#
/*
 *			G E T K W K
 */

/*)BUILD	$(TKBOPTIONS) = {
			TASK	= ...GTK
		}
*/

#ifdef	DOCUMENTATION
title	getkwk	Build Keyword Index
index		Build Keyword Index

synopsis

	getkwk [-w -c] >output.fil file_list

description

	Getkwk scans library (macro) files for "; index" lines, building
	the input to kwik.  It runs only on the decus compiler.
	The format of the library files is described in getrno.c.
	.s
	The -w and -c options are as described for getrno:
	.lm +8
	.s.i -8;-w	Wizard
	.s.i -8;-c	C source, rather than Macro
	.s.lm -8
	To build an index to the Decus C runtime library on RSTS/E:
	.s.nf
		getkwk >index.tmp [5,4]*.mac [5,5]*.mac
		kwik -t 16 -w 64 <index.tmp >index.tm1
		rnoidx <index.tm1 >index.tm2
		pip index.rno=indhed.rno,index.tm2/fa
		rno index=index
		pip index.tmp,index.tm1,index.tm2/de
	.s.f

author

	Martin Minow

#endif

#include <stdio.h>
#define		FALSE		0
#define		TRUE		1
#define		EOS		0
#define		NAMESIZE	16	/* -t NAMESIZE in kwik		*/
int		debug;
int		cflag		= 0;	/* -c C source files		*/
int		wizard		= 0;	/* -w Wizard flag		*/
char		line[133];		/* Input text line		*/
char		namebuf[NAMESIZE];

FILE		*infd;

main(argc, argv)
int		argc;
char		*argv[];
{

	register int		c;
	register int		i;
	register char		*ap;

	for (i = 1; i < argc; i++) {
		if (*(ap = argv[i]) == '-') {
			while ((c = tolower(*++ap)) != EOS) {
				switch (c) {
				case 'd':
					debug++;
					break;

				case 'c':
					cflag++;

				case 'w':
					wizard++;
					break;

				default:
					bug("W", "Unknown switch", ap);
					break;
				}
			}
		}
		else {
			process(argv[i]);
		}
	}
}

process(name)
char		*name;		/* Wild spec to process			*/
/*
 * Do this wild spec.
 */
{
	register int	count;

	if ((infd = fwild(name, "r")) == NULL) {
		bug("W", "Can't open file", name);
		return;
	}
	for (count = 0; fnext(infd) != NULL; count++) {
		dofile();
	}
	if (count == 0)
		bug("W", "No files found", name);
}

dofile()
/*
 * Process the current file (open on infd)
 */
{
	register char	*lp;
	register char	*namep;
	char		*skipuntil();
	char		*skipbl();
	char		*match();

	/*
	 * First, find the .title to get the index name
	 */
	if (cflag) {
		for (;;) {
			if ((lp = skipuntil("#ifdef")) == NULL)
				return;
			while (*lp && *lp > ' ')
				*lp++;
			lp = skipbl(lp);
			if (match(lp, "DOCUMENTATION"))
				break;
		}
	}
	if ((lp = skipuntil((cflag) ? "title" : ".title")) == NULL)
		return;
	/*
	 * Skip over .title, skip to the entry name, copy it to namebuf[].
	 */
	namep = namebuf;
	while (*lp != EOS && *lp > ' ')
		lp++;
	lp = skipbl(lp);
	while (*lp > ' ' && namep < &namebuf[NAMESIZE-1])
		*namep++ = *lp++;
	*namep = EOS;
	/*
	 * Now, (if not cflag) read the file to ;+, then to "; Index"
	 * If "; Internal" seen and it's not for wizards, quit.
	 */
	if (!cflag) {
		if ((lp = skipuntil(";+")) == NULL)
			return;
		while (getline(infd)) {
			if (line[0] != ';' || line[1] == '-')
				return;
			if (!wizard && match(line, "; internal"))
				return;
			if (match(line, "; index")) {
				lp = skipbl(&line[7]);
				printf("%s\t%s\n", namebuf, lp);
			}
		}
	}
	else {
		while (getline(infd)) {
			if (match(line, "#endif"))
				return;
			if (match(line, "index")) {
				lp = skipbl(&line[5]);
				printf("%s\t%s\n", namebuf, lp);
			}
		}
	}
}

char *
skipuntil(matcharg)
char		*matcharg;	/* what to look for			*/
/*
 * Read infd until eof or a match with matcharg.
 * Return a pointer to the first byte of matcharg.  Return NULL on eof
 * or upon scanning ";-".
 */
{
	register char	*lp;
	char		*skipbl();
	char		*match();

	while (getline(infd)) {
		if (line[0] == ';' && line[1] == '-')
			return(NULL);
		lp = skipbl(line);
		if (!match(lp, matcharg))
			continue;
		return(lp);
	}
	return(NULL);
}

char *
skipbl(text)
register char	*text;
/*
 * Skip over blanks and tabs, return -> first non-blank or trailing null
 */
{
	register char	c;

	while ((c = *text) != EOS && c <= ' ')
		text++;
	return(text);
}

char *
match(text, lookfor)
register char	*text;
register char	*lookfor;
/*
 * If the beginning of text matches lookfor (ignoring case)
 * return TRUE, lookfor must always be in lowercase.
 */
{
	register int	tc;		/* Text character		*/

	while (*lookfor != EOS) {
		if ((tc = *text++) != *lookfor && (tc + 040) != *lookfor)
			return(FALSE);
		lookfor++;
	}
	return(TRUE);
}

getline(fd)
FILE		*fd;
/*
 * Read the next line from fd into line[].  Return FALSE at eof
 * getline() strips trailing blanks from the line.
 */
{
	register char	*lp;

	if (fgetss(line, sizeof line, fd) == NULL)
		return(FALSE);
	for (lp = &line[strlen(line)]; lp > line && lp[-1] <= ' ';)
		lp--;
	*lp = 0;
	return(TRUE);
}

bug(severity, mess, arg)
char		*severity;
char		*mess;
char		*arg;
/*
 * Error messages
 */
{
	fprintf(stderr, "%cGETKWK-%s-%s",
		(*severity == 'W') ? '%' : '?', severity, mess);
	if (arg != NULL)
		fprintf(stderr, ": \"%s\"", arg);
	fprintf(stderr, "\n");
	if (*severity != 'W')
		error("?GETKWK-F-Can't continue");
}
