Back to index

tetex-bin  3.0
genind.c
Go to the documentation of this file.
00001 /*
00002  *
00003  *  This file is part of
00004  *     MakeIndex - A formatter and format independent index processor
00005  *
00006  *  Copyright (C) 1989 by Chen & Harrison International Systems, Inc.
00007  *  Copyright (C) 1988 by Olivetti Research Center
00008  *  Copyright (C) 1987 by Regents of the University of California
00009  *
00010  *  Author:
00011  *     Pehong Chen
00012  *     Chen & Harrison International Systems, Inc.
00013  *     Palo Alto, California
00014  *     USA
00015  *     (phc@renoir.berkeley.edu or chen@orc.olivetti.com)
00016  *
00017  *  Contributors:
00018  *     Please refer to the CONTRIB file that comes with this release
00019  *     for a list of people who have contributed to this and/or previous
00020  *     release(s) of MakeIndex.
00021  *
00022  *  All rights reserved by the copyright holders.  See the copyright
00023  *  notice distributed with this software for a complete description of
00024  *  the conditions under which it is made available.
00025  *
00026  */
00027 
00028 #include    "mkind.h"
00029 #include    "genind.h"
00030 
00031 #ifdef HAVE_LOCALE_H
00032 #include <locale.h>
00033 #endif
00034 
00035 static FIELD_PTR curr = NULL;
00036 static FIELD_PTR prev = NULL;
00037 static FIELD_PTR begin = NULL;
00038 static FIELD_PTR the_end = NULL;
00039 static FIELD_PTR range_ptr;
00040 static int level = 0;
00041 static int prev_level = 0;
00042 static char *encap = NULL;
00043 static char *prev_encap = NULL;
00044 static int in_range = FALSE;
00045 static int encap_range = FALSE;
00046 static char buff[2 * ARGUMENT_MAX];
00047 static char line[2 * ARGUMENT_MAX];       /* output buffer */
00048 static int ind_lc = 0;                    /* overall line count */
00049 static int ind_ec = 0;                    /* erroneous line count */
00050 static int ind_indent;
00051 
00052 static void   flush_line ARGS((int print));
00053 static void   insert_page ARGS((void));
00054 static int    make_entry ARGS((int n));
00055 static void   make_item ARGS((char* term));
00056 static  unsigned char first_letter ARGS((char* term));
00057 static void   new_entry ARGS((void));
00058 static void   old_entry ARGS((void));
00059 static int    page_diff ARGS((struct KFIELD *a,struct KFIELD *b));
00060 static void   put_header ARGS((int let));
00061 static void   wrap_line ARGS((int print));
00062 
00063 void
00064 gen_ind(VOID_ARG)
00065 {
00066     int     n;
00067     int     tmp_lc;
00068 
00069     MESSAGE("Generating output file %s...", ind_fn);
00070     PUT(preamble);
00071     ind_lc += prelen;
00072     if (init_page)
00073        insert_page();
00074 
00075     /* reset counters for putting out dots */
00076     idx_dc = 0;
00077     for (n = 0; n < idx_gt; n++) {
00078        if (idx_key[n]->type != DUPLICATE)
00079            if (make_entry(n)) {
00080               IDX_DOT(DOT_MAX);
00081            }
00082     }
00083     tmp_lc = ind_lc;
00084     if (in_range) {
00085        curr = range_ptr;
00086        IND_ERROR("Unmatched range opening operator %c.\n", idx_ropen);
00087     }
00088     prev = curr;
00089     flush_line(TRUE);
00090     PUT(delim_t);
00091     PUT(postamble);
00092     tmp_lc = ind_lc + postlen;
00093     if (ind_ec == 1) {
00094        DONE(tmp_lc, "lines written", ind_ec, "warning");
00095     } else {
00096        DONE(tmp_lc, "lines written", ind_ec, "warnings");
00097     }
00098 }
00099 
00100 
00101 static int
00102 #if STDC
00103 make_entry(int n)
00104 #else
00105 make_entry(n)
00106 int     n;
00107 #endif
00108 {
00109     int     let;
00110 
00111     /* determine current and previous pointer */
00112     prev = curr;
00113     curr = idx_key[n];
00114     /* check if current entry is in range */
00115     if ((*curr->encap == idx_ropen) || (*curr->encap == idx_rclose))
00116        encap = &(curr->encap[1]);
00117     else
00118        encap = curr->encap;
00119 
00120     /* determine the current nesting level */
00121     if (n == 0) {
00122        prev_level = level = 0;
00123        let = *curr->sf[0];
00124        put_header(let);
00125        make_item(NIL);
00126     } else {
00127        prev_level = level;
00128        for (level = 0; level < FIELD_MAX; level++)
00129            if (STRNEQ(curr->sf[level], prev->sf[level]) ||
00130               STRNEQ(curr->af[level], prev->af[level]))
00131               break;
00132        if (level < FIELD_MAX)
00133            new_entry();
00134        else
00135            old_entry();
00136     }
00137 
00138     if (*curr->encap == idx_ropen)
00139        if (in_range) {
00140            IND_ERROR("Extra range opening operator %c.\n", idx_ropen);
00141        } else {
00142            in_range = TRUE;
00143            range_ptr = curr;
00144        }
00145     else if (*curr->encap == idx_rclose)
00146        if (in_range) {
00147            in_range = FALSE;
00148            if (STRNEQ(&(curr->encap[1]), "") &&
00149               STRNEQ(prev_encap, &(curr->encap[1]))) {
00150 IND_ERROR("Range closing operator has an inconsistent encapsulator %s.\n",
00151                        &(curr->encap[1]));
00152            }
00153        } else {
00154            IND_ERROR("Unmatched range closing operator %c.\n", idx_rclose);
00155        }
00156     else if ((*curr->encap != NUL) &&
00157             STRNEQ(curr->encap, prev_encap) && in_range)
00158        IND_ERROR("Inconsistent page encapsulator %s within range.\n",
00159                 curr->encap);
00160     return (1);
00161 }
00162 
00163 
00164 static void
00165 #if STDC
00166 make_item(char *term)
00167 #else
00168 make_item(term)
00169 char   *term;
00170 #endif
00171 {
00172     int     i;
00173 
00174     if (level > prev_level) {
00175        /* ascending level */
00176        if (*curr->af[level] == NUL)
00177            sprintf(line, "%s%s%s", term, item_u[level], curr->sf[level]);
00178        else
00179            sprintf(line, "%s%s%s", term, item_u[level], curr->af[level]);
00180        ind_lc += ilen_u[level];
00181     } else {
00182        /* same or descending level */
00183        if (*curr->af[level] == NUL)
00184            sprintf(line, "%s%s%s", term, item_r[level], curr->sf[level]);
00185        else
00186            sprintf(line, "%s%s%s", term, item_r[level], curr->af[level]);
00187        ind_lc += ilen_r[level];
00188     }
00189 
00190     i = level + 1;
00191     while (i < FIELD_MAX && *curr->sf[i] != NUL) {
00192        PUT(line);
00193        if (*curr->af[i] == NUL)
00194            sprintf(line, "%s%s", item_x[i], curr->sf[i]);
00195        else
00196            sprintf(line, "%s%s", item_x[i], curr->af[i]);
00197        ind_lc += ilen_x[i];
00198        level = i;           /* Added at 2.11 <brosig@gmdzi.gmd.de> */
00199        i++;
00200     }
00201 
00202     ind_indent = 0;
00203     strcat(line, delim_p[level]);
00204     SAVE;
00205 }
00206 
00207 static unsigned char
00208 #if STDC
00209 first_letter(char *term)
00210 #else
00211 first_letter(term)
00212 char   *term;
00213 #endif
00214 {
00215     if (thai_sort)
00216         return strchr("אבגדה", term[0]) ? term[1] : term[0];
00217 
00218     return TOLOWER(term[0]);
00219 }
00220 
00221 static void
00222 new_entry(VOID_ARG)
00223 {
00224     int    let;
00225     FIELD_PTR ptr;
00226 #ifdef HAVE_SETLOCALE
00227     char *prev_locale;
00228     prev_locale = setlocale(LC_CTYPE, NULL);
00229     setlocale(LC_CTYPE, "");
00230 #endif
00231 
00232     if (in_range) {
00233        ptr = curr;
00234        curr = range_ptr;
00235        IND_ERROR("Unmatched range opening operator %c.\n", idx_ropen);
00236        in_range = FALSE;
00237        curr = ptr;
00238     }
00239     flush_line(TRUE);
00240 
00241     /* beginning of a new group? */
00242 
00243     if (((curr->group != ALPHA) && (curr->group != prev->group) &&
00244         (prev->group == SYMBOL)) ||
00245        ((curr->group == ALPHA) &&
00246         ((unsigned char)(let = first_letter(curr->sf[0])) 
00247          != first_letter(prev->sf[0]))) ||
00248        (german_sort &&
00249         (curr->group != ALPHA) && (prev->group == ALPHA))) {
00250        PUT(delim_t);
00251        PUT(group_skip);
00252        ind_lc += skiplen;
00253        /* beginning of a new letter? */
00254        put_header(let);
00255        make_item(NIL);
00256     } else
00257        make_item(delim_t);
00258 #ifdef HAVE_SETLOCALE
00259     setlocale(LC_CTYPE, prev_locale);
00260 #endif
00261 }
00262 
00263 
00264 static void
00265 old_entry(VOID_ARG)
00266 {
00267     int     diff;
00268 
00269     /* current entry identical to previous one: append pages */
00270     diff = page_diff(the_end, curr);
00271 
00272     if ((prev->type == curr->type) && (diff != -1) &&
00273        (((diff == 0) && (prev_encap != NULL) && STREQ(encap, prev_encap)) ||
00274         (merge_page && (diff == 1) &&
00275          (prev_encap != NULL) && STREQ(encap, prev_encap)) ||
00276         in_range)) {
00277        the_end = curr;
00278        /* extract in-range encaps out */
00279        if (in_range &&
00280            (*curr->encap != NUL) &&
00281            (*curr->encap != idx_rclose) &&
00282            STRNEQ(curr->encap, prev_encap)) {
00283            sprintf(buff, "%s%s%s%s%s", encap_p, curr->encap,
00284                   encap_i, curr->lpg, encap_s);
00285            wrap_line(FALSE);
00286        }
00287        if (in_range)
00288            encap_range = TRUE;
00289     } else {
00290        flush_line(FALSE);
00291        if ((diff == 0) && (prev->type == curr->type)) {
00292 IND_ERROR(
00293 "Conflicting entries: multiple encaps for the same page under same key.\n",
00294 "");
00295        } else if (in_range && (prev->type != curr->type)) {
00296 IND_ERROR(
00297 "Illegal range formation: starting & ending pages are of different types.\n",
00298 "");
00299        } else if (in_range && (diff == -1)) {
00300 IND_ERROR(
00301 "Illegal range formation: starting & ending pages cross chap/sec breaks.\n",
00302 "");
00303        }
00304        SAVE;
00305     }
00306 }
00307 
00308 
00309 static int
00310 #if STDC
00311 page_diff(FIELD_PTR a,FIELD_PTR b)
00312 #else
00313 page_diff(a, b)
00314 FIELD_PTR a;
00315 FIELD_PTR b;
00316 #endif
00317 {
00318     short   i;
00319 
00320     if (a->count != b->count)
00321        return (-1);
00322     for (i = 0; i < a->count - 1; i++)
00323        if (a->npg[i] != b->npg[i])
00324            return (-1);
00325     return (b->npg[b->count - 1] - a->npg[a->count - 1]);
00326 }
00327 
00328 static void
00329 #if STDC
00330 put_header(int let)
00331 #else
00332 put_header(let)
00333 int    let;
00334 #endif
00335 {
00336     if (headings_flag)
00337     {
00338        PUT(heading_pre);
00339        ind_lc += headprelen;
00340        switch (curr->group)
00341        {
00342        case SYMBOL:
00343            if (headings_flag > 0)
00344            {
00345               PUT(symhead_pos);
00346            }
00347            else
00348            {
00349               PUT(symhead_neg);
00350            }
00351            break;
00352        case ALPHA:
00353            if (headings_flag > 0)
00354            {
00355               let = TOUPPER(let);
00356               PUTC(let);
00357            }
00358            else
00359            {
00360               let = TOLOWER(let);
00361               PUTC(let);
00362            }
00363            break;
00364        default:
00365            if (headings_flag > 0)
00366            {
00367               PUT(numhead_pos);
00368            }
00369            else
00370            {
00371               PUT(numhead_neg);
00372            }
00373            break;
00374        }
00375        PUT(heading_suf);
00376        ind_lc += headsuflen;
00377     }
00378 }
00379 
00380 
00381 /* changes for 2.12 (May 20, 1993) by Julian Reschke (jr@ms.maus.de):
00382    Use keywords suffix_2p, suffix_3p or suffix_mp for one, two or
00383    multiple page ranges (when defined) */
00384 
00385 static void
00386 #if STDC
00387 flush_line(int print)
00388 #else
00389 flush_line(print)
00390 int     print;
00391 #endif
00392 {
00393     char    tmp[sizeof(buff)];
00394 
00395     if (page_diff(begin, the_end) != 0)
00396        if (encap_range || (page_diff(begin, prev) > (*suffix_2p ? 0 : 1)))
00397        {
00398               int diff = page_diff(begin, the_end);
00399               
00400               if ((diff == 1) && *suffix_2p)
00401                   sprintf(buff, "%s%s", begin->lpg, suffix_2p);
00402               else if ((diff == 2) && *suffix_3p)
00403                   sprintf(buff, "%s%s", begin->lpg, suffix_3p);
00404               else if ((diff >= 2) && *suffix_mp)
00405                   sprintf(buff, "%s%s", begin->lpg, suffix_mp);
00406               else
00407                   sprintf(buff, "%s%s%s", begin->lpg, delim_r, the_end->lpg);
00408 
00409            encap_range = FALSE;
00410        }
00411        else
00412               sprintf(buff, "%s%s%s", begin->lpg, delim_n, the_end->lpg);
00413     else
00414     {
00415        encap_range = FALSE; /* might be true from page range on same page */
00416        strcpy(buff, begin->lpg);
00417     }
00418 
00419     if (*prev_encap != NUL)
00420     {
00421        strcpy(tmp, buff);
00422        sprintf(buff, "%s%s%s%s%s",
00423               encap_p, prev_encap, encap_i, tmp, encap_s);
00424     }
00425     wrap_line(print);
00426 }
00427 
00428 static void
00429 #if STDC
00430 wrap_line(int print)
00431 #else
00432 wrap_line(print)
00433 int     print;
00434 #endif
00435 {
00436     int     len;
00437 
00438     len = strlen(line) + strlen(buff) + ind_indent;
00439     if (print) {
00440        if (len > linemax) {
00441            PUTLN(line);
00442            PUT(indent_space);
00443            ind_indent = indent_length;
00444        } else
00445            PUT(line);
00446        PUT(buff);
00447     } else {
00448        if (len > linemax) {
00449            PUTLN(line);
00450            sprintf(line, "%s%s%s", indent_space, buff, delim_n);
00451            ind_indent = indent_length;
00452        } else {
00453            strcat(buff, delim_n);
00454            strcat(line, buff);
00455        }
00456     }
00457 }
00458 
00459 
00460 static void
00461 insert_page(VOID_ARG)
00462 {
00463     int     i = 0;
00464     int     j = 0;
00465     int     page = 0;
00466 
00467     if (even_odd >= 0) {
00468        /* find the rightmost digit */
00469        while (pageno[i++] != NUL);
00470        j = --i;
00471        /* find the leftmost digit */
00472        while (isdigit(pageno[--i]) && i > 0);
00473        if (!isdigit(pageno[i]))
00474            i++;
00475        /* convert page from literal to numeric */
00476        page = strtoint(&pageno[i]) + 1;
00477        /* check even-odd numbering */
00478        if (((even_odd == 1) && (page % 2 == 0)) ||
00479            ((even_odd == 2) && (page % 2 == 1)))
00480            page++;
00481        pageno[j + 1] = NUL;
00482        /* convert page back to literal */
00483        while (page >= 10) {
00484            pageno[j--] = TOASCII(page % 10);
00485            page = page / 10;
00486        }
00487        pageno[j] = TOASCII(page);
00488        if (i < j) {
00489            while (pageno[j] != NUL)
00490               pageno[i++] = pageno[j++];
00491            pageno[i] = NUL;
00492        }
00493     }
00494     PUT(setpage_open);
00495     PUT(pageno);
00496     PUT(setpage_close);
00497     ind_lc += setpagelen;
00498 }