Annotation of OpenXM/src/asir-doc/jtexindex/C/texindex.c, Revision 1.1
1.1 ! noro 1: /* Prepare TeX index dribble output into an actual index.
! 2:
! 3: Version 1.45
! 4:
! 5: Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
! 6:
! 7: This program is free software; you can redistribute it and/or modify
! 8: it under the terms of the GNU General Public License as published by
! 9: the Free Software Foundation; either version 2, or (at your option)
! 10: any later version.
! 11:
! 12: This program is distributed in the hope that it will be useful,
! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 15: GNU General Public License for more details.
! 16:
! 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. */
! 20:
! 21: /*
! 22: 95.10.18 modified by Nobuyosi KAMEI <CXK03514@niftyserve.or.jp>
! 23: 日本語EUCが処理できるようにした。
! 24: 95.10.19 modified by K. Handa <handa@etl.go.jp>
! 25: \initial{...} の出力を調整。
! 26: */
! 27:
! 28:
! 29: #include <stdio.h>
! 30: #include <ctype.h>
! 31: #include <errno.h>
! 32: #include <assert.h>
! 33: #include "getopt.h"
! 34:
! 35: #define TEXINDEX_VERSION_STRING "GNU Texindex 2.0 for Texinfo release 3.4"
! 36: #define TEXINDEX_MODIFICATION_STRING "(modified for Japanese EUC encoding)"
! 37:
! 38: #if defined (emacs)
! 39: # include "../src/config.h"
! 40: /* Some s/os.h files redefine these. */
! 41: # undef read
! 42: # undef close
! 43: # undef write
! 44: # undef open
! 45: #endif
! 46:
! 47: #if defined (HAVE_STRING_H)
! 48: # include <string.h>
! 49: #endif /* HAVE_STRING_H */
! 50:
! 51: #if !defined (HAVE_STRCHR)
! 52: char *strrchr ();
! 53: #endif /* !HAVE_STRCHR */
! 54:
! 55: #if defined (STDC_HEADERS)
! 56: # include <stdlib.h>
! 57: #else /* !STDC_HEADERS */
! 58: char *getenv (), *malloc (), *realloc ();
! 59: #endif /* !STDC_HEADERS */
! 60:
! 61: #if defined (HAVE_UNISTD_H)
! 62: # include <unistd.h>
! 63: #else /* !HAVE_UNISTD_H */
! 64: off_t lseek ();
! 65: #endif /* !HAVE_UNISTD_H */
! 66:
! 67: #if !defined (HAVE_MEMSET)
! 68: #undef memset
! 69: #define memset(ptr, ignore, count) bzero (ptr, count)
! 70: #endif
! 71:
! 72:
! 73: char *mktemp ();
! 74:
! 75: #if defined (VMS)
! 76: # include <file.h>
! 77: # define TI_NO_ERROR ((1 << 28) | 1)
! 78: # define TI_FATAL_ERROR ((1 << 28) | 4)
! 79: # define unlink delete
! 80: #else /* !VMS */
! 81: # if defined (HAVE_SYS_FCNTL_H)
! 82: # include <sys/types.h>
! 83: # include <sys/fcntl.h>
! 84: # endif /* HAVE_SYS_FCNTL_H */
! 85:
! 86: # if defined (_AIX) || !defined (_POSIX_VERSION)
! 87: # include <sys/file.h>
! 88: # else /* !AIX && _POSIX_VERSION */
! 89: # if !defined (HAVE_SYS_FCNTL_H)
! 90: # include <fcntl.h>
! 91: # endif /* !HAVE_FCNTL_H */
! 92: # endif /* !_AIX && _POSIX_VERSION */
! 93: # define TI_NO_ERROR 0
! 94: # define TI_FATAL_ERROR 1
! 95: #endif /* !VMS */
! 96:
! 97: #if !defined (SEEK_SET)
! 98: # define SEEK_SET 0
! 99: # define SEEK_CUR 1
! 100: # define SEEK_END 2
! 101: #endif /* !SEEK_SET */
! 102:
! 103: #if !defined (errno)
! 104: extern int errno;
! 105: #endif
! 106: char *strerror ();
! 107:
! 108: /* When sorting in core, this structure describes one line
! 109: and the position and length of its first keyfield. */
! 110: struct lineinfo
! 111: {
! 112: u_short *text; /* The actual text of the line. */
! 113: union {
! 114: u_short *text; /* The start of the key (for textual comparison). */
! 115: long number; /* The numeric value (for numeric comparison). */
! 116: } key;
! 117: long keylen; /* Length of KEY field. */
! 118: };
! 119:
! 120: /* This structure describes a field to use as a sort key. */
! 121: struct keyfield
! 122: {
! 123: int startwords; /* Number of words to skip. */
! 124: int startchars; /* Number of additional chars to skip. */
! 125: int endwords; /* Number of words to ignore at end. */
! 126: int endchars; /* Ditto for characters of last word. */
! 127: char ignore_blanks; /* Non-zero means ignore spaces and tabs. */
! 128: char fold_case; /* Non-zero means case doesn't matter. */
! 129: char reverse; /* Non-zero means compare in reverse order. */
! 130: char numeric; /* Non-zeros means field is ASCII numeric. */
! 131: char positional; /* Sort according to file position. */
! 132: char braced; /* Count balanced-braced groupings as fields. */
! 133: };
! 134:
! 135: /* Vector of keyfields to use. */
! 136: struct keyfield keyfields[3];
! 137:
! 138: /* Number of keyfields stored in that vector. */
! 139: int num_keyfields = 3;
! 140:
! 141: /* Vector of input file names, terminated with a null pointer. */
! 142: char **infiles;
! 143:
! 144: /* Vector of corresponding output file names, or NULL, meaning default it
! 145: (add an `s' to the end). */
! 146: char **outfiles;
! 147:
! 148: /* Length of `infiles'. */
! 149: int num_infiles;
! 150:
! 151: /* Pointer to the array of pointers to lines being sorted. */
! 152: u_short **linearray;
! 153:
! 154: /* The allocated length of `linearray'. */
! 155: long nlines;
! 156:
! 157: /* Directory to use for temporary files. On Unix, it ends with a slash. */
! 158: char *tempdir;
! 159:
! 160: /* Start of filename to use for temporary files. */
! 161: char *tempbase;
! 162:
! 163: /* Number of last temporary file. */
! 164: int tempcount;
! 165:
! 166: /* Number of last temporary file already deleted.
! 167: Temporary files are deleted by `flush_tempfiles' in order of creation. */
! 168: int last_deleted_tempcount;
! 169:
! 170: /* During in-core sort, this points to the base of the data block
! 171: which contains all the lines of data. */
! 172: u_short *text_base;
! 173:
! 174: /* Additional command switches .*/
! 175:
! 176: /* Nonzero means do not delete tempfiles -- for debugging. */
! 177: int keep_tempfiles;
! 178:
! 179: /* The name this program was run with. */
! 180: char *program_name;
! 181:
! 182: /* 仮名文字の母音テーブル */
! 183: int Vowel_Table[0x60];
! 184:
! 185: /* Forward declarations of functions in this file. */
! 186:
! 187: void decode_command ();
! 188: void sort_in_core ();
! 189: void sort_offline ();
! 190: u_short **parsefile ();
! 191: u_short *find_field ();
! 192: u_short *find_pos ();
! 193: long find_value ();
! 194: u_short *find_braced_pos (u_short *str, int words, int chars, int ignore_blanks);
! 195: u_short *find_braced_end ();
! 196: void writelines (u_short **linearray, int nlines, FILE *ostream);
! 197: int compare_field ();
! 198: int compare_full ();
! 199: long readline ();
! 200: int merge_files ();
! 201: int merge_direct ();
! 202: void pfatal_with_name ();
! 203: void fatal ();
! 204: void error ();
! 205: void *xmalloc (), *xrealloc ();
! 206: char *concat ();
! 207: char *maketempname ();
! 208: void flush_tempfiles ();
! 209: char *tempcopy ();
! 210: static void memory_error();
! 211: static int wstrncmp(const u_short *s1, const u_short *s2, size_t n);
! 212: static int wfwrite(u_short *ptr, size_t size, size_t nmemb, FILE*stream);
! 213: static int wtoc(char *cptr, u_short const *ptr, int len);
! 214: static int Vowel_of(int c);
! 215: static void init_Vowel_Table(void);
! 216:
! 217: #define EUC_BYTE(c) (0x00A1 <= c && c <= 0x00FE)
! 218: #define G1_CHAR(c) (c & 0xFF00)
! 219:
! 220: #define MAX_IN_CORE_SORT 500000
! 221:
! 222: void
! 223: main (argc, argv)
! 224: int argc;
! 225: char **argv;
! 226: {
! 227: int i;
! 228:
! 229: tempcount = 0;
! 230: last_deleted_tempcount = 0;
! 231:
! 232: program_name = strrchr (argv[0], '/');
! 233: if (program_name != (char *)NULL)
! 234: program_name++;
! 235: else
! 236: program_name = argv[0];
! 237:
! 238: /* Describe the kind of sorting to do. */
! 239: /* The first keyfield uses the first braced field and folds case. */
! 240: keyfields[0].braced = 1;
! 241: keyfields[0].fold_case = 1;
! 242: keyfields[0].endwords = -1;
! 243: keyfields[0].endchars = -1;
! 244:
! 245: /* The second keyfield uses the second braced field, numerically. */
! 246: keyfields[1].braced = 1;
! 247: keyfields[1].numeric = 1;
! 248: keyfields[1].startwords = 1;
! 249: keyfields[1].endwords = -1;
! 250: keyfields[1].endchars = -1;
! 251:
! 252: /* The third keyfield (which is ignored while discarding duplicates)
! 253: compares the whole line. */
! 254: keyfields[2].endwords = -1;
! 255: keyfields[2].endchars = -1;
! 256:
! 257: decode_command (argc, argv);
! 258:
! 259: tempbase = mktemp (concat ("txiXXXXXX", "", ""));
! 260:
! 261: /* Process input files completely, one by one. */
! 262:
! 263: for (i = 0; i < num_infiles; i++)
! 264: {
! 265: int desc;
! 266: long ptr;
! 267: char *outfile;
! 268:
! 269: desc = open (infiles[i], O_RDONLY, 0);
! 270: if (desc < 0)
! 271: pfatal_with_name (infiles[i]);
! 272: lseek (desc, (off_t) 0, SEEK_END);
! 273: ptr = (long) lseek (desc, (off_t) 0, SEEK_CUR);
! 274:
! 275: close (desc);
! 276:
! 277: outfile = outfiles[i];
! 278: if (!outfile)
! 279: {
! 280: outfile = concat (infiles[i], "s", "");
! 281: }
! 282:
! 283: if (ptr < MAX_IN_CORE_SORT)
! 284: /* Sort a small amount of data. */
! 285: sort_in_core (infiles[i], ptr, outfile);
! 286: else
! 287: sort_offline (infiles[i], ptr, outfile);
! 288: }
! 289:
! 290: flush_tempfiles (tempcount);
! 291: exit (TI_NO_ERROR);
! 292: }
! 293:
! 294: typedef struct
! 295: {
! 296: char *long_name;
! 297: char *short_name;
! 298: int *variable_ref;
! 299: int variable_value;
! 300: char *arg_name;
! 301: char *doc_string;
! 302: } TEXINDEX_OPTION;
! 303:
! 304: TEXINDEX_OPTION texindex_options[] = {
! 305: { "--keep", "-k", &keep_tempfiles, 1, (char *)NULL,
! 306: "Keep temporary files around after processing" },
! 307: { "--no-keep", 0, &keep_tempfiles, 0, (char *)NULL,
! 308: "Do not keep temporary files around after processing (default)" },
! 309: { "--output", "-o", (int *)NULL, 0, "FILE",
! 310: "Send output to FILE" },
! 311: { "--version", (char *)NULL, (int *)NULL, 0, (char *)NULL,
! 312: "Show version information" },
! 313: { "--help", "-h", (int *)NULL, 0, (char *)NULL, "Produce this listing" },
! 314: { (char *)NULL, (char *)NULL, (int *)NULL, 0, (char *)NULL }
! 315: };
! 316:
! 317: void
! 318: usage (result_value)
! 319: int result_value;
! 320: {
! 321: register int i;
! 322:
! 323: fprintf (stderr, "Usage: %s [OPTIONS] FILE...\n", program_name);
! 324: fprintf (stderr, " Generate a permuted index for the TeX files given.\n");
! 325: fprintf (stderr, " Usually FILE... is `foo.??' for the source file `foo.tex'.\n");
! 326: fprintf (stderr, " The OPTIONS are:\n");
! 327:
! 328: for (i = 0; texindex_options[i].long_name; i++)
! 329: {
! 330: fprintf (stderr, " %s %s",
! 331: texindex_options[i].long_name,
! 332: texindex_options[i].arg_name ?
! 333: texindex_options[i].arg_name : "");
! 334:
! 335: if (texindex_options[i].short_name)
! 336: fprintf (stderr, " \n or %s %s",
! 337: texindex_options[i].short_name,
! 338: texindex_options[i].arg_name ?
! 339: texindex_options[i].arg_name : "");
! 340: fprintf (stderr, "\t%s\n", texindex_options[i].doc_string);
! 341: }
! 342: exit (result_value);
! 343: }
! 344:
! 345: /* Decode the command line arguments to set the parameter variables
! 346: and set up the vector of keyfields and the vector of input files. */
! 347:
! 348: void
! 349: decode_command (argc, argv)
! 350: int argc;
! 351: char **argv;
! 352: {
! 353: int arg_index = 1;
! 354: char **ip;
! 355: char **op;
! 356:
! 357: /* Store default values into parameter variables. */
! 358:
! 359: tempdir = getenv ("TMPDIR");
! 360: #ifdef VMS
! 361: if (tempdir == NULL)
! 362: tempdir = "sys$scratch:";
! 363: #else
! 364: if (tempdir == NULL)
! 365: tempdir = "/tmp/";
! 366: else
! 367: tempdir = concat (tempdir, "/", "");
! 368: #endif
! 369:
! 370: keep_tempfiles = 0;
! 371:
! 372: /* Allocate ARGC input files, which must be enough. */
! 373:
! 374: infiles = (char **) xmalloc (argc * sizeof (char *));
! 375: outfiles = (char **) xmalloc (argc * sizeof (char *));
! 376: ip = infiles;
! 377: op = outfiles;
! 378:
! 379: while (arg_index < argc)
! 380: {
! 381: char *arg = argv[arg_index++];
! 382:
! 383: if (*arg == '-')
! 384: {
! 385: if (strcmp (arg, "--version") == 0)
! 386: {
! 387: fprintf (stderr, "%s", TEXINDEX_VERSION_STRING);
! 388: #ifdef TEXINDEX_MODIFICATION_STRING
! 389: fprintf (stderr, " %s", TEXINDEX_MODIFICATION_STRING);
! 390: #endif
! 391: fprintf (stderr, "\n");
! 392: exit (0);
! 393: }
! 394: else if ((strcmp (arg, "--keep") == 0) ||
! 395: (strcmp (arg, "-k") == 0))
! 396: {
! 397: keep_tempfiles = 1;
! 398: }
! 399: else if ((strcmp (arg, "--help") == 0) ||
! 400: (strcmp (arg, "-h") == 0))
! 401: {
! 402: usage (0);
! 403: }
! 404: else if ((strcmp (arg, "--output") == 0) ||
! 405: (strcmp (arg, "-o") == 0))
! 406: {
! 407: if (argv[arg_index] != (char *)NULL)
! 408: {
! 409: arg_index++;
! 410: if (op > outfiles)
! 411: *(op - 1) = argv[arg_index];
! 412: }
! 413: else
! 414: usage (1);
! 415: }
! 416: else
! 417: usage (1);
! 418: }
! 419: else
! 420: {
! 421: *ip++ = arg;
! 422: *op++ = (char *)NULL;
! 423: }
! 424: }
! 425:
! 426: /* Record number of keyfields and terminate list of filenames. */
! 427: num_infiles = ip - infiles;
! 428: *ip = (char *)NULL;
! 429: if (num_infiles == 0)
! 430: usage (1);
! 431: }
! 432:
! 433: /* Return a name for a temporary file. */
! 434:
! 435: char *
! 436: maketempname (count)
! 437: int count;
! 438: {
! 439: char tempsuffix[10];
! 440: sprintf (tempsuffix, "%d", count);
! 441: return concat (tempdir, tempbase, tempsuffix);
! 442: }
! 443:
! 444: /* Delete all temporary files up to TO_COUNT. */
! 445:
! 446: void
! 447: flush_tempfiles (to_count)
! 448: int to_count;
! 449: {
! 450: if (keep_tempfiles)
! 451: return;
! 452: while (last_deleted_tempcount < to_count)
! 453: unlink (maketempname (++last_deleted_tempcount));
! 454: }
! 455:
! 456: /* Copy the input file open on IDESC into a temporary file
! 457: and return the temporary file name. */
! 458:
! 459: #define BUFSIZE 1024
! 460:
! 461: char *
! 462: tempcopy (idesc)
! 463: int idesc;
! 464: {
! 465: char *outfile = maketempname (++tempcount);
! 466: int odesc;
! 467: char buffer[BUFSIZE];
! 468:
! 469: odesc = open (outfile, O_WRONLY | O_CREAT, 0666);
! 470:
! 471: if (odesc < 0)
! 472: pfatal_with_name (outfile);
! 473:
! 474: while (1)
! 475: {
! 476: int nread = read (idesc, buffer, BUFSIZE);
! 477: write (odesc, buffer, nread);
! 478: if (!nread)
! 479: break;
! 480: }
! 481:
! 482: close (odesc);
! 483:
! 484: return outfile;
! 485: }
! 486:
! 487: /* Compare LINE1 and LINE2 according to the specified set of keyfields. */
! 488:
! 489: int
! 490: compare_full (line1, line2)
! 491: u_short **line1, **line2;
! 492: {
! 493: int i;
! 494:
! 495: /* Compare using the first keyfield;
! 496: if that does not distinguish the lines, try the second keyfield;
! 497: and so on. */
! 498:
! 499: for (i = 0; i < num_keyfields; i++)
! 500: {
! 501: long length1, length2;
! 502: u_short *start1 = find_field (&keyfields[i], *line1, &length1);
! 503: u_short *start2 = find_field (&keyfields[i], *line2, &length2);
! 504: int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base,
! 505: start2, length2, *line2 - text_base);
! 506: if (tem)
! 507: {
! 508: if (keyfields[i].reverse)
! 509: return -tem;
! 510: return tem;
! 511: }
! 512: }
! 513:
! 514: return 0; /* Lines match exactly. */
! 515: }
! 516:
! 517: /* Compare LINE1 and LINE2, described by structures
! 518: in which the first keyfield is identified in advance.
! 519: For positional sorting, assumes that the order of the lines in core
! 520: reflects their nominal order. */
! 521:
! 522: int
! 523: compare_prepared (line1, line2)
! 524: struct lineinfo *line1, *line2;
! 525: {
! 526: int i;
! 527: int tem;
! 528: u_short *text1, *text2;
! 529:
! 530: /* Compare using the first keyfield, which has been found for us already. */
! 531: if (keyfields->positional)
! 532: {
! 533: if (line1->text - text_base > line2->text - text_base)
! 534: tem = 1;
! 535: else
! 536: tem = -1;
! 537: }
! 538: else if (keyfields->numeric)
! 539: tem = line1->key.number - line2->key.number;
! 540: else
! 541: tem = compare_field (keyfields, line1->key.text, line1->keylen, 0,
! 542: line2->key.text, line2->keylen, 0);
! 543: if (tem)
! 544: {
! 545: if (keyfields->reverse)
! 546: return -tem;
! 547: return tem;
! 548: }
! 549:
! 550: text1 = line1->text;
! 551: text2 = line2->text;
! 552:
! 553: /* Compare using the second keyfield;
! 554: if that does not distinguish the lines, try the third keyfield;
! 555: and so on. */
! 556:
! 557: for (i = 1; i < num_keyfields; i++)
! 558: {
! 559: long length1, length2;
! 560: u_short *start1 = find_field (&keyfields[i], text1, &length1);
! 561: u_short *start2 = find_field (&keyfields[i], text2, &length2);
! 562: int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base,
! 563: start2, length2, text2 - text_base);
! 564: if (tem)
! 565: {
! 566: if (keyfields[i].reverse)
! 567: return -tem;
! 568: return tem;
! 569: }
! 570: }
! 571:
! 572: return 0; /* Lines match exactly. */
! 573: }
! 574:
! 575: /* Like compare_full but more general.
! 576: You can pass any strings, and you can say how many keyfields to use.
! 577: POS1 and POS2 should indicate the nominal positional ordering of
! 578: the two lines in the input. */
! 579:
! 580: int
! 581: compare_general (str1, str2, pos1, pos2, use_keyfields)
! 582: u_short *str1, *str2;
! 583: long pos1, pos2;
! 584: int use_keyfields;
! 585: {
! 586: int i;
! 587:
! 588: /* Compare using the first keyfield;
! 589: if that does not distinguish the lines, try the second keyfield;
! 590: and so on. */
! 591:
! 592: for (i = 0; i < use_keyfields; i++)
! 593: {
! 594: long length1, length2;
! 595: u_short *start1 = find_field (&keyfields[i], str1, &length1);
! 596: u_short *start2 = find_field (&keyfields[i], str2, &length2);
! 597: int tem = compare_field (&keyfields[i], start1, length1, pos1,
! 598: start2, length2, pos2);
! 599: if (tem)
! 600: {
! 601: if (keyfields[i].reverse)
! 602: return -tem;
! 603: return tem;
! 604: }
! 605: }
! 606:
! 607: return 0; /* Lines match exactly. */
! 608: }
! 609:
! 610: /* Find the start and length of a field in STR according to KEYFIELD.
! 611: A pointer to the starting character is returned, and the length
! 612: is stored into the int that LENGTHPTR points to. */
! 613:
! 614: u_short *
! 615: find_field (keyfield, str, lengthptr)
! 616: struct keyfield *keyfield;
! 617: u_short *str;
! 618: long *lengthptr;
! 619: {
! 620: u_short *start;
! 621: u_short *end;
! 622: u_short *(*fun) ();
! 623:
! 624: if (keyfield->braced)
! 625: fun = find_braced_pos;
! 626: else
! 627: fun = find_pos;
! 628:
! 629: start = (*fun) (str, keyfield->startwords, keyfield->startchars,
! 630: keyfield->ignore_blanks);
! 631: if (keyfield->endwords < 0)
! 632: {
! 633: if (keyfield->braced)
! 634: end = find_braced_end (start);
! 635: else
! 636: {
! 637: end = start;
! 638: while (*end && *end != '\n')
! 639: end++;
! 640: }
! 641: }
! 642: else
! 643: {
! 644: end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0);
! 645: if (end - str < start - str)
! 646: end = start;
! 647: }
! 648: *lengthptr = end - start;
! 649: return start;
! 650: }
! 651:
! 652: /* Return a pointer to a specified place within STR,
! 653: skipping (from the beginning) WORDS words and then CHARS chars.
! 654: If IGNORE_BLANKS is nonzero, we skip all blanks
! 655: after finding the specified word. */
! 656:
! 657: u_short *
! 658: find_pos (str, words, chars, ignore_blanks)
! 659: u_short *str;
! 660: int words, chars;
! 661: int ignore_blanks;
! 662: {
! 663: int i;
! 664: u_short *p = str;
! 665:
! 666: for (i = 0; i < words; i++)
! 667: {
! 668: u_short c;
! 669: /* Find next bunch of nonblanks and skip them. */
! 670: while ((c = *p) == ' ' || c == '\t')
! 671: p++;
! 672: while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t'))
! 673: p++;
! 674: if (!*p || *p == '\n')
! 675: return p;
! 676: }
! 677:
! 678: while (*p == ' ' || *p == '\t')
! 679: p++;
! 680:
! 681: for (i = 0; i < chars; i++)
! 682: {
! 683: if (!*p || *p == '\n')
! 684: break;
! 685: p++;
! 686: }
! 687: return p;
! 688: }
! 689:
! 690: /* Like find_pos but assumes that each field is surrounded by braces
! 691: and that braces within fields are balanced. */
! 692:
! 693: u_short *
! 694: find_braced_pos (str, words, chars, ignore_blanks)
! 695: u_short *str;
! 696: int words, chars;
! 697: int ignore_blanks;
! 698: {
! 699: int i;
! 700: int bracelevel;
! 701: u_short *p = str;
! 702: u_short c;
! 703:
! 704: for (i = 0; i < words; i++)
! 705: {
! 706: bracelevel = 1;
! 707: while ((c = *p++) != '{' && c != '\n' && c)
! 708: /* Do nothing. */ ;
! 709: if (c != '{')
! 710: return p - 1;
! 711: while (bracelevel)
! 712: {
! 713: c = *p++;
! 714: if (c == '{')
! 715: bracelevel++;
! 716: if (c == '}')
! 717: bracelevel--;
! 718: if (c == 0 || c == '\n')
! 719: return p - 1;
! 720: }
! 721: }
! 722:
! 723: while ((c = *p++) != '{' && c != '\n' && c)
! 724: /* Do nothing. */ ;
! 725:
! 726: if (c != '{')
! 727: return p - 1;
! 728:
! 729: if (ignore_blanks)
! 730: while ((c = *p) == ' ' || c == '\t')
! 731: p++;
! 732:
! 733: for (i = 0; i < chars; i++)
! 734: {
! 735: if (!*p || *p == '\n')
! 736: break;
! 737: p++;
! 738: }
! 739: return p;
! 740: }
! 741:
! 742: /* Find the end of the balanced-brace field which starts at STR.
! 743: The position returned is just before the closing brace. */
! 744:
! 745: u_short *
! 746: find_braced_end (str)
! 747: u_short *str;
! 748: {
! 749: int bracelevel;
! 750: u_short *p = str;
! 751: u_short c;
! 752:
! 753: bracelevel = 1;
! 754: while (bracelevel)
! 755: {
! 756: c = *p++;
! 757: if (c == '{')
! 758: bracelevel++;
! 759: if (c == '}')
! 760: bracelevel--;
! 761: if (c == 0 || c == '\n')
! 762: return p - 1;
! 763: }
! 764: return p - 1;
! 765: }
! 766:
! 767: long
! 768: find_value (start, length)
! 769: u_short *start;
! 770: long length;
! 771: {
! 772: long val;
! 773:
! 774: while (length != 0L)
! 775: {
! 776: if (isdigit (*start))
! 777: break;
! 778: length--;
! 779: start++;
! 780: }
! 781:
! 782: val = 0;
! 783: while(isdigit(*start) && length > 0L)
! 784: {
! 785: val = val*10 + *start;
! 786: start++;
! 787: length--;
! 788: }
! 789:
! 790: return val;
! 791: }
! 792:
! 793: /* Vector used to translate characters for comparison.
! 794: This is how we make all alphanumerics follow all else,
! 795: and ignore case in the first sorting. */
! 796: int char_order[0x8000];
! 797:
! 798: void
! 799: init_char_order (void)
! 800: {
! 801: int i;
! 802:
! 803: for (i = 1; i < 0x8000; i++)
! 804: char_order[i] = i;
! 805:
! 806: for (i = '0'; i <= '9'; i++)
! 807: char_order[i] += 512;
! 808:
! 809: for (i = 'a'; i <= 'z'; i++)
! 810: {
! 811: char_order[i] = 512 + i;
! 812: char_order[i + 'A' - 'a'] = 512 + i;
! 813: }
! 814:
! 815: /* 以下のシンボルは無視 (i.e. char_order[XXX] = 0) */
! 816: for (i = 0x2121; i <= 0x2132; i++) /* 全角空白 〜 _ */
! 817: char_order[i] = 0;
! 818: for (i = 0x213D; i <= 0x215B; i++) /* − 〜 】 */
! 819: char_order[i] = 0;
! 820:
! 821: /* 促音、拗音、濁音、半濁音、片仮名/平仮名の処理 */
! 822: /* 1. 平仮名と片仮名、同じに扱う */
! 823: /* ぁ/ァ(2421/2521)〜ん/ン(2473/2573) */
! 824: for (i = 0x2421; i < 0x2474; i++)
! 825: char_order[i + 0x100] = i;
! 826:
! 827: /* 2. 促音、拗音、濁音、半濁音、類 */
! 828: /* ぁ〜ぉ → あ〜お */
! 829: for (i = 0x2421; i < 0x242B; i += 2)
! 830: char_order[i] = char_order[i + 0x100] = i+1;
! 831: /* が〜ぢ → か〜ち */
! 832: for (i = 0x242C; i < 0x2443; i += 2)
! 833: char_order[i] = char_order[i + 0x100] = i-1;
! 834: /* っ */
! 835: char_order[0x2443] = char_order[0x2543] = 0x2443+1;
! 836: /* づ〜ど → つ〜と */
! 837: for (i = 0x2445; i < 0x244A; i += 2)
! 838: char_order[i] = char_order[i + 0x100] = i-1;
! 839: /* ばぱ〜ぼぽ → は〜ほ */
! 840: for (i = 0x2450; i < 0x245E; i += 3)
! 841: {
! 842: char_order[i] = char_order[i + 0x100] = i-1;
! 843: char_order[i+1] = char_order[i+1 + 0x100] = i-1;
! 844: }
! 845: /* ゃ〜ょ → や〜よ */
! 846: for (i = 0x2463; i < 0x2469; i += 2)
! 847: char_order[i] = char_order[i + 0x100] = i+1;
! 848: /* ゎ → わ */
! 849: char_order[0x246E] = char_order[0x256E] = 0x246E +1;
! 850:
! 851: /* 3. 特殊片仮名の扱い */
! 852: char_order[0x2574] = 0x2426; /* ヴ → う */
! 853: char_order[0x2575] = 0x242B; /* ヵ → か */
! 854: char_order[0x2576] = 0x2431; /* ヶ → け */
! 855:
! 856: /* JISX0208のアルファベット、数字 */
! 857: for (i = 0x2330; i <= 0x2339; i++) /* 0〜9 -> 0-9 */
! 858: char_order[i] = i - 0x2330 + 512;
! 859: for (i = 0x2341; i <= 0x235A; i++) /* A〜Z、a〜z -> A-Z */
! 860: char_order[i] = char_order[i + (0x2361 - 0x2341)]
! 861: = 512 + (i - 0x2341) + 'a';
! 862:
! 863: /* 長音処理は比較ルーチンで行なう */
! 864:
! 865: init_Vowel_Table();
! 866: }
! 867:
! 868: /* Compare two fields (each specified as a start pointer and a character count)
! 869: according to KEYFIELD.
! 870: The sign of the value reports the relation between the fields. */
! 871:
! 872: int
! 873: compare_field (keyfield, start1, length1, pos1, start2, length2, pos2)
! 874: struct keyfield *keyfield;
! 875: u_short *start1;
! 876: long length1;
! 877: long pos1;
! 878: u_short *start2;
! 879: long length2;
! 880: long pos2;
! 881: {
! 882: if (keyfields->positional)
! 883: {
! 884: if (pos1 > pos2)
! 885: return 1;
! 886: else
! 887: return -1;
! 888: }
! 889: if (keyfield->numeric)
! 890: {
! 891: long value = find_value (start1, length1) - find_value (start2, length2);
! 892: if (value > 0)
! 893: return 1;
! 894: if (value < 0)
! 895: return -1;
! 896: return 0;
! 897: }
! 898: else
! 899: {
! 900: /* lexical ってか? */
! 901: u_short *p1 = start1;
! 902: u_short *p2 = start2;
! 903: u_short *e1 = start1 + length1;
! 904: u_short *e2 = start2 + length2;
! 905: u_short lastchar1 = 0, lastchar2 = 0;
! 906: int c1, c2;
! 907:
! 908: do
! 909: {
! 910: int co1, co2;
! 911:
! 912: /* char_order[X] が 0 のもの(シンボル)は無視する */
! 913: c1 = c2 = 0;
! 914: while (p1 < e1)
! 915: {
! 916: if (char_order[c1 = *p1++]) break;
! 917: c1 = 0;
! 918: }
! 919: while (p2 < e2)
! 920: {
! 921: if (char_order[c2 = *p2++]) break;
! 922: c2 = 0;
! 923: }
! 924:
! 925: /* 長音処理 */
! 926: if (c1 == 0x213C) /* ー */
! 927: c1 = Vowel_of(lastchar1);
! 928: if (c2 == 0x213C) /* ー */
! 929: c2 = Vowel_of(lastchar2);
! 930: co1 = char_order[c1];
! 931: co2 = char_order[c2];
! 932:
! 933: if (co1 != co2)
! 934: return co1 - co2;
! 935: else
! 936: lastchar1 = c1, lastchar2 = c2;
! 937:
! 938: } while(c1);
! 939:
! 940: /* Strings are equal except possibly for case. */
! 941: p1 = start1;
! 942: p2 = start2;
! 943: while (1)
! 944: {
! 945: int c1, c2;
! 946:
! 947: if (p1 == e1)
! 948: c1 = 0;
! 949: else
! 950: c1 = *p1++;
! 951: if (p2 == e2)
! 952: c2 = 0;
! 953: else
! 954: c2 = *p2++;
! 955:
! 956: if (c1 != c2)
! 957: /* Reverse sign here so upper case comes out last. */
! 958: return c2 - c1;
! 959: if (!c1)
! 960: break;
! 961: }
! 962:
! 963: return 0;
! 964: }
! 965: }
! 966:
! 967: /* A `struct linebuffer' is a structure which holds a line of text.
! 968: `readline' reads a line from a stream into a linebuffer
! 969: and works regardless of the length of the line. */
! 970:
! 971: struct linebuffer
! 972: {
! 973: long size;
! 974: u_short *buffer;
! 975: };
! 976:
! 977: /* Initialize LINEBUFFER for use. */
! 978:
! 979: void
! 980: initbuffer (linebuffer)
! 981: struct linebuffer *linebuffer;
! 982: {
! 983: linebuffer->size = 200;
! 984: linebuffer->buffer = (u_short *) xmalloc (200*sizeof(u_short));
! 985: }
! 986:
! 987: /* Read a line of text from STREAM into LINEBUFFER.
! 988: Return the length of the line. */
! 989:
! 990: long
! 991: readline (linebuffer, stream)
! 992: struct linebuffer *linebuffer;
! 993: FILE *stream;
! 994: {
! 995: u_short *buffer = linebuffer->buffer;
! 996: u_short *p = linebuffer->buffer;
! 997: u_short *end = p + linebuffer->size;
! 998:
! 999: while (1)
! 1000: {
! 1001: int c = getc (stream);
! 1002: if (p == end)
! 1003: {
! 1004: buffer =
! 1005: (u_short *) xrealloc (buffer,
! 1006: (linebuffer->size *= 2)*sizeof(u_short));
! 1007: p += buffer - linebuffer->buffer;
! 1008: end += buffer - linebuffer->buffer;
! 1009: linebuffer->buffer = buffer;
! 1010: }
! 1011: if (c < 0 || c == '\n')
! 1012: {
! 1013: *p = 0;
! 1014: break;
! 1015: }
! 1016: *p++ = c;
! 1017: }
! 1018:
! 1019: return p - buffer;
! 1020: }
! 1021:
! 1022: /* Sort an input file too big to sort in core. */
! 1023:
! 1024: void
! 1025: sort_offline (infile, nfiles, total, outfile)
! 1026: char *infile;
! 1027: int nfiles;
! 1028: long total;
! 1029: char *outfile;
! 1030: {
! 1031: /* More than enough. */
! 1032: int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;
! 1033: char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
! 1034: FILE *istream = fopen (infile, "r");
! 1035: int i;
! 1036: struct linebuffer lb;
! 1037: long linelength;
! 1038: int failure = 0;
! 1039:
! 1040: initbuffer (&lb);
! 1041:
! 1042: /* Read in one line of input data. */
! 1043:
! 1044: linelength = readline (&lb, istream);
! 1045:
! 1046: if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
! 1047: {
! 1048: error ("%s: not a texinfo index file", infile);
! 1049: return;
! 1050: }
! 1051:
! 1052: /* Split up the input into `ntemps' temporary files, or maybe fewer,
! 1053: and put the new files' names into `tempfiles' */
! 1054:
! 1055: for (i = 0; i < ntemps; i++)
! 1056: {
! 1057: char *outname = maketempname (++tempcount);
! 1058: FILE *ostream = fopen (outname, "w");
! 1059: long tempsize = 0;
! 1060:
! 1061: if (!ostream)
! 1062: pfatal_with_name (outname);
! 1063: tempfiles[i] = outname;
! 1064:
! 1065: /* Copy lines into this temp file as long as it does not make file
! 1066: "too big" or until there are no more lines. */
! 1067:
! 1068: while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
! 1069: {
! 1070: tempsize += linelength + 1;
! 1071: {
! 1072: u_short *tp;
! 1073:
! 1074: for (tp = lb.buffer; *tp; tp++)
! 1075: putc(*tp, ostream);
! 1076: }
! 1077: putc ('\n', ostream);
! 1078:
! 1079: /* Read another line of input data. */
! 1080:
! 1081: linelength = readline (&lb, istream);
! 1082: if (!linelength && feof (istream))
! 1083: break;
! 1084:
! 1085: if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
! 1086: {
! 1087: error ("%s: not a texinfo index file", infile);
! 1088: failure = 1;
! 1089: goto fail;
! 1090: }
! 1091: }
! 1092: fclose (ostream);
! 1093: if (feof (istream))
! 1094: break;
! 1095: }
! 1096:
! 1097: free (lb.buffer);
! 1098:
! 1099: fail:
! 1100: /* Record number of temp files we actually needed. */
! 1101:
! 1102: ntemps = i;
! 1103:
! 1104: /* Sort each tempfile into another tempfile.
! 1105: Delete the first set of tempfiles and put the names of the second
! 1106: into `tempfiles'. */
! 1107:
! 1108: for (i = 0; i < ntemps; i++)
! 1109: {
! 1110: char *newtemp = maketempname (++tempcount);
! 1111: sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp);
! 1112: if (!keep_tempfiles)
! 1113: unlink (tempfiles[i]);
! 1114: tempfiles[i] = newtemp;
! 1115: }
! 1116:
! 1117: if (failure)
! 1118: return;
! 1119:
! 1120: /* Merge the tempfiles together and indexify. */
! 1121:
! 1122: merge_files (tempfiles, ntemps, outfile);
! 1123: }
! 1124:
! 1125: /* Sort INFILE, whose size is TOTAL,
! 1126: assuming that is small enough to be done in-core,
! 1127: then indexify it and send the output to OUTFILE (or to stdout). */
! 1128:
! 1129: void
! 1130: sort_in_core (infile, total, outfile)
! 1131: char *infile;
! 1132: long total;
! 1133: char *outfile;
! 1134: {
! 1135: u_short **nextline;
! 1136: u_short *data = (u_short *) xmalloc ((total + 1)*sizeof(u_short));
! 1137: u_short *file_data;
! 1138: long file_size;
! 1139: int i;
! 1140: FILE *ostream = stdout;
! 1141: struct lineinfo *lineinfo;
! 1142: FILE *ifp;
! 1143: int c;
! 1144:
! 1145: /* Read the contents of the file into the moby array `data'. */
! 1146: ifp = fopen(infile, "r");
! 1147: if (!ifp)
! 1148: fatal ("failure reopening %s", infile);
! 1149: memset(data, 0, (total + 1)*sizeof(u_short)); /* zero clear */
! 1150: for (i = 0, c = fgetc(ifp); c != EOF; c = fgetc(ifp), i++)
! 1151: {
! 1152: if (EUC_BYTE(c))
! 1153: {
! 1154: data[i] = (c & 0x007F) << 8;
! 1155: c = fgetc(ifp) & 0x007F;
! 1156: }
! 1157: data[i] += c;
! 1158: }
! 1159: file_size = i;
! 1160: file_data = data;
! 1161: data[file_size] = 0;
! 1162:
! 1163: fclose(ifp);
! 1164:
! 1165: if (file_size > 0 && data[0] != '\\' && data[0] != '@')
! 1166: {
! 1167: error ("%s: not a texinfo index file", infile);
! 1168: return;
! 1169: }
! 1170:
! 1171: init_char_order ();
! 1172:
! 1173: /* Sort routines want to know this address. */
! 1174:
! 1175: text_base = data;
! 1176:
! 1177: /* Create the array of pointers to lines, with a default size
! 1178: frequently enough. */
! 1179:
! 1180: nlines = total / 50;
! 1181: if (!nlines)
! 1182: nlines = 2;
! 1183: linearray = (u_short **) xmalloc (nlines * sizeof (u_short *));
! 1184:
! 1185: /* `nextline' points to the next free slot in this array.
! 1186: `nlines' is the allocated size. */
! 1187:
! 1188: nextline = linearray;
! 1189:
! 1190: /* Parse the input file's data, and make entries for the lines. */
! 1191:
! 1192: nextline = parsefile (nextline, file_data, file_size);
! 1193:
! 1194: if (nextline == 0)
! 1195: {
! 1196: error ("%s: not a texinfo index file", infile);
! 1197: return;
! 1198: }
! 1199:
! 1200: /* Sort the lines. */
! 1201:
! 1202: /* If we have enough space, find the first keyfield of each line in advance.
! 1203: Make a `struct lineinfo' for each line, which records the keyfield
! 1204: as well as the line, and sort them. */
! 1205:
! 1206: lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo));
! 1207:
! 1208: if (lineinfo)
! 1209: {
! 1210: struct lineinfo *lp;
! 1211: u_short **p;
! 1212:
! 1213: for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
! 1214: {
! 1215: lp->text = *p;
! 1216: lp->key.text = find_field (keyfields, *p, &lp->keylen);
! 1217: if (keyfields->numeric)
! 1218: lp->key.number = find_value (lp->key.text, lp->keylen);
! 1219: }
! 1220:
! 1221: qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared);
! 1222:
! 1223: for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
! 1224: *p = lp->text;
! 1225:
! 1226: free (lineinfo);
! 1227: }
! 1228: else
! 1229: qsort (linearray, nextline - linearray, sizeof (u_short *), compare_full);
! 1230:
! 1231: /* Open the output file. */
! 1232:
! 1233: if (outfile)
! 1234: {
! 1235: ostream = fopen (outfile, "w");
! 1236: if (!ostream)
! 1237: pfatal_with_name (outfile);
! 1238: }
! 1239:
! 1240: writelines (linearray, nextline - linearray, ostream);
! 1241: if (outfile)
! 1242: fclose (ostream);
! 1243:
! 1244: free (linearray);
! 1245: free (data);
! 1246: }
! 1247:
! 1248: /* Parse an input string in core into lines.
! 1249: DATA is the input string, and SIZE is its length.
! 1250: Data goes in LINEARRAY starting at NEXTLINE.
! 1251: The value returned is the first entry in LINEARRAY still unused.
! 1252: Value 0 means input file contents are invalid. */
! 1253:
! 1254: u_short **
! 1255: parsefile (nextline, data, size)
! 1256: u_short **nextline;
! 1257: u_short *data;
! 1258: long size;
! 1259: {
! 1260: u_short *p, *end;
! 1261: u_short **line = nextline;
! 1262:
! 1263: p = data;
! 1264: end = p + size;
! 1265: *end = 0;
! 1266:
! 1267: while (p != end)
! 1268: {
! 1269: if (p[0] != '\\' && p[0] != '@')
! 1270: return 0;
! 1271:
! 1272: *line = p;
! 1273: while (*p && *p != '\n')
! 1274: p++;
! 1275: if (p != end)
! 1276: p++;
! 1277:
! 1278: line++;
! 1279: if (line == linearray + nlines)
! 1280: {
! 1281: u_short **old = linearray;
! 1282: linearray =
! 1283: (u_short **) xrealloc (linearray,
! 1284: sizeof (u_short *) * (nlines *= 4));
! 1285: line += linearray - old;
! 1286: }
! 1287: }
! 1288:
! 1289: return line;
! 1290: }
! 1291:
! 1292: /* Indexification is a filter applied to the sorted lines
! 1293: as they are being written to the output file.
! 1294: Multiple entries for the same name, with different page numbers,
! 1295: get combined into a single entry with multiple page numbers.
! 1296: The first braced field, which is used for sorting, is discarded.
! 1297: However, its first character is examined, folded to lower case,
! 1298: and if it is different from that in the previous line fed to us
! 1299: a \initial line is written with one argument, the new initial.
! 1300:
! 1301: If an entry has four braced fields, then the second and third
! 1302: constitute primary and secondary names.
! 1303: In this case, each change of primary name
! 1304: generates a \primary line which contains only the primary name,
! 1305: and in between these are \secondary lines which contain
! 1306: just a secondary name and page numbers. */
! 1307:
! 1308: /* The last primary name we wrote a \primary entry for.
! 1309: If only one level of indexing is being done, this is the last name seen. */
! 1310: u_short *lastprimary;
! 1311: /* Length of storage allocated for lastprimary. */
! 1312: int lastprimarylength;
! 1313:
! 1314: /* Similar, for the secondary name. */
! 1315: u_short *lastsecondary;
! 1316: int lastsecondarylength;
! 1317:
! 1318: /* Zero if we are not in the middle of writing an entry.
! 1319: One if we have written the beginning of an entry but have not
! 1320: yet written any page numbers into it.
! 1321: Greater than one if we have written the beginning of an entry
! 1322: plus at least one page number. */
! 1323: int pending;
! 1324:
! 1325: /* The initial (for sorting purposes) of the last primary entry written.
! 1326: When this changes, a \initial {c} line is written */
! 1327:
! 1328: u_short *lastinitial;
! 1329:
! 1330: int lastinitiallength;
! 1331:
! 1332: /* When we need a string of length 1 for the value of lastinitial,
! 1333: store it here. */
! 1334:
! 1335: u_short lastinitial1[2];
! 1336:
! 1337: /* Initialize static storage for writing an index. */
! 1338:
! 1339: void
! 1340: init_index ()
! 1341: {
! 1342: pending = 0;
! 1343: lastinitial = lastinitial1;
! 1344: lastinitial1[0] = 0;
! 1345: lastinitial1[1] = 0;
! 1346: lastinitiallength = 0;
! 1347: lastprimarylength = 100;
! 1348: lastprimary = (u_short *) xmalloc ((lastprimarylength + 1)*sizeof(u_short));
! 1349: memset (lastprimary, '\0', (lastprimarylength + 1)*sizeof(u_short));
! 1350: lastsecondarylength = 100;
! 1351: lastsecondary =
! 1352: (u_short *) xmalloc ((lastsecondarylength + 1)*sizeof(u_short));
! 1353: memset (lastsecondary, '\0', (lastsecondarylength + 1)*sizeof(u_short));
! 1354: }
! 1355:
! 1356: /* Indexify. Merge entries for the same name,
! 1357: insert headers for each initial character, etc. */
! 1358:
! 1359: void
! 1360: indexify (u_short *line, FILE *ostream)
! 1361: {
! 1362: u_short *primary, *secondary, *pagenumber;
! 1363: int primarylength, secondarylength = 0, pagelength;
! 1364: int nosecondary;
! 1365: int initiallength;
! 1366: u_short *initial;
! 1367: u_short initial1[2];
! 1368: register u_short *p;
! 1369:
! 1370: /* First, analyze the parts of the entry fed to us this time. */
! 1371:
! 1372: p = find_braced_pos (line, 0, 0, 0);
! 1373: if (*p == '{')
! 1374: {
! 1375: initial = p;
! 1376: /* Get length of inner pair of braces starting at `p',
! 1377: including that inner pair of braces. */
! 1378: initiallength = find_braced_end (p + 1) + 1 - p;
! 1379: }
! 1380: else
! 1381: {
! 1382: initial = initial1;
! 1383: initial1[0] = *p & 0x7F7F;
! 1384: initial1[1] = 0;
! 1385: initiallength = 1;
! 1386:
! 1387: if (initial1[0] >= 'a' && initial1[0] <= 'z')
! 1388: initial1[0] -= ' ';
! 1389: else if (initial1[0] > 0x2000)
! 1390: initial1[0] = char_order[initial1[0]];
! 1391: }
! 1392:
! 1393: pagenumber = find_braced_pos (line, 1, 0, 0);
! 1394: pagelength = find_braced_end (pagenumber) - pagenumber;
! 1395: if (pagelength == 0)
! 1396: abort ();
! 1397:
! 1398: primary = find_braced_pos (line, 2, 0, 0);
! 1399: primarylength = find_braced_end (primary) - primary;
! 1400:
! 1401: secondary = find_braced_pos (line, 3, 0, 0);
! 1402: nosecondary = !*secondary;
! 1403: if (!nosecondary)
! 1404: secondarylength = find_braced_end (secondary) - secondary;
! 1405:
! 1406: /* If the primary is different from before, make a new primary entry. */
! 1407: if (wstrncmp (primary, lastprimary, primarylength))
! 1408: {
! 1409: /* Close off current secondary entry first, if one is open. */
! 1410: if (pending)
! 1411: {
! 1412: fputs ("}\n", ostream);
! 1413: pending = 0;
! 1414: }
! 1415:
! 1416: /* If this primary has a different initial, include an entry for
! 1417: the initial. */
! 1418: if (initiallength != lastinitiallength ||
! 1419: (*initial && wstrncmp (initial, lastinitial, initiallength)))
! 1420: {
! 1421: fprintf (ostream, "\\initial {");
! 1422: wfwrite (initial, initiallength, 1, ostream);
! 1423: fprintf (ostream, "}\n", initial);
! 1424: if (initial == initial1)
! 1425: {
! 1426: lastinitial = lastinitial1;
! 1427: *lastinitial1 = *initial1;
! 1428: }
! 1429: else
! 1430: {
! 1431: lastinitial = initial;
! 1432: }
! 1433: lastinitiallength = initiallength;
! 1434: }
! 1435:
! 1436: /* Make the entry for the primary. */
! 1437: if (nosecondary)
! 1438: fputs ("\\entry {", ostream);
! 1439: else
! 1440: fputs ("\\primary {", ostream);
! 1441: wfwrite (primary, primarylength, 1, ostream);
! 1442: if (nosecondary)
! 1443: {
! 1444: fputs ("}{", ostream);
! 1445: pending = 1;
! 1446: }
! 1447: else
! 1448: fputs ("}\n", ostream);
! 1449:
! 1450: /* Record name of most recent primary. */
! 1451: if (lastprimarylength < primarylength)
! 1452: {
! 1453: lastprimarylength = primarylength + 100;
! 1454: lastprimary =
! 1455: (u_short *) xrealloc (lastprimary,
! 1456: (1 + lastprimarylength)*sizeof(u_short));
! 1457: }
! 1458: memcpy (lastprimary, primary, primarylength*sizeof(u_short));
! 1459: lastprimary[primarylength] = 0;
! 1460:
! 1461: /* There is no current secondary within this primary, now. */
! 1462: lastsecondary[0] = 0;
! 1463: }
! 1464:
! 1465: /* Should not have an entry with no subtopic following one with a subtopic. */
! 1466:
! 1467: if (nosecondary && *lastsecondary)
! 1468: {
! 1469: char tline[2001];
! 1470: int len;
! 1471:
! 1472: len = wtoc(tline, line, 2000); /* 2000 is much enough ? */
! 1473: tline[len] = '\0';
! 1474: error ("entry %s follows an entry with a secondary name", tline);
! 1475: }
! 1476:
! 1477: /* Start a new secondary entry if necessary. */
! 1478: if (!nosecondary && wstrncmp (secondary, lastsecondary, secondarylength))
! 1479: {
! 1480: if (pending)
! 1481: {
! 1482: fputs ("}\n", ostream);
! 1483: pending = 0;
! 1484: }
! 1485:
! 1486: /* Write the entry for the secondary. */
! 1487: fputs ("\\secondary {", ostream);
! 1488: wfwrite (secondary, secondarylength, 1, ostream);
! 1489: fputs ("}{", ostream);
! 1490: pending = 1;
! 1491:
! 1492: /* Record name of most recent secondary. */
! 1493: if (lastsecondarylength < secondarylength)
! 1494: {
! 1495: lastsecondarylength = secondarylength + 100;
! 1496: lastsecondary =
! 1497: (u_short *) xrealloc ((lastsecondary,
! 1498: 1 + lastsecondarylength)*sizeof(u_short));
! 1499: }
! 1500: memcpy (lastsecondary, secondary, secondarylength * sizeof(u_short));
! 1501: lastsecondary[secondarylength] = 0;
! 1502: }
! 1503:
! 1504: /* Here to add one more page number to the current entry. */
! 1505: if (pending++ != 1)
! 1506: fputs (", ", ostream); /* Punctuate first, if this is not the first. */
! 1507: wfwrite (pagenumber, pagelength, 1, ostream);
! 1508: }
! 1509:
! 1510: /* Close out any unfinished output entry. */
! 1511:
! 1512: void
! 1513: finish_index (ostream)
! 1514: FILE *ostream;
! 1515: {
! 1516: if (pending)
! 1517: fputs ("}\n", ostream);
! 1518: free (lastprimary);
! 1519: free (lastsecondary);
! 1520: }
! 1521:
! 1522: /* Copy the lines in the sorted order.
! 1523: Each line is copied out of the input file it was found in. */
! 1524:
! 1525: void
! 1526: writelines (linearray, nlines, ostream)
! 1527: u_short **linearray;
! 1528: int nlines;
! 1529: FILE *ostream;
! 1530: {
! 1531: u_short **stop_line = linearray + nlines;
! 1532: u_short **next_line;
! 1533:
! 1534: init_index ();
! 1535:
! 1536: /* Output the text of the lines, and free the buffer space. */
! 1537:
! 1538: for (next_line = linearray; next_line != stop_line; next_line++)
! 1539: {
! 1540: /* If -u was specified, output the line only if distinct from previous one. */
! 1541: if (next_line == linearray
! 1542: /* Compare previous line with this one, using only the
! 1543: explicitly specd keyfields. */
! 1544: || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
! 1545: {
! 1546: u_short *p = *next_line;
! 1547: u_short c;
! 1548:
! 1549: while ((c = *p++) && c != '\n')
! 1550: /* Do nothing. */ ;
! 1551: *(p - 1) = 0;
! 1552: indexify (*next_line, ostream);
! 1553: }
! 1554: }
! 1555:
! 1556: finish_index (ostream);
! 1557: }
! 1558:
! 1559: /* Assume (and optionally verify) that each input file is sorted;
! 1560: merge them and output the result.
! 1561: Returns nonzero if any input file fails to be sorted.
! 1562:
! 1563: This is the high-level interface that can handle an unlimited
! 1564: number of files. */
! 1565:
! 1566: #define MAX_DIRECT_MERGE 10
! 1567:
! 1568: int
! 1569: merge_files (infiles, nfiles, outfile)
! 1570: char **infiles;
! 1571: int nfiles;
! 1572: char *outfile;
! 1573: {
! 1574: char **tempfiles;
! 1575: int ntemps;
! 1576: int i;
! 1577: int value = 0;
! 1578: int start_tempcount = tempcount;
! 1579:
! 1580: if (nfiles <= MAX_DIRECT_MERGE)
! 1581: return merge_direct (infiles, nfiles, outfile);
! 1582:
! 1583: /* Merge groups of MAX_DIRECT_MERGE input files at a time,
! 1584: making a temporary file to hold each group's result. */
! 1585:
! 1586: ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;
! 1587: tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
! 1588: for (i = 0; i < ntemps; i++)
! 1589: {
! 1590: int nf = MAX_DIRECT_MERGE;
! 1591: if (i + 1 == ntemps)
! 1592: nf = nfiles - i * MAX_DIRECT_MERGE;
! 1593: tempfiles[i] = maketempname (++tempcount);
! 1594: value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);
! 1595: }
! 1596:
! 1597: /* All temporary files that existed before are no longer needed
! 1598: since their contents have been merged into our new tempfiles.
! 1599: So delete them. */
! 1600: flush_tempfiles (start_tempcount);
! 1601:
! 1602: /* Now merge the temporary files we created. */
! 1603:
! 1604: merge_files (tempfiles, ntemps, outfile);
! 1605:
! 1606: free (tempfiles);
! 1607:
! 1608: return value;
! 1609: }
! 1610:
! 1611: /* Assume (and optionally verify) that each input file is sorted;
! 1612: merge them and output the result.
! 1613: Returns nonzero if any input file fails to be sorted.
! 1614:
! 1615: This version of merging will not work if the number of
! 1616: input files gets too high. Higher level functions
! 1617: use it only with a bounded number of input files. */
! 1618:
! 1619: int
! 1620: merge_direct (infiles, nfiles, outfile)
! 1621: char **infiles;
! 1622: int nfiles;
! 1623: char *outfile;
! 1624: {
! 1625: struct linebuffer *lb1, *lb2;
! 1626: struct linebuffer **thisline, **prevline;
! 1627: FILE **streams;
! 1628: int i;
! 1629: int nleft;
! 1630: int lossage = 0;
! 1631: int *file_lossage;
! 1632: struct linebuffer *prev_out = 0;
! 1633: FILE *ostream = stdout;
! 1634:
! 1635: if (outfile)
! 1636: {
! 1637: ostream = fopen (outfile, "w");
! 1638: }
! 1639: if (!ostream)
! 1640: pfatal_with_name (outfile);
! 1641:
! 1642: init_index ();
! 1643:
! 1644: if (nfiles == 0)
! 1645: {
! 1646: if (outfile)
! 1647: fclose (ostream);
! 1648: return 0;
! 1649: }
! 1650:
! 1651: /* For each file, make two line buffers.
! 1652: Also, for each file, there is an element of `thisline'
! 1653: which points at any time to one of the file's two buffers,
! 1654: and an element of `prevline' which points to the other buffer.
! 1655: `thisline' is supposed to point to the next available line from the file,
! 1656: while `prevline' holds the last file line used,
! 1657: which is remembered so that we can verify that the file is properly sorted. */
! 1658:
! 1659: /* lb1 and lb2 contain one buffer each per file. */
! 1660: lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
! 1661: lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
! 1662:
! 1663: /* thisline[i] points to the linebuffer holding the next available line in file i,
! 1664: or is zero if there are no lines left in that file. */
! 1665: thisline = (struct linebuffer **)
! 1666: xmalloc (nfiles * sizeof (struct linebuffer *));
! 1667: /* prevline[i] points to the linebuffer holding the last used line
! 1668: from file i. This is just for verifying that file i is properly
! 1669: sorted. */
! 1670: prevline = (struct linebuffer **)
! 1671: xmalloc (nfiles * sizeof (struct linebuffer *));
! 1672: /* streams[i] holds the input stream for file i. */
! 1673: streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
! 1674: /* file_lossage[i] is nonzero if we already know file i is not
! 1675: properly sorted. */
! 1676: file_lossage = (int *) xmalloc (nfiles * sizeof (int));
! 1677:
! 1678: /* Allocate and initialize all that storage. */
! 1679:
! 1680: for (i = 0; i < nfiles; i++)
! 1681: {
! 1682: initbuffer (&lb1[i]);
! 1683: initbuffer (&lb2[i]);
! 1684: thisline[i] = &lb1[i];
! 1685: prevline[i] = &lb2[i];
! 1686: file_lossage[i] = 0;
! 1687: streams[i] = fopen (infiles[i], "r");
! 1688: if (!streams[i])
! 1689: pfatal_with_name (infiles[i]);
! 1690:
! 1691: readline (thisline[i], streams[i]);
! 1692: }
! 1693:
! 1694: /* Keep count of number of files not at eof. */
! 1695: nleft = nfiles;
! 1696:
! 1697: while (nleft)
! 1698: {
! 1699: struct linebuffer *best = 0;
! 1700: struct linebuffer *exch;
! 1701: int bestfile = -1;
! 1702: int i;
! 1703:
! 1704: /* Look at the next avail line of each file; choose the least one. */
! 1705:
! 1706: for (i = 0; i < nfiles; i++)
! 1707: {
! 1708: if (thisline[i] &&
! 1709: (!best ||
! 1710: 0 < compare_general (best->buffer, thisline[i]->buffer,
! 1711: (long) bestfile, (long) i, num_keyfields)))
! 1712: {
! 1713: best = thisline[i];
! 1714: bestfile = i;
! 1715: }
! 1716: }
! 1717:
! 1718: /* Output that line, unless it matches the previous one and we
! 1719: don't want duplicates. */
! 1720:
! 1721: if (!(prev_out &&
! 1722: !compare_general (prev_out->buffer,
! 1723: best->buffer, 0L, 1L, num_keyfields - 1)))
! 1724: indexify (best->buffer, ostream);
! 1725: prev_out = best;
! 1726:
! 1727: /* Now make the line the previous of its file, and fetch a new
! 1728: line from that file. */
! 1729:
! 1730: exch = prevline[bestfile];
! 1731: prevline[bestfile] = thisline[bestfile];
! 1732: thisline[bestfile] = exch;
! 1733:
! 1734: while (1)
! 1735: {
! 1736: /* If the file has no more, mark it empty. */
! 1737:
! 1738: if (feof (streams[bestfile]))
! 1739: {
! 1740: thisline[bestfile] = 0;
! 1741: /* Update the number of files still not empty. */
! 1742: nleft--;
! 1743: break;
! 1744: }
! 1745: readline (thisline[bestfile], streams[bestfile]);
! 1746: if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))
! 1747: break;
! 1748: }
! 1749: }
! 1750:
! 1751: finish_index (ostream);
! 1752:
! 1753: /* Free all storage and close all input streams. */
! 1754:
! 1755: for (i = 0; i < nfiles; i++)
! 1756: {
! 1757: fclose (streams[i]);
! 1758: free (lb1[i].buffer);
! 1759: free (lb2[i].buffer);
! 1760: }
! 1761: free (file_lossage);
! 1762: free (lb1);
! 1763: free (lb2);
! 1764: free (thisline);
! 1765: free (prevline);
! 1766: free (streams);
! 1767:
! 1768: if (outfile)
! 1769: fclose (ostream);
! 1770:
! 1771: return lossage;
! 1772: }
! 1773:
! 1774: /* Print error message and exit. */
! 1775:
! 1776: void
! 1777: fatal (format, arg)
! 1778: char *format, *arg;
! 1779: {
! 1780: error (format, arg);
! 1781: exit (TI_FATAL_ERROR);
! 1782: }
! 1783:
! 1784: /* Print error message. FORMAT is printf control string, ARG is arg for it. */
! 1785: void
! 1786: error (format, arg)
! 1787: char *format, *arg;
! 1788: {
! 1789: printf ("%s: ", program_name);
! 1790: printf (format, arg);
! 1791: if (format[strlen (format) -1] != '\n')
! 1792: printf ("\n");
! 1793: }
! 1794:
! 1795: void
! 1796: perror_with_name (name)
! 1797: char *name;
! 1798: {
! 1799: char *s;
! 1800:
! 1801: s = strerror (errno);
! 1802: printf ("%s: ", program_name);
! 1803: printf ("%s; for file `%s'.\n", s, name);
! 1804: }
! 1805:
! 1806: void
! 1807: pfatal_with_name (name)
! 1808: char *name;
! 1809: {
! 1810: char *s;
! 1811:
! 1812: s = strerror (errno);
! 1813: printf ("%s: ", program_name);
! 1814: printf ("%s; for file `%s'.\n", s, name);
! 1815: exit (TI_FATAL_ERROR);
! 1816: }
! 1817:
! 1818: /* Return a newly-allocated string whose contents concatenate those of
! 1819: S1, S2, S3. */
! 1820:
! 1821: char *
! 1822: concat (s1, s2, s3)
! 1823: char *s1, *s2, *s3;
! 1824: {
! 1825: int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
! 1826: char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
! 1827:
! 1828: strcpy (result, s1);
! 1829: strcpy (result + len1, s2);
! 1830: strcpy (result + len1 + len2, s3);
! 1831: *(result + len1 + len2 + len3) = 0;
! 1832:
! 1833: return result;
! 1834: }
! 1835:
! 1836: #if !defined (HAVE_STRERROR)
! 1837: extern char *sys_errlist[];
! 1838: extern int sys_nerr;
! 1839:
! 1840: char *
! 1841: strerror (num)
! 1842: int num;
! 1843: {
! 1844: if (num >= sys_nerr)
! 1845: return ("");
! 1846: else
! 1847: return (sys_errlist[num]);
! 1848: }
! 1849: #endif /* !HAVE_STRERROR */
! 1850:
! 1851: #if !defined (HAVE_STRCHR)
! 1852: char *
! 1853: strrchr (string, character)
! 1854: char *string;
! 1855: int character;
! 1856: {
! 1857: register int i;
! 1858:
! 1859: for (i = strlen (string) - 1; i > -1; i--)
! 1860: if (string[i] == character)
! 1861: return (string + i);
! 1862:
! 1863: return ((char *)NULL);
! 1864: }
! 1865: #endif /* HAVE_STRCHR */
! 1866:
! 1867: /* Just like malloc, but kills the program in case of fatal error. */
! 1868: void *
! 1869: xmalloc (nbytes)
! 1870: int nbytes;
! 1871: {
! 1872: void *temp = (void *) malloc (nbytes);
! 1873:
! 1874: if (nbytes && temp == (void *)NULL)
! 1875: memory_error ("xmalloc", nbytes);
! 1876:
! 1877: return (temp);
! 1878: }
! 1879:
! 1880: /* Like realloc (), but barfs if there isn't enough memory. */
! 1881: void *
! 1882: xrealloc (pointer, nbytes)
! 1883: void *pointer;
! 1884: int nbytes;
! 1885: {
! 1886: void *temp;
! 1887:
! 1888: if (!pointer)
! 1889: temp = (void *)xmalloc (nbytes);
! 1890: else
! 1891: temp = (void *)realloc (pointer, nbytes);
! 1892:
! 1893: if (nbytes && !temp)
! 1894: memory_error ("xrealloc", nbytes);
! 1895:
! 1896: return (temp);
! 1897: }
! 1898:
! 1899: void
! 1900: memory_error (callers_name, bytes_wanted)
! 1901: char *callers_name;
! 1902: int bytes_wanted;
! 1903: {
! 1904: char printable_string[80];
! 1905:
! 1906: sprintf (printable_string,
! 1907: "Virtual memory exhausted in %s ()! Needed %d bytes.",
! 1908: callers_name, bytes_wanted);
! 1909:
! 1910: error (printable_string);
! 1911: abort();
! 1912: }
! 1913:
! 1914:
! 1915: static int
! 1916: wstrncmp(const u_short *s1, const u_short *s2, size_t n)
! 1917: {
! 1918: int i;
! 1919: int d = 0;
! 1920:
! 1921: for (i=0; i<n && d == 0; i++)
! 1922: d = s1[i] - s2[i];
! 1923:
! 1924: return d;
! 1925: }
! 1926:
! 1927:
! 1928: static int
! 1929: wfwrite(u_short *ptr, size_t size, size_t nmemb, FILE*stream)
! 1930: {
! 1931: char *cptr;
! 1932: int ret, len;
! 1933:
! 1934: cptr = (char *)xmalloc(size * nmemb * sizeof(u_short)); /* 丼一杯! */
! 1935: len = wtoc(cptr, ptr, size*nmemb);
! 1936: assert(len <= (size * nmemb * sizeof(u_short)));
! 1937:
! 1938: ret = fwrite(cptr, len, nmemb, stream);
! 1939: free(cptr);
! 1940: return ret;
! 1941: }
! 1942:
! 1943:
! 1944: static int
! 1945: wtoc(char *cptr, u_short const *ptr, int len)
! 1946: {
! 1947: char *tptr;
! 1948: u_short c;
! 1949: int i;
! 1950:
! 1951: tptr = cptr;
! 1952: for (i = 0; i < len; i++)
! 1953: {
! 1954: c = ptr[i];
! 1955: if (G1_CHAR(c))
! 1956: {
! 1957: *tptr++ = c >> 8 | 0x0080; /* to EUC */
! 1958: c &= 0x007F;
! 1959: c |= 0x0080;
! 1960: }
! 1961: *tptr++ = c;
! 1962: }
! 1963:
! 1964: return tptr - cptr;
! 1965: }
! 1966:
! 1967:
! 1968: static int
! 1969: Vowel_of(int c)
! 1970: {
! 1971: if (0x2521 <= c && c < 0x2577) /* 片仮名は */
! 1972: c -= 0x100; /* 平仮名へ */
! 1973: /* ヴ、ヵ、ヶ、の3字は相当する平仮名はないが、コードがあると仮定する */
! 1974: /* 普通は問題にならない筈。 */
! 1975:
! 1976: if (0x2421 <= c && c < 0x2474)
! 1977: return Vowel_Table[c - 0x2420];
! 1978: else
! 1979: return c; /* 平仮名以外はそのまま */
! 1980: }
! 1981:
! 1982:
! 1983: static void
! 1984: init_Vowel_Table(void)
! 1985: {
! 1986: int i;
! 1987:
! 1988: /* あ〜ぞ */
! 1989: for (i = 0x2421 - 0x2420; i < 0x2445 - 0x2420; i += 10)
! 1990: {
! 1991: Vowel_Table[i] = Vowel_Table[i+1] = 0x2422; /* あ段 */
! 1992: Vowel_Table[i+2] = Vowel_Table[i+3] = 0x2424; /* い段 */
! 1993: Vowel_Table[i+4] = Vowel_Table[i+5] = 0x2426; /* う段 */
! 1994: Vowel_Table[i+6] = Vowel_Table[i+7] = 0x2428; /* え段 */
! 1995: Vowel_Table[i+8] = Vowel_Table[i+9] = 0x242A; /* お段 */
! 1996: }
! 1997: Vowel_Table[0x243F - 0x2420] = 0x2422; /* た */
! 1998: Vowel_Table[0x2440 - 0x2420] = 0x2422; /* だ */
! 1999: Vowel_Table[0x2441 - 0x2420] = 0x2424; /* ち */
! 2000: Vowel_Table[0x2442 - 0x2420] = 0x2424; /* ぢ */
! 2001: Vowel_Table[0x2443 - 0x2420] = 0x2426; /* っ */
! 2002: Vowel_Table[0x2444 - 0x2420] = 0x2426; /* つ */
! 2003: Vowel_Table[0x2445 - 0x2420] = 0x2426; /* づ */
! 2004: Vowel_Table[0x2446 - 0x2420] = 0x2428; /* て */
! 2005: Vowel_Table[0x2447 - 0x2420] = 0x2428; /* で */
! 2006: Vowel_Table[0x2448 - 0x2420] = 0x242A; /* と */
! 2007: Vowel_Table[0x2449 - 0x2420] = 0x242A; /* ど */
! 2008: Vowel_Table[0x244A - 0x2420] = 0x2422; /* な */
! 2009: Vowel_Table[0x244B - 0x2420] = 0x2424; /* に */
! 2010: Vowel_Table[0x244C - 0x2420] = 0x2426; /* ぬ */
! 2011: Vowel_Table[0x244D - 0x2420] = 0x2428; /* ね */
! 2012: Vowel_Table[0x244E - 0x2420] = 0x242A; /* の */
! 2013: /* は〜ぽ */
! 2014: for (i = 0x244F - 0x2420; i < 0x245E - 0x2420; i += 15)
! 2015: {
! 2016: Vowel_Table[i] = Vowel_Table[i+1] = Vowel_Table[i+2] = 0x2422;
! 2017: Vowel_Table[i+3] = Vowel_Table[i+4] = Vowel_Table[i+5] = 0x2424;
! 2018: Vowel_Table[i+6] = Vowel_Table[i+7] = Vowel_Table[i+8] = 0x2426;
! 2019: Vowel_Table[i+9] = Vowel_Table[i+11] = Vowel_Table[i+12] = 0x2428;
! 2020: Vowel_Table[i+12] = Vowel_Table[i+13] = Vowel_Table[i+14] = 0x242A;
! 2021: }
! 2022: Vowel_Table[0x245E - 0x2420] = 0x2422; /* ま */
! 2023: Vowel_Table[0x245F - 0x2420] = 0x2424; /* み */
! 2024: Vowel_Table[0x2460 - 0x2420] = 0x2426; /* む */
! 2025: Vowel_Table[0x2461 - 0x2420] = 0x2428; /* め */
! 2026: Vowel_Table[0x2462 - 0x2420] = 0x242A; /* も */
! 2027: Vowel_Table[0x2463 - 0x2420] = 0x2422; /* ゃ */
! 2028: Vowel_Table[0x2464 - 0x2420] = 0x2422; /* や */
! 2029: Vowel_Table[0x2465 - 0x2420] = 0x2426; /* ゅ */
! 2030: Vowel_Table[0x2466 - 0x2420] = 0x2426; /* ゆ */
! 2031: Vowel_Table[0x2467 - 0x2420] = 0x242A; /* ょ */
! 2032: Vowel_Table[0x2468 - 0x2420] = 0x242A; /* よ */
! 2033: Vowel_Table[0x2469 - 0x2420] = 0x2422; /* ら */
! 2034: Vowel_Table[0x246A - 0x2420] = 0x2424; /* り */
! 2035: Vowel_Table[0x246B - 0x2420] = 0x2426; /* る */
! 2036: Vowel_Table[0x246C - 0x2420] = 0x2428; /* れ */
! 2037: Vowel_Table[0x246D - 0x2420] = 0x242A; /* ろ */
! 2038: Vowel_Table[0x246E - 0x2420] = 0x2422; /* ゎ */
! 2039: Vowel_Table[0x246F - 0x2420] = 0x2422; /* わ */
! 2040: /* ゐ〜ヶ は、そのまま。母音への変換はしない。 */
! 2041: for (i = 0x2470 - 0x2420; i < 0x2477 - 0x2420; i++)
! 2042: Vowel_Table[i] = i;
! 2043: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>