diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /indexing/makeindexk/genind.c |
Initial commit
Diffstat (limited to 'indexing/makeindexk/genind.c')
-rw-r--r-- | indexing/makeindexk/genind.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/indexing/makeindexk/genind.c b/indexing/makeindexk/genind.c new file mode 100644 index 0000000000..1d1ba03ad5 --- /dev/null +++ b/indexing/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; +} |