sources-request@mirror.UUCP (02/11/87)
Submitted by: ksb@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@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@purdue * Other Makefile related features have been added or merged in from * other programs. * * Written & hacked by Stephen Uitti, PUCC staff, ach@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@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@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@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