v08i056: Ease, a language for writing sendmail.cf files, Part04/04

sources-request at mirror.UUCP sources-request at mirror.UUCP
Thu Feb 12 06:35:40 AEST 1987


Submitted by: ksb at j.cc.purdue.edu
Mod.sources: Volume 8, Issue 56
Archive-name: ease/Part04

[  A couple of things to note, here.  First, watch out for the horribly
   long "usage" string -- I bet some compilers can't handle it (it should
   probably be an array of text lines, anyhow).  Second, it would be
   great if someone converted this program to use getopt(3), and sent the
   changes on to the maintainers...  --r$  ]

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	maketd
mkdir maketd
chdir maketd
cat << \SHAR_EOF > Makefile
# For a VAX
DEFS=	-DBSD4_2
LDFLAGS=

# For a PDP 11/70
# DEFS= -DBSD2_9
# LDFLAGS= -i

INCLUDE=	
CFLAGS=	-O ${DEFS} ${INCLUDE}
DEST=	/usr/new/bin

SRC=	abrv.c maketd.c misc.c nshpopen.c breakargs.c srtunq.c
HDR=	maketd.h abrv.h nshpopen.h srtunq.h
OBJ=	maketd.o abrv.o misc.o nshpopen.o breakargs.o srtunq.o

all: maketd

maketd:	${OBJ}
	${CC} ${LDFLAGS} ${OBJ} -o maketd

clean: FRC
	rm -f ${OBJ} maketd \#* *.bak core a.out

depend:	source
	maketd -a ${DEFS} ${INCLUDE} ${SRC}

install: maketd
	install -s -m 0751 -o binary -g system maketd ${DEST}

lint: source
	lint -hpx ${SRC}

print: source
	lpr -p Makefile ${HDR} ${SRC}

shar: source
	shar Makefile ${SRC} ${HDR} Manual

source: Makefile ${SRC} ${HDR}

spotless: clean
	rcsclean ${SRC} ${HDR} Makefile

${SRC} ${HDR}:
	co $@

FRC:

# a clever way to save a few more characters
I=/usr/include/
S=/usr/include/sys/

# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT

abrv.o: $Ictype.h $Istdio.h abrv.c abrv.h maketd.h srtunq.h

maketd.o: $Ictype.h $Imachine/machparam.h $Isignal.h $Istdio.h $Sdir.h \
	$Sfile.h $Sparam.h $Stypes.h abrv.h maketd.c maketd.h nshpopen.h \
	srtunq.h

misc.o: $Istdio.h $Ssignal.h maketd.h misc.c

nshpopen.o: $Isignal.h $Istdio.h nshpopen.c

breakargs.o: $Istdio.h breakargs.c

srtunq.o: $Istdio.h $Stypes.h srtunq.c srtunq.h

# *** Do not add anything here - It will go away. ***
SHAR_EOF
if test 1371 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 1371 characters)'
fi
mkdir Manual
chdir Manual
cat << \SHAR_EOF > maketd.1l
.TH MAKETD 1L "11 November 1985"
.if n \{.de Q
"\\$1"\\$2
.\}
.if t \{.de Q
``\\$1''\\$2
.\}
..
.SH NAME
maketd \- make transitive dependencies
.SH SYNOPSIS
.B maketd
[
.I option(s)
] 
.I file(s)
.SH DESCRIPTION
.I Maketd
computes dependencies for makefiles from sources introduced through
include files.
It generates lines like
.Q "xx.o: e.h struct.h ../h/const.h ..." .
It makes xx.o not only dependent on all files it includes,
but also recursively on all files other files include.
This is achieved by passing the source through the C preprocessor.
.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 `#define's, `#ifdef's, etc. are evaluated.
It may therefore be necessary to recompute the dependencies if
any source has been changed, including the associated Makefile.
.PP
A typical application in a Makefile goes as follows:
.nf

	INCL= \-I../include  \-I../h
	CFLAGS= \-DPUCC \-DBSD4_2 ${INCL}
	SRC= a.c b.c c.c

	maketd: ${SRC}
		maketd \-a ${CFLAGS} ${SRC}

	# DO NOT DELETE THIS LINE \- make depend DEPENDS ON IT

.fi
The generated dependencies will be inserted after the `# DO NOT DELETE...'
line.
Everything after this line will go away through the editing
process of the Makefile.
If no such line exists, a line of the expected form will be emitted,
followed by the dependencies.
The default filename for the Makefile is `makefile'.
If `makefile' does not exist, `Makefile' is used.
The \-m and \-d options override this default action.
Before it is edited, the Makefile will be saved in `Makefile.bak',
overwritting any existing `Makefile.bak'.
.PP
Several options apply.
If an option takes any arguments, all arguments follow the option
directly, with no spaces.
If spaces are required inside an argument to an option, then
quotes must be used to prevent the shell from breaking up the
argument.
.TP
.BI \-a
Normally, dependencies on files in `/usr/include' are
not included \- this option also includes dependencies on those files.
.TP
.BI \-b
Generate dependencies for binaries rather than object files.
This is equivelent to specifying a null suffix.
The `.o' is stripped from the filename.
.TP
.BI \-d
Instead of editing the Makefile, dependencies are written to standard
output.
The standard header and trailer, `# DO NOT...' are not emitted.
.TP
.BI \-f
Force printing of header and trailer.
Normally, these are suppresed when the output file is the standard
output.
.TP
.BI \-h
Print a set of oneline descriptions to the terminal and exit.
.TP
.BI \-m file
Instead of editing `makefile' or `Makefile', the file named
.I file
is edited.
.TP
.BI \-nonlocalo
Generate dependency paths that match the source paths given.
.TP
.BI \-o directory
Normally dependencies are of the form
.Q "a.o: ....." .
This option generates dependencies of the form
.Q "\fIdirectory\fP/a.o:...." ,
which is useful for Makefiles which store the objects in
a separate subdirectory.
The name of the directory must not be empty.
.TP
.BI \-r
Causes the dependencies for a single source file to be generated and
replaced in the edited Makefile.
.TP
.BI \-s suffix
Supply a suffix for the target.
The suffix should start with a `.'.
The target file name should have a suffix of some sort that
is delimited by a `.' that is replaced by this suffix.
.TP
.BI \-t target
Supply a new basename for the target.
.TP
.BI \-x
Don't shorten include files.
The default action is to replace various strings with abbreviations.
The Makefile is scanned to see which single letter uppercase
variables are set.
These definitions are remembered.
The pathnames `/usr/include' and `/usr/include/sys', along with any
pathnames specified with \-I options are also used in abbreviations.
Unused uppercase single letters are defined, printed to the Makefile,
and used.
.TP
.BI \-v
Be verbose.
Extra output is directed to
.I stderr.
.TP
.BI \-I...
Specify a directory to search for include files.
This option is passed to /lib/cpp, and thus behaves identically to
the same option to `cc'.
.TP
.BI \-D...
Specify a definition.
This option is passed to /lib/cpp, and thus behaves identically to
the same option to `cc'.
.TP
.BI \-U....
Specify that a variable that should not be defined.
This option is passed to /lib/cpp, and thus behaves identically to
the same option to `cc'.
.IR cc (1).
.SH "AUTHOR"
Stephan v. Bechtolsheim (the shell script) (Purdue CS)
.br
Stephen Uitti (the C version) (PUCC)
.SH "SEE ALSO"
make(1), cc(1)
SHAR_EOF
if test 4509 -ne "`wc -c maketd.1l`"
then
echo shar: error transmitting maketd.1l '(should have been 4509 characters)'
fi
cat << \SHAR_EOF > nshpopen.3l
.TH NSHPOPEN 3 "local"
.SH NAME
nshpopen, nshpclose \- initiate I/O to/from a process
.SH SYNOPSIS
.B #include <stdio.h>
.PP
.SM
.B FILE
.B *nshpopen(command, type)
.br
.B char *command, *type;
.PP
.B nshpclose(stream)
.br
.SM
.B FILE
.B *stream;
.SH DESCRIPTION
The arguments to 
.I nshpopen
are pointers to null-terminated strings containing respectively
a shell command line and an I/O mode, either "r" for reading or
"w" for writing.
It creates a pipe between the calling process and the command
to be executed.
The value returned is a stream pointer that can be used (as
appropriate) to write to the standard input of the command or
read from its standard output.
.PP
A stream opened by
.I nshpopen
should be closed by
.IR nshpclose ,
which waits for the associated process to terminate
and returns the exit status of the command.
.PP
Because open files are shared, a type "r" command may be used
as an input filter, and a type "w" as an output filter.
.PP
.I Nshpopen
breaks up the
.I command
argument string at spaces and tabs for the child process.
However, it does not invoke a shell, and does not
attempt any shell shell meta character parsing.
In particular, quoted white space will still cause argument seperation.
By avoiding calling a shell, pipe creation is a great deal quicker.
Also, by avoiding the (rather complicated) shell meta character
parsing, some types of bugs may be avoided.
This is important where the security of setuid programs is involved.
.SH "SEE ALSO"
pipe(2),
popen(3),
fopen(3S),
fclose(3S),
system(3),
wait(2),
sh(1)
.SH DIAGNOSTICS
.I Nshpopen
returns a null pointer if files or processes cannot be created,
or the shell cannot be accessed.
.PP
.I Nshpclose
returns \-1 if
.I stream
is not associated with an `nshpopened' command.
.SH BUGS
Buffered reading before opening an input filter
may leave the standard input of that filter mispositioned.
Similar problems with an output filter may be
forestalled by careful buffer flushing, for instance, with
.I fflush,
see
.IR fclose (3).
.LP
.I Nshpopen
does not call a shell to do it's work.
It does not attempt to process shell meta characters.
Thus, it does not treat quotes, I/O redirects, or file
name wildcard characters specially.
This is it's incompatibility with
.I popen(3).
.LP
This type of function should have been included with
.I popen(3)
in the standard I/O library.
SHAR_EOF
if test 2367 -ne "`wc -c nshpopen.3l`"
then
echo shar: error transmitting nshpopen.3l '(should have been 2367 characters)'
fi
cat << \SHAR_EOF > srtunq.3l
.TH SRTUNQ 1L PUCC
.SH NAME
srtinit, srtin, srtgti, srtgets, srtfree, srtdtree
.SH SYNOPSIS
.B #include <stdio.h>
.br
.B #include <local/srtunq.h>
.sp
cc file.c
.B \-lsrtunq
.SH DESCRIPTION
.I Libsrtunq.a
is a set of sorting routines for a particular purpose.
It's use is extracting unique items from a possibly long list,
where items are likely to be replicated numerously.
The list of unique items will be small enough to
fit in main memory.
High speed is desired.
.PP
The caller has control over the database through the use of a
.I struct srtent
variable.
The subroutines provide for data entry and retrieval,
memory allocation and deallocation.
.SH ROUTINES
.TP
.ft B
void srtinit(ent) struct srtent *ent;
.ft
This subroutine must be called before the first time
any data is entered or retrieved
from a database tree whose tag is pointed to by
.B ent.
It assumes that the database tag has not been used
to store a tree, and therefore does not attempt to free
any such data.
.TP
.ft B
char *srtin(ent, string, compar) struct srtent *ent; char *string; int (*compar)();
.ft
The existing data tree is searched.
If the string is found in the tree then nothing is done.
Otherwise, space is allocated for the string and pointer structure via
.I malloc(3).
The string is copied to this new space.
The structure is linked into the tree.
If space cannot be obtained, the operation is aborted, and
a pointer to an error string is returned.
The data structure remains consistent, but the string is not placed in it.
If the operation is successful, NULL is returned.
The strings are compared and sorted with the subroutine pointed to by
.I compar.
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.
If the subroutine pointer is NULL, then a simple string compare is used, which
sorts in ascending ASCII order, and strings of different length comparing
as unequal.
.TP
.ft B
void srtgti(ent); struct srtent *ent;
.ft
This subroutine initializes the database tag pointed to by
.B ent
so that a tree transversal can be made via
.I srtgets.
.TP
.ft B
char *srtgets(ent); struct srtent *ent;
.ft
This routine extracts the next string from the data structure.
The strings are returned in increasing order.
When the list is exhausted, NULL is returned.
.TP
.ft B
void srtfree(ent) struct srtent *ent;
.ft
This subroutine deletes a database, and re-initializes the
database tag.
It assumes that the database tag was initialized at one time via
.I srtinit
(other routines will probably also have been called).
The space formally occupied by string data and pointer structures is
deallocated via
.I free(3).
.TP
.ft B
void srtdtree(ent, tbl) struct srtent *ent; struct srtbl *tbl;
.ft
This subroutine recursively deletes a database subtree.
The space formally occupied by the string data and pointer structures is
deallocated via
.I free(3).
This routine is most likely only of use internally.
.SH EXAMPLE
.nf
main()
{
    char buf[80], *p;
    struct srtent d;
    srtinit(&d);
    while (fgets(buf, stdin, 79) != NULL)
        if ((p = srtin(&d, "foo")) != NULL)
            printf("test: %s\n", p);  /* warning message */
    srtgti(&d);
    while ((p = srtgets(&d)) != NULL)
        puts(p);
    srtfree(&d);
}
.fi
.SH DIAGNOSTICS
There are no messages printed by these routines.
Catchable errors are returned as strings.
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), qsort(3)
.SH AUTHOR
Stephen Uitti, PUCC
.SH BUGS
Likely.
SHAR_EOF
if test 3745 -ne "`wc -c srtunq.3l`"
then
echo shar: error transmitting srtunq.3l '(should have been 3745 characters)'
fi
chdir ..
cat << \SHAR_EOF > abrv.c
/* abbreviation related routines 
 * Written & hacked by Stephen Uitti, PUCC staff, ach at pucc-j, 1985
 * maketd is copyright (C) Purdue University, 1985
 *
 * Permission is hereby given for its free reproduction and
 * modification for non-commercial purposes, provided that this
 * notice and all embedded copyright notices be retained.
 * Commercial organisations may give away copies as part of their
 * systems provided that they do so without charge, and that they
 * acknowledge the source of the software.
 */

#ifdef BSD2_9
#include <sys/types.h>
#endif
#include <stdio.h>
#include <ctype.h>
extern char *malloc();

#include "srtunq.h"
#include "abrv.h"
#include "maketd.h"

struct srtent abrv;			/* include file abrevs */
char   *abrvtbl[MXABR];			/* translation table strings */
int	abrvlen[MXABR];			/* string lengths (for speed) */

/* lngsrt - string length more important than lexicographical compare.
 * return > 0 if b is longer than a.
 * return < 0 if b is shorter than a.
 * if a & b are the same length, return strcmp(a, b), which means
 * that 0 is returned if the strings are THE SAME,
 * if b > a: return > 0
 * if b < a: return < 0
 */
int
lngsrt(a, b)
char *a, *b;
{
    register i;

    if ((i = strlen(b) - strlen(a)) != 0)
	return i;
    else
	return strcmp(a, b);
}

/* hincl - include header optimizer:
 * Compress multiple leading /'s to just one.
 * Remove leading "./".
 * Doesn't change date, just returns pointer into begining of path.
 */
char *
hincl(p)
register char *p;
{
    if (*p == '/')		/* compress multiple leading /'s */
	while (p[1] == '/')	/* to just one */
	    p++;
    if (strncmp("./", p, 2) == 0) {
	p += 2;			/* leading "./" can confuse make */
	while (*p == '/')	/* don't change ".//a.h" to "/a.h" */
	    p++;
    }
    return p;
}

/* srchincl - search line for make defines of A-Z
 * Put entries into abrvtbl.
 */
void
srchincl(p)
register char *p;
{
    register char *q, *r;
    register i;

    if (shortincl && *p != '\0') {
	while (*p == SPC || *p == '\t')
	    p++;		/* ignore white space */
	q = p;			/* what letter */
	if (isupper(*p)) {	/* A-Z, for now */
	    p++;
	    while (*p == SPC || *p == '\t')
		p++;		/* ignore white space */
	    if (*p++ == '=') {
		while (*p == SPC || *p == '\t')
		    p++;
		if ((i = strlen(p)) != 0) {
		    if ((r = malloc((unsigned)(i + 1))) == NULL)
			err("Out of memory in define search");
		    if (abrvtbl[*q - 'A'])
			fprintf(stderr, "%s: warning - %c redefined in %s\n",
			    prgnm, *q, makename);
		    abrvtbl[*q - 'A'] = r;
		    while (*p != '\0' && *p != '#' && *p != '\n')
			*r++ = *p++;
		    *r = '\0';	/* null terminate result */
		}		/* if non-null string */
	    }			/* if = */
	}			/* if A-Z */
    }				/* if shortinclude & string */
}

/* abrvsetup - set up abrev table, spit out the abrevs.	 Use
 * any A-Z definitions found in Makefile, no duplicates.  Add
 * /usr/include & /usr/include/sys if "all" dependencies are
 * being generated (including /usr/include based files).
 * Try to use I=/usr/include and S=/usr/include/sys, but don't
 * make a stink about it.
 */
void
abrvsetup()
{
    register i;				/* temp */
    register char *p;			/* temp */
    register slot;			/* slot search point */
    register j;				/* temp */
    static abrdone = FALSE;		/* do this only once */
    register flushi = FALSE;		/* print I=.. */
    register flushs = FALSE;		/* print S=.. */
    static char *istring = "I=/usr/include";
    static char *sstring = "S=/usr/include/sys";

    if (abrdone)
	return;
    if (shortincl) {
	abrdone = TRUE;			/* we've done this */
	/* add /usr/include/sys, /usr/include if not already there */
	if (alldep) {
	    if (abrvtbl['S'-'A'] == NULL) {
		flushs = TRUE;
		srchincl(sstring);
	    } else if ((p = srtin(&abrv, &sstring[2], lngsrt)) != NULL)
		fprintf(stderr, "%s: %s - %s\n", prgnm, p, &sstring[2]);
	    if (abrvtbl['I'-'A'] == NULL) {
		flushi = TRUE;
		srchincl(istring);
	    } else if ((p = srtin(&abrv, &istring[2], lngsrt)) != NULL)
		fprintf(stderr, "%s: %s - %s\n", prgnm, p, &istring[2]);
	}
	if (!replace) {			/* no new defines with replace */
	    srtgti(&abrv);		/* init tree traversal */
	    slot = 0;			/* start at bgn */
	    while ((p = srtgets(&abrv)) != NULL) {
		j = strlen(p);
		for (i = 0; i < MXABR; i++) { /* look for this definition */
		    if (abrvtbl[i] == NULL)
			continue;	/* check non-null entries */
		    if (*abrvtbl[i] == '\0')
			continue;	/* check non-null entries */
		    if (strcmp(p, abrvtbl[i]) == 0)
			break;		/* exact match found */
		    else if (strlen(abrvtbl[i]) == j + 1 &&
			strncmp(p, abrvtbl[i], j) == 0 &&
			    abrvtbl[i][j] == '/')
			break;		/* match of "p/" found */
		}
		if (i == MXABR) {	/* not found */
		    for (i = slot; i < MXABR; i++) /* find free slot */
			if (abrvtbl[i] == NULL)
			    break;
		    if (i < MXABR) {	/* free slot found */
		/* 	if (!usestdout && !replace) */
			    fprintf(makefd, "%c=%s\n", 'A' + i, p);
			abrvtbl[i++] = p;
			slot = i;	/* reduce free slot search time */
		    }
		}			/* if not found */
	    }				/* while */
	}				/* if !replace */
	if (flushi && !usestdout && !replace)
	    fprintf(makefd, "%s\n", istring);
	if (flushs && !usestdout && !replace)
	    fprintf(makefd, "%s\n", sstring);
	for (i = 0; i < MXABR; i++) {	/* set up string lengths */
	    if (abrvtbl[i] == NULL) {
		abrvlen[i] = 0;
	    } else {
		abrvlen[i] = strlen(abrvtbl[i]);
		if (verbose)
		    fprintf(stderr, "%s: %c='%s'\n",
			prgnm, i + 'A', abrvtbl[i]);
	    }				/* if */
	}				/* for */
    }					/* if */
}

/* findabr - find an abbreviation in abrvtbl for string p (if any).
 * if multiple abbreations work, use longest.
 * (ie: /usr/include & /usr/include/sys; use /usr/include/sys)
 * if found, return index
 * else: MXABR
 * Do not match abbreviations of less than 3 characters.
 */
int
findabr(p)
register char *p;			/* string pointer */
{
    register i;				/* for index */
    register j;				/* found index */

    for (i = 0, j = MXABR; i < MXABR; i++)
	if (abrvlen[i] > 2)		/* changing "." to $A is evil */
	    if (strncmp(abrvtbl[i], p, abrvlen[i]) == 0)
		if (j == MXABR || (abrvlen[i] > abrvlen[j]))
		    j = i;
    return j;
}
SHAR_EOF
if test 6197 -ne "`wc -c abrv.c`"
then
echo shar: error transmitting abrv.c '(should have been 6197 characters)'
fi
cat << \SHAR_EOF > abrv.h
/* include srtunq.h first */

#define MXABR 26			/* upper case chars used */
extern char	*abrvtbl[];		/* translation table strings */
extern int	abrvlen[];		/* string lengths (for speed) */
extern SRTUNQ	abrv;			/* include file abrevs */

/* abbreviation fucntions */
extern int	lngsrt();		/* compare function for abrevs */
extern char	*hincl();		/* optimizer for include paths */
extern void	srchincl();		/* find [A-Z] makefile defines */
extern void	abrvsetup();		/* create abrvs, write them */
extern int	findabr();		/* find longest abrv */
SHAR_EOF
if test 544 -ne "`wc -c abrv.h`"
then
echo shar: error transmitting abrv.h '(should have been 544 characters)'
fi
cat << \SHAR_EOF > breakargs.c
/* breakargs - break a string into a string vector for execv.
 * Returns NULL if can't malloc space for vector, else vector.
 * Note, when done with the vector, mearly "free" the vector.
 * Written by Stephen Uitti, PUCC, Nov '85 for the new version
 * of "popen" - "nshpopen", that doesn't use a shell.
 * (used here for the as filters, a newer option).
 *
 * breakargs is copyright (C) Purdue University, 1985
 *
 * put in a fix for cmds lines with "string string" in them
 * Mon Aug 25 13:34:27 EST 1986 (ksb)
 *
 * Permission is hereby given for its free reproduction and
 * modification for non-commercial purposes, provided that this
 * notice and all embedded copyright notices be retained.
 * Commercial organisations may give away copies as part of their
 * systems provided that they do so without charge, and that they
 * acknowledge the source of the software.
 */
#ifdef BSD2_9
#include <sys/types.h>
#endif
#include <stdio.h>			/* for nothing, really */
#define SPC '\040'			/* ascii space */

char *
mynext(pch)
register char *pch;
{
	register int fQuote;

	for (fQuote = 0; (*pch != '\000' && *pch != SPC && *pch != '\t')||fQuote; ++pch) {
		if ('\\' == *pch) {
			continue;
		}
		switch (fQuote) {
		default:
		case 0:
			if ('"' == *pch) {
				fQuote = 1;
			} else if ('\'' == *pch) {
				fQuote = 2;
			}
			break;
		case 1:
			if ('"' == *pch)
				fQuote = 0;
			break;
		case 2:
			if ('\'' == *pch)
				fQuote = 0;
			break;
		}
	}
	return pch;
}

char **
breakargs(cmd)
char *cmd;
{
	register char *p;		/* tmp				*/
	register char **v;		/* vector of commands returned	*/
	register unsigned sum;		/* bytes for malloc		*/
	register int i;			/* number of args		*/
	register char *s;		/* save old position		*/
	char *malloc(), *strcpy();

	p = cmd;
	while (*p == SPC || *p == '\t')
		p++;
	cmd = p;			/* no leading spaces		*/
	sum = sizeof(char *);
	i = 0;
	while (*p != '\0') {		/* space for argv[];		*/
		++i;
		s = p;
		p = mynext(p);
		sum += sizeof(char *) + 1 + (unsigned)(p - s);
		while (*p == SPC || *p == '\t')
			p++;
	}
	++i;
	/* vector starts at v, copy of string follows NULL pointer */
	v = (char **)malloc(sum+1);
	if (v == NULL)
		return (char **)NULL;
	p = (char *)v + i * sizeof(char *); /* after NULL pointer */
	i = 0;				/* word count, vector index */
	while (*cmd != '\0') {
		v[i++] = p;
		s = cmd;
		cmd = mynext(cmd);
		if (*cmd != '\0')
			*cmd++ = '\0';
		strcpy(p, s);
		p += strlen(p);
		++p;
		while (*cmd == SPC || *cmd == '\t')
			++cmd;
	}
	v[i] = (char *)NULL;
	return v;
}
SHAR_EOF
if test 2529 -ne "`wc -c breakargs.c`"
then
echo shar: error transmitting breakargs.c '(should have been 2529 characters)'
fi
cat << \SHAR_EOF > maketd.c
/* maketd - MAKE Transitive Dependencies.
 * (This is a lie - the dependencies are not transitive, but "all"
 * dependencies are correctly made.)
 *
 * Based loosely on a shell script by Stephan Bechtolsheim, svb at purdue
 * Other Makefile related features have been added or merged in from
 * other programs.
 *
 * Written & hacked by Stephen Uitti, PUCC staff, ach at pucc-j, 1985
 * maketd is copyright (C) Purdue University, 1985
 *
 * removed some of Steve's good, but unnecessary, options in favor
 * of more compile time flags & better implicit rules in the makefile
 * dinked: -q -e -E -k
 * Kevin S Braunsdorf, PUCC UNIX Group 1986	(ksb at j.cc.purdue.edu)
 *
 * Permission is hereby given for its free reproduction and
 * modification for non-commercial purposes, provided that this
 * notice and all embedded copyright notices be retained.
 * Commercial organisations may give away copies as part of their
 * systems provided that they do so without charge, and that they
 * acknowledge the source of the software.
 */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/file.h>			/* for access */
#ifdef BSD2_9
#include <ndir.h>			/* for MAXPATHLEN, MAXNAMLEN */
#endif
#ifdef BSD4_2
#include <sys/dir.h>			/* for MAXNAMLEN in 4.2 */
#endif
#include <ctype.h>			/* for isupper */
#include <stdio.h>
extern char *rindex(), *index(), *strcat(), *strcpy();

#include "srtunq.h"
#include "abrv.h"
#include "nshpopen.h"
#include "maketd.h"

#ifndef CPP
#define CPP	"/lib/cpp "
#endif CPP not in Makefile

/* forward functions */
void	msoio();			/* open output file */
void	rdwr();				/* read old Makefile into new */
void	mkdepend();			/* does the real work */

/* globals */
char *prgnm;				/* our program name		*/
FILE *makefd;				/* makefile stream		*/
int	alldep = FALSE;			/* -a all - /usr/include too	*/
char   *targetname = NULL;		/* -t target name for next file */
char   *destsuffix = ".o";		/* -s suffix for targets	*/
int	header = TRUE;			/* print header & trailer	*/
int	usestdout = FALSE;		/* -d use stdout for makefile	*/
int	forcehead = FALSE;		/* -f force header/trailer	*/
int	makenseen = FALSE;		/* output file has been specified */
char   *makename = "makefile";		/* -m default file for edit	*/
int	backedup = FALSE;		/* for interupt recovery	*/
char	backupfn[MAXNAMLEN+1];		/* backup file name		*/
int	ismakeopen = FALSE;		/* if the output file is open	*/
char	objpath[MAXPATHLEN+1];		/* -o prepended to .o's		*/
int	nonlocalo = FALSE;		/* -nonlocalo objects in source dir */
int	replace = FALSE;		/* -r replace depends in Makefile */
char	cppflags[BUFSIZ];		/* -D, -I, -U flags to pass to cpp */
int	shortincl = TRUE;		/* -x do abreviations		*/
int	verbose = FALSE;		/* -v verbage for the debugger	*/
static char   sopts[] = "abdfhrxv";	/* single char opts		*/
static SRTUNQ u;			/* unique include files		*/

char   usage[] =
"Usage: maketd [-a -b -d -f -h -mMAKEFILE -nonlocalo -oDIR -r -sSUFFIX\n\
 -tTARGETNAME -x -v -Iincludedir -Ddefine -Uundefine file...]\n";
char   helptext[] =
"-a\tdo all dependencies, including /usr/include\n\
-b\tgenerate binary, rather than object related dependencies\n\
-d\tdependencies to stdout, rather than Makefile\n\
-f\tforce header/trailer (use with -d)\n\
-h\thelp (this text)\n\
-m\tspecify MAKEFILE for edit\n\
-nonlocalo Objects live in source directory\n\
-o\tprepend DIR to target: DIR/a.o: foo.h\n\
-r\treplace dependencies for a target\n\
-s\tchange suffix target's SUFFIX: a.SUFFIX: foo.h\n\
-t\tchange target's basename: TARGET.o: foo.h\n\
-x\tdon't abbreviate includes\n\
-v\tprint extra verbose (debug) output to stderr\n\
-I\tspecify include directory, as in /lib/cpp\n\
-D\tspecify defines, as in /lib/cpp\n\
-U\tspecify undefines, as in /lib/cpp\n";

char deplin[] = "# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT\n";
char searchdep[] = "# DO NOT DELETE THIS LINE";
char trailer[] = "\n# *** Do not add anything here - It will go away. ***\n";

/* some init & argv parsing */
main(argc, argv)
register int argc;
register char **argv;
{
    register a;				/* argv subscript		*/
    register i;				/* tmp				*/
    register len;			/* length of current argument	*/
    register files = FALSE;		/* files ever seen		*/
    register char *q;			/* tmp				*/

    /* prgnm = program name, for error printing */
    if ((prgnm = rindex(argv[0], '/')) == NULL)
	prgnm = argv[0];
    else
	prgnm++;
    catchsig();				/* init signal traps */
    srtinit(&abrv);			/* init abbreviations tree */
    for (a = 1; a < argc; a++) {	/* argv prepass: find all -I's */
	if (argv[a][0] == '-' && argv[a][1] == 'I' && strlen(&argv[a][2]) > 2)
	    if ((q = srtin(&abrv, hincl(&argv[a][2]), lngsrt)) != NULL)
		fprintf(stderr, "%s: %s - %s\n", prgnm, q, &argv[a][2]);
    }
    cppflags[0] = '\0';			/* terminate cpp flags string */
    objpath[0] = '\0';			/* init object path */
    srtinit(&u);			/* init sorting database tag */
    for (a = 1; a < argc; a++) {
	len = strlen(argv[a]);
	if (argv[a][0] == '-' && len > 2 && index(sopts, argv[a][1]) != NULL)
	    err("options must be listed seperately - '%s'\n", argv[a]);
	if (len > 1 && argv[a][0] == '-') {
	    switch (argv[a][1]) {
	    case 'D':			/* /lib/cpp flags to pass */
	    case 'I':
	    case 'U':
		if (strlen(cppflags) + strlen(argv[a]) + 2 > BUFSIZ)
		    err("too many cpp flags - buffer overflow");
		strcat(cppflags, argv[a]);
		strcat(cppflags, " ");	/* add a space separator */
		break;
	    case 'a':			/* /usr/include deps too */
		alldep = TRUE;
		break;
	    case 'b':			/* target has no suffix */
		destsuffix = "";
		break;
	    case 'd':			/* don't edit Makefile */
		if (ismakeopen)
		    err("Makefile already open, -d must precede filenames");
		if (makenseen)
		    err("Conflict - check -d and -m options");
		makenseen = TRUE;
		usestdout = TRUE;
		if (!forcehead)
		    header = FALSE;	/* don't do header & trailer */
		break;
	    case 'f':			/* force header/trailer */
		forcehead = TRUE;
		header = TRUE;
		break;
	    case 'h':			/* help */
		fputs(usage, stdout);
		fputs(helptext, stdout);
		exit(0);
		break;
	    case 'm':			/* specify makefile name for edit */
		if (ismakeopen)
		    err("Makefile already open, -m must precede filenames");
		if (makenseen)
		    err("Conflict, check -m and -d options.");
		if (strlen(makename) == 0)
		    err("-m option requires file name.");
		makenseen = TRUE;
		makename = &argv[a][2];
		break;
	    case 'n':			/* objects reside with sources */
		if (strcmp("nonlocalo", &argv[a][1]) != 0)
		    err("bad -n option"); /* what a crock of an option */
		if (objpath[0] != '\0')
		    err("nonlocalo conflict - check -o's");
		nonlocalo = TRUE;
		break;
	    case 'o':
		if (nonlocalo)
		    err("object path conflict - check -o's and -nonlocalo's");
		strcpy(objpath, &argv[a][2]);
		i = strlen(objpath);
		if (i == 0)
		    err("-o requires path string.");
		if (i >= MAXPATHLEN)
		    err("Object path too long: max is %d.", MAXPATHLEN);
		if (objpath[i - 1] != '/')
		    strcat(objpath, "/");
		break;
	    case 'r':			/* replace mode */
		if (ismakeopen)
		    err("Makefile already open, -r must precede filenames");
		replace = TRUE;
		break;
	    case 's':			/* destination suffix */
		destsuffix = &argv[a][2];
		break;
	    case 't':			/* set target's basename */
		targetname = &argv[a][2];
		if (len <= 2)
		    err("target option requires name.");
		break;
	    case 'v':			/* user wants to hear noise */
		verbose = TRUE;
		break;
	    case 'x':			/* don't abbrev. */
		if (files)
		    err("-x option must preceed all files.");
		shortincl = FALSE;
		break;
	    default:
		err("Unknown option %s.", argv[a]);
	    }				/* end switch */
	} else {			/* must be a filename */
	    if (verbose)
		fprintf(stderr, "%s: working on %s.\n", prgnm, argv[a]);
	    files = TRUE;		/* at least one file seen */
	    if (replace && a != argc - 1)
		err("Only one file allowed with -r (edit aborted)");
	    mkdepend(argv[a]);		/* file to process */
	    targetname = NULL;		/* affect only one file */
	}				/* if option */
    }					/* for argv */
    if (ismakeopen && header)
	fputs(trailer, makefd);		/* do not delete... */
#if	DEL_BACKUP
    if (backedup)
	if (unlink(backupfn))
	    err("Can't delete backup file %s on completion", backupfn);
#endif	DEL_BACKUP
    if (!files)
	err("No files to process, use -h for full help.\n%s", usage);
    exit(0);				/* exit status - good */
}

/* msoio - Make Sure Output Is Open.
 * Interacts strongly via globals: makefd, backedup, backupfn, makename,
 * header, ismakeopen
 */
void
msoio(targ)
char *targ;				/* if -r, is target name */
{
    FILE *tmpfd;			/* temp file desc for -d */
    char buf[BUFSIZ];			/* for reading the makefile */

    if (ismakeopen)
	return;
    ismakeopen = TRUE;			/* will be: all errs are fatal */
    if (usestdout) {
	makefd = stdout;
	if (header) {
	    fputc('\n', makefd);	/* one blank line */
	    fputs(deplin, makefd);	/* the first line */
	}
	/* scan "makefile" or "Makefile" for include defines */
	if (access(makename, R_OK) != 0) {
	    makename[0] = 'M';		/* try Makefile */
	    if (access(makename, R_OK) != 0)
		return;			/* just punt */
	}
	if ((tmpfd = fopen(makename, "r")) == NULL)
	    return;			/* just punt */
	while (fgets(buf, BUFSIZ, tmpfd) != NULL)
	    srchincl(buf);		/* scan whole file */
	fclose(tmpfd);
	return;
    }					/* ... if standard out */
/* !makenseen means (default) try "makefile" then "Makefile" */
    if (!makenseen && access(makename, F_OK) != 0)
	makename[0] = 'M';		/* try Makefile */
/* side effect: "Makefile" will be created if neither exist */
    if (access(makename, F_OK) == 0) {	/* if makefile exits */
	strcpy(backupfn, makename);	/* get rid of .bak */
	strcat(backupfn, ".bak");
	if (access(backupfn, F_OK) == 0) {
	    if (unlink(backupfn))
		err("Can't remove %s for pre-edit\n", backupfn);
	}
	if (link(makename, backupfn))	/* mv makefile to .bak */
	    err("Can't link %s to %s.", backupfn, makename);
	backedup = TRUE;		/* for interupt status */
	if (unlink(makename))
	    err("Can't unlink %s during rename.", makename);
    } else {
	backupfn[0] = '\0';		/* no copy (no makefile) */
    }
    if ((makefd = fopen(makename, "w")) == NULL)
	err("Can't open output file '%s' for write.", makename);
    if (backupfn[0] != '\0')		/* if no .bak file - done */
	rdwr(targ);			/* read/write Makefile */
    else
	fputs(deplin, makefd);		/* must start with this */
}

/* create beginging of new Makefile by reading old one */
void
rdwr(targ)
char *targ;
{
    register FILE *oldfd;		/* file pointer for .old */
    char rwbuf[BUFSIZ];			/* temp for read/write */
    register tlen;			/* targ length */
    register puntln = FALSE;		/* punt current line? */
    register contln = FALSE;		/* previous line ended with '\'? */
    register blankln = 0;		/* number of blank lines seen */
    register srchsn = FALSE;		/* search line seen? */

    if ((oldfd = fopen(backupfn, "r")) == NULL)
	err("Can't open backup copy of %s\n", makename);
    tlen = strlen(targ);
    while (fgets(rwbuf, BUFSIZ, oldfd) != NULL) { /* until EOF */
	if (!srchsn) {
	    if (strncmp(searchdep, rwbuf, (sizeof searchdep) - 1) == 0) {
		srchsn = TRUE;
		fputs(deplin, makefd);	/* re-write this line */
		if (!replace)
		    break;
		continue;		/* don't print this line */
	    }
	} else {
	    if (strcmp("\n", rwbuf) == 0) {
		if (!puntln)
		    blankln++;
		contln = FALSE;
		puntln = FALSE;
		continue;		/* don't output this blank line */
	    }
	    if (!contln) {
		if (strncmp(targ, rwbuf, tlen) == 0)
		    puntln = TRUE;
		else if (strcmp(&trailer[1], rwbuf) == 0)
		    puntln = TRUE;
	    }
	    if (lastlnch(rwbuf) == '\\')
		contln = TRUE;
	    else
		contln = FALSE;
	}				/* if srchsn */
	if (!puntln) {
	    srchincl(&rwbuf[0]);	/* search this line for defines */
	    if (blankln != 0) {		/* compress mult blank lines to one */
		putc('\n', makefd);
		blankln = 0;
	    }
	    fputs(rwbuf, makefd);	/* non targ lines */
	}
    }					/* while fgets */
    if (!srchsn)			/* deplin never found */
	fputs(deplin, makefd);		/* so write one */
    (void) fclose(oldfd);		/* close the .old file for gigles */
}

#define MAXCOL 78			/* output width max for makefile */

/* mkdepend - name is historical, but does the "real work" */
void
mkdepend(infile)
char *infile;
{
    register char *p;			/* temp pointer */
    register char *q;			/* temp pointer */
    register char *r;			/* temp pointer */
    register FILE *cppfd;		/* file desc for /lib/cpp */
    char buf[BUFSIZ];			/* temp buff */
    char basename[MAXNAMLEN+1];		/* just the file name */
    register oplen;			/* length target & path */
    register le;			/* length of current output line */
    register char *targ;		/* target's name */
    register i;				/* tmp for index */
    register firstln;			/* first line of a list */

    if ((p = rindex(infile, '/')) == NULL) /* past path */
	p = infile;
    else
	p++;
    if (nonlocalo && p != infile) {	/* objpath = source path */
	for (q = objpath, r = infile; r < p;)
	    *q++ = *r++;
	*q = '\0';			/* null terminate */
    }
    strcpy(basename, p);
    if ((p = rindex(basename, '.')) != NULL)
	*p = '\0';			/* remove trailing ".*" */
    if (targetname != NULL)		/* set up target's name */
	targ = targetname;
    else
	targ = basename;
    if (makename == NULL) {
	makename = "Makefile";
	if (access(makename, F_OK) != 0)
	    makename[0] = 'm';		/* not a real check */
    }
    msoio(targ);			/* Make Sure Output Is Open */
    abrvsetup();			/* create abrev table, write defs. */
    if (access(infile, R_OK) != 0) {
	fprintf(stderr, "%s: Can't open input file '%s', skipped.\n",
	    prgnm, infile);
	return;
    }
    (void)strcpy(buf, CPP);	/* build cpp cmd line */
#if CPP_M
	strcat(buf, "-M ");		/* -M flag - does dependencies */
#endif
    if (strlen(buf) + strlen(cppflags) + strlen(infile) + 1 > BUFSIZ)
	err("cpp command line buffer overflow");
    (void)strcat(buf, cppflags);	/* add command flags */
    (void)strcat(buf, infile);		/* add file name */
    srtfree(&u);			/* init insertion sorter */
    if (verbose)
	fprintf(stderr, "%s: cpp line is '%s'\n", prgnm, buf);
    if ((cppfd = nshpopen(buf, "r")) == NULL)
	err("Can't open pipe for %s", buf);
#if CPP_M
     while (fgets(buf, BUFSIZ, cppfd) != NULL) {
	 if ((p = index(buf, ':')) == NULL)
	     err("cpp -M format error - colon");
	 p++;			/* pass colon */
	 if (*p++ != SPC)
	     err("cpp -M format error - space");
	 p = hincl(p);		/* skip any uglies in include path */
	 if (!alldep && strncmp("/usr/include", p, 12) == 0)
	     continue;		/* ignore /usr/include... stuff */
	 if (index(p, '\n') != NULL) /* replace newline with EOS */
	     *index(p, '\n') = '\0';
	 if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */
	     fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */
     }
#else
     while (fgets(buf, BUFSIZ, cppfd) != NULL) {
	 if (buf[0] != '#')		/* must start with '#' */
	     continue;
	 if ((p = index(buf, '"')) == NULL) /* find first double quote */
	     continue;
	 p++;
	 p = hincl(p);		/* skip any uglies in include path */
	 if (index(p, '"') != NULL)	/* terminate the file name */
	     *index(p, '"') = '\0';
	 if (!alldep && strncmp("/usr/include", p, 12) == 0)
	     continue;		/* ignore /usr/include... stuff */
	 if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */
	     fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */
     }
#endif
    srtgti(&u);				/* init for srtgets */
    /* 2 for colon space */
    oplen = strlen(objpath) + strlen(targ) + strlen(destsuffix) + 2;
    le = MAXCOL;			/* force new line output */
    firstln = TRUE;			/* first line of a file entry */
    while ((p = srtgets(&u)) != NULL) { /* write out the entries */
	if (shortincl)
	    if ((i = findabr(p)) != MXABR) /* i = found index or MXABR */
		p += abrvlen[i] - 2;
	if (le + strlen(p) >= MAXCOL) {
	    if (firstln) {
		le = oplen;
		fprintf(makefd, "\n%s%s%s: ", objpath, targ, destsuffix);
		firstln = FALSE;
	    } else {
		le = 8;
		fprintf(makefd, " \\\n\t");
	    }
	} else {
	    fputc(SPC, makefd);
	}
	if (shortincl && i != MXABR) {
	    fprintf(makefd, "$%c", 'A' + i);
	    p += 2;			/* right place */
	    le += 2;
	}
	fputs(p, makefd);
	le += 1 + strlen(p);
    }
    fputc('\n', makefd);		/* end with newline */
    nshpclose(cppfd);			/* end of that file */
}
SHAR_EOF
if test 16381 -ne "`wc -c maketd.c`"
then
echo shar: error transmitting maketd.c '(should have been 16381 characters)'
fi
cat << \SHAR_EOF > maketd.h
#define TRUE	1
#define FALSE	0
#define SPC	'\040'

/* globals */
extern char	*prgnm;			/* the progs called name */
extern int	alldep;			/* -a all - /usr/include too */
extern int	usestdout;		/* -d use stdout for makefile */
extern FILE	*makefd;		/* file desc. for output file */
extern char	*makename;		/* -m default file for edit */
extern int	backedup;		/* for interupt recovery */
extern char	backupfn[];		/* backup file name */
extern int	replace;		/* -r replace depends in Makefile */
extern int	shortincl;		/* -x do abreviations */
extern int	verbose;		/* -v verbage for the debugger */
extern char	usage[];		/* for error output */

extern void	err();			/* error msg, exit cleanly */
extern void	errrec();		/* exit cleanly - also signal trap */
extern char	lastlnch();		/* last char in line (not \n) */
SHAR_EOF
if test 809 -ne "`wc -c maketd.h`"
then
echo shar: error transmitting maketd.h '(should have been 809 characters)'
fi
cat << \SHAR_EOF > misc.c
/* Written & hacked by Stephen Uitti, PUCC staff, ach at pucc-j, 1985
 * maketd is copyright (C) Purdue University, 1985
 *
 * Permission is hereby given for its free reproduction and
 * modification for non-commercial purposes, provided that this
 * notice and all embedded copyright notices be retained.
 * Commercial organisations may give away copies as part of their
 * systems provided that they do so without charge, and that they
 * acknowledge the source of the software.
 */

#ifdef BSD2_9
#include <sys/types.h>
#include <signal.h>
#endif
#ifdef BSD4_2
#include <sys/signal.h>
#endif
#include <stdio.h>

#include "maketd.h"

/* VARARGS */
/* print and error and exit */
void
err(a, b, c, d)
char *a;				/* the format string, as printf */
char *b, *c, *d;			/* arguments, as printf */
{
    fprintf(stderr, "%s: ", prgnm);
    fprintf(stderr, a, b, c, d);
    fprintf(stderr, "\n");
    errrec();				/* clean up backup file, if any */
    exit(1);
}

/* errrec - error recovery: recover temp file */
static void
errrec()
{
    if (backedup) {
	backedup = FALSE;		/* prevent infinite error recursion */
	unlink(makename);		/* may or may not exist */
	if (link(backupfn, makename))
	    err("can't link %s to %s during recovery", makename, backupfn);
	if (unlink(backupfn))
	    err("can't delete %s during recovery", backupfn);
	err("edit of '%s' aborted - file unchanged.", makename);
    }
    exit(1);
}

/* signal trap routines, one for each */
static void
errhup()
{
    fprintf(stderr, "%s: SIGHUP recieved\n", prgnm);
    errrec();
}

static void
errint()
{
    fprintf(stderr, "%s: SIGINT recieved\n", prgnm);
    errrec();
}

static void
errill()
{
    fprintf(stderr, "%s: SIGILL recieved\n", prgnm);
    errrec();
}

static void
errtrap()
{
    fprintf(stderr, "%s: SIGTRAP recieved\n", prgnm);
    errrec();
}

static void
erriot()
{
    fprintf(stderr, "%s: SIGIOT recieved\n", prgnm);
    errrec();
}

static void
erremt()
{
    fprintf(stderr, "%s: SIGEMT recieved\n", prgnm);
    errrec();
}

static void
errfpe()
{
    fprintf(stderr, "%s: SIGFPE recieved\n", prgnm);
    errrec();
}

static void
errbus()
{
    fprintf(stderr, "%s: SIGBUS recieved\n", prgnm);
    errrec();
}

static void
errsegv()
{
    fprintf(stderr, "%s: SIGSEGV recieved\n", prgnm);
    errrec();
}

static void
errsys()
{
    fprintf(stderr, "%s: SIGSYS recieved\n", prgnm);
    errrec();
}

static void
errpipe()
{
    fprintf(stderr, "%s: SIGPIPE recieved\n", prgnm);
    errrec();
}

static void
erralrm()
{
    fprintf(stderr, "%s: SIGALRM recieved\n", prgnm);
    errrec();
}

static void
errterm()
{
    fprintf(stderr, "%s: SIGTERM recieved\n", prgnm);
    errrec();
}

/* catchsig - init signal traps */
catchsig()
{
    signal(SIGHUP, errhup);
    signal(SIGINT, errint);
    signal(SIGILL, errill);
    signal(SIGTRAP, errtrap);
    signal(SIGIOT, erriot);
    signal(SIGEMT, erremt);
    signal(SIGFPE, errfpe);
    signal(SIGBUS, errbus);
    signal(SIGSEGV, errsegv);
    signal(SIGSYS, errsys);
    signal(SIGPIPE, errpipe);
    signal(SIGALRM, erralrm);
    signal(SIGTERM, errterm);
/* Stock 2.9BSD has all the above, but not as many as 4.2BSD:
 * Want SIGQUIT to drop core.
 * Not worrying about:	SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF
 * cannot be caught: SIGKILL, SIGSTOP
 * Leaving alone: SIGURG, SIGTSTP, SIGCONT, SIGCHLD, SIGTTIN, SIGTTOU, SIGIO
 */
}

/* lastlnch - return last char before newline or NULL in string */
char
lastlnch(p)
register char *p;
{
    register char *q;

    q = p;
    while (*p != '\0' && *p != '\n')
	q = p++;
    return *q;
}
SHAR_EOF
if test 3572 -ne "`wc -c misc.c`"
then
echo shar: error transmitting misc.c '(should have been 3572 characters)'
fi
cat << \SHAR_EOF > nshpopen.c
/* @(#)popen.c	4.5 (Berkeley) 7/6/84
 * Modified from 4.2, 2.9 BSD popen by Stephen Uitti, PUCC, Nov '85
 * Doesn't invoke shell, saving time, becoming more secure.
 * Calls breakargs to break line into command line arguments,
 * delimited by white space, but ignores globing and quoting
 * characters.  For use where you don't need shell meta character
 * expansion or filename globbing.
 */
#ifdef BSD2_9
#include <sys/types.h>
#endif
#include <stdio.h>
#include <signal.h>

#define	tst(a,b)	(*mode == 'r'? (b) : (a))
#define	RDR	0
#define	WTR	1
#define SPC '\040'			/* ascii space */

static	int popen_pid[20];
extern char **environ;
char **breakargs();

/* no-shell popen */
FILE *
nshpopen(cmd, mode)
char *cmd;
char *mode;
{
	int p[2];
	int myside, hisside, pid;
	char **elist;				/* the execv list */

	elist = breakargs(cmd);
	if (pipe(p) < 0)
		return (NULL);
	myside = tst(p[WTR], p[RDR]);
	hisside = tst(p[RDR], p[WTR]);
	if ((pid = vfork()) == 0) {
		/* myside and hisside reverse roles in child */
		close(myside);
		if (hisside != tst(0, 1)) {	/* 0, 1 => stdin, stdout */
			dup2(hisside, tst(0, 1));
			close(hisside);
		}
		execve(elist[0], elist, environ);
		perror("execv");
		_exit(1);			/* bombed execv, child dies */
	}
	free(elist);				/* discard the broken args */
	if (pid == -1) {
		close(myside);
		close(hisside);
		return (NULL);
	}
	popen_pid[myside] = pid;
	close(hisside);
	return (fdopen(myside, mode));
}

/* close for nshpopen */
int *
nshpclose(ptr)
FILE *ptr;
{
#ifdef	BSD4_2
	int child, pid, status, omask;

	child = popen_pid[fileno(ptr)];
	fclose(ptr);
#define	mask(s)	(1 << ((s)-1))
	omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP));
	while ((pid = wait(&status)) != child && pid != -1)
		/* empty */;
	(void) sigsetmask(omask);
	return (int *)(pid == -1 ? -1 : status);
#else		/* 2.9 BSD, at least */
	register f, r, (*hstat)(), (*istat)(), (*qstat)();
	int status;

	f = fileno(ptr);
	fclose(ptr);
	istat = signal(SIGINT, SIG_IGN);
	qstat = signal(SIGQUIT, SIG_IGN);
	hstat = signal(SIGHUP, SIG_IGN);
	while((r = wait(&status)) != popen_pid[f] && r != -1)
		;
	if(r == -1)
		status = -1;
	signal(SIGINT, istat);
	signal(SIGQUIT, qstat);
	signal(SIGHUP, hstat);
	return (int *)(status);
#endif	BSD4_2
}
SHAR_EOF
if test 2253 -ne "`wc -c nshpopen.c`"
then
echo shar: error transmitting nshpopen.c '(should have been 2253 characters)'
fi
cat << \SHAR_EOF > nshpopen.h
/* nshpopen defines */
extern FILE   *nshpopen();		/* open pipe */
extern int    *nshpclose();		/* close pipe */
SHAR_EOF
if test 113 -ne "`wc -c nshpopen.h`"
then
echo shar: error transmitting nshpopen.h '(should have been 113 characters)'
fi
cat << \SHAR_EOF > srtunq.c
/* Sorting function that inserts strings one at a time into memory.
 * Strings are null terminated.
 * Only uniq strings are stored (no count is kept of how many)
 * Any memory used is freed on init (or re-init).
 *
 * Author: Stephen Uitti, PUCC, 1985
 * libsrtunq is copyright (C) Purdue University, 1985
 *
 * Permission is hereby given for its free reproduction and
 * modification for non-commercial purposes, provided that this
 * notice and all embedded copyright notices be retained.
 * Commercial organisations may give away copies as part of their
 * systems provided that they do so without charge, and that they
 * acknowledge the source of the software.
 */

#ifndef lint
static char *rcsid =
    "$Id: srtunq.c,v 1.4 86/08/30 21:35:36 ksb Exp Locker: ksb $";
#endif

#ifdef BSD2_9
#include <sys/types.h>
#endif
#ifdef notdef			/* a comment that allows comments. */
 * use:
 * #include <local/srtunq.h>			/* defines, etc */
 * struct srtent d;				/* data structure foothold */
 * char *p;					/* temp */
 * srtinit(&d);					/* init the structure */
 * if ((p = srtin(&d, "foo", NULL)) != NULL) err(p);	/* add the data */
 *	...
 * srtgti(&d);					/* init for get */
 * p = srtgets(&d);				/* get next entry */
 *	...
 * srtfree(&d);					/* delete the structure */
#endif

#include <stdio.h>			/* for null */
#include <sys/types.h>			/* for void, in V7 */
#include "srtunq.h"			/* for srtunq structs & functions */
/* #include <local/srtunq.h>		/* for srtunq structs & functions */

/* libc functions */
char   *malloc();			/* need more memory */
char   *strcpy();			/* copy string */

/* srtgti - init get string function */
void
srtgti(ent)
struct srtent *ent;
{
    ent->srt_next = ent->srt_top;
    if (ent->srt_next == NULL)
	return;
    while (ent->srt_next->srt_less != NULL)
	ent->srt_next = ent->srt_next->srt_less;
}

/* srtgets - get next string from sorted list, NULL if none more. */
/* The least shall be first... and the greatest shall be last */
char *
srtgets(ent)
struct srtent *ent;
{
    register struct srtbl *s;		/* tmp */
    register char *p;			/* ret val */

    if ((s = ent->srt_next) == NULL)
	return NULL;
    p = s->srt_str;			/* ret val */
    if (s->srt_more != NULL) {
	s = s->srt_more;		/* go one more */
	while (s->srt_less != NULL)	/* then all the way less */
	    s = s->srt_less;
	ent->srt_next = s;
	return p;
    }
    while (s != ent->srt_top && s->srt_prev->srt_more == s)
	s = s->srt_prev;		/* back down any more's */
    if (s == ent->srt_top)
	s = NULL;			/* no more */
    else
	s = s->srt_prev;
    ent->srt_next = s;
    return p;
}

/* srtinit - init the database tag */
void
srtinit(ent)
struct srtent *ent;
{
    ent->srt_top = NULL;		/* erase any knowledge of it */
    ent->srt_next = NULL;		/* extractions at the begining */
}

/* srtfree - delete all the data, init the tag */
void
srtfree(ent)
struct srtent *ent;
{
    if (ent->srt_top == NULL)		/* is the structure empty? */
	return;				/* yes - exit */
    srtdtree(ent->srt_top);
    free((char *)ent->srt_top);		/* clean up last struct */
    srtinit(ent);			/* init the tag */
}

/* srtdtree - recursive tree delete
 * frees all less & more entries pointed to by the srt struct */
void
srtdtree(srt)
register struct srtbl *srt;
{
    if (srt->srt_less != NULL) {
	srtdtree(srt->srt_less);
	free((char *)srt->srt_less);
	srt->srt_less = NULL;		/* for consistency */
    }
    if (srt->srt_more != NULL) {
	srtdtree(srt->srt_more);
	free((char *)srt->srt_more);
	srt->srt_more = NULL;
    }
}

/* srtin - insert string sorted & unique.
 * returns NULL if good, else error message string. */
char *
srtin(ent, str, compar)
struct srtent *ent;
char *str;
int (*compar)();			/* if NULL: use strcmp */
{
    register char *p;			/* temp string pointer */
    register i;				/* string compare result */
    register struct srtbl *s;		/* temp */
    register struct srtbl *srtold;	/* old temp */

    s = srtold = ent->srt_top;
    while (s != NULL) {
    	if ((i = (compar == NULL ?
		strcmp(str, s->srt_str) : (*compar)(str, s->srt_str))) == 0)
	    return NULL;		/* found: do nothing - "good" */
	srtold = s;
	if (i > 0)
	    s = s->srt_more;
	else
	    s = s->srt_less;
    }
    if ((p = malloc((unsigned)(strlen(str) + sizeof(struct srtbl)))) == NULL)
	return "srtin: warning - out of memory"; /* soft error - caller \n */
    s = (struct srtbl *)p;
    if (srtold == NULL) {		/* empty list */
	ent->srt_top = s;
	srtold = ent->srt_top;
    } else {
	if (i > 0)
	    srtold->srt_more = s;
	else
	    srtold->srt_less = s;
    }
    s->srt_prev = srtold;
    s->srt_less = NULL;
    s->srt_more = NULL;
    (void) strcpy(s->srt_str, str);
    return NULL;
}
SHAR_EOF
if test 4678 -ne "`wc -c srtunq.c`"
then
echo shar: error transmitting srtunq.c '(should have been 4678 characters)'
fi
cat << \SHAR_EOF > srtunq.h
/* include file for memory resident unique sorting routines.
 *
 * Written & hacked by Stephen Uitti, PUCC staff, ach at pucc-j, 1985
 * libsrtunq is copyright (C) Purdue University, 1985
 *
 * Permission is hereby given for its free reproduction and
 * modification for non-commercial purposes, provided that this
 * notice and all embedded copyright notices be retained.
 * Commercial organisations may give away copies as part of their
 * systems provided that they do so without charge, and that they
 * acknowledge the source of the software.
 */

/* database entry */
struct srtbl {
    struct srtbl *srt_prev;		/* parent */
    struct srtbl *srt_less;		/* something < srt_str */
    struct srtbl *srt_more;		/* something > srt_str */
    char srt_str[1];			/* dynamic: 1 for null at EOS */
};

/* database tag */
typedef struct srtent {
    struct srtbl *srt_top;		/* root of the tree */
    struct srtbl *srt_next;		/* pointer for srtget */
} SRTUNQ;

/* The functions */
void	srtinit();			/* init for srtin */
void	srtdtree();			/* recursive delete of subtree */
char   *srtin();			/* insert string - return err */
void	srtgti();			/* init for srtgets */
char   *srtgets();			/* get next string */
void	srtfree();			/* free a database */
SHAR_EOF
if test 1244 -ne "`wc -c srtunq.h`"
then
echo shar: error transmitting srtunq.h '(should have been 1244 characters)'
fi
cat << \SHAR_EOF > maketd.sh
#! /bin/sh
#
# maketd - generates file dependencies for makefiles using cc -M
#
PATH=/usr/local/bin:/bin:/usr/bin:/usr/ucb
export PATH

progname=`basename $0`

# Name of the Makefile which will be edited to add the dependencies
if [ $# = 0 ] ; then
    cat << EOF
usage: $progname [-a] [-d] [-m<file>] [-o<directory>] [-D...] [-I...] [-U...]
	      [<file> ...] [-T <file> ...]
EOF
    exit
fi

DEPFILE=/tmp/mtd3$$.tmp
touch $DEPFILE
EDDFILE=/tmp/mtd4$$.tmp

trap 'rm -f $DEPFILE $EDDFILE ; exit ' 1 2 3 15

# Default values for -a, -d, -m and -o options
AOPTION="-e /\/usr\/include/d"
DOPTION=0
MAKEFILE=Makefile
OBJDIR=

# Collect in OPTIONS all options you want to pass on to the C preprocessor.
# 	  in SOURCES all files you want to create dependencies for
while [ -n "$1" ] ; do
    case $1 in

	-a)
	    AOPTION=
	;;

	-d)
	    DOPTION=1
	;;

	-m*)
	    MAKEFILE=`expr $1 : '-m\(.*\)'`
	;;

	-nonlocalo)
	    echo "$progname: -nonlocalo option obsolete"
	    exit 1
	;;

	-o*)
	    if [ "$1" = "-o" ] ; then
		echo    "$progname: -o option requires directory name"
		exit 1
	    fi
	    OBJDIR=`expr $1 : '-o\(.*\)'`
	    if [ ! -d $OBJDIR ] ; then
		echo    "$progname: -o option: \"$OBJDIR\" is not a directory"
		exit 1
	    fi
	    OBJDIR="$OBJDIR/"
	;;

	-[D,I,U]*)
	    OPTIONS="$OPTIONS $1"
	;;

	-T)
	    shift
	    TSOURCES="$*"
	    set ""
	;;

	-*)
	    echo        "$progname: option \"$1\" unknown; ignored"
	;;

	*)
	    SOURCES="$SOURCES $1"
	;;
    esac
    shift
done

#       Run everything through the preprocessor (using cc), sort this
#	output and remove duplictate lines.  If there is no '-a' option
#	remove all dependencies of the form '/usr/include/<file>'. Cc
#	will exit quietly if there are no source files.
/bin/cc -M $OPTIONS $SOURCES | sort | uniq | \
    sed $AOPTION \
	-e "s, \./, ,g" \
	-e "s,\.\./[a-zA-Z0-9]*/\.\.,\.\.,g" \
	-e "s,^,$OBJDIR," >> $DEPFILE

/bin/cc -M $OPTIONS $TSOURCES | sort | uniq | \
    sed $AOPTION \
	-e "s,\.o:,:," \
	-e "s, \./, ,g" \
	-e "s,\.\./[a-zA-Z0-9]*/\.\.,\.\.,g" \
	-e "s,^,$OBJDIR," >> $DEPFILE

# If DOPTION then cat file and exit, otherwise edit Makefile
if [ $DOPTION -eq 1 ] ; then
    cat $DEPFILE
    rm -f $DEPFILE $EDDFILE
    exit
fi

# Now start editing the Makefile
if [ ! -w $MAKEFILE ] ; then
    echo        "$progname: can't edit $MAKEFILE"
    rm -f $DEPFILE $EDDFILE
    exit 1
fi


# Make sure we have the "DO NOT DELETE" line in the Makefile
cat << EOF >> $MAKEFILE

# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
EOF

# Build the editor script to edit the Makefile later.
cat << EOF > $EDDFILE
/# DO NOT DELETE THIS LINE/,\$d
\$a
# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
# Dependencies generated at: `date`

EOF
cat $DEPFILE >> $EDDFILE
cat << EOF >> $EDDFILE

# DO NOT ADD ANYTHING HERE - WILL GO AWAY



More information about the Mod.sources mailing list