home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8707 / 40 < prev    next >
Encoding:
Internet Message Format  |  1990-07-13  |  44.4 KB

  1. From: simpson@trwrb.UUCP (Scott Simpson)
  2. Newsgroups: comp.sources.misc
  3. Subject: LaTeX Index Processor (Part 1 of 2)
  4. Message-ID: <2836@ncoast.UUCP>
  5. Date: 10 Jul 87 02:02:01 GMT
  6. Sender: allbery@ncoast.UUCP
  7. Lines: 1689
  8. Approved: allbery@ncoast.UUCP
  9. X-Archive: comp.sources.misc/8707/40
  10.  
  11. This is a repost of the LaTeX index processor I posted ages ago.
  12. Thanks to John Renner (adobe!renner@decwrl.dec.com) it now handles
  13. roman numeral page numbering too.  It does not handle upper case
  14. roman numeral page numbering though.  You might want to install the
  15. libraries distributed with it, especially the profile library.  It is
  16. quite useful.  To make it, type "make install".  Don't worry, it
  17. won't actually install anything.
  18.         Scott Simpson
  19.         TRW Electronics and Defense Sector
  20.         ...{decvax,ihnp4,ucbvax}!trwrb!simpson
  21.  
  22. #! /bin/sh
  23. # To extract, remove mail header lines and type "sh filename"
  24. echo x - Makefile
  25. sed -e 's/^X//' > Makefile << '!FaR!OuT!'
  26. X# $Header$
  27. XCFLAGS=-O
  28. X
  29. Xall: getopt.o shift.o
  30. X    cd libglob;make all
  31. X    cd libprofile;make all
  32. X    cd indexsrc;make all
  33. X
  34. Xinstall: all
  35. X    mv indexsrc/index .
  36. X
  37. Xclean:
  38. X    -rm index getopt.o shift.o
  39. X    cd libglob;make clean
  40. X    cd libprofile;make clean
  41. X    cd indexsrc;make clean
  42. !FaR!OuT!
  43. echo x - getopt.c
  44. sed -e 's/^X//' > getopt.c << '!FaR!OuT!'
  45. X/* @(#)getopt.c    2.1 (TRW) 3/8/86 */
  46. X#include <stdio.h>
  47. X
  48. X/*
  49. X * get option letter from argument vector
  50. X */
  51. Xint    opterr = 1,        /* useless, never set or used */
  52. X    optind = 1,        /* index into parent argv vector */
  53. X    optopt;            /* character checked for validity */
  54. Xchar    *optarg;        /* argument associated with option */
  55. X
  56. X#define BADCH    (int)'?'
  57. X#define EMSG    ""
  58. X#define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  59. X        fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  60. X
  61. Xgetopt(nargc,nargv,ostr)
  62. Xint    nargc;
  63. Xchar    **nargv,
  64. X    *ostr;
  65. X{
  66. X    static char    *place = EMSG;    /* option letter processing */
  67. X    register char    *oli;        /* option letter list index */
  68. X    char    *index();
  69. X
  70. X    if(!*place) {            /* update scanning pointer */
  71. X        if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  72. X        if (*place == '-') {    /* found "--" */
  73. X            ++optind;
  74. X            return(EOF);
  75. X        }
  76. X    }                /* option letter okay? */
  77. X    if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  78. X        if(!*place) ++optind;
  79. X        tell(": illegal option -- ");
  80. X    }
  81. X    if (*++oli != ':') {        /* don't need argument */
  82. X        optarg = NULL;
  83. X        if (!*place) ++optind;
  84. X    }
  85. X    else {                /* need an argument */
  86. X        if (*place) optarg = place;    /* no white space */
  87. X        else if (nargc <= ++optind) {    /* no arg */
  88. X            place = EMSG;
  89. X            tell(": option requires an argument -- ");
  90. X        }
  91. X         else optarg = nargv[optind];    /* white space */
  92. X        place = EMSG;
  93. X        ++optind;
  94. X    }
  95. X    return(optopt);            /* dump back option letter */
  96. X}
  97. !FaR!OuT!
  98. if [ ! -d include.local ]
  99. then
  100.     mkdir include.local
  101.     echo mkdir include.local
  102. fi
  103. echo x - include.local/standard.h
  104. sed -e 's/^X//' > include.local/standard.h << '!FaR!OuT!'
  105. X/* $Header */
  106. X#include "standenviron.h"
  107. X#include "standconst.h"
  108. X#include "standtype.h"
  109. X#include "standmacro.h"
  110. !FaR!OuT!
  111. if [ ! -d include.local ]
  112. then
  113.     mkdir include.local
  114.     echo mkdir include.local
  115. fi
  116. echo x - include.local/standconst.h
  117. sed -e 's/^X//' > include.local/standconst.h << '!FaR!OuT!'
  118. X/* $Header */
  119. X/* Standard constants. */
  120. X#ifndef STANDARD_CONST
  121. X#define STANDARD_CONST
  122. X
  123. X/*
  124. X * These are the only values boolean variables may be set to,
  125. X * or that boolean functions may return.
  126. X */
  127. X#define    TRUE 1
  128. X#define    FALSE 0
  129. X
  130. X/*
  131. X * Program exit status.
  132. X * These two codes are intended to be used as arguments to the
  133. X * exit(2) system call.  Obviously, more failure codes may be
  134. X * defined but for simple programs that need indicate only
  135. X * success or failure these will suffice.
  136. X */
  137. X#define    SUCCEED 0    /* successful program execution    */
  138. X#define    FAIL 1        /* some error in running program */
  139. X
  140. X/* All bits on or off. */
  141. X#define    ON ~(long)0    /* all bits set    */
  142. X#define    OFF (long)0    /* all bits off    */
  143. X
  144. X/* UNIX file descriptor numbers for standard input, output, and error. */
  145. X#define    STANDARD_IN 0
  146. X#define    STANDARD_OUT 1
  147. X#define    STANDARD_ERROR 2
  148. X
  149. X/*
  150. X * Extreme values.
  151. X * These constants are the largest and smallest values
  152. X * that variables of the indicated type may hold.
  153. X */
  154. X#if defined(vax) || defined(pyr)
  155. X#   define MAX_TINY 0x7f
  156. X#   define MIN_TINY 0x80
  157. X
  158. X#   define MAX_UNSIGNED_TINY 0xff
  159. X#   define MIN_UNSIGNED_TINY 0
  160. X
  161. X#   define MAX_SHORT 0x7fff
  162. X#   define MIN_SHORT 0x8000
  163. X
  164. X#   define MAX_UNSIGNED_SHORT 0xffff
  165. X#   define MIN_UNSIGNED_SHORT 0
  166. X
  167. X#   define MAX_INTEGER 0x7fffffff
  168. X#   define MIN_INTEGER 0x80000000
  169. X
  170. X#   define MAX_UNSIGNED_INTEGER 0xffffffff
  171. X#   define MIN_UNSIGNED_INTEGER 0
  172. X
  173. X#   define MAX_LONG MAX_INTEGER
  174. X#   define MIN_LONG MIN_INTEGER
  175. X#   define MAX_UNSIGNED_LONG MAX_UNSIGNED_INTEGER
  176. X#   define MIN_UNSIGNED_LONG MIN_UNSIGNED_INTEGER
  177. X#   define BITS_PER_BYTE 8
  178. X#endif
  179. X
  180. X/* for pointers */
  181. X#define NIL ((long)0)
  182. X#endif STANDARD_CONST
  183. !FaR!OuT!
  184. if [ ! -d include.local ]
  185. then
  186.     mkdir include.local
  187.     echo mkdir include.local
  188. fi
  189. echo x - include.local/standenviron.h
  190. sed -e 's/^X//' > include.local/standenviron.h << '!FaR!OuT!'
  191. X/* $Header */
  192. X/*
  193. X * This file defines the machine/compiler C environment. It defines
  194. X * pre-processor macros that tell what C features are supported.
  195. X *
  196. X * #define HAS_UNSIGNED_SHORT    Implies unsigned shorts are supported
  197. X * #define CHAR_IS_SIGNED    Implies chars are signed
  198. X * #define HAS_UNSIGNED_CHAR    Implies unsigned chars are supported
  199. X * #define HAS_UNSIGNED_LONG    Implies unsigned longs are supported
  200. X * #define BITS_PER_CHAR n    Number of bits in a char
  201. X * #define BITS_PER_INT n    Number of bits in an int
  202. X * #define BITS_PER_LONG n    Number of bits in a long
  203. X * #define BITS_PER_POINTER n    Number of bits in a pointer
  204. X * #define BITS_PER_SHORT n    Number of bits in a short
  205. X * #define HAS_VOID        Implies void function type is supported
  206. X */
  207. X
  208. X#ifndef    STANDARD_ENVIRON    /* prevent multiple inclusions    */
  209. X
  210. X#if defined(vax) || defined(pyr)
  211. X#   define HAS_UNSIGNED_SHORT
  212. X#   define CHAR_IS_SIGNED
  213. X#   define HAS_UNSIGNED_CHAR
  214. X#   define HAS_UNSIGNED_LONG
  215. X#   define HAS_VOID
  216. X
  217. X#   define BITS_PER_CHAR 8
  218. X#   define BITS_PER_SHORT 16
  219. X#   define BITS_PER_INT 32
  220. X#   define BITS_PER_LONG 32
  221. X#   define BITS_PER_POINTER 32
  222. X#   define STANDARD_ENVIRON
  223. X#endif
  224. X
  225. X#endif STANDARD_ENVIRON
  226. X
  227. X/* make sure a known processor type was    specified */
  228. X#ifndef    STANDARD_ENVIRON
  229. X#   include "Processor type unknown or unspecified"
  230. X#endif STANDARD_ENVIRON
  231. !FaR!OuT!
  232. if [ ! -d include.local ]
  233. then
  234.     mkdir include.local
  235.     echo mkdir include.local
  236. fi
  237. echo x - include.local/standmacro.h
  238. sed -e 's/^X//' > include.local/standmacro.h << '!FaR!OuT!'
  239. X/* $Header */
  240. X#ifndef STANDARD_MACRO
  241. X#define STANDARD_MACRO
  242. X#define    MAX(x, y) ((x) > (y) ? (x) : (y))
  243. X#define    MIN(x, y) ((x) < (y) ? (x) : (y))
  244. X#define    ABS(x) ((x) < 0 ? -(x) : (x))
  245. X#define ROUND(x)   ((int)(((x)<0)?((x)-0.5):((x)+0.5)))
  246. X#define CEILING(x) (((x)>=0)?(int)(x)==(x)?(int)(x):(int)((x)+1):(int)(x))
  247. X#define FLOOR(x)   (((x)>=0)?(int)(x):(int)(x)==(x)?(int)(x):(int)((x)-1))
  248. X#define EQ(s, t)    (!strcmp(s, t))
  249. X#define EQN(s, t, n)    (!strncmp(s, t, n))
  250. X#endif STANDARD_MACRO
  251. !FaR!OuT!
  252. if [ ! -d include.local ]
  253. then
  254.     mkdir include.local
  255.     echo mkdir include.local
  256. fi
  257. echo x - include.local/standtype.h
  258. sed -e 's/^X//' > include.local/standtype.h << '!FaR!OuT!'
  259. X/* $Header */
  260. X/* Standard machine independent type definitions. */
  261. X
  262. X#ifndef    STANDARD_TYPE    /* prevent multiple inclusions    */
  263. X#define    STANDARD_TYPE
  264. X
  265. X/*
  266. X * Integers
  267. X *     Tiny/UnsignedTiny    8+ bit integers
  268. X *     Short/UnsignedShort    16+ bit integers
  269. X *     Integer/UnsignedInteger    natural machine integer size
  270. X *     Long/UnsignedLong    32+ bit integers
  271. X *
  272. X * Bits
  273. X *     TinyBits        8+ bits
  274. X *     Bits        16+ bits
  275. X *     LongBits        32+ bits
  276. X *
  277. X * Booleans
  278. X *     TinyBoolean
  279. X *     Boolean
  280. X *
  281. X * Void
  282. X *
  283. X * Storage Classes
  284. X *     Export        Seen in other compilation units
  285. X *     Import        Supplied by another compilation unit
  286. X *     Local        Unseen outside compilation unit
  287. X */
  288. X
  289. X/*
  290. X * Each of the following sections for the integer types defines both
  291. X * a base type and an extraction macro for the value.
  292. X */
  293. X
  294. Xtypedef char    Tiny;
  295. X/* Not all machines have signed characters so we may have to simulate them. */
  296. X#ifdef CHAR_IS_SIGNED
  297. X#   define TINY(x) (x)
  298. X#else
  299. X#   define TINY(x) (((x) & MIN_TINY) ? (~MAX_TINY | (x)) : (x))
  300. X#endif CHAR_IS_SIGNED
  301. X
  302. X/* Not all compilers support unsigned chars so we may have to simulate them. */
  303. X#ifdef HAS_UNSIGNED_CHAR
  304. X    typedef unsigned char UnsignedTiny;
  305. X#else
  306. X    typedef char UnsignedTiny;
  307. X#endif HAS_UNSIGNED_CHAR
  308. X#ifdef CHAR_IS_SIGNED
  309. X#   define UNSIGNED_TINY(x) ((x) & MAX_UNSIGNED_TINY)
  310. X#else
  311. X#   define UNSIGNED_TINY(x) (x)
  312. X#endif
  313. X
  314. X/*
  315. X * All compilers have signed short integers.  This type is included
  316. X * for lexical consistency.
  317. X */
  318. Xtypedef short Short;
  319. X
  320. X/* Not all compilers support unsigned shorts so we may have to simulate them. */
  321. X#ifdef HAS_UNSIGNED_SHORT
  322. X    typedef unsigned short UnsignedShort;
  323. X#else
  324. X    typedef short UnsignedShort;
  325. X#endif
  326. X#   define UNSIGNED_SHORT(x) ((unsigned)(x) & MAX_UNSIGNED_SHORT)
  327. X
  328. X/* These types are solely for lexical consistency. */
  329. Xtypedef int Integer;
  330. Xtypedef    unsigned int UnsignedInteger;
  331. X
  332. Xtypedef long Long;
  333. X
  334. X/* Not all compilers support unsigned longs so we may have to simulate them. */
  335. X#ifdef HAS_UNSIGNED_LONG
  336. X    typedef unsigned long UnsignedLong;
  337. X#   define UNSIGNED_LONG(s) ((UnsignedLong)(x))
  338. X#else
  339. X    typedef long UnsignedLong;
  340. X#   define UNSIGNED_LONG(x) ((long)(x) & MAX_LONG)
  341. X#endif HAS_UNSIGNED_LONG
  342. X
  343. X/* Boolean types take on only the values TRUE or FALSE. */
  344. Xtypedef    char TinyBoolean;
  345. Xtypedef    short Boolean;
  346. X
  347. X/* This type is included for lexical consistency. */
  348. Xtypedef char Character;
  349. X
  350. X/* Bit types are used only for bit set, clear and test operations. */
  351. Xtypedef    char TinyBits;
  352. Xtypedef    short Bits;
  353. Xtypedef    long LongBits;
  354. X
  355. X/* Not all compilers support void functions so we may have to simulate it. */
  356. X#ifdef HAS_VOID
  357. X#   define Void void
  358. X#else
  359. X    typedef int Void;
  360. X#endif
  361. X
  362. X/* Storage classes. */
  363. X#define    Export
  364. X#define Import extern
  365. X#define    Local static
  366. X
  367. X#endif    STANDARD_TYPE
  368. !FaR!OuT!
  369. if [ ! -d indexsrc ]
  370. then
  371.     mkdir indexsrc
  372.     echo mkdir indexsrc
  373. fi
  374. echo x - indexsrc/Makefile
  375. sed -e 's/^X//' > indexsrc/Makefile << '!FaR!OuT!'
  376. X# $Header: Makefile,v 1.1 86/06/10 08:25:26 control Exp $
  377. XLDFLAGS=-s
  378. XCFLAGS=-O -I../libglob -I../libprofile -I../include.local
  379. X
  380. Xall: index
  381. X
  382. Xindex: indexlex.c index.o
  383. X    $(CC) $(CFLAGS) $(LDFLAGS) -o index index.o ../getopt.o ../shift.o \
  384. X    ../libprofile/libprofile.a ../libglob/libglob.a -ll
  385. X
  386. Xindexlex.c: indexlex.l
  387. X
  388. Xindex.o: indexlex.c
  389. X
  390. Xinstall: all
  391. X
  392. Xclean:
  393. X    -rm *.o lex.yy.c y.tab.c indexlex.c index
  394. !FaR!OuT!
  395. if [ ! -d indexsrc ]
  396. then
  397.     mkdir indexsrc
  398.     echo mkdir indexsrc
  399. fi
  400. echo x - indexsrc/index.y
  401. sed -e 's/^X//' > indexsrc/index.y << '!FaR!OuT!'
  402. X/* $Header */
  403. X/* Yacc parser for LaTeX index processor */
  404. X/* Roman numeral code written by John Renner (adobe!renner@decwrl.dec.com) */
  405. X%{
  406. X#include <stdio.h>
  407. X#include "standard.h"
  408. X#include "profile.h"
  409. X#include <ctype.h>
  410. X#include <pwd.h>
  411. X#define TABLEINCREMENT    50        /* Number of additional entries added when expanding a table */
  412. X#define eq(s,t)        (!strcmp((s),(t)))
  413. X#define odd(i)        (((i) % 2) == 1)
  414. X#define ITEMDEPTH    3        /* Number of nestings of \item's, \subitem's, \subsubitem's, etc. */
  415. Xchar *ItemRep[] = { "\\item", "\\subitem", "\\subsubitem", NULL }; /* and their representation */
  416. Xchar    *calloc(), *realloc();
  417. Xenum TokenType    {controlword, controlsymbol, string, integer, roman, comma, obrace, cbrace, whitespace};
  418. Xstruct IndexEntry {
  419. X    char        literal[81];    /* Literal representation of index entry */
  420. X    char        alphabetic[81];    /* Alphabetic representation for sorting of index entry */
  421. X    struct Token    *tokenlist;    /* Doubly linked token list */
  422. X    struct IndexEntry    *subitem;    /* Pointer to subitem table, subsubitem table, etc */
  423. X    int            subitemcount;    /* Number of items in subitem table */
  424. X    int            subitemtabsize;    /* Subitem table size currently allocated */
  425. X    struct PageNoTable    *pagenos;    /* List of page numbers */
  426. X    int            pagetablecount;    /* Number of items in page number table */
  427. X    int            pagetablesize;    /* Size of page number table currently allocated */
  428. X};
  429. Xstruct Token {
  430. X    enum TokenType    type;        /* Token type */
  431. X    char        lexeme[81];    /* Representation of all the token types */
  432. X    struct Token    *prev, *next;
  433. X};
  434. Xstruct PageNoTable {
  435. X    int            number;        /* Page number */
  436. X    Boolean        range;        /* True if this is the beginning of a range */
  437. X    Boolean        isroman;    /* True if this was a roman numeral */
  438. X};
  439. Xstruct IndexEntry    *IndexTable = NULL;    /* Table of primary index entries */
  440. Xint            IndexTableCount = 0;    /* Count of number of elements used in index table */
  441. Xint            IndexTableSize = 0;    /* Current allocated size of index table */
  442. Xint            ExitStatus = SUCCEED;    /* Guess */
  443. Xint            LineNo = 1;        /* Line number at start of token */
  444. Xint            EndLineNo = 1;        /* Line number at end of token */
  445. XBoolean            Label = FALSE;        /* True if -l option given */
  446. XBoolean            Range;            /* True if this \indexentry is a range */
  447. XPROFILE_STANZA        *SortStanza = NULL;    /* Alphabetize stanza */
  448. Xextern int        optind;            /* From getopt(3) */
  449. Xextern char        *optarg;
  450. Xchar            *Whoami;        /* argv[0] */
  451. Xchar            *Usage = "Usage: %s [-l] [-f alphabetizefile] [file...]\n";
  452. Xchar            *Marker[] = { "alphabetize", NULL };    /* Markers for alphabetize stanza */
  453. Xchar            IdxFileName[81];    /* .idx file name */
  454. Xchar            Literal[81];        /* Literal string of key */
  455. Xchar            Alphabetic[81];        /* Alphabetic string of key */
  456. XFILE            *InputFile;        /* Current input file */
  457. XFILE            *OutputFile;        /* Current output file */
  458. Xstruct Token        *CurKey;        /* Current key we are constructing */
  459. Xstruct IndexEntry    **CurSearchTable;    /* Current table to search for match */
  460. Xstruct IndexEntry    *CurEntry;        /* Current table entry */
  461. Xstruct IndexEntry    *PrevEntry;        /* Previous Entry */
  462. X%}
  463. X%union {
  464. X    char        value[81];
  465. X    struct Token    *t;
  466. X}
  467. X%token <value> ROMAN CONTROLSEQUENCE INTEGER WHITESPACE STRING INDEXENTRY
  468. X%type <t> noncommaelement anyelement anyelements
  469. X%%
  470. Xindexfile :
  471. X    optwhitespace
  472. X    indexentries
  473. X    {
  474. X        sort(IndexTable, IndexTableCount);
  475. X        fprintf(OutputFile, "\\begin{theindex}\n");
  476. X        if (Label) {
  477. X        fprintf(OutputFile,
  478. X "\\newcommand{\\largeletter}[1]{{\\pagebreak[2]\\Large\\hspace{-.5in}\\parbox[t]{.5in}{\\makebox[.35in][r]");
  479. X        fprintf(OutputFile, "{\\uppercase{#1}}}\\nopagebreak[4]\\vspace{-1.5ex}}}\n");
  480. X        }
  481. X        printindexentries(IndexTable, IndexTableCount, 1);
  482. X        fprintf(OutputFile, "\\end{theindex}\n");
  483. X    }
  484. X    ;
  485. X
  486. Xindexentries :
  487. X    indexentries
  488. X    indexentry
  489. X    |
  490. X    indexentry
  491. X    ;
  492. X
  493. Xindexentry :
  494. X    INDEXENTRY
  495. X    {
  496. X        CurSearchTable = &IndexTable, PrevEntry = NULL;
  497. X        CurKey = NULL;
  498. X        Range = FALSE;
  499. X    }
  500. X    optwhitespace
  501. X    '{'
  502. X    keys
  503. X    '}'
  504. X    optwhitespace
  505. X    '{'
  506. X    optwhitespace
  507. X    anumber
  508. X    optwhitespace
  509. X    '}'
  510. X    optwhitespace
  511. X    ;
  512. X
  513. Xanumber : 
  514. X    INTEGER
  515. X    {
  516. X        struct PageNoTable    *p;
  517. X
  518. X        if (!(p = findpage(CurEntry->pagenos, CurEntry->pagetablecount, atoi($1), FALSE))) {
  519. X        if (CurEntry->pagetablecount >= CurEntry->pagetablesize) {
  520. X            if (!(CurEntry->pagenos = (struct PageNoTable *)reallocate(CurEntry->pagenos, CurEntry->pagetablesize,
  521. X            TABLEINCREMENT, sizeof(struct PageNoTable)))) {
  522. X            yyerror("memory allocation failure");
  523. X            exit(FAIL);
  524. X            }
  525. X            CurEntry->pagetablesize += TABLEINCREMENT;
  526. X        }
  527. X        CurEntry->pagenos[CurEntry->pagetablecount].number = atoi($1);
  528. X        CurEntry->pagenos[CurEntry->pagetablecount].isroman = FALSE;
  529. X        CurEntry->pagenos[CurEntry->pagetablecount].range = Range;
  530. X        CurEntry->pagetablecount++;
  531. X        } else
  532. X        p->range = Range;
  533. X    }
  534. X      |
  535. X      ROMAN
  536. X    {
  537. X        struct PageNoTable    *p;
  538. X
  539. X        if (!(p = findpage(CurEntry->pagenos, CurEntry->pagetablecount, rmtoi($1), TRUE))) {
  540. X        if (CurEntry->pagetablecount >= CurEntry->pagetablesize) {
  541. X            if (!(CurEntry->pagenos = (struct PageNoTable *)reallocate(CurEntry->pagenos, CurEntry->pagetablesize,
  542. X            TABLEINCREMENT, sizeof(struct PageNoTable)))) {
  543. X            yyerror("memory allocation failure");
  544. X            exit(FAIL);
  545. X            }
  546. X            CurEntry->pagetablesize += TABLEINCREMENT;
  547. X        }
  548. X        CurEntry->pagenos[CurEntry->pagetablecount].number = rmtoi($1);
  549. X        CurEntry->pagenos[CurEntry->pagetablecount].isroman = TRUE;
  550. X        CurEntry->pagenos[CurEntry->pagetablecount].range = Range;
  551. X        CurEntry->pagetablecount++;
  552. X        } else
  553. X        p->range = Range;
  554. X    }
  555. X    
  556. Xkeys :
  557. X    multiplekeys
  558. X    key
  559. X    {
  560. X    struct Token    *t;
  561. X
  562. X    for (t = CurKey; t->next; t = t->next)
  563. X        ;
  564. X    if (t->type == string)
  565. X        if (t->lexeme[strlen(t->lexeme) - 1] == '-') {
  566. X        t->lexeme[strlen(t->lexeme) - 1] = '\0';
  567. X        Range = TRUE;
  568. X        }
  569. X    goto installkey;
  570. X    }
  571. X    ;
  572. X
  573. Xmultiplekeys :
  574. X    multiplekeys
  575. X    key
  576. X    ','
  577. X    {
  578. X        struct Token    *t;
  579. X
  580. Xinstallkey: strcpy(Literal, literalstring(CurKey));
  581. X        strcpy(Alphabetic, alphabetizestring(CurKey, SortStanza));
  582. X        if (!*CurSearchTable) {
  583. X        if (!(*CurSearchTable = (struct IndexEntry *)reallocate(*CurSearchTable, 0, TABLEINCREMENT,
  584. X        sizeof(struct IndexEntry)))) {
  585. X            yyerror("memory allocation failure");
  586. X            exit(FAIL);
  587. X        }
  588. X        if (!PrevEntry)
  589. X            IndexTableSize = TABLEINCREMENT;
  590. X        else
  591. X            PrevEntry->subitemtabsize = TABLEINCREMENT;
  592. X        }
  593. X        if (!(CurEntry = findentry(*CurSearchTable, PrevEntry ? PrevEntry->subitemcount : IndexTableCount, Literal))) {
  594. X        if (!PrevEntry) {
  595. X            if (IndexTableCount >= IndexTableSize) {
  596. X            if (!(*CurSearchTable = (struct IndexEntry *)reallocate(*CurSearchTable, IndexTableSize, TABLEINCREMENT,
  597. X            sizeof(struct IndexEntry)))) {
  598. X                yyerror("memory allocation failure");
  599. X                exit(FAIL);
  600. X            }
  601. X            IndexTableSize += TABLEINCREMENT;
  602. X            }
  603. X            CurEntry = (*CurSearchTable + IndexTableCount);
  604. X            IndexTableCount++;
  605. X        } else {
  606. X            if (PrevEntry->subitemcount >= PrevEntry->subitemtabsize) {
  607. X            if (!(*CurSearchTable = (struct IndexEntry *)reallocate(*CurSearchTable, PrevEntry->subitemtabsize,
  608. X            TABLEINCREMENT, sizeof(struct IndexEntry)))) {
  609. X                yyerror("memory allocation failure");
  610. X                exit(FAIL);
  611. X            }
  612. X            PrevEntry->subitemtabsize += TABLEINCREMENT;
  613. X            }
  614. X            CurEntry = (*CurSearchTable + PrevEntry->subitemcount);
  615. X            PrevEntry->subitemcount++;
  616. X        }
  617. X        strcpy(CurEntry->literal, Literal);
  618. X        strcpy(CurEntry->alphabetic, Alphabetic);
  619. X        CurKey->prev = CurEntry->tokenlist, CurEntry->tokenlist = CurKey;
  620. X        CurEntry->subitem = NULL, CurEntry->subitemcount = CurEntry->subitemtabsize = 0;
  621. X        CurEntry->pagenos = NULL, CurEntry->pagetablecount = CurEntry->pagetablesize = 0;
  622. X        }
  623. X        CurSearchTable = &CurEntry->subitem;
  624. X        PrevEntry = CurEntry;
  625. X        CurKey = NULL;
  626. X    }
  627. X    |
  628. X    /* epsilon */
  629. X    ;
  630. X
  631. Xkey :
  632. X    key
  633. X    noncommaelement
  634. X    |
  635. X    noncommaelement
  636. X    ;
  637. X
  638. Xnoncommaelement :
  639. X    CONTROLSEQUENCE
  640. X    {
  641. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  642. X        yyerror("memory allocation failure");
  643. X        exit(FAIL);
  644. X        }
  645. X        $$->type = isalpha($1[1]) ? controlword : controlsymbol;
  646. X        strcpy($$->lexeme, $1);
  647. X        $$->next = NULL;
  648. X        if (!CurKey)
  649. X        $$->prev = CurKey, CurKey = $$;
  650. X        else {
  651. X        struct Token *p;
  652. X        
  653. X        for (p = CurKey; p->next; p = p->next)
  654. X            ;
  655. X        p->next = $$, $$->prev = p;
  656. X        }
  657. X        $$ = CurKey;
  658. X    }
  659. X    |
  660. X    ROMAN
  661. X    {
  662. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  663. X        yyerror("memory allocation failure");
  664. X        exit(FAIL);
  665. X        }
  666. X        $$->type = roman;
  667. X        strcpy($$->lexeme, $1);
  668. X        $$->next = NULL;
  669. X        if (!CurKey)
  670. X        $$->prev = CurKey, CurKey = $$;
  671. X        else {
  672. X        struct Token *p;
  673. X        
  674. X        for (p = CurKey; p->next; p = p->next)
  675. X            ;
  676. X        p->next = $$, $$->prev = p;
  677. X        }
  678. X        $$ = CurKey;
  679. X    }
  680. X    |
  681. X    INTEGER
  682. X    {
  683. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  684. X        yyerror("memory allocation failure");
  685. X        exit(FAIL);
  686. X        }
  687. X        $$->type = integer;
  688. X        strcpy($$->lexeme, $1);
  689. X        $$->next = NULL;
  690. X        if (!CurKey)
  691. X        $$->prev = CurKey, CurKey = $$;
  692. X        else {
  693. X        struct Token *p;
  694. X        
  695. X        for (p = CurKey; p->next; p = p->next)
  696. X            ;
  697. X        p->next = $$, $$->prev = p;
  698. X        }
  699. X        $$ = CurKey;
  700. X    }
  701. X    |
  702. X    WHITESPACE
  703. X    {
  704. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  705. X        yyerror("memory allocation failure");
  706. X        exit(FAIL);
  707. X        }
  708. X        $$->type = whitespace;
  709. X        strcpy($$->lexeme, $1);
  710. X        $$->next = NULL;
  711. X        if (!CurKey)
  712. X        $$->prev = CurKey, CurKey = $$;
  713. X        else {
  714. X        struct Token *p;
  715. X        
  716. X        for (p = CurKey; p->next; p = p->next)
  717. X            ;
  718. X        p->next = $$, $$->prev = p;
  719. X        }
  720. X        $$ = CurKey;
  721. X    }
  722. X    |
  723. X    STRING
  724. X    {
  725. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  726. X        yyerror("memory allocation failure");
  727. X        exit(FAIL);
  728. X        }
  729. X        $$->type = string;
  730. X        strcpy($$->lexeme, $1);
  731. X        $$->next = NULL;
  732. X        if (!CurKey)
  733. X        $$->prev = CurKey, CurKey = $$;
  734. X        else {
  735. X        struct Token *p;
  736. X        
  737. X        for (p = CurKey; p->next; p = p->next)
  738. X            ;
  739. X        p->next = $$, $$->prev = p;
  740. X        }
  741. X        $$ = CurKey;
  742. X    }
  743. X    |
  744. X    '{'
  745. X    {
  746. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  747. X        yyerror("memory allocation failure");
  748. X        exit(FAIL);
  749. X        }
  750. X        $$->type = obrace;
  751. X        strcpy($$->lexeme, "{");
  752. X        $$->next = NULL;
  753. X        if (!CurKey)
  754. X        $$->prev = CurKey, CurKey = $$;
  755. X        else {
  756. X        struct Token *p;
  757. X
  758. X        for (p = CurKey; p->next; p = p->next)
  759. X            ;
  760. X        p->next = $$, $$->prev = p;
  761. X        }
  762. X    }
  763. X    anyelements
  764. X    '}'
  765. X    {
  766. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  767. X        yyerror("memory allocation failure");
  768. X        exit(FAIL);
  769. X        }
  770. X        $$->type = cbrace;
  771. X        strcpy($$->lexeme, "}");
  772. X        $$->next = NULL;
  773. X        if (!CurKey)
  774. X        $$->prev = CurKey, CurKey = $$;
  775. X        else {
  776. X        struct Token *p;
  777. X        
  778. X        for (p = CurKey; p->next; p = p->next)
  779. X            ;
  780. X        p->next = $$, $$->prev = p;
  781. X        }
  782. X        $$ = CurKey;
  783. X    }
  784. X    ;
  785. X
  786. Xanyelements :
  787. X    anyelements
  788. X    anyelement
  789. X    {
  790. X        $$ = $2;
  791. X    }
  792. X    |
  793. X    anyelement        /* Default action is $$ = $1 */
  794. X    ;
  795. X
  796. Xanyelement :
  797. X    noncommaelement     /* Default action is $$ = $1 */
  798. X    |
  799. X    ','
  800. X    {
  801. X        if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) {
  802. X        yyerror("memory allocation failure");
  803. X        exit(FAIL);
  804. X        }
  805. X        $$->type = comma;
  806. X        strcpy($$->lexeme, ",");
  807. X        $$->next = NULL;
  808. X        if (!CurKey)
  809. X        $$->prev = CurKey, CurKey = $$;
  810. X        else {
  811. X        struct Token *p;
  812. X        
  813. X        for (p = CurKey; p->next; p = p->next)
  814. X            ;
  815. X        p->next = $$, $$->prev = p;
  816. X        }
  817. X        $$ = CurKey;
  818. X    }
  819. X    ;
  820. X
  821. Xoptwhitespace :
  822. X    WHITESPACE
  823. X    |
  824. X    ;
  825. X    
  826. X%%
  827. X#include "indexlex.c"
  828. X
  829. Xmain(argc, argv)
  830. Xint    argc;
  831. Xchar    *argv[];
  832. X{
  833. X    int            c;
  834. X    Boolean        sortfilegiven = FALSE;
  835. X    char        sortfilename[81];
  836. X    char        indfilename[81];
  837. X    struct passwd    *pwentry;
  838. X    FILE        *stanzafileptr;
  839. X
  840. X    Whoami = argv[0];
  841. X    pwentry = getpwuid(geteuid());
  842. X    sprintf(sortfilename, "%s/.alphabetize", pwentry->pw_dir);
  843. X    while ((c = getopt(argc, argv, "f:l")) != EOF)
  844. X    switch (c) {
  845. X    case 'l':
  846. X        Label = TRUE;
  847. X        break;
  848. X    case 'f':
  849. X        strcpy(sortfilename, optarg);
  850. X        sortfilegiven = TRUE;
  851. X        break;
  852. X    case '?':
  853. X        fprintf(stderr, Usage, Whoami);
  854. X        exit(FAIL);
  855. X    }
  856. X    stanzafileptr = fopen(sortfilename, "r");
  857. X    if (sortfilegiven && !stanzafileptr) {
  858. X    fprintf(stderr, "%s: cannot open alphabetization file %s\n", Whoami, sortfilename);
  859. X    exit(FAIL);
  860. X    }
  861. X    if (stanzafileptr) {
  862. X    if (!(SortStanza = profile_read_profile(stanzafileptr))) {
  863. X        fprintf(stderr, "%s: file %s is not in stanza format\n", Whoami, sortfilename);
  864. X        fclose(stanzafileptr);
  865. X        exit(FAIL);
  866. X    }
  867. X    if (!(SortStanza = profile_has_stanza(SortStanza, Marker))) {
  868. X        fprintf(stderr, "%s: file %s does not contain a stanza with marker %s\n", Whoami, sortfilename, Marker[0]);
  869. X        fclose(stanzafileptr);
  870. X        exit(FAIL);
  871. X    }
  872. X    fclose(stanzafileptr);
  873. X    }
  874. X    checkstanza(SortStanza);
  875. X    if (optind == argc) {
  876. X    InputFile = stdin;
  877. X    OutputFile = stdout;
  878. X    strcpy(IdxFileName, "stdin");
  879. X    }
  880. X    do {
  881. X    if (InputFile != stdin) {
  882. X        strcpy(IdxFileName, argv[optind]);
  883. X        if (!(InputFile = fopen(argv[optind], "r"))) {
  884. X        strcpy(IdxFileName, argv[optind]);
  885. X        strcat(IdxFileName, ".idx");
  886. X        if (!(InputFile = fopen(IdxFileName, "r"))) {
  887. X            fprintf(stderr, "%s: cannot open %s\n", Whoami, IdxFileName);
  888. X            ExitStatus = FAIL;
  889. X            continue;
  890. X        }
  891. X        }
  892. X        if (strlen(IdxFileName) >= 4 && eq(&IdxFileName[strlen(IdxFileName)-4], ".idx"))
  893. X        sprintf(indfilename, "%.*s.ind", strlen(IdxFileName)-4, IdxFileName);
  894. X        else
  895. X        sprintf(indfilename, "%s.ind", IdxFileName);
  896. X        if (!(OutputFile = fopen(indfilename, "w"))) {
  897. X        fprintf(stderr, "%s: cannot open output file %s\n", Whoami, indfilename);
  898. X        fclose(InputFile);
  899. X        ExitStatus = FAIL;
  900. X        continue;
  901. X        }
  902. X    } else
  903. X        strcpy(IdxFileName, "stdin");
  904. X    if (yyparse() != 0)
  905. X        ExitStatus = FAIL;
  906. X    fclose(InputFile);
  907. X    fclose(OutputFile);
  908. X    freetables(IndexTable, IndexTableCount);
  909. X    IndexTable = NULL, IndexTableCount = IndexTableSize = 0, LineNo = EndLineNo = 1;
  910. X    yysptr = yysbuf;    /* Resets Lex lookahead buffer */
  911. X    } while (++optind < argc);
  912. X    exit(ExitStatus);
  913. X}
  914. X
  915. Xyyerror(s)
  916. Xchar *s;
  917. X{
  918. X    fprintf(stderr, "\"%s\", line %d: %s\n", IdxFileName, LineNo, s);
  919. X}
  920. X
  921. X/* Allocates additional space for tables. Returns NULL if memory allocation failure or inconsistent parameters */
  922. Xchar *reallocate(table, current, increment, elementsize)
  923. Xchar    *table;            /* pointer to current table */
  924. Xint    current;        /* current size of table */
  925. Xint    increment;        /* additional entries to add */
  926. Xint    elementsize;        /* size of an element in the table */
  927. X{
  928. X    char    *calloc(), *realloc();
  929. X    char    *p;
  930. X
  931. X    if ((!table && current > 0) || current < 0 || increment < 0 || elementsize < 0)
  932. X    return NULL;
  933. X    if (increment == 0 || elementsize == 0)
  934. X    return table;
  935. X    if (current == 0)
  936. X    if (!(p = calloc(increment, elementsize)))
  937. X        return NULL;
  938. X    else
  939. X        return p;
  940. X    else
  941. X    if (!(p = realloc(table, (current + increment) * elementsize)))
  942. X        return NULL;
  943. X    else
  944. X        return p;
  945. X}
  946. X
  947. X/* Frees the space allocated for all the tables */
  948. Xfreetables(index, noentries)
  949. Xstruct IndexEntry    *index;        /* index table */
  950. Xint            noentries;    /* number of entries in table */
  951. X{
  952. X    struct Token    *t, *ttemp;
  953. X    int            i;
  954. X
  955. X    if (!index || noentries == 0)
  956. X    return;
  957. X    for (i = 0; i < noentries; i++)
  958. X    if (index[i].subitem)
  959. X    freetables(index[i].subitem, index[i].subitemcount);    /* recursion! */
  960. X    for (t = index[i].tokenlist; t; t = ttemp)
  961. X    ttemp = t->next, free(t);
  962. X    if (index[i].pagenos)
  963. X    free(index[i].pagenos);
  964. X    free(index);
  965. X}
  966. X
  967. X/* Checks alphabetize stanza for validity */
  968. Xcheckstanza(ps)
  969. XPROFILE_STANZA    *ps;
  970. X{
  971. X    PROFILE_BINDING    *pb;
  972. X    PROFILE_VALUE    *pv;
  973. X    int            count;
  974. X
  975. X    if (!ps)
  976. X    return;
  977. X    if (pb = profile_has_binding(ps, "skipchars"))
  978. X    for (pv = pb->value; pv; pv = pv->next)
  979. X        if (pv->class != PROFILE_CHARACTER)
  980. X        switch (pv->class) {
  981. X        case PROFILE_INTEGER:
  982. X            fprintf(stderr, "%s: illegal integer constant %d in skipchars binding\n", Whoami, pv->value.i);
  983. X            break;
  984. X        case PROFILE_HEX:
  985. X            fprintf(stderr, "%s: illegal hex constant 0x%x in skipchars binding\n", Whoami, pv->value.i);
  986. X            break;
  987. X        case PROFILE_OCTAL:
  988. X            fprintf(stderr, "%s: illegal octal constant 0%o in skipchars binding\n", Whoami, pv->value.i);
  989. X            break;
  990. X        case PROFILE_FLOAT:
  991. X            fprintf(stderr, "%s: illegal float constant %f in skipchars binding\n", Whoami, pv->value.f);
  992. X            break;
  993. X        case PROFILE_STRING:
  994. X        case PROFILE_OTHER:
  995. X            fprintf(stderr, "%s: illegal string constant %s in skipchars binding\n", Whoami, pv->value.s);
  996. X            break;
  997. X        }
  998. X    if (pb = profile_has_binding(ps, "mapctrlsequence")) {
  999. X    for (count = 0, pv = pb->value; pv; pv = pv->next, count++)
  1000. X        if (pv->class != PROFILE_OTHER || pv->class != PROFILE_STRING)
  1001. X        switch (pv->class) {
  1002. X        case PROFILE_INTEGER:
  1003. X            fprintf(stderr, "%s: illegal integer constant %d in mapctrlsequence binding\n", Whoami, pv->value.i);
  1004. X            break;
  1005. X        case PROFILE_HEX:
  1006. X            fprintf(stderr, "%s: illegal hex constant 0x%x in mapctrlsequence binding\n", Whoami, pv->value.i);
  1007. X            break;
  1008. X        case PROFILE_OCTAL:
  1009. X            fprintf(stderr, "%s: illegal octal constant 0%o in mapctrlsequence binding\n", Whoami, pv->value.i);
  1010. X            break;
  1011. X        case PROFILE_FLOAT:
  1012. X            fprintf(stderr, "%s: illegal float constant %f in mapctrlsequence binding\n", Whoami, pv->value.f);
  1013. X            break;
  1014. X        case PROFILE_CHARACTER:
  1015. X            fprintf(stderr, "%s: illegal character constant %c in mapctrlsequence binding\n", Whoami, pv->value.c);
  1016. X            break;
  1017. X        }
  1018. X    if (odd(count))
  1019. X        fprintf(stderr, "%s: must have an even number of string values for mapctrlsequence binding\n", Whoami);
  1020. X    }
  1021. X    if (pb = profile_has_binding(ps, "mapindexentry")) {
  1022. X    for (count = 0, pv = pb->value; pv; pv = pv->next, count++)
  1023. X        if (pv->class != PROFILE_OTHER || pv->class != PROFILE_STRING)
  1024. X        switch (pv->class) {
  1025. X        case PROFILE_INTEGER:
  1026. X            fprintf(stderr, "%s: illegal integer constant %d in mapindexentry binding\n", Whoami, pv->value.i);
  1027. X            break;
  1028. X        case PROFILE_HEX:
  1029. X            fprintf(stderr, "%s: illegal hex constant 0x%x in mapindexentry binding\n", Whoami, pv->value.i);
  1030. X            break;
  1031. X        case PROFILE_OCTAL:
  1032. X            fprintf(stderr, "%s: illegal octal constant 0%o in mapindexentry binding\n", Whoami, pv->value.i);
  1033. X            break;
  1034. X        case PROFILE_FLOAT:
  1035. X            fprintf(stderr, "%s: illegal float constant %f in mapindexentry binding\n", Whoami, pv->value.f);
  1036. X            break;
  1037. X        case PROFILE_CHARACTER:
  1038. X            fprintf(stderr, "%s: illegal character constant %c in mapindexentry binding\n", Whoami, pv->value.c);
  1039. X            break;
  1040. X        }
  1041. X    if (odd(count))
  1042. X        fprintf(stderr, "%s: must have an even number of string values for mapindexentry binding\n", Whoami);
  1043. X    }
  1044. X}
  1045. X
  1046. X/* Returns the literal string of a token list */
  1047. Xchar    *literalstring(t)
  1048. Xstruct Token    *t;
  1049. X{
  1050. X    static char    literal[81];
  1051. X
  1052. X    strcpy(literal, "");
  1053. X    for (t = CurKey; t; t = t->next)
  1054. X        strcat(literal, t->lexeme);
  1055. X    return literal;
  1056. X}
  1057. X
  1058. X/* Returns alphabetization string for a token list and a stanza */
  1059. Xchar    *alphabetizestring(tokenlist, stanza)
  1060. Xstruct Token    *tokenlist;
  1061. XPROFILE_STANZA    *stanza;
  1062. X{
  1063. X    char        litstring[81];
  1064. X    char        ctrlstring[21];
  1065. X    char        c[2];
  1066. X    static char        alphastring[81];
  1067. X    int            i;
  1068. X    Boolean        add;
  1069. X    struct Token    *t;
  1070. X    PROFILE_BINDING    *pb, *pbchars, *pbctrlsequence;
  1071. X    PROFILE_VALUE    *pv;
  1072. X    
  1073. X    if (!tokenlist)
  1074. X    return NULL;
  1075. X    strcpy(alphastring, "");
  1076. X    if (!stanza) {
  1077. X    for (t = tokenlist; t; t = t->next)
  1078. X        switch (t->type) {
  1079. X        case string:
  1080. X        case integer:
  1081. X        case roman:
  1082. X        case comma:
  1083. X        case obrace:
  1084. X        case cbrace:
  1085. X        strcat(alphastring, t->lexeme);
  1086. X        break;
  1087. X        }
  1088. X    return alphastring;
  1089. X    } else {
  1090. X    if (pb = profile_has_binding(stanza, "mapindexentry")) {
  1091. X        strcpy(litstring, literalstring(tokenlist));
  1092. X        for (pv = pb->value; pv && pv->next; pv = pv->next, pv = pv->next)
  1093. X        if ((pv->class == PROFILE_STRING || pv->class == PROFILE_OTHER) && (pv->next->class == PROFILE_STRING ||
  1094. X        pv->next->class == PROFILE_OTHER))
  1095. X            if (eq(litstring, pv->value.s)) {
  1096. X            strcpy(alphastring, pv->next->value.s);
  1097. X            return alphastring;
  1098. X            }
  1099. X    } /* end if there is a mapindexentry binding */
  1100. X    pbchars = profile_has_binding(stanza, "skipchars");
  1101. X    pbctrlsequence = profile_has_binding(stanza, "mapctrlsequence");
  1102. X    c[1] = '\0';
  1103. X    for (t = tokenlist; t; t = t->next)
  1104. X        switch (t->type) {
  1105. X        case controlword:
  1106. X        case controlsymbol:
  1107. X        if (pbctrlsequence)
  1108. X            for (pv = pbctrlsequence->value; pv && pv->next; pv = pv->next, pv = pv->next)
  1109. X            if ((pv->class == PROFILE_STRING || pv->class == PROFILE_OTHER) && (pv->next->class == PROFILE_STRING ||
  1110. X            pv->next->class == PROFILE_OTHER))
  1111. X                if (strlen(pv->value.s) > 0) {
  1112. X                if (pv->value.s[0] != '\\')
  1113. X                    sprintf(ctrlstring, "\\%s", pv->value.s);
  1114. X                else
  1115. X                    strcpy(ctrlstring, pv->value.s);
  1116. X                if (eq(ctrlstring, t->lexeme))
  1117. X                    strcat(alphastring, pv->next->value.s);
  1118. X                }
  1119. X        break;
  1120. X        case string:
  1121. X        case integer:
  1122. X        case roman:
  1123. X        for (i = 0; t->lexeme[i]; i++)
  1124. X            if (pbchars) {
  1125. X            for (add = TRUE, pv = pbchars->value; pv && add; pv = pv->next)
  1126. X                if (pv->class == PROFILE_CHARACTER)
  1127. X                if (pv->value.c == t->lexeme[i])
  1128. X                    add = FALSE;
  1129. X            if (add) {
  1130. X                c[0] = t->lexeme[i];
  1131. X                strcat(alphastring, c);
  1132. X            }
  1133. X            } else {
  1134. X            c[0] = t->lexeme[i];
  1135. X            strcat(alphastring, c);
  1136. X            }
  1137. X        break;
  1138. X        case comma:
  1139. X        c[0] = ',';
  1140. X        goto insert;
  1141. X        case obrace:
  1142. X        c[0] = '{';
  1143. X        goto insert;
  1144. X        case cbrace:
  1145. X        c[0] = '}';
  1146. Xinsert:        if (pbchars) {
  1147. X            for (add = TRUE, pv = pbchars->value; pv && add; pv = pv->next)
  1148. X            if (pv->class == PROFILE_CHARACTER)
  1149. X                if (pv->value.c == c[0])
  1150. X                add = FALSE;
  1151. X            if (add)
  1152. X            strcat(alphastring, c);
  1153. X        } else
  1154. X            strcat(alphastring, c);
  1155. X        break;
  1156. X        }
  1157. X    return alphastring;
  1158. X    }
  1159. X}
  1160. X
  1161. X/* Finds an entry in a table. Returns NULL if not found. */
  1162. Xstruct IndexEntry    *findentry(table, noentries, string)
  1163. Xstruct IndexEntry     *table;
  1164. Xint            noentries;
  1165. Xchar            *string;
  1166. X{
  1167. X    int    i;
  1168. X
  1169. X    if (noentries <= 0)
  1170. X    return NULL;
  1171. X    for (i = 0; i < noentries; i++)
  1172. X    if (eq(string, table[i].literal))
  1173. X        return &table[i];
  1174. X    return NULL;
  1175. X}
  1176. X
  1177. X/* Returns pointer to page number if found, NULL otherwise */
  1178. Xstruct PageNoTable    *findpage(pagearray, elements, pageno, aromannum)
  1179. Xstruct PageNoTable    *pagearray;
  1180. Xint            elements;
  1181. Xint            pageno;
  1182. XBoolean            aromannum;
  1183. X{
  1184. X    int    i;
  1185. X
  1186. X    if (!pagearray)
  1187. X    return NULL;
  1188. X    for (i = 0; i < elements; i++)
  1189. X    if ((pagearray[i].number == pageno) &&
  1190. X        (pagearray[i].isroman == aromannum))
  1191. X        return &pagearray[i];
  1192. X    return NULL;
  1193. X}
  1194. X
  1195. X/* Sorts the entries in the structures */
  1196. Xsort(base, numberelements)
  1197. Xstruct IndexEntry    *base;
  1198. Xint            numberelements;
  1199. X{
  1200. X    int    i;
  1201. X    int numericcompare();
  1202. X    int alphacompare();
  1203. X
  1204. X    for (i = 0; i < numberelements; i++) {
  1205. X    if (base[i].pagenos)
  1206. X        qsort(base[i].pagenos, base[i].pagetablecount, sizeof(struct PageNoTable), numericcompare);
  1207. X    if (base[i].subitem)
  1208. X        sort(base[i].subitem, base[i].subitemcount);    /* recursion! */
  1209. X    }
  1210. X    qsort(base, numberelements, sizeof(struct IndexEntry), alphacompare);
  1211. X}
  1212. X
  1213. X/* Prints out the index entries */
  1214. Xprintindexentries(base, noelements, level)
  1215. Xstruct IndexEntry    *base;
  1216. Xint            noelements;
  1217. Xint            level;
  1218. X{
  1219. X    int             i, j;
  1220. X    Boolean         prevoutput = FALSE;
  1221. X    Boolean         prevrange = FALSE;
  1222. X    char            c;
  1223. X    char            letter = '\0';
  1224. X
  1225. X    if (level > ITEMDEPTH)
  1226. X        return;
  1227. X    for (i = 0; i < noelements; i++) {
  1228. X        if (level == 1)
  1229. X            if (strlen(base[i].alphabetic) > 0)
  1230. X                if (isalpha(base[i].alphabetic[0])) {
  1231. X                    if (isupper(c = base[i].alphabetic[0]))
  1232. X                        c = tolower(c);
  1233. X                    if (!letter) {
  1234. X                        if (Label) {
  1235. X                            fprintf(OutputFile, "\\indexspace\n");
  1236. X                            fprintf(OutputFile, "\\largeletter{%c}\n", c);
  1237. X                        } else if (prevoutput)
  1238. X                            fprintf(OutputFile, "\\indexspace\n");
  1239. X                    } else if (letter != c) {
  1240. X                        fprintf(OutputFile, "\\indexspace\n");
  1241. X                        if (Label)
  1242. X                            fprintf(OutputFile, "\\largeletter{%c}\n", c);
  1243. X                    }
  1244. X                    letter = c;
  1245. X                }
  1246. X        prevoutput = TRUE;
  1247. X        for (j = 1; j < level; j++)
  1248. X            fprintf(OutputFile, "  ");
  1249. X        fprintf(OutputFile, "%s %s ", ItemRep[level - 1], base[i].literal);
  1250. X        if (base[i].pagenos) {
  1251. X            for (j = 0; j < base[i].pagetablecount; j++) {
  1252. X                if (j == base[i].pagetablecount - 1) {
  1253. X                    if (base[i].pagenos[j].isroman == FALSE)
  1254. X                        fprintf(OutputFile, "%d\n", base[i].pagenos[j].number);
  1255. X                    else {
  1256. X                        fprintf(OutputFile, "{\\romannumeral %d}\n", base[i].pagenos[j].number);
  1257. X                    }
  1258. X                } else if (base[i].pagenos[j].range) {
  1259. X                    if (!prevrange) {
  1260. X                        if (base[i].pagenos[j].isroman == FALSE)
  1261. X                            fprintf(OutputFile, "%d--", base[i].pagenos[j].number);
  1262. X                        else {
  1263. X                            fprintf(OutputFile, "{\\romannumeral %d}--", base[i].pagenos[j].number);
  1264. X                        }
  1265. X                    }
  1266. X                } else {
  1267. X                    if (base[i].pagenos[j].isroman == FALSE)
  1268. X                        fprintf(OutputFile, "%d, ", base[i].pagenos[j].number);
  1269. X                    else {
  1270. X                        fprintf(OutputFile, "{\\romannumeral %d}, ", base[i].pagenos[j].number);
  1271. X                    }
  1272. X                }
  1273. X                prevrange = base[i].pagenos[j].range;
  1274. X            }
  1275. X            if (prevrange)
  1276. X                fprintf(stderr, "%s: file %s, %s %s ends with a range\n", Whoami, IdxFileName, ItemRep[level - 1],
  1277. X                    base[i].literal);
  1278. X        } else
  1279. X            fprintf(OutputFile, "\n");
  1280. X        if (base[i].subitem)
  1281. X            printindexentries(base[i].subitem, base[i].subitemcount, level + 1);    /* recursion! */
  1282. X    }
  1283. X}
  1284. X
  1285. Xint    numericcompare(e1, e2)
  1286. Xstruct PageNoTable    *e1, *e2;
  1287. X{
  1288. X    if ((e1->isroman == TRUE) && (e2->isroman == FALSE))
  1289. X        return -1;
  1290. X    if ((e1->isroman == FALSE) && (e2->isroman == TRUE))
  1291. X        return 1;
  1292. X           /* else either both roman or both integers */
  1293. X    if (e1->number == e2->number)
  1294. X    return 0;
  1295. X    else if (e1->number < e2->number)
  1296. X    return -1;
  1297. X    else
  1298. X    return 1;
  1299. X}
  1300. X
  1301. Xint alphacompare(e1, e2)
  1302. Xstruct IndexEntry    *e1, *e2;
  1303. X{
  1304. X    char    s1[81], s2[81];
  1305. X
  1306. X    strcpy(s1, e1->alphabetic), strcpy(s2, e2->alphabetic);
  1307. X    return(strcmp(string_downshift(s1), string_downshift(s2)));
  1308. X}
  1309. X
  1310. Xint rmtoi (romanstr)
  1311. Xchar *romanstr;
  1312. X{
  1313. X    register char  *p = romanstr;
  1314. X    register int    w;
  1315. X    register int    prevw = (-1);
  1316. X    register int    result = 0;
  1317. X    int             romanwt();
  1318. X
  1319. X    while (*p) {
  1320. X        if ((w = romanwt(*p)) == (-1)) {
  1321. X            fprintf(stderr, "illegal char in roman string:'%c'\n", (*p));
  1322. X            return (-1);
  1323. X        } else {
  1324. X            if (prevw > 0) {    /* check for subtractive
  1325. X                         * notation */
  1326. X                if (w > prevw) { /* e.g., the case "ix" */
  1327. X                    result += (w - prevw) - prevw;
  1328. X                } else
  1329. X                    result += w;
  1330. X            } else {
  1331. X                result += w;
  1332. X            }
  1333. X        }
  1334. X        prevw = w;
  1335. X        p++;
  1336. X    }
  1337. X    return (result);
  1338. X}
  1339. X
  1340. Xstatic int romanwt (c)
  1341. Xregister char c;
  1342. X{
  1343. X    static char     romanlett[7] = {'m', 'd', 'c', 'l', 'x', 'v', 'i'};
  1344. X    static int      weight[7] = {1000, 500, 100, 50, 10, 5, 1};
  1345. X
  1346. X    register char  *pt;
  1347. X
  1348. X    if (isupper(c))
  1349. X        c = tolower(c);
  1350. X    pt = romanlett;
  1351. X    while (*pt) {
  1352. X        if (*pt == c) {
  1353. X            return (weight[(int) (pt - romanlett)]);
  1354. X        } else
  1355. X            pt++;
  1356. X    }
  1357. X    return (-1);        /* roman letter not found */
  1358. X}
  1359. X
  1360. !FaR!OuT!
  1361. if [ ! -d indexsrc ]
  1362. then
  1363.     mkdir indexsrc
  1364.     echo mkdir indexsrc
  1365. fi
  1366. echo x - indexsrc/indexlex.l
  1367. sed -e 's/^X//' > indexsrc/indexlex.l << '!FaR!OuT!'
  1368. X/* $Header */
  1369. X/* Lex Lexical Analyzer for LaTeX index processor */
  1370. X/* Roman numeral code written by John Renner (adobe!renner@decwrl.dec.com) */
  1371. X%{
  1372. X#undef input
  1373. X#define input()    (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(InputFile)) \
  1374. X    ==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
  1375. X%}
  1376. Xletter        [A-Za-z]
  1377. Xinteger        -?[0-9]{1,9}
  1378. Xroman        [mdclxvi]+
  1379. Xwhitespace    [ \t\n]
  1380. X%%
  1381. X\\indexentry        {
  1382. X                LineNo = EndLineNo;
  1383. X                return(INDEXENTRY);
  1384. X            }
  1385. X{roman}            {            
  1386. X                LineNo = EndLineNo;
  1387. X                strcpy(yylval.value, yytext);
  1388. X                return(ROMAN);
  1389. X            }
  1390. X\\{letter}+        {    /* Control word */
  1391. X                LineNo = EndLineNo;
  1392. X                strcpy(yylval.value, yytext);
  1393. X                return(CONTROLSEQUENCE);
  1394. X            }
  1395. X\\[^{letter}]        {    /* Control symbol */
  1396. X                LineNo = EndLineNo;
  1397. X                strcpy(yylval.value, yytext);
  1398. X                return(CONTROLSEQUENCE);
  1399. X            }
  1400. X\%.*\n            LineNo = EndLineNo++;    /* Comment. Don't pass to parser */
  1401. X{integer}        {
  1402. X                LineNo = EndLineNo;
  1403. X                strcpy(yylval.value, yytext);
  1404. X                return(INTEGER);
  1405. X            }
  1406. X\{ |
  1407. X\} |
  1408. X\,            {
  1409. X                LineNo = EndLineNo;
  1410. X                return(yytext[0]);
  1411. X            }
  1412. X{whitespace}+        {
  1413. X                char    *p;    /* Utility variable */
  1414. X
  1415. X                LineNo = EndLineNo;
  1416. X                for (p = yytext; *p; p++)
  1417. X                if (*p == '\n')
  1418. X                    EndLineNo++;
  1419. X                strcpy(yylval.value, yytext);
  1420. X                return(WHITESPACE);
  1421. X            }
  1422. X[^\\\{\}\%\, \t\n0-9]+    {
  1423. X                LineNo = EndLineNo;
  1424. X                strcpy(yylval.value, yytext);
  1425. X                return(STRING);
  1426. X            }
  1427. X%%
  1428. !FaR!OuT!
  1429. if [ ! -d libglob ]
  1430. then
  1431.     mkdir libglob
  1432.     echo mkdir libglob
  1433. fi
  1434. echo x - libglob/Makefile
  1435. sed -e 's/^X//' > libglob/Makefile << '!FaR!OuT!'
  1436. X# @(#)Makefile    1.1 (TRW) 1/14/86
  1437. XCFLAGS = -O
  1438. X
  1439. X.c.o:
  1440. X    ${CC} ${CFLAGS} -c $*.c
  1441. X    -ld -x -r $*.o
  1442. X    mv a.out $*.o
  1443. X
  1444. Xall: libglob.a
  1445. X
  1446. Xlibglob.a: glob.o
  1447. X    ar cr libglob.a glob.o
  1448. X    ranlib libglob.a
  1449. X    chmod 644 libglob.a
  1450. X
  1451. Xinstall: all
  1452. X
  1453. Xclean:
  1454. X    rm -f *.o *.a
  1455. X
  1456. !FaR!OuT!
  1457. if [ ! -d libglob ]
  1458. then
  1459.     mkdir libglob
  1460.     echo mkdir libglob
  1461. fi
  1462. echo x - libglob/glob.c
  1463. sed -e 's/^X//' > libglob/glob.c << '!FaR!OuT!'
  1464. Xstatic char *trwsccs= "@(#)glob.c    1.1 (TRW) 1/14/86";
  1465. X#include "glob.h"
  1466. X
  1467. X#define SLOP 5
  1468. X#define MAX_SET 0177
  1469. X
  1470. X/* control codes for regular expression evaluation */
  1471. X#define PATTERN_ANY '?'
  1472. X#define PATTERN_CHARACTER 'X'
  1473. X#define PATTERN_END '$'
  1474. X#define PATTERN_SET '['
  1475. X#define PATTERN_SET_MEMBER 'M'
  1476. X#define PATTERN_SET_RANGE '-'
  1477. X#define PATTERN_STAR '*'
  1478. X
  1479. X/*
  1480. X * Examples (=> denotes `compiles into')
  1481. X *
  1482. X *    a    =>    Xa
  1483. X *    ?    =>    ?
  1484. X *    [x0-9]    =>    [^EMx-09    (^E is control-E)
  1485. X *    *    =>    *
  1486. X *    END    =>    $
  1487. X *
  1488. X *    a?[x0-9]* => Xa?[^EMx-09*$
  1489. X */
  1490. X
  1491. Xglob_compile (pattern, buffer)
  1492. Xchar *pattern;
  1493. Xchar *buffer;    /* compiled pattern */
  1494. X{
  1495. X    char *x;    /* pointer into compiled pattern */
  1496. X    int c;
  1497. X    int result;
  1498. X
  1499. X    if (pattern == 0 || pattern[0] == 0)
  1500. X        return(GLOB_PATTERN_EMPTY);
  1501. X
  1502. X    x = buffer;
  1503. X    while (x < &buffer[GLOB_MAX_PATTERN - SLOP]) {
  1504. X        c = *pattern++;
  1505. X        if (c == 0) {
  1506. X            *x++ = PATTERN_END;
  1507. X            return(GLOB_OK);
  1508. X        }
  1509. X
  1510. X        switch (c) {
  1511. X        case '?':
  1512. X            *x++ = PATTERN_ANY;
  1513. X            continue;
  1514. X
  1515. X        case '[':
  1516. X            if ((result = compile_set(pattern, x, &buffer[GLOB_MAX_PATTERN - SLOP])) < 0)
  1517. X                return(result);
  1518. X            pattern += result + 1;
  1519. X            x += x[1] + 2;
  1520. X            continue;
  1521. X
  1522. X        case '*':
  1523. X            *x++ = PATTERN_STAR;
  1524. X            continue;
  1525. X
  1526. X        default:
  1527. X            *x++ = PATTERN_CHARACTER;
  1528. X            *x++ = c;
  1529. X            continue;
  1530. X        }
  1531. X    }
  1532. X    return(GLOB_PATTERN_TOO_BIG);
  1533. X}
  1534. X
  1535. Xint glob_execute (pattern, s)
  1536. Xchar *pattern;    /* compiled pattern */
  1537. Xchar *s;    /* string to be matched against */
  1538. X{
  1539. X    char *current;
  1540. X    int result;
  1541. X
  1542. X    for (;;)
  1543. X        switch (*pattern++) {
  1544. X        case PATTERN_ANY:
  1545. X            if (*s++)
  1546. X                continue;
  1547. X            return(0);
  1548. X
  1549. X        case PATTERN_CHARACTER:
  1550. X            if (*pattern++ == *s++)
  1551. X                continue;
  1552. X            return(0);
  1553. X
  1554. X        case PATTERN_END:
  1555. X            return(*s == 0);
  1556. X
  1557. X        case PATTERN_SET:
  1558. X            if ((result = in_set(pattern, *s++)) == 1) {
  1559. X                pattern += *pattern + 1;
  1560. X                continue;
  1561. X            }
  1562. X            return(result);
  1563. X
  1564. X        case PATTERN_STAR:
  1565. X            current = s;
  1566. X            while (*s++)
  1567. X                continue;
  1568. X            do {
  1569. X                s--;
  1570. X                if (result = glob_execute(pattern, s))
  1571. X                    return(result);
  1572. X            } while (s > current);
  1573. X            return(0);
  1574. X
  1575. X        default:
  1576. X            return(GLOB_EXECUTION_ERROR);
  1577. X        }
  1578. X}
  1579. X
  1580. Xint glob_match (pattern, s)
  1581. Xchar *pattern;
  1582. Xchar *s;
  1583. X{
  1584. X    int result;
  1585. X    char buffer[GLOB_MAX_PATTERN];
  1586. X
  1587. X    if ((result = glob_compile(pattern, buffer)) < 0)
  1588. X        return(result);
  1589. X    else
  1590. X        return(glob_execute(buffer, s));
  1591. X}
  1592. X
  1593. X/* returns 1 if character c is member of set and 0 otherwise */
  1594. Xstatic int in_set (set, c)
  1595. Xchar *set;    /* compiled set pattern */
  1596. Xchar c;
  1597. X{
  1598. X    int n;
  1599. X
  1600. X    if (c == 0)
  1601. X        return(0);
  1602. X    n = *set++;
  1603. X    while (n > 0)
  1604. X        switch (*set++) {
  1605. X        case PATTERN_SET_MEMBER:
  1606. X            if (*set++ == c)
  1607. X                return(1);
  1608. X            n -= 2;
  1609. X            continue;
  1610. X
  1611. X        case PATTERN_SET_RANGE:
  1612. X            if (*set++ <= c && c <= *set++)
  1613. X                return(1);
  1614. X            n -= 3;
  1615. X            continue;
  1616. X
  1617. X        default:
  1618. X            return(GLOB_EXECUTION_ERROR);
  1619. X        }
  1620. X    return(0);
  1621. X}
  1622. X
  1623. X#define IS_RANGE(s) (s[1] && s[2] && s[1] == '-' && s[2] != ']')
  1624. X
  1625. X/* compiles a set returning the number of pattern characters consumed */
  1626. Xstatic int compile_set (pattern, x, limit)
  1627. Xchar *pattern;
  1628. Xchar *x;
  1629. Xchar *limit;
  1630. X{
  1631. X    char *slot;    /* size of set goes here */
  1632. X    int size;    /* number of bytes in compiled set */
  1633. X    char *start = pattern;
  1634. X
  1635. X    if (*pattern == 0)
  1636. X        return(GLOB_BRACKET_MISSING);
  1637. X
  1638. X    *x++ = PATTERN_SET;
  1639. X    slot = x++;
  1640. X    size = 0;
  1641. X
  1642. X    if (IS_RANGE(pattern)) {
  1643. X        if (pattern[0] > pattern[2])    /* pattern[1] == '-' */
  1644. X            return(GLOB_RANGE_INVERTED);
  1645. X        *x++ = PATTERN_SET_RANGE;
  1646. X        *x++ = pattern[0];
  1647. X        *x++ = pattern[2];
  1648. X        pattern += 3;
  1649. X        size += 3;
  1650. X    } else {
  1651. X        *x++ = PATTERN_SET_MEMBER;
  1652. X        *x++ = *pattern++;
  1653. X        size += 2;
  1654. X    }
  1655. X
  1656. X    while (*pattern != ']' && x < limit) {
  1657. X        if (*pattern == 0)
  1658. X            return(GLOB_BRACKET_MISSING);
  1659. X        if (IS_RANGE(pattern)) {
  1660. X            if (pattern[0] > pattern[2])    /* pattern[1] == '-' */
  1661. X                return(GLOB_RANGE_INVERTED);
  1662. X            *x++ = PATTERN_SET_RANGE;
  1663. X            *x++ = pattern[0];
  1664. X            *x++ = pattern[2];
  1665. X            pattern += 3;
  1666. X            size += 3;
  1667. X        } else {
  1668. X            *x++ = PATTERN_SET_MEMBER;
  1669. X            *x++ = *pattern++;
  1670. X            size += 2;
  1671. X        }
  1672. X    }
  1673. X    if (size > MAX_SET)
  1674. X        return(GLOB_SET_TOO_BIG);
  1675. X    *slot = size;
  1676. X    return(pattern - start);
  1677. X}
  1678. !FaR!OuT!
  1679. if [ ! -d libglob ]
  1680. then
  1681.     mkdir libglob
  1682.     echo mkdir libglob
  1683. fi
  1684. echo x - libglob/glob.h
  1685. sed -e 's/^X//' > libglob/glob.h << '!FaR!OuT!'
  1686. X/* @(#)glob.h    1.1 (TRW) 1/14/86 */
  1687. X#define GLOB_MAX_PATTERN    1024
  1688. X#define GLOB_OK            0
  1689. X#define GLOB_PATTERN_TOO_BIG    -1
  1690. X#define GLOB_PATTERN_EMPTY    -2
  1691. X#define GLOB_BRACKET_MISSING    -3
  1692. X#define GLOB_RANGE_INVERTED    -4
  1693. X#define GLOB_SET_TOO_BIG    -5
  1694. X#define GLOB_EXECUTION_ERROR    -6
  1695. !FaR!OuT!
  1696. exit
  1697.