[comp.sources.wanted] troff indexer wanted

root@tndsyd.oz (Berny M Goodheart) (06/06/90)

I need "indexing" software for troff documents. The Sys V "subj" and
"ndx" facilities are not flexible enough so I am sourcing something
better. The program must be able to make an educated guess at what
the document is about and provide indecies including page numbering
ready to be processed by troff. 

Any useful software will do i.e awk shell scripts etc ...

ANY HELP or suggestions on this are much appreciated. The software is
to enable me to create an index for my new book about to be published
by Prentice Hall Q4 1990.

IF YOU CAN HELP, I WILL ACKNOWLEDGE YOUR CONTRIBUTION IN THE BOOK.

Much appreciated
Berny M. Goodheart     

 TANDEM Computers Incorporated  76 Berry St, North Sydney, NSW, 2060, Australia
 ==============================================================================
        ______  _______    __      __    _   _____    _____   __    __   
       /  /  /||__   __|  /  \    |  \  | | |  __ \  |  ___| |  \  /  | 
      /  /  / |   | |    / /\ \   | \ \ | | | |  \ \ | |_    | \ \/ / |
     /  /  /| |   | |   / /__\ \  | |\ \| | | |  | | |  _|   | |\  /| |
    /__/__/ | |   | |  / ______ \ | | \ \ | | |__/ / | |___  | | \/ | |
          | | /   |_| /_/      \_\|_|  \__| |_____/  |_____| |_|(TM)|_|
          | |/                   
          |/  Integrity-S2 Fault Tolerant UNIX  "Theres no stopping UNIX now!"
 ==============================================================================
 UUCP: uunet!munnari.oz!tndsyd.oz!berny             INTERNET:berny@tndsyd.oz.au    

brown@vidiot.UUCP (Vidiot) (06/07/90)

In article <211@tndsyd.oz> root@tndsyd.oz (Berny M Goodheart) writes:
<I need "indexing" software for troff documents. The Sys V "subj" and
<"ndx" facilities are not flexible enough so I am sourcing something
<better. The program must be able to make an educated guess at what
<the document is about and provide indecies including page numbering
<ready to be processed by troff. 

Attached below is the software that I use for my Star Trek: The Next
Generation Program Guide.  It isn't automatic, in that it doesn't go looking
for key words.  You have to supply them in the troff document.

The program works by building up a special file from the stderr output.
That file is operated on and the result is made troff ready.

If you have any questions on its use, let me know via e-mail.


---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#                                                                          
#                                                                          
#
#	Run the following text with /bin/sh to create:
#	  genidx.1
#	  genidx.c
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
echo "x - extracting genidx.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > genidx.1 &&
X.\" $Header: /usr/brown/startrek/RCS/genidx.1,v 3.0 89/10/18 13:30:21 brown Exp Locker: brown $
X.TH "genidx" "1L"
X.tr ~  
X.fi
X.ad b
X.SH NAME
Xgenidx - generate index source for troff
X.SH SYNOPSIS
Xgenidx [ -s ] [ -i input ] [ -o output ]
X.SH DESCRIPTION
X\f2Genidx\f1 is a postprocessor/filter that produces troff source.
XIt processes either normal
Xsequential page numbering or ``section-page'' numbering style (register
XN=3).  The output of \f2genidx\f1 is suitable for processing by
Xtroff and the tmac.lb (-mlb) macro package,
Xor may be edited to use the user's preferred macros.
XPage titles and footers should be added.
X
XThe output file is set to work with leading dots before the index page number.
XBefore printing the index, the normal setup is to indent 1 inch and have
Xtabs set for the width of the page numbers plus three spaces and 4.5i.
XBy using the width of the page numbers, floating leading dots can be done.
XThe size of the index letters is increased by 4 points and it is enbolded.
X.SS Options
X.IP "-i input" 12
XThe input file may be specified as the argument to the \f2-i\f1 option.
XIf omitted, input will be read from standard input.  The format of the
Xinput file is described below.
X.IP "-o output" 12
XThe output file may be specified as the argument to the \f2-o\f1 option.
XIf omitted, output will be written to standard output.
X.IP "-s" 12
XThe \f2-s\f1 flag indicates that the input is to be processed in
X``section-page'' numbering style.
X.SS "Input File"
X.P
XThe input file consists of individual records separated by newlines.
XEach line contains six fields separated by vertical bars, as follows:
X.if t \{\
X(spaces around the `|' for clarification only)
X.\}
X.nf
X.RS 6
X.P
X.ie t section | page | major | minor | reference | font |
X.el section|page|major|minor|reference|font|
X.RE
X.fi
X.IP section 12
XThe \f2section\f1 number will only be used in the presence of the
X\f2-s\f1 option.  The index macro (.IX) includes the section number in
Xthe event that the number register N is set to 3 (refer to the troff man
Xpages).  If that register is not
Xset to 3 or is not set, the section number will be set to 0.
X.IP page 12
XThe \f2page\f1 number will always be set by the index macro.  It will be
Xthe current page number at the point at which the macro is encountered.
XThe index macro is defined such that it may be included in the middle of
Xa paragraph without affecting fill and adjustment modes.
X.IP major 12
XThe \f2major\f1 subject must be present.  Also, each major subject must
Xbe present at least once in a macro with no minor subject or reference.
X.IP minor 12
XThe \f2minor\f1 subject may be one of hyphen ('-'), dot/period ('.'), or
Xa word or words.  The hyphen will be put in automatically by the index
Xmacro whenever there is no reference and no minor subject.  This is for
Xthe purpose of forcing these entries to sort before the dot and all
Xother characters.  The dot must be placed, with the index macro, by the
Xuser to indicate that the third argument is a reference and is to appear
Xon a ``see also'' line in the index.  Any other value will be treated as a
Xminor subject and appear in the index offset from the major subject.
X.IP reference 12
XThe \f2reference\f1 field is used in conjunction with the dot minor
Xsubject (see above).  When the dot is present as the minor subject, this
Xthird argument to the index macro or fifth input file field contains a
Xreference to another major subject.
X.IP font 12
XThe \f2font\f1 field is used to change the font of the major field to either
Xbold or italic.
XThe fourth argument, or sixth field, is set to either \f2B\f1 or \f2I\f1,
Xfor bold or italic.
XThe font change option cannot be used with minor or referenced fields.
X.SS "Index Macro"
X.P
XThe index macro is defined below in the \f2MACROS\f1 section.
XIt's use is as follows:
X.RS 6
X.nf
X.P
X\&.IX major minor reference font
X.RE
X.fi
X.P
XSee the section \f2Input File\f1 above.  This macro may be included anywhere
Xwithin the text of a document.  The index source entries will be written
Xto standard error, via the use of the .tm macro.
XAll unused fields \f3must\f1 be null filled.
XIf you are going to use a font change the \f2minor\f1 and \f2reference\f1
Xfields must be nulled.
X.SH EXAMPLES
XThe following demonstrates the use of the Index Macro and postprocessor
X(\f2genidx\f1).  Note that the macro may be included in the middle of a
Xparagraph without affecting justification or filling.
X.nf
X.RS 6
X.P
X\&.ad b
X\&.fi
X\&Now is the time
X\&.IX time
X\&.IX time . duration
X\&for all good men to come to the aid of their party.
X\&.IX men
X\&.IX men good
X\&.IX "good men"
X\&.IX party "" "" B
X.RE
X.fi
X.P
XNotice that \f2good men\f1 is placed inside of double quotes,
Xbecause both words are a part of the major subject.
XAlso notice the null filled double quotes, used as markers so that the
Xfont indicator will be placed into the correct field.
X.P
XProcessing is accomplished with either
X.RS 4
X.P
X$ troff -t -z file 2> idx.out
X.RE
X.P
Xfrom the Bourne Shell, or from the C Shell
X.P
X.RS 4
X.P
X% troff -t -z file >& idx.out
X.P
X			or
X.P
X% troff -t -z file |& genidx [options] > index.out
X.RE
X.P
XAnd produces the document
X.RS 4
X.P
XNow is the time for all good men to come
Xto the aid of their party.
X.RE
X.P
Xand index source
X.RS 4
X.nf
X.P
X.ie t \{\
X0 | 1 | time | - |  |  |
X0 | 1 | time | . | duration |  |
X0 | 1 | men | - |  |  |
X0 | 1 | men | good |  |  |
X0 | 1 | good men | - |  |  |
X0 | 1 | party | - |  | B |
X.\}
X.el \{\
X0|1|time|-|||
X0|1|time|.|duration||
X0|1|men|-|||
X0|1|men|good|||
X0|1|good men|-|||
X0|1|party|-||B|
X.\}
X.RE
X.fi
X.P
XPostprocessing is accomplished by
X.RS 4
X.nf
X.P
X$ genidx -i infile
X.RS 6
X.P
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4G\\s0\\f1
X\&.sp
X\&.IN "good men" "1"
X\&.ed
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4M\\s0\\f1
X\&.sp
X\&.IN "men" "1"
X\&\\h'24p'good, 1
X\&.ed
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4P\\s0\\f1
X\&.sp
X\&.IN "\\f3party\\fP" "1"
X\&.ed
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4T\\s0\\f1
X\&.sp
X\&.IN "time" "1"
X\&\\h'24p'also see ``\\f2duration\\f1''
X\&.ed
X.RE
X.fi
X.SH MACROS
X.P
XThe following two macros are what make up the troff requirements.
XThe .IX macro is what creates the standard error output for the genidx program.
XIn order for the .IX macro call to produce output only when it is needed,
Xthe I register is set to 1 on the command line.
X.P
XThe .IN macro call is what is used in the actual printing of the index pages.
XThis allows you to set the tab spacing the way you would like it.
XThe use of the \\a and \\t allow the file to be sent over USENET.
X.if t \{\
X(spaces around the `|' for clarification only)
X.\}
X.RS 6
X.nf
X.P
X.ie t \{\
X\&.de IN	\\" Index - provide means for doing \\a and \\t without losing
X\&.\\"		   control characters when sending out file.
X\&.ta 4.5i-\\w'\\\\$2\\\f2(space)\f1\\\f2(space)\f1\\\f2(space)\f1'uR 4.5iR
X\&\\\\$1\\\f2(space)\f1\\\f2(space)\f1\\\f2(space)\f1\\a\\t\\\\$2
X\&..
X\&.\\" If the I register is set to 1, allow the creation of the index list
X\&.if \\nI==1 \\{\\
X\&.de IX
X\&'ie !\\\\nN=3 \\{\\
X\&'ie '\\\\$2''  'tm 0 | \\\\n% | \\\\$1 | - | \\\\$3 | \\\\$4 |
X\&'el 'tm 0 | \\\\n% | \\\\$1 | \\\\$2 | \\\\$3 | \\\\$4 | \\}
X\&'el \\{
X\&'ie '\\\\$2''  'tm \\\\n(H1 | \\\\n% | \\\\$1 | - | \\\\$3 | \\\\$4 |
X\&'el 'tm \\\\n(H1 | \\\\n% | \\\\$1 | \\\\$2 | \\\\$3 | \\\\$4 | \\}
X\&.. \\}
X.\}
X.el \{\
X\&.de IN	\\" Index - provide means for doing \\a and \\t without losing
X\&.\\"		   control characters when sending out file.
X\&.ta 4.5i-\\w'\\\\$2\\ \\ \\ 'uR 4.5iR
X\&\\\\$1\\ \\ \\ \\a\\t\\\\$2
X\&..
X\&.\\" If the I register is set to 1, allow the creation of the index list
X\&.if \\nI==1 \\{\\
X\&.de IX
X\&'ie !\\\\nN=3 \\{\\
X\&'ie '\\\\$2''  'tm 0|\\\\n%|\\\\$1|-|\\\\$3|\\\\$4|
X\&'el 'tm 0|\\\\n%|\\\\$1|\\\\$2|\\\\$3|\\\\$4|\\}
X\&'el \\{
X\&'ie '\\\\$2''  'tm \\\\n(H1|\\\\n%|\\\\$1|-|\\\\$3|\\\\$4|
X\&'el 'tm \\\\n(H1|\\\\n%|\\\\$1|\\\\$2|\\\\$3|\\\\$4|\\}
X\&.. \\}
X.\}
X.RE
X.fi
X.SH "SEE ALSO"
Xtroff(1), mlb(7)
X.SH AUTHOR
X.nf
XSteven M. List
XBenetics Corporation
XMountain View, CA
XOctober, 1985
X{cdp,greipa,idi,oliveb,plx,sun,tolerant}!bene!luke!itkin
X
XModified by:
XMichael L. Brown
X6013 Mayhill Drive
XMadison, WI
XAugust, 1989
Xuwvax!astroatc!vidiot!brown
SHAR_EOF
chmod 0644 genidx.1 || echo "restore of genidx.1 fails"
set `wc -c genidx.1`;Sum=$1
if test "$Sum" != "8087"
then echo original size 8087, current size $Sum;fi
echo "x - extracting genidx.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > genidx.c &&
Xstatic char rcsid[] = "$Header: /usr/brown/startrek/RCS/genidx.c,v 3.1 90/01/05 20:17:39 brown Exp Locker: brown $";
X/*T genidx - generate troff source for index from .IX macro output */
X/*S globals, includes, defines */
X/*H genidx ***********************************************************
X*
X*                                   genidx
X*
X*  This program is part of a package composed of three parts: the
X*  index macros defined below, this program which postprocesses the output
X*  from those macros, and the troff mlb macros and troff.  A separate file
X*  should be created for inclusion in those documents that will use indexing.
X*
X*    '''\"		       version 1.0 - 10/01/85	Initial code
X*    '''\"	  Michael L. Brown     1.1 -  5/27/88	fixed first letter
X*    '''\"						changed section.
X*    '''\"			       1.2 -  5/18/89	hanging-tagged the
X*    '''\"						section letter.
X*    '''\"						Added .sd/.ed macros.
X*    '''\"			       1.3 -  7/03/89	Removed the .ta output
X*    '''\"			       3.0 -  8/02/89	Added font changing
X*    '''\"			       3.1 - 12/08/89	Changed tp->page from
X*    '''\"						int to char.
X*
X*    .de IN	\" Index - provide means for doing \a and \t without losing
X*    .\"		   control characters when sending out file.
X*    .ta 4.5i-\w'\\$2\ \ \ 'uR 4.5iR
X*    \\$1\ \ \ \a\t\\$2
X*    ..
X*    .\" If the I register is set to 1, allow the creation of the index list
X*    .if \nI==1 \{\
X*    .de IX
X*    'ie !\\nN=3 \{\
X*    'ie '\\$2''  'tm 0|\\n%|\\$1|-|\\$3|\\$4|
X*    'el 'tm 0|\\n%|\\$1|\\$2|\\$3|\\$4|\}
X*    'el \{
X*    'ie '\\$2''  'tm \\n(H1|\\n%|\\$1|-|\\$3|\\$4|
X*    'el 'tm \\n(H1|\\n%|\\$1|\\$2|\\$3|\\$4|\}
X*    .. \}
X*
X*  The output of the index macros has the form:
X*
X*    section|page|major|minor_or_flag|reference|font|
X*
X*  where
X*	section = current section number for section-page numbering
X*	page = current page number (absolute or within section)
X*	major = major subject
X*	minor_or_flag = minor subject unless it is `.' or `-'
X*	   where
X*		. = this is a reference, use the last field for "see also"
X*		- = this is a major declaration - used to force proper sort
X*	reference = cross reference to another major subject,
X*		    used with . as the minor
X*	font = B for bold and I for italic
X*
X*  Because of the use of the .tm macro, the output of the index
X*  macro goes to standard error.
X*
X*  Genidx sorts its input and produces troff -mlb source as its output.
X*  The output is readily modified to use other macros.
X*
X*  usage: genidx [ -i indexin ] [ -o troffout ] [ -s ]
X*
X*  If -i is omitted, input defaults to standard input.
X*  If -o is omitted, output defaults to standard output.
X*  If -s, section-page style is employed.
X*
X*********************************************************************/
X/*E*/
X#define EQ ==
X#define NE !=
X#define GT >
X#define GE >=
X#define LT <
X#define LE <=
X#define OR ||
X#define AND &&
X
X#define TRUE 1
X#define FALSE 0
X#define YES 1
X#define NO 0
X
X#define NULLSTMT     
X#define DO_FOREVER for(;;)
X
X#define SPACE ' '
X#define NUL '\0'
X
Xtypedef short   BOOL;
X
X#define INULL -32768
X#define LNULL -2147483648
X
X#define MAX(a,b) ((a) > (b) ? (a) : (b))
X#define MIN(a,b) ((a) < (b) ? (a) : (b))
X#define ABS(a) ((a) >= 0 ? (a) : -(a))
X
X#include	<stdio.h>
X#include	<ctype.h>
X
Xchar	*pgm;		/* place to store the program name */
X
X#define NAMSIZ 128	/* convenient buffer size */
X
X	/* ------------------------------------------------------------ */
X	/* this structure is used to build a table of all entries       */
X	/* for the current major subject                                */
X	/* ------------------------------------------------------------ */
X
Xstruct tbl
X{
X	int	section;
X	char	page[NAMSIZ];
X	char	subnm[NAMSIZ];
X	char	subsubnm[NAMSIZ];
X	char	reference[NAMSIZ];
X	char	font[NAMSIZ];
X}	*tbl = NULL;
X
Xint		nent = 0;		/* number of entries in the current */
X					/* major subject */
Xint		maxent = 20;		/* table size */
Xint		sectpage = FALSE;	/* true if section-page numbering */
X					/* style in use */
Xint		first = 1;		/* This is first pass, do not output the .ed */
X
X#ifdef BSD
Xextern char *rindex ();
X#else
Xextern char *strrchr ();
X#endif
Xextern struct tbl *malloc ();
Xextern struct tbl *realloc ();
X
Xchar	buf[128];			/* input records */
X/*S main loop */
X/*Page Eject*/
Xmain (ac, av)
Xint		ac;
Xchar	*av[];
X{
X	static char *_fnm = "main";	/* function name for messages */
X
X	extern FILE *popen ();		/* open pipe from sort */
X
X	register FILE *in = stdin;	/* input stream */
X	register FILE *out = stdout;	/* output stream */
X
X	char	*infile = NULL;		/* input stream pathname */
X	char	*outfile = NULL;	/* output stream pathname */
X
X	char	sortbuf[80];		/* place to build sort command */
X
X	extern char *optarg;		/* option argument pointer */
X	extern int optind;		/* option index (av[optind]) */
X
X	register int i;			/* general purpose temp */
X
X	/* ------------------------------------------------------------ */
X	/* set program name for messages                                */
X	/* ------------------------------------------------------------ */
X
X#ifdef BSD
X	if (pgm = rindex (av[0], '/')) pgm++;
X#else
X	if (pgm = strrchr (av[0], '/')) pgm++;
X#endif
X	else pgm = av[0];
X
X	/* ------------------------------------------------------------ */
X	/* process command line arguments                               */
X	/* ------------------------------------------------------------ */
X
X	while ((i = getopt (ac, av, "i:o:s")) NE EOF)
X	{
X		switch (i)
X		{
X			case	'i':			/* input file name */
X				infile = optarg;
X				break;
X			case	'o':			/* output file name */
X				outfile = optarg;
X				break;
X			case	's':			/* turn on sect-page style */
X				sectpage = TRUE;
X				break;
X			default:
X				usage ();
X				exit (1);
X				break;
X		}
X	}
X
X	/* ------------------------------------------------------------ */
X	/* open the files (input/stdin, output/stdout)                  */
X	/* ------------------------------------------------------------ */
X
X	if (infile)
X	{
X		sprintf (sortbuf, "sort -d -t'|' +2f +0n -1n +1n -2n %s", infile);
X	}
X	else
X	{
X		sprintf (sortbuf, "sort -d -t'|' +2f +0n -1n +1n -2n");
X	}
X
X	if (!(in = popen (sortbuf, "r")))
X	{
X		fprintf (stderr,
X			"%s<%s>: ERROR: cannot read input file %s\n",
X			pgm, _fnm, infile);
X		exit (99);
X	}
X
X	if (outfile AND !(out = fopen (outfile, "w")))
X	{
X		fprintf (stderr,
X			"%s<%s>: ERROR: cannot create output file %s\n",
X			pgm, _fnm, outfile);
X		exit (99);
X	}
X
X	/* ------------------------------------------------------------ */
X	/* process the index                                            */
X	/* ------------------------------------------------------------ */
X
X	doidx (in, out);
X
X	exit (0);
X}
X/*S doidx - do the actual processing here */
X/*H doidx ************************************************************
X*
X*                                   doidx
X*
X*  Doidx reads the sorted input and processes each major subject
X*  as a separate entity, generating the appropriate troff and mlb
X*  macros.
X*
X*********************************************************************/
X/*E*/
Xdoidx (in, out)
Xregister FILE *in;
Xregister FILE *out;
X{
X	static char *_fnm = "doidx";	/* function name for messages */
X
X	char	subname[40];		/* major subject name */
X
X	register char *cp;		/* temporary pointer */
X	register struct tbl *tp;	/* pointer into subject table */
X
X	extern char *strtok ();		/* find tokens */
X
X	struct tbl ttmp;		/* temporary subject table entry */
X
X	subname[0] = NUL;		/* initialize last subject name */
X
X	/* ------------------------------------------------------------ */
X	/* process all lines in the sorted input                        */
X	/* ------------------------------------------------------------ */
X
X	while (fgets (buf, sizeof buf, in) EQ buf)
X	{
X	/* ------------------------------------------------------------ */
X	/* initialize the temporary table entry to NULs                 */
X	/* ------------------------------------------------------------ */
X		strncpy (&ttmp, "", sizeof ttmp);
X	/* ------------------------------------------------------------ */
X	/* crack out the pieces of the line                             */
X	/* ------------------------------------------------------------ */
X		breakup (buf, &ttmp);
X	/* ------------------------------------------------------------ */
X	/* first time - set the last subject name to this one           */
X	/* ------------------------------------------------------------ */
X		if (!subname[0]) strcpy (subname, ttmp.subnm);
X	/* ------------------------------------------------------------ */
X	/* grow the subject table if necessary                          */
X	/* ------------------------------------------------------------ */
X		checktbl ();
X	/* ------------------------------------------------------------ */
X	/* if the subject has changed,                                  */
X	/*   if there is only one entry, move it into the table         */
X	/*   flush the current table and reinitialize the table and     */
X	/*     last subject name                                        */
X	/* else copy the entry into the table                           */
X	/* ------------------------------------------------------------ */
X		if (strcmp (subname, ttmp.subnm))
X		{
X			if (!nent) tbl[nent++] = ttmp;
X			flushidx (out);
X			nent = 0;
X			tbl[nent++] = ttmp;
X			strcpy (subname, ttmp.subnm);
X		}
X		else
X		{
X			tbl[nent++] = ttmp;
X		}
X	}
X	/* ------------------------------------------------------------ */
X	/* if there is anything in the table, flush it                  */
X	/* ------------------------------------------------------------ */
X	if (nent)
X	{
X		flushidx (out);
X	}
X	/* ------------------------------------------------------------ */
X	/* output any remaining stuff for troff				*/
X	/* ------------------------------------------------------------ */
X	/* output the final .ed */
X	fprintf (out,".ed\n");
X	return;
X}
X/*S flushidx - print out the contents of the subject table */
X/*H flushidx *********************************************************
X*
X*                                   flushidx
X*
X*  Flushidx prints out each table entry with appropriate macros
X*  depending on the type of entry.
X*
X*********************************************************************/
X/*E*/
Xflushidx (out)
Xregister FILE *out;				/* output stream */
X{
X	register struct tbl *tp;		/* subject table pointer */
X	register struct tbl *end = &tbl[nent];	/* end of subject table	*/
X
X	static char alphachar = NUL;		/* section letter for dividing */
X						/* the index alphabetically */
X	register char tc;			/* temp for lower/upper conv */
X
X	tp = tbl;				/* start at the top */
X
X	/* ------------------------------------------------------------ */
X	/* if the first letter has changed, start a new section         */
X	/* ------------------------------------------------------------ */
X
X	if (isdigit(tp->subnm[0]) OR isupper(tp->subnm[0]))
X	{
X		tc = tp->subnm[0];
X	}
X	else
X	{
X		tc = toupper(tp->subnm[0]);
X	}
X	if (tc NE alphachar)
X	{
X		alphachar = tc;
X		/* if this is not the first time through, output the .ed first */
X		if (first EQ 0)
X		{
X			fprintf (out, ".ed\n");
X		}
X		first=0;
X		fprintf (out, ".sd 1i\n");
X		fprintf (out, ".sp 2v\n");
X		fprintf (out, "\\f3\\s+4%c\\s0\\f1\n", alphachar);
X		fprintf (out, ".sp\n");
X	}
X
X	/* ------------------------------------------------------------ */
X	/* print out the basics of the major subject                    */
X	/* ------------------------------------------------------------ */
X
X	if (sectpage)
X	{
X		fprintf (out, "%s, %d-%s",
X			tp->subnm, tp->section, tp->page);
X	}
X	else
X	{
X		if (*tp->font EQ 'B')
X		{
X			fprintf (out, ".IN \"\\f3%s\\fP\" \"%s", tp->subnm, tp->page);
X		}
X		else if (*tp->font EQ 'I')
X		{
X			fprintf (out, ".IN \"\\f2%s\\fP\" \"%s", tp->subnm, tp->page);
X		}
X		else
X		{
X			fprintf (out, ".IN \"%s\" \"%s", tp->subnm, tp->page);
X		}
X	}
X	tp++;
X
X	/* ------------------------------------------------------------ */
X	/* for each repeat entry, add the page number                   */
X	/* ------------------------------------------------------------ */
X
X	while (tp LT end AND !strcmp (tp->subsubnm, (tp-1)->subsubnm))
X	{
X		if (strcmp(tp->page,(tp-1)->page) != 0)
X		{
X			if (sectpage AND tp->section NE (tp-1)->section)
X			{
X				fprintf (out, ", %d-%s", tp->section, tp->page);
X			}
X			else if (!sectpage)
X			{
X				fprintf (out, ", %s", tp->page);
X			}
X		}
X		tp++;
X	}
X
X	fprintf (out, "\"\n");
X
X	/* ------------------------------------------------------------ */
X	/* add all reference entries                                    */
X	/* ------------------------------------------------------------ */
X
X	while (tp LT end AND *tp->reference)
X	{
X		fprintf (out, "\\h'24p'also see ``\\f2%s\\f1''\n",
X			tp->reference);
X		tp++;
X	}
X
X	/* ------------------------------------------------------------ */
X	/* if there are any minor subjects, list them                   */
X	/* ------------------------------------------------------------ */
X
X	if (tp LT end)
X	{
X		if (sectpage)
X		{
X			fprintf (out, "\\h'24p'%s, %d-%s",
X				tp->subsubnm, tp->section, tp->page);
X		}
X		else
X		{
X			fprintf (out, "\\h'24p'%s, %s", tp->subsubnm, tp->page);
X		}
X		tp++;
X
X		while (tp LT end)
X		{
X			if (!strcmp (tp->subsubnm, (tp-1)->subsubnm))
X			{
X				if (strcmp(tp->page,(tp-1)->page) !=0 AND
X					tp->section NE (tp-1)->section)
X				{
X					if (sectpage)
X					{
X						fprintf (out, ", %d-%s", tp->section, tp->page);
X					}
X					else
X					{
X						fprintf (out, ", %s", tp->page);
X					}
X				}
X			}
X			else
X			{
X				if (sectpage)
X					fprintf (out, "\n\\h'24p'%s, %d-%s",
X						tp->subsubnm, tp->section, tp->page);
X				else
X					fprintf (out, "\n\\h'24p'%s, %s",
X						tp->subsubnm, tp->page);
X			}
X			tp++;
X		}
X
X		fprintf (out, "\n");
X	}
X
X	return;
X}
X/*S breakup - process an input record */
X/*H breakup **********************************************************
X*
X*                                   breakup
X*
X*  This function extract each of the fields from the input record
X*  and places them into a subject table entry.
X*
X*********************************************************************/
X/*E*/
Xbreakup (buf, tp)
Xregister char *buf;			/* input record */
Xregister struct tbl *tp;		/* subject table structure */
X{
X	register char *cp;		/* temporary pointer */
X
X/********************************************************************
X*
X* The strtok call will search for the first non-separator character.
X* If there are separator characters back-to-back, it will skip those
X* "null" fields until it finds a non-separator character, or the end
X* of the string.
X*
X* This procedure takes advantage of that, whereby the font field is
X* not necessarily looked for by position, only that it is the next
X* filled-in field after the minor/reference check.
X*
X*********************************************************************/
X
X	if (cp = strtok (buf, "|"))		/* section number */
X	{
X		tp->section = atoi (cp);
X		cp = strtok (0, "|");
X		strcpy(tp->page,cp);		/* page number */
X		if (cp = strtok (0, "|"))	/* major subject */
X		{
X			strncpy (tp->subnm, cp, sizeof tp->subnm);
X			if (cp = strtok (0, "|"))
X			{
X				if (!strcmp (cp, "."))		/* reference */
X				{
X					cp = strtok (0, "|");
X					strncpy (tp->reference, cp, sizeof tp->reference);
X				}
X				else		/* minor subject */
X				{
X					strncpy (tp->subsubnm, cp, sizeof tp->subsubnm);
X				}
X			}
X		}
X		if (cp = strtok(0, "|"))	/* Font change */
X		{
X			strncpy (tp->font, cp, sizeof tp->font);
X		}
X	}
X
X	return;
X}
X/*S usage - print out helpful usage messages */
X/*H usage ************************************************************
X*
X*                                  usage
X*
X*********************************************************************/
X/*E*/
Xusage ()
X{
X	fprintf (stderr, "\
Xusage: %s [ -i indexin ] [ -o troffout ] [ -s ]\n\n\
X\tindexin = standard error from troff with index macros\n\
X\ttroffout = input to troff to generate index\n\
X\t-s = use section-page numbering style\n\n\
Xdefaults are standard input and standard output\n\n",
X		pgm);
X	
X	return;
X}
X/*S checktbl - grow the subject table if necessary */
X/*H checktbl *********************************************************
X*
X*                                   checktbl
X*
X*  Checktbl checks the current size of the table against the number
X*  of entries possible.  If we are outgrowing the table, it will be
X*  expanded and the maximum increased.
X*
X*********************************************************************/
X/*E*/
Xchecktbl ()
X{
X	static char *_fnm = "checktbl";	/* function name for messages	*/
X
X	if (!tbl)
X	{
X		if (!(tbl = malloc (maxent * sizeof (struct tbl))))
X		{
X			fprintf (stderr,
X				"%s<%s>: ERROR: cannot allocate table space - exiting\n",
X				pgm, _fnm);
X			exit (3);
X		}
X	}
X	else if (nent GE maxent)
X	{
X		maxent += 20;
X		if (!(tbl = realloc (tbl, maxent * sizeof (struct tbl))))
X		{
X			fprintf (stderr,
X				"%s<%s>: ERROR: cannot reallocate table space - exiting\n",
X				pgm, _fnm);
X			exit (4);
X		}
X	}
X
X	return;
X}
SHAR_EOF
chmod 0644 genidx.c || echo "restore of genidx.c fails"
set `wc -c genidx.c`;Sum=$1
if test "$Sum" != "16796"
then echo original size 16796, current size $Sum;fi
exit 0
-- 
      harvard\     att!nicmad\        spool.cs.wisc.edu!astroatc!vidiot!brown
Vidiot  ucbvax!uwvax..........!astroatc!vidiot!brown
      rutgers/  decvax!nicmad/ INET:<@spool.cs.wisc.edu,@astroatc:brown@vidiot>
Newsgroups: comp.sources.wanted,aus.wanted,misc.wanted,alt.sources.wanted
Subject: Re: troff indexer wanted
Summary: 
Expires: 
References: <211@tndsyd.oz>
Sender: 
Reply-To: brown@vidiot.UUCP (Vidiot)
Followup-To: 
Distribution: 
Organization: Vidiot's Hangout
Keywords: indexer software

In article <211@tndsyd.oz> root@tndsyd.oz (Berny M Goodheart) writes:
<I need "indexing" software for troff documents. The Sys V "subj" and
<"ndx" facilities are not flexible enough so I am sourcing something
<better. The program must be able to make an educated guess at what
<the document is about and provide indecies including page numbering
<ready to be processed by troff. 

Attached below is the software that I use for my Star Trek: The Next
Generation Program Guide.  It isn't automatic, in that it doesn't go looking
for key words.  You have to supply them in the troff document.

The program works by building up a special file from the stderr output.
That file is operated on and the result is made troff ready.

If you have any questions on its use, let me know via e-mail.


---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#                                                                          
#                                                                          
#
#	Run the following text with /bin/sh to create:
#	  genidx.1
#	  genidx.c
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
echo "x - extracting genidx.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > genidx.1 &&
X.\" $Header: /usr/brown/startrek/RCS/genidx.1,v 3.0 89/10/18 13:30:21 brown Exp Locker: brown $
X.TH "genidx" "1L"
X.tr ~  
X.fi
X.ad b
X.SH NAME
Xgenidx - generate index source for troff
X.SH SYNOPSIS
Xgenidx [ -s ] [ -i input ] [ -o output ]
X.SH DESCRIPTION
X\f2Genidx\f1 is a postprocessor/filter that produces troff source.
XIt processes either normal
Xsequential page numbering or ``section-page'' numbering style (register
XN=3).  The output of \f2genidx\f1 is suitable for processing by
Xtroff and the tmac.lb (-mlb) macro package,
Xor may be edited to use the user's preferred macros.
XPage titles and footers should be added.
X
XThe output file is set to work with leading dots before the index page number.
XBefore printing the index, the normal setup is to indent 1 inch and have
Xtabs set for the width of the page numbers plus three spaces and 4.5i.
XBy using the width of the page numbers, floating leading dots can be done.
XThe size of the index letters is increased by 4 points and it is enbolded.
X.SS Options
X.IP "-i input" 12
XThe input file may be specified as the argument to the \f2-i\f1 option.
XIf omitted, input will be read from standard input.  The format of the
Xinput file is described below.
X.IP "-o output" 12
XThe output file may be specified as the argument to the \f2-o\f1 option.
XIf omitted, output will be written to standard output.
X.IP "-s" 12
XThe \f2-s\f1 flag indicates that the input is to be processed in
X``section-page'' numbering style.
X.SS "Input File"
X.P
XThe input file consists of individual records separated by newlines.
XEach line contains six fields separated by vertical bars, as follows:
X.if t \{\
X(spaces around the `|' for clarification only)
X.\}
X.nf
X.RS 6
X.P
X.ie t section | page | major | minor | reference | font |
X.el section|page|major|minor|reference|font|
X.RE
X.fi
X.IP section 12
XThe \f2section\f1 number will only be used in the presence of the
X\f2-s\f1 option.  The index macro (.IX) includes the section number in
Xthe event that the number register N is set to 3 (refer to the troff man
Xpages).  If that register is not
Xset to 3 or is not set, the section number will be set to 0.
X.IP page 12
XThe \f2page\f1 number will always be set by the index macro.  It will be
Xthe current page number at the point at which the macro is encountered.
XThe index macro is defined such that it may be included in the middle of
Xa paragraph without affecting fill and adjustment modes.
X.IP major 12
XThe \f2major\f1 subject must be present.  Also, each major subject must
Xbe present at least once in a macro with no minor subject or reference.
X.IP minor 12
XThe \f2minor\f1 subject may be one of hyphen ('-'), dot/period ('.'), or
Xa word or words.  The hyphen will be put in automatically by the index
Xmacro whenever there is no reference and no minor subject.  This is for
Xthe purpose of forcing these entries to sort before the dot and all
Xother characters.  The dot must be placed, with the index macro, by the
Xuser to indicate that the third argument is a reference and is to appear
Xon a ``see also'' line in the index.  Any other value will be treated as a
Xminor subject and appear in the index offset from the major subject.
X.IP reference 12
XThe \f2reference\f1 field is used in conjunction with the dot minor
Xsubject (see above).  When the dot is present as the minor subject, this
Xthird argument to the index macro or fifth input file field contains a
Xreference to another major subject.
X.IP font 12
XThe \f2font\f1 field is used to change the font of the major field to either
Xbold or italic.
XThe fourth argument, or sixth field, is set to either \f2B\f1 or \f2I\f1,
Xfor bold or italic.
XThe font change option cannot be used with minor or referenced fields.
X.SS "Index Macro"
X.P
XThe index macro is defined below in the \f2MACROS\f1 section.
XIt's use is as follows:
X.RS 6
X.nf
X.P
X\&.IX major minor reference font
X.RE
X.fi
X.P
XSee the section \f2Input File\f1 above.  This macro may be included anywhere
Xwithin the text of a document.  The index source entries will be written
Xto standard error, via the use of the .tm macro.
XAll unused fields \f3must\f1 be null filled.
XIf you are going to use a font change the \f2minor\f1 and \f2reference\f1
Xfields must be nulled.
X.SH EXAMPLES
XThe following demonstrates the use of the Index Macro and postprocessor
X(\f2genidx\f1).  Note that the macro may be included in the middle of a
Xparagraph without affecting justification or filling.
X.nf
X.RS 6
X.P
X\&.ad b
X\&.fi
X\&Now is the time
X\&.IX time
X\&.IX time . duration
X\&for all good men to come to the aid of their party.
X\&.IX men
X\&.IX men good
X\&.IX "good men"
X\&.IX party "" "" B
X.RE
X.fi
X.P
XNotice that \f2good men\f1 is placed inside of double quotes,
Xbecause both words are a part of the major subject.
XAlso notice the null filled double quotes, used as markers so that the
Xfont indicator will be placed into the correct field.
X.P
XProcessing is accomplished with either
X.RS 4
X.P
X$ troff -t -z file 2> idx.out
X.RE
X.P
Xfrom the Bourne Shell, or from the C Shell
X.P
X.RS 4
X.P
X% troff -t -z file >& idx.out
X.P
X			or
X.P
X% troff -t -z file |& genidx [options] > index.out
X.RE
X.P
XAnd produces the document
X.RS 4
X.P
XNow is the time for all good men to come
Xto the aid of their party.
X.RE
X.P
Xand index source
X.RS 4
X.nf
X.P
X.ie t \{\
X0 | 1 | time | - |  |  |
X0 | 1 | time | . | duration |  |
X0 | 1 | men | - |  |  |
X0 | 1 | men | good |  |  |
X0 | 1 | good men | - |  |  |
X0 | 1 | party | - |  | B |
X.\}
X.el \{\
X0|1|time|-|||
X0|1|time|.|duration||
X0|1|men|-|||
X0|1|men|good|||
X0|1|good men|-|||
X0|1|party|-||B|
X.\}
X.RE
X.fi
X.P
XPostprocessing is accomplished by
X.RS 4
X.nf
X.P
X$ genidx -i infile
X.RS 6
X.P
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4G\\s0\\f1
X\&.sp
X\&.IN "good men" "1"
X\&.ed
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4M\\s0\\f1
X\&.sp
X\&.IN "men" "1"
X\&\\h'24p'good, 1
X\&.ed
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4P\\s0\\f1
X\&.sp
X\&.IN "\\f3party\\fP" "1"
X\&.ed
X\&.sd 1i
X\&.sp 2v
X\&\\f3\\s+4T\\s0\\f1
X\&.sp
X\&.IN "time" "1"
X\&\\h'24p'also see ``\\f2duration\\f1''
X\&.ed
X.RE
X.fi
X.SH MACROS
X.P
XThe following two macros are what make up the troff requirements.
XThe .IX macro is what creates the standard error output for the genidx program.
XIn order for the .IX macro call to produce output only when it is needed,
Xthe I register is set to 1 on the command line.
X.P
XThe .IN macro call is what is used in the actual printing of the index pages.
XThis allows you to set the tab spacing the way you would like it.
XThe use of the \\a and \\t allow the file to be sent over USENET.
X.if t \{\
X(spaces around the `|' for clarification only)
X.\}
X.RS 6
X.nf
X.P
X.ie t \{\
X\&.de IN	\\" Index - provide means for doing \\a and \\t without losing
X\&.\\"		   control characters when sending out file.
X\&.ta 4.5i-\\w'\\\\$2\\\f2(space)\f1\\\f2(space)\f1\\\f2(space)\f1'uR 4.5iR
X\&\\\\$1\\\f2(space)\f1\\\f2(space)\f1\\\f2(space)\f1\\a\\t\\\\$2
X\&..
X\&.\\" If the I register is set to 1, allow the creation of the index list
X\&.if \\nI==1 \\{\\
X\&.de IX
X\&'ie !\\\\nN=3 \\{\\
X\&'ie '\\\\$2''  'tm 0 | \\\\n% | \\\\$1 | - | \\\\$3 | \\\\$4 |
X\&'el 'tm 0 | \\\\n% | \\\\$1 | \\\\$2 | \\\\$3 | \\\\$4 | \\}
X\&'el \\{
X\&'ie '\\\\$2''  'tm \\\\n(H1 | \\\\n% | \\\\$1 | - | \\\\$3 | \\\\$4 |
X\&'el 'tm \\\\n(H1 | \\\\n% | \\\\$1 | \\\\$2 | \\\\$3 | \\\\$4 | \\}
X\&.. \\}
X.\}
X.el \{\
X\&.de IN	\\" Index - provide means for doing \\a and \\t without losing
X\&.\\"		   control characters when sending out file.
X\&.ta 4.5i-\\w'\\\\$2\\ \\ \\ 'uR 4.5iR
X\&\\\\$1\\ \\ \\ \\a\\t\\\\$2
X\&..
X\&.\\" If the I register is set to 1, allow the creation of the index list
X\&.if \\nI==1 \\{\\
X\&.de IX
X\&'ie !\\\\nN=3 \\{\\
X\&'ie '\\\\$2''  'tm 0|\\\\n%|\\\\$1|-|\\\\$3|\\\\$4|
X\&'el 'tm 0|\\\\n%|\\\\$1|\\\\$2|\\\\$3|\\\\$4|\\}
X\&'el \\{
X\&'ie '\\\\$2''  'tm \\\\n(H1|\\\\n%|\\\\$1|-|\\\\$3|\\\\$4|
X\&'el 'tm \\\\n(H1|\\\\n%|\\\\$1|\\\\$2|\\\\$3|\\\\$4|\\}
X\&.. \\}
X.\}
X.RE
X.fi
X.SH "SEE ALSO"
Xtroff(1), mlb(7)
X.SH AUTHOR
X.nf
XSteven M. List
XBenetics Corporation
XMountain View, CA
XOctober, 1985
X{cdp,greipa,idi,oliveb,plx,sun,tolerant}!bene!luke!itkin
X
XModified by:
XMichael L. Brown
X6013 Mayhill Drive
XMadison, WI
XAugust, 1989
Xuwvax!astroatc!vidiot!brown
SHAR_EOF
chmod 0644 genidx.1 || echo "restore of genidx.1 fails"
set `wc -c genidx.1`;Sum=$1
if test "$Sum" != "8087"
then echo original size 8087, current size $Sum;fi
echo "x - extracting genidx.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > genidx.c &&
Xstatic char rcsid[] = "$Header: /usr/brown/startrek/RCS/genidx.c,v 3.1 90/01/05 20:17:39 brown Exp Locker: brown $";
X/*T genidx - generate troff source for index from .IX macro output */
X/*S globals, includes, defines */
X/*H genidx ***********************************************************
X*
X*                                   genidx
X*
X*  This program is part of a package composed of three parts: the
X*  index macros defined below, this program which postprocesses the output
X*  from those macros, and the troff mlb macros and troff.  A separate file
X*  should be created for inclusion in those documents that will use indexing.
X*
X*    '''\"		       version 1.0 - 10/01/85	Initial code
X*    '''\"	  Michael L. Brown     1.1 -  5/27/88	fixed first letter
X*    '''\"						changed section.
X*    '''\"			       1.2 -  5/18/89	hanging-tagged the
X*    '''\"						section letter.
X*    '''\"						Added .sd/.ed macros.
X*    '''\"			       1.3 -  7/03/89	Removed the .ta output
X*    '''\"			       3.0 -  8/02/89	Added font changing
X*    '''\"			       3.1 - 12/08/89	Changed tp->page from
X*    '''\"						int to char.
X*
X*    .de IN	\" Index - provide means for doing \a and \t without losing
X*    .\"		   control characters when sending out file.
X*    .ta 4.5i-\w'\\$2\ \ \ 'uR 4.5iR
X*    \\$1\ \ \ \a\t\\$2
X*    ..
X*    .\" If the I register is set to 1, allow the creation of the index list
X*    .if \nI==1 \{\
X*    .de IX
X*    'ie !\\nN=3 \{\
X*    'ie '\\$2''  'tm 0|\\n%|\\$1|-|\\$3|\\$4|
X*    'el 'tm 0|\\n%|\\$1|\\$2|\\$3|\\$4|\}
X*    'el \{
X*    'ie '\\$2''  'tm \\n(H1|\\n%|\\$1|-|\\$3|\\$4|
X*    'el 'tm \\n(H1|\\n%|\\$1|\\$2|\\$3|\\$4|\}
X*    .. \}
X*
X*  The output of the index macros has the form:
X*
X*    section|page|major|minor_or_flag|reference|font|
X*
X*  where
X*	section = current section number for section-page numbering
X*	page = current page number (absolute or within section)
X*	major = major subject
X*	minor_or_flag = minor subject unless it is `.' or `-'
X*	   where
X*		. = this is a reference, use the last field for "see also"
X*		- = this is a major declaration - used to force proper sort
X*	reference = cross reference to another major subject,
X*		    used with . as the minor
X*	font = B for bold and I for italic
X*
X*  Because of the use of the .tm macro, the output of the index
X*  macro goes to standard error.
X*
X*  Genidx sorts its input and produces troff -mlb source as its output.
X*  The output is readily modified to use other macros.
X*
X*  usage: genidx [ -i indexin ] [ -o troffout ] [ -s ]
X*
X*  If -i is omitted, input defaults to standard input.
X*  If -o is omitted, output defaults to standard output.
X*  If -s, section-page style is employed.
X*
X*********************************************************************/
X/*E*/
X#define EQ ==
X#define NE !=
X#define GT >
X#define GE >=
X#define LT <
X#define LE <=
X#define OR ||
X#define AND &&
X
X#define TRUE 1
X#define FALSE 0
X#define YES 1
X#define NO 0
X
X#define NULLSTMT     
X#define DO_FOREVER for(;;)
X
X#define SPACE ' '
X#define NUL '\0'
X
Xtypedef short   BOOL;
X
X#define INULL -32768
X#define LNULL -2147483648
X
X#define MAX(a,b) ((a) > (b) ? (a) : (b))
X#define MIN(a,b) ((a) < (b) ? (a) : (b))
X#define ABS(a) ((a) >= 0 ? (a) : -(a))
X
X#include	<stdio.h>
X#include	<ctype.h>
X
Xchar	*pgm;		/* place to store the program name */
X
X#define NAMSIZ 128	/* convenient buffer size */
X
X	/* ------------------------------------------------------------ */
X	/* this structure is used to build a table of all entries       */
X	/* for the current major subject                                */
X	/* ------------------------------------------------------------ */
X
Xstruct tbl
X{
X	int	section;
X	char	page[NAMSIZ];
X	char	subnm[NAMSIZ];
X	char	subsubnm[NAMSIZ];
X	char	reference[NAMSIZ];
X	char	font[NAMSIZ];
X}	*tbl = NULL;
X
Xint		nent = 0;		/* number of entries in the current */
X					/* major subject */
Xint		maxent = 20;		/* table size */
Xint		sectpage = FALSE;	/* true if section-page numbering */
X					/* style in use */
Xint		first = 1;		/* This is first pass, do not output the .ed */
X
X#ifdef BSD
Xextern char *rindex ();
X#else
Xextern char *strrchr ();
X#endif
Xextern struct tbl *malloc ();
Xextern struct tbl *realloc ();
X
Xchar	buf[128];			/* input records */
X/*S main loop */
X/*Page Eject*/
Xmain (ac, av)
Xint		ac;
Xchar	*av[];
X{
X	static char *_fnm = "main";	/* function name for messages */
X
X	extern FILE *popen ();		/* open pipe from sort */
X
X	register FILE *in = stdin;	/* input stream */
X	register FILE *out = stdout;	/* output stream */
X
X	char	*infile = NULL;		/* input stream pathname */
X	char	*outfile = NULL;	/* output stream pathname */
X
X	char	sortbuf[80];		/* place to build sort command */
X
X	extern char *optarg;		/* option argument pointer */
X	extern int optind;		/* option index (av[optind]) */
X
X	register int i;			/* general purpose temp */
X
X	/* ------------------------------------------------------------ */
X	/* set program name for messages                                */
X	/* ------------------------------------------------------------ */
X
X#ifdef BSD
X	if (pgm = rindex (av[0], '/')) pgm++;
X#else
X	if (pgm = strrchr (av[0], '/')) pgm++;
X#endif
X	else pgm = av[0];
X
X	/* ------------------------------------------------------------ */
X	/* process command line arguments                               */
X	/* ------------------------------------------------------------ */
X
X	while ((i = getopt (ac, av, "i:o:s")) NE EOF)
X	{
X		switch (i)
X		{
X			case	'i':			/* input file name */
X				infile = optarg;
X				break;
X			case	'o':			/* output file name */
X				outfile = optarg;
X				break;
X			case	's':			/* turn on sect-page style */
X				sectpage = TRUE;
X				break;
X			default:
X				usage ();
X				exit (1);
X				break;
X		}
X	}
X
X	/* ------------------------------------------------------------ */
X	/* open the files (input/stdin, output/stdout)                  */
X	/* ------------------------------------------------------------ */
X
X	if (infile)
X	{
X		sprintf (sortbuf, "sort -d -t'|' +2f +0n -1n +1n -2n %s", infile);
X	}
X	else
X	{
X		sprintf (sortbuf, "sort -d -t'|' +2f +0n -1n +1n -2n");
X	}
X
X	if (!(in = popen (sortbuf, "r")))
X	{
X		fprintf (stderr,
X			"%s<%s>: ERROR: cannot read input file %s\n",
X			pgm, _fnm, infile);
X		exit (99);
X	}
X
X	if (outfile AND !(out = fopen (outfile, "w")))
X	{
X		fprintf (stderr,
X			"%s<%s>: ERROR: cannot create output file %s\n",
X			pgm, _fnm, outfile);
X		exit (99);
X	}
X
X	/* ------------------------------------------------------------ */
X	/* process the index                                            */
X	/* ------------------------------------------------------------ */
X
X	doidx (in, out);
X
X	exit (0);
X}
X/*S doidx - do the actual processing here */
X/*H doidx ************************************************************
X*
X*                                   doidx
X*
X*  Doidx reads the sorted input and processes each major subject
X*  as a separate entity, generating the appropriate troff and mlb
X*  macros.
X*
X*********************************************************************/
X/*E*/
Xdoidx (in, out)
Xregister FILE *in;
Xregister FILE *out;
X{
X	static char *_fnm = "doidx";	/* function name for messages */
X
X	char	subname[40];		/* major subject name */
X
X	register char *cp;		/* temporary pointer */
X	register struct tbl *tp;	/* pointer into subject table */
X
X	extern char *strtok ();		/* find tokens */
X
X	struct tbl ttmp;		/* temporary subject table entry */
X
X	subname[0] = NUL;		/* initialize last subject name */
X
X	/* ------------------------------------------------------------ */
X	/* process all lines in the sorted input                        */
X	/* ------------------------------------------------------------ */
X
X	while (fgets (buf, sizeof buf, in) EQ buf)
X	{
X	/* ------------------------------------------------------------ */
X	/* initialize the temporary table entry to NULs                 */
X	/* ------------------------------------------------------------ */
X		strncpy (&ttmp, "", sizeof ttmp);
X	/* ------------------------------------------------------------ */
X	/* crack out the pieces of the line                             */
X	/* ------------------------------------------------------------ */
X		breakup (buf, &ttmp);
X	/* ------------------------------------------------------------ */
X	/* first time - set the last subject name to this one           */
X	/* ------------------------------------------------------------ */
X		if (!subname[0]) strcpy (subname, ttmp.subnm);
X	/* ------------------------------------------------------------ */
X	/* grow the subject table if necessary                          */
X	/* ------------------------------------------------------------ */
X		checktbl ();
X	/* ------------------------------------------------------------ */
X	/* if the subject has changed,                                  */
X	/*   if there is only one entry, move it into the table         */
X	/*   flush the current table and reinitialize the table and     */
X	/*     last subject name                                        */
X	/* else copy the entry into the table                           */
X	/* ------------------------------------------------------------ */
X		if (strcmp (subname, ttmp.subnm))
X		{
X			if (!nent) tbl[nent++] = ttmp;
X			flushidx (out);
X			nent = 0;
X			tbl[nent++] = ttmp;
X			strcpy (subname, ttmp.subnm);
X		}
X		else
X		{
X			tbl[nent++] = ttmp;
X		}
X	}
X	/* ------------------------------------------------------------ */
X	/* if there is anything in the table, flush it                  */
X	/* ------------------------------------------------------------ */
X	if (nent)
X	{
X		flushidx (out);
X	}
X	/* ------------------------------------------------------------ */
X	/* output any remaining stuff for troff				*/
X	/* ------------------------------------------------------------ */
X	/* output the final .ed */
X	fprintf (out,".ed\n");
X	return;
X}
X/*S flushidx - print out the contents of the subject table */
X/*H flushidx *********************************************************
X*
X*                                   flushidx
X*
X*  Flushidx prints out each table entry with appropriate macros
X*  depending on the type of entry.
X*
X*********************************************************************/
X/*E*/
Xflushidx (out)
Xregister FILE *out;				/* output stream */
X{
X	register struct tbl *tp;		/* subject table pointer */
X	register struct tbl *end = &tbl[nent];	/* end of subject table	*/
X
X	static char alphachar = NUL;		/* section letter for dividing */
X						/* the index alphabetically */
X	register char tc;			/* temp for lower/upper conv */
X
X	tp = tbl;				/* start at the top */
X
X	/* ------------------------------------------------------------ */
X	/* if the first letter has changed, start a new section         */
X	/* ------------------------------------------------------------ */
X
X	if (isdigit(tp->subnm[0]) OR isupper(tp->subnm[0]))
X	{
X		tc = tp->subnm[0];
X	}
X	else
X	{
X		tc = toupper(tp->subnm[0]);
X	}
X	if (tc NE alphachar)
X	{
X		alphachar = tc;
X		/* if this is not the first time through, output the .ed first */
X		if (first EQ 0)
X		{
X			fprintf (out, ".ed\n");
X		}
X		first=0;
X		fprintf (out, ".sd 1i\n");
X		fprintf (out, ".sp 2v\n");
X		fprintf (out, "\\f3\\s+4%c\\s0\\f1\n", alphachar);
X		fprintf (out, ".sp\n");
X	}
X
X	/* ------------------------------------------------------------ */
X	/* print out the basics of the major subject                    */
X	/* ------------------------------------------------------------ */
X
X	if (sectpage)
X	{
X		fprintf (out, "%s, %d-%s",
X			tp->subnm, tp->section, tp->page);
X	}
X	else
X	{
X		if (*tp->font EQ 'B')
X		{
X			fprintf (out, ".IN \"\\f3%s\\fP\" \"%s", tp->subnm, tp->page);
X		}
X		else if (*tp->font EQ 'I')
X		{
X			fprintf (out, ".IN \"\\f2%s\\fP\" \"%s", tp->subnm, tp->page);
X		}
X		else
X		{
X			fprintf (out, ".IN \"%s\" \"%s", tp->subnm, tp->page);
X		}
X	}
X	tp++;
X
X	/* ------------------------------------------------------------ */
X	/* for each repeat entry, add the page number                   */
X	/* ------------------------------------------------------------ */
X
X	while (tp LT end AND !strcmp (tp->subsubnm, (tp-1)->subsubnm))
X	{
X		if (strcmp(tp->page,(tp-1)->page) != 0)
X		{
X			if (sectpage AND tp->section NE (tp-1)->section)
X			{
X				fprintf (out, ", %d-%s", tp->section, tp->page);
X			}
X			else if (!sectpage)
X			{
X				fprintf (out, ", %s", tp->page);
X			}
X		}
X		tp++;
X	}
X
X	fprintf (out, "\"\n");
X
X	/* ------------------------------------------------------------ */
X	/* add all reference entries                                    */
X	/* ------------------------------------------------------------ */
X
X	while (tp LT end AND *tp->reference)
X	{
X		fprintf (out, "\\h'24p'also see ``\\f2%s\\f1''\n",
X			tp->reference);
X		tp++;
X	}
X
X	/* ------------------------------------------------------------ */
X	/* if there are any minor subjects, list them                   */
X	/* ------------------------------------------------------------ */
X
X	if (tp LT end)
X	{
X		if (sectpage)
X		{
X			fprintf (out, "\\h'24p'%s, %d-%s",
X				tp->subsubnm, tp->section, tp->page);
X		}
X		else
X		{
X			fprintf (out, "\\h'24p'%s, %s", tp->subsubnm, tp->page);
X		}
X		tp++;
X
X		while (tp LT end)
X		{
X			if (!strcmp (tp->subsubnm, (tp-1)->subsubnm))
X			{
X				if (strcmp(tp->page,(tp-1)->page) !=0 AND
X					tp->section NE (tp-1)->section)
X				{
X					if (sectpage)
X					{
X						fprintf (out, ", %d-%s", tp->section, tp->page);
X					}
X					else
X					{
X						fprintf (out, ", %s", tp->page);
X					}
X				}
X			}
X			else
X			{
X				if (sectpage)
X					fprintf (out, "\n\\h'24p'%s, %d-%s",
X						tp->subsubnm, tp->section, tp->page);
X				else
X					fprintf (out, "\n\\h'24p'%s, %s",
X						tp->subsubnm, tp->page);
X			}
X			tp++;
X		}
X
X		fprintf (out, "\n");
X	}
X
X	return;
X}
X/*S breakup - process an input record */
X/*H breakup **********************************************************
X*
X*                                   breakup
X*
X*  This function extract each of the fields from the input record
X*  and places them into a subject table entry.
X*
X*********************************************************************/
X/*E*/
Xbreakup (buf, tp)
Xregister char *buf;			/* input record */
Xregister struct tbl *tp;		/* subject table structure */
X{
X	register char *cp;		/* temporary pointer */
X
X/********************************************************************
X*
X* The strtok call will search for the first non-separator character.
X* If there are separator characters back-to-back, it will skip those
X* "null" fields until it finds a non-separator character, or the end
X* of the string.
X*
X* This procedure takes advantage of that, whereby the font field is
X* not necessarily looked for by position, only that it is the next
X* filled-in field after the minor/reference check.
X*
X*********************************************************************/
X
X	if (cp = strtok (buf, "|"))		/* section number */
X	{
X		tp->section = atoi (cp);
X		cp = strtok (0, "|");
X		strcpy(tp->page,cp);		/* page number */
X		if (cp = strtok (0, "|"))	/* major subject */
X		{
X			strncpy (tp->subnm, cp, sizeof tp->subnm);
X			if (cp = strtok (0, "|"))
X			{
X				if (!strcmp (cp, "."))		/* reference */
X				{
X					cp = strtok (0, "|");
X					strncpy (tp->reference, cp, sizeof tp->reference);
X				}
X				else		/* minor subject */
X				{
X					strncpy (tp->subsubnm, cp, sizeof tp->subsubnm);
X				}
X			}
X		}
X		if (cp = strtok(0, "|"))	/* Font change */
X		{
X			strncpy (tp->font, cp, sizeof tp->font);
X		}
X	}
X
X	return;
X}
X/*S usage - print out helpful usage messages */
X/*H usage ************************************************************
X*
X*                                  usage
X*
X*********************************************************************/
X/*E*/
Xusage ()
X{
X	fprintf (stderr, "\
Xusage: %s [ -i indexin ] [ -o troffout ] [ -s ]\n\n\
X\tindexin = standard error from troff with index macros\n\
X\ttroffout = input to troff to generate index\n\
X\t-s = use section-page numbering style\n\n\
Xdefaults are standard input and standard output\n\n",
X		pgm);
X	
X	return;
X}
X/*S checktbl - grow the subject table if necessary */
X/*H checktbl *********************************************************
X*
X*                                   checktbl
X*
X*  Checktbl checks the current size of the table against the number
X*  of entries possible.  If we are outgrowing the table, it will be
X*  expanded and the maximum increased.
X*
X*********************************************************************/
X/*E*/
Xchecktbl ()
X{
X	static char *_fnm = "checktbl";	/* function name for messages	*/
X
X	if (!tbl)
X	{
X		if (!(tbl = malloc (maxent * sizeof (struct tbl))))
X		{
X			fprintf (stderr,
X				"%s<%s>: ERROR: cannot allocate table space - exiting\n",
X				pgm, _fnm);
X			exit (3);
X		}
X	}
X	else if (nent GE maxent)
X	{
X		maxent += 20;
X		if (!(tbl = realloc (tbl, maxent * sizeof (struct tbl))))
X		{
X			fprintf (stderr,
X				"%s<%s>: ERROR: cannot reallocate table space - exiting\n",
X				pgm, _fnm);
X			exit (4);
X		}
X	}
X
X	return;
X}
SHAR_EOF
chmod 0644 genidx.c || echo "restore of genidx.c fails"
set `wc -c genidx.c`;Sum=$1
if test "$Sum" != "16796"
then echo original size 16796, current size $Sum;fi
exit 0
-- 
      harvard\     att!nicmad\        spool.cs.wisc.edu!astroatc!vidiot!brown
Vidiot  ucbvax!uwvax..........!astroatc!vidiot!brown
      rutgers/  decvax!nicmad/ INET:<@spool.cs.wisc.edu,@astroatc:brown@vidiot>