/* * * This file is part of * MakeIndex - A formatter and format independent index processor * * 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 * (phc@renoir.berkeley.edu or chen@orc.olivetti.com) * * 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" #if sun /* avoid conflict with symbol in */ /* /usr/lang/SC1.0/include/CC/stdlib.h */ #define end the_end #endif static FIELD_PTR curr = NULL; static FIELD_PTR prev = NULL; static FIELD_PTR begin = NULL; static FIELD_PTR 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 ARGS((int print)); static void insert_page ARGS((void)); static int make_entry ARGS((int n)); static void make_item ARGS((char* term)); static void new_entry ARGS((void)); static void old_entry ARGS((void)); static int page_diff ARGS((struct KFIELD *a,struct KFIELD *b)); static void put_header ARGS((int let)); static void wrap_line ARGS((int print)); void gen_ind(VOID_ARG) { int n; int tmp_lc; MESSAGE("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_ERROR("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 #if STDC make_entry(int n) #else make_entry(n) int n; #endif { 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(); else old_entry(); } if (*curr->encap == idx_ropen) if (in_range) { IND_ERROR("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_ERROR("Range closing operator has an inconsistent encapsulator %s.\n", &(curr->encap[1])); } } else { IND_ERROR("Unmatched range closing operator %c.\n", idx_rclose); } else if ((*curr->encap != NUL) && STRNEQ(curr->encap, prev_encap) && in_range) IND_ERROR("Inconsistent page encapsulator %s within range.\n", curr->encap); return (1); } static void #if STDC make_item(char *term) #else make_item(term) char *term; #endif { 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 */ i++; } ind_indent = 0; strcat(line, delim_p[level]); SAVE; } static void new_entry(VOID_ARG) { int let; FIELD_PTR ptr; if (in_range) { ptr = curr; curr = range_ptr; IND_ERROR("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 = TOLOWER(curr->sf[0][0])) != (TOLOWER(prev->sf[0][0])))) || (german_sort && (curr->group != ALPHA) && (prev->group == ALPHA))) { PUT(delim_t); PUT(group_skip); ind_lc += skiplen; /* beginning of a new letter? */ put_header(let); make_item(NIL); } else make_item(delim_t); } static void old_entry(VOID_ARG) { int diff; /* current entry identical to previous one: append pages */ diff = page_diff(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)) { 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 #if STDC page_diff(FIELD_PTR a,FIELD_PTR b) #else page_diff(a, b) FIELD_PTR a; FIELD_PTR b; #endif { 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 #if STDC put_header(int let) #else put_header(let) int let; #endif { 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 #if STDC flush_line(int print) #else flush_line(print) int print; #endif { char tmp[sizeof(buff)]; if (page_diff(begin, end) != 0) if (encap_range || (page_diff(begin, prev) > (*suffix_2p ? 0 : 1))) { int diff = page_diff(begin, 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, end->lpg); encap_range = FALSE; } else sprintf(buff, "%s%s%s", begin->lpg, delim_n, 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 #if STDC wrap_line(int print) #else wrap_line(print) int print; #endif { 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_ARG) { 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(pageno[--i]) && i > 0); if (!isdigit(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; }