[comp.sources.unix] v24i055: Library for Purdue University Computing Center tools, Part01/02

rsalz@uunet.uu.net (Rich Salz) (03/20/91)

Submitted-by: Kevin Braunsdorf <ksb@cc.purdue.edu>
Posting-number: Volume 24, Issue 55
Archive-name: pucc-lib/part01

This two part archive contains the libraries that most of the PUCC
(Purdue University Computing Center) tools require to compile.  You'll
need to build these to compile any of the nifty stuff that follows.
Included are:
	libopt(3l)	- process a command line
	maketd(1l)	- edit a makefile to update transitive dependencies
	srtunq(3l)	- in memory string sorting
-- ksb


#!/bin/sh
# This is pucc-1a, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 11/29/1990 15:57 UTC by ksb@cc.purdue.edu (Kevin Braunsdorf)
# Source directory /ksb/c.s.u-2
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   1321 -rw-r--r-- INSTALL.01
#  21424 -r--r--r-- maketd/maketd.c
#   8481 -r--r--r-- maketd/maketd.1l
#   4616 -r--r--r-- libopt/libopt.3l
#   5705 -r--r--r-- libsrtunq/libsrtunq.3l
#   4905 -r--r--r-- maketd/abrv.c
#   2814 -r--r--r-- libopt/envopt.c
#   4235 -r--r--r-- maketd/main.c
#   3826 -r--r--r-- maketd/M4.patch
#   1360 -rw-r--r-- libopt/Makefile
#    619 -rw-r--r-- libopt/README
#   1999 -r--r--r-- libopt/getopt.c
#   2793 -rw-r--r-- libsrtunq/Makefile
#   2530 -r--r--r-- libsrtunq/srtdel.c
#   2731 -rw-r--r-- maketd/Makefile
#   2359 -r--r--r-- maketd/errors.c
#   1514 -r--r--r-- libsrtunq/srtapply.c
#   1452 -r--r--r-- libsrtunq/srtgets.c
#   1723 -r--r--r-- libsrtunq/srtin.c
#   1226 -r--r--r-- libsrtunq/srtdtree.c
#   1240 -r--r--r-- libsrtunq/srtmem.c
#   1278 -rw-r--r-- maketd/machine.h
#   1148 -r--r--r-- libopt/getopt.h
#   1067 -r--r--r-- libsrtunq/srtfree.c
#   1067 -r--r--r-- libsrtunq/srtgti.c
#   1011 -r--r--r-- libsrtunq/srtinit.c
#   1144 -r--r--r-- maketd/maketd.h
#    819 -r--r--r-- libsrtunq/srtunq.h
#    621 -r--r--r-- maketd/abrv.h
#    519 -r--r--r-- libopt/getarg.c
#    490 -r--r--r-- libsrtunq/README
#    471 -r--r--r-- maketd/GCC.awk
#    310 -r--r--r-- maketd/errors.h
#    256 -r--r--r-- libopt/rescan.c
#    245 -r--r--r-- maketd/README
#    216 -r--r--r-- maketd/main.h
#
# ============= INSTALL.01 ==============
if test -f 'INSTALL.01' -a X"$1" != X"-c"; then
	echo 'x - skipping INSTALL.01 (File already exists)'
else
echo 'x - extracting INSTALL.01 (Text)'
sed 's/^X//' << 'Purdue' > 'INSTALL.01' &&
Contains:
X	libopt(3l)	- process a command line
X	maketd(1l)	- edit a makefile to update transitive dependencies
X	srtunq(3l)	- in memory string sorting
X
X
Notes on depends:
X	- libopt.a and libsrtunq.a need not be installed, but it
X	  would make life easier if you want other PUCC tools.
X
X	- maketd needs libopt.a and libsrtunq.a to compile
X
X
To install these tools:
X
0\ read the manual pages, see if you want any of them
X
1\ vi libopt/Makefile and set DEFS if we do not have strchr/strrchr
X	vi libopt/Makefile
X
2\ build libopt and libsrtunq, ranlib them if you have to
X	(cd libopt && make)
X	(cd libsrtunq && make)
X
X	ranlib libopt/libopt.a libsrtunq/libsrtunq.a
X
3\ decide where to install all this stuff, change the destinations in
X   the Makefiles {BIN,LIB,ETC,HEADER}
X	vi */Makefile
X	
4\ install libopt and libsrtunq if you decided to
X	su
X	(cd libopt && make install)
X	(cd libsrtunq && make install)
X	exit
X
4\ build maketd
X	(cd maketd && make)
X
5\ install maketd
X	su root
X	(cd maketd && make install)
X	exit
X
6\ clean up the dirs
X	(cd libopt && make clean)
X	(cd libsrtunq && make clean)
X	(cd maketd && make clean)
X
7\ if you have mkcat install any manual pages you want
X	su root
X	mkcat -v maketd/maketd.1l libopt/libopt.3l libsrtunq/srtunq.3l
X	exit
X
kayessbee
--
Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb
Purdue
chmod 0644 INSTALL.01 ||
echo 'restore of INSTALL.01 failed'
Wc_c="`wc -c < 'INSTALL.01'`"
test 1321 -eq "$Wc_c" ||
	echo 'INSTALL.01: original size 1321, current size' "$Wc_c"
fi
# ============= maketd/maketd.c ==============
if test ! -d 'maketd'; then
    echo 'x - creating directory maketd'
    mkdir 'maketd'
fi
if test -f 'maketd/maketd.c' -a X"$1" != X"-c"; then
	echo 'x - skipping maketd/maketd.c (File already exists)'
else
echo 'x - extracting maketd/maketd.c (Text)'
sed 's/^X//' << 'Purdue' > 'maketd/maketd.c' &&
/*
X * the real brains are in this file
X */
#include "machine.h"
X
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <ctype.h>
#if defined(SYSV)
#include <string.h>
#include "bsd.h"
#else
#include <strings.h>
#endif
X
extern FILE *popen();
extern int errno;
extern char *sys_errlist[];
#define strerror(Me) (sys_errlist[Me])
X
#include "main.h"
#include "maketd.h"
#include "srtunq.h"
#include "abrv.h"
#include "errors.h"
X
#if !defined(F_OK)
#define F_OK	0
#endif
X
/*
X * if your cpp doesn't grok -M use something like this...
X *	"/lib/cpp -E %I %F |sed -n 's@^# *[0-9]* *"\\(.*\\)"@%f: \\1@p'"
X * to format the lines into `file.o: file.d'
X * Otherwise use:
X *	"/lib/cpp -M %I %F",
X * the line for gcc's cpp is not so short, but it can be done.
X * (See GCC.awk for a description, and some clues.)
X */
X
char *preprocessors[] = {
#if defined(CPP)
X	CPP,
#else
#if defined(CPP_M)
X	"/lib/cpp -M %I %F",
#else
X	/* once for C, once for expand, once for sed */
X	"/lib/cpp -E %I %F |sed -n 's@^# *[0-9]* *\"\\\\(.*\\\\)\"@%f: \\\\1@p'",
#endif
#endif
X
#if defined(M4)
X	M4
#else
X	"/usr/bin/m4 -M %F"
#endif
};
X
char
X	*pchBackup;	/* the backup file name				*/
X
FILE	*makefp;	/* file pointer to the dest makefile		*/
int
X	backedup = FALSE; /* is the backup file is present		*/
X
static struct srtent
X	incld;
static DependInfo
X	FileInfo = {	/* our template for all files			*/
X		0, 0,
X		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
X		(DependInfo *)0
X	};
static FILE
X	*fpBackup,	/* file pointer to the backup file		*/
X	*fpPipe;	/* pipe file pointer for preproc		*/
static char
X	sbInc[] =
#if defined(INCLD)
X		INCLD,
#else
X		"/usr/include",
#endif
X	deplin[] =
X		"# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT\n",
X	searchdep[] =
X		"# DO NOT DELETE THIS LINE",
X	trailer[] =
X		"\n# *** Do not add anything here - It will go away. ***\n";
X
/* SetPP
X * This routine changes the preprocessor to be used on the next filename.
X * It has one argument (i) that is the number of the preprocessor to use
X *	0 == /lib/cpp
X *	1 == /usr/bin/m4
X */
int
SetPP(i)
int i;
{
X	FileInfo.preprocessor = preprocessors[i];
}
X
/* user filter
X * This routine allows the user to scan anything he can code a program
X * (script?) to produce `file.z: dep.x' lines on std for, like
X *
X * /lib/cpp -E %I %F | sed -n 's/^# *[0-9]* *"\(.*\)"/%f: \1/p'
X */
int
UserFilter(pcFilter)
char *pcFilter;
{
X	if ((char *)0 == pcFilter || '\000' != pcFilter[0])
X		FileInfo.preprocessor = pcFilter;
X	else
X		FileInfo.preprocessor = (char *)0;
}
X
X
/* SetSuffix
X * This routine changes the suffix to add to the next file that is processed.
X * If binary is set, it goes into binary mode. The only way to unset binary
X * mode is to set a new suffix.
X */
int
SetSuffix(option, suffix)
int option;
char *suffix;
{
X	if ('b' == option) {
X		FileInfo.binarydep = 1;
X	} else {
X		FileInfo.suffix	= STRSAVE(suffix);
X		FileInfo.binarydep = 0;
X	}
}
X
/* SetLocalO
X * Hey, what more can I say, this sets the local-o and the non-local o
X * options in the file structure.
X */
int
SetLocalO(i)
int i;
{
X	FileInfo.localo = i;
}
X
/* SetCPPFlags
X * This function sets the CPP flags. It is given two arguments, the
X * option (CDIU), and the argument given. If the option is C, it
X * clears the previous CPP flags. Otherwise, it just catentiates a
X * string of options.
X */
int
SetCPPFlags(option, argument)
int option;
char *argument;
{
X	register char *pch = NULL;
X	register unsigned len;
X	static char sbOption[4] = " -?";
X	extern char *malloc(), *realloc();
X
X	if ('C' == option) {
X		if (NULL != FileInfo.cppflags) {
X			free(FileInfo.cppflags);
X			FileInfo.cppflags = NULL;
X		}
X		return ;
X	} 
X	pch = FileInfo.cppflags;
X	len = strlen(argument)+4;
X	if (NULL == pch) {
X		FileInfo.cppflags = malloc(len);
X		FileInfo.cppflags[0] = '\000';
X	} else {
X		len += strlen(pch);
X		FileInfo.cppflags = realloc(FileInfo.cppflags, len);
X	}
X	sbOption[2] = option;
X	strcat(FileInfo.cppflags, sbOption);
X	strcat(FileInfo.cppflags, argument);
X
X	/* insert -I files includes into abbreviation list
X	 */
X	if ('I' == option) {
X		/* if we end in '/' take it off */
X		pch = strrchr(argument, '/');
X		if ((char *)0 != pch && '\000' == pch[1]) 
X			pch[1] = '\000';
X		if (NULL == srtin(&abrv, hincl(argument), lngsrt)) {
X			OutOfMemory();
X		}
X		if (FALSE != verbose)
X			fprintf(stderr, "%s: inserted abbr %s\n", progname, argument);
X	}
}
X
/* SetObjPath
X *	tell processing part about non-local dot-o's
X */
int
SetObjPath(destdir)
char *destdir;
{
X	FileInfo.destdir = '.' == FileInfo.destdir[0] && '\000' == FileInfo.destdir ? NULL : STRSAVE(destdir);
}
X
/* SetTargetName
X * we don't ned to string save it because only one file can use it, and
X * it will string save it.
X */
int
SetTargetName(basename)
char *basename;
{
X	FileInfo.basename = basename;
}
X
int
FileArgs(filename)
char *filename;
{
X	register DependInfo *pDI = &FileInfo;
X
X	while (NULL != pDI->next)
X		pDI = pDI->next;
X	pDI->next = (DependInfo *)malloc((unsigned)sizeof(DependInfo));
X	pDI = pDI->next;
X	pDI->localo = FileInfo.localo;
X	pDI->binarydep = FileInfo.binarydep;
X	pDI->filename = STRSAVE(filename);
X	pDI->inlib = inlib;
X	
X	if (FileInfo.preprocessor)
X		pDI->preprocessor = FileInfo.preprocessor;
X	else
X		pDI->preprocessor = preprocessors[0];
X
X	pDI->explicit = explicit;	/* from main.c parser	*/
X
X	pDI->cppflags = pDI->destdir = pDI->suffix = pDI->basename = (char *)0;
X	if (NULL != FileInfo.cppflags)
X		pDI->cppflags = STRSAVE(FileInfo.cppflags);
X	if (NULL != FileInfo.destdir)
X		pDI->destdir = STRSAVE(FileInfo.destdir);
X	if (NULL != FileInfo.suffix)
X		pDI->suffix = STRSAVE(FileInfo.suffix);
X	if (NULL != FileInfo.basename)
X		pDI->basename = STRSAVE(FileInfo.basename);
X	pDI->next = NULL;
X	FileInfo.basename = NULL;
}
X
/* BackUp
X *	Back up the makefile into the backup makefile.
X */
void
BackUp()
{
X	register unsigned len;
X	if (NULL == exten) {
X		exten = STRSAVE(".bak");
X	}
X	
X	len = strlen(makename)+strlen(exten)+2;
X	pchBackup = malloc(len);
X	strcpy(pchBackup, makename);
X	if ('.' != *exten) {
X		strcat(pchBackup, ".");
X	}
X	strcat(pchBackup, exten);
X
X	/* Remove the old backup file */
X	if (0 == access(pchBackup, F_OK) && 0 != unlink(pchBackup)) {
X		fprintf(stderr, "%s: unlink: %s: %s\n", progname, pchBackup, strerror(errno));
X		exit(3);
X	}
X
X	/* Move current makefile to backup file */
X	if (0 != link(makename, pchBackup)) {
X		fprintf(stderr, "%s: link: %s to %s: %s\n", progname, makename, pchBackup, strerror(errno));
X		exit(4);
X	}
X
X	backedup = TRUE;
X	if (0 != unlink(makename)) {
X		fprintf(stderr, "%s: unlink: %s: %s\n", progname, makename, strerror(errno));
X		RestoreFiles();
X	}
}
X
/* DestName
X * Given the info about the file, figure out what the destination name
X * should be on the dependancy line.
X */
char *
DestName(file)
DependInfo *file;
{
X	static char buf[BUFSIZE];
X	register char *pch = NULL;
X
X	/* find a prefix:
X	 * the -o (destdir) flag has precedence over the -n or -l flags;
X	 * then the non-local o option;
X	 * else we don't want one
X	 */
X	if (NULL != file->destdir) {
X		strcpy(buf, file->destdir);
X		pch = strrchr(buf, '\000');
X		if ('/' != *--pch) {
X			*++pch = '/';
X			*++pch = '\000';
X		}
X	} else if (FALSE != file->localo) {
X		strcpy(buf, file->filename);
X		if (NULL != (pch = strrchr(buf, '/'))) {
X			pch[1] = '\000';
X		}
X	} else {
X		buf[0] = '\000';
X	}
X
X	/* find a basename
X	 * when they supplied the basename, trust them
X	 * else strip off any leading pathname to the file and save it in buf
X	 *	(but get rid of the suffix too)
X	 * thus buf contains only the basename
X	 */
X	if (NULL != file->basename) {
X		strcat(buf, file->basename);
X	} else {
X		if (NULL == (pch = strrchr(file->filename, '/'))) {
X			pch = file->filename;
X		} else {
X			++pch;
X		}
X		strcat(buf, pch);
X		if (NULL != (pch = strrchr(buf, '.'))) {
X			*pch = '\000';
X		}
X	}
X
X	/* if this is not a binary dependancy, add a suffix to it
X	 */
X	if (1 != file->binarydep) {
X		if (NULL != file->suffix) {
X			strcat(buf, file->suffix);
X		} else {
X			strcat(buf, ".o");
X		}
X	}
X
X	return buf;
}
X
/* DoReplace
X * This is a routine that goes through the current dependancies (if any)
X * and spits out the ones that are NOT being replaced. If the shortening
X * of include file names is turned off, it will spit out the currently
X * defined vars, otherwise, it lets them be rebuilt.
X */
void
DoReplace()
{
X	register DependInfo *pDI;
X	register int found = FALSE, cont = FALSE;
X	register char *fname;
X	register int len;
X	auto char buf[BUFSIZE];
X
X	while (NULL != fgets(buf, BUFSIZE, fpBackup)) {
X		if (FALSE != cont) {
X			if (FALSE == found) {
X				fputs(buf, makefp);
X			}
X			cont = '\\' == buf[strlen(buf) - 2] ? TRUE : FALSE;
X			continue;
X		}
X
X		found = cont = FALSE;
X		if ('\n' == buf[0]) {
X			continue;
X		}
X
X		/* If we are not shortening the include file names on this
X		 * replacement, we at least have to spit out the old
X		 * abbreviations
X		 */
X		if (isupper(buf[0]) && '=' == buf[1]) {
X			fname = strrchr(buf, '\n');
X			if ((char *)0 == fname) {
X				fprintf(stderr, "%s: internal error or line too long\n", progname);
X				RestoreFiles();
X			}
X			*fname = '\000';
X			if (NULL == srtin(&abrv, hincl(buf+2), lngsrt)) {
X				OutOfMemory();
X			}
X			if (FALSE != verbose)
X				fprintf(stderr, "%s: inserted abbr %s\n", progname, buf+2);
X		} else {
X			for (pDI = FileInfo.next; NULL != pDI; pDI = pDI->next) {
X				fname = DestName(pDI);
X				len = strlen(fname);
X				found = (':' == buf[len] &&
X				   0 == strncmp(fname, buf, len))? TRUE: FALSE;
X				if (found)
X					break;
X			}
X			if (FALSE == found && '#' != buf[0]) {
X				fputc('\n', makefp);
X				fputs(buf, makefp);
X			}
X			cont = '\\' == buf[strlen(buf) - 2] ? TRUE : FALSE;
X		}
X	}
}
X
/*
X * output a user rule expanded						(ksb)
X */
void
expand(src, pDI, fpTo)
char *src;
DependInfo *pDI;
FILE *fpTo;
{
X	register int i, num;
X	register char chLast = '\n';
X	register char *pc;
X	auto char acf[1025];
X	auto char acF[1025];
X	auto char
X		*tp,	/* the / in %o/%t%s		*/
X		*sp,	/* the . in %s, or a "\000"	*/
X		*Tp,	/* the / in %o/%t%s		*/
X		*Sp;	/* the . in %s, or a "\000"	*/
X
X	pc = strrchr(pDI->filename, '/');
X	if ((char *)0 == pc) {
X		strcpy(acf, ".");
X		strcpy(acF, ".");
X	} else {
X		*pc = '\000';
X		strcpy(acf, pDI->filename);
X		strcpy(acF, pDI->filename);
X		*pc = '/';
X	}
X	if ((char *)0 != pDI->destdir) {
X		strcpy(acf, pDI->destdir);
X	}
X
X	tp = strrchr(acf, '\000');
X	tp[0] =  '/';
X	Tp = strrchr(acF, '\000');
X	Tp[0] =  '/';
X	if ((char *)0 == pc) {
X		strcpy(tp+1, pDI->filename);
X		strcpy(Tp+1, pDI->filename);
X	} else {
X		strcpy(tp+1, pc+1);
X		strcpy(Tp+1, pc+1);
X	}
X	if ((char *)0 != pDI->basename) {
X		strcpy(tp+1, pDI->basename);
X	}
X
X	sp = strrchr(tp, '.');
X	if ((char *)0 == sp)
X		sp = strrchr(tp, '\000');
X	Sp = strrchr(Tp, '.');
X
X	if ((char *)0 != pDI->suffix) {
X		strcpy(sp, pDI->suffix);
X	} else if (1 == pDI->binarydep) {
X		sp[0] = '\000';
X	} else {
X		strcpy(sp, ".o");
X	}
X
X	while (*src) {
X		if ('\n' == chLast) {
X			if (makefp == fpTo)	/* ZZZ hack */
X				putc('\t', fpTo);
X		}
X		chLast = *src;
X		switch (*src) {
X		case '%':
X			/* %f: %F
X			 * %o/%t.%s: %O/%T.%S
X			 * %%
X			 */
X			switch (*++src) {
X			/* target */
X			case 'o':	/* directory part	*/
X				*tp = '\000';
X				fputs(acf, fpTo);
X				*tp = '/';
X				break;
X
X			case 't':
X				if ('\000' == *sp) {
X					fputs(tp+1, fpTo);
X				} else {
X					i = *sp;
X					*sp = '\000';
X					fputs(tp+1, fpTo);
X					*sp = i;
X				}
X				break;
X
X			case 's':
X				fputs(sp, fpTo);
X				break;
X
X			case 'f':
X				fputs(acf, fpTo);
X				break;
X
X			/* source */
X			case 'O':
X				*Tp = '\000';
X				fputs(acF, fpTo);
X				*Tp = '/';
X				break;
X
X			case 'T':
X				if ((char *)0 == Sp) {
X					fputs(Tp+1, fpTo);
X				} else {
X					*Sp = '\000';
X					fputs(Tp+1, fpTo);
X					*Sp = '.';
X				}
X				break;
X
X			case 'S':
X				if ((char *)0 != Sp)
X					fputs(Sp, fpTo);
X				break;
X
X			case 'F':
X				fputs(acF, fpTo);
X				break;
X
X			/* global */
X			case 'L':
X				if ((char *)0 != pDI->inlib)
X					fputs(pDI->inlib, fpTo);
X				break;
X
X			case 'I':
X				if ((char *)0 != pDI->cppflags)
X					fputs(pDI->cppflags, fpTo);
X				break;
X
X			case '%':
X			default:	/* unrecognized chars are copied thru */
X				fputc(*src, fpTo);
X				break;
X			}
X			src++;
X			break;
X
X		case '\\':
X			switch (*++src) {
X			case '\n':	/* how would this happen? */
X				++src;
X				break;
X			case 'a':
X				fputc('\007', fpTo);
X				++src;
X				break;
X			case 'n':	/* newline */
X				fputc('\n', fpTo);
X				chLast = '\n';
X				++src;
X				break;
X			case 't':
X				fputc('\t', fpTo);
X				++src;
X				break;
X			case 'b':
X				fputc('\b', fpTo);
X				++src;
X				break;
X			case 'r':
X				fputc('\r', fpTo);
X				++src;
X				break;
X			case 'f':
X				fputc('\f', fpTo);
X				++src;
X				break;
X			case 'v':
X				fputc('\013', fpTo);
X				++src;
X				break;
X			case '\\':
X				++src;
X			case '\000':
X				fputc('\\', fpTo);
X				break;
X
X			case '0': case '1': case '2': case '3':
X			case '4': case '5': case '6': case '7':
X				num = *src++ - '0';
X				for (i = 0; i < 2; i++) {
X					if (! isdigit(*src)) {
X						break;
X					}
X					num <<= 3;
X					num += *src++ - '0';
X				}
X				fputc(num, fpTo);
X				chLast = num;
X				break;
X			case '8': case '9':
X				/* 8 & 9 are bogus octals,
X				 * cc makes them literals
X				 */
X				/*fallthrough*/
X			default:
X				fputc(*src++, fpTo);
X				break;
X			}
X			break;
X		default:
X			fputc(*src, fpTo);
X			src++;
X			break;
X		}
X	}
X
X	if ('\n' != chLast)
X		fputc('\n', fpTo);
}
X
/* generate the depend info for a given file
X */
void
DoDepend(file)
DependInfo *file;
{
X	register int lineend, i;
X	register char *p, *q, *name;
X	auto int complen;
X	auto char ppbuf[BUFSIZE], buf[BUFSIZE];
X	auto char acFile[1025];
X	auto FILE *fpCmd;
X
X	/* compute the dest name and save it, we want this one for a while
X	 */
X	name = DestName(file);
X	name = STRSAVE(name);
X	if (FALSE != verbose)
X		fprintf(stderr, "%s: working on %s\n", progname, name);
X
X	/* with the help of a little conditional compilation
X	 * set up the command string
X	 */
X	mktemp(strcpy(acFile, "/tmp/mtdXXXXXX"));
X	if (NULL == (fpCmd = fopen(acFile, "w"))) {
X		fprintf(stderr, "%s: fopen: %s: %s\n", progname, acFile, strerror(errno));
X		RestoreFiles();
X	}
X	expand(file->preprocessor, file, fpCmd);
X	fclose(fpCmd);
X
X	if (FALSE != verbose) {
X		fprintf(stderr, "%s: shell command: (in %s)\n", progname, acFile);
X		sprintf(buf, "cat %s", acFile);
X		system(buf);
X	}
X
X	(void)sprintf(buf, "sh <%s", acFile);
X	if (NULL == (fpPipe = popen(buf, "r"))) {
X		fprintf(stderr, "%s: popen: %s: %s\n", progname, buf, strerror(errno));
X		RestoreFiles();
X	}
X
X	/* Start with a fresh list of dependancy files */
X	srtfree(&incld);
X
X	while (NULL != fgets(ppbuf, BUFSIZE, fpPipe)) {
X		if (NULL == (p = strchr(ppbuf, ':'))) {
X			fprintf(stderr, "%s: preprocessor output missing colon\n", progname);
X			RestoreFiles();
X		}
X		++p;	/* Get past colon */
X		if (' ' != *p++) {
X			fprintf(stderr, "%s: preprocessor output missing space\n", progname);
X			RestoreFiles();
X		}
X
X		/* Make pathname pretty */
X		p = hincl(p);
X
X		/* Replace newline with a null */
X		if (NULL != (q = strchr(p, '\n')))
X			*q = '\000';
X
X		/* If all dependancies are NOT to be made, skip over
X		 * the basic include path
X		 */
X		if (FALSE == alldep && 0 == strncmp(sbInc, p, sizeof(sbInc)-1))
X			continue;
X
X		/* Insert it into our list */
X		if (NULL == srtin(&incld, p, strcmp)) {
X			OutOfMemory();
X		}
X		if (FALSE != verbose)
X			fprintf(stderr, "%s: inserted %s\n", progname, p);
X	}
#if 0
X	while (NULL != fgets(ppbuf, BUFSIZE, fpPipe)) {
X		/* An include statement starts with a # */
X		if ('#' != ppbuf[0])
X			continue;
X		
X		/* eat #ident lines (mostly a sysv thing) */
X		p = ppbuf;
X		do {
X			++p;
X		} while (' ' == *p || '\t' == *p);
X		if (! isdigit(*p)) {
X			continue;
X		}
X
X		/* Find the first double quote and go one past it */
X		if (NULL == (p = strchr(p, '"')))
X			continue;
X		++p;
X
X		/* Make the path pretty */
X		p = hincl(p);
X
X		if (NULL != (q = strchr(p, '"')))
X			*q = '\000';
X
X		/* If all dependancies are NOT to be made, skip over
X		 * the basic include path
X		 */
X		if (FALSE == alldep && 0 == strncmp(sbInc, p, sizeof(sbInc)-1))
X			continue;
X
X		/* Insert it into our list */
X		if (NULL == srtin(&incld, p, strcmp))
X			OutOfMemory();
X		if (FALSE != verbose)
X			fprintf(stderr, "%s: inserted %s\n", progname, p);
X	}
#endif /* need to look at raw cpp output */
X
X	/* Initialize so we can use srtgets */
X	srtgti(&incld);
X
X	lineend = MAXCOL+1;		/* Force a newline in the output */
X	/* Write out the entries */
X	while (NULL != (p = srtgets(&incld))) {
X		/* set i = found index or MXABR */
X		if (FALSE != shortincl && MXABR != (i = findabr(p))) {
X			p += abrvlen[i];
X			if ('/' != p[0] && '\000' != p[0]) {
X				complen = 4;
X			} else {
X				complen = 2;
X			}
X		} else {
X			complen = 0;
X		}
X
X		complen += strlen(p);
X		if (MAXCOL <= lineend + complen) {
X			if ((char *)0 != name) {
X				/* 2 for the colon and space */
X				lineend = strlen(name) + 2;
X				if ((char *)0 != file->inlib) {
X					/* + parens  and lib name */
X					lineend += 2 + strlen(file->inlib);
X					fprintf(makefp, "\n%s(%s): ", file->inlib, name);
X				} else {
X					fprintf(makefp, "\n%s: ", name);
X				}
X				free(name);
X				name = (char *) 0;
X				if (MAXCOL <= lineend + complen) {
X					lineend = 8;
X					fprintf(makefp, "\\\n\t");
X				}
X			} else {
X				lineend = 8;
X				fprintf(makefp, " \\\n\t");
X			}
X		} else {
X			++lineend;
X			fputc(' ', makefp);
X		}
X
X		if (FALSE != shortincl && MXABR != i) {
X			if ('/' != p[0] && '\000' != p[0]) {
X				fprintf(makefp, "${%c}", 'A' + i);
X			} else {
X				fprintf(makefp, "$%c", 'A' + i);
X			}
X		}
X		fputs(p, makefp);
X		lineend += complen;
X	}
X	fputc('\n', makefp);
X	pclose(fpPipe);
X	(void)unlink(acFile);
X	if ((char *)0 != file->explicit) {
X		expand(file->explicit, file, makefp);
X	}
}
X
/* DoInit
X * Initialize the signal catching routines
X * and abreviation list
X */
int
DoInit()
{
X	init_sigs();
X	srtinit(&abrv);
}
X
/* MakeTD
X * This part is the actual work-horse of the program. All of the options
X * have been processed at this point, and all we have to do is interpret
X * their meanings
X */
int
MakeTD()
{
X	register DependInfo *pDI;
X	register int fCont;
X	register char *pchTemp;
X	auto char sbLine[BUFSIZE];
X	auto struct stat stOld;
X
X	/* Find out which makefile is to be used. First, if the user
X	 * specifies a makefile, use that. If he doesn't, check and
X	 * see if 'makefile' exists. Finally, if that doesn't check
X	 * out, see if 'Makefile' exists.
X	 */
X	if (NULL == makename) {
X		makename = STRSAVE("makefile");
X		if (0 != access(makename, F_OK)) {
X			makename[0] = 'M';
X			if (0 != access(makename, F_OK)) {
X				fprintf(stderr, "%s: cannot find makefile\n", progname);
X				exit(1);
X			}
X		}
X	} else {
X		if (0 != access(makename, F_OK)) {
X			fprintf(stderr, "%s: access: %s: %s\n", progname, makename, strerror(errno));
X			exit(1);
X		}
X	}
X
X	/* Now backup the makefile to a backup file and unlink the current one
X	 */
X	if (FALSE == use_stdout) {
X		BackUp();
X	} else {
X		pchBackup = makename;
X	}
X	stat(pchBackup, &stOld);
X
X	/* Now open the destination makefile, copy over all of the current
X	 * makefile up to the '# DO NOT DELETE THIS LINE' line (or the
X	 * end-of-file, whichever comes first), and then continue with
X	 * processing.
X	 */
X	if (NULL == (fpBackup = fopen(pchBackup, "r"))) {
X		fprintf(stderr, "%s: fopen: %s: %s\n", progname, pchBackup, strerror(errno));
X		RestoreFiles();
X	}
X
X	if (FALSE != use_stdout) {
X		makefp = stdout;
X	} else if (NULL == (makefp = fopen(makename, "w"))) {
X		fprintf(stderr, "%s fopen: %s: %s\n", progname, makename, strerror(errno));
X		RestoreFiles();
X	} else {
X		/* chmod the Makefile */
X		if (-1 == chmod(makename, (stOld.st_mode & 07777))) {
X			fprintf(stderr, "%s: chmod: %s: %s\n", progname, makename, strerror(errno));
X			RestoreFiles();
X		}
X	}
X
X	/* clever use of continuations used to hose us over
X	 */
X	fCont = FALSE;
X	while (NULL != fgets(sbLine, BUFSIZE, fpBackup) && (FALSE != fCont ||
X		0 != strncmp(searchdep, sbLine, strlen(searchdep)))) {
X		pchTemp = strrchr(sbLine, '\\');
X		if ((char *)0 != pchTemp && '\n' == pchTemp[1]) {
X			fCont = TRUE;
X		} else {
X			if (FALSE == fCont)
X				srchincl(sbLine);
X
X			fCont = FALSE;
X		}
X		if (FALSE == use_stdout)
X			(void)fputs(sbLine, makefp);
X	}
X
X	/* If we need the header put in, do it now
X	 */
X	if (FALSE == use_stdout || FALSE != force_head) {
X		(void)fputs(deplin, makefp);
X	}
X
X	/* Put out the abbreviations table
X	 */
X	if (FALSE != alldep) {
X		sprintf(sbLine, "%s/sys", sbInc);
X		if (FALSE != verbose)
X			fprintf(stderr, "%s: all depends inserts %s and %s\n", progname, sbInc, sbLine);
X		if (NULL == srtin(&abrv, hincl(sbInc), lngsrt) ||
X		    NULL == srtin(&abrv, hincl(sbLine), lngsrt)) {
X			OutOfMemory();
X		}
X	}
X
X	if (FALSE != shortincl) {
X		abrvsetup();
X	}
X
X	/* Check to see if we have to replace the files instead of just
X	 * recreating all dependancies
X	 */
X	if (FALSE != replace && FALSE == use_stdout) {
X		DoReplace();
X	}
X
X	/* Now, after we have done everything that needs to be done except
X	 * putting out the dependancies for the list of files we have, lets
X	 * go ahead and do that! First we have to initialize our sorted
X	 * list.
X	 */
X	srtinit(&incld);	/* Initialize sorted list of files */
X	for (pDI = FileInfo.next ; NULL != pDI; pDI = pDI->next) {
X		DoDepend(pDI);
X	}
X
X	/* Put out the trailer if needed
X	 */
X	if (FALSE == use_stdout || FALSE != force_head) {
X		fputs(trailer, makefp);
X	}
X
#ifdef DEL_BACKUP
X	if (FALSE != backedup && 0 != unlink(backupfn)) {
X		fprintf(stderr, "%s: unlink: %s: %s\n", progname, pchBackup, strerror(errno));
X		exit(1);
X	}
#endif /* DEL_BACKUP */
X	exit(0);
}
Purdue
chmod 0444 maketd/maketd.c ||
echo 'restore of maketd/maketd.c failed'
Wc_c="`wc -c < 'maketd/maketd.c'`"
test 21424 -eq "$Wc_c" ||
	echo 'maketd/maketd.c: original size 21424, current size' "$Wc_c"
fi
# ============= maketd/maketd.1l ==============
if test -f 'maketd/maketd.1l' -a X"$1" != X"-c"; then
	echo 'x - skipping maketd/maketd.1l (File already exists)'
else
echo 'x - extracting maketd/maketd.1l (Text)'
sed 's/^X//' << 'Purdue' > 'maketd/maketd.1l' &&
.\" by Kevin Braunsdorf
.\" $Laser: tbl %f | ltroff -man
.TH MAKETD 1L PUCC
.SH NAME
maketd \- edit a makefile to update transitive dependencies
.SH SYNOPSIS
\fBmaketd\fP [\-\fB4CabcdfhlnrvVx\fP] [\-\fBD\fP \fIdefine\fP] [\-\fBL\fP \fIlib.a\fP] [\-\fBI\fP \fIincludedir\fP] [\-\fBU\fP \fIundefine\fP] [\-\fBj\fP \fIextender\fP] [\-\fBm\fP \fImakefile\fP] [\-\fBo\fP \fIdir\fP] [\-\fBs\fP \fIsuffix\fP] [\-\fBt\fP \fItarget\fP] [\fBfiles\fP]
.SH DESCRIPTION
.B Maketd
computes dependencies for targets that are introduced through the
C preprocessor's (cpp) \fI#include\fP directive.
The development of this program resulted from
.IR make ( 1 )'s
inability to recognize transitive dependencies.  For example,
given the following makefile fragment:
.sp 1
X	xx.o: xx.c e.h
.sp 1
X	e.h: struct.h /usr/include/local/const.h
.sp 1
\fIMake\fP will not recognize the target xx.o's dependency on struct.h.
\fIMaketd\fP generates lines like:
.sp 1
X	xx.o: xx.c e.h struct.h $L/const.h
.sp 1
Thus making the target xx.o not only dependent on all files that it includes,
but also recursively on all files that the included files include.
This is achieved by passing the source through the C preprocessor
(\fI/bin/cc\fP \-\fIM\fP).
.PP
The directories used in the search for include files
are identical to the ones used by the C compiler because the
C preprocessor is used.  This also means that 
.IR #define 's, 
.IR #ifdef 's, 
etc., are evaluated.
It is necessary to recompute the dependencies when any source has been changed.
The generated dependencies will be inserted after a line of the form 
\*(lq# DO NOT DELETE...\*(rq (which will be inserted if \fBmaketd\fP
finds the end of file).
Everything after this line may be deleted or changed as \fBmaketd\fP edits
the \fImakefile\fP (the portion of the makefile before this line is only
examined for context).
If no such line exists, a line of the expected form will be emitted,
followed by the dependencies.
.PP
By default \fBmaketd\fP will search for the \fImakefile\fP
to be edited in the same way \fImake\fP does; that is by first checking
for the existence of \*(lqmakefile\*(rq, then \*(lqMakefile\*(rq.
The \-\fBm\fP and \-\fBd\fP options override this default action (below).
Before it is edited, \fImakefile\fP will be saved in
\*(lq\fImakefile\fP.\fIextend\fP\*(rq
(overwriting any existing file with the same name).
This \fIextender\fP on the old version of \fImakefile\fP may
be changed by using the \-\fBj\fP option (below).
.SH OPTIONS
.PP
Options and arguments may be intermixed on the command line to modify
\fBmaketd\fP's behavior on a per file basis.
.TP
.BI \-4
Use 
.IR m4 ( 1 )
as the preprocessor rather than 
.IR cc ( 1 ) .  
This requires that modifications have been made to m4 and that 
this program be compiled with CPP_M defined.  Use \*(lqmaketd \-h\*(rq 
to check this.
.TP
.BI \-a
Normally, dependencies on files in \*(lq/usr/include\*(rq are
not included.  This option also includes dependencies on those files.
This option should always be used for system level makefiles.
.TP
.BI \-b
Generate dependencies for binaries rather than object files.
This is equivalent to specifying a null suffix:  the \*(lq.o\*(rq 
is stripped from the target.
.TP
.BI \-c
Use cc to generate dependencies (rather than m4).  This is the default.
.TP
.BI \-d
Dependencies are written to standard output instead of editing a makefile.
The standard header and trailer, \*(lq# DO NOT DELETE...\*(rq are not printed.
.\".TP
.\".BI \-e rule
.\"The given \fIrule\fP is ouptut under each of the following \fIfile\fP's
.\"dependency lists.
.\"For \fIprintf\fP-like percent (%) escapes are expanded to allow the
.\"user to customize the rule.
.\".sp 1
.\".RS
.\".TS
.\"l l l.
.\"escape  expands
.\"%	a percent
.\"F	the source file
.\"I	the \fIcpp\fP flags for this file
.\"O	the source dir
.\"S	the source suffix
.\"L	the library containing this file
.\"T	the source basename
.\"f	the full target file
.\"o	the target dir (set by \-\fBo\fP)
.\"s	the target suffix (set by \-\fBs\fP)
.\"t	the target base name (set by \-\fBt\fP)
.\".TE
.\".RE
.TP
.BI \-f
Force printing of header and trailer.
Normally these are suppressed when the output file is the standard output.
.TP
.BI \-h
Only output a usage summary.
.TP
.BI \-j extender
Specify an extension for the backup makefile, rather than the default 
\*(lqbak\*(rq extender.
.TP
.BI \-l
Turn off the nonlocal object option, and make all targets local.
.TP
.BI \-m makefile
Instead of editing \*(lqmakefile\*(rq, \fImakefile\fP is edited.
.TP
.BI \-n
Generate nonlocal object dependency paths.
These paths will match the source paths given.
.TP
.BI \-o dir
Generate nonlocal object dependencies in the specified \fIdir\fP.
This option generates dependencies of the form
.sp 1
X	\fIdir\fP/a.o: a.c
.sp 1
which is useful for makefiles that produce the objects in
a separate subdirectory.
The name of the directory must not be empty (see \-\fBl\fP above).
.TP
.BI \-r
Replace the dependencies for the target(s) mentioned on the command line.
Do not alter any other dependencies that may have been in \fImakefile\fP.
This option is of limited use and unlimited misuse: beware.
.TP
.BI \-s suffix
Supply a suffix for the target.  The \fIsuffix\fP should
start with a \*(lq.\*(rq.
The target file name should have a suffix of some sort that
is delimited by a \*(lq.\*(rq that is replaced by this suffix.
.TP
.BI \-t target
Supply a new basename for the target rather than using the basename of the
source file.
.TP
.BI \-v
Be verbose.
Extra output is directed to the standard error channel.
.TP
.BI \-V
Show which version of \fImaketd\fP is running.
.TP
.BI \-x
Do not shorten include files.
The pathnames \*(lq/usr/include\*(rq and \*(lq/usr/include/sys\*(rq
along with any pathnames specified with the \-I options, are abbreviated.
Unused uppercase single letters are defined in \fImakefile\fP and used to
compress pathnames.
.TP
.BI \-C
Cancel all previous cpp flags (\-\fBD\fP, \-\fBI\fP, and \-\fBU\fP)
and begin a new list.  This is useful for generating
dependencies for more than one product with only one \fBmaketd\fP call.
.TP
.BI \-D define
Specify a cpp (C preprocessor) definition.  See
.IR cc ( 1 ).
for a complete description.
.\".TP
.\".BI \-E
.\"Cancel an explicit \fIrule\fP given by \-\fBe\fP.
.\".TP
.\".BI \-F gen-dep
.\"The \fIgen-dep\fP shell command is expanded as a \-e \fIrule\fP would be
.\"and given to the shell.  The resulting output must look like the
.\"output of \fIcpp\fP \fI\-M\fP, that is contain only lines of the form:
.\".sp 1
.\"	\fItarget\fP\fB: \fP\fIdep\fP
.\".sp 1
.\"which should list of all the \fIdeps\fP on which \fItarget\fP
.\"depends one per line.
.TP
.BI \-I includedir
Specify a directory for cpp to search for include files.
See
.IR cc ( 1 )
for a complete description.
Note that \fIincludedir\fP is subject to abbreviation unless \-\fBx\fP is
given.
.TP
.BI \-L lib.a
This option produces a dependency that tells \fImake\fP(1) that the
target is part of \fIlib.a\fP.
.TP
.BI \-U name
Remove any initial definition of the (C preprocessor) variable
.IR name .
.SH EXAMPLES
A typical application in a makefile might look like:
.sp 1
.RS
.nf
L=/usr/include/local
INCLUDE=  \-I$L \-I../h
CDEFS=	\-DPUCC \-DBSD4_2
CFLAGS=	${DEFS} ${INCLUDE}
X
SRC=	a.c b.c c.c
HDR=	a.h b.h c.h
X
\&. . .
depend: ${SRC} ${HDR}
X	maketd \-a ${CDEFS} ${INCLUDE} ${SRC}
X
# DO NOT DELETE THIS LINE \- maketd DEPENDS ON IT
X
a.o: a.c a.h b.h c.h $L/goop.h
X
b.o: b.c b.h $L/goop.h
X
c.o: c.c c.h
X
# *** Do not add anything here \- It will go away. ***
.fi
.RE
.sp 1
.SH BUGS
.PP
If a single letter macro name is used but never defined (in the makefile)
\fBmaketd\fP might still use it for an abbreviation name.  This should not
effect the makefile as all the dependencies and the redefinition of the
macro will follow the users last usage of it.  This happens in DYNIX makefiles
that use \*(lqP\*(rq to indicate that parallel compilation should be used.
We suggest that Makefiles which use this trick put a
.sp 1
X	P=
.sp 1
in the Makefile (above the all target) to keep \fImaketd\fP from using
the macro \*(lqP\*(rq; the command line definition of P="&" will override
the Makefile's definition.
.PP
Some more path compression could be done.
.SH AUTHORS
Stephan Bechtolsheim (a shell script), Purdue CS
.br
Stephen Uitti (a C version), Purdue CC
.br
Craig Norborg (m4 modifications), Purdue CC
.br
Kevin Braunsdorf (intermix options), Purdue CC
.SH SEE ALSO
make(1), cc(1), m4(1)
Purdue
chmod 0444 maketd/maketd.1l ||
echo 'restore of maketd/maketd.1l failed'
Wc_c="`wc -c < 'maketd/maketd.1l'`"
test 8481 -eq "$Wc_c" ||
	echo 'maketd/maketd.1l: original size 8481, current size' "$Wc_c"
fi
# ============= libopt/libopt.3l ==============
if test ! -d 'libopt'; then
    echo 'x - creating directory libopt'
    mkdir 'libopt'
fi
if test -f 'libopt/libopt.3l' -a X"$1" != X"-c"; then
	echo 'x - skipping libopt/libopt.3l (File already exists)'
else
echo 'x - extracting libopt/libopt.3l (Text)'
sed 's/^X//' << 'Purdue' > 'libopt/libopt.3l' &&
.\" Copyright (c) 1988 Regents of the University of California.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms are permitted
.\" provided that the above copyright notice and this paragraph are
.\" duplicated in all such forms and that any documentation,
.\" advertising materials, and other materials related to such
.\" distribution and use acknowledge that the software was developed
.\" by the University of California, Berkeley.  The name of the
.\" University may not be used to endorse or promote products derived
.\" from this software without specific prior written permission.
.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
.\"	@(#)getopt.3	6.8 (Berkeley) 7/9/88
.\"
.TH LIBOPT 3L "June 1990"
.UC 6
.SH NAME
envopt, getopt, getarg, optind, optarg, optsil, rescan \- process a command line
.SH SYNOPSIS
#include \*(lqgetopt.h\*(rq
.sp
.ft B
int getopt(argc, argv, optstring)
.br
int argc;
.br
char **argv;
.br
char *optstring;
.sp
int getarg(argc, argv)
.br
int argc;
.br
char **argv;
.sp
envopt(toscan)
.br
char *toscan;
.sp
extern char *optarg;
.br
extern int optind;
.br
extern int optsil;
.sp
int rescan()
.ft
.sp 1
cc -I/usr/include/local -o tool ... -lopt
.SH DESCRIPTION
.I Getopt
returns the next option letter in
.I argv
that matches a letter in
.IR optstring .
.I Optstring
is a string of recognized option letters;
if a letter is followed by a colon, the option is expected to have
an argument that may or may not be separated from it by white space.
.I Optarg
is set to point to the start of the option argument on return from
.IR getopt .
.PP
.I Getopt
places in
.I optind
the
.I argv
index of the next argument to be processed.
Because
.I optind
is external, it is normally initialized to zero automatically
before the first call to 
.IR getopt .
.PP
When all options have been processed (i.e., up to the first
non-option argument),
.I getopt
returns
.BR EOF .
The special option
.B \-\-
may be used to delimit the end of the options;
.B EOF
will be returned, and
.B \-\-
will be skipped.
.PP
After
.IR getopt
has returned an EOF
.IR getarg
may be called to extract the remaining arguments from the command line
one at a time.
.PP
If another scan of the argument list is required the function
.IR rescan ()
may be called to reset the index into the option list.
.PP
If an environment variable is read as options to the program its
value must be passed to
.IR envopt
before the first call the
.IR getopt .
.SH DIAGNOSTICS
.I Getopt
prints an error message on
.I stderr
and returns a question mark
.RB ( ? )
when it encounters an option letter not included in
.IR optstring .
Setting \fIopterr\fP to a zero will disable this error message.
.SH EXAMPLE
The following code fragment shows how one might process the arguments
for a command that can take the mutually exclusive options
.B a
and
.BR b ,
and the options
.B f
and
.BR o ,
both of which require arguments:
.PP
.RS
.nf
#include <stdio.h>
#include "getopt.h"
X
main(argc, argv)
int argc;
char **argv;
{
X	int c;
X	extern int optind;
X	extern char *optarg;
X	extern char *getenv();
X	char *scanme;
X	\&.
X	\&.
X	\&.
X	/* option environment variable to read */
X	if (0 != (scanme = getenv("TRY")))
X		envopt(scanme);
X	\&.
X	\&.
X	\&.
X	while ((c = getopt(argc, argv, "abf:o:")) != EOF)
X		switch (c) {
X		case `a':
X			if (bflg)
X				errflg++;
X			else
X				aflg++;
X			break;
X		case `b':
X			if (aflg)
X				errflg++;
X			else
X				bproc();
X			break;
X		case `f':
X			ifile = optarg;
X			break;
X		case `o':
X			ofile = optarg;
X			break;
X		case `?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg) {
X		fprintf(stderr, "Usage: ...");
X		exit(2);
X	}
X	while (EOF != getarg(argc, argv))) {
X		process(optarg);
X		\&.
X		\&.
X		\&.
X	}
X	\&.
X	\&.
X	\&.
}
.RE
.SH HISTORY
Written by Henry Spencer, working from a Bell Labs manual page.
Modified by Keith Bostic to behave more like the System V version.
Modified by Kevin Braunsdorf to read environment variables.
.SH BUGS
``-'' may be specified as an option letter, however it should never have
an argument associated with it.  This allows getopt to be used with
programs that think that ``-'' means standard input.
.PP
Option arguments are allowed to begin with ``\-'';
this is reasonable but reduces the amount of error checking possible.
.PP
.I Getopt
is quite flexible but the obvious price must be paid:  there is much
it could do that it doesn't, like
checking mutually exclusive options, checking type of
option arguments, etc.
Purdue
chmod 0444 libopt/libopt.3l ||
echo 'restore of libopt/libopt.3l failed'
Wc_c="`wc -c < 'libopt/libopt.3l'`"
test 4616 -eq "$Wc_c" ||
	echo 'libopt/libopt.3l: original size 4616, current size' "$Wc_c"
fi
# ============= libsrtunq/libsrtunq.3l ==============
if test ! -d 'libsrtunq'; then
    echo 'x - creating directory libsrtunq'
    mkdir 'libsrtunq'
fi
if test -f 'libsrtunq/libsrtunq.3l' -a X"$1" != X"-c"; then
	echo 'x - skipping libsrtunq/libsrtunq.3l (File already exists)'
else
echo 'x - extracting libsrtunq/libsrtunq.3l (Text)'
sed 's/^X//' << 'Purdue' > 'libsrtunq/libsrtunq.3l' &&
.\"	# my routine titler -- accepts the lines of the title as args
.de TM
.in .5i
.B \\$1
.br
.B \\$2
.br
.B \\$3
.br
.B \\$4
.br
.B \\$5
.br
.B \\$6
.br
.B \\$7
.br
.B \\$8
.br
.B \\$9
.br
.ft R
.in +.5i
..
'
'
'
.TH SRTUNQ 3L PUCC
.SH NAME
srtdel, srtinit, srtin, srtmem, srtgti, srtgets, srtapply, srtfree, srtdtree \- in memory
string sorting
.SH SYNOPSIS
.B #include <stdio.h>
.br
.B #include \*(lqsrtunq.h\*(rq
.sp
cc \-I/usr/include/local file.c
.B \-lsrtunq
.SH DESCRIPTION
.I Libsrtunq.a
is used to extract unique items from a possibly long list,
where items are likely to be replicated numerously.
The list of unique items must be small enough to
fit in memory, but the number of repetitions is possibly high.
.PP
The caller has control over the database through the use of a
\fBSRTTABLE\fP variable.  The subroutines provide for data entry and
retrieval, memory allocation and deallocation.
.SH ROUTINES
.TM "typedef  struct ... SRTTABLE;"
Users will define one variable of this type to hold the root of
each sorted list they wish to keep.
Most routines in this library require the address of such
a variable as their first argument.
X
.TM "typedef  struct ... SRTENTRY;"
Strings are kept in a structure of this type internally.
The user should not depend on the internal details of this type.
X
.TM "void" "srtinit(tbl)" "SRTTABLE *tbl;"
This subroutine must be called to initialize the database tag \fItbl\fP
before any data are entered or retrieved from that tree.
It assumes that the tag has not been used
to store a tree, and therefore does not attempt to free any such data.
X
.TM "char *" "srtin(tbl, string, compare)" "SRTTABLE *tbl;" "char *string;" "int (*compare)();"
The existing data tree is searched for the string,
if it is found then a pointer to that string is returned.
Otherwise, space is allocated for the string and pointer structure via
\fImalloc\fP(3).
The string is copied to this new space which is linked into the tree
and a pointer to the new string is returned.
If space cannot be obtained, the operation is aborted and NULL is returned
(the data structure remains consistent, but the string is not added).
The strings are compared and sorted with the subroutine pointed to by
\fIcompare\fP.  This subroutine takes two string pointers as arguments.
It returns zero if the strings are the same,
less than zero if the first string should precede the second, and
greater than zero if the second string should precede the first.
Use \fIstrcmp\fP(3) if simple lexicographical ordering is desired.
It is confusing at best if different \fIcompare\fP functions are used
when inserting strings into a given tree.
X
.TM "char *" "srtmem(tbl, string, compare)" "SRTTABLE *tbl;" "char *string;" "int (*compare)();"
Return the database entry for \fIstring\fP if it is already a member of
the table, else NULL.
X
.TM "int" "srtdel(tbl, string, compare)" "SRTTABLE *tbl;" "char *string;" "int (*compare)();"
The existing data tree is searched for the string,
if it is found then it is deleted and a nonzero value is returned.
Otherwise, 0 is returned.
X
.TM "void" "srtgti(tbl);" "SRTTABLE *tbl;"
This subroutine initializes the database tag pointed to by \fItbl\fP
so that a tree traversal can be made via \fIsrtgets\fP.
X
.TM "char *" "srtgets(tbl);" "SRTTABLE *tbl;"
This subroutine extracts the next string from the data structure.
The strings are returned in the order specified by the \fIcompare\fP
function when they were inserted with \fIsrtin\fP.
When the list is exhausted, NULL is returned.
X
.TM "int" "srtapply(tbl, func)" "SRTTABLE *tbl;" "int (*func)();"
This subroutine applies the \fIfunc\fP to each string in the tree (order
determined by \fIcompare\fP when they were inserted) until the func returns
non-zero, or there are no more strings.  If the \fIfunc\fP returned
non-zero then that value is returned, otherwise 0 is returned.
X
.TM "void" "srtfree(tbl)" "SRTTABLE *tbl;"
This subroutine deletes a database, and re-initializes the
database tag.
It assumes that the database tag was initialized at one time via \fIsrtinit\fP
(other routines will probably also have been called).
The space formally occupied by string data and pointer structures is
deallocated via \fIfree\fP(3).
X
.TM "void" "srtdtree(tbl, ent)" "SRTTABLE *tbl;" "SRTENTRY *ent;"
This subroutine recursively deletes a database subtree.
The space formally occupied by the string data and pointer structures is
deallocated via \fIfree\fP(3).
This routine is most likely only of use internally.
.SH EXAMPLE
.nf
#include <stdio.h>
main()
{
X	extern int strcmp();
X	SRTTABLE tree;
X	char buf[80], *p;
X	int i;
X
X	/* init the tree */
X	srtinit(&tree);
X
X	/* add some strings */
X	while (NULL != fgets(buf, 80, stdin))  /* want the \en terminator */
X		if (NULL == (p = srtin(&tree, buf, strcmp)))
X			printf("out of memory!\en");
X	
X	/* init tree for srtgets */
X	srtgti(&tree);
X
X	/* print out the strings with srtapply and printf -- can't have
X	 * a legal printf % escape in the strings! */
X	(void) srtapply(&tree, printf);
X
X	/* use srtgets to print the strings out this time -- keep count */
X	for (i = 0; NULL != (p = srtgets(&tree)); ++i)
X		printf("string %2d is: %s\en", i, p);
X	printf("there were %d strings\en", i);
X
X	/* free the database */
X	srtfree(&tree);
}
.fi
.SH DIAGNOSTICS
There are no messages printed by these routines.
Catchable errors are returned as NULL.
Compiled in errors such as the use of strings that
are not null terminated tend to result in core files.
.SH FILES
/usr/local/lib/libsrtunq.a
.br
/usr/include/local/srtunq.h
.SH SEE ALSO
malloc(3), free(3), qsort(3), strcmp(3)
.SH AUTHOR
Stephen Uitti, PUCC
.SH BUGS
The structure names and typedefs seem confused.  The typedefs make more sense.
Purdue
chmod 0444 libsrtunq/libsrtunq.3l ||
echo 'restore of libsrtunq/libsrtunq.3l failed'
Wc_c="`wc -c < 'libsrtunq/libsrtunq.3l'`"
test 5705 -eq "$Wc_c" ||
	echo 'libsrtunq/libsrtunq.3l: original size 5705, current size' "$Wc_c"
fi
# ============= maketd/abrv.c ==============
if test -f 'maketd/abrv.c' -a X"$1" != X"-c"; then
	echo 'x - skipping maketd/abrv.c (File already exists)'
else
echo 'x - extracting maketd/abrv.c (Text)'
sed 's/^X//' << 'Purdue' > 'maketd/abrv.c' &&
/*
X * abbreviation related routines 
X * Written & hacked by Stephen Uitti, PUCC staff
X * 1985 maketd is copyright (C) Purdue University, 1985 
X *
X * Permission is hereby given for its free reproduction and modification for
X * non-commercial purposes, provided that this notice and all embedded
X * copyright notices be retained. Commercial organizations may give away
X * copies as part of their systems provided that they do so without charge,
X * and that they acknowledge the source of the software. 
X */
X
#include "machine.h"
X
#ifdef pdp11
#include <sys/types.h>
#endif
#include <stdio.h>
#include <ctype.h>
X
extern char *strrchr();
X
#include "srtunq.h"
#include "abrv.h"
#include "main.h"
#include "maketd.h"
#include "errors.h"
X
#define SPACE	'\040'		/* ascii for space			*/
X
struct srtent abrv;		/* include file abrevs			*/
char   *abrvtbl[MXABR];		/* translation table strings		*/
int     abrvlen[MXABR];		/* string lengths (for speed)		*/
X
/*
X * lngsrt - string length more important than lexicographical compare. 
X * return > 0 if b is longer than a. 
X * return < 0 if b is shorter than a. 
X * if a & b are * the same length, return strcmp(a, b), which means that 
X * 0 is returned if the strings are THE SAME, 
X * if b > a: return > 0 if b < a: return < 0 
X */
int
lngsrt(a, b)
char   *a, *b;
{
X	register int i;
X
X	if (0 != (i = strlen(b) - strlen(a)))
X		return i;
X	return strcmp(a, b);
}
X
/*
X * hincl - include header optimizer: 
X * Compress multiple leading /'s to just one. Remove leading "./". 
X * Doesn't change date, just returns pointer into beginning of path. 
X */
char *
hincl(p)
register char *p;
{
X	if ('/' == *p) {		/* compress multiple leading /'s */
X		while ('/' == p[1])	/* to just one */
X			++p;
X	}
X	if (0 == strncmp("./", p, 2)) {
X		p += 2;			/* leading "./" can confuse make */
X		while ('/' == *p)	/* don't change ".//a.h" to "/a.h" */
X			++p;
X	}
X	return p;
}
X
/* makeabrv
X * add an abreviation to the table
X */
void
makeabrv(pos, p)
int pos;
char *p;
{
X	register int len;
X
X	if (NULL != abrvtbl[pos]) {
X		fprintf(stderr, "%s: macro letter '%c' redefined\n", progname, 'A' + pos);
X		return;
X	}
X	abrvtbl[pos] = p;
X	if (3 > (len = strlen(p))) {	/* don't use, but hold letter	*/
X		len = 0;
X	}
X	abrvlen[pos] = len;
X	if (FALSE != verbose) {
X		fprintf(stderr, "%s: %c='%s'\n", progname, pos + 'A', p);
X	}
}
X
/*
X * srchincl - search line for make defines of A-Z Put entries into abrvtbl. 
X */
void
srchincl(p)
register char *p;
{
X	register char letter, *q, *r;
X	register unsigned i;
X	extern char *malloc();
X
X	if (FALSE == shortincl || '\000' == *p) {
X		return;
X	}
X
X	while (isspace(*p))		/* ignore white space */
X		++p;
X	letter = *p++;
X	if (! isupper(letter)) {
X		return;
X	}
X
X	while (isspace(*p))
X		++p;
X	if ('=' != *p++) {
X		return;
X	}
X
X	while (isspace(*p))
X		++p;
X	i = strlen(p);
X
X	if (NULL == (q = r = malloc(i+1))) {
X		OutOfMemory();
X	}
X
X	while ('\000' != *p && '#' != *p && ! isspace(*p))
X		*q++ = *p++;
X	*q = '\000';
X
X	makeabrv(letter-'A', r);
X	if (FALSE != verbose)
X		fprintf(stderr, "%s: use macro %c as %s\n", progname, letter, r);
}
X
/*
X * abrvsetup - set up abrev table, spit out the abrevs.	 
X * Use any A-Z definitions found in Makefile, no duplicates.  
X * look at each sting we have noticed as a prefix
X *  (make sure is non-NULL, not too small)
X * macro them
X * output table
X */
void
abrvsetup()
{
X	register int i;			/* scan tables			*/
X	register char *p;		/* surrent abrev. canidate	*/
X	register char *q;		/* temp string			*/
X	register int slot;		/* slot search point		*/
X
X	srtgti(&abrv);
X	while (NULL != (p = srtgets(&abrv))) {
X		if (FALSE != verbose)
X			fprintf(stderr, "%s: examine %s, ", progname, p);
X		slot = -1;
X		for (i = 0; i < MXABR; ++i) {
X			q = abrvtbl[i];
X			if (NULL == q) {
X				if (slot == -1)
X					slot = i;
X				continue;
X			}
X			if (0 == strcmp(p, q))
X				break;
X		}
X
X		/* already in table or no more room in table
X		 */
X		if (MXABR != i || slot == -1) {
X			if (FALSE != verbose)
X				fprintf(stderr, "rejected\n");
X			continue;
X		}
X
X		/* slot is a known free slot,
X		 * but we'd rather be mnemonic
X		 */
X		q = strrchr(p, '/');
X		if ((char *)0 != q && isalpha(q[1])) {
X			i = q[1] - (islower(q[1]) ? 'a' : 'A');
X			if (NULL == abrvtbl[i])
X				slot = i;
X		}
X		if (FALSE != verbose)
X			fprintf(stderr, "accepted as %c\n", slot+'A');
X		makeabrv(slot, p);
X		fprintf(makefp, "%c=%s\n", slot+'A', p);
X	}
}
X
/*
X * findabr - find an abbreviation in abrvtbl for string p (if any). 
X * if multiple abbreations work, use longest. (ie: /usr/include &
X * /usr/include/sys; use /usr/include/sys) if found, return index else: MXABR
X */
int
findabr(p)
register char *p;		/* string pointer			*/
{
X	register int i;		/* for index				*/
X	register int j;		/* found index				*/
X
X	for (i = 0, j = MXABR; i < MXABR; ++i) {
X		if (0 == abrvlen[i])
X			continue;
X		if (0 == strncmp(abrvtbl[i], p, abrvlen[i]))
X			if (MXABR == j || abrvlen[i] > abrvlen[j])
X				j = i;
X	}
X	return j;
}
Purdue
chmod 0444 maketd/abrv.c ||
echo 'restore of maketd/abrv.c failed'
Wc_c="`wc -c < 'maketd/abrv.c'`"
test 4905 -eq "$Wc_c" ||
	echo 'maketd/abrv.c: original size 4905, current size' "$Wc_c"
fi
# ============= libopt/envopt.c ==============
if test -f 'libopt/envopt.c' -a X"$1" != X"-c"; then
	echo 'x - skipping libopt/envopt.c (File already exists)'
else
echo 'x - extracting libopt/envopt.c (Text)'
sed 's/^X//' << 'Purdue' > 'libopt/envopt.c' &&
/*
X * take options from an envirionment variable
X */
#include <stdio.h>
#include "getopt.h"
X
extern char **_eargv;
extern int _eargc;
X
/* breakargs - break a string into a string vector for execv.
X * Note, when done with the vector, mearly "free" the vector.
X * Written by Stephen Uitti, PUCC, Nov '85 for the new version
X * of "popen" - "nshpopen", that doesn't use a shell.
X * (used here for the as filters, a newer option).
X *
X * breakargs is copyright (C) Purdue University, 1985
X *
X * put in a fix for cmds lines with "string string" in them
X * Mon Aug 25 13:34:27 EST 1986 (ksb)
X *
X * Permission is hereby given for its free reproduction and
X * modification for non-commercial purposes, provided that this
X * notice and all embedded copyright notices be retained.
X * Commercial organisations may give away copies as part of their
X * systems provided that they do so without charge, and that they
X * acknowledge the source of the software.
X */
#ifdef BSD2_9
#include <sys/types.h>
#endif
#include <stdio.h>			/* for nothing, really */
#define SPC '\040'			/* ascii space */
X
char *
mynext(pch)
register char *pch;
{
X	register int fQuote;
X
X	for (fQuote = 0; (*pch != '\000' && *pch != SPC && *pch != '\t')||fQuote; ++pch) {
X		if ('\\' == *pch) {
X			continue;
X		}
X		switch (fQuote) {
X		default:
X		case 0:
X			if ('"' == *pch) {
X				fQuote = 1;
X			} else if ('\'' == *pch) {
X				fQuote = 2;
X			}
X			break;
X		case 1:
X			if ('"' == *pch)
X				fQuote = 0;
X			break;
X		case 2:
X			if ('\'' == *pch)
X				fQuote = 0;
X			break;
X		}
X	}
X	return pch;
}
X
/*
X * given an envirionment variable insert it in the option list (exploded)
X */
int
envopt(cmd)
char *cmd;
{
X	register char *p;		/* tmp				*/
X	register char **v;		/* vector of commands returned	*/
X	register unsigned sum;		/* bytes for malloc		*/
X	register int i;			/* number of args		*/
X	register char *s;		/* save old position		*/
X	register char hold;		/* hold a character for a second*/
X	extern char *malloc(), *strcpy();
X
X	p = cmd;
X	while (*p == SPC || *p == '\t')
X		p++;
X	cmd = p;			/* no leading spaces		*/
X	sum = sizeof(char *);
X	i = 1;
X	while (*p != '\0') {		/* space for argv[];		*/
X		++i;
X		s = p;
X		p = mynext(p);
X		sum += sizeof(char *) + 1 + (unsigned)(p - s);
X		while (*p == SPC || *p == '\t')
X			p++;
X	}
X	++i;
X	/* vector starts at v, copy of string follows NULL pointer */
X	v = (char **)malloc(sum+sizeof(char *));
X	if (v == NULL)
X		return 0;
X	p = (char *)v + i * sizeof(char *); /* after NULL pointer */
X	i = 0;				/* word count, vector index */
X	v[i++] = "";
X	while (*cmd != '\0') {
X		v[i++] = p;
X		s = cmd;
X		cmd = mynext(cmd);
X		hold = *cmd;
X		*cmd = '\000';
X		strcpy(p, s);
X		p += strlen(p);
X		++p;
X		if ('\000' != hold)
X			*cmd++ = hold;
X		while (*cmd == SPC || *cmd == '\t')
X			++cmd;
X	}
X	v[i] = (char *)NULL;
X	_eargv = v;
X	_eargc = i;
X	return i;
}
Purdue
chmod 0444 libopt/envopt.c ||
echo 'restore of libopt/envopt.c failed'
Wc_c="`wc -c < 'libopt/envopt.c'`"
test 2814 -eq "$Wc_c" ||
	echo 'libopt/envopt.c: original size 2814, current size' "$Wc_c"
fi
true || echo 'restore of maketd/main.c failed'
echo End of part 1, continue with part 2
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.