Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!ll-xn!ames!necntc!ncoast!allbery From: simpson@trwrb.UUCP (Scott Simpson) Newsgroups: comp.sources.misc Subject: LaTeX Index Processor (Part 1 of 2) Message-ID: <2836@ncoast.UUCP> Date: Thu, 9-Jul-87 22:02:01 EDT Article-I.D.: ncoast.2836 Posted: Thu Jul 9 22:02:01 1987 Date-Received: Sun, 12-Jul-87 10:46:02 EDT Sender: allbery@ncoast.UUCP Lines: 1689 Approved: allbery@ncoast.UUCP X-Archive: comp.sources.misc/8707/40 This is a repost of the LaTeX index processor I posted ages ago. Thanks to John Renner (adobe!renner@decwrl.dec.com) it now handles roman numeral page numbering too. It does not handle upper case roman numeral page numbering though. You might want to install the libraries distributed with it, especially the profile library. It is quite useful. To make it, type "make install". Don't worry, it won't actually install anything. Scott Simpson TRW Electronics and Defense Sector ...{decvax,ihnp4,ucbvax}!trwrb!simpson #! /bin/sh # To extract, remove mail header lines and type "sh filename" echo x - Makefile sed -e 's/^X//' > Makefile << '!FaR!OuT!' X# $Header$ XCFLAGS=-O X Xall: getopt.o shift.o X cd libglob;make all X cd libprofile;make all X cd indexsrc;make all X Xinstall: all X mv indexsrc/index . X Xclean: X -rm index getopt.o shift.o X cd libglob;make clean X cd libprofile;make clean X cd indexsrc;make clean !FaR!OuT! echo x - getopt.c sed -e 's/^X//' > getopt.c << '!FaR!OuT!' X/* @(#)getopt.c 2.1 (TRW) 3/8/86 */ X#includeX X/* X * get option letter from argument vector X */ Xint opterr = 1, /* useless, never set or used */ X optind = 1, /* index into parent argv vector */ X optopt; /* character checked for validity */ Xchar *optarg; /* argument associated with option */ X X#define BADCH (int)'?' X#define EMSG "" X#define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \ X fputc(optopt,stderr);fputc('\n',stderr);return(BADCH); X Xgetopt(nargc,nargv,ostr) Xint nargc; Xchar **nargv, X *ostr; X{ X static char *place = EMSG; /* option letter processing */ X register char *oli; /* option letter list index */ X char *index(); X X if(!*place) { /* update scanning pointer */ X if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF); X if (*place == '-') { /* found "--" */ X ++optind; X return(EOF); X } X } /* option letter okay? */ X if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) { X if(!*place) ++optind; X tell(": illegal option -- "); X } X if (*++oli != ':') { /* don't need argument */ X optarg = NULL; X if (!*place) ++optind; X } X else { /* need an argument */ X if (*place) optarg = place; /* no white space */ X else if (nargc <= ++optind) { /* no arg */ X place = EMSG; X tell(": option requires an argument -- "); X } X else optarg = nargv[optind]; /* white space */ X place = EMSG; X ++optind; X } X return(optopt); /* dump back option letter */ X} !FaR!OuT! if [ ! -d include.local ] then mkdir include.local echo mkdir include.local fi echo x - include.local/standard.h sed -e 's/^X//' > include.local/standard.h << '!FaR!OuT!' X/* $Header */ X#include "standenviron.h" X#include "standconst.h" X#include "standtype.h" X#include "standmacro.h" !FaR!OuT! if [ ! -d include.local ] then mkdir include.local echo mkdir include.local fi echo x - include.local/standconst.h sed -e 's/^X//' > include.local/standconst.h << '!FaR!OuT!' X/* $Header */ X/* Standard constants. */ X#ifndef STANDARD_CONST X#define STANDARD_CONST X X/* X * These are the only values boolean variables may be set to, X * or that boolean functions may return. X */ X#define TRUE 1 X#define FALSE 0 X X/* X * Program exit status. X * These two codes are intended to be used as arguments to the X * exit(2) system call. Obviously, more failure codes may be X * defined but for simple programs that need indicate only X * success or failure these will suffice. X */ X#define SUCCEED 0 /* successful program execution */ X#define FAIL 1 /* some error in running program */ X X/* All bits on or off. */ X#define ON ~(long)0 /* all bits set */ X#define OFF (long)0 /* all bits off */ X X/* UNIX file descriptor numbers for standard input, output, and error. */ X#define STANDARD_IN 0 X#define STANDARD_OUT 1 X#define STANDARD_ERROR 2 X X X/* X * Extreme values. X * These constants are the largest and smallest values X * that variables of the indicated type may hold. X */ X#if defined(vax) || defined(pyr) X# define MAX_TINY 0x7f X# define MIN_TINY 0x80 X X# define MAX_UNSIGNED_TINY 0xff X# define MIN_UNSIGNED_TINY 0 X X# define MAX_SHORT 0x7fff X# define MIN_SHORT 0x8000 X X# define MAX_UNSIGNED_SHORT 0xffff X# define MIN_UNSIGNED_SHORT 0 X X# define MAX_INTEGER 0x7fffffff X# define MIN_INTEGER 0x80000000 X X# define MAX_UNSIGNED_INTEGER 0xffffffff X# define MIN_UNSIGNED_INTEGER 0 X X# define MAX_LONG MAX_INTEGER X# define MIN_LONG MIN_INTEGER X# define MAX_UNSIGNED_LONG MAX_UNSIGNED_INTEGER X# define MIN_UNSIGNED_LONG MIN_UNSIGNED_INTEGER X# define BITS_PER_BYTE 8 X#endif X X/* for pointers */ X#define NIL ((long)0) X#endif STANDARD_CONST !FaR!OuT! if [ ! -d include.local ] then mkdir include.local echo mkdir include.local fi echo x - include.local/standenviron.h sed -e 's/^X//' > include.local/standenviron.h << '!FaR!OuT!' X/* $Header */ X/* X * This file defines the machine/compiler C environment. It defines X * pre-processor macros that tell what C features are supported. X * X * #define HAS_UNSIGNED_SHORT Implies unsigned shorts are supported X * #define CHAR_IS_SIGNED Implies chars are signed X * #define HAS_UNSIGNED_CHAR Implies unsigned chars are supported X * #define HAS_UNSIGNED_LONG Implies unsigned longs are supported X * #define BITS_PER_CHAR n Number of bits in a char X * #define BITS_PER_INT n Number of bits in an int X * #define BITS_PER_LONG n Number of bits in a long X * #define BITS_PER_POINTER n Number of bits in a pointer X * #define BITS_PER_SHORT n Number of bits in a short X * #define HAS_VOID Implies void function type is supported X */ X X#ifndef STANDARD_ENVIRON /* prevent multiple inclusions */ X X#if defined(vax) || defined(pyr) X# define HAS_UNSIGNED_SHORT X# define CHAR_IS_SIGNED X# define HAS_UNSIGNED_CHAR X# define HAS_UNSIGNED_LONG X# define HAS_VOID X X# define BITS_PER_CHAR 8 X# define BITS_PER_SHORT 16 X# define BITS_PER_INT 32 X# define BITS_PER_LONG 32 X# define BITS_PER_POINTER 32 X# define STANDARD_ENVIRON X#endif X X#endif STANDARD_ENVIRON X X/* make sure a known processor type was specified */ X#ifndef STANDARD_ENVIRON X# include "Processor type unknown or unspecified" X#endif STANDARD_ENVIRON !FaR!OuT! if [ ! -d include.local ] then mkdir include.local echo mkdir include.local fi echo x - include.local/standmacro.h sed -e 's/^X//' > include.local/standmacro.h << '!FaR!OuT!' X/* $Header */ X#ifndef STANDARD_MACRO X#define STANDARD_MACRO X#define MAX(x, y) ((x) > (y) ? (x) : (y)) X#define MIN(x, y) ((x) < (y) ? (x) : (y)) X#define ABS(x) ((x) < 0 ? -(x) : (x)) X#define ROUND(x) ((int)(((x)<0)?((x)-0.5):((x)+0.5))) X#define CEILING(x) (((x)>=0)?(int)(x)==(x)?(int)(x):(int)((x)+1):(int)(x)) X#define FLOOR(x) (((x)>=0)?(int)(x):(int)(x)==(x)?(int)(x):(int)((x)-1)) X#define EQ(s, t) (!strcmp(s, t)) X#define EQN(s, t, n) (!strncmp(s, t, n)) X#endif STANDARD_MACRO !FaR!OuT! if [ ! -d include.local ] then mkdir include.local echo mkdir include.local fi echo x - include.local/standtype.h sed -e 's/^X//' > include.local/standtype.h << '!FaR!OuT!' X/* $Header */ X/* Standard machine independent type definitions. */ X X#ifndef STANDARD_TYPE /* prevent multiple inclusions */ X#define STANDARD_TYPE X X/* X * Integers X * Tiny/UnsignedTiny 8+ bit integers X * Short/UnsignedShort 16+ bit integers X * Integer/UnsignedInteger natural machine integer size X * Long/UnsignedLong 32+ bit integers X * X * Bits X * TinyBits 8+ bits X * Bits 16+ bits X * LongBits 32+ bits X * X * Booleans X * TinyBoolean X * Boolean X * X * Void X * X * Storage Classes X * Export Seen in other compilation units X * Import Supplied by another compilation unit X * Local Unseen outside compilation unit X */ X X/* X * Each of the following sections for the integer types defines both X * a base type and an extraction macro for the value. X */ X Xtypedef char Tiny; X/* Not all machines have signed characters so we may have to simulate them. */ X#ifdef CHAR_IS_SIGNED X# define TINY(x) (x) X#else X# define TINY(x) (((x) & MIN_TINY) ? (~MAX_TINY | (x)) : (x)) X#endif CHAR_IS_SIGNED X X/* Not all compilers support unsigned chars so we may have to simulate them. */ X#ifdef HAS_UNSIGNED_CHAR X typedef unsigned char UnsignedTiny; X#else X typedef char UnsignedTiny; X#endif HAS_UNSIGNED_CHAR X#ifdef CHAR_IS_SIGNED X# define UNSIGNED_TINY(x) ((x) & MAX_UNSIGNED_TINY) X#else X# define UNSIGNED_TINY(x) (x) X#endif X X/* X * All compilers have signed short integers. This type is included X * for lexical consistency. X */ Xtypedef short Short; X X/* Not all compilers support unsigned shorts so we may have to simulate them. */ X#ifdef HAS_UNSIGNED_SHORT X typedef unsigned short UnsignedShort; X#else X typedef short UnsignedShort; X#endif X# define UNSIGNED_SHORT(x) ((unsigned)(x) & MAX_UNSIGNED_SHORT) X X/* These types are solely for lexical consistency. */ Xtypedef int Integer; Xtypedef unsigned int UnsignedInteger; X Xtypedef long Long; X X/* Not all compilers support unsigned longs so we may have to simulate them. */ X#ifdef HAS_UNSIGNED_LONG X typedef unsigned long UnsignedLong; X# define UNSIGNED_LONG(s) ((UnsignedLong)(x)) X#else X typedef long UnsignedLong; X# define UNSIGNED_LONG(x) ((long)(x) & MAX_LONG) X#endif HAS_UNSIGNED_LONG X X/* Boolean types take on only the values TRUE or FALSE. */ Xtypedef char TinyBoolean; Xtypedef short Boolean; X X/* This type is included for lexical consistency. */ Xtypedef char Character; X X/* Bit types are used only for bit set, clear and test operations. */ Xtypedef char TinyBits; Xtypedef short Bits; Xtypedef long LongBits; X X/* Not all compilers support void functions so we may have to simulate it. */ X#ifdef HAS_VOID X# define Void void X#else X typedef int Void; X#endif X X/* Storage classes. */ X#define Export X#define Import extern X#define Local static X X#endif STANDARD_TYPE !FaR!OuT! if [ ! -d indexsrc ] then mkdir indexsrc echo mkdir indexsrc fi echo x - indexsrc/Makefile sed -e 's/^X//' > indexsrc/Makefile << '!FaR!OuT!' X# $Header: Makefile,v 1.1 86/06/10 08:25:26 control Exp $ XLDFLAGS=-s XCFLAGS=-O -I../libglob -I../libprofile -I../include.local X Xall: index X Xindex: indexlex.c index.o X $(CC) $(CFLAGS) $(LDFLAGS) -o index index.o ../getopt.o ../shift.o \ X ../libprofile/libprofile.a ../libglob/libglob.a -ll X Xindexlex.c: indexlex.l X Xindex.o: indexlex.c X Xinstall: all X Xclean: X -rm *.o lex.yy.c y.tab.c indexlex.c index !FaR!OuT! if [ ! -d indexsrc ] then mkdir indexsrc echo mkdir indexsrc fi echo x - indexsrc/index.y sed -e 's/^X//' > indexsrc/index.y << '!FaR!OuT!' X/* $Header */ X/* Yacc parser for LaTeX index processor */ X/* Roman numeral code written by John Renner (adobe!renner@decwrl.dec.com) */ X%{ X#include X#include "standard.h" X#include "profile.h" X#include X#include X#define TABLEINCREMENT 50 /* Number of additional entries added when expanding a table */ X#define eq(s,t) (!strcmp((s),(t))) X#define odd(i) (((i) % 2) == 1) X#define ITEMDEPTH 3 /* Number of nestings of \item's, \subitem's, \subsubitem's, etc. */ Xchar *ItemRep[] = { "\\item", "\\subitem", "\\subsubitem", NULL }; /* and their representation */ Xchar *calloc(), *realloc(); Xenum TokenType {controlword, controlsymbol, string, integer, roman, comma, obrace, cbrace, whitespace}; Xstruct IndexEntry { X char literal[81]; /* Literal representation of index entry */ X char alphabetic[81]; /* Alphabetic representation for sorting of index entry */ X struct Token *tokenlist; /* Doubly linked token list */ X struct IndexEntry *subitem; /* Pointer to subitem table, subsubitem table, etc */ X int subitemcount; /* Number of items in subitem table */ X int subitemtabsize; /* Subitem table size currently allocated */ X struct PageNoTable *pagenos; /* List of page numbers */ X int pagetablecount; /* Number of items in page number table */ X int pagetablesize; /* Size of page number table currently allocated */ X}; Xstruct Token { X enum TokenType type; /* Token type */ X char lexeme[81]; /* Representation of all the token types */ X struct Token *prev, *next; X}; Xstruct PageNoTable { X int number; /* Page number */ X Boolean range; /* True if this is the beginning of a range */ X Boolean isroman; /* True if this was a roman numeral */ X}; Xstruct IndexEntry *IndexTable = NULL; /* Table of primary index entries */ Xint IndexTableCount = 0; /* Count of number of elements used in index table */ Xint IndexTableSize = 0; /* Current allocated size of index table */ Xint ExitStatus = SUCCEED; /* Guess */ Xint LineNo = 1; /* Line number at start of token */ Xint EndLineNo = 1; /* Line number at end of token */ XBoolean Label = FALSE; /* True if -l option given */ XBoolean Range; /* True if this \indexentry is a range */ XPROFILE_STANZA *SortStanza = NULL; /* Alphabetize stanza */ Xextern int optind; /* From getopt(3) */ Xextern char *optarg; Xchar *Whoami; /* argv[0] */ Xchar *Usage = "Usage: %s [-l] [-f alphabetizefile] [file...]\n"; Xchar *Marker[] = { "alphabetize", NULL }; /* Markers for alphabetize stanza */ Xchar IdxFileName[81]; /* .idx file name */ Xchar Literal[81]; /* Literal string of key */ Xchar Alphabetic[81]; /* Alphabetic string of key */ XFILE *InputFile; /* Current input file */ XFILE *OutputFile; /* Current output file */ Xstruct Token *CurKey; /* Current key we are constructing */ Xstruct IndexEntry **CurSearchTable; /* Current table to search for match */ Xstruct IndexEntry *CurEntry; /* Current table entry */ Xstruct IndexEntry *PrevEntry; /* Previous Entry */ X%} X%union { X char value[81]; X struct Token *t; X} X%token ROMAN CONTROLSEQUENCE INTEGER WHITESPACE STRING INDEXENTRY X%type noncommaelement anyelement anyelements X%% Xindexfile : X optwhitespace X indexentries X { X sort(IndexTable, IndexTableCount); X fprintf(OutputFile, "\\begin{theindex}\n"); X if (Label) { X fprintf(OutputFile, X "\\newcommand{\\largeletter}[1]{{\\pagebreak[2]\\Large\\hspace{-.5in}\\parbox[t]{.5in}{\\makebox[.35in][r]"); X fprintf(OutputFile, "{\\uppercase{#1}}}\\nopagebreak[4]\\vspace{-1.5ex}}}\n"); X } X printindexentries(IndexTable, IndexTableCount, 1); X fprintf(OutputFile, "\\end{theindex}\n"); X } X ; X Xindexentries : X indexentries X indexentry X | X indexentry X ; X Xindexentry : X INDEXENTRY X { X CurSearchTable = &IndexTable, PrevEntry = NULL; X CurKey = NULL; X Range = FALSE; X } X optwhitespace X '{' X keys X '}' X optwhitespace X '{' X optwhitespace X anumber X optwhitespace X '}' X optwhitespace X ; X Xanumber : X INTEGER X { X struct PageNoTable *p; X X if (!(p = findpage(CurEntry->pagenos, CurEntry->pagetablecount, atoi($1), FALSE))) { X if (CurEntry->pagetablecount >= CurEntry->pagetablesize) { X if (!(CurEntry->pagenos = (struct PageNoTable *)reallocate(CurEntry->pagenos, CurEntry->pagetablesize, X TABLEINCREMENT, sizeof(struct PageNoTable)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X CurEntry->pagetablesize += TABLEINCREMENT; X } X CurEntry->pagenos[CurEntry->pagetablecount].number = atoi($1); X CurEntry->pagenos[CurEntry->pagetablecount].isroman = FALSE; X CurEntry->pagenos[CurEntry->pagetablecount].range = Range; X CurEntry->pagetablecount++; X } else X p->range = Range; X } X | X ROMAN X { X struct PageNoTable *p; X X if (!(p = findpage(CurEntry->pagenos, CurEntry->pagetablecount, rmtoi($1), TRUE))) { X if (CurEntry->pagetablecount >= CurEntry->pagetablesize) { X if (!(CurEntry->pagenos = (struct PageNoTable *)reallocate(CurEntry->pagenos, CurEntry->pagetablesize, X TABLEINCREMENT, sizeof(struct PageNoTable)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X CurEntry->pagetablesize += TABLEINCREMENT; X } X CurEntry->pagenos[CurEntry->pagetablecount].number = rmtoi($1); X CurEntry->pagenos[CurEntry->pagetablecount].isroman = TRUE; X CurEntry->pagenos[CurEntry->pagetablecount].range = Range; X CurEntry->pagetablecount++; X } else X p->range = Range; X } X X Xkeys : X multiplekeys X key X { X struct Token *t; X X for (t = CurKey; t->next; t = t->next) X ; X if (t->type == string) X if (t->lexeme[strlen(t->lexeme) - 1] == '-') { X t->lexeme[strlen(t->lexeme) - 1] = '\0'; X Range = TRUE; X } X goto installkey; X } X ; X Xmultiplekeys : X multiplekeys X key X ',' X { X struct Token *t; X Xinstallkey: strcpy(Literal, literalstring(CurKey)); X strcpy(Alphabetic, alphabetizestring(CurKey, SortStanza)); X if (!*CurSearchTable) { X if (!(*CurSearchTable = (struct IndexEntry *)reallocate(*CurSearchTable, 0, TABLEINCREMENT, X sizeof(struct IndexEntry)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X if (!PrevEntry) X IndexTableSize = TABLEINCREMENT; X else X PrevEntry->subitemtabsize = TABLEINCREMENT; X } X if (!(CurEntry = findentry(*CurSearchTable, PrevEntry ? PrevEntry->subitemcount : IndexTableCount, Literal))) { X if (!PrevEntry) { X if (IndexTableCount >= IndexTableSize) { X if (!(*CurSearchTable = (struct IndexEntry *)reallocate(*CurSearchTable, IndexTableSize, TABLEINCREMENT, X sizeof(struct IndexEntry)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X IndexTableSize += TABLEINCREMENT; X } X CurEntry = (*CurSearchTable + IndexTableCount); X IndexTableCount++; X } else { X if (PrevEntry->subitemcount >= PrevEntry->subitemtabsize) { X if (!(*CurSearchTable = (struct IndexEntry *)reallocate(*CurSearchTable, PrevEntry->subitemtabsize, X TABLEINCREMENT, sizeof(struct IndexEntry)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X PrevEntry->subitemtabsize += TABLEINCREMENT; X } X CurEntry = (*CurSearchTable + PrevEntry->subitemcount); X PrevEntry->subitemcount++; X } X strcpy(CurEntry->literal, Literal); X strcpy(CurEntry->alphabetic, Alphabetic); X CurKey->prev = CurEntry->tokenlist, CurEntry->tokenlist = CurKey; X CurEntry->subitem = NULL, CurEntry->subitemcount = CurEntry->subitemtabsize = 0; X CurEntry->pagenos = NULL, CurEntry->pagetablecount = CurEntry->pagetablesize = 0; X } X CurSearchTable = &CurEntry->subitem; X PrevEntry = CurEntry; X CurKey = NULL; X } X | X /* epsilon */ X ; X Xkey : X key X noncommaelement X | X noncommaelement X ; X Xnoncommaelement : X CONTROLSEQUENCE X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = isalpha($1[1]) ? controlword : controlsymbol; X strcpy($$->lexeme, $1); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X | X ROMAN X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = roman; X strcpy($$->lexeme, $1); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X | X INTEGER X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = integer; X strcpy($$->lexeme, $1); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X | X WHITESPACE X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = whitespace; X strcpy($$->lexeme, $1); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X | X STRING X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = string; X strcpy($$->lexeme, $1); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X | X '{' X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = obrace; X strcpy($$->lexeme, "{"); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X } X anyelements X '}' X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = cbrace; X strcpy($$->lexeme, "}"); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X ; X Xanyelements : X anyelements X anyelement X { X $$ = $2; X } X | X anyelement /* Default action is $$ = $1 */ X ; X Xanyelement : X noncommaelement /* Default action is $$ = $1 */ X | X ',' X { X if (!($$ = (struct Token *)calloc(1, sizeof(struct Token)))) { X yyerror("memory allocation failure"); X exit(FAIL); X } X $$->type = comma; X strcpy($$->lexeme, ","); X $$->next = NULL; X if (!CurKey) X $$->prev = CurKey, CurKey = $$; X else { X struct Token *p; X X for (p = CurKey; p->next; p = p->next) X ; X p->next = $$, $$->prev = p; X } X $$ = CurKey; X } X ; X Xoptwhitespace : X WHITESPACE X | X ; X X%% X#include "indexlex.c" X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X int c; X Boolean sortfilegiven = FALSE; X char sortfilename[81]; X char indfilename[81]; X struct passwd *pwentry; X FILE *stanzafileptr; X X Whoami = argv[0]; X pwentry = getpwuid(geteuid()); X sprintf(sortfilename, "%s/.alphabetize", pwentry->pw_dir); X while ((c = getopt(argc, argv, "f:l")) != EOF) X switch (c) { X case 'l': X Label = TRUE; X break; X case 'f': X strcpy(sortfilename, optarg); X sortfilegiven = TRUE; X break; X case '?': X fprintf(stderr, Usage, Whoami); X exit(FAIL); X } X stanzafileptr = fopen(sortfilename, "r"); X if (sortfilegiven && !stanzafileptr) { X fprintf(stderr, "%s: cannot open alphabetization file %s\n", Whoami, sortfilename); X exit(FAIL); X } X if (stanzafileptr) { X if (!(SortStanza = profile_read_profile(stanzafileptr))) { X fprintf(stderr, "%s: file %s is not in stanza format\n", Whoami, sortfilename); X fclose(stanzafileptr); X exit(FAIL); X } X if (!(SortStanza = profile_has_stanza(SortStanza, Marker))) { X fprintf(stderr, "%s: file %s does not contain a stanza with marker %s\n", Whoami, sortfilename, Marker[0]); X fclose(stanzafileptr); X exit(FAIL); X } X fclose(stanzafileptr); X } X checkstanza(SortStanza); X if (optind == argc) { X InputFile = stdin; X OutputFile = stdout; X strcpy(IdxFileName, "stdin"); X } X do { X if (InputFile != stdin) { X strcpy(IdxFileName, argv[optind]); X if (!(InputFile = fopen(argv[optind], "r"))) { X strcpy(IdxFileName, argv[optind]); X strcat(IdxFileName, ".idx"); X if (!(InputFile = fopen(IdxFileName, "r"))) { X fprintf(stderr, "%s: cannot open %s\n", Whoami, IdxFileName); X ExitStatus = FAIL; X continue; X } X } X if (strlen(IdxFileName) >= 4 && eq(&IdxFileName[strlen(IdxFileName)-4], ".idx")) X sprintf(indfilename, "%.*s.ind", strlen(IdxFileName)-4, IdxFileName); X else X sprintf(indfilename, "%s.ind", IdxFileName); X if (!(OutputFile = fopen(indfilename, "w"))) { X fprintf(stderr, "%s: cannot open output file %s\n", Whoami, indfilename); X fclose(InputFile); X ExitStatus = FAIL; X continue; X } X } else X strcpy(IdxFileName, "stdin"); X if (yyparse() != 0) X ExitStatus = FAIL; X fclose(InputFile); X fclose(OutputFile); X freetables(IndexTable, IndexTableCount); X IndexTable = NULL, IndexTableCount = IndexTableSize = 0, LineNo = EndLineNo = 1; X yysptr = yysbuf; /* Resets Lex lookahead buffer */ X } while (++optind < argc); X exit(ExitStatus); X} X Xyyerror(s) Xchar *s; X{ X fprintf(stderr, "\"%s\", line %d: %s\n", IdxFileName, LineNo, s); X} X X/* Allocates additional space for tables. Returns NULL if memory allocation failure or inconsistent parameters */ Xchar *reallocate(table, current, increment, elementsize) Xchar *table; /* pointer to current table */ Xint current; /* current size of table */ Xint increment; /* additional entries to add */ Xint elementsize; /* size of an element in the table */ X{ X char *calloc(), *realloc(); X char *p; X X if ((!table && current > 0) || current < 0 || increment < 0 || elementsize < 0) X return NULL; X if (increment == 0 || elementsize == 0) X return table; X if (current == 0) X if (!(p = calloc(increment, elementsize))) X return NULL; X else X return p; X else X if (!(p = realloc(table, (current + increment) * elementsize))) X return NULL; X else X return p; X} X X/* Frees the space allocated for all the tables */ Xfreetables(index, noentries) Xstruct IndexEntry *index; /* index table */ Xint noentries; /* number of entries in table */ X{ X struct Token *t, *ttemp; X int i; X X if (!index || noentries == 0) X return; X for (i = 0; i < noentries; i++) X if (index[i].subitem) X freetables(index[i].subitem, index[i].subitemcount); /* recursion! */ X for (t = index[i].tokenlist; t; t = ttemp) X ttemp = t->next, free(t); X if (index[i].pagenos) X free(index[i].pagenos); X free(index); X} X X/* Checks alphabetize stanza for validity */ Xcheckstanza(ps) XPROFILE_STANZA *ps; X{ X PROFILE_BINDING *pb; X PROFILE_VALUE *pv; X int count; X X if (!ps) X return; X if (pb = profile_has_binding(ps, "skipchars")) X for (pv = pb->value; pv; pv = pv->next) X if (pv->class != PROFILE_CHARACTER) X switch (pv->class) { X case PROFILE_INTEGER: X fprintf(stderr, "%s: illegal integer constant %d in skipchars binding\n", Whoami, pv->value.i); X break; X case PROFILE_HEX: X fprintf(stderr, "%s: illegal hex constant 0x%x in skipchars binding\n", Whoami, pv->value.i); X break; X case PROFILE_OCTAL: X fprintf(stderr, "%s: illegal octal constant 0%o in skipchars binding\n", Whoami, pv->value.i); X break; X case PROFILE_FLOAT: X fprintf(stderr, "%s: illegal float constant %f in skipchars binding\n", Whoami, pv->value.f); X break; X case PROFILE_STRING: X case PROFILE_OTHER: X fprintf(stderr, "%s: illegal string constant %s in skipchars binding\n", Whoami, pv->value.s); X break; X } X if (pb = profile_has_binding(ps, "mapctrlsequence")) { X for (count = 0, pv = pb->value; pv; pv = pv->next, count++) X if (pv->class != PROFILE_OTHER || pv->class != PROFILE_STRING) X switch (pv->class) { X case PROFILE_INTEGER: X fprintf(stderr, "%s: illegal integer constant %d in mapctrlsequence binding\n", Whoami, pv->value.i); X break; X case PROFILE_HEX: X fprintf(stderr, "%s: illegal hex constant 0x%x in mapctrlsequence binding\n", Whoami, pv->value.i); X break; X case PROFILE_OCTAL: X fprintf(stderr, "%s: illegal octal constant 0%o in mapctrlsequence binding\n", Whoami, pv->value.i); X break; X case PROFILE_FLOAT: X fprintf(stderr, "%s: illegal float constant %f in mapctrlsequence binding\n", Whoami, pv->value.f); X break; X case PROFILE_CHARACTER: X fprintf(stderr, "%s: illegal character constant %c in mapctrlsequence binding\n", Whoami, pv->value.c); X break; X } X if (odd(count)) X fprintf(stderr, "%s: must have an even number of string values for mapctrlsequence binding\n", Whoami); X } X if (pb = profile_has_binding(ps, "mapindexentry")) { X for (count = 0, pv = pb->value; pv; pv = pv->next, count++) X if (pv->class != PROFILE_OTHER || pv->class != PROFILE_STRING) X switch (pv->class) { X case PROFILE_INTEGER: X fprintf(stderr, "%s: illegal integer constant %d in mapindexentry binding\n", Whoami, pv->value.i); X break; X case PROFILE_HEX: X fprintf(stderr, "%s: illegal hex constant 0x%x in mapindexentry binding\n", Whoami, pv->value.i); X break; X case PROFILE_OCTAL: X fprintf(stderr, "%s: illegal octal constant 0%o in mapindexentry binding\n", Whoami, pv->value.i); X break; X case PROFILE_FLOAT: X fprintf(stderr, "%s: illegal float constant %f in mapindexentry binding\n", Whoami, pv->value.f); X break; X case PROFILE_CHARACTER: X fprintf(stderr, "%s: illegal character constant %c in mapindexentry binding\n", Whoami, pv->value.c); X break; X } X if (odd(count)) X fprintf(stderr, "%s: must have an even number of string values for mapindexentry binding\n", Whoami); X } X} X X/* Returns the literal string of a token list */ Xchar *literalstring(t) Xstruct Token *t; X{ X static char literal[81]; X X strcpy(literal, ""); X for (t = CurKey; t; t = t->next) X strcat(literal, t->lexeme); X return literal; X} X X/* Returns alphabetization string for a token list and a stanza */ Xchar *alphabetizestring(tokenlist, stanza) Xstruct Token *tokenlist; XPROFILE_STANZA *stanza; X{ X char litstring[81]; X char ctrlstring[21]; X char c[2]; X static char alphastring[81]; X int i; X Boolean add; X struct Token *t; X PROFILE_BINDING *pb, *pbchars, *pbctrlsequence; X PROFILE_VALUE *pv; X X if (!tokenlist) X return NULL; X strcpy(alphastring, ""); X if (!stanza) { X for (t = tokenlist; t; t = t->next) X switch (t->type) { X case string: X case integer: X case roman: X case comma: X case obrace: X case cbrace: X strcat(alphastring, t->lexeme); X break; X } X return alphastring; X } else { X if (pb = profile_has_binding(stanza, "mapindexentry")) { X strcpy(litstring, literalstring(tokenlist)); X for (pv = pb->value; pv && pv->next; pv = pv->next, pv = pv->next) X if ((pv->class == PROFILE_STRING || pv->class == PROFILE_OTHER) && (pv->next->class == PROFILE_STRING || X pv->next->class == PROFILE_OTHER)) X if (eq(litstring, pv->value.s)) { X strcpy(alphastring, pv->next->value.s); X return alphastring; X } X } /* end if there is a mapindexentry binding */ X pbchars = profile_has_binding(stanza, "skipchars"); X pbctrlsequence = profile_has_binding(stanza, "mapctrlsequence"); X c[1] = '\0'; X for (t = tokenlist; t; t = t->next) X switch (t->type) { X case controlword: X case controlsymbol: X if (pbctrlsequence) X for (pv = pbctrlsequence->value; pv && pv->next; pv = pv->next, pv = pv->next) X if ((pv->class == PROFILE_STRING || pv->class == PROFILE_OTHER) && (pv->next->class == PROFILE_STRING || X pv->next->class == PROFILE_OTHER)) X if (strlen(pv->value.s) > 0) { X if (pv->value.s[0] != '\\') X sprintf(ctrlstring, "\\%s", pv->value.s); X else X strcpy(ctrlstring, pv->value.s); X if (eq(ctrlstring, t->lexeme)) X strcat(alphastring, pv->next->value.s); X } X break; X case string: X case integer: X case roman: X for (i = 0; t->lexeme[i]; i++) X if (pbchars) { X for (add = TRUE, pv = pbchars->value; pv && add; pv = pv->next) X if (pv->class == PROFILE_CHARACTER) X if (pv->value.c == t->lexeme[i]) X add = FALSE; X if (add) { X c[0] = t->lexeme[i]; X strcat(alphastring, c); X } X } else { X c[0] = t->lexeme[i]; X strcat(alphastring, c); X } X break; X case comma: X c[0] = ','; X goto insert; X case obrace: X c[0] = '{'; X goto insert; X case cbrace: X c[0] = '}'; Xinsert: if (pbchars) { X for (add = TRUE, pv = pbchars->value; pv && add; pv = pv->next) X if (pv->class == PROFILE_CHARACTER) X if (pv->value.c == c[0]) X add = FALSE; X if (add) X strcat(alphastring, c); X } else X strcat(alphastring, c); X break; X } X return alphastring; X } X} X X/* Finds an entry in a table. Returns NULL if not found. */ Xstruct IndexEntry *findentry(table, noentries, string) Xstruct IndexEntry *table; Xint noentries; Xchar *string; X{ X int i; X X if (noentries <= 0) X return NULL; X for (i = 0; i < noentries; i++) X if (eq(string, table[i].literal)) X return &table[i]; X return NULL; X} X X/* Returns pointer to page number if found, NULL otherwise */ Xstruct PageNoTable *findpage(pagearray, elements, pageno, aromannum) Xstruct PageNoTable *pagearray; Xint elements; Xint pageno; XBoolean aromannum; X{ X int i; X X if (!pagearray) X return NULL; X for (i = 0; i < elements; i++) X if ((pagearray[i].number == pageno) && X (pagearray[i].isroman == aromannum)) X return &pagearray[i]; X return NULL; X} X X/* Sorts the entries in the structures */ Xsort(base, numberelements) Xstruct IndexEntry *base; Xint numberelements; X{ X int i; X int numericcompare(); X int alphacompare(); X X for (i = 0; i < numberelements; i++) { X if (base[i].pagenos) X qsort(base[i].pagenos, base[i].pagetablecount, sizeof(struct PageNoTable), numericcompare); X if (base[i].subitem) X sort(base[i].subitem, base[i].subitemcount); /* recursion! */ X } X qsort(base, numberelements, sizeof(struct IndexEntry), alphacompare); X} X X/* Prints out the index entries */ Xprintindexentries(base, noelements, level) Xstruct IndexEntry *base; Xint noelements; Xint level; X{ X int i, j; X Boolean prevoutput = FALSE; X Boolean prevrange = FALSE; X char c; X char letter = '\0'; X X if (level > ITEMDEPTH) X return; X for (i = 0; i < noelements; i++) { X if (level == 1) X if (strlen(base[i].alphabetic) > 0) X if (isalpha(base[i].alphabetic[0])) { X if (isupper(c = base[i].alphabetic[0])) X c = tolower(c); X if (!letter) { X if (Label) { X fprintf(OutputFile, "\\indexspace\n"); X fprintf(OutputFile, "\\largeletter{%c}\n", c); X } else if (prevoutput) X fprintf(OutputFile, "\\indexspace\n"); X } else if (letter != c) { X fprintf(OutputFile, "\\indexspace\n"); X if (Label) X fprintf(OutputFile, "\\largeletter{%c}\n", c); X } X letter = c; X } X prevoutput = TRUE; X for (j = 1; j < level; j++) X fprintf(OutputFile, " "); X fprintf(OutputFile, "%s %s ", ItemRep[level - 1], base[i].literal); X if (base[i].pagenos) { X for (j = 0; j < base[i].pagetablecount; j++) { X if (j == base[i].pagetablecount - 1) { X if (base[i].pagenos[j].isroman == FALSE) X fprintf(OutputFile, "%d\n", base[i].pagenos[j].number); X else { X fprintf(OutputFile, "{\\romannumeral %d}\n", base[i].pagenos[j].number); X } X } else if (base[i].pagenos[j].range) { X if (!prevrange) { X if (base[i].pagenos[j].isroman == FALSE) X fprintf(OutputFile, "%d--", base[i].pagenos[j].number); X else { X fprintf(OutputFile, "{\\romannumeral %d}--", base[i].pagenos[j].number); X } X } X } else { X if (base[i].pagenos[j].isroman == FALSE) X fprintf(OutputFile, "%d, ", base[i].pagenos[j].number); X else { X fprintf(OutputFile, "{\\romannumeral %d}, ", base[i].pagenos[j].number); X } X } X prevrange = base[i].pagenos[j].range; X } X if (prevrange) X fprintf(stderr, "%s: file %s, %s %s ends with a range\n", Whoami, IdxFileName, ItemRep[level - 1], X base[i].literal); X } else X fprintf(OutputFile, "\n"); X if (base[i].subitem) X printindexentries(base[i].subitem, base[i].subitemcount, level + 1); /* recursion! */ X } X} X Xint numericcompare(e1, e2) Xstruct PageNoTable *e1, *e2; X{ X if ((e1->isroman == TRUE) && (e2->isroman == FALSE)) X return -1; X if ((e1->isroman == FALSE) && (e2->isroman == TRUE)) X return 1; X /* else either both roman or both integers */ X if (e1->number == e2->number) X return 0; X else if (e1->number < e2->number) X return -1; X else X return 1; X} X Xint alphacompare(e1, e2) Xstruct IndexEntry *e1, *e2; X{ X char s1[81], s2[81]; X X strcpy(s1, e1->alphabetic), strcpy(s2, e2->alphabetic); X return(strcmp(string_downshift(s1), string_downshift(s2))); X} X X Xint rmtoi (romanstr) Xchar *romanstr; X{ X register char *p = romanstr; X register int w; X register int prevw = (-1); X register int result = 0; X int romanwt(); X X while (*p) { X if ((w = romanwt(*p)) == (-1)) { X fprintf(stderr, "illegal char in roman string:'%c'\n", (*p)); X return (-1); X } else { X if (prevw > 0) { /* check for subtractive X * notation */ X if (w > prevw) { /* e.g., the case "ix" */ X result += (w - prevw) - prevw; X } else X result += w; X } else { X result += w; X } X } X prevw = w; X p++; X } X return (result); X} X Xstatic int romanwt (c) Xregister char c; X{ X static char romanlett[7] = {'m', 'd', 'c', 'l', 'x', 'v', 'i'}; X static int weight[7] = {1000, 500, 100, 50, 10, 5, 1}; X X register char *pt; X X if (isupper(c)) X c = tolower(c); X pt = romanlett; X while (*pt) { X if (*pt == c) { X return (weight[(int) (pt - romanlett)]); X } else X pt++; X } X return (-1); /* roman letter not found */ X} X !FaR!OuT! if [ ! -d indexsrc ] then mkdir indexsrc echo mkdir indexsrc fi echo x - indexsrc/indexlex.l sed -e 's/^X//' > indexsrc/indexlex.l << '!FaR!OuT!' X/* $Header */ X/* Lex Lexical Analyzer for LaTeX index processor */ X/* Roman numeral code written by John Renner (adobe!renner@decwrl.dec.com) */ X%{ X#undef input X#define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(InputFile)) \ X ==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar) X%} Xletter [A-Za-z] Xinteger -?[0-9]{1,9} Xroman [mdclxvi]+ Xwhitespace [ \t\n] X%% X\\indexentry { X LineNo = EndLineNo; X return(INDEXENTRY); X } X{roman} { X LineNo = EndLineNo; X strcpy(yylval.value, yytext); X return(ROMAN); X } X\\{letter}+ { /* Control word */ X LineNo = EndLineNo; X strcpy(yylval.value, yytext); X return(CONTROLSEQUENCE); X } X\\[^{letter}] { /* Control symbol */ X LineNo = EndLineNo; X strcpy(yylval.value, yytext); X return(CONTROLSEQUENCE); X } X\%.*\n LineNo = EndLineNo++; /* Comment. Don't pass to parser */ X{integer} { X LineNo = EndLineNo; X strcpy(yylval.value, yytext); X return(INTEGER); X } X\{ | X\} | X\, { X LineNo = EndLineNo; X return(yytext[0]); X } X{whitespace}+ { X char *p; /* Utility variable */ X X LineNo = EndLineNo; X for (p = yytext; *p; p++) X if (*p == '\n') X EndLineNo++; X strcpy(yylval.value, yytext); X return(WHITESPACE); X } X[^\\\{\}\%\, \t\n0-9]+ { X LineNo = EndLineNo; X strcpy(yylval.value, yytext); X return(STRING); X } X%% !FaR!OuT! if [ ! -d libglob ] then mkdir libglob echo mkdir libglob fi echo x - libglob/Makefile sed -e 's/^X//' > libglob/Makefile << '!FaR!OuT!' X# @(#)Makefile 1.1 (TRW) 1/14/86 XCFLAGS = -O X X.c.o: X ${CC} ${CFLAGS} -c $*.c X -ld -x -r $*.o X mv a.out $*.o X Xall: libglob.a X Xlibglob.a: glob.o X ar cr libglob.a glob.o X ranlib libglob.a X chmod 644 libglob.a X Xinstall: all X Xclean: X rm -f *.o *.a X !FaR!OuT! if [ ! -d libglob ] then mkdir libglob echo mkdir libglob fi echo x - libglob/glob.c sed -e 's/^X//' > libglob/glob.c << '!FaR!OuT!' Xstatic char *trwsccs= "@(#)glob.c 1.1 (TRW) 1/14/86"; X#include "glob.h" X X#define SLOP 5 X#define MAX_SET 0177 X X/* control codes for regular expression evaluation */ X#define PATTERN_ANY '?' X#define PATTERN_CHARACTER 'X' X#define PATTERN_END '$' X#define PATTERN_SET '[' X#define PATTERN_SET_MEMBER 'M' X#define PATTERN_SET_RANGE '-' X#define PATTERN_STAR '*' X X/* X * Examples (=> denotes `compiles into') X * X * a => Xa X * ? => ? X * [x0-9] => [^EMx-09 (^E is control-E) X * * => * X * END => $ X * X * a?[x0-9]* => Xa?[^EMx-09*$ X */ X Xglob_compile (pattern, buffer) Xchar *pattern; Xchar *buffer; /* compiled pattern */ X{ X char *x; /* pointer into compiled pattern */ X int c; X int result; X X if (pattern == 0 || pattern[0] == 0) X return(GLOB_PATTERN_EMPTY); X X x = buffer; X while (x < &buffer[GLOB_MAX_PATTERN - SLOP]) { X c = *pattern++; X if (c == 0) { X *x++ = PATTERN_END; X return(GLOB_OK); X } X X switch (c) { X case '?': X *x++ = PATTERN_ANY; X continue; X X case '[': X if ((result = compile_set(pattern, x, &buffer[GLOB_MAX_PATTERN - SLOP])) < 0) X return(result); X pattern += result + 1; X x += x[1] + 2; X continue; X X case '*': X *x++ = PATTERN_STAR; X continue; X X default: X *x++ = PATTERN_CHARACTER; X *x++ = c; X continue; X } X } X return(GLOB_PATTERN_TOO_BIG); X} X Xint glob_execute (pattern, s) Xchar *pattern; /* compiled pattern */ Xchar *s; /* string to be matched against */ X{ X char *current; X int result; X X for (;;) X switch (*pattern++) { X case PATTERN_ANY: X if (*s++) X continue; X return(0); X X case PATTERN_CHARACTER: X if (*pattern++ == *s++) X continue; X return(0); X X case PATTERN_END: X return(*s == 0); X X case PATTERN_SET: X if ((result = in_set(pattern, *s++)) == 1) { X pattern += *pattern + 1; X continue; X } X return(result); X X case PATTERN_STAR: X current = s; X while (*s++) X continue; X do { X s--; X if (result = glob_execute(pattern, s)) X return(result); X } while (s > current); X return(0); X X default: X return(GLOB_EXECUTION_ERROR); X } X} X Xint glob_match (pattern, s) Xchar *pattern; Xchar *s; X{ X int result; X char buffer[GLOB_MAX_PATTERN]; X X if ((result = glob_compile(pattern, buffer)) < 0) X return(result); X else X return(glob_execute(buffer, s)); X} X X/* returns 1 if character c is member of set and 0 otherwise */ Xstatic int in_set (set, c) Xchar *set; /* compiled set pattern */ Xchar c; X{ X int n; X X if (c == 0) X return(0); X n = *set++; X while (n > 0) X switch (*set++) { X case PATTERN_SET_MEMBER: X if (*set++ == c) X return(1); X n -= 2; X continue; X X case PATTERN_SET_RANGE: X if (*set++ <= c && c <= *set++) X return(1); X n -= 3; X continue; X X default: X return(GLOB_EXECUTION_ERROR); X } X return(0); X} X X#define IS_RANGE(s) (s[1] && s[2] && s[1] == '-' && s[2] != ']') X X/* compiles a set returning the number of pattern characters consumed */ Xstatic int compile_set (pattern, x, limit) Xchar *pattern; Xchar *x; Xchar *limit; X{ X char *slot; /* size of set goes here */ X int size; /* number of bytes in compiled set */ X char *start = pattern; X X if (*pattern == 0) X return(GLOB_BRACKET_MISSING); X X *x++ = PATTERN_SET; X slot = x++; X size = 0; X X if (IS_RANGE(pattern)) { X if (pattern[0] > pattern[2]) /* pattern[1] == '-' */ X return(GLOB_RANGE_INVERTED); X *x++ = PATTERN_SET_RANGE; X *x++ = pattern[0]; X *x++ = pattern[2]; X pattern += 3; X size += 3; X } else { X *x++ = PATTERN_SET_MEMBER; X *x++ = *pattern++; X size += 2; X } X X while (*pattern != ']' && x < limit) { X if (*pattern == 0) X return(GLOB_BRACKET_MISSING); X if (IS_RANGE(pattern)) { X if (pattern[0] > pattern[2]) /* pattern[1] == '-' */ X return(GLOB_RANGE_INVERTED); X *x++ = PATTERN_SET_RANGE; X *x++ = pattern[0]; X *x++ = pattern[2]; X pattern += 3; X size += 3; X } else { X *x++ = PATTERN_SET_MEMBER; X *x++ = *pattern++; X size += 2; X } X } X if (size > MAX_SET) X return(GLOB_SET_TOO_BIG); X *slot = size; X return(pattern - start); X} !FaR!OuT! if [ ! -d libglob ] then mkdir libglob echo mkdir libglob fi echo x - libglob/glob.h sed -e 's/^X//' > libglob/glob.h << '!FaR!OuT!' X/* @(#)glob.h 1.1 (TRW) 1/14/86 */ X#define GLOB_MAX_PATTERN 1024 X#define GLOB_OK 0 X#define GLOB_PATTERN_TOO_BIG -1 X#define GLOB_PATTERN_EMPTY -2 X#define GLOB_BRACKET_MISSING -3 X#define GLOB_RANGE_INVERTED -4 X#define GLOB_SET_TOO_BIG -5 X#define GLOB_EXECUTION_ERROR -6 !FaR!OuT! exit