[comp.sources.misc] LaTeX Index Processor

simpson@trwrb.UUCP (Scott Simpson) (07/10/87)

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#include <stdio.h>
X
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 <stdio.h>
X#include "standard.h"
X#include "profile.h"
X#include <ctype.h>
X#include <pwd.h>
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 <value> ROMAN CONTROLSEQUENCE INTEGER WHITESPACE STRING INDEXENTRY
X%type <t> 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

simpson@trwrb.UUCP (Scott Simpson) (07/10/87)

#! /bin/sh
# To extract, remove mail header lines and type "sh filename"
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/Makefile
sed -e 's/^X//' > libprofile/Makefile << '!FaR!OuT!'
X# @(#)Makefile	1.1 (TRW) 1/14/86
XCFLAGS = -O
XOBJECTS = boolean.o free.o has.o read.o space.o write.o
X
X.c.o:
X	${CC} ${CFLAGS} -c $*.c
X	-ld -r -x $*.o
X	mv a.out $*.o
X
Xall: libprofile.a
X
Xlibprofile.a: ${OBJECTS}
X	ar cr libprofile.a ${OBJECTS}
X	ranlib libprofile.a
X	chmod 644 libprofile.a
X
Xinstall: all
X
Xclean:
X	rm -f *.o *.a
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/boolean.c
sed -e 's/^X//' > libprofile/boolean.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)boolean.c	1.1 (TRW) 1/14/86";
X#include <ctype.h>
X#include "profile.h"
X
Xstatic char *Yes[] = {
X	"yes",
X	"on",
X	"true",
X	"enable",
X	"available",
X	"present",
X	0
X};
X
Xstatic char *No[] = {
X	"no",
X	"off",
X	"false",
X	"disable",
X	"unavailable",
X	"absent",
X	0
X};
X
Xint profile_boolean (v)
XPROFILE_VALUE *v;
X{
X	char x[16];
X	int i;
X
X	if (v == 0)
X		return(0);
X
X	switch (v->class) {
X	case PROFILE_OTHER:
X	case PROFILE_STRING:
X		strncpy(x, v->value.s, sizeof(x)-1);
X		x[sizeof(x)-1] = 0;
X		downshift(x);
X		for (i = 0; Yes[i]; i++)
X			if (strcmp(x, Yes[i]) == 0)
X				return(1);
X			else if (strcmp(x, No[i]) == 0)
X				return(0);
X		return(-1);	/* unknown string */
X
X	case PROFILE_HEX:
X	case PROFILE_INTEGER:
X	case PROFILE_OCTAL:
X		return(v->value.i != 0);
X
X	case PROFILE_CHARACTER:
X		return(v->value.c != 0);
X
X	case PROFILE_FLOAT:
X		return(v->value.f != 0.0);
X
X	default:
X		return(-1);	/* unknown class */
X	}
X}
X
X/* downshift a string in place */
Xstatic downshift (s)
Xchar *s;
X{
X	for (; *s; s++)
X		if (isupper(*s))
X			*s = tolower(*s);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/free.c
sed -e 's/^X//' > libprofile/free.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)free.c	1.1 (TRW) 1/14/86";
X#include "profile.h"
X
Xprofile_free_profile (s)
XPROFILE_STANZA *s;
X{
X	PROFILE_STANZA *x;
X
X	for (x = s; x != (PROFILE_STANZA *)0 && x != s; x = x->next)
X		profile_free_stanza(x);
X}
X
Xprofile_free_stanza (s)
XPROFILE_STANZA *s;
X{
X	free_markers(s->marker);
X	free_bindings(s->binding);
X	free(s);
X}
X
Xstatic free_markers (m)
XPROFILE_MARKER *m;
X{
X	PROFILE_MARKER *x;
X
X	for (; m; m = x) {
X		x = m->next;
X		free(m);
X	}
X}
X
Xstatic free_bindings (b)
XPROFILE_BINDING *b;
X{
X	PROFILE_BINDING *x;
X
X	for (; b; b = x) {
X		x = b->next;
X		free_values(b->value);
X		free(b);
X	}
X}
X
Xstatic free_values (v)
XPROFILE_VALUE *v;
X{
X	PROFILE_VALUE *x;
X
X	for (; v; v = x) {
X		x = v->next;
X		free(v);
X	}
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/has.c
sed -e 's/^X//' > libprofile/has.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)has.c	1.1 (TRW) 1/14/86";
X#include <stdio.h>
X#include "profile.h"
X
XPROFILE_MARKER *profile_has_marker (s, m)
XPROFILE_STANZA *s;
Xchar *m;
X{
X	PROFILE_MARKER *x;
X	int result;
X
X	for (x = s->marker; x; x = x->next)
X		if(glob_match(x->text, m) > 0)
X			return(x);
X	return((PROFILE_MARKER *)0);
X}
X
X/*
X * read down a linked list of stanzas looking
X * for a stanza that has the requested markers
X */
XPROFILE_STANZA *profile_has_stanza(s, marker)
XPROFILE_STANZA *s;
Xchar *marker[];		/* terminated by a null pointer */
X{
X	int i;
X	PROFILE_STANZA *x;
X
X	if (s == NULL)
X		return(s);
X	x = s;
X	do {
X		for (i = 0; marker[i] != NULL; i++)
X			if (profile_has_marker(x, marker[i]) == NULL)
X				break;
X		if (marker[i] == NULL)
X			return(x);
X		x = x->next;
X	} while (x != s && x != NULL);
X
X	return((PROFILE_STANZA *)NULL);
X}
X
XPROFILE_BINDING *profile_has_binding (s, b)
XPROFILE_STANZA *s;
Xchar *b;
X{
X	PROFILE_BINDING *x;
X
X	for (x = s->binding; x; x = x->next)
X		if (glob_match(x->name, b) > 0)
X			return(x);
X	return((PROFILE_BINDING *)0);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/profile.h
sed -e 's/^X//' > libprofile/profile.h << '!FaR!OuT!'
X/* @(#)profile.h	1.1 (TRW) 1/14/86 */
Xtypedef struct PROFILE_VALUE {
X	char class;
X	union {
X		long int i;
X		double f;
X		char c;
X		char *s;
X	} value;
X	struct PROFILE_VALUE *previous;
X	struct PROFILE_VALUE *next;
X} PROFILE_VALUE;
X
Xtypedef struct PROFILE_BINDING {
X	char *name;
X	PROFILE_VALUE *value;
X	struct PROFILE_BINDING *previous;
X	struct PROFILE_BINDING *next;
X} PROFILE_BINDING;
X
Xtypedef struct PROFILE_MARKER {
X	char *text;
X	struct PROFILE_MARKER *previous;
X	struct PROFILE_MARKER *next;
X} PROFILE_MARKER;
X
Xtypedef struct PROFILE_STANZA {
X	PROFILE_MARKER *marker;
X	PROFILE_BINDING *binding;
X	struct PROFILE_STANZA *previous;
X	struct PROFILE_STANZA *next;
X} PROFILE_STANZA;
X
X/* classes */
X#define PROFILE_INTEGER 01
X#define PROFILE_FLOAT 02
X#define PROFILE_STRING 03
X#define PROFILE_CHARACTER 04
X#define PROFILE_OTHER 05
X#define PROFILE_OCTAL 06
X#define PROFILE_HEX 07
X
X/* no single lexical element may exceed this size in characters */
X#define PROFILE_MAX_TEXT 255
X
XPROFILE_STANZA *profile_read_stanza();
XPROFILE_STANZA *profile_read_profile();
XPROFILE_MARKER *profile_has_marker();
XPROFILE_STANZA *profile_has_stanza();
XPROFILE_BINDING *profile_has_binding();
XPROFILE_STANZA *profile_stanza_space();
XPROFILE_MARKER *profile_marker_space();
XPROFILE_BINDING *profile_binding_space();
XPROFILE_VALUE *profile_value_space();
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/read.c
sed -e 's/^X//' > libprofile/read.c << '!FaR!OuT!'
Xstatic char *trwrcs = "$Header: read.c,v 1.1 87/03/16 14:00:10 control Exp $";
Xstatic char *trwsccs = "@(#)read.c	1.1 (TRW) 1/14/86";
X#include <stdio.h>
X#include <ctype.h>
X#include "profile.h"
X
X#define isoctal(d) ('0' <= d && d <= '7')
X#define ishex(x) (isdigit(x) || ('a' <= x && x <= 'f') || ('A' <= x && x <= 'F'))
X#define isprime(c) (c == '\'')
X#define isbackslash(c) (c == '\\')
X#define iscaret(c) (c == '^')
X
Xextern char *strcpy();
Xextern PROFILE_STANZA *profile_stanza_space();
Xextern PROFILE_MARKER *profile_marker_space();
Xextern PROFILE_BINDING *profile_binding_space();
Xextern PROFILE_VALUE *profile_value_space();
X
Xstatic PROFILE_BINDING *get_binding();
Xstatic PROFILE_BINDING *get_bindings();
Xstatic PROFILE_MARKER *get_marker();
Xstatic PROFILE_MARKER *get_markers();
Xstatic PROFILE_VALUE *get_value();
Xstatic PROFILE_VALUE *get_values();
Xstatic char parse_character();
Xstatic PROFILE_VALUE *parse_value();
X
XPROFILE_STANZA *profile_read_stanza (f)
XFILE *f;
X{
X	PROFILE_STANZA *stanza;
X
X	stanza = profile_stanza_space();
X	if (stanza == NULL)
X		return(NULL);
X	stanza->marker = get_markers(f);
X	if (get_open_bindings(f))
X		stanza->binding = get_bindings(f);
X	else {
X		profile_free_stanza(stanza);
X		return(NULL);
X	}
X	if (get_close_bindings(f))
X		return(stanza);
X	else {
X		profile_free_stanza(stanza);
X		return(NULL);
X	}
X}
X
X/* Returns the list of markers at the head of a stanza. */
Xstatic PROFILE_MARKER *get_markers (f)
XFILE *f;
X{
X	PROFILE_MARKER *head, *tail, *m;
X
X	head = tail = NULL;
X	while (m = get_marker(f))
X		if (tail) {
X			tail->next = m;
X			m->previous = tail;
X			tail = m;
X		} else
X			head = tail = m;
X	return(head);
X}
X
X/* Returns the next marker from the head of the stanza. */
Xstatic PROFILE_MARKER *get_marker (f)
XFILE *f;
X{
X	int n;
X	PROFILE_MARKER *m;
X	char scratch[PROFILE_MAX_TEXT+1];
X
X	for (;;)
X		if (n = get_name_text(f, scratch)) {
X			if ((m = profile_marker_space(n)) == NULL)
X				return(NULL);
X			strcpy(m->text, scratch);
X			return(m);
X		} else if (get_end_of_line(f))
X			continue;
X		else
X			return(NULL);
X}
X
X/* Returns the list of bindings in the body of the stanza. */
Xstatic PROFILE_BINDING *get_bindings (f)
XFILE *f;
X{
X	PROFILE_BINDING *head, *tail, *b;
X
X	head = tail = NULL;
X	while (b = get_binding(f))
X		if (tail) {
X			tail->next = b;
X			b->previous = tail;
X			tail = b;
X		} else
X			head = tail = b;
X	return(head);
X}
X
X/* Returns the next binding in the body of the stanza. */
Xstatic PROFILE_BINDING *get_binding (f)
XFILE *f;
X{
X	int n;
X	PROFILE_BINDING *b;
X	char scratch[PROFILE_MAX_TEXT+1];
X
X	for (;;)
X		if (n = get_name_text(f, scratch)) {
X			if ((b = profile_binding_space(n)) == NULL)
X				return(NULL);
X			strcpy(b->name, scratch);
X			break;
X		} else if (get_end_of_line(f))
X			continue;
X		else
X			return(NULL);
X	b->value = get_values(f);
X	return(b);
X}
X
X/* Returns the list of values following the name of the binding. */
Xstatic PROFILE_VALUE *get_values (f)
XFILE *f;
X{
X	PROFILE_VALUE *head, *tail, *v;
X
X	head = tail = NULL;
X	while (v = get_value(f))
X		if (tail) {
X			tail->next = v;
X			v->previous = tail;
X			tail = v;
X		} else
X			head = tail = v;
X	return(head);
X}
X
X/* Returns the next value in the binding. */
Xstatic PROFILE_VALUE *get_value (f)
XFILE *f;
X{
X	char text[PROFILE_MAX_TEXT+1];
X	int n;
X
X	for (;;)
X		if (n = get_value_text(f, text))
X			return(parse_value(text, n));
X		else if (get_end_of_line(f))
X			return(NULL);
X		else
X			return(NULL);
X}
X
X/*
X * Reads the text of the next value (if any) in the binding.  Returns
X * the length of the literal text in characters.
X */
Xstatic int get_value_text (f, text)
XFILE *f;
Xchar *text;
X{
X	register int c;
X	char *s = text;
X
X	while ((c = getc(f)) != EOF)
X		switch (c) {
X		case '\b': case '\f':
X		case '\r': case '\t': case ' ':
X			/* white space terminates any text gathered so far */
X			if (s > text) {
X				*s = '\0';
X				return(s - text);
X			}
X			continue;
X
X		case '\n':
X			/* newline terminates a binding */
X			ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		case '#':
X			/* gobble up the comment */
X			while ((c = getc(f)) != EOF && c != '\n')
X				continue;
X			if (c == '\n')
X				ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		case '{': case '}':
X			ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		case '"':		/* string quotes */
X			ungetc(c, f);
X			if (s > text) {
X				*s = '\0';
X				return(s - text);
X			} else
X				return(get_string(f, s));
X
X		case '\'':		/* character quotes */
X			ungetc(c, f);
X			if (s > text) {
X				*s = '\0';
X				return(s - text);
X			} else
X				return(get_character(f, s));
X
X		case '\\':		/* newline escape */
X			c = getc(f);
X			if (c == '\n') {
X				if (s > text) {
X					*s = '\0';
X					return(s - text);
X				}
X				continue;	/* just like a blank */
X			}
X			ungetc(c, f);
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = '\\';
X			continue;
X
X		default:
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			continue;
X		}
X	*s = '\0';
X	return(s - text);
X}
X
X/* Digests the raw value text returning a new value structure. */
Xstatic PROFILE_VALUE *parse_value (s, length)
Xchar *s;		/* literal text */
Xint length;		/* in characters */
X{
X	PROFILE_VALUE *v;
X
X	if (is_integer(s)) {
X		if ((v = profile_value_space(0)) == NULL)
X			return(NULL);
X		v->class = PROFILE_INTEGER;
X		sscanf(s, "%D", &v->value.i);
X	} else if (is_octal(s)) {
X		if ((v = profile_value_space(0)) == NULL)
X			return(NULL);
X		v->class = PROFILE_OCTAL;
X		/* skip the `0o' prefix */
X		sscanf(s+2, "%O", &v->value.i);
X	} else if (is_hex(s)) {
X		if ((v = profile_value_space(0)) == NULL)
X			return(NULL);
X		v->class = PROFILE_HEX;
X		/* skip the `0x' prefix */
X		sscanf(s+2, "%X", &v->value.i);
X	} else if (is_string(s)) {
X		/* be careful when dealing with the empty string "" */
X		if ((v = profile_value_space(length > 2 ? length - 2 : 1)) == NULL)
X			return(NULL);
X		v->class = PROFILE_STRING;
X		/* erase the terminating double quote */
X		s[length - 1] = '\0';
X		/* skip past the initial quote */
X		parse_string(s + 1, v->value.s);
X	} else if (is_character(s)) {
X		if ((v = profile_value_space(0)) == NULL)
X			return(NULL);
X		v->class = PROFILE_CHARACTER;
X		/* erase the end single quote */
X		s[length - 1] = '\0';
X		v->value.c = parse_character(s + 1);
X	} else if (is_float(s)) {
X		if ((v = profile_value_space(0)) == NULL)
X			return(NULL);
X		v->class = PROFILE_FLOAT;
X		sscanf(s, "%E", &v->value.f);
X	} else {
X		if ((v = profile_value_space(length)) == NULL)
X			return(NULL);
X		v->class = PROFILE_OTHER;
X		strcpy(v->value.s, s);
X	}
X	return(v);
X}
X
X/* Converts a string literal to the internal representation. */
Xstatic parse_string (source, result)
Xchar *source;
Xchar *result;
X{
X	for (; *source; source++)
X		if (*source == '\\')
X			switch (*++source) {
X			case 'b':			/* backspace */
X				*result++ = '\b';
X				continue;
X			case 'f':			/* formfeed */
X				*result++ = '\f';
X				continue;
X			case 'n':			/* newline */
X				*result++ = '\n';
X				continue;
X			case 'r':			/* carriage return */
X				*result++ = '\r';
X				continue;
X			case 't':			/* horizontal tab */
X				*result++ = '\t';
X				continue;
X			case '\'':			/* single quote */
X				*result++ = '\'';
X				continue;
X			case '"':			/* double quote */
X				*result++ = '"';
X				continue;
X			case '\\':			/* backslash */
X				*result++ = '\\';
X				continue;			
X			case '^':			/* caret */
X				*result++ = '^';
X				continue;
X			case '0': case '1':		/* octal constant */
X			case '2': case '3':
X			case '4': case '5':
X			case '6': case '7':
X				source += parse_octal(source, result) - 2;
X				result++;
X				continue;
X			default:
X				*result++ = *source;	/* ignore backslash */
X			}
X		else if (*source == '^') {	/* control escape */
X			char c = *++source;
X			*result++ = ('@' <= c && c <= '_') ? c - '@' :
X				    (c == '?') ? '\177' : c;
X			continue;
X		} else
X			*result++ = *source;
X	*result = '\0';
X}
X
X/* Converts a character literal to the internal representation. */
Xstatic char parse_character (source)
Xchar *source;
X{
X	char c;
X
X	if (*source == '\\')
X		switch (*++source) {
X		case 'b':			/* backspace */
X			return('\b');
X		case 'f':			/* formfeed */
X			return('\f');
X		case 'n':			/* newline */
X			return('\n');
X		case 'r':			/* carriage return */
X			return('\r');
X		case 't':			/* horizontal tab */
X			return('\t');
X		case '\'':			/* single quote */
X			return('\'');
X		case '\\':			/* backslash */
X			return('\\');
X		case '^':
X			return('^');
X		case '0': case '1':		/* octal constant */
X		case '2': case '3':
X		case '4': case '5':
X		case '6': case '7':
X			parse_octal(source, &c);
X			return(c);
X		default:
X			return(*source);	/* ignore backslash */
X		}
X	else if (*source == '^') {	/* control escape */
X		c = *++source;
X		return(('@' <= c && c <= '_') ? c - '@' : (c == '?') ? '\177' : c);
X	} else
X		return(*source);
X}
X
X/* Converts an octal escape `\ddd' to its byte representation. */
Xstatic int parse_octal (source, result)
Xchar *source;
Xchar *result;
X{
X	int count;
X	char byte = '\0';
X	char digit;
X
X	for (count = 1; count <= 3; count++) {
X		digit = *source++;
X		if ('0' <= digit && digit <= '7')
X			byte = (byte * 8) + (digit - '0');
X		else
X			break;
X	}
X	*result = byte;
X	return(count);
X}
X
X/*
X * Reads the literal text for markers and binding names.  Returns the
X * length in characters of the literal text.
X */
Xstatic int get_name_text (f, text)
XFILE *f;
Xchar *text;
X{
X	register int c;
X	char *s = text;
X
X	while ((c = getc(f)) != EOF)
X		switch (c) {
X		case '\b': case '\f':
X		case '\r': case '\t': case ' ':
X			/* white space terminates text gathered so far */
X			if (s > text) {
X				*s = '\0';
X				return(s - text);
X			}
X			continue;
X
X		case '\n':
X			ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		case '#':
X			/* gobble up the comment */
X			while ((c = getc(f)) != EOF && c != '\n')
X				continue;
X			if (c == '\n')
X				ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		case '{': case '}':
X			ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		case '[':
X			/* sets may contain embedded white space */
X			if (s + 1 < &text[PROFILE_MAX_TEXT]) {
X				*s++ = '[';
X				if ((c = getc(f)) != EOF)
X				*s++ = c;
X			}
X			while ((c = getc(f)) != EOF) {
X				if (s < &text[PROFILE_MAX_TEXT])
X					*s++ = c;
X				if (c == ']')
X					break;
X			}
X			continue;
X
X		case '\\':
X			c = getc(f);
X			if (c == '\n') {
X				if (s > text) {
X					*s = '\0';
X					return(s - text);
X				}
X				continue;	/* just like a blank */
X			}
X			ungetc(c, f);
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = '\\';
X			continue;
X
X		default:
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			continue;
X		}
X	*s = '\0';
X	return(s - text);
X}
X
X/* Returns non-zero on end of line and zero otherwise. */
Xstatic int get_end_of_line (f)
XFILE *f;
X{
X	int c;
X
X	if ((c = getc(f)) == '\n')
X		return(1);
X	ungetc(c, f);
X	return(0);
X}
X
X/* Returns non-zero on seeing `{' and zero otherwise. */
Xstatic int get_open_bindings (f)
XFILE *f;
X{
X	int c;
X
X	if ((c = getc(f)) == '{')
X		return(1);
X	ungetc(c, f);
X	return(0);
X}
X
X/* Returns non-zero on seeing `}' and zero otherwise. */ 
Xstatic int get_close_bindings (f)
XFILE *f;
X{
X	int c;
X
X	if ((c = getc(f)) == '}')
X		return(1);
X	ungetc(c, f);
X	return(0);
X}
X
X/* Reads a string literal returning the length of the literal text in characters */
Xstatic int get_string (f, text)
XFILE *f;
Xchar *text;
X{
X	register int c;
X	char *s = text;
X
X	/* the first double quote is guaranteed */
X	*s++ = getc(f);
X	while ((c = getc(f)) != EOF)
X		switch (c) {
X		case '\\':
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			c = getc(f);
X			if (c == EOF)
X				return(s - text);
X			else if (c == '\n') {
X				ungetc(c, f);
X				return(s - text);
X			} else if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			continue;
X
X		case '"':
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			*s = '\0';
X			return(s - text);
X
X		case '\n':
X			ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X
X		default:
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			continue;
X		}
X	*s = '\0';
X	return(s - text);
X}
X
X/* Reads a character literal returning the length of the literal text in characters. */
Xstatic int get_character (f, text)
XFILE *f;
Xchar *text;
X{
X	register int c;
X	char *s = text;
X
X	/* the first single quote is guaranteed */
X	*s++ = getc(f);
X	while ((c = getc(f)) != EOF)
X		switch (c) {
X		case '\\':
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			c = getc(f);
X			if (c == EOF)
X				return(s - text);
X			else if (c == '\n') {
X				ungetc(c, f);
X				return(s - text);
X			} else if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			continue;
X		case '\'':
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			*s = '\0';
X			return(s - text);
X		case '\n':
X			ungetc(c, f);
X			*s = '\0';
X			return(s - text);
X		default:
X			if (s < &text[PROFILE_MAX_TEXT])
X				*s++ = c;
X			continue;
X		}
X	*s = '\0';
X	return(s - text);
X}
X
X/* all regular expressions below are in lex notation */
X
X/* returns non-zero iff -?[0-9]+ matches */
Xstatic int is_integer (s)
Xchar *s;
X{
X	char *x;
X
X	/* -? */
X	if (*s == '-')
X		s++;
X	/* [0-9]+ */
X	for (x = s; isdigit(*s); s++)
X		continue;
X	return(s > x && !*s);
X}
X
X/* returns non-zero iff 0[oO][0-7]+ matches */
Xstatic int is_octal (s)
Xchar *s;
X{
X	char *x;
X
X	/* 0 */
X	if (*s == '0')
X		s++;
X	else
X		return(0);
X	/* [oO] */
X	if (*s == 'o' || *s == 'O')
X		s++;
X	else
X		return(0);
X	/* [0-7]+ */
X	for (x = s; isoctal(*s); s++)
X		continue;
X	return(s > x && !*s);
X}
X
X/* returns non-zero iff 0[xX][0-9a-fA-F]+ matches */
Xstatic int is_hex (s)
Xchar *s;
X{
X	char *x;
X
X	/* 0 */
X	if (*s == '0')
X		s++;
X	else
X		return(0);
X	/* [xX] */
X	if (*s == 'x' || *s == 'X')
X		s++;
X	else
X		return(0);
X	/* [0-9a-fA-F]+ */
X	for (x = s; ishex(*s); s++)
X		continue;
X	return(s > x && !*s);
X}
X
X/* returns non-zero iff [eE][-+]?[0-9]+ matches */
Xstatic int is_exponent (s)
Xchar *s;
X{
X	char *x;
X
X	/* [eE] */
X	if (*s == 'e' || *s == 'E')
X		s++;
X	else
X		return(0);
X	/* [-+]? */
X	if (*s == '-' || *s == '+')
X		s++;
X	/* [0-9]+ */
X	for (x = s; isdigit(*s); s++)
X		continue;
X	return(s > x && !*s);
X}
X
Xstatic int is_float (s)
Xchar *s;
X{
X	return(is_integer_part_float(s) ||
X	       is_fractional_part_float(s) ||
X	       is_power_float(s));
X}
X
X/* returns non-zero iff -?[0-9]+"."[0-9]*({exponent})? matches */
Xstatic int is_integer_part_float (s)
Xchar *s;
X{
X	char *x;
X
X	/* -? */
X	if (*s == '-')
X		s++;
X	/* [0-9]+"." */
X	for (x = s; isdigit(*s); s++)
X		continue;
X	if (x == s || *s != '.')
X		return(0);
X	/* [0-9]* */
X	for (s++; isdigit(*s); s++)
X		continue;
X	/* ({exponent})? */
X	return(*s ? is_exponent(s) : 1);
X}
X
X/* returns non-zero iff -?"."[0-9]+({exponent})? matches */
Xstatic int is_fractional_part_float (s)
Xchar *s;
X{
X	char *x;
X
X	/* -? */
X	if (*s == '-')
X		s++;
X	/* "." */
X	if (*s == '.')
X		s++;
X	else
X		return(0);
X	/* [0-9]+({exponent})? */
X	for (x = s; isdigit(*s); s++)
X		continue;
X	return(s > x ? !*s || is_exponent(s) : 0);
X}
X
X/* returns non-zero iff -?[0-9]+{exponent} matches */
Xstatic int is_power_float (s)
Xchar *s;
X{
X	char *x;
X
X	/* -? */
X	if (*s == '-')
X		s++;
X	/* [0-9]+{exponent} */
X	for (x = s; isdigit(*s); s++)
X		continue;
X	return(s > x ? is_exponent(s) : 0);
X}
X
X/* returns non-zero iff '[^^\]' | '\^.' | '\\\\' | '\\'' | '\[0-7]{1-3}' matches */
Xstatic int is_character (s)
Xchar *s;
X{
X	char *x;
X
X	if (isprime(*s))
X		s++;
X	else
X		return(0);
X	if (isbackslash(*s)) {
X		s++;
X		if ((isbackslash(s[0]) || isprime(s[0]) || !isdigit(s[0])) &&
X		    isprime(s[1]) && !s[2])
X			return(1);
X		for (x = s; isoctal(*s); s++)
X			continue;
X		return(x < s && s < (x+4) && isprime(s[0]) && !s[1]);
X	} else if (iscaret(*s))
X		s++;
X	return(isprint(s[0]) && isprime(s[1]) && !s[2]);
X}
X
X/* returns non-zero iff s is a string constant */
Xstatic int is_string (s)
Xchar *s;
X{
X	char *x;
X
X	if (*s != '"')
X		return(0);
X	for (s++; *s; s++) {
X		if (*s == '"')
X			return(!*++s);	/* quote must be followed by null */
X		if (isbackslash(*s) || iscaret(*s)) {
X			if (*++s)
X				continue;	/* legal escape */
X			return(0);	/* null follows \ or ^ */
X		}
X	}
X	return(0);
X}
X
X/*
X * read an entire profile, making a bidirectional
X * circularly linked list
X * returns pointer to the first stanza or NULL on error
X */
XPROFILE_STANZA *profile_read_profile(f)
XFILE *f;
X{
X	PROFILE_STANZA *head = NULL;
X	PROFILE_STANZA *tail = NULL;
X	PROFILE_STANZA *x = NULL;
X
X	while ((x = profile_read_stanza(f)) != NULL) {
X		if (head == NULL)
X			head = tail = x;
X		else {
X			tail->next = x; 
X			x->previous = tail;
X			tail = x;
X		}
X	}
X	if (head != NULL) { 
X		tail->next = head;
X		head->previous = tail;
X	}
X	return(head);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/space.c
sed -e 's/^X//' > libprofile/space.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)space.c	1.1 (TRW) 1/14/86";
X#include "profile.h"
X
Xextern char *calloc();
X
XPROFILE_STANZA *profile_stanza_space ()
X{
X	return((PROFILE_STANZA *)calloc(1, sizeof(PROFILE_STANZA)));
X}
X
XPROFILE_MARKER *profile_marker_space (n)
Xint n;
X{
X	char *space;
X	PROFILE_MARKER *m = (PROFILE_MARKER *)0;
X
X	if (space = calloc(1, sizeof(PROFILE_MARKER) + n + 1)) {
X		m = (PROFILE_MARKER *)space;
X		m->text = space + sizeof(PROFILE_MARKER);
X	}
X	return(m);
X}
X
XPROFILE_BINDING *profile_binding_space (n)
Xint n;		/* length of binding name in characters */
X{
X	char *space;
X	PROFILE_BINDING *b = (PROFILE_BINDING *)0;
X
X	if (space = calloc(1, sizeof(PROFILE_BINDING) + n + 1)) {
X		b = (PROFILE_BINDING *)space;
X		b->name = space + sizeof(PROFILE_BINDING);
X	}
X	return(b);
X}
X
XPROFILE_VALUE *profile_value_space (n)
Xint n;
X{
X	char *space;
X	PROFILE_VALUE *v = (PROFILE_VALUE *)0;
X
X	if (n > 0) {
X		if (space = calloc(1, sizeof(PROFILE_VALUE) + n + 1)) {
X			v = (PROFILE_VALUE *)space;
X			v->value.s = space + sizeof(PROFILE_VALUE);
X		}
X	} else
X		v = (PROFILE_VALUE *)calloc(1, sizeof(PROFILE_VALUE));
X	return(v);
X}
!FaR!OuT!
if [ ! -d libprofile ]
then
	mkdir libprofile
	echo mkdir libprofile
fi
echo x - libprofile/write.c
sed -e 's/^X//' > libprofile/write.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)write.c	1.1 (TRW) 1/14/86";
X#include <stdio.h>
X#include <ctype.h>
X#include "profile.h"
X
Xprofile_write_stanza (f, s)
XFILE *f;
XPROFILE_STANZA *s;
X{
X	write_markers(f, s->marker);
X	fprintf(f, "{\n");
X	write_bindings(f, s->binding);
X	fprintf(f, "}\n");
X}
X
Xstatic write_markers (f, m)
XFILE *f;
XPROFILE_MARKER *m;
X{
X	for (; m; m = m->next)
X		fprintf(f, "%s\n", m->text);
X}
X
Xstatic write_bindings (f, b)
XFILE *f;
XPROFILE_BINDING *b;
X{
X	while (b) {
X		fprintf(f, "\t%s", b->name);
X		write_values(f, b->value);
X		fputc('\n', f);
X		b = b->next;
X	}
X}
X
Xstatic write_values (f, v)
XFILE *f;
XPROFILE_VALUE *v;
X{
X	char scratch[PROFILE_MAX_TEXT+1];
X
X	for (; v; v = v->next)
X		switch (v->class) {
X		case PROFILE_INTEGER:
X			fprintf(f, " %D", v->value.i);
X			continue;
X		case PROFILE_FLOAT:
X			fprintf(f, " %G", v->value.f);
X			continue;
X		case PROFILE_STRING:
X			unparse_string(v->value.s, scratch);
X			fprintf(f, " \"%s\"", scratch);
X			continue;
X		case PROFILE_CHARACTER:
X			unparse_character(v->value.c, scratch);
X			fprintf(f, " '%s'", scratch);
X			continue;
X		case PROFILE_OCTAL:
X			fprintf(f, " 0o%O", v->value.i);
X			continue;
X		case PROFILE_HEX:
X			fprintf(f, " 0x%X", v->value.i);
X			continue;
X		case PROFILE_OTHER:
X			fprintf(f, " %s", v->value.s);
X			continue;
X		}
X}
X
Xstatic int unparse_string (from, to)
Xchar *from;
Xchar *to;
X{
X	char *x = to;
X
X	for (; *from; from++)
X		switch (*from) {
X		case '\b':		/* backspace */
X			*x++ = '\\';
X			*x++ = 'b';
X			continue;
X		case '\f':		/* formfeed */
X			*x++ = '\\';
X			*x++ = 'f';
X			continue;
X		case '\n':		/* newline */
X			*x++ = '\\';
X			*x++ = 'n';
X			continue;
X		case '\r':
X			*x++ = '\\';
X			*x++ = 'r';
X			continue;
X		case '\t':		/* horizontal tab */
X			*x++ = '\\';
X			*x++ = 't';
X			continue;
X		case '\\':		/* backslash */
X			*x++ = '\\';
X			*x++ = '\\';
X			continue;
X		case '"':		/* double quote */
X			*x++ = '\\';
X			*x++ = '"';
X			continue;
X		case '^':
X			*x++ = '\\';
X			*x++ = '^';
X			continue;
X		default:
X			if (isascii(*from))
X				if (iscntrl(*from)) {
X					sprintf(x, "^%c", *from == '\177' ? '?' : *from + '@');
X					x += 2;
X				} else
X					*x++ = *from;
X			else {
X				sprintf(x, "\\%03o", *from);
X				x += 4;
X			}
X			continue;
X		}
X	*x = '\0';
X	return(x - to);
X}
X
Xstatic int unparse_character (from, to)
Xchar from;
Xchar *to;
X{
X	char *x = to;
X
X	switch (from) {
X	case '\b':		/* backspace */
X		*x++ = '\\';
X		*x++ = 'b';
X		break;
X	case '\f':		/* formfeed */
X		*x++ = '\\';
X		*x++ = 'f';
X		break;
X	case '\n':		/* newline */
X		*x++ = '\\';
X		*x++ = 'n';
X		break;
X	case '\r':
X		*x++ = '\\';
X		*x++ = 'r';
X		break;
X	case '\t':		/* horizontal tab */
X		*x++ = '\\';
X		*x++ = 't';
X		break;
X	case '\\':		/* backslash */
X		*x++ = '\\';
X		*x++ = '\\';
X		break;
X	case '\'':		/* single quote */
X		*x++ = '\\';
X		*x++ = '\'';
X		break;
X	case '^':
X		*x++ = '\\';
X		*x++ = '^';
X		break;
X	default:
X		if (isascii(from))
X			if (iscntrl(from)) {
X				sprintf(x, "^%c", from == '\177' ? '?' : from + '@');
X				x += 2;
X			} else
X				*x++ = from;
X		else {
X			sprintf(x, "\\%03o", from);
X			x += 4;
X		}
X		break;
X	}
X	*x = '\0';
X	return(x - to);
X}
X
X/*
X * write out a linked list of stanzas
X */
Xprofile_write_profile(f, s)
XFILE *f;
XPROFILE_STANZA *s;
X{
X	PROFILE_STANZA *x;
X
X	for (x = s; x != NULL; x = x->next) {
X		profile_write_stanza(f, x);
X		if (x->next == s)
X			break;
X	}
X}
!FaR!OuT!
if [ ! -d man ]
then
	mkdir man
	echo mkdir man
fi
echo x - man/glob.3
sed -e 's/^X//' > man/glob.3 << '!FaR!OuT!'
X.\" %W% (TRW) %G%
X.TH GLOB 3 TRW
X.UC
X.SH NAME
Xglob \- shell style pattern matching
X.SH SYNOPSIS
X.nf
X.B #include <local/glob.h>
X
X.B int glob_compile(pattern, buffer)
X.B char *pattern;
X.B char *buffer;
X
X.B int glob_execute(buffer, s)
X.B char *buffer;
X.B char *s;
X
X.B int glob_match (pattern, s)
X.B char *pattern;
X.B char *s;
X.fi
X
X.B cc 
X[ flags ] files
X.B -lglob
X[ libraries ]
X.fi
X.SH DESCRIPTION
X.I Glob
Xis a pattern matching facility similar to that of
X.IR sh (1)
Xand
X.IR csh (1).
X.PP
XA pattern specifies a set of strings of characters.
XA member of this set of strings is said to be matched by the pattern.
X.TP
X(1)
XAny character except a special character matches itself.
XThe special characters are [ * and ?.
X.TP
X(2)
XA ? matches any character.
X.TP
X(3)
XA nonempty string
X.I s
Xbracketed
X.RI [ s ]
Xmatches any character in
X.IR s .
XIn
X.I s
X] may only appear as the first letter.
XA substring
X.IR a \- b ,
Xwith
X.I a
Xand
X.I b
Xin ascending ASCII order,
Xstands for the inclusive range of ASCII characters.
X.TP
X(4)
XA * matches 0 or more characters.
X.PP
X.I Glob_compile
Xcompiles a
X.I pattern
Xinto an internal form suitable for matching,
Xplacing the result in the character array
X.IR buffer .
X.I Buffer
Xmust be a character array of size
X.BR GLOB_MAX_PATTERN .
X.I Glob_compile
Xreturns 0 if the
X.I pattern
Xwas compiled successfully;
Xotherwise a negative error code is returned.
X.PP
X.I Glob_execute
Xchecks the argument string
X.I s
Xagainst the compiled
X.IR pattern .
X.I Glob_execute
Xreturns 1 if the string
X.I s
Xmatches the compiled pattern in
X.IR buffer ,
X0 if the string
X.I s
Xfailed to match the compiled pattern in
X.IR buffer ,
Xand a negative error code if the compiled pattern was invalid.
X.PP
XThe strings passed to both
X.I glob_compile
Xand
X.I glob_execute
Xmay have trailing or embedded newline characters;
Xthey are terminated by nulls.
X.PP
X.I Glob_match
Xcompiles
X.I pattern
Xand matches it against the argument string
X.IR s .
XIt returns 1 if the string
X.I s
Xmatches the pattern;
X0 if the string
X.I s
Xfails to match the pattern
Xand a negative error code if the pattern was invalid.
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xregex(3)
X.SH DIAGNOSTICS
XThe following diagnostic codes are provided:
X.TP
XGLOB_OK
Xreturned by
X.I glob_compile
Xindicating the pattern compiled successfully;
X.TP
XGLOB_PATTERN_TOO_BIG
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating the compiled pattern overflowed the buffer;
X.TP
XGLOB_PATTERN_EMPTY
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating the pattern is the empty string;
X.TP
XGLOB_BRACKET_MISSING
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating that a set expression
X.RI [ s ]
Xis missing the terminating bracket ];
X.TP
XGLOB_RANGE_INVERTED
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating a range expression in a set
Xis inverted, for example [z-a];
X.TP
XGLOB_SET_TOO_BIG
Xreturned by
X.I glob_compile
Xor
X.I glob_match
Xindicating a compiled set requires more than 127 bytes
X(a single character consumes 2 bytes and a range consumes 3 bytes);
X.TP
XGLOB_EXECUTION_ERROR
Xreturned by
X.I glob_execute
Xor
X.I glob_match
Xindicating an internal error.
!FaR!OuT!
if [ ! -d man ]
then
	mkdir man
	echo mkdir man
fi
echo x - man/index.1
sed -e 's/^X//' > man/index.1 << '!FaR!OuT!'
X.\" $Header: index.1,v 1.1 86/06/10 08:25:56 control Exp $
X.if t .ds LX L\v'-.22m'a\v'.22m'T\h'-.1667m'\v'.22m'E\h'-.125m'\v'-.22m'X
X.if n .ds LX LaTeX
X.TH INDEX 1 TRW
X.UC
X.SH NAME
Xindex \- index processor for converting LaTeX idx files
X.SH ORIGIN
XTRW
X.SH SYNOPSIS
X.B index [ -l ]
X.B [ -f
X.I alphabetizefile
X.B ] [
X.I file...
X.B ]
X.SH DESCRIPTION
X.I Index
Xconverts 
X.I idx 
Xfiles generated by \*(LX into 
X.I theindex 
Xenvironments that can be processed by \*(LX.
XMultiple files may be given.
XIf the file is not found, the extension
X.I idx
Xis appended and the new file is looked for.
XIndex files will be created with the extension
X.I ind.
XIf no files are given, standard input is read and standard output it written.
XSubitems and subsubitems can be generated by separating index entries
Xwith commas.
XFor example, after running your document
Xthrough \*(LX you may obtain an index file 
X.I sample.idx
Xcontaining entries
Xthat look like
X.RS
X.nf
X\eindexentry{Reagan}{32}
X\eindexentry{Reagan}{54}
X\eindexentry{Reagan,republicans}{54}
X\eindexentry{Carter}{60}
X\eindexentry{Reagan,republicans,conventions}{62}
X.fi
X.RE
XAfter running the index file through
X.I index
Xa file
X.I sample.ind 
Xwill be created that will contain
X.RS
X.nf
X\ebegin{theindex}
X\eitem Carter 60
X\eindexspace 
X\eitem Reagan 32, 54
X  \esubitem republicans 54
X    \esubsubitem conventions 62
X\eend{theindex}
X.fi
X.RE
XThe 
X.I indexspace 
Xleaves a little extra vertical space between the entries that start with
Xa new letter.
XIf the 
X.I -l 
Xoption is given, then a large index letter will precede each entry
Xthat starts with a new letter.
X.PP
X.I Index
Xreads the file
X.I .alphabetize
Xin the home directory if it exists
Xto determine how to alphabetize an
X.I idx
Xfile.
XThis file contains rules for skipping control sequences, characters, etc
Xwhen alphabetizing a file.
XThe format of this file is described in
X.IR index (5).
XIf the 
X.I -f 
Xoption is given, then another alphabetization file can be given.
X.PP
XA dash following an entry indicates the beginning of a range. 
XThe range is ended by the occurence of the next equivalent entry.
XFor example, suppose you had a \*(LX file containing
X.RS
X.nf
X\&...and they fought\eindex{fighting-} and wept...
X.fi
X.RE
Xon page 40 and
X.RS
X.nf
X\&...and were still fighting\eindex{fighting} years later...
X.fi
X.RE 
Xon page 42 with no intervening
X.I \eindex
Xcommands.
XThen after running the 
X.I idx
Xfile through 
X.I index,
Xthe line 
X.RS
X.nf
X\eitem fighting 40--42
X.fi
X.RE 
Xwould be contained in the 
X.I ind 
Xfile.
XWhen ranges are given for subitems and subsubitems, only the last
Xcomma separated entry should have a dash suffix.
XDuplicate page numbers are suppressed.
X.PP
XIf you wish to insert a comma into your index entry, you will need to 
Xhide it from the index processor with braces
Xsince only outer level commas are recognized as item delimeters.
XFor example,
X.RS
X.nf
X\eindex{Reagan{,} Ronald}
X.fi
X.RE
Xgenerates the index entry for
X.I Reagan, Ronald.
X.SH FILES
X.nf
X.ta \w'~/.alphabetize  'u
X~/.alphabetize	Default alphabetization file
X.fi
X.SH AUTHOR
XScott Simpson
X.SH SEE ALSO
Xprofile(3), index(5), profile(5)
X.SH DIAGNOSTICS
XComplains about illegal values in bindings in alphabetization file.
!FaR!OuT!
if [ ! -d man ]
then
	mkdir man
	echo mkdir man
fi
echo x - man/index.5
sed -e 's/^X//' > man/index.5 << '!FaR!OuT!'
X.\" $Header
X.if t .ds LX L\v'-.22m'a\v'.22m'T\h'-.1667m'\v'.22m'E\h'-.125m'\v'-.22m'X
X.if n .ds LX LaTeX
X.TH INDEX 5 TRW
X.UC
X.SH NAME
Xindex \- format of alphabetization stanza for LaTeX index processor
X.SH ORIGIN
XTRW
X.SH SYNOPSIS
X~/.alphabetize
X.SH DESCRIPTION
XThe \*(LX index processor
X.IR index (1)
Xreads the file
X.I .alphabetize
Xfile in the home directory to determine
Xhow to sort index entries.
XThis file is in 
X.IR profile (5)
Xformat and consists of a stanza containing bindings.
XThese bindings consist of key/value pairs.
XThere may be multiple values for each key.
X.PP
XThe stanza contained in the 
X.I .alphabetize 
Xfile should contain one stanza with the marker 
X.I alphabetize.
XThis stanza may contain three keys: 
X.I skipchars,
X.I mapctrlsequence 
Xand 
X.I mapindexentry.
X.PP
X.I Skipchars
Xis a list of characters to ignore when alphabetizing index entries.
X.PP
X.I Mapctrlsequence
Xis a list of pairs of values.
XThe odd numbered value 
X.I n
X(a control sequence)
Xmaps into the even value
X.I n+1
X(any text).
XThe leading backslash may 
Xbe omitted for the odd control sequence strings.
X.PP
X.I Mapindexentry
Xis a list of index entries to match exactly.
XThe odd numbered value
X.I n
X(an index entry) maps into the even value
X.I n+1
X(any text).
XThe backslashes
Xmay not be omitted here.
X.SH EXAMPLES
XHere is an example stanza to help clarify some ideas.
X.RS
X.nf
X.ta \w'    mapctrlsequence     'u
Xalphabetize
X{
X    skipchars		'{' '}' '$' '\e^' '\e'' '`' '_' '"'
X    mapctrlsequence	"\e\etrwlogo" "TRW" \e
X			"LaTeX" "LaTeX"
X    mapindexentry	"\e\everb|\e\e\e\e|" "\e\e" \e
X			"\e\everb|\e\e\e"|" "\e""
X}
X.fi
X.RE
XWhen alphabetizing the index file, the characters {, }, $, ^, ', `, _,
Xand " will be ignored.
X.IR Profile (5)
Xrequires escaping the ^, ' and \e.
X.PP
XThe control word
X.I \etrwlogo
Xwill be treated as the string
X.I TRW
Xwherever it occurs in an index entry
Xand the control word
X.I \eLaTeX
Xwill be treated as 
X.I LaTeX
Xwherever it occurs in an index entry.
XNote that the leading backslash in the third value (i.e.,
X.IR \eLaTeX )
Xcan be omitted without ill effect.
XNormally, control words and control symbols are removed when alphabetizing.
X.PP
XThe index entries
X.I \everb|\e\e|
Xand
X\fI\everb|\e"|\fR
Xwill be treated as \e and " when alphabetizing, respectively.
X.PP
XHere is one last example illustrating the sorting rules.
XSuppose we have the stanza
X.RS
X.nf
X.ta \w'    mapctrlsequence     'u
Xalphabetize
X{
X    skipchars		'{' '}'
X    mapctrlsequence	"\e\ehello" "salutation"
X    mapindexentry	"{\e\ela de da}" "z"
X}
X.fi
X.RE
Xand we have the
X.I \eindex
Xcommands
X.RS
X.nf
X\eindex{{\ebf Orca!} kills}
X\eindex{say,{\ela de da}}
X\eindex{say,{\ehello} there}
X\eindex{say,mazzard}
X\eindex{{\ela de da} de da}
X\eindex{{\eit Wolfman} Jack}
X.fi
X.RE
Xsprinkled throughout the document.
X\*(LX may generate the following 
X.I idx
Xfile
X.RS
X.nf
X\eindexentry{{\ebf Orca!} kills}{5}
X\eindexentry{say,{\ela de da}}{10}
X\eindexentry{say,{\ehello} there}{15}
X\eindexentry{say,mazzard}{20}
X\eindexentry{{\ela de da} de da}{25}
X\eindexentry{{\eit Wolfman} Jack}{30}
X.fi
X.RE
XAfter running through
X.I index
Xwe obtain the 
X.I ind
Xfile
X.RS
X.nf
X\ebegin{theindex}
X\eitem {\ela de da} de da 25
X\eindexspace
X\eitem {\ebf Orca!} kills 5
X\eindexspace
X\eitem say
X  \esubitem mazzard 20
X  \esubitem {\ehello} there 15
X  \esubitem {\ela de da} 10
X\eindexspace
X\eitem {\eit Wolfman} Jack 30
X\eend{theindex}
X.fi
X.RE
XThe entries are logically sorted using the strings
X.RS
X.nf
Xdedadeda
XOrca!kills
Xsay
X  mazzard
X  salutationthere
X  z
XWolfmanJack
X.fi
X.RE
XNote that the 
X.I mapindexentry
Xmust match everything between the commas and braces while the 
X.I mapctrlsequence
Xmatches control sequences anywhere within the index entry.
X.SH COMMENTS
XThe 
X.I mapindexentry 
Xentries are examined first and must completely match an index entry.
XIf they match, no other alphabetizing substitution takes place.
X.br
XUpper and lower case letters are equivalent when sorting.
XUpper case alphabetics are converted to lower case; consequently,
Xmost non-alphabetic characters precede the alphabetic characters
Xin the ASCII collating sequence.
XThe exception are the characters {, |, } and ~.
X.br
XBlanks are ignored when sorting.
X.br
XAfter control sequences are expanded into their logical sort string,
Xthey are not scanned for
X.I skipchars.
X.br
XLowercase roman numerals are recognized when the \epagestyle is roman.
XThey always precede their arabic counterparts.
XUppercase roman numerals are not recognized.
X.SH FILES
X.nf
X.ta \w'~/.alphabetize   'u
X~/.alphabetize	alphabetization file
X.fi
X.SH AUTHOR
XScott Simpson
X.SH SEE ALSO
Xindex(1), profile(3), profile(5), ascii(7)
X.SH BUGS
XThis manual page is confusing.
!FaR!OuT!
if [ ! -d man ]
then
	mkdir man
	echo mkdir man
fi
echo x - man/profile.3
sed -e 's/^X//' > man/profile.3 << '!FaR!OuT!'
X.\" %W% (TRW) %G%
X.TH PROFILE 3 TRW
X.UC 4
X.SH NAME
Xprofile \- read/write configuration files
X.SH SYNOPSIS
X.nf
X.B #include <stdio.h>
X.B #include <local/profile.h>
X
X.B PROFILE_STANZA *profile_read_stanza(f)
X.B FILE *f;
X
X.B PROFILE_STANZA *profile_read_profile(f)
X.B FILE *f;
X
X.B profile_write_stanza(f, s)
X.B FILE *f;
X.B PROFILE_STANZA *s;
X
X.B profile_write_profile(f, s)
X.B FILE *f;
X.B PROFILE_STANZA *s;
X
X.B profile_free_stanza(s)
X.B PROFILE_STANZA *s;
X
X.B PROFILE_MARKER *profile_has_marker(s, m)
X.B PROFILE_STANZA *s;
X.B char *m;
X
X.B PROFILE_STANZA *profile_has_stanza(s, marker)
X.B PROFILE_STANZA *s;
X.B char *marker[];
X
X.B PROFILE_BINDING *profile_has_binding(s, b)
X.B PROFILE_STANZA *s;
X.B char *b;
X
X.B PROFILE_STANZA *profile_stanza_space()
X
X.B PROFILE_MARKER *profile_marker_space(n)
X.B int n;
X
X.B PROFILE_BINDING *profile_binding_space(n)
X.B int n;
X
X.B PROFILE_VALUE *profile_value_space(n)
X.B int n;
X.fi
X.SH DESCRIPTION
X.I Profile_read_stanza
Xreads a single stanza from a configuration file returning
Xa pointer to the stanza if successful and NULL on error or end of file.
XA stanza is defined as:
X.nf
X.ta 1i +\w'typedef 'u
X
X	typedef struct PROFILE_STANZA {
X		PROFILE_MARKER *marker;
X		PROFILE_BINDING *binding;
X		struct PROFILE_STANZA *previous;
X		struct PROFILE_STANZA *next;
X	} PROFILE_STANZA;
X.fi
X.PP
X.I Marker
Xand
X.I binding
Xpoint to linked lists of markers and bindings respectively.
XIf
X.I marker
Xis
X.B NULL
Xthe stanza has no markers.
XIf
X.I binding
Xis
X.B NULL
Xthe stanza has no bindings.
X.I Previous
Xand
X.I next
Xare ignored and may be used to doubly link successive stanzas together.
X.DT
X.PP
XA marker is defined as:
X.nf
X.ta 1i +\w'typedef 'u
X
X	typedef struct PROFILE_MARKER {
X		char *text;
X		struct PROFILE_MARKER *previous;
X		struct PROFILE_MARKER *next;
X	} PROFILE_MARKER;
X.fi
X.DT
X.PP
X.I Text
Xis a string containing the literal text of the marker
Xand is always nonempty.
X.IR Previous " (" next )
Xis a pointer to the previous (next) marker in the sequence.
XIn the first (last) marker
X.IR previous " (" next )
Xis
X.BR NULL .
X.PP
XA binding is defined as:
X.nf
X.ta 1i +\w'typedef 'u
X
X	typedef struct PROFILE_BINDING {
X		char *name;
X		PROFILE_VALUE *value;
X		struct PROFILE_BINDING *previous;
X		struct PROFILE_BINDING *next;
X	} PROFILE_BINDING;
X.fi
X.DT
X.PP
X.I Name
Xis the literal text of the name of the binding and is always nonempty.
X.I Value
Xis a pointer to the list of values associated with the name.
XIf
X.I value
Xis
X.B NULL
Xthen the binding consists solely of a name with no associated value.
X.IR Previous " (" next )
Xpoints to the previous (next) binding in the sequence.
XIn the first (last) binding
X.IR previous " (" next )
Xis
X.BR NULL .
X.PP
XA value is defined as:
X.nf
X.ta 1i +\w'typedef 'u +\w'union { 'u
X
X	typedef struct PROFILE_VALUE {
X		char class;
X		union {
X			long int i;
X			double f;
X			char c;
X			char *s;
X		} value;
X		struct PROFILE_VALUE *previous;
X		struct PROFILE_VALUE *next;
X	} PROFILE_VALUE;
X.fi
X.DT
X.PP
X.I Class
Xis always one of:
X.TP
XPROFILE_CHARACTER
Xthe value is a character constant contained in
X.IR c .
X.TP
XPROFILE_HEX
Xthe value is a hex constant contained in
X.IR i .
X.TP
XPROFILE_INTEGER
Xthe value is an integer constant contained in
X.IR i .
X.TP
XPROFILE_FLOAT
Xthe value is a real constant contained in
X.IR f .
X.TP
XPROFILE_OCTAL
Xthe value is an octal constant contained in
X.IR i .
X.TP
XPROFILE_STRING
Xthe value is a string constant contained in
X.IR s .
X.TP
XPROFILE_OTHER
Xthe value is not recognizably
Xcharacter,
Xhex,
Xinteger,
Xfloat,
Xoctal
Xor string.
XThe literal text is contained in
X.IR s .
X.PP
X.IR Previous " (" next )
Xpoints to the previous (next) value in the sequence.
XIn the first (last) value
X.IR previous " (" next )
Xis
X.BR NULL .
X.PP
X.I Profile_read_profile
Xreads an entire configuration file and builds a bi-directional, 
Xcircularly linked list of stanzas using the 
X.I previous
Xand 
X.I next
Xpointers.
XThe value returned is a pointer to the first stanza in the list.
X.PP
X.I Profile_write_stanza
Xwrites a stanza in a canonical form suitable for input by
X.IR profile_read_stanza .
XMarkers are output one to a line.
XEach binding is indented by a single tab.
XNames and values are separated, one from the other,
Xby a single blank.
X.PP
X.I Profile_write_profile
Xwrites all the stanzas in a linked list by applying
X.I profile_write_stanza
Xto each stanza in the list.
XThe list need not be doubly linked.
X.PP
X.I Profile_free_stanza
Xfrees all storage associated with a stanza.
X.PP
X.I Profile_has_marker
Xsearches the marker list of a stanza for a match to the given marker,
X.IR m .
XA pointer to the marker is returned on success and
X.B NULL
Xon failure.
X.PP
X.I Profile_has_stanza
Xsearches a linked list of stanzas for a stanza that has all the
Xmarkers in
X.I marker.
X.I Marker 
Xmust be terminated by a null entry.
X.PP
X.I Profile_has_binding
Xsearches the binding list of a stanza
Xfor a binding with a match to the given name.
XA pointer to the binding is returned on success and
X.B NULL
Xon failure.
X.PP
XThe following routines are useful for constructing stanzas on the fly.
X.I Profile_stanza_space
Xallocates storage for a stanza.
X.I Profile_marker_space
Xallocates storage for a marker including sufficient space for
X.I n
Xcharacters of text plus a terminating null byte.
X.I Profile_binding_space
Xallocates storage for a binding including sufficient space for
X.I n
Xcharacters of name text plus a terminating null byte.
X.I Profile_value_space
Xallocates storage for a value.
XIf
X.I n
Xis positive and non-zero the component
X.IR value . s
Xis initialized as a
X.IR n +1
Xcharacter array.
XAll of the above routines return a pointer on success and
X.B NULL
Xon failure.
XAll storage is zero filled.
XThe routine
X.IR free (3)
Xmay be safely used to release storage allocated by these routines.
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xmalloc(3), profile(5)
!FaR!OuT!
if [ ! -d man ]
then
	mkdir man
	echo mkdir man
fi
echo x - man/profile.5
sed -e 's/^X//' > man/profile.5 << '!FaR!OuT!'
X.\" @(#)profile.5	1.1 (TRW) 6/11/84
X.TH PROFILE 5 TRW
X.UC 4
X.SH NAME
Xprofile \- configuration file format
X.SH SYNOPSIS
X.B #include <local/profile.h>
X.SH DESCRIPTION
X.I Profile
Xis a general purpose configuration file facility.
X.PP
XEach profile is an ASCII file containing a sequence of one or more
X.IR stanzas .
XEach stanza in turn consists of a sequence of
X.I markers
Xfollowed by a sequence of
X.IR bindings .
XThe characters `{' (left brace) and `}' (right brace)
Xdelimit the beginning and end respectively of the stanza bindings.
XEach binding consists of a name
Xfollowed by an optional sequence of values. 
X.SH MARKERS
XMarkers are arbitrary patterns in the style of
X.IR glob (3)
Xdelimited by white space.
XThe list of markers may be empty.
XThere is no limit to the number of markers.
XExamples of markers are:
X.nf
X
X	queue
X	/usr/lib
X	1776
X	a_long_marker
X	file[0-9]*.?
X.fi
X.SH BINDINGS
XBindings are the association of names with values.
XThere is one binding to a line each consisting of a name followed
Xby an optional sequence of values.
XNames and values are separated,
Xone from the other,
Xby blanks or tabs.
XHere a newline preceded by a backslash is equivalent to a blank.
XThe list of bindings may be empty.
XThere is no limit to the number of bindings.
XBy convention each binding is indented by a single tab.
X.SH NAMES
XNames are arbitrary patterns in the style of
X.IR glob (3)
Xdelimited by white space.
X.SH VALUES
XValues are
Xinteger,
Xreal,
Xoctal,
Xhex,
Xcharacter,
Xor
Xstring
Xconstants.
XArbitrary text,
Xnot recognizably one of the aforementioned types,
Xis classified as
X.I other
Xand is a legitimate value.
X.TP
Xinteger
XA sequence of digits optionally preceded by a minus sign.
XEvery integer constant is taken to be long.
X.TP
Xfloating
XA floating constant consists of an optional minus sign,
Xan integer part
Xa decimal point,
Xa fraction part,
Xan
X.B e
Xor
X.BR E ,
Xand an optionally signed integer exponent.
XThe integer and fraction parts both consist of a sequence of digits.
XEither the integer part or the fraction part (not both)
Xmay be missing;
Xeither the decimal point or the
X.B e
Xand the exponent (not both) may be missing.
XEvery floating constant is taken to be double-precision.
X.TP
Xhex
XA sequence of hexidecimal digits preceded by
X.B 0x
Xor
X.BR 0X .
XThe hexidecimal digits are 0-9, a-e and A-F.
XEvery hex constant is taken to be long.
X.TP
Xoctal
XA sequence of octal digits preceded by
X.B 0o
Xor
X.B 0O 
X(digit zero followed by a letter o).
XThe octal digits are 0-7.
XEvery octal constant is taken to be long.
X.TP
Xcharacter
XA character constant is a character enclosed in single quotes.
XCertain non-graphic characters,
Xthe single quote ',
Xthe caret ^ and
Xthe backslash \\,
Xmay be represented according to the following table of escape sequences:
X.ta 1i +\w'carriage return  'u
X.nf
X
X 	newline	\\n
X	horizontal tab	\\t
X	backspace	\\b
X	carriage return	\\r
X	form feed	\\f
X	escape	\\e
X	backslash	\\\\
X	single quote	\\'
X	caret	\\^
X	control-@	^@
X	control-A	^A
X	...	...
X	control-Z	^Z
X	control-[	^[
X	control-\\	^\\
X	control-^	^^
X	control-_	^_
X	delete	^?
X	bit pattern	\\\fIddd\fR
X
X.fi
X.DT
XThe escape \\\fIddd\fR
Xconsists of the backslash followed by 1, 2, or 3 octal digits
Xwhich are taken to specify the value of the desired character.
XIf the character following a backslash (caret) is not one of those
Xspecified, the backslash (caret) is ignored.
X.TP
Xstring
XA string is a sequence of characters surrounded by double quotes, as in
X\fB"..."\fR.
XIn a string,
Xthe double quote character \fB"\fR must be preceded by a \\;
Xin addition,
Xthe same escapes as described for character constants may be used.
X.PP
XExamples of values are:
X.nf
X
X	7
X	-1.293e3
X	0x10a5
X	0o1273
X	'x'
X	"a string"
X	an_other_value
X.fi
X.SH COMMENTS
XComments may appear anywhere within a profile.
XThey are introduced by the character `#' and are terminated by
Xthe succeeding newline.
X.SH EXAMPLES
XThe empty stanza.
X.nf
X
X{
X}
X.fi
X.PP
XA stanza in the configuration file of a fictitious network server.
X.nf
X.ta \w'queue 'u +\w'cost_per_packet 'u +\w'0o125 0x1af  'u
X
Xqueue net*
X{
X	priority	7	# integer
X	expect	"who is it"	# string
X	send	'?'	# character
X	flags[0-9]	0o125 0x1af 	# octal and hex
X	cost_per_packet	0.28	# floating
X	device	/dev/net	# other
X	homebrew		# a name with no associated value
X}	
X.fi
X.DT
X.PP
XA password file entry recast as a stanza.
X.nf
X.ta \w'brown 'u +\w'password 'u
X
Xbrown
X{
X	password	/bObOZtyGclMV
X	userid	225
X	groupid	30
X	home	/home/brown
X	shell	/bin/csh
X}
X.fi
X.DT
X.PP
XA termcap entry recast as a stanza.
X.nf
X.ta \w'adm3a 'u +\w'mm 'u
X
Xadm3a
X{
X	fullname "lsi adm3a"
X	am
X	bs
X	cm	"\\e=%+ %+ "
X	cl	"1^Z"
X	co	80
X	li	24
X	ho	'^^'
X	ma	"^K^P"
X	nd	'^L'
X	up	'^K'
X}
X.fi
X.SH AUTHOR
XMichael Gorlick, TRW
X.SH SEE ALSO
Xglob(3), profile(3)
!FaR!OuT!
if [ ! -d man ]
then
	mkdir man
	echo mkdir man
fi
echo x - man/standard.5
sed -e 's/^X//' > man/standard.5 << '!FaR!OuT!'
X.\" $Header: standard.5,v 1.1 87/06/23 10:14:41 control Exp $
X.TH STANDARD 5 TRW
X.UC
X.SH NAME
Xstandard \- standard include file for portability
X.SH ORIGIN
XTRW
X.SH SYNOPSIS
X#include <local/standard.h>
X.SH DESCRIPTION
X.I Standard
Xis a set of defines, macro definitions and typedefs that provide
Xportable constructs 
Xand machine specific information
Xfor different machine architectures and C compilers.
XBasically, the include file is divided up into four sections: 
Xmachine
Xenvironment
Xinformation,
Xstandard type definitions,
Xuseful constants and useful macros.
X.PP
XThe environment of the computer a program is executing on is described by
Xthe following defines:
X.TP
XHAS_UNSIGNED_SHORT
XIf defined, unsigned shorts are supported.
X.TP
XCHAR_IS_SIGNED
XIf defined, chars are signed.
X.TP
XHAS_UNSIGNED_CHAR
XIf defined, unsigned chars are supported.
X.TP
XHAS_UNSIGNED_LONG
XIf defined, unsigned longs are supported.
X.TP
XHAS_VOID
XIf defined, the void function type is supported.
X.TP
XBITS_PER_CHAR
XDefined as the number of bits in a char.
X.TP
XBITS_PER_SHORT
XDefined as the number of bits in a short.
X.TP
XBITS_PER_INT
XDefined as the number of bits in an int.
X.TP
XBITS_PER_LONG
XDefined as the number of bits in a long.
X.TP
XBITS_PER_POINTER
XDefined as the number of bits in a pointer.
X.PP
XThere are a set of machine independent type definitions and macros.
X.TP
XTiny
XA signed character type.
X.TP
XTINY(\fIx\fP)
XAn extraction macro for a signed character.  The value of the macro is an
Xinteger that will be sign extended if the most significant bit of the 
Xcharacter is one.
X.TP
XUnsignedTiny
XAn unsigned character type.
X.TP
XUNSIGNED_TINY(\fIx\fP)
XAn extraction macro for an unsigned character.  The value of the macro is an
Xinteger that will not be signed extended even if the most significant bit
Xof the character is one.
X.TP
XShort
XSimply a short type.  All compilers have a short type but this is included
Xfor lexical consistency.
X.TP
XUnsignedShort
XAn unsigned short type.
X.TP
XUNSIGNED_SHORT(\fIx\fP)
XAn extraction macro for an unsigned short.
XThe value of the macro is an integer that will not be sign extended even if
Xthe most significant bit of the short is one.
X.TP
XInteger
XThe int type.  Included for lexical consistency.
X.TP
XUnsignedInteger
XThe unsigned integer type.
X.TP
XLong
XThe long type.
X.TP
XUnsignedLong
XAn unsigned long type.
X.TP
XUNSIGNED_LONG(\fIx\fP)
XAn extraction macro for an unsigned long integer.
XNot all compilers support unsigned longs so we may have to simulate them.
X.TP
XTinyBoolean
XA tiny boolean value.  Boolean types take on only the values TRUE and FALSE.
X.TP
XBoolean
XA regular boolean value.
X.TP
XCharacter
XThe char type.  Included for lexical consistency.
X.TP
XTinyBits
XA type used only for bit set, clear and test operations.
X.TP
XBits
XThe regular size bit type.
X.TP
XLongBits
XThe long size bit type.
X.TP
XVoid
XThe void type.  If the void type is not supported then it is defined as
Xan int.
X.TP
XImport
XThe storage class used when importing variables from separate files.
XIt is defined to be the keyword 
X.I extern.
X.TP
XExport
XThe storage class used when exporting variables from separate files.
XIn C, you needn't 
Xdeclare that a variable is available to other files if it is declared
Xoutside a function so this is defined as a no-op.
X.TP
XLocal
XThe static storage class.
X.PP
XA number of useful constants are also defined.
X.TP
XTRUE and FALSE
XThe values 1 and 0 respectively.
X.TP
XSUCCEED and FAIL
XThe values 0 and 1 respectively.  These are normally used as exit statuses.
X.TP
XON
XA long with all the bits set.  
X.TP
XOFF
XA long with no bits set.
X.TP
XSTANDARD_IN
XDefined as 0.
X.TP
XSTANDARD_OUT
XDefined as 1.
X.TP
XSTANDARD_ERROR
XDefined as 2.
X.TP
XMAX_TINY
XThe maximum value a Tiny type can hold.
X.TP
XMIN_TINY
XThe minimum value a Tiny type can hold.
X.TP
XMAX_UNSIGNED_TINY
XThe maximum value an UnsignedTiny type can hold.
X.TP
XMIN_UNSIGNED_TINY
XThe minimum value an UnsignedTiny type can hold.
X.TP
XMAX_SHORT
XThe maximum value a Short type can hold.
X.TP
XMIN_SHORT 
XThe minimum value a Short type can hold.
X.TP
XMAX_UNSIGNED_SHORT
XThe maximum value an UnsignedShort type can hold.
X.TP
XMIN_UNSIGNED_SHORT
XThe minimum value an UnsignedShort type can hold.
X.TP
XMAX_INTEGER
XThe maximum value an Integer type can hold.
X.TP
XMIN_INTEGER
XThe minimum value an Integer type can hold.
X.TP
XMAX_UNSIGNED_INTEGER
XThe maximum value an UnsignedInteger type can hold.
X.TP
XMIN_UNSIGNED_INTEGER
XThe minimum value an UnsignedInteger type can hold.
X.TP
XMAX_LONG
XThe maximum value a Long type can hold.
X.TP
XMIN_LONG
XThe minimum value a Long type can hold.
X.TP
XMAX_UNSIGNED_LONG
XThe maximum value an UnsignedLong type can hold.
X.TP
XMIN_UNSIGNED_LONG
XThe minimum value an UnsignedLong type can hold.
X.TP
XBITS_PER_BYTE
XThe number of bits in a byte.
X.PP
XA number of useful macro are also defined.
X.TP
XMAX(\fIx\fP, \fIy\fP)
XReturns the maximum value of 
X.I x
Xand 
X.I y.
X.TP
XMIN(\fIx\fP, \fIy\fP)
XReturns the minimum value of 
X.I x
Xand
X.I y.
X.TP
XABS(\fIx\fP)
XReturns the absolute value of its parameter.  This works for integers and
Xreals.
X.TP
XROUND(\fIx\fP)
XReturns
Xits parameter rounded to the nearest integer value.
X.TP
XCEILING(\fIx\fP)
XReturns the ceiling of its parameter.
X.TP
XFLOOR(\fIx\fP)
XReturns the floor of its parameter.
X.TP
XEQ(\fIs\fP, \fIt\fP)
XReturns true if the two strings passed to it as parameters are equal.
X.TP
XEQN(\fIs\fP, \fIt\fP, \fIn\fP)
XReturns true if the two strings passed to it as parameters are equal in
Xthe first
X.I n
Xcharacters (as in
X.IR strcmp ).
X.SH FILES
X.nf
X.ta \w'/usr/include/local/standenviron.h   'u
X/usr/include/local/standard.h
X/usr/include/local/standenviron.h
X/usr/include/local/standtype.h
X/usr/include/local/standconst.h
X/usr/include/local/standmacro.h
X.fi
X.SH AUTHOR
XMichael Gorlick
!FaR!OuT!
echo x - shift.c
sed -e 's/^X//' > shift.c << '!FaR!OuT!'
Xstatic char *trwsccs = "@(#)shift.c	1.1 (TRW) 1/14/86";
X#include <ctype.h>
X
X/*
X * Downshifts a string in place.
X */
Xchar *string_downshift(s)
Xchar *s;
X{
X
X	register char *x = s;
X	for (; *x; x++)
X		if (isupper(*x))
X			*x = tolower(*x);
X	return(s);
X}
X
X/*
X * Upshifts a string in place.
X */
Xchar *string_upshift(s)
Xchar *s;
X{
X
X	register char *x = s;
X	for (; *x; x++)
X		if (islower(*x))
X			*x = toupper(*x);
X	return(s);
X}
!FaR!OuT!
exit