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