summaryrefslogtreecommitdiff
path: root/Build/source/texk/makeindexk/genind.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/makeindexk/genind.c')
-rw-r--r--Build/source/texk/makeindexk/genind.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/Build/source/texk/makeindexk/genind.c b/Build/source/texk/makeindexk/genind.c
new file mode 100644
index 00000000000..1d1ba03ad51
--- /dev/null
+++ b/Build/source/texk/makeindexk/genind.c
@@ -0,0 +1,470 @@
+/*
+ *
+ * This file is part of
+ * MakeIndex - A formatter and format independent index processor
+ *
+ * Copyright (C) 1998-2011 by the TeX Live project.
+ * Copyright (C) 1989 by Chen & Harrison International Systems, Inc.
+ * Copyright (C) 1988 by Olivetti Research Center
+ * Copyright (C) 1987 by Regents of the University of California
+ *
+ * Author:
+ * Pehong Chen
+ * Chen & Harrison International Systems, Inc.
+ * Palo Alto, California
+ * USA
+ *
+ * Contributors:
+ * Please refer to the CONTRIB file that comes with this release
+ * for a list of people who have contributed to this and/or previous
+ * release(s) of MakeIndex.
+ *
+ * All rights reserved by the copyright holders. See the copyright
+ * notice distributed with this software for a complete description of
+ * the conditions under which it is made available.
+ *
+ */
+
+#include "mkind.h"
+#include "genind.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+static FIELD_PTR curr = NULL;
+static FIELD_PTR prev = NULL;
+static FIELD_PTR begin = NULL;
+static FIELD_PTR the_end = NULL;
+static FIELD_PTR range_ptr;
+static int level = 0;
+static int prev_level = 0;
+static char *encap = NULL;
+static char *prev_encap = NULL;
+static int in_range = FALSE;
+static int encap_range = FALSE;
+static char buff[2 * ARGUMENT_MAX];
+static char line[2 * ARGUMENT_MAX]; /* output buffer */
+static int ind_lc = 0; /* overall line count */
+static int ind_ec = 0; /* erroneous line count */
+static int ind_indent;
+
+static void flush_line (int print);
+static void insert_page (void);
+static int make_entry (int n);
+static void make_item (const char* term);
+static unsigned char first_letter (char* term);
+static void new_entry (void);
+static void old_entry (void);
+static int page_diff (struct KFIELD *a,struct KFIELD *b);
+static void put_header (int let);
+static void wrap_line (int print);
+
+void
+gen_ind(void)
+{
+ int n;
+ int tmp_lc;
+
+ MESSAGE1("Generating output file %s...", ind_fn);
+ PUT(preamble);
+ ind_lc += prelen;
+ if (init_page)
+ insert_page();
+
+ /* reset counters for putting out dots */
+ idx_dc = 0;
+ for (n = 0; n < idx_gt; n++) {
+ if (idx_key[n]->type != DUPLICATE)
+ if (make_entry(n)) {
+ IDX_DOT(DOT_MAX);
+ }
+ }
+ tmp_lc = ind_lc;
+ if (in_range) {
+ curr = range_ptr;
+ IND_ERROR1("Unmatched range opening operator %c.\n", idx_ropen);
+ }
+ prev = curr;
+ flush_line(TRUE);
+ PUT(delim_t);
+ PUT(postamble);
+ tmp_lc = ind_lc + postlen;
+ if (ind_ec == 1) {
+ DONE(tmp_lc, "lines written", ind_ec, "warning");
+ } else {
+ DONE(tmp_lc, "lines written", ind_ec, "warnings");
+ }
+}
+
+
+static int
+make_entry(int n)
+{
+ int let;
+
+ /* determine current and previous pointer */
+ prev = curr;
+ curr = idx_key[n];
+ /* check if current entry is in range */
+ if ((*curr->encap == idx_ropen) || (*curr->encap == idx_rclose))
+ encap = &(curr->encap[1]);
+ else
+ encap = curr->encap;
+
+ /* determine the current nesting level */
+ if (n == 0) {
+ prev_level = level = 0;
+ let = *curr->sf[0];
+ put_header(let);
+ make_item(NIL);
+ } else {
+ prev_level = level;
+ for (level = 0; level < FIELD_MAX; level++)
+ if (STRNEQ(curr->sf[level], prev->sf[level]) ||
+ STRNEQ(curr->af[level], prev->af[level]))
+ break;
+ if (level < FIELD_MAX)
+ new_entry();
+
+ /* Repeat test from just below to see if we are already in an
+ open range. If so, we don't want to output anything. (It
+ ends up being output as an erroneous \(. See
+ tests/nested-range-bb.tex.) */
+ else if (! (*curr->encap == idx_ropen && in_range)) {
+ old_entry();
+ }
+ }
+
+ if (*curr->encap == idx_ropen)
+ if (in_range) {
+ IND_ERROR1("Extra range opening operator %c.\n", idx_ropen);
+ } else {
+ in_range = TRUE;
+ range_ptr = curr;
+ }
+ else if (*curr->encap == idx_rclose)
+ if (in_range) {
+ in_range = FALSE;
+ if (STRNEQ(&(curr->encap[1]), "") &&
+ STRNEQ(prev_encap, &(curr->encap[1]))) {
+IND_ERROR1("Range closing operator has an inconsistent encapsulator %s.\n",
+ &(curr->encap[1]));
+ }
+ } else {
+ IND_ERROR1("Unmatched range closing operator %c.\n", idx_rclose);
+ }
+ else if ((*curr->encap != NUL) &&
+ STRNEQ(curr->encap, prev_encap) && in_range)
+ IND_ERROR1("Inconsistent page encapsulator %s within range.\n",
+ curr->encap);
+ return (1);
+}
+
+
+static void
+make_item(const char *term)
+{
+ int i;
+
+ if (level > prev_level) {
+ /* ascending level */
+ if (*curr->af[level] == NUL)
+ sprintf(line, "%s%s%s", term, item_u[level], curr->sf[level]);
+ else
+ sprintf(line, "%s%s%s", term, item_u[level], curr->af[level]);
+ ind_lc += ilen_u[level];
+ } else {
+ /* same or descending level */
+ if (*curr->af[level] == NUL)
+ sprintf(line, "%s%s%s", term, item_r[level], curr->sf[level]);
+ else
+ sprintf(line, "%s%s%s", term, item_r[level], curr->af[level]);
+ ind_lc += ilen_r[level];
+ }
+
+ i = level + 1;
+ while (i < FIELD_MAX && *curr->sf[i] != NUL) {
+ PUT(line);
+ if (*curr->af[i] == NUL)
+ sprintf(line, "%s%s", item_x[i], curr->sf[i]);
+ else
+ sprintf(line, "%s%s", item_x[i], curr->af[i]);
+ ind_lc += ilen_x[i];
+ level = i; /* Added at 2.11 <brosig@gmdzi.gmd.de> */
+ i++;
+ }
+
+ ind_indent = 0;
+ strcat(line, delim_p[level]);
+ SAVE;
+}
+
+static unsigned char
+first_letter(char *term)
+{
+ if (thai_sort)
+ return strchr("\340\341\342\343\344", term[0]) ? term[1] : term[0];
+
+ return TOLOWER(term[0]);
+}
+
+static void
+new_entry(void)
+{
+ int let = -1; /* see comment below */
+ FIELD_PTR ptr;
+#ifdef HAVE_SETLOCALE
+ char *prev_locale;
+ prev_locale = setlocale(LC_CTYPE, NULL);
+ setlocale(LC_CTYPE, "");
+#endif
+
+ if (in_range) {
+ ptr = curr;
+ curr = range_ptr;
+ IND_ERROR1("Unmatched range opening operator %c.\n", idx_ropen);
+ in_range = FALSE;
+ curr = ptr;
+ }
+ flush_line(TRUE);
+
+ /* beginning of a new group? */
+
+ if (((curr->group != ALPHA) && (curr->group != prev->group) &&
+ (prev->group == SYMBOL)) ||
+ ((curr->group == ALPHA) &&
+ ((unsigned char)(let = first_letter(curr->sf[0]))
+ != first_letter(prev->sf[0]))) ||
+ (german_sort &&
+ (curr->group != ALPHA) && (prev->group == ALPHA))) {
+ PUT(delim_t);
+ PUT(group_skip);
+ ind_lc += skiplen;
+ /* beginning of a new letter? */
+ /* Although we may use let unassigned here, it doesn't matter,
+ because put_header will not use its arg except in case
+ ALPHA, when it is assigned in the midst of condition above.
+ Let's not perturb the logic, just initialize it (above) to
+ avoid the warning. */
+ put_header(let);
+ make_item(NIL);
+ } else
+ make_item(delim_t);
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_CTYPE, prev_locale);
+#endif
+}
+
+
+static void
+old_entry(void)
+{
+ int diff;
+
+ /* current entry identical to previous one: append pages */
+ diff = page_diff(the_end, curr);
+
+ if ((prev->type == curr->type) && (diff != -1) &&
+ (((diff == 0) && (prev_encap != NULL) && STREQ(encap, prev_encap)) ||
+ (merge_page && (diff == 1) &&
+ (prev_encap != NULL) && STREQ(encap, prev_encap)) ||
+ in_range)) {
+ the_end = curr;
+ /* extract in-range encaps out */
+ if (in_range &&
+ (*curr->encap != NUL) &&
+ (*curr->encap != idx_rclose) &&
+ STRNEQ(curr->encap, prev_encap)) {
+ sprintf(buff, "%s%s%s%s%s", encap_p, curr->encap,
+ encap_i, curr->lpg, encap_s);
+ wrap_line(FALSE);
+ }
+ if (in_range)
+ encap_range = TRUE;
+ } else {
+ flush_line(FALSE);
+ if ((diff == 0) && (prev->type == curr->type)) {
+IND_ERROR(
+"Conflicting entries: multiple encaps for the same page under same key.\n");
+ } else if (in_range && (prev->type != curr->type)) {
+IND_ERROR(
+"Illegal range formation: starting & ending pages are of different types.\n");
+ } else if (in_range && (diff == -1)) {
+IND_ERROR(
+"Illegal range formation: starting & ending pages cross chap/sec breaks.\n");
+ }
+ SAVE;
+ }
+}
+
+
+static int
+page_diff(FIELD_PTR a,FIELD_PTR b)
+{
+ short i;
+
+ if (a->count != b->count)
+ return (-1);
+ for (i = 0; i < a->count - 1; i++)
+ if (a->npg[i] != b->npg[i])
+ return (-1);
+ return (b->npg[b->count - 1] - a->npg[a->count - 1]);
+}
+
+static void
+put_header(int let)
+{
+ if (headings_flag)
+ {
+ PUT(heading_pre);
+ ind_lc += headprelen;
+ switch (curr->group)
+ {
+ case SYMBOL:
+ if (headings_flag > 0)
+ {
+ PUT(symhead_pos);
+ }
+ else
+ {
+ PUT(symhead_neg);
+ }
+ break;
+ case ALPHA:
+ if (headings_flag > 0)
+ {
+ let = TOUPPER(let);
+ PUTC(let);
+ }
+ else
+ {
+ let = TOLOWER(let);
+ PUTC(let);
+ }
+ break;
+ default:
+ if (headings_flag > 0)
+ {
+ PUT(numhead_pos);
+ }
+ else
+ {
+ PUT(numhead_neg);
+ }
+ break;
+ }
+ PUT(heading_suf);
+ ind_lc += headsuflen;
+ }
+}
+
+
+/* changes for 2.12 (May 20, 1993) by Julian Reschke (jr@ms.maus.de):
+ Use keywords suffix_2p, suffix_3p or suffix_mp for one, two or
+ multiple page ranges (when defined) */
+
+static void
+flush_line(int print)
+{
+ char tmp[sizeof(buff)];
+
+ if (page_diff(begin, the_end) != 0)
+ if (encap_range || (page_diff(begin, prev) > (*suffix_2p ? 0 : 1)))
+ {
+ int diff = page_diff(begin, the_end);
+
+ if ((diff == 1) && *suffix_2p)
+ sprintf(buff, "%s%s", begin->lpg, suffix_2p);
+ else if ((diff == 2) && *suffix_3p)
+ sprintf(buff, "%s%s", begin->lpg, suffix_3p);
+ else if ((diff >= 2) && *suffix_mp)
+ sprintf(buff, "%s%s", begin->lpg, suffix_mp);
+ else
+ sprintf(buff, "%s%s%s", begin->lpg, delim_r, the_end->lpg);
+
+ encap_range = FALSE;
+ }
+ else
+ sprintf(buff, "%s%s%s", begin->lpg, delim_n, the_end->lpg);
+ else
+ {
+ encap_range = FALSE; /* might be true from page range on same page */
+ strcpy(buff, begin->lpg);
+ }
+
+ if (*prev_encap != NUL)
+ {
+ strcpy(tmp, buff);
+ sprintf(buff, "%s%s%s%s%s",
+ encap_p, prev_encap, encap_i, tmp, encap_s);
+ }
+ wrap_line(print);
+}
+
+static void
+wrap_line(int print)
+{
+ int len;
+
+ len = strlen(line) + strlen(buff) + ind_indent;
+ if (print) {
+ if (len > linemax) {
+ PUTLN(line);
+ PUT(indent_space);
+ ind_indent = indent_length;
+ } else
+ PUT(line);
+ PUT(buff);
+ } else {
+ if (len > linemax) {
+ PUTLN(line);
+ sprintf(line, "%s%s%s", indent_space, buff, delim_n);
+ ind_indent = indent_length;
+ } else {
+ strcat(buff, delim_n);
+ strcat(line, buff);
+ }
+ }
+}
+
+
+static void
+insert_page(void)
+{
+ int i = 0;
+ int j = 0;
+ int page = 0;
+
+ if (even_odd >= 0) {
+ /* find the rightmost digit */
+ while (pageno[i++] != NUL);
+ j = --i;
+ /* find the leftmost digit */
+ while (isdigit((unsigned char)pageno[--i]) && i > 0);
+ if (!isdigit((unsigned char)pageno[i]))
+ i++;
+ /* convert page from literal to numeric */
+ page = strtoint(&pageno[i]) + 1;
+ /* check even-odd numbering */
+ if (((even_odd == 1) && (page % 2 == 0)) ||
+ ((even_odd == 2) && (page % 2 == 1)))
+ page++;
+ pageno[j + 1] = NUL;
+ /* convert page back to literal */
+ while (page >= 10) {
+ pageno[j--] = TOASCII(page % 10);
+ page = page / 10;
+ }
+ pageno[j] = TOASCII(page);
+ if (i < j) {
+ while (pageno[j] != NUL)
+ pageno[i++] = pageno[j++];
+ pageno[i] = NUL;
+ }
+ }
+ PUT(setpage_open);
+ PUT(pageno);
+ PUT(setpage_close);
+ ind_lc += setpagelen;
+}