: "@(#): shar.sh,v 1.10 1997/06/02 21:45:00 johnl Exp $" #! /bin/sh # # This is a shell archive. # Remove everything above this line and run sh on the resulting file. # If this archive is complete, you will see this message at the end: # "All files extracted" # # Created: Fri Jun 20 13:31:56 PDT 1997 by johnl at Informix Software Ltd. # Files archived in this archive: # Makefile # al.1 # al.c # basename.c # delget.1 # delget.sh # dirname.c # dod.1 # dod.sh # escape.1 # escape.c # expand.c # expand.h # filter.c # filter.h # getopt.c # getopt.h # gfile.1 # gfile.sh # instfile.sh # jlss.h # jlss.sh # la.1 # la.c # latest.1 # latest.sh # memmove.c # mkbod.sh # mkpath.sh # mkversion.sh # newsccs.1 # newsccs.sh # pfiles.1 # pfiles.sh # sccs.1 # sccs.bod # sccs.c # sccs.doc # sccs.ins # sccs.lst # sccs2rcs.sh # sccschk.1 # sccschk.sh # sccsfile.1 # sccsfile.sh # sccsinst.1 # sccsinst.sh # sccsmv.1 # sccsmv.sh # sccssid.1 # sccssid.sh # sfile.1 # sfile.c # stderr.c # stderr.h # undelta.1 # undelta.sh # vstrcpy.c # what.1 # what.c # #-------------------- if [ -f Makefile -a "$1" != "-c" ] then echo shar: Makefile already exists else echo 'x - Makefile (2244 characters)' sed -e 's/^X//' >Makefile <<'SHAR-EOF' X# @(#)$Id: Makefile,v 1.5 1997/06/09 20:19:23 johnl Exp $ X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Makefile for SCCS ToolKit X X# Set the SCCSLOC to the directory where the real SCCS programs are found. X# The trailing slash is necessary in SCCSDIR; so are both lots of quotes. X XRANLIB = : ranlib XOFLAGS = XSCCSLOC = /usr/ccs/bin # SVR4 XSCCSDIR = -DSCCSDIR='"$(SCCSLOC)/"' XCFLAGS = -D_POSIX_SOURCE -DNO_PROTOTYPES -O ${SCCSDIR} ${OFLAGS} XSTRIP = -s XLIBS = -ljlss XLDFLAGS = ${STRIP} ${LIBS} X XSCRIPTS = \ X delget \ X dod \ X gfile \ X latest \ X newsccs \ X pfiles \ X sccs2rcs \ X sccschk \ X sccsfile \ X sccsinst \ X sccsmv \ X sccssid \ X undelta X XPROGRAMS = \ X al \ X escape \ X la \ X sccs \ X sfile \ X what X XLIBFILES.c = \ X basename.c \ X dirname.c \ X expand.c \ X filter.o \ X getopt.c \ X stderr.c \ X vstrcpy.c X XLIBRARY = libjlss.a X XLIBOBJECTS = \ X ${LIBRARY}(basename.o) \ X ${LIBRARY}(dirname.o) \ X ${LIBRARY}(expand.o) \ X ${LIBRARY}(filter.o) \ X ${LIBRARY}(getopt.o) \ X ${LIBRARY}(stderr.o) \ X ${LIBRARY}(vstrcpy.o) X Xall: ${LIBRARY} ${PROGRAMS} ${SCRIPTS} X X${LIBRARY}: ${LIBOBJECTS} X ${RANLIB} $@ X XWHAT.o = what.o XSCCS.o = sccs.o XSFILE.o = sfile.o X Xwhat: ${WHAT.o} ${LIBRARY} X ${CC} -o $@ ${WHAT.o} ${LDFLAGS} X Xsccs: ${SCCS.o} ${LIBRARY} X ${CC} -o $@ ${SCCS.o} ${LDFLAGS} X Xsfile: ${SFILE.o} ${LIBRARY} X ${CC} -o $@ ${SFILE.o} ${LDFLAGS} X Xwhat.o: getopt.h stderr.h Xsccs.o: stderr.h X X####################### X# Distribution System # X####################### X XBASENAME = sccs X XFILES.msd = \ X ${BASENAME}.msd \ X mkmsd X XFILES.nmd = \ X ${BASENAME}.nmd \ X mknmd \ X mkversion X XFILES.bod = \ X ${BASENAME}.bod \ X ${BASENAME}.ins \ X ${BASENAME}.lst \ X instfile \ X jlss \ X mkbod \ X mkpath X XMSD: ${FILES.msd} .FORCE X mkmsd . $@ ${BASENAME}.msd X XNMD: ${FILES.nmd} .FORCE X mknmd . $@ ${BASENAME}.nmd X XBOD: ${FILES.bod} .FORCE X mkbod . $@ ${BASENAME}.bod X X.FORCE: X X###################################### X# Non-preferred distribution targets # X###################################### X#msd: ${FILES.msd} .FORCE X# mkmsd . . ${BASENAME}.msd X# X#nmd: ${FILES.nmd} .FORCE X# mknmd . . ${BASENAME}.nmd X# X#bod: ${FILES.bod} .FORCE X# mkbod . . ${BASENAME}.bod X###################################### X Xmkversion: mkversion.sh X rm -f $@ X sh $? $? >$@ X chmod 555 $@ SHAR-EOF chmod 444 Makefile if [ `wc -c al.1 <<'SHAR-EOF' X.\" @(#)$Id: al.1,v 1.3 1996/09/24 18:27:07 johnl Exp $ X'\" Documentation for $RCSfile: al.1,v $ X.TH AL 1 "Sphinx" X.SH NAME Xal \(em list arguments one per line X.SH SYNOPSIS X\fBal\fP [arg ...] X.SH DESCRIPTION X\fBAl\fP prints its arguments one to a line. XIt is most useful for debugging complex shell scripts Xas it allows you to see exactly what arguments are being provided Xwith which spaces, whereas the \fB\-x\fP option in the Bourne Xshell does not make it clear where the arguments are broken. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd X.br X21st December 1987 SHAR-EOF chmod 444 al.1 if [ `wc -c al.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: al.c,v $ X@(#)Version: $Revision: 1.4 $ X@(#)Last changed: $Date: 1996/08/13 11:14:15 $ X@(#)Purpose: List arguments one per line X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1992,1996 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X#include X#include X X#ifndef lint Xstatic const char sccs[] = "@(#)$Id: al.c,v 1.4 1996/08/13 11:14:15 johnl Exp $"; X#endif X Xint main(int argc, char **argv) X{ X while (*++argv) X puts(*argv); X return(EXIT_SUCCESS); X} SHAR-EOF chmod 444 al.c if [ `wc -c basename.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: basename.c,v $ X@(#)Version: $Revision: 1.4 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: Return basename of filename X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1989,1991,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X#include X X#define NIL(x) ((x)0) X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: basename.c,v 1.4 1997/06/02 16:41:57 johnl Exp $"; X#endif X Xconst char *basename(const char *s) X{ X const char *cp; X X /* Strip trailing slashes, worrying about "/" */ X if ((cp = strrchr(s, '/')) != NIL(char *) && cp > s && cp[1] == '\0') X { X /* Skip backwards over trailing slashes */ X while (cp > s && *cp == '/') X cp--; X /* Skip backwards over non-slashes */ X while (cp > s && *cp != '/') X cp--; X } X X return((cp == NIL(char *) || (cp == s && cp[1] == '\0')) ? s : cp + 1); X} X X#ifdef TEST X#include X Xstatic char *list[] = X{ X "/usr/fred/bloggs", X "/usr/fred/bloggs/", X "/usr/fred/bloggs////", X "bloggs", X "/.", X ".", X "/", X "//", X "///", X "////", X "", X NIL(char *) X}; X Xint main(void) X{ X char **name; X X for (name = list; *name != NIL(char *); name++) X { X printf("%-20s ->", *name); X printf(" '%s'\n", basename(*name)); X } X return(0); X} X#endif /* TEST */ SHAR-EOF chmod 444 basename.c if [ `wc -c delget.1 <<'SHAR-EOF' X.\" @(#)$Id: delget.1,v 1.2 1997/02/13 14:37:23 johnl Exp $ X'\" @(#)Manual page: DELGET/DELEDIT -- combined delta and get X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:23 $) X.TH DELGET 1S "Sphinx UNIX Tools" X.SH NAME Xdelget \(em create delta and retrieve new version X.br Xdeledit \(em create delta and retrive new version for editing X.SH SYNOPSIS X\fBdelget\fP [-opt] [file ...] X.br X\fBdeledit\fP [-opt] [file ...] X.SH DESCRIPTION X\fBDelget\fP and \fBDeledit\fP are two links to the same file. X\fBDelget\fP does the delta using \fBdelta\fP(1) Xon the files specified and then retrieves the Xfiles using \fBget\fP(1). X\fBDeledit\fP does the same thing but it gets the files for editing. X.P XAny option arguments are passed to the appropriate commands. XThe `\*c-r\*d' flag is passed to both \fBget\fP and \fBdelta\fP; Xthe `\*c-e\*d' flag is passed to \fBget\fP alone (and effectively Xconverts \fBdelget\fP into \fBdeledit\fP), and anything else is simply Xpassed to \fBdelta\fP. XUnless the files are being retrieved for editing, Xthe \fBget\fP is done silently. X.P XThis script uses \fBescape\fP(1S) to ensure that quotes can be embedded Xin `\*c-y"reason for t'change"\*d' type arguments. X.SH "SEE ALSO" Xdelta(1), get(1), admin(1), escape(1S) X.SH DIAGNOSTICS XFrom \fBdelta\fP and \fBget\fP. X.SH BUGS XIf there is a default SID specified (via \fBadmin\fP(1)) and no X`\*c-r\*d\fIsid\fP' flag is specified, the retrieved version may Xbe different from the changed version. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd. X.br X4th October 1989 SHAR-EOF chmod 444 delget.1 if [ `wc -c delget.sh <<'SHAR-EOF' X: "@(#)$Id: delget.sh,v 1.8 1992/12/29 10:46:21 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Delta and get files X# Uses escape to allow for all weird combinations of quotes in arguments X Xcase `basename $0 .sh` in Xdeledit) eflag="-e";; Xesac X Xsflag="-s" Xfor arg in "$@" Xdo X case "$arg" in X -r*) gargs="$gargs `escape \"$arg\"`" X dargs="$dargs `escape \"$arg\"`" X ;; X -e) gargs="$gargs `escape \"$arg\"`" X sflag="" X eflag="" X ;; X -*) dargs="$dargs `escape \"$arg\"`" X ;; X *) gargs="$gargs `escape \"$arg\"`" X dargs="$dargs `escape \"$arg\"`" X ;; X esac Xdone X Xeval delta "$dargs" && eval get $eflag $sflag "$gargs" SHAR-EOF chmod 444 delget.sh if [ `wc -c dirname.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: dirname.c,v $ X@(#)Version: $Revision: 1.7 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: Return directory name for filename X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1989,1991-93,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X#include X#include X#include "stderr.h" X X#define NIL(x) ((x)0) X Xstatic char s_buf[64]; Xstatic size_t s_len = sizeof(s_buf); Xstatic char *s_str = s_buf; X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: dirname.c,v 1.7 1997/06/02 16:41:57 johnl Exp $"; X#endif X Xconst char *dirname(const char *s) X{ X const char *cp; X int c_len; X X /* Strip trailing slashes, worrying about "/" */ X if ((cp = strrchr(s, '/')) != NIL(char *) && cp > s && cp[1] == '\0') X { X /* Skip backwards over trailing slashes */ X while (cp > s && *cp == '/') X cp--; X /* Skip backwards over non-slashes */ X while (cp > s && *cp != '/') X cp--; X } X X if (cp == NIL(char *)) X (void)strcpy(s_str, "."); X else if (cp == s) X (void)strcpy(s_str, "/"); X else X { X c_len = cp - s; X if (c_len > s_len) X { X if (s_str != s_buf) X free(s_str); X s_len = cp - s + 1; X s_str = (char *)malloc(s_len); X if (s_str == NIL(char *)) X error("out of memory"); X } X (void)strncpy(s_str, s, c_len); X s_str[c_len] = '\0'; X } X return(s_str); X} X X#ifdef TEST X#include X X#define DIM(x) (sizeof(x)/sizeof(*(x))) X Xstatic const char *files[] = X{ X "/usr/lib", X "/usr/", X "usr", X "/", X ".", X "..", X"/the/lion/is/the/king/of/the/jungle/and/this/is/more/than/64/chars/long", X"/the/lion/is/the/king/of/the/jungle/and/this/is/much/longer/than/the/other/is", X}; Xstatic const char *dirs[] = X{ X "/usr", X "/", X ".", X "/", X ".", X ".", X"/the/lion/is/the/king/of/the/jungle/and/this/is/more/than/64/chars", X"/the/lion/is/the/king/of/the/jungle/and/this/is/much/longer/than/the/other", X}; X X/* X** The test must interact with malloc in its own right to show up the bug in X** version 1.4 (where the free released the argument s instead of s_str). X*/ Xint main(void) X{ X const char **p1; X const char **p2; X char *p; X X for (p1 = files, p2 = dirs; p1 < files + DIM(files); p1++, p2++) X { X printf("File = %-10s Dirname = %-10s Correct = %s\n", *p1, dirname(*p1), X (strcmp(dirname(*p1), *p2) == 0) ? "Yes" : "No"); X p = malloc(32); X strncpy(p, "complete and utter garbage", 32); X } X X#if 0 X { X char buff[512]; X printf("Name? "); X while (fgets(buff, sizeof(buff), stdin) != NIL(char *)) X { X buff[strlen(buff) - 1] = '\0'; X printf("Full Name: %s\nDirectory: %s\n", buff, dirname(buff)); X printf("Name? "); X } X putchar('\n'); X } X#endif /* 0 */ X X return(0); X} X X#endif /* TEST */ SHAR-EOF chmod 444 dirname.c if [ `wc -c dod.1 <<'SHAR-EOF' X.\" @(#)$Id: dod.1,v 1.2 1997/02/13 14:37:23 johnl Exp $ X'\" @(#)Manual page: DOD -- delta files extracted for editing X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:23 $) X.TH DOD 1S "Sphinx UNIX Tools" X.SH NAME Xdod \(em delta files extracted for editing X.SH SYNOPSIS X\fBdod\fP [-y'reason'][-rsngmp] [file ...] X.SH DESCRIPTION X\fBDod\fP is used to put back into SCCS (using \fBdelta\fP) Xthose files in its argument list which were extracted for editing X(\fBget -e\fP) and which have been altered. XFiles not extracted for editing are left alone; files extracted for editing Xand not changed have the edit cancelled (\fBunget\fP). X.P X\fBDod\fP takes exactly the same arguments as \fBdelta\fP; for details, Xsee \fBdelta\fP's manual page. X.SH FILES Xdod.sh X.SH "SEE ALSO" Xget(1), delta(1), unget(1), val(1), sact(1). X.SH DIAGNOSTICS XVarious self-explanatory. X.SH BUGS XA comment supplied to the `\*c-y\*d' option containing quotes Xis likely to cause trouble. XThe program should probably use \fBescape\fP(1S) to prevent this from Xhappening, but it occurs sufficiently irregularly that it is Xdeemed not to be a problem. X.P XThe code could be written more neatly if the shell had a command to invert Xthe exit status of a command \(em one name for it would be \fBnot\fP, and Xa suitable link would be`\fB!\fP'. X.SH AUTHOR XJonathan Leffler and Barry Kew X.br XSphinx Ltd. X.br X20th October 1989 SHAR-EOF chmod 444 dod.1 if [ `wc -c dod.sh <<'SHAR-EOF' X: "@(#)$Id: dod.sh,v 1.6 1992/12/29 10:47:22 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Delta listed files which have been modified X# Unget listed files which have not been modified X# Leave listed files which are not SCCS files alone X# Report listed files which are not out for editing but have changed X# Assumes you are using SCCS(1J) front-end to SCCS X X: ${DELTA:=delta} X: ${VAL:=val} X: ${SACT:=sact} X: ${UNGET:=unget} X: ${GET:=get} X Xarg0=`basename $0 .sh` X Xwhile [ $# -gt 0 ] Xdo X case "$1" in X -y) X echo "$arg0: -y argument must be used without a space after the `y'" >&2 X echo "For example: $arg0 -y'Because I said so'" >&2 X exit 1;; X -[rsngmyp]*) X args="$args \"$1\"" X shift;; X --) shift X break;; X -*) echo "$arg0: unknown option ($1) for $arg0/$DELTA" >&2 X exit 1;; X *) break;; X esac Xdone X Xif [ $# = 0 ] Xthen X echo "Usage: $arg0 [-y'Reason'] filename [...]" >&2 X exit 1 Xfi X Xfor file in $* Xdo X if [ ! -f $file ] X then X if [ $file != SCCS -o ! -d $file ] X then echo "$arg0: $file is not a file" >&2 X else echo "$arg0: $file is a directory -- ignored" >&2 X fi X elif $VAL $file >/dev/null 2>/dev/null X then X if $SACT -s $file >/dev/null 2>/dev/null X then X sfile=`sfile $file` X gfile=`gfile $file` X if $GET -k -s -p $sfile | diff - $gfile > /dev/null 2>/dev/null X then X echo "$file unchanged" X $UNGET -s $file >/dev/null 2>/dev/null X else X echo "$file" X eval $DELTA $args $file X fi X else X echo "$file not extracted for editing" X fi X else X echo "$arg0: $file is not an SCCS file" >&2 X fi Xdone SHAR-EOF chmod 444 dod.sh if [ `wc -c escape.1 <<'SHAR-EOF' X.\" @(#)$Id: escape.1,v 1.2 1996/09/24 18:27:15 johnl Exp $ X'\" @(#)Manual page: ESCAPE -- Help handle argument lists for remote shell X.ds fC "Version: $Revision: 1.2 $ ($Date: 1996/09/24 18:27:15 $) X.TH ESCAPE 1S "Sphinx Unix Tools" X.SH NAME Xescape \(em print arguments with spaces preserved for eval and remote shell X.SH SYNOPSIS X\fBescape\fP [arg ...] X.SH DESCRIPTION X\fBEscape\fP prints its argument list in such a form that it can be passed to Xeval or a remote shell and the arguments will be interpreted correctly. XIt does so in a bloody minded way; every argument is embedded in single quotes, Xand each single quote in the argument is recoded as single quote, Xbackslash, single quote, single quote. X(The first single quote terminates the current quoted string; the backslash Xfollowed by a single quote is a single quote, and the last single quote starts Xa new single quoted string.) X.SH "SEE ALSO" X\fBeval\fP, \fBsh\fP, \fBrsh\fP X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd. X.br X23rd August 1989 SHAR-EOF chmod 444 escape.1 if [ `wc -c escape.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: escape.c,v $ X@(#)Version: $Revision: 1.5 $ X@(#)Last changed: $Date: 1997/02/04 14:34:25 $ X@(#)Purpose: Escape argument list for passing to eval or rsh X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1989,1992,1996-97 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X/* X** Usage1: eval thingy `escape "$@"` X** Usage2: rsh remote cmd `escape "$@"` X*/ X X#include X#include X#include X X#define NIL(x) ((x)0) X#define SPECIALCHARS " \t\n\f$`\"\'\\()[];#!^|&<>*?~" X X#ifndef lint Xstatic const char sccs[] = "@(#)$Id: escape.c,v 1.5 1997/02/04 14:34:25 johnl Exp $"; X#endif X X/* Print string in single quotes accounting for embedded single quotes */ Xstatic void doescape(char *s, FILE *fp) X{ X char c; X X putc('\'', fp); X while ((c = *s++) != '\0') X { X if (c == '\'') X { X putc('\'', fp); X putc('\\', fp); X putc('\'', fp); X } X putc(c, fp); X } X putc('\'', fp); X} X X/* Decide whether string needs to be escaped and print appropriately */ Xstatic void escape(char *s, FILE *fp) X{ X if (strpbrk(s, SPECIALCHARS) != NIL(char *)) X doescape(s, fp); X else X fputs(s, fp); X} X X/* X * Print arguments so that they will be unchanged when subjected to shell X * command evaluation (eval ...) X */ Xint main(int argc, char **argv) X{ X char *s; X char delim[2]; X X strncpy(delim, "", 2); X while ((s = *++argv) != NIL(char *)) X { X fputs(delim, stdout); X escape(s, stdout); X delim[0] = ' '; X } X fputs("\n", stdout); X X return(EXIT_SUCCESS); X} SHAR-EOF chmod 444 escape.c if [ `wc -c expand.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: expand.c,v $ X@(#)Version: $Revision: 3.3 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: Perform filename expansion (globbing) X@(#)Author: Kenneth Almquist X@(#)Amendments: J Leffler X@(#)Copyright: (C) JLSS 1989-1991,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X/* -- Include Files */ X X#include X#include X#include X#include X#include X#include "expand.h" X X#if defined(_POSIX_SOURCE) || defined(USG_DIRENT) X#include X#elif defined(BSD_DIRENT) X#include X#define dirent direct X#else XWhat type of directory handling do you have? X#endif X X#ifndef PATHNAME_MAX X#define PATHNAME_MAX 1024 X#endif X X/* -- Type Definitions */ X Xtypedef struct strlist Strlist; Xtypedef struct arglist Arglist; X Xtypedef struct dirent Dirent; Xtypedef struct direct Direct; Xtypedef struct stat Stat; X X#ifdef BSD Xtypedef Direct Dirfile; X#else Xtypedef Dirent Dirfile; X#endif /* BSD */ X X/* -- Structure Definitions */ X Xstruct strlist X{ X Strlist *next; X char *text; X}; X Xstruct arglist X{ X Strlist *list; X Strlist **lastp; X}; X X/* -- Declarations */ X Xextern const char *basename(const char *file); Xextern const char *dirname(const char *file); Xextern char *vstrcpy(char *, int, const char *, ...); X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: expand.c,v 3.3 1997/06/02 16:41:57 johnl Exp $"; X#endif X Xstatic char *expdir; Xstatic Arglist exparg; /* holds expanded arg list */ X Xstatic void expandmeta(Strlist *); Xstatic void expmeta(char *, char *); Xstatic void addfname(char *); Xstatic Strlist *expsort(Strlist *); Xstatic Strlist *msort(Strlist *, int); Xstatic int patmatch(char *, char *); X X/* Do filename expansion on string */ Xvoid shell_glob(char *s) X{ X static Strlist x; X X x.next = (Strlist *)NULL; X x.text = s; X exparg.lastp = &exparg.list; X *exparg.lastp = (Strlist *)NULL; X expandmeta(&x); X} X X/* Return nth expanded argument (counting from zero) */ Xchar *argument(int n) X{ X int i; X Strlist *p; X X i = 0; X for (p = exparg.list; p != NULL; p = p->next) X { X if (i++ == n) X return(p->text); X } X return(NULL); X} X X/* Check whether name contains metacharacters */ Xint metaname(const char *p) X{ X register char c; X X while ((c = *p++) != '\0') X { X if (c == '*' || c == '?' || c == '[') X return(1); X } X return(0); X} X X/* X** Expand shell metacharacters. At this point, the only control characters X** should be escapes. The results are stored in the list exparg. X*/ Xstatic void expandmeta(Strlist * str) X{ X Strlist **savelastp; X Strlist *sp; X X for (; str != (Strlist *)NULL; str = str->next) X { X /* Do metacharacter expansion if necessary */ X if (metaname(str->text)) X { X savelastp = exparg.lastp; X if (expdir == NULL) X { X if ((expdir = malloc(PATHNAME_MAX)) == NULL) X { X errno = ENOMEM; X return; X } X } X expmeta(expdir, str->text); X *exparg.lastp = NULL; X *savelastp = sp = expsort(*savelastp); X while (sp != NULL && sp->next != NULL) X { X sp = sp->next; X } X exparg.lastp = &sp->next; X } X else X { X *exparg.lastp = str; X exparg.lastp = &str->next; X } X } X} X X/* X** Do metacharacter (i.e. *, ?, [...])expansion. (RECURSIVE) X*/ Xstatic void expmeta(char *enddir, char *name) X{ X register char *p; X char *q; X char *start; X char *endname; X int metaflag; X struct stat statb; X DIR *dirp; X Dirfile *dp; X int atend; X int matchdot; X char c; X X metaflag = 0; X p = start = name; X while ((c = *p++) != '\0') X { X if (c == '*' || c == '?') X metaflag = 1; X else if (c == '[') X { X q = p; X if (*q == '!') X q++; X if (*q == ']') X q++; X while (*q != '/' && *q != '\0') X { X if (*++q == ']') X { X metaflag = 1; X break; X } X } X } X if (c == '/') X { X if (metaflag) X break; X start = p; X } X } X endname = p - 1; /* Incremented p once too often */ X X if (metaflag == 0) X { /* we've reached the end of the file name */ X if (enddir != expdir) X metaflag++; X strcpy(enddir, name); X if (metaflag == 0 || stat(expdir, &statb) >= 0) X addfname(expdir); X return; X } X X if (start != name) X { X p = name; X while (p < start) X { X *enddir++ = *p++; X } X } X X /* Work out name of directory to read */ X if (enddir == expdir) X { X p = "."; X } X else if (enddir == expdir + 1 && *expdir == '/') X { X p = "/"; X } X else X { X p = expdir; X enddir[-1] = '\0'; X } X X /* Open directory */ X if ((dirp = opendir(p)) == NULL) X return; X if (enddir != expdir) X enddir[-1] = '/'; X if (*endname == 0) X { X atend = 1; X } X else X { X atend = 0; X *endname++ = '\0'; X } X X matchdot = 0; X if (start[0] == '.') X matchdot++; X X /* Look for matching entries */ X while ((dp = readdir(dirp)) != NULL) X { X if (dp->d_name[0] == '.' && !matchdot) X continue; X if (patmatch(start, dp->d_name)) X { X if (atend) X { X strcpy(enddir, dp->d_name); X addfname(expdir); X } X else X { X p = vstrcpy(enddir, 2, dp->d_name, "/"); X expmeta(p, endname); /* RECURSE -- Depth First Search */ X } X } X } X X /* Finished */ X closedir(dirp); X if (!atend) X endname[-1] = '/'; X} X X/* X** Add a file name to the list. X*/ Xstatic void addfname(char *name) X{ X char *p; X Strlist *sp; X X p = malloc(strlen(name) + 1); X strcpy(p, name); X sp = (Strlist *)malloc(sizeof *sp); X sp->text = p; X *exparg.lastp = sp; X exparg.lastp = &sp->next; X} X X/* X** Sort the results of file name expansion. It calculates the number of X** strings to sort and then calls msort (short for merge sort)to do the X** work. X*/ Xstatic Strlist *expsort(Strlist * str) X{ X int len; X Strlist *sp; X X len = 0; X for (sp = str; sp; sp = sp->next) X len++; X return(msort(str, len)); X} X Xstatic Strlist *msort(Strlist * list, int len) X{ X Strlist *p; X Strlist *q = 0; X Strlist **lpp; X int half; X int n; X X if (len <= 1) X return(list); X half = len >> 1; X p = list; X for (n = half; --n >= 0;) X { X q = p; X p = p->next; X } X assert(q != 0); X q->next = NULL; /* terminate first half of list */ X q = msort(list, half); /* sort first half of list */ X p = msort(p, len - half); /* sort second half */ X lpp = &list; X for (;;) X { X if (strcmp(p->text, q->text) < 0) X { X *lpp = p; X lpp = &p->next; X if ((p = *lpp) == NULL) X { X *lpp = q; X break; X } X } X else X { X *lpp = q; X lpp = &q->next; X if ((q = *lpp) == NULL) X { X *lpp = p; X break; X } X } X } X return(list); X} X X/* X** Returns true if the pattern matches the string. X*/ Xstatic int patmatch(char *pattern, char *string) X{ X register char *p; X register char *q; X register char c; X char *endp; X int invert; X int found; X char chr; X X p = pattern; X q = string; X while ((c = *p++) != '\0') X { X switch (c) X { X case '?': X if (*q++ == '\0') X return(0); X break; X X case '*': X c = *p; X if (c != '?' && c != '*' && c != '[') X { X while (*q != c) X { X if (*q == '\0') X return(0); X q++; X } X } X do X { X if (patmatch(p, q)) /* RECURSE */ X return(1); X } while (*q++ != '\0'); X return(0); X X case '[': X endp = p; X if (*endp == '!') X endp++; X if (*endp == ']') X endp++; X while ((chr = *endp++) != ']') X { X if (*endp == '\0') X { /* no matching ] */ X if (*q++ != c) X return(0); X continue; X } X } X invert = 0; X if (*p == '!') X { X invert++; X p++; X } X found = 0; X chr = *q++; X c = *p++; X do X { X if (*p == '-' && p[1] != ']') X { X p++; X if (chr >= c && chr <= *p) X found = 1; X p++; X } X else X { X if (chr == c) X found = 1; X } X } while ((c = *p++) != ']'); X if (found == invert) X return(0); X break; X X default: X if (*q++ != c) X return(0); X break; X } X } X X if (*q != '\0') X return(0); X return(1); X} X X#ifdef TEST X#include Xstatic char *dirlist[] = {"SCCS/", "sccs/", "SCCS/s.", "sccs/s.", 0}; X Xint main(int argc, char **argv) X{ X int i; X int j; X int k; X char buff[512]; X char *s; X struct stat sb; X X for (i = 1; i < argc; i++) X { X printf("argv[%d] = <<%s>>\n", i, argv[i]); X shell_glob(argv[i]); X X k = 0; X strcpy(buff, argv[i]); X while (1) X { X j = 0; X s = argument(j++); X if (s != NULL && (strcmp(s, buff) != 0 || stat(s, &sb) == 0)) X { X while (s != NULL) X { X printf("exparg[%d] = 0x%08lX = <<%s>>\n", j, X (unsigned long)s, s); X s = argument(j++); X } X break; X } X else if (dirlist[k] == NULL) X { X if (s == NULL) X printf("No expanded filenames\n"); X else X printf("exparg[%d] = 0x%08lX = <<%s>>\n", j, X (unsigned long)s, s); X break; X } X else X { X const char *d; X const char *b; X X d = dirname(argv[i]); X b = basename(argv[i]); X vstrcpy(buff, 4, d, "/", dirlist[k++], b); X printf("Globbing %s\n", buff); X shell_glob(buff); X } X } X } X X return(0); X} X X#endif /* TEST */ SHAR-EOF chmod 444 expand.c if [ `wc -c expand.h <<'SHAR-EOF' X/* X@(#)File: $RCSfile: expand.h,v $ X@(#)Version: $Revision: 1.2 $ X@(#)Last changed: $Date: 1997/06/02 16:24:26 $ X@(#)Purpose: Perform filename expansion (globbing) X@(#)Author: Kenneth Almquist X@(#)Amendments: J Leffler X@(#)Copyright: (C) JLSS 1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X#ifndef EXPAND_H X#define EXPAND_H X X#ifdef MAIN_PROGRAM X#ifndef lint Xstatic const char expand_h[] = "@(#)$Id: expand.h,v 1.2 1997/06/02 16:24:26 johnl Exp $"; X#endif /* lint */ X#endif /* MAIN_PROGRAM */ X Xextern void shell_glob(char *s); Xextern int metaname(const char *p); Xextern char *argument(int n); X X#endif /* EXPAND_H */ SHAR-EOF chmod 444 expand.h if [ `wc -c filter.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: filter.c,v $ X@(#)Version: $Revision: 3.6 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: Standard File Filter X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1987-89,1991,1993,1996 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X#include X#include X#include "stderr.h" X#include "filter.h" X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: filter.c,v 3.6 1997/06/02 16:41:57 johnl Exp $"; X#endif X X/* X Purpose: Standard File Filter X X Maintenance Log X --------------- X 09/03/87 JL Original version stabilised X 18/04/88 JL Now pass fp and file name to function X 15/12/91 JL Upgrade for ANSI C X 29/06/93 JL Rename to filter and accept optind argument X 15/10/96 JL Remove non-ANSI support and ffilter(); rename file X X Arguments X --------- X argc In: Number of arguments X argv In: Argument list of program X optind In: Offset in list to start at X function In: Function to process file X X Comments X -------- X 1. For every non-flag option in the argument list, or standard input X if there are no non-flag arguments, run 'function' on file. X 2. If a file name is '-', use standard input. X 3. The optnum argument should normally be the value of optind as X supplied by getopt(3). But it should be the index of the first X non-flag argument. X X*/ Xvoid filter(int argc, char **argv, int optnum, Filter function) X{ X int i; X FILE *fp; X char *file; X X if (argc <= optnum) X { X /* Assumes argv[argc] == NIL(char *) and can be assigned to */ X argv[argc] = "-"; X argc++; X } X X for (i = optnum; i < argc; i++) X { X if (strcmp(argv[i], "-") == 0) X { X file = "(standard input)"; X (*function)(stdin, file); X } X else if ((fp = fopen(argv[i], "r")) != NULL) X { X file = argv[i]; X (*function)(fp, file); X fclose(fp); X } X else X error2("failed to open file", argv[i]); X } X} X X#ifdef TEST X/* X** Test program -- equivalent to: cat [-v] [file ...] X*/ X X#include X#include "getopt.h" X Xvoid fcopy(FILE *f1, FILE *f2) X{ X char buffer[BUFSIZ]; X int n; X X while ((n = fread(buffer, sizeof(char), sizeof(buffer), f1)) > 0) X { X if (fwrite(buffer, sizeof(char), n, f2) != n) X error("write failed"); X } X} X Xvoid vis(FILE *fp, char *fn) X{ X int c; X X fprintf(stdout, "%s:\n", fn); X while ((c = getc(fp)) != EOF) X { X if (!isascii(c) || !isprint(c)) X printf("\\%03o", c); X else X putchar(c); X } X} X Xvoid cat(FILE *fp, char *fn) X{ X fprintf(stdout, "%s:\n", fn); X fcopy(fp, stdout); X} X Xint main(int argc, char **argv) X{ X int opt; X Filter f = cat; X X setarg0(argv[0]); X opterr = 0; X while ((opt = getopt(argc, argv, "v")) != EOF) X { X if (opt == 'v') X f = vis; X else X usage("[-v] [file ...]"); X } X filter(argc, argv, optind, f); X return(0); X} X X#endif /* TEST */ SHAR-EOF chmod 444 filter.c if [ `wc -c filter.h <<'SHAR-EOF' X/* X@(#)File: $RCSfile: filter.h,v $ X@(#)Version: $Revision: 1.6 $ X@(#)Last changed: $Date: 1997/06/02 16:24:26 $ X@(#)Purpose: Header for filter functions X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1993,1996-97 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X#ifndef FILTER_H X#define FILTER_H X X#ifdef MAIN_PROGRAM X#ifndef lint Xstatic const char filter_h[] = "@(#)$Id: filter.h,v 1.6 1997/06/02 16:24:26 johnl Exp $"; X#endif /* lint */ X#endif /* MAIN_PROGRAM */ X X#include X Xtypedef void (*Filter)(FILE *fp, char *fn); X Xextern void filter(int argc, char **argv, int optnum, Filter function); X X/* Backwards compatability */ X#ifdef USE_FFILTER Xextern void ffilter(int argc, char **argv, Filter function); X#else X#define ffilter(argc, argv, function) filter(argc, argv, 1, function) X#endif X X#endif /* FILTER_H */ SHAR-EOF chmod 444 filter.h if [ `wc -c getopt.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: getopt.c,v $ X@(#)Version: $Revision: 2.11 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: GNU version of GETOPT(3) X@(#)Copyright: (C) 1987 Free Software Foundation, Inc. X@(#)Amendments: J Leffler, JLSS X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: getopt.c,v 2.11 1997/06/02 16:41:57 johnl Exp $"; X#endif X X/* X** Rename to gnu_getopt() and use revised getopt.h header. X** X** J Leffler, JLSS, 6th August 1996. X*/ X X/* X** Convert to ANSI C and use getopt.h header X** X** J Leffler, JLSS, 27th June 1996. X*/ X X/* X** Initialize optopt to avoid a loading problem on Pyramids X** X** J Leffler, JLSS, 28th June 1992. X*/ X X/* X** Function xmalloc removed -- inline code used instead. X** Changed error message to "out of memory". X** Use stdlib.h to declare malloc(). Use memmove() instead of memcpy(). X** Remove BSD bcopy and index stuff -- not POSIX compatible. X** X** J Leffler, JLSS, 15th December 1991. X*/ X X/* X** Global variable optopt added to conform with System V Release 4. X** This contains the function return value unless the return value is the X** error return '?', in which case, optopt contains the value of the option X** which caused the error return. Also use isprint() (from ctype.h) to X** determine whether character is printable (instead of the non-portable X** and not always helpful (c < 040 || c >= 0177)). X** X** J Leffler, Informix Software Ltd, 17th December 1990. X*/ X X/* X** Format of code and comments revised to suit local conventions. X** Function completely unaltered, though appended memcpy() removed. X** Default compilation changed to SYSV mode -- unless BSD is defined, X** it will be compiled using strchr and memcpy. X** X** NB: this version of getopt(3) allows for flags which take optional X** arguments. This is done by using "f::" in place of "f:" in the X** option string. The optional argument must be attached to flag. X** X** J Leffler, Sphinx Ltd, 3rd April 1990. X*/ X X/* X Getopt for GNU. X Modified by David MacKenzie to use malloc and free instead of alloca, X and memcpy instead of bcopy under System V. X Copyright (C) 1987 Free Software Foundation, Inc. X X NO WARRANTY X XBECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, XRICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY XAND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE XDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR XCORRECTION. X XIN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. XSTALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY XWHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE XLIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR XOTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE XUSE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR XDATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR XA FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS XPROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH XDAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. X X GENERAL PUBLIC LICENSE TO COPY X X 1. You may copy and distribute verbatim copies of this source file Xas you receive it, in any medium, provided that you conspicuously and Xappropriately publish on each copy a valid copyright notice "Copyright X (C) 1987 Free Software Foundation, Inc."; and include following the Xcopyright notice a verbatim copy of the above disclaimer of warranty Xand of this License. You may charge a distribution fee for the Xphysical act of transferring a copy. X X 2. You may modify your copy or copies of this source file or Xany portion of it, and copy and distribute such modifications under Xthe terms of Paragraph 1 above, provided that you also do the following: X X a) cause the modified files to carry prominent notices stating X that you changed the files and the date of any change; and X X b) cause the whole of any work that you distribute or publish, X that in whole or in part contains or is a derivative of this X program or any part thereof, to be licensed at no charge to all X third parties on terms identical to those contained in this X License Agreement (except that you may choose to grant more X extensive warranty protection to third parties, at your option). X X c) You may charge a distribution fee for the physical act of X transferring a copy, and you may at your option offer warranty X protection in exchange for a fee. X X 3. You may copy and distribute this program or any portion of it in Xcompiled, executable or object code form under the terms of Paragraphs X1 and 2 above provided that you do the following: X X a) cause each such copy to be accompanied by the X corresponding machine-readable source code, which must X be distributed under the terms of Paragraphs 1 and 2 above; or, X X b) cause each such copy to be accompanied by a X written offer, with no time limit, to give any third party X free (except for a nominal shipping charge) a machine readable X copy of the corresponding source code, to be distributed X under the terms of Paragraphs 1 and 2 above; or, X X c) in the case of a recipient of this program in compiled, executable X or object code form (without the corresponding source code) you X shall cause copies you distribute to be accompanied by a copy X of the written offer of source code which you received along X with the copy you received. X X 4. You may not copy, sublicense, distribute or transfer this program Xexcept as expressly provided under this License Agreement. Any attempt Xotherwise to copy, sublicense, distribute or transfer this program is void and Xyour rights to use the program under this License agreement shall be Xautomatically terminated. However, parties who have received computer Xsoftware programs from you with this License Agreement will not have Xtheir licenses terminated so long as such parties remain in full compliance. X X 5. If you wish to incorporate parts of this program into other free Xprograms whose distribution conditions are different, write to the Free XSoftware Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet Xworked out a simple rule that can be stated here, but we will often permit Xthis. We will be guided by the two goals of preserving the free status of Xall derivatives of our free software and of promoting the sharing and reuse of Xsoftware. X XIn other words, you are welcome to use, share and improve this program. XYou are forbidden to forbid anyone else to use, share and improve Xwhat you give them. Help stamp out software-hoarding! X*/ X X/* X** This version of `getopt' appears to the caller more or less like the X** standard Unix `getopt' but it behaves differently for the user, since it X** allows the user to intersperse the options with the other arguments. X** X** As `getopt' works, it permutes the elements of `argv' so that, X** when it is done, all the options precede everything else. Thus X** all application programs are extended to handle flexible argument order. X** X** Setting the environment variable _POSIX_OPTION_ORDER disables permutation. X** Then the behavior is completely standard. X** X** GNU application programs can use a third alternative mode in which X** they can distinguish the relative order of options and other arguments. X*/ X X#include X#include X#include X#include X#include "getopt.h" X X/* X** optarg -- for communication from `getopt' to the caller. X** When `getopt' finds an option that takes an argument, X** the argument value is returned here. X** Also, when `ordering' is RETURN_IN_ORDER, X** each non-option ARGV-element is returned here. X*/ Xchar *optarg = 0; X X/* X** optind -- index in ARGV of the next element to be scanned. X** This is used for communication to and from the caller X** and for communication between successive calls to `getopt'. X** X** On entry to `getopt', zero means this is the first call; initialize. X** X** When `getopt' returns EOF, this is the index of the first of the X** non-option elements that the caller should itself scan. X** X** Otherwise, `optind' communicates from one call to the next X** how much of ARGV has been scanned so far. X*/ Xint optind = 0; X X/* X** nextchar -- the next char to be scanned in the option-element X** in which the last option character we returned was found. X** This allows us to pick up the scan where we left off. X** X** If this is zero, or a null string, it means resume the scan X** by advancing to the next ARGV-element. X*/ Xstatic char *nextchar; X X/* X** opterr -- callers store zero here to inhibit the error message X** for unrecognized options. X*/ Xint opterr = 1; X X/* X** optopt -- copy of option which was detected. It is the same as the X** function return value unless the function returns '?' (for an invalid X** option) when optopt contains the actual flag which caused the error. X** Added in conformity with UNIX System V Release 4. X*/ Xint optopt = '0'; X X/* X** Describe how to deal with options that follow non-option ARGV-elements. X** X** UNSPECIFIED means the caller did not specify anything; X** the default is then REQUIRE_ORDER if the environment variable X** _POSIX_OPTION_ORDER is defined, PERMUTE otherwise. X** X** REQUIRE_ORDER means don't recognize them as options. X** Stop option processing when the first non-option is seen. X** This is what Unix does. X** X** PERMUTE is the default. We permute the contents of `argv' as we scan, X** so that eventually all the options are at the end. This allows options X** to be given in any order, even with programs that were not written to X** expect this. X** X** RETURN_IN_ORDER is an option available to programs that were written X** to expect options and other ARGV-elements in any order and that care about X** the ordering of the two. We describe each non-option ARGV-element X** as if it were the argument of an option with character code zero. X** Using `-' as the first character of the list of option characters X** requests this mode of operation. X** X** The special argument `--' forces an end of option-scanning regardless X** of the value of `ordering'. In the case of RETURN_IN_ORDER, only X** `--' can cause `getopt' to return EOF with `optind' != ARGC. X*/ Xstatic enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; X X/* Handle permutation of arguments. */ X X/* X** Describe the part of ARGV that contains non-options that have X** been skipped. `first_nonopt' is the index in ARGV of the first of them; X** `last_nonopt' is the index after the last of them. X*/ Xstatic int first_nonopt; Xstatic int last_nonopt; X X/* X** Exchange two adjacent subsequences of ARGV. X** One subsequence is elements [first_nonopt,last_nonopt) X** which contains all the non-options that have been skipped so far. X** The other is elements [last_nonopt,optind), which contains all X** the options processed since those non-options were skipped. X** `first_nonopt' and `last_nonopt' are relocated so that they describe X** the new indices of the non-options in ARGV after they are moved. X*/ X Xstatic void exchange(char **argv) X{ X int nonopts_size = (last_nonopt - first_nonopt) * sizeof(char *); X char **temp; X X if ((temp = (char **)malloc(nonopts_size)) == (char **)0) X { X fprintf(stderr, "out of memory\n"); X exit(1); X } X X /* Interchange the two blocks of data in argv. */ X memmove(temp, &argv[first_nonopt], nonopts_size); X memmove(&argv[first_nonopt], &argv[last_nonopt], X (optind - last_nonopt) * sizeof(char *)); X memmove(&argv[first_nonopt + optind - last_nonopt], temp, nonopts_size); X X free(temp); X X /* Update records for the slots the non-options now occupy. */ X first_nonopt += (optind - last_nonopt); X last_nonopt = optind; X} X X/* X** Scan elements of ARGV (whose length is ARGC) for option characters X** given in OPTSTRING. X** X** If an element of ARGV starts with '-', and is not exactly "-" or "--", X** then it is an option element. The characters of this element X** (aside from the initial '-') are option characters. If `getopt' X** is called repeatedly, it returns successively each of the option characters X** from each of the option elements. X** X** If `getopt' finds another option character, it returns that character, X** updating `optind' and `nextchar' so that the next call to `getopt' can X** resume the scan with the following option character or ARGV-element. X** X** If there are no more option characters, `getopt' returns `EOF'. X** Then `optind' is the index in ARGV of the first ARGV-element X** that is not an option. (The ARGV-elements have been permuted X** so that those that are not options now come last.) X** X** OPTSTRING is a string containing the legitimate option characters. X** A colon in OPTSTRING means that the previous character is an option X** that wants an argument. The argument is taken from the rest of the X** current ARGV-element, or from the following ARGV-element, X** and returned in `optarg'. X** X** If an option character is seen that is not listed in OPTSTRING, X** return '?' after printing an error message. If you set `opterr' to X** zero, the error message is suppressed but we still return '?'. X** X** If a char in OPTSTRING is followed by a colon, that means it wants an arg, X** so the following text in the same ARGV-element, or the text of the following X** ARGV-element, is returned in `optarg. Two colons mean an option that X** wants an optional arg; if there is text in the current ARGV-element, X** it is returned in `optarg'. X** X** If OPTSTRING starts with `-', it requests a different method of handling the X** non-option ARGV-elements. See the comments about RETURN_IN_ORDER, above. X*/ X Xint gnu_getopt(int argc, char **argv, const char *optstring) X{ X if (optind == 0) X { X /* X ** Initialize the internal data when the first call is made. X ** Start processing options with ARGV-element 1 (since ARGV-element 0 X ** is the program name); the sequence of previously skipped X ** non-option ARGV-elements is empty. X */ X first_nonopt = last_nonopt = optind = 1; X nextchar = 0; X X /* Determine how to handle the ordering of options and nonoptions. */ X if (optstring[0] == '-') X ordering = RETURN_IN_ORDER; X else if (getenv("_POSIX_OPTION_ORDER") != 0) X ordering = REQUIRE_ORDER; X else X ordering = PERMUTE; X } X X if (nextchar == 0 || *nextchar == 0) X { X if (ordering == PERMUTE) X { X /* X ** If we have just processed some options following some X ** non-options, exchange them so that the options come first. X */ X if (first_nonopt != last_nonopt && last_nonopt != optind) X exchange(argv); X else if (last_nonopt != optind) X first_nonopt = optind; X X /* X ** Now skip any additional non-options and extend X ** the range of non-options previously skipped. X */ X while (optind < argc && X (argv[optind][0] != '-' || argv[optind][1] == 0)) X optind++; X last_nonopt = optind; X } X X /* X ** Special ARGV-element `--' means premature end of options. X ** Skip it like a null option, then exchange with previous X ** non-options as if it were an option, then skip everything else X ** like a non-option. X */ X if (optind != argc && !strcmp(argv[optind], "--")) X { X optind++; X X if (first_nonopt != last_nonopt && last_nonopt != optind) X exchange(argv); X else if (first_nonopt == last_nonopt) X first_nonopt = optind; X last_nonopt = argc; X X optind = argc; X } X X /* X ** If we have done all the ARGV-elements, stop the scan X ** and back over any non-options that we skipped and permuted. X */ X if (optind == argc) X { X /* X ** Set the next-arg-index to point at the non-options X ** that we previously skipped, so the caller will digest them. X */ X if (first_nonopt != last_nonopt) X optind = first_nonopt; X return EOF; X } X X /* X ** If we have come to a non-option and did not permute it, X ** either stop the scan or describe it to the caller and pass it by. X */ X if (argv[optind][0] != '-' || argv[optind][1] == 0) X { X if (ordering == REQUIRE_ORDER) X return EOF; X optarg = argv[optind++]; X return 0; X } X X /* X ** We have found another option-ARGV-element. X ** Start decoding its characters. X */ X nextchar = argv[optind] + 1; X } X X /* Look at and handle the next option-character. */ X { X char c = *nextchar++; X char *temp = strchr(optstring, c); X X /* Set optopt */ X optopt = c; X X /* Increment `optind' when we start to process its last character. */ X if (*nextchar == 0) X optind++; X X if (temp == 0 || c == ':') X { X if (opterr != 0) X { X if (!isprint(c)) X fprintf(stderr, "%s: unrecognized option, character code 0%o\n", X argv[0], c); X else X fprintf(stderr, "%s: unrecognized option `-%c'\n", X argv[0], c); X } X return '?'; X } X if (temp[1] == ':') X { X if (temp[2] == ':') X { X /* This is an option that accepts an argument optionally. */ X if (*nextchar != 0) X { X optarg = nextchar; X optind++; X } X else X optarg = 0; X nextchar = 0; X } X else X { X /* This is an option that requires an argument. */ X if (*nextchar != 0) X { X optarg = nextchar; X /* X ** If we end this ARGV-element by taking the rest as X ** an arg, we must advance to the next element now. X */ X optind++; X } X else if (optind == argc) X { X if (opterr != 0) X fprintf(stderr, "%s: no argument for `-%c' option\n", X argv[0], c); X c = '?'; X } X else X { X /* X ** We already incremented `optind' once; increment it X ** again when taking next ARGV-elt as argument. X */ X optarg = argv[optind++]; X } X nextchar = 0; X } X } X return c; X } X} SHAR-EOF chmod 444 getopt.c if [ `wc -c getopt.h <<'SHAR-EOF' X/* X@(#)File: $RCSfile: getopt.h,v $ X@(#)Version: $Revision: 1.9 $ X@(#)Last changed: $Date: 1997/06/02 16:36:22 $ X@(#)Purpose: Declarations for GETOPT(3) and GETSUBOPT(3) X@(#)Author: J Leffler X@(#)Copyright: JLSS (C) 1992-93,1996-97 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X#ifndef GETOPT_H X#define GETOPT_H X X#ifdef MAIN_PROGRAM X#ifndef lint Xstatic const char getopt_h[] = "@(#)$Id: getopt.h,v 1.9 1997/06/02 16:36:22 johnl Exp $"; X#endif /* lint */ X#endif /* MAIN_PROGRAM */ X X/* X** GNU getopt provides facilities not available in standard getopt. X** Specifically, it will reorder all option arguments before all non-option X** arguments unless the environment variable _POSIX_OPTION_ORDER is X** defined. It can also handle optional arguments, which must be attached X** to option letter on the command line, indicated by two colons after the X** option letter. It can be told to return all arguments in order, with a X** value of '\0' indicating a file option by starting the options string X** with a '-'. It also has a different interface from standard getopt X** because the second (argv) argument is not const. X*/ X Xextern int optopt; Xextern int opterr; Xextern int optind; Xextern char *optarg; X Xextern int getopt(int argc, char *const*argv, const char *opts); Xextern int getsubopt(char **opt, char *const*names, char **value); Xextern int gnu_getopt(int argc, char **argv, const char *opts); X X#ifndef GETOPT X#ifdef USE_GNU_GETOPT X#define GETOPT(argc, argv, opts) gnu_getopt(argc, argv, opts) X#else X#define GETOPT(argc, argv, opts) getopt(argc, argv, opts) X#endif /* USE_GNU_GETOPT */ X#endif /* GETOPT */ X X#endif /* GETOPT_H */ SHAR-EOF chmod 444 getopt.h if [ `wc -c gfile.1 <<'SHAR-EOF' X.\" @(#)$Id: gfile.1,v 1.2 1997/02/13 14:37:24 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for GFILE(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:24 $) X.TH GFILE 1J "SCCS ToolKit" X.SH NAME Xgfile \(em print name of g-file given name of SCCS file (s-file) X.SH SYNOPSIS X\fBgfile\fP file [...] X.SH DESCRIPTION X\fBGfile\fP analyses the names supplied and prints a modified version Xof each name on a separate line of standard output. XThe modification is to remove the `\*cs.\*d' prefix to the s-file, and if the Xprevious directory name in the path is either `\*cSCCS\*d' or `\*csccs\*d', Xthat is removed too. XThe changes are purely lexical; there is no checking whether the files or Xdirectories exist. XIf the name does not correspond to an s-file, it is passed through unchanged. X.SH "SEE ALSO" Xsfile(1J), sccsfile(1J) X.SH BUGS XNone known. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 gfile.1 if [ `wc -c gfile.sh <<'SHAR-EOF' X: "@(#)$Id: gfile.sh,v 1.2 1992/12/29 10:47:51 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Print names of g-files for given s-files X# Works on purely textual basis X# Handles paranoid cases such as: SCCS/s.sccs/s.dddd/s.junk// X Xal $* | Xsed -e 's%//*$%%' \ X -e 's%SCCS/s\.\([^/][^/]*\)$%\1%' \ X -e 's%sccs/s\.\([^/][^/]*\)$%\1%' \ X -e 's%s\.\([^/][^/]*\)$%\1%' \ X -e 's%^$%/%' SHAR-EOF chmod 444 gfile.sh if [ `wc -c instfile.sh <<'SHAR-EOF' X: "@(#)$Id: instfile.sh,v 1.3 1997/06/02 21:45:00 johnl Exp $" X# X# @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Install file X# Put in named directory belonging to owner, group and with permissions set X Xcase $# in X5) if [ ! -f $1 ] X then X echo "$0: $1 not found" X exit 1 X fi X dname=$2/`dirname $1` X if [ ! -d $dname ] X then X echo "$0: $dname is not a directory" X exit 1 X fi X mv $1 tmp.$$ # Save new file (just in case it is in correct place) X rm -f $2/$1 # Remove existing destination file X mv tmp.$$ $2/$1 # Store new file in correct place X set -e X chmod $5 $2/$1 X chgrp $4 $2/$1 X chown $3 $2/$1 X ;; X*) echo "Usage: $0 file dir owner group perms" >&2 X exit 1;; Xesac SHAR-EOF chmod 444 instfile.sh if [ `wc -c jlss.h <<'SHAR-EOF' X/* X@(#)File: $RCSfile: jlss.h,v $ X@(#)Version: $Revision: 1.5 $ X@(#)Last changed: $Date: 1997/06/02 16:24:26 $ X@(#)Purpose: JLSS Library Functions X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X#ifndef JLSS_H X#define JLSS_H X X#ifdef MAIN_PROGRAM X#ifndef lint Xstatic const char jlss_h[] = "@(#)$Id: jlss.h,v 1.5 1997/06/02 16:24:26 johnl Exp $"; X#endif /* lint */ X#endif /* MAIN_PROGRAM */ X X#include X Xextern FILE *efopen(const char *name, const char *mode); Xextern char *vstrcpy(char *s1, int n, ...); Xextern const char *cistrstr(const char *s1, const char *s2); Xextern int cistrcmp(const char *s1, const char *s2); Xextern void fcopy(FILE *f1, FILE *f2); Xextern void image_print(FILE *fp, long offset, const char *buffer, long nbytes); X X#endif /* JLSS_H */ SHAR-EOF chmod 444 jlss.h if [ `wc -c jlss.sh <<'SHAR-EOF' X: "@(#)$Id: jlss.sh,v 3.3 1997/06/09 20:44:01 johnl Exp $" X# X# @(#)Generic JLSS Installation and Uninstallation Tool X# @(#)(C) Copyright JLSS 1992-93,97 X X################################################################ X# This script may be run by Bourne Shell or Korn Shell # X################################################################ X# This is a big script to enable all the products installed # X# using this system to be handled on both installation and # X# uninstallation with only two auxilliary files -- the `.lst' # X# file and the `.ins' file. And too make life about as easy # X# as possible for the users, they only have to type 3 words # X# once they have set the environment correctly: # X# Either: jlss install prodcode # X# Or: jlss uninstall prodcode # X# where "prodcode" is the code name used by JLSS to identify # X# the set of software which is to be installed or uninstalled. # X# The corresponding configuration files are prodcode.lst and # X# prodcode.ins, and these are either in the current directory # X# "." or in "./etc". The software can be installed in either # X# the current directory or some other directory, and the other # X# directory need not exist prior to installing the software. # X################################################################ X# This script insists that root runs it to ensure that all the # X# mkdir, chmod, chgrp and chown commands succeed. If the user # X# will have sufficient privileges without being root, then the # X# test in the "Check Authorisation" section can be removed and # X# installation will proceed without problems. # X# Set JLSS_NONROOT_INSTALL to suppress the root check. # X# Note that you can set CHOWN, CHGRP and CHMOD in the environ- # X# ment if desired. This should be able to do any damage. # X################################################################ X# The script is fussy about the environment variables set in # X# the configuration file so that any "exec" scripts can tell # X# where the software has been placed. # X################################################################ X X################################################################ X# Sample installation configuration file # X################################################################ X# NB: Some variable names in the configuration file are fixed. # X# These are: envdir, envusr, envgrp, envtmp, defdir, # X# defusr, defgrp, deftmp, IN_MSG, IN_TRAP, RM_MSG, # X# RM_TRAP, PRODUCT, FILELIST # X# Other variables can be defined to suit the installation. # X# eg for FGLGEN, FGLGENBIN can be defined and exported for use # X# by the customisation script. The environment variables in # X# IN_MSG etc could be spelt out literally (eg SCCSDIR instead # X# of $envdir), but envdir etc must be set. # X################################################################ X# X#envdir=SCCSDIR X#defdir=/usr/local X#envusr=SCCSUSR X#defusr=bin X#envgrp=SCCSGRP X#defgrp=bin X#envtmp=SCCSTMP X#deftmp=${TMPDIR:-/tmp}/jlss X# X#PRODUCT='SCCS ToolKit Version 1 (1992-12-29)' X# X#IN_MSG=' X#echo " Base Directory: $envdir=$DIR" X#echo " Owner: $envusr=$USR" X#echo " Group: $envgrp=$GRP" X#echo "" X#echo "The executables will go in $envdir/bin" X#echo "The documentation will go in $envdir/doc" X#echo "The other files will go in $envdir/etc" X#' X# X#IN_TRAP=" X#echo 'Set: $envdir to define the location of the programs' X#echo ' $envusr to define the owner' X#echo ' $envgrp to define the group' X#trap 0 X#exit 1" X# X#RM_MSG=' X#echo " Base Directory: $envdir=$DIR" X#echo " Owner: $envusr=$USR" X#echo " Group: $envgrp=$GRP" X#echo "" X#echo "The executables were placed in $envdir/bin" X#echo "The documentation were placed in $envdir/doc" X#echo "The other files were placed in $envdir/etc" X#' X# X#RM_TRAP=" X#echo 'Set: $envdir to define the location of the programs' X#echo ' $envusr to define the owner' X#echo ' $envgrp to define the group' X#echo ' $envtmp to define where the files are to be moved to' X#trap 0 X#exit 1" X# X#FILELIST=etc/sccs.lst X################################################################ X X####################### X# Check authorisation # X####################### X Xarg0=`basename $0 .sh` X Xif [ -z "$JLSS_NONROOT_INSTALL" ] Xthen X uid=`id | sed 's/uid=\([0-9][0-9]*\)[^0-9].*/\1/'` X case "$uid" in X 0) : OK;; X *) echo "$arg0: You must be root to install this software" >&2 X exit 1;; X esac Xfi X X: ${CHGRP:=chgrp} X: ${CHOWN:=chown} X: ${CHMOD:=chmod} X X############# X# Functions # X############# X Xusage(){ X echo "Usage: $arg0 [install|uninstall] product" >&2 X exit 1 X} X Xconfig(){ X error "fault in configuration file $config" X} X Xerror(){ X { X echo "$arg0: $*" X echo "$arg0: please report this to your supplier" X echo X [ -z "$PRODUCT" ] && echo "*** $MODE failed ***" X [ -n "$PRODUCT" ] && echo "*** $MODE of $PRODUCT failed ***" X echo X } >&2 X exit 1 X} X Xmkpath(){ X # Make all directories leading to named directory X echo $file | X awk -F/ '{ string = ""; X # $1 is empty X for (i = 2; i <= NF; i++) { X string = string "/" $i; X print string; X } X }' | X while read directory X do X if [ ! -d $directory ] X then X mkdir $directory X ${CHMOD} $perms $directory X ${CHGRP} $group $directory X ${CHOWN} $owner $directory X fi X done X} X Xwarn(){ X echo "$arg0: $*" 1>&2 X} X Xerror(){ X echo "$arg0: $*" 1>&2 X exit 1 X} X Xchk_usrgrp(){ X tmp=./jlss.$$ X trap "rm -f $tmp; exit 1" 1 2 3 13 15 X cp /dev/null $tmp X if [ -n "$JLSS_NONROOT_INSTALL" ] X then X # Check whether user can set user to specified user X if ${CHOWN} $USR $tmp >/dev/null 2>&1 X then : OK X else X warn "Cannot use '$CHOWN' to set owner to $USR" >&2 X CHOWN=: X fi X # Check whether user can set group to specified group X if ${CHGRP} $GRP $tmp >/dev/null 2>&1 X then : OK X else X warn "Cannot use '$CHGRP' to set group to $GRP" >&2 X CHGRP=: X fi X else X # Check that user and group exist X if ${CHOWN} $USR $tmp >/dev/null 2>&1 X then : OK X else error "User $USR is not valid" >&2 X fi X if ${CHGRP} $GRP $tmp >/dev/null 2>&1 X then : OK X else error "Group $GRP is not valid" >&2 X fi X fi X rm -f $tmp X trap 1 2 3 13 15 X} X X################### X# Check arguments # X################### X Xcase $# in X2) case $1 in X install) MODE=Installation;; X uninstall) MODE=Uninstallation;; X *) usage;; X esac;; X*) usage;; Xesac X XPATH=$PATH:.:etc Xexport PATH X X############################# X# Locate configuration file # X############################# X Xconfig=$2.ins Xif [ -f $config -a -r $config ] Xthen : OK Xelif [ -f etc/$config -a -r etc/$config ] Xthen : OK Xelse X echo "$arg0: cannot locate configuration file $config for ${1}ing $2" >&2 X exit 1 Xfi X X########################### X# Read configuration file # X########################### X X# Ensure that we don't get affected by stray environment variables XFILELIST= XDIR= XUSR= XGRP= XTMP= XPRODUCT= XIN_MSG= XRM_MSG= XRM_TRAP= XIN_TRAP= Xenvdir= Xenvgrp= Xenvusr= Xenvtmp= Xdefdir= Xdefgrp= Xdefusr= Xdeftmp= X X. $config X X####################### X# Check configuration # X####################### X XPRODUCT=`echo "$PRODUCT" | sed 's/[$]Product: \(.*\) [$]/\1/'` X X[ -z "$envdir" ] && config X[ -z "$envgrp" ] && config X[ -z "$envusr" ] && config X[ -z "$envtmp" ] && config X[ -z "$defdir" ] && config X[ -z "$defgrp" ] && config X[ -z "$defusr" ] && config X[ -z "$deftmp" ] && config X Xeval "DIR=\${$envdir:=$defdir}" Xeval "USR=\${$envusr:=$defusr}" Xeval "GRP=\${$envgrp:=$defgrp}" Xeval "TMP=\${$envtmp:=$deftmp}" X X# Yes, the $ characters really are required! Xexport $envdir $envusr $envgrp $envtmp X X[ -z "$FILELIST" ] && config X[ -z "$IN_MSG" ] && config X[ -z "$IN_TRAP" ] && config X[ -z "$PRODUCT" ] && config X[ -z "$RM_MSG" ] && config X[ -z "$RM_TRAP" ] && config X X################################# X# Installation & Uninstallation # X################################# Xif [ $MODE = Installation ] Xthen X X echo "" X echo "" X echo "$MODE of $PRODUCT" X echo "" X echo "The software will be installed as follows:" X echo "" X eval "$IN_MSG" X echo "" X echo "If this is incorrect, hit the INTERRUPT key." X echo "If this is correct, hit the RETURN key." X echo "" X echo "" X X trap "$IN_TRAP" 0 2 3 X read x || exit X echo X trap 0 2 3 X X chk_usrgrp X X echo "$MODE of $PRODUCT started...\c" X sleep 5 X echo "" X echo "" X X # Install programs and files X sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' $FILELIST | X while read file type link owner group perms X do X if [ $owner = - ] ; then owner=$USR ; fi X if [ $group = - ] ; then group=$GRP ; fi X case "$type" in X directory) X dirlist="$file $dirlist" X file=$DIR/$file X echo "Installing directory $file" X [ -d $file ] || mkpath $file X ;; X deleted) X rm -f $DIR/$file X ;; X link) X file=$DIR/$file X link=$DIR/$link X [ -f $link ] || error "missing link file $link" X rm -f $file X ln $link $file X ;; X symlink) X file=$DIR/$file X link=$DIR/$link X [ -f $link ] || error "missing link file $link" X rm -f $file X ln -s $link $file X ;; X file) X [ -f $file ] || error "$file not found" X dname=$DIR/`dirname $file` X [ -d $dname ] || error "$dname is not a directory" X mv $file tmp.$$ # Save file (in case it is already in situ) X rm -f $DIR/$file # Remove existing destination file (if any) X mv tmp.$$ $DIR/$file # Store new file in correct place X ${CHMOD} $perms $DIR/$file X ${CHGRP} $group $DIR/$file X ${CHOWN} $owner $DIR/$file X ;; X exec) X file=$DIR/$file X if [ "$link" != "-" ] X then link=$DIR/$link X else link= X fi X [ -x $file ] || error "$file not executable" X $file $link X ;; X *) error "unknown file type $type" X ;; X esac X done X X echo "" X echo "$MODE of $PRODUCT complete" X echo "" X Xelse X X echo "" X echo "" X echo "$MODE of $PRODUCT" X echo "" X echo "The software was installed as follows:" X echo "" X eval "$RM_MSG" X echo "" X echo "The uninstalled software will be moved to:" X echo "" X echo " Junk Directory: $envtmp=$TMP" X echo "" X echo "If this is incorrect, hit the INTERRUPT key." X echo "If this is correct, hit the RETURN key." X echo "" X echo "" X X trap "$RM_TRAP" 0 2 3 X read x || exit X echo X trap 0 2 3 X X chk_usrgrp X X echo "$MODE of $PRODUCT started...\c" X sleep 5 X echo "" X echo "" X X # Uninstall programs and files X sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' $FILELIST | X { X while read file type link owner group perms X do X if [ $owner = - ] ; then owner=$USR ; fi X if [ $group = - ] ; then group=$GRP ; fi X case "$type" in X directory) X dirlist="$DIR/$file $dirlist" X file=$TMP/$file X echo "Creating directory $file" X [ -d $file ] || mkpath $file X ;; X deleted|exec) X : OK X ;; X file|link) X ifile=$DIR/$file X jfile=$TMP/$file X [ -f $ifile ] && mv $ifile $jfile X ;; X *) X error "unknown file type $type" X ;; X esac X done X rmdir $dirlist 2>/dev/null X } X X echo "" X echo "$MODE of $PRODUCT complete" X echo "" X echo "Remember to remove the software from $TMP as soon as convenient" X echo "" X Xfi SHAR-EOF chmod 444 jlss.sh if [ `wc -c la.1 <<'SHAR-EOF' X.\" @(#)$Id: la.1,v 1.2 1996/09/24 18:27:24 johnl Exp $ X'\" Documentation for $RCSfile: la.1,v $ X.TH LA 1 "Sphinx" X.SH NAME Xla \(em print last argument X.SH SYNOPSIS X\fBla\fP ``$@'' X.SH DESCRIPTION X\fBLa\fP is used inside shell scripts to find the last argument Xregardless of how many arguments were supplied. XIt is useful inside shell scripts which provide a front-end to Xprograms like \fBcp(1)\fP where the last argument should be a Xdirectory. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd X.br X21st December 1987 SHAR-EOF chmod 444 la.1 if [ `wc -c la.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: la.c,v $ X@(#)Version: $Revision: 1.3 $ X@(#)Last changed: $Date: 1997/02/05 10:56:43 $ X@(#)Purpose: Print last argument X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1987,1990,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X#include X X#ifndef lint Xstatic const char sccs[] = "@(#)$Id: la.c,v 1.3 1997/02/05 10:56:43 johnl Exp $"; X#endif X Xint main(int argc, char **argv) X{ X if (argc > 1) X puts(argv[argc-1]); X return(0); X} SHAR-EOF chmod 444 la.c if [ `wc -c latest.1 <<'SHAR-EOF' X.\" @(#)$Id: latest.1,v 1.2 1997/02/13 14:37:25 johnl Exp $ X'\" @(#)Manual page: Latest -- print times of last change to SCCS files X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:25 $) X.TH LATEST 1S "Sphinx UNIX Tools" X.SH NAME Xlatest \(em print latest modification time of SCCS file(s) X.SH SYNOPSIS X\fBlatest\fP [-opt] file [...] X.SH DESCRIPTION X\fBLatest\fP is a simple interface to \fBprs\fP(1). XIt prints out the file name, version number, date and time of the Xlatest version of the SCCS files named on the command line. XAny options to \fBprs\fP apart from the `\-d' option could be Xspecified on the command line too. X.SH "SEE ALSO" Xprs(1) X.SH DIAGNOSTICS XAs produced by prs(1) X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd. X.br X26th September 1989 SHAR-EOF chmod 444 latest.1 if [ `wc -c latest.sh <<'SHAR-EOF' X: "@(#)$Id: latest.sh,v 1.5 1997/02/13 15:49:39 johnl Exp $" X# X# Print name and latest SCCS version number for specified arguments X Xsfile $* | Xprs -d':F: :I: :D: :T:' - | Xawk '{ printf("%-40s %-6s %s %s\n", $1, $2, $3, $4);}' SHAR-EOF chmod 444 latest.sh if [ `wc -c memmove.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: memmove.c,v $ X@(#)Version: $Revision: 1.4 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: Simulate MEMMOVE(3) X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1991,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X#include X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: memmove.c,v 1.4 1997/06/02 16:41:57 johnl Exp $"; X#endif X Xvoid *memmove(void *s1, const void *s2, size_t n) X{ X const char *t; X char *t1 = (char *)s1; X const char *t2 = (const char *)s2; X void *s = s1; X X if (t1 < t2) X { /* Copy forwards */ X t = t1 + n; X while (t1 < t) X *t1++ = *t2++; X } X else X { /* Copy backwards */ X t = t2; X t1 += n; X t2 += n; X while (t2 > t) X *--t1 = *--t2; X } X return(s); X} X X#ifdef TEST X X#include X Xint main(void) X{ X char buffer[80]; X int ok = 0; X X strcpy(&buffer[0], "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); X printf("buffer = %s\n", buffer); X printf("memmove(&buffer[0], &buffer[9], 10);\n"); X memmove(&buffer[0], &buffer[9], 10); X printf("buffer = %s\n", buffer); X if (strcmp(buffer, "JKLMNOPQRSKLMNOPQRSTUVWXYZ") != 0) X ok++, printf("** FAILED **\n"); X printf("memmove(&buffer[5], &buffer[0], 10);\n"); X memmove(&buffer[5], &buffer[0], 10); X printf("buffer = %s\n", buffer); X if (strcmp(buffer, "JKLMNJKLMNOPQRSPQRSTUVWXYZ") != 0) X ok++, printf("** FAILED **\n"); X X if (ok == 0) X printf("OK\n"); X return(0); X} X X#endif /* TEST */ SHAR-EOF chmod 444 memmove.c if [ `wc -c mkbod.sh <<'SHAR-EOF' X: "@(#)$Id: mkbod.sh,v 2.3 1997/06/09 20:07:59 johnl Exp $" X# X# @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Make Binary-Only Distribution X Xarg0=`basename $0 .sh` X Xif [ $# -ne 3 ] Xthen X echo "Usage: $arg0 source object bod-file" >&2 X exit 1 Xfi X XSOURCEDIR=${1} XOBJECTDIR=${2} X X: ${CP:="cp -p"} # POSIX.2 X Xsed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' ${3} | X{ Xstatus=0 Xwhile read dist comp Xdo X X case $dist in # Handle variable setting lines X *=*) eval $dist $comp X continue;; X esac X X eval target=$OBJECTDIR/$dist X if [ ! -f $target ] X then X tgtdir=`dirname $target` X [ -d $tgtdir ] || mkpath $tgtdir X echo $target X eval comp=$comp X case $comp in X /*) # Absolute X if [ ! -f $comp ] X then X echo "$arg0: cannot find $comp" >&2 X status=1 X continue X fi X $CP $comp $target X ;; X *) # Relative X eval source=$SOURCEDIR/$comp X if [ ! -f $source ] X then X echo "$0: cannot find $source" >&2 X status=1 X continue X fi X if [ $source != $target ] X then X $CP $source $target X fi X ;; X esac X fi X Xdone Xexit $status X} SHAR-EOF chmod 444 mkbod.sh if [ `wc -c mkpath.sh <<'SHAR-EOF' X: "@(#)$Id: mkpath.sh,v 1.7 1997/06/02 21:45:00 johnl Exp $" X# X# @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Make all directories down to named directory X Xarg0=`basename $0 .sh` Xusage(){ Xecho "Usage: $arg0 [-o owner] [-g group] [-p perms] directory [...]" >&2 Xexit 1 X} X Xset -- `getopt o:g:p: "$@"` X Xwhile [ $# -gt 0 ] Xdo X case $1 in X --) shift; break;; X -o) owner=$2;; X -g) group=$2;; X -p) perms=$2;; X -*) usage;; X *) break;; X esac X shift 2 Xdone X Xcase $# in X0) usage;; Xesac X Xfor directory in $* Xdo X echo $directory Xdone | Xawk -F/ ' { string="" X pad="" X for (i = 1; i <= NF; i++) { X string=string pad $i X if (string != "") print string X pad="/" X } X }' | Xsort -u | Xwhile read directory Xdo X if [ ! -d $directory ] X then X mkdir $directory X [ -z "$perms" ] || chmod $perms $directory X [ -z "$group" ] || chgrp $group $directory X [ -z "$owner" ] || chown $owner $directory X fi Xdone SHAR-EOF chmod 444 mkpath.sh if [ `wc -c mkversion.sh <<'SHAR-EOF' X: "@(#)$Id: mkversion.sh,v 1.2 1997/06/09 17:42:11 johnl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Branding Tool (Poor Man's Version of VC) X XVERSION="2 (1997-06-09)" XREPLACE="\$Product: SCCS ToolKit Version $VERSION \$" X Xsed -e "s%[:]SQLCMD:%$REPLACE%" \ X -e "s%[:]PRODUCT:%$REPLACE%" $* SHAR-EOF chmod 444 mkversion.sh if [ `wc -c newsccs.1 <<'SHAR-EOF' X.\" @(#)$Id: newsccs.1,v 1.3 1997/02/13 14:37:25 johnl Exp $ X'\" @(#)Manual page: NEWSCCS -- Install files under SCCS X.ds fC "Version: $Revision: 1.3 $ ($Date: 1997/02/13 14:37:25 $) X.TH NEWSCCS 1S "Sphinx UNIX Tools" X.SH NAME Xnewsccs \(em install files under SCCS X.SH SYNOPSIS X\fBnewsccs\fP [-gEX] file [file ...] X.SH DESCRIPTION X\fBNewsccs\fP is a front-end for \fBadmin\fP which installs files under SCCS. XFor each file in its argument list, it checks that the file exists, and that Xthe length of the file name is 12 characters or fewer. XIt then looks to see if there is a directory called `SCCS' or `sccs' immediately Xunder the directory containing the file; if there is, the s-file will be put Xin that directory, and if not, the s-file will be placed in the same Xdirectory as the g-file. XThe file is then put under SCCS; if the \fBadmin\fP command succeeds, the Xg-file is renamed and the s-file is extracted. XIf the \fBget\fP succeeds too, the original file and the gotten file are both Xremoved. XIf anything fails, the original file is left untouched. X.P XThe `\fB-g\fP' flag indicates that \fBnewsccs\fP should leave the gotten file Xin the relevant directory. X.P XBy default, \fBnewsccs\fP applies the option `\fB-fi\fP' to \fBadmin\fP; Xthis insists on at least one ID keyword in the g-file. XThe `\fB-X\fP' option suppresses this requirement. X.P XIt is occasionally useful to install a file under SCCS and to immediately Xextract it for editing; the `\fB-E\fP' option does this. XIt cannot, regrettably, be the `\fB-e\fP' option since this is used by X\fBadmin\fP to erase logins from the list that are allowed to make Xchanges to the s-file. X.SH "SEE ALSO" XSCCS system manual pages. X.SH DIAGNOSTICS XVarious error messages can be produced, especially by the SCCS commands. XThe return status of \fBnewsccs\fP is 0 if all the files were successfully Xinstalled under SCCS. XIf any file fails, the return status is 1. XIf one of the files fails, processing on the other files continues. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd. X.br X8th September 1989 SHAR-EOF chmod 444 newsccs.1 if [ `wc -c newsccs.sh <<'SHAR-EOF' X: "@(#)$Id: newsccs.sh,v 2.13 1992/12/29 10:52:53 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Install files under SCCS X XADMIN=${ADMIN:-"admin"} XGET=${GET:-"get"} Xfiflag=-fi # Insist on ID keywords Xadflags=-fn # Insert null deltas when necessary Xgetflag=no Xarg0=`basename $0` X Xwhile [ $# -gt 0 ] Xdo X case "$1" in X -g) getflag=yes X shift;; X -E) gtflags="$gtflags -e" X getflag=yes X shift;; X -X) fiflag="" X shift;; X -s) gtflags="$gtflags -s" X echodev=">/dev/null" X shift;; X -*) adflags="$adflags '$1'" X shift;; X *) break;; X esac Xdone X Xcase $# in X0) echo "Usage: $arg0 [-EXg] [-adminflags] file [file ...]" >&2 X exit 1;; Xesac X Xadflags="$adflags $fiflag" X Xstatus=0 Xfor file in $* Xdo X # Check existence of file X if [ ! -f $file ] X then X if [ -d $file ] X then echo "$arg0: $file is a directory" >&2 X elif [ -b $file -o -c $file ] X then echo "$arg0: $file is a device" >&2 X elif [ -p $file ] X then echo "$arg0: $file is a fifo" >&2 X else echo "$arg0: file $file does not exist" >&2 X fi X continue X fi X X dname=`dirname $file` X if [ "$dname" = "." ] X then dname= X elif [ "$dname" != "/" ] X then dname=$dname/ X fi X bname=`basename $file` X X # Check length of basename X if [ `echo "$bname" | wc -c` -gt 13 ] X then X echo "$arg0: basename of file is too long -- $bname" >&2 X continue X fi X X eval echo $file $echodev X X if [ -d ${dname}SCCS ] X then sccs=${dname}SCCS/ X elif [ -d ${dname}sccs ] X then sccs=${dname}sccs/ X else sccs=${dname} X fi X if eval $ADMIN -i$file $adflags ${ADMIN_FLAGS} ${sccs}s.$bname X then X ofile=${dname}o.$bname X mv $file $ofile X if $GET $gtflags ${sccs}s.$bname X then X # OK -- cleanup X rm -f $ofile X if [ $getflag = no ] X then X rm -f $bname $file X elif [ $bname != $file ] X then X rm -f $file X mv $bname $file /dev/null 2>&1 X # Redirections don't let mv ask questions X fi X else X # Failed -- restore file X status=1 X rm -f $file $bname X if [ $getflag = no ] X then X mv $ofile $file X fi X fi X else X status=1 X fi Xdone Xexit $status SHAR-EOF chmod 444 newsccs.sh if [ `wc -c pfiles.1 <<'SHAR-EOF' X.\" @(#)$Id: pfiles.1,v 1.2 1997/02/13 14:37:26 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for PFILES(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:26 $) X.TH PFILES 1J "SCCS ToolKit" X.SH NAME Xpfiles \(em print names of all p-files underneath specified directories X.SH SYNOPSIS X\fBpfiles\fP [directory ...] X.SH DESCRIPTION X\fBPfiles\fP uses \fIfind(1)\fP to locate all the p-files underneath Xthe specified directories (defaulting to the current directory if no Xdirectory is specified). XAs a matter of detail, the options to \fIfind\fP could be modified by Xincluding them at the end of the directory list. XThis could be useful to specify `\*c-mount\*d', for instance. X.SH BUGS XNone known. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 pfiles.1 if [ `wc -c pfiles.sh <<'SHAR-EOF' X: "@(#)$Id: pfiles.sh,v 1.3 1997/05/27 08:49:49 johnl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Print all the p-files under the named directories X Xexec find ${*:-.} -name 'p.*' -print SHAR-EOF chmod 444 pfiles.sh if [ `wc -c sccs.1 <<'SHAR-EOF' X.\" @(#)$Id: sccs.1,v 1.5 1997/02/13 14:37:27 johnl Exp $ X'\" @(#)Manual Page: SCCS -- front-end for real SCCS commands X.ds fC "Version: $Revision: 1.5 $ ($Date: 1997/02/13 14:37:27 $) X.TH SCCS 1 "Sphinx UNIX Tools" X.SH NAME Xsccs \(em front-end for SCCS X.SH SYNOPSIS X\fBsccs\fP sccscmd [-opt] [file ...] X.br X\fBsccscmd\fP [-opt] [file ...] X.SH DESCRIPTION X\fBSccs\fP is a front-end for the SCCS commands which Xhas two roles: Xit can be a \s-2SUID\s0 program which Xallows users access to files via SCCS which they would not Xotherwise be allowed to access, Xand it endeavours to convert names supplied by the user into XSCCS file names. X.P XThe \s-2SUID\s0 capability is useful Xwhen a number of users are working on a project and yet the Xadministrator wishes to know (or control) which users can do what with the XSCCS files. XThe normal technique is to create an administrative login to own Xthe files, and to set up an SCCS directory under each working Xdirectory which has limited permissions; specifically, only the Xadministrator can create files in the directory so only the Xadministrator can get SCCS files out for changing. XThe \s-2SUID\s0 property means that the administrator need not do Xit in person, of course. XEach user works as themselves and uses the \s-2SUID\s0 \fBsccs\fP Xto access the SCCS files. XThe SCCS system records the real UID in the SCCS file, Xso any changes can be tracked down. X.P XThis version of \fBsccs\fP may be used in either of two ways. XThe standard use is as a command prefix X(analogous to \fBnice\fP or \fBtime\fP), in which case, Xthe first argument is the name of the SCCS command to be executed, Xand the other arguments are the arguments to that SCCS command. XAlternatively, \fBsccs\fP may also (or instead) be given Xlinks which have the same name as the SCCS commands. XThis gives better control, since the administrator could ensure Xthat the \fBadmin\fP command was not available to most users. XEither way, the program refuses to execute any programs which are Xnot in the built-in list of SCCS command names. XWhen the program is compiled, the directory in which the real XSCCS commands are installed must be specified, so the system is Xas secure as that directory. XDo not forget that the SCCS system allows the administrator to Xspecify a list of login names which are allowed to make changes Xto an SCCS file independently of the permissions on the file. X.P XTo do the file name conversion, the program checks each argument. XIf it starts with a `\-' sign, it is an option and is left untouched. XIf it is a name which which does not start with `s.', Xor if it starts with `s.' but is not accessible, Xthe name is transformed to see whether an Xalternative accessible name can be found. XIf the name does not start with `s.', Xthis is applied in front of the name. XIf the file is still inaccessible, the directory name `SCCS' is Xinserted into the path to see whether an accessible file of that Xname exists. XIf not, the alternative directory name `sccs' is inserted; Xif that fails too, the user supplied name is used unchanged and Xthe SCCS program that is executed will provide the appropriate diagnostic. X.SH "SEE ALSO" Xadmin(1), comb(1), cdc(1), delta(1), get(1), Xhelp(1), prs(1), rmdel(1), sact(1), sccsdiff(1), unget(1), Xval(1), what(1) X.SH DIAGNOSTICS XVarious, and intended to be self-explanatory. XOther diagnostics come from the official SCCS programs. X.SH WARNING XOnly \fBadmin\fP, \fBcdc\fP, \fBdelta\fP, \fBget\fP and \fBunget\fP Xshould be SUID programs. XThe other programs come in two categories: X.in 5n X.ti -5n X1. X.sp -1v X\fBrmdel\fP and \fBcomb\fP are dangerous because Xthey can be used to destroy valuable change information. XOnly someone whose real UID is the same as the SUID should be Xable to use these programs. X.ti -5n X2. X.sp -1v X\fBhelp\fP, \fBprs\fP, \fBsact\fP, \fBsccsdiff\fP and X\fBval\fP do not need to be SUID programs to be able to work because they Xdo not modify the s-file at all. X.in X.P XBecause the program \fBsccs\fP can be used to run any of the SCCS commands, Xit should not be made SUID. X.SH CONFIGURATION XWhen \fBsccs\fP is compiled, you must define the directory where the real XSCCS commands live. XThis defaults to /usr/bin, but if you intend to install the front-end in place Xof the real commands, they should probably be put in somewhere like X\*c/usr/lib/sccs\*d or \*c/usr/sccs\*d. XSimilarly, it is possible to redefine the names of the directories Xwhich are searched. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd X.br X21st December 1987 SHAR-EOF chmod 444 sccs.1 if [ `wc -c sccs.bod <<'SHAR-EOF' X# @(#)$Id: sccs.bod,v 1.5 1997/06/09 20:30:32 johnl Exp $ X# X# @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X# @(#)Definitive list of files -- Binary-Only Distribution X# X# -- The Distributed file column contains the name of a file in X# the distribution directory. X# -- The Compiled file column contains the name of the file in the X# working directory. X# X# -- Note that it is possible to rename files using this mechanism. X# X# -- Note that it is possible to include variable definitions as in a X# shell script. If necessary, these can include defaults such as X# ${JH:-/u/j/h} but not termination constructs such as: ${XYZ:?} X# Note that spaces are not allowed in definitions. X# X# -- Comment lines start with a hash (#) X# -- Blank lines are ignored X# -- Tabs are non-preferred characters X################################################################## X X################################################################## X# Distributed file Compiled file # X################################################################## X X# SCCS tools Xbin/al al Xbin/delget delget Xbin/dod dod Xbin/escape escape Xbin/gfile gfile Xbin/la la Xbin/latest latest Xbin/newsccs newsccs Xbin/pfiles pfiles Xbin/sccs sccs Xbin/sccs2rcs sccs2rcs Xbin/sccschk sccschk Xbin/sccsfile sccsfile Xbin/sccsinst sccsinst Xbin/sccsmv sccsmv Xbin/sccssid sccssid Xbin/sfile sfile Xbin/undelta undelta Xbin/what what X X# SCCS Documentation Xman/man1/al.1 al.1 Xman/man1/delget.1 delget.1 Xman/man1/dod.1 dod.1 Xman/man1/escape.1 escape.1 Xman/man1/gfile.1 gfile.1 Xman/man1/la.1 la.1 Xman/man1/latest.1 latest.1 Xman/man1/newsccs.1 newsccs.1 Xman/man1/pfiles.1 pfiles.1 Xman/man1/sccs.1 sccs.1 Xman/man1/sccs.doc sccs.doc Xman/man1/sccschk.1 sccschk.1 Xman/man1/sccsfile.1 sccsfile.1 Xman/man1/sccsinst.1 sccsinst.1 Xman/man1/sccsmv.1 sccsmv.1 Xman/man1/sccssid.1 sccssid.1 Xman/man1/sfile.1 sfile.1 Xman/man1/undelta.1 undelta.1 Xman/man1/what.1 what.1 X X# Distribution tools Xetc/instfile instfile Xjlss jlss Xetc/mkpath mkpath Xetc/sccs.ins sccs.ins Xetc/sccs.lst sccs.lst SHAR-EOF chmod 444 sccs.bod if [ `wc -c sccs.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: sccs.c,v $ X@(#)Version: $Revision: 6.3 $ X@(#)Last changed: $Date: 1997/06/09 20:17:25 $ X@(#)Purpose: Interface to SCCS commands X@(#)Author: J Leffler / A Waters X@(#)Copyright: (C) JLSS 1987-1992,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X/* X** Interface to SCCS commands. X** X** This program provides two capabilities. X** 1. It can be made into a SUID (or SGID) program to allow unprivileged X** people limited access to the SCCS files. This works best when the X** SCCS files are stored in a directory called SCCS with permissions X** 750 (or 755) which is owned by the project administrator, and with X** the program made SUID to the project administrator. The program will X** run the real SCCS programs with sufficient privileges to allow SCCS X** files to be obtained for editing and changes to be made with delta. X** X** 2. To make it easier to use, you do not have to specify the SCCS/s. in X** front of the name of the SCCS file (provided that the SCCS file X** exists). This program is fairly intelligent about what it does and X** does not handle. If the s-file exists in the current directory, it is X** used in preference to the s-file in the SCCS or sccs subdirectories. X** X** 3. By default, it now tries to expand metacharacters if any of the X** filename arguments contain them as well as adding the SCCS subdirectory X** and "s." prefix. This behaviour can be suppressed by defining X** -DNO_METACHAR on the compiler command line. X** X** Exit Status: Normally the exit status of the relevant SCCS command. X** If used incorrectly, produces an error message and exit status 1. X** X** Authors: J.Leffler & A.Waters X*/ X X#define _POSIX_SOURCE 1 /* Ambitious! */ X X#include X#include X#include X#include X#include X#include X#include X X#define MAIN_PROGRAM X#include "stderr.h" X X#define DIM(x) (sizeof(x)/sizeof(*x)) X#define NIL(x) ((x)0) X X#ifndef NO_METACHAR X#define METACHAR X#endif /* NO_METACHAR */ X X#ifndef SCCSDIR X#define SCCSDIR "/usr/bin/" /* Directory containing SCCS commands */ X#endif /* SCCSDIR */ X X#define SCCSFILESIZE 256 /* Max length for SCCS file name */ X#define SCCS1 "SCCS/" /* Directory containing SCCS files */ X#define SCCS2 "sccs/" /* Alternative directory for SCCS files */ X X#define IS_SUID (0x01) X#define IS_PLAIN (0x00) X#define MAX_ARGC (1024) X Xstatic char *dirlist[] = { X "s.", X "SCCS/", X "sccs/", X "SCCS/s.", X "sccs/s.", X 0 X}; X Xstruct Command X{ X char *username; X char *realname; X int flag; X}; Xtypedef struct Command Command; X Xstatic Command sccs_cmds[] = X{ X { "admin", "admin", IS_SUID }, X { "cdc", "cdc", IS_SUID }, X { "comb", "comb", IS_PLAIN }, X { "delta", "delta", IS_SUID }, X { "get", "get", IS_SUID }, X { "help", "help", IS_PLAIN }, X { "sccshelp", "help", IS_PLAIN }, X { "prs", "prs", IS_PLAIN }, X { "rmdel", "rmdel", IS_PLAIN }, X { "sact", "sact", IS_PLAIN }, X { "sccsdiff", "sccsdiff", IS_PLAIN }, X { "unget", "unget", IS_SUID }, X { "val", "val", IS_PLAIN }, X { "what", "what", IS_PLAIN }, X}; X X#ifdef METACHAR Xextern char *argument(int); Xextern char *basename(char *); Xextern char *dirname(char *); Xextern char *vstrcpy(char *, int, char *,...); Xextern int metaname(char *arg); Xextern void shell_glob(char *arg); Xstatic int sccsglob(char *arg, int i, char **nargv); X#endif /* METACHAR */ X Xstatic char *newarg(char *, char *); Xstatic char *sccsfile(char *); Xstatic int charcount(char *s, char m); Xstatic void use_sh(int, char **); X X#ifndef lint Xstatic const char sccs[] = "@(#)$Id: sccs.c,v 6.3 1997/06/09 20:17:25 johnl Exp $"; X#endif X Xint main(int argc, char **argv) X{ X char *sccs_cmd; X char *cmd; X char *arg; X char *nargv[MAX_ARGC]; /* Space for new argument list */ X int argindex; X int i; X int resetuid; X X setarg0(argv[0]); X X /* Check how we were called */ X /* Either: sccs_cmd */ X /* Or: sccs sccs_cmd */ X if (strcmp(getarg0(), "sccs") == 0) X { X if (argc <= 1) X usage("sccs_cmd [args ...]"); X sccs_cmd = argv[1]; X argindex = 2; X } X else X { X sccs_cmd = (char *)getarg0(); /* const_cast */ X argindex = 1; X } X X /* Check that name is valid */ X for (i = 0; i < DIM(sccs_cmds); i++) X if (strcmp(sccs_cmd, sccs_cmds[i].username) == 0) X break; X X if (i >= DIM(sccs_cmds)) X error2("Unknown SCCS command", sccs_cmd); X X resetuid = !(sccs_cmds[i].flag & IS_SUID); X X cmd = newarg(SCCSDIR, sccs_cmds[i].realname); X nargv[0] = sccs_cmds[i].realname; X X /* Massage all arguments */ X i = 1; X while (argindex < argc) X { X arg = argv[argindex++]; X if (arg[0] == '-') X nargv[i++] = arg; X else if (strncmp("s.", arg, 2) == 0 && access(arg, 0) == 0) X nargv[i++] = arg; X#ifdef METACHAR X else if (metaname(arg)) X i = sccsglob(arg, i, nargv); /* Metacharacters in file name */ X#endif /* METACHAR */ X else X nargv[i++] = sccsfile(arg); X if (i >= MAX_ARGC) X error("too many arguments"); X } X nargv[i] = NIL(char *); X X if (resetuid) X { X (void)setuid(getuid()); X (void)setgid(getgid()); X } X X (void)execv(cmd, nargv); X X /* Shouldn't really end up here: the only case we */ X /* handle is trying to exec a shell script */ X if (errno == ENOEXEC) X { X nargv[0] = cmd; X use_sh(argc, nargv); /* no return */ X } X X error2("failed to exec command", nargv[0]); X /* NOTREACHED */ X return(1); X} X X/* X** newarg() X** X** allocate an area of memory, and concatenate the two passed strings into X** this area. X** X** return: a pointer to the memory allocated. X*/ Xstatic char *newarg(char *pref, char *suff) X{ X size_t len1; /* size of area required */ X size_t len; /* size of area required */ X char *newarea; /* pointer to area for prefixed arg */ X X len = (len1 = strlen(pref)) + strlen(suff) + 1; X newarea = (char *)malloc(len); X if (newarea == NIL(char *)) X error2("failed to allocate memory", ""); X X (void)strcpy(newarea, pref); X (void)strcpy(newarea + len1, suff); X return(newarea); X} X X/* X** use_sh() X** X** we're trying to execute a command that is a shell script, so we can't X** 'exec' it. Execute a shell to run it. X** X** Note that we set the effective uid back to the real-uid before executing X** the command. Certainly sccsdiff does not require to run set-uid. X*/ Xstatic void use_sh(int argc, char **argv) X{ X char **new_argv; /* points to new argument list */ X char *sh_arg; /* concatentated arguments to sccs */ X register char *p; X register char *s; X register char c; X register int i; X register size_t size; X X /* Calculate size of area required for the argument list */ X /* Enclose each argument in single quotes to preserve spaces */ X for (size = 0, i = 0; i < argc; i++) X size += strlen(argv[i]) + 3 + 3 * charcount(argv[i], '\''); X X if ((sh_arg = (char *)malloc(size)) == NIL(char *)) X error2("failed to allocate memory", ""); X X /* Copy each of the current argv arguments into the new area */ X /* Secure -- arguments containing single quotes are handled */ X for (p = sh_arg, i = 0; i < argc; i++) X { X *p++ = '\''; X s = argv[i]; X while ((c = *s++) != '\0') X { X if (c == '\'') X { X *p++ = c; X *p++ = '\\'; X *p++ = c; X } X *p++ = c; X } X *p++ = '\''; X *p++ = ' '; X } X *(p - 1) = '\0'; X X /* now allocate the new 'argv' area. Note that if 'argc' is already */ X /* >= 3 then we can re-use that area */ X if (argc >= 3) X new_argv = argv; X else if ((new_argv = (char **)malloc(4 * sizeof(char *))) == (char **)0) X error2("failed to allocate memory", ""); X X new_argv[0] = "sh"; X new_argv[1] = "-c"; X new_argv[2] = sh_arg; X new_argv[3] = NIL(char *); X X (void)setuid(getuid()); /* reset euid to uid */ X (void)setgid(getgid()); /* reset egid to gid */ X X (void)execv("/bin/sh", new_argv); X error2("failed to exec /bin/sh", ""); /* no return */ X} X X/* X** split_name -- break name into base and directory X** name is shortened by any trailing slashes. X** base and dir are in allocated space. X*/ Xstatic void split_name(char *name, char **base, char **dir) X{ X size_t l; X char *p; X X l = strlen(name); X X /* Remove trailing slashes -- and worry about "/" */ X while (name[l - 1] == '/' && l > 1) X name[--l] = '\0'; X X /* Split name into directory and basename */ X if ((p = strrchr(name, '/')) == name) X { /* Using root -- and the best of British */ X *dir = ""; X *base = "/"; X } X else if (p != NIL(char *)) X { /* Ordinary path name */ X *base = newarg("", p + 1); X *p = '\0'; X *dir = newarg(name, "/"); X *p = '/'; X } X else X { /* Plain file name */ X *base = name; X *dir = ""; X } X} X X/* X** sccsfile -- try to find a SCCS file corresponding to name X** X** look in same directory as specified file X** then in subdirectory SCCS1 of specified directory X** then in subdirectory SCCS2 of specified directory X** then give up and return original name X** X** name is InOut because split_name()can strip trailing slashes X*/ Xstatic char *sccsfile(char *name) X{ X char *base; X char *dir; X char sccsname[SCCSFILESIZE]; X X split_name(name, &base, &dir); X X /* Insert s. if missing */ X if (strncmp(base, "s.", 2)) X base = newarg("s.", base); X X (void)sprintf(sccsname, "%s%s", dir, base); X if (access(sccsname, 0) == 0) X return(newarg(sccsname, "")); X (void)sprintf(sccsname, "%s%s%s", dir, SCCS1, base); X if (access(sccsname, 0) == 0) X return(newarg(sccsname, "")); X (void)sprintf(sccsname, "%s%s%s", dir, SCCS2, base); X if (access(sccsname, 0) == 0) X return(newarg(sccsname, "")); X X /* Cannot find SCCS file corresponding to name */ X return(name); X} X Xstatic int charcount(char *s, char m) X{ X register char c; X register int n = 0; X X while ((c = *s++) != '\0') X { X if (c == m) X n++; X } X return(n); X} X X#ifdef METACHAR X/* X** Do Shell-like filename expansion to locate SCCS files X*/ Xstatic int sccsglob(char *arg, int i, char **nargv) X{ X int j; X int k; X char buff[512]; X char *s; X struct stat sb; X char *d; X char *b; X X shell_glob(arg); X k = 0; X (void)strcpy(buff, arg); X while (1) X { X j = 0; X s = argument(j++); X if (s != NIL(char *) && (strcmp(s, buff) != 0 || stat(s, &sb) == 0)) X { X while (s != NIL(char *)) X { X nargv[i++] = s; X s = argument(j++); X } X break; X } X else if (dirlist[k] == NIL(char *)) X { X nargv[i++] = s; X break; X } X else X { X d = dirname(arg); X b = basename(arg); X (void)vstrcpy(buff, 4, d, "/", dirlist[k++], b); X shell_glob(buff); X } X } X return(i); X} X X#endif /* METACHAR */ SHAR-EOF chmod 444 sccs.c if [ `wc -c sccs.doc <<'SHAR-EOF' X'\" @(#)$Id: sccs.doc,v 1.1 1993/01/12 22:26:10 jl Exp $ X'\" @(#)SCCS ToolKit X'\" @(#)General Description of SCCS X'\" X.PH "''\s10Company Confidential\s0''" X.PF "'\s8SCCS ToolKit\s0'Page %'\s8Version $Revision: 1.1 $ $Date: 1993/01/12 22:26:10 $\s0'" X'\" X'\" ----------------------------------------------------- X'\" X.S 18 X.ft B X.ce 99 XUsing the SCCS ToolKit X.ce 0 X.ft R X.S 12 X.sp 2 X.PH "'\s8Document\s0'Using SCCS ToolKit'\s8JLSS\s0'" X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "SCCS" XSCCS is the name for a group of related commands which collectively Xhelp maintain and record the development of software. XIt is strongly recommended that this software is used to maintain Xany software developed, even if it consists of a single file. X.P XOne of the advantages of using SCCS is that if any changes are Xmade which turn out not to work, or if you need to go back to Xan earlier version of the software, it is easy to do so X(without referring to any backup media). XAll the previous versions are kept in a master file called the s-file, Xbut since only the differences between the versions are kept, Xthe s-file is usually not as large as keeping a copy Xof all the previous versions. XMore importantly, if SCCS is in use, there is no need to remember Xto make a backup copy before starting to edit it; the backup Xexists automatically. X.P XSCCS also provides support for variants of a single program, but Xusing this facility is rather complex and should be avoided Xwhenever possible. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "CONVENTIONS" XSCCS creates master files with the prefix `s.'; for example, the XSCCS file for \*ctbo.sh\*d would be \*cs.tbo.sh\*d. XThis file is called the s-file, and it contains all the Xinformation about previous versions of the file, who made the Xchanges, when the changes were made, and so on. XThis file is always preserved by SCCS with 444 permissions; this Xshould never need changing. X.P XThe extracted version (typically the current version) of the file X(eg \*ctbo.sh\*d) is called the g-file. XIf the file is extracted for editing (see below), then it will be Xgiven 644 permissions; if it is not extracted for editing, it Xwill be given 444 permissions. X.P XThere is another file (eg \*cp.tbo.sh\*d) which is Xcalled the p-file and it is created when an s-file is got for editing. XIt will be created in the same directory as the s-file is kept in. XThis file is given 644 permissions. X.P XThere are a number of other files which can be created by SCCS Xcommands, but the only one which is not transient is the l-file X(with the prefix `\*cl.\*d'). XThe reference manuals also mention the q-file, x-file, z-file and Xd-file, each of which has the obvious prefix. X.P XThe version of an SCCS file is called its SID, and is either a X2-part number (eg 3.15) or a 4-part number (eg 3.15.3.2). XThe first number is the release, the second is the level, the Xthird is the branch and the fourth is the sequence. X.P XThe SCCS commands have a set of argument conventions which differ Xslightly from standard Unix conventions, but which are rigidly Xadhered to, so it is not too painful to learn them. XThe biggest change is that if an argument has a value associated Xwith it, the value must be attached to the flag. XThis means that using `\*c-y"Reason"\*d' is correct whereas X`\*c-y "Reason"\*d', with a blank between the flag and the Xargument, is incorrect. XA second change is that arguments cannot be combined; `\*c-ks\*d' Xis generally incorrect (unless the `\*c-k\*d' option takes an Xargument and `\*cs\*d' is a valid argument), whereas `\*c-k X-s\*d' is correct. XThe other changes are that arguments may appear anywhere in the Xcommand line, and that no argument may be repeated. XAny argument which does not start with a dash is clearly the name Xof an SCCS file. X.P XSCCS itself does not require that s-files are kept in a Xsub-directory, but development is much easier if the files are Xkept in the sub-directory. XBy convention, the name of the sub-directory is called SCCS. XIf an SCCS sub-directory is not used, the p-files and the s-files Xwill litter the main working directory and \*Cls\*D listings will Xcontain lots of extra files. XAdditionally, there is much more danger of losing the SCCS files Xaccidentally, because the working directory is normally writable Xby members of the group, and someone might accidentally remove Xall the files from the directory. XWith an appropriate SUID front-end and a suitably protected SCCS Xsub-directory, this problem can be completely avoided. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "INTERFACE PROGRAM" XThere is a program called \*csccs\*d which is a front-end to all Xthe standard SCCS commands. XIt can be invoked as \*csccs\*d with the first argument being Xthe name of a standard SCCS command and the other arguments as Xnormal for that command, in which case \*csccs\*d will modify Xthe argument list and then run the named SCCS command. XHowever, \*csccs\*d is normally installed with a set of links Xwhich have the same names as the real SCCS commands. XIf the linked command names are used instead of the standard commands (which can Xbe arranged by strategic ordering of the \*cPATH\*d environment Xvariable), then they modify the argument list and then invoke Xthe real SCCS commands. XThe modifications allows you to miss out either the `\*cs.\*d' prefix to Xthe file name, or the `\*cSCCS/\*d' for the sub-directory, or both. XThe description which follows is in terms of these front-end commands; if you Xuse the raw SCCS commands, you will have to worry about whether Xthe names should have `\*cSCCS/s.\*d' in front of them. X.P XThe \fIsccs\fP program can also perform another important function Xbecause it can safely be made SUID. XNormally, there is a project adminstrator login (for sake of Xexample, \*cadm\*d) which owns the XSCCS sub-directories, and these directories are given 755 Xpermissions, so only the administrator can modify the files in Xthe SCCS directories, or add or delete files. XThe \*cadm\*d login should seldom be used. XHowever, the programmers can use a SUID \*cadm\*d copy of the Xinterface program \fIsccs\fP which will give them temporary Xpermission to modify the files in the SCCS directories using the Xreal versions of the SCCS programs. XWhen the \fIsccs\fP command is compiled, the place where the real XSCCS programs are kept is specified. XAdditionally, if the command either has no need to be SUID (eg X\fIsccshelp\fP), or if the command can damage the SCCS file (ie X\fIcomb\fP or \fIrmdel\fP), the command is not run as a SUID Xprogram after all. X(Since \fIundelta\fP uses \fIrmdel\fP, this means that only \*cadm\*d Xcan use \fIundelta\fP to undo a delta.) X.P XNote that this program called \fIsccs\fP is different from the Xprogram called \fIsccs\fP available on BSD-derived versions of Unix. XFor the purposes of discussion, the BSD \fIsccs\fP program will Xbe called \fIsccs.bsd\fP. XAlthough \fIsccs.bsd\fP is also an interface to SCCS, it doesn't Xdo the argument massaging that \fIsccs\fP does. XIt also provides a number of convenience functions which are not Xsupplied by \fIsccs\fP; these include \fIdeledit\fP, X\fIdelget\fP, \fIedit\fP, \fItell\fP, and \fIclean\fP. XThe \fIsccs.bsd\fP program is always used as `\*csccs cmd\*d'; Xit cannot be linked as \fIsccs\fP can. XWhen \fIsccs.bsd\fP is available, the actual SCCS commands Xnormally live in the directory \*c/usr/sccs\*d. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "PUTTING A FILE UNDER SCCS" XThe shell script \fInewsccs\fP is used to insert a file under SCCS control. XIt will create the s-file in the SCCS sub-directory if there is such a Xdirectory, and in the current directory if not. XIt removes the original file if everything went OK; Xit leaves the original alone if anything goes wrong. X.P X\fINewsccs\fP is essentially a front-end to the \fIadmin\fP Xcommand, though it also uses \fIget\fP to check that the X\fIadmin\fP command succeeded. XThe \fIadmin\fP command normally only creates a single s-file at a Xtime; using \fInewsccs\fP allows many files to be installed under XSCCS control with a single command. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "GETTING A FILE FOR USE" XIf the file is required for use (eg for compiling), rather than for editing, Xthe \fIget\fP command is used. XThe name of the g-file is normally supplied to the front-end; if you Xuse raw SCCS, you must supply the name of the s-file. XThe file retrieved is not writable \(em which is correct because Xyou did not ask to edit it. X.P XIf a particular version of the file is required, the version X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "GETTING A FILE FOR EDITING" XIf the file is required for editing, use the `\*c-e\*d' option Xto \fIget\fP; this creates a p-file to record that the file is Xbeing edited, and retrieves a writable version of the g-file. XThe file can then be edited to create a new version, which should Xbe tested before it is recorded in SCCS. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "MAKING A NEW VERSION" XWhen a file has been edited and tested, the \fIdelta\fP command is Xused to create the new version in the s-file. XIf the `\*c-y\*d' option is not used, you will be Xasked for your comments on the change. XIf you want to supply several lines of Xtext, terminate each line with a backslash `\*c\e\*d'. X.P XAfter making the new version, use \fIget\fP to retrieve a working Xversion of the g-file. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "BRANDING FILES WITH THE VERSION NUMBER" XSCCS provides a facility for inserting what are known as XID-keywords into a file which can be used to identify the version Xof a file. XThese can be made mandatory or optional, and \fInewsccs\fP makes Xthem mandatory by default. XIf a file does not contain any ID-keywords but you want to use XSCCS on the file anyway, specify the `\*c-X\*d' flag. XYou will then get warnings about `no id-keywords' which can be Xignored. X.P XWhat is an ID-keyword? XThey take two forms, depending on whether the file has Xbeen extracted for editing or as a working version. XIf the file is extracted for editing, Xthe keywords all look like `%\&A\&%', that is a capital letter Xsurrounded by percent symbols. X.P XThe important keywords are: X.sp 0.5v X.TS Xl l. XZ a magic string which can be detected by a program called \fIwhat\fP. XM the name of the g-file XI the version of the g-file XE the date of the last change in yy/mm/dd format XU the time of the last change in hh:mm:ss format XW a shorthand for `%\&Z%%\&M% %\&I%' X.TE X.sp 0.5v XThus, at the top of many shell scripts, you will find a line such as: X.eS X: "%\&W\&% %\&E\&%" X.eE XThis gives the script name, the version and the date it was changed. XSome similar string can be inserted in most files. X.P XWhen a file is not extracted for editing, the keywords are expanded Xby \fIget\fP to contain the working versions of the strings. XFor example: X.eS X: "@(#)collist.sh 1.1 91/01/14" X.eE XThe sequence `\*c@(#)\*d' is the magic string; there is a program called X\fIwhat\fP which will read any file and search it for occurences Xof this string and print the text which follows up to a delimiter. XThere are a number of delimiters which Xinclude a newline, a double quote or a null character. XThus, to identify the Xversions of the files in use in a particular directory, the command: X.eS Xwhat * | more X.eE Xcan be very useful indeed. XIn particular, it gives you a way of getting the Xusers to identify the exact version of the software that they are having Xtrouble with \(em an immense advantage. XThis applies to both scripts and compiled C programs. X.P XThere is a modified version of \fIwhat\fP which also detects the keywords Xin the editing form; this can be useful for finding out which programs Xwere compiled with code that was out of SCCS for editing. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "ERROR MESSAGES" XOccasionally, you will get error messages from SCCS commands. XThese always include a code number in brackets, e.g (cm7). XThis number (minus the brackets) can be used as an argument Xto \fIhelp\fP (or \fIsccshelp\fP) which will give some more Xinformation on what the message means. X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "OTHER COMMANDS" XThe standard set of SCCS commands is: X.in +0.5i X.sp 0.5v X.TS Xl l. Xadmin create and administer SCCS files Xcdc change delta commentary Xcomb get rid of unwanted versions Xdelta create new versions of SCCS files Xget retrieve SCCS files Xhelp explain error message Xprs print statistics on SCCS files Xrmdel remove a delta (version) Xsact report on editing activity Xsccsdiff difference between two versions of an SCCS file Xunget cancel an edit Xval validate an SCCS file X.TE X.sp 0.5v X.in X.P XOf these, only \fIget\fP and \fIdelta\fP are used frequently. XThere are a number of SCCS related commands available Xwhich mostly use one or more of the commands above: X.in +0.5i X.sp 0.5v X.TS Xl l. Xnewsccs create a new SCCS file Xsccschk T{ Xcheck the differences between the latest version in SCCS Xand the version out for editing. XT} Xsccsinst install the sccs front-ends Xundelta undo a hastily made delta, leaving an editable file Xsccsmv T{ Xmove/rename an SCCS file; handles the s-file, the g-file Xand the p-file. XT} Xdelget combines \fIdelta\fP and \fIget\fP after the delta. Xdeledit similar to \fIdelget\fP, but gets the file for editing. Xdod T{ Xmake the same change to all the files extracted for editing Xwhich have actually changed, cancelling the edits for unmodified Xfiles and leaving files not extracted for editing alone. XT} X.TE X.sp 0.5v X.in X.P X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "FILES" X.sp 0.5v X.TS Xl l. Xsccs compiled C interface program XT{ Xget, delta, admin, rmdel, cdc, help, sccsdiff, Xval, sact, unget, comb, prs XT} links to sccs Xwhat alternative version of the standard what program XT{ Xnewsccs, undelta, sccschk, sccsmv, delget, deledit XT} shell scripts which do useful things X.TE X.sp 0.5v X'\" X'\" ----------------------------------------------------- X'\" X.H 1 "SEE ALSO" XThe Programmers Reference Manual entries for the SCCS commands. X'\" X'\" ----------------------------------------------------- X'\" X.sp 3 X.ne 3 XJonathan Leffler X.br XJLSS X.br X12th January 1993 SHAR-EOF chmod 444 sccs.doc if [ `wc -c sccs.ins <<'SHAR-EOF' X# "@(#)$Id: sccs.ins,v 1.3 1997/06/09 20:57:00 johnl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Installation configuration file X Xenvdir=SCCSDIR Xdefdir=/usr/local Xenvusr=SCCSUSR Xdefusr=bin Xenvgrp=SCCSGRP Xdefgrp=bin Xenvtmp=SCCSTMP Xdeftmp=${TMPDIR:-/tmp}/sccs X XFILELIST=etc/sccs.lst XPRODUCT='$Product: SCCS ToolKit Version 2 (1997-06-09) $' X X################################################# X XIN_MSG=' Xecho " Base Directory: $envdir = $DIR" Xecho " Owner: $envusr = $USR" Xecho " Group: $envgrp = $GRP" Xecho "" Xecho "The executables will go in $envdir/bin" Xecho "The documentation will go in $envdir/man/man1" Xecho "The other files will go in $envdir/etc" X' X XIN_TRAP=" Xecho 'Set: $envdir to define the location of the programs' Xecho ' $envusr to define the owner' Xecho ' $envgrp to define the group' Xtrap 0 Xexit 1" X XRM_MSG=' Xecho " Base Directory: $envdir = $DIR" Xecho " Owner: $envusr = $USR" Xecho " Group: $envgrp = $GRP" Xecho "" Xecho "The executables were placed in $envdir/bin" Xecho "The documentation were placed in $envdir/man/man1" Xecho "The other files were placed in $envdir/etc" X' X XRM_TRAP=" Xecho 'Set: $envdir to define the location of the programs' Xecho ' $envusr to define the owner' Xecho ' $envgrp to define the group' Xecho ' $envtmp to define where the files are to be moved to' Xtrap 0 Xexit 1" SHAR-EOF chmod 444 sccs.ins if [ `wc -c sccs.lst <<'SHAR-EOF' X# @(#)$Id: sccs.lst,v 1.8 1997/06/09 20:24:32 johnl Exp $ X# X# @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X# @(#)Definitive list of files -- Installed Software X# X# -- The installed file column contains the name of the file to be X# installed. The name is quoted relative to the base directory. X# The name could also be prefixed with an environment variable X# which would be set by the installation script. X# X# -- The type of file indicates what sort of file is to be installed. X# -- The type "file" indicates an ordinary file X# -- The type "directory" indicates that the file is the name of a X# directory which must exist when the software is installed. X# The installation program will create the directory X# if it does not already exist. The directory entry must come before X# the first file entry which lives in the directory. X# -- The type "deleted" means that this file used to exist in a previous X# release of the software and is no longer relevant. The file will X# be removed from the installed system. X# -- The type "link" means that the installed file is a link to a file X# already installed. The name in the Link column is the name of the X# file which the file is to be linked to. X# This file must already exist. If the line is not a link entry, a X# dummy value (conventionally '-') must be present in the column. X# X# -- Permissions are the file permissions to be set on the file. X# The three subfields are owner, group, mode. X# The owner - indicates the owner specified by the install script. X# The group - indicates the group specified by the install script. X# Other owner/group values (eg root) are treated as literal values. X# X# -- Comment lines start with a hash (#) X# -- Blank lines are ignored X# -- Tabs are non-preferred characters X# X# Installed file Type Link Permissions X X. directory - - - 775 X./jlss file - - - 544 X X# Programs Xbin directory - - - 775 Xbin/al file - - - 555 Xbin/delget file - - - 555 Xbin/dod file - - - 555 Xbin/escape file - - - 555 Xbin/gfile file - - - 555 Xbin/la file - - - 555 Xbin/latest file - - - 555 Xbin/newsccs file - - - 555 Xbin/pfiles file - - - 555 Xbin/sccs file - - - 555 Xbin/sccs2rcs file - - - 555 Xbin/sccschk file - - - 555 Xbin/sccsfile file - - - 555 Xbin/sccsinst file - - - 555 Xbin/sccsmv file - - - 555 Xbin/sccssid file - - - 555 Xbin/sfile file - - - 555 Xbin/undelta file - - - 555 Xbin/what file - - - 555 X Xbin/deledit link bin/delget - - 555 X X# Documentation Xman directory - - - 775 Xman/man1 directory - - - 775 Xman/man1/al.1 file - - - 444 Xman/man1/delget.1 file - - - 444 Xman/man1/dod.1 file - - - 444 Xman/man1/escape.1 file - - - 444 Xman/man1/gfile.1 file - - - 444 Xman/man1/la.1 file - - - 444 Xman/man1/latest.1 file - - - 444 Xman/man1/newsccs.1 file - - - 444 Xman/man1/pfiles.1 file - - - 444 Xman/man1/sccs.1 file - - - 444 Xman/man1/sccs.doc file - - - 444 Xman/man1/sccschk.1 file - - - 444 Xman/man1/sccsfile.1 file - - - 444 Xman/man1/sccsinst.1 file - - - 444 Xman/man1/sccsmv.1 file - - - 444 Xman/man1/sccssid.1 file - - - 444 Xman/man1/sfile.1 file - - - 444 Xman/man1/undelta.1 file - - - 444 Xman/man1/what.1 file - - - 444 X X# Distribution tools Xetc directory - - - 775 Xetc/instfile file - - - 544 Xetc/mkpath file - - - 544 Xetc/sccs.ins file - - - 544 Xetc/sccs.lst file - - - 444 Xetc/jlss link jlss - - 544 X Xjlss deleted - - - - SHAR-EOF chmod 444 sccs.lst if [ `wc -c sccs2rcs.sh <<'SHAR-EOF' X: "@(#)$Id: sccs2rcs.sh,v 1.8 1997/06/03 07:04:08 johnl Exp $" X# X# Sccs2rcs was a C Shell script to convert an existing SCCS history into an X# RCS history without losing any of the information contained therein. X# As such, it had been tested under the following OS's: X# SunOS 3.5, 4.0.3, 4.1 X# Ultrix-32 2.0, 3.1 X# X# It is now written in as a Bourne Shell script. As such, it has been X# tested under the following OS's: X# Interactive 386/IX System V Release 3.2.2 X# SunOS 4.1 X# It assumes your shell supports functions, but it would not be difficult X# to convert the functions into miniscule, temporary shell scripts which X# were removed automatically when the script exited. X# X# Things to note: X# * The comments prefixed with + were present in the C Shell version and X# * are still relevant. The comments prefixed with ! were present in the X# * C Shell version and are no longer correct. The comments prefixed X# * with a * were added when the Bourne Shell version was created. X# X# + It will NOT delete or alter your ./SCCS files under any circumstances. X# X# * Unlike the C Shell version, it does not extract SCCS files for X# * editing -- there was never any need to do so. X# X# + Run in a directory where ./SCCS exists and where you can create ./RCS X# X# ! /usr/local/bin is put in front of the default path. (SCCS under X# ! Ultrix is set-uid sccs, bad bad bad, so /usr/local/bin/sccs here X# ! fixes that). X# X# * Since the user has presumably got their path set correctly so that X# * SCCS works OK, we don't need to change it in here. It is assumed X# * that a front end called sccs exists and understands the commands get X# * and prs. If it doesn't exist (some System V derived machines), or if X# * you need to sort out the path, you can define environment variable X# * GET as get and PRS as prs. It is assumed that the sccs program does X# * not get confused when the name of the s-file is specified with the X# * leading "SCCS/s." present. The Bourne Shell version does not use the X# * non-original SCCS commands such as tell, edit, clean. This should X# * improve portability. X# X# + Date, time, author, comments, branches, are all preserved. X# * Actually, the time was not preserved, but it is now. X# X# * The -d option to prs extracts exactly the required information, so X# * the Bourne Shell version does not have to use grep and awk to X# * post-process the output of prs. System V does not (necessarily) X# * support "tail -r" so sort is used to re-order the revision numbers. X# X# ! If a command fails somewhere in the middle, it bombs with a message. X# ! Remove what it's done so far and try again. X# ! "rm -rf RCS; sccs unedit `sccs tell`; sccs clean" X# ! There is no recovery and exit is far from graceful. X# X# * The Bourne Shell version uses functions both to record what is X# * happening, and to clean up. It removes the temporary files (other X# * than the log file), and also the whole RCS directory. (This is X# * reasonable: before starting, the RCS directory either did not exist X# * or was empty; either way, no damage is done by removing it.) All the X# * error messages are reported on standard error (because it's easy to X# * do in Bourne Shell). X# X# + If a particular module is hanging you up, consider doing it X# + separately; move it from the current area so that the next run will X# + have a better chance or working. Also (for the brave only) you might X# + consider hacking the s-file for simpler problems: I've successfully X# + changed the date of a delta to be in sync, then run "sccs admin -z" X# + on the thing. X# X# + After everything finishes, ./SCCS will be moved to ./Old.SCCS. X# X# This file may be copied, processed, hacked, mutilated, and X# even destroyed as long as you don't tell anyone you wrote it. X# X# C Shell version: X# Ken Cox X# Viewlogic Systems, Inc. X# kenstir@viewlogic.com X# ...!harvard!cg-atla!viewlog!kenstir X# X# @(#)$Id: sccs2rcs.sh,v 1.8 1997/06/03 07:04:08 johnl Exp $ X# X# Bourne Shell version: X# Jonathan Leffler X# Informix Software Ltd X# johnl@obelix.informix.com X# ...!uunet!pyramid!infmx!johnl X X: ${GET:="sccs get"} X: ${PRS:="sccs prs"} X X############################################################ X# Error checking Xif [ ! -w . ] Xthen X echo "Error: current directory `pwd` is not writeable." >&2 X exit 1 Xfi Xif [ ! -d SCCS ] Xthen X echo "Error: ./SCCS directory not found." >&2 X exit 1 Xfi X Xx=`ls SCCS/p.* 2>/dev/null | wc -l` Xif [ $x -gt 0 ] Xthen X { X echo "Error: $x file(s) are out for editing." X ls SCCS/p.* | sed 's:SCCS/p.: :' X echo "Clean them up and try again." X } >&2 X exit 1 Xfi X Xif [ -d RCS ] Xthen X { X echo "Warning: RCS directory exists \c" X if [ `ls -a RCS | wc -l` -gt 2 ] X then X echo "and it's not empty!" X exit 1 X else X echo "but it's empty." X fi X } >&2 Xelse X mkdir RCS Xfi X Xlogfile=${TMPDIR:-/tmp}/s2r.$$.log Xtmpfile=${TMPDIR:-/tmp}/s2r.$$.tmp Xempfile=/dev/null Xinifile=${TMPDIR:-/tmp}/s2r.$$.init Xsedfile=${TMPDIR:-/tmp}/s2r.$$.sed Xmapfile=${TMPDIR:-/tmp}/s2r.$$.map Xecho "Initial revision" > $inifile X X# Error reporting function XERROR(){ X # The C Shell error code removed files got for editing. X # The Bourne Shell code does not get files for editing. X { X echo X echo "ERROR: $*" X echo X echo "Please remove the logfile $logfile ASAP" X echo X echo "Incomplete conversion in ./RCS removed" X echo "Original files in ./SCCS unchanged" X } | tee -a $logfile >&2 X rm -fr RCS $tmpfile $inifile $sedfile $mapfile X exit 1 X} X X# Record some information in the logfile and on standard output. Xrecord(){ X echo "$@" | tee -a $logfile X} X X# Trace execution of a command, and abort if it fails. Xtrace(){ X record "$@" X eval "$@" || ERROR "Doing $@" X} X Xtrap "ERROR 'Signal received'" 1 2 3 13 15 X X# The quotes surround the RCS keywords to fool RCS X# Likewise, the quotes around the SCCS ID keywords to fool SCCS X# The character pair "^I" is used to denote tabs for alignment. Xsed "s/'//g" <<'mapfile-here-document' | X%'W'%[ ^I]*%'G'% = @(#)$'Id'$ X%'W'%[ ^I]*%'E'% = @(#)$'Id'$ X%'W'% = @(#)$'Id'$ X%'M'%[ ^I]*%'I'%[ ^I]*%'G'% = @(#)$'Id'$ X%'M'%[ ^I]*%'I'%[ ^I]*%'E'% = @(#)$'Id'$ X%'M'% = $'RCSfile'$ X%'I'% = $'Revision'$ X%'G'% = $'Date'$ X%'E'% = $'Date'$ X%'U'% = X%'Z'% = @(#) Xmapfile-here-document Xawk -F= '{printf "%-30s => %s\n", $1, $2; }' >$mapfile X X############################################################ X# Get some information from the user Xnodesc=1 X X#echo X#echo "Do you want to be prompted for a description of each" X#echo "file as it is checked in to RCS initially?" X#echo "(y=prompt for description, n=null description) [y] ? \c" X#read ans X#case "$ans" in X#""|[yY]*) nodesc=0;; X#*) nodesc=1;; X#esac X X# If we were feeling interested, then we would probably check whether there X# was any descriptive text associated with the SCCS file. We would either X# add that to what the user supplied, or use it instead of the default X# message. It is extracted by using prs -d':FD:'. If there is no X# descriptive text, then the output contains "(none)". X Xecho Xecho "The default keyword substitutions are as follows and are" Xecho "applied in the order specified:" Xcat $mapfile Xecho X#echo "Do you want to change them [n] ? \c" X#read ans X#case "$ans" in X#[yY]*) X# echo X# echo "You can't always get what you want." X# echo "Edit this script file and change the mapfile-here-document:" X# exit 1 X# ;; X#*) X# echo X# echo "Good idea.";; X#esac X X# Create the ID keyword mapping sed script X# E1: convert "^I" to tab X# E2: deal with null mapping X# E3: deal with non-null mapping Xsed -e 's/\^I/ /g' \ X -e 's:\(.*[^ ]\) *=> *$:s,\1,,:g' \ X -e 's:\(.*[^ ]\) *=> *\([^ ].*\):s,\1,\2,:g' <$mapfile >$sedfile X X############################################################ X# Loop over every s-file in SCCS dir X Xfor sfile in SCCS/s.* Xdo X record "\nSCCS file: $sfile" X # get rid of the "s." at the beginning of the name X file=`expr $sfile : 'SCCS/s.\(.*\)'` X [ -w $file ] && ERROR "Writable copy of $file exists" X X # Process each rev of that file in ascending order. X # The PRS command uses a cutoff time equivalent to yyyy/mm/dd 23:59:59, X # (where yyyy/mm/dd is today's date) and prints all releases earlier X # than that cutoff time. It doesn't matter if you start running this X # script at 23:59:59 unless someone else makes a change while it is X # running and you want that change recorded. PRS prints the deltas in X # reverse order of application; SORT puts them into order of SID. X firsttime=1 X for rev in `$PRS -e -c\`date '+%y%m%d'\` -d':I:' $sfile | X sed '/[0-9][0-9]*\.[0-9][0-9]*\./d' | X sort -t. +0n -1 +1n -2 +3n -4 +4n` X do X # Check for auto-null deltas and skip them. X if $PRS -r$rev -d':C:' $sfile | grep 'AUTO NULL DELTA' >/dev/null X then X echo "Skip AUTO NULL DELTA ($rev)" X continue X fi X X # Get file into current dir and get stats X # NB: this breaks down in less than 7 years! X date=`$PRS -d'19:D: :T:' -r$rev $sfile` X author=`$PRS -d':P:' -r$rev $sfile` X record "==> file $file, rev=$rev, date=$date, author=$author" X trace "$GET -s -k -r$rev $sfile" X X # Add RCS keywords in place of SCCS keywords X trace "sed -f $sedfile $file > $tmpfile" X #record "performed keyword substitutions" X cp $tmpfile $file X X # Check file into RCS X if [ $firsttime = 1 ] X then X firsttime=0 X if [ $nodesc = 1 ] X then X txtfile=$inifile X else X echo X echo "Enter brief description of $file (end with Ctrl-D)" X cat - > $tmpfile X txtfile=$tmpfile X fi X trace "ci -f -r$rev -d'$date' -w$author -t$empfile $file <$txtfile" X record "Initial rev checked into RCS with message" X cat $txtfile X else X # Get RCS lock X trace "rcs -l -q $file" X trace "$PRS -r$rev -d':C:' $sfile >$tmpfile" X trace "ci -f -r$rev -d'$date' -w$author $file < $tmpfile" X fi X done X rm -f $file Xdone X X############################################################ X# Clean up Xecho cleaning up... Xmv SCCS Old.SCCS Xrm -f $tmpfile $inifile $sedfile $mapfile X Xecho Xecho "===================================================" Xecho " Conversion Completed Successfully" Xecho Xecho " SCCS history now in Old.SCCS" Xecho Xecho "Please remove the logfile $logfile ASAP" Xecho "===================================================" Xecho X Xexit 0 SHAR-EOF chmod 444 sccs2rcs.sh if [ `wc -c sccschk.1 <<'SHAR-EOF' X.\" @(#)$Id: sccschk.1,v 1.3 1997/02/13 14:37:28 johnl Exp $ X'\" @(#)Manual page: SCCSCHK -- Check changes on SCCS file(s) X.ds fC "Version: $Revision: 1.3 $ ($Date: 1997/02/13 14:37:28 $) X.TH SCCSCHK 1S "Sphinx UNIX Tools" X.SH NAME Xsccschk \(em check changes on SCCS files X.SH SYNOPSIS X\fBsccschk\fP [-opt] file [...] X.SH DESCRIPTION X\fBSccschk\fP takes each file in turn and compares the version in SCCS Xwith the extracted version. XThe option argument `\*c-b\*d' is passed to \fBdiff\fP(1) X(and means all strings of blanks and tabs compare equal); Xany other options are passed to \fBget\fP(1). XTwo useful options to know are `\*c-s\*d' which suppresses the version number Xand line count information from \fBget\fP, and `\*c-k\*d' which leaves any XSCCS ID keywords in the `%\&W\&%' form and normally reduces the number of Xdifferences reported. X.P XThis program uses \fBsccsfile\fP(1S) to locate the SCCS version of the file. X.SH "SEE ALSO" Xdiff(1), get(1), sccsfile(1S) X.SH DIAGNOSTICS XIf it cannot find either the named file or the SCCS version of that file. XOther complaints from \fBget\fP. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd. X.br X4th October 1989 SHAR-EOF chmod 444 sccschk.1 if [ `wc -c sccschk.sh <<'SHAR-EOF' X: "@(#)$Id: sccschk.sh,v 1.5 1992/12/29 10:59:14 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Check differences between SCCS version of file and gotten version X X: ${GET:=get} X Xfor file in $* Xdo X case $file in X -b) X dflag=$file X ;; X -*) X gflag="$gflag $file" X ;; X *) X sfile=`sfile $file` X if [ ! -f $sfile ] X then X echo "$0: file $sfile not found" >&2 X elif [ ! -f $file ] X then X echo "$0: file $file not found" >&2 X else X echo $file X ${GET} $gflag -p $sfile | diff $dflag - $file X fi X ;; X esac Xdone SHAR-EOF chmod 444 sccschk.sh if [ `wc -c sccsfile.1 <<'SHAR-EOF' X.\" @(#)$Id: sccsfile.1,v 1.2 1997/02/13 14:37:28 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for SCCSFILE(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:28 $) X.TH SCCSFILE 1J "SCCS ToolKit" X.SH NAME Xsccsfile \(em print names of s-files corresponding to g-files X.SH SYNOPSIS X\fBsccsfile\fP file [...] X.SH DESCRIPTION X\fBSccsfile\fP is a shell script which converts each of the Xg-file names it is given into the name of the corresponding s-file. XIt adds the `\*cs.\*d' prefix to the basename of the g-file X(assuming it is not specified; if it is included, then a second Xprefix is not added). XIt then tries to locate the s-file in the directory containing the g-file, and Xthen in the `\*cSCCS\*d' subdirectory, and then `\*csccs\*d' subdirectory. XIt prints out the name of the s-file, or the name of the g-file unchanged. X.SH "SEE ALSO" Xsfile(1J) X.SH BUGS XThe version supplied assumes a Korn Shell is available and will be used. XThe code for the Bourne Shell equivalent is included as comments in the file. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 sccsfile.1 if [ `wc -c sccsfile.sh <<'SHAR-EOF' X: "@(#)$Id: sccsfile.sh,v 1.2 1992/12/29 11:00:58 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Find SCCS version of file X X# Korn shell version enabled -- uses ${x#s.} X# Bourne Shell version disabled -- uses expr X Xcase $# in X0) echo "Usage: $0 file [...]" >&2 X exit 1;; Xesac X Xfor file in $* Xdo X bfile=`basename $file` X dir=`dirname $file` X if [ "$dir" = "" -o $dir = . ] X then dir= X else dir=$dir/ X fi X X nfile=${bfile#s.} # Korn Shell X #case "$bfile" in # Bourne Shell X #s.*) nfile=`expr "$bfile" : '..\(..*\)'`;; # Bourne Shell X #*) nfile=$bfile;; # Bourne Shell X #esac # Bourne Shell X X if [ -f ${dir}s.$nfile ] X then echo ${dir}s.$nfile X elif [ -f ${dir}SCCS/s.$nfile ] X then echo ${dir}SCCS/s.$nfile X elif [ -f ${dir}sccs/s.$nfile ] X then echo ${dir}sccs/s.$nfile X else echo $file X fi Xdone SHAR-EOF chmod 444 sccsfile.sh if [ `wc -c sccsinst.1 <<'SHAR-EOF' X.\" @(#)$Id: sccsinst.1,v 1.2 1997/02/13 14:37:29 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for SCCSINST(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:29 $) X.TH SCCSINST 1J "SCCS ToolKit" X.SH NAME Xsccsinst \(em create links to the SCCS interface program X.SH SYNOPSIS X\fBsccsinst\fP X.SH DESCRIPTION X\fBSccsinst\fP is typically used just once. XIt is run in the bin directory where the program \fIsccs(1J)\fP Xis installed, and creates a set of links to files with the same Xname as the SCCS commands \(em \fIadmin\fP, \fIcdc\fP, X\fIcomb\fP, \fIdelta\fP, \fIget\fP, \fIprs\fP, \fIrmdel\fP, X\fIsact\fP, \fIsccsdiff\fP, \fIsccshelp\fP, \fIunget\fP, \fIval\fP. X.P XThe command \fIhelp\fP is not linked, but \fIsccshelp\fP is used Xas a more sensible name for \fIhelp\fP. XSince \fIhelp\fP does not operate on files at all, it is not Ximportant that it is provided with an interface. XThe command \fIwhat\fP is not listed because it does not normally Xoperate on s-files. X.SH FILES Xsccs(1J) X.SH "SEE ALSO" Xsccs(1J) X.SH DIAGNOSTICS XComplains if the file `\*csccs\*d' cannot be located. X.SH BUGS XNone known. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 sccsinst.1 if [ `wc -c sccsinst.sh <<'SHAR-EOF' X# "@(#)$Id: sccsinst.sh,v 1.8 1992/12/29 11:07:26 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Install sccs: make links to sccs program X X# NB: sccshelp is an alternative name for help. X# No link called help is supplied because help does not operate on file X# names. The front-end is unnecessary unless the real SCCS commands X# are stored off most users' normal PATH. X Xcmds="admin cdc comb delta get prs rmdel sact sccsdiff sccshelp unget val" X Xif [ -f sccs -a -x sccs ] Xthen X for file in $cmds X do X rm -f $file X ln sccs $file X done Xelse X echo "$0: cannot locate file 'sccs'" >&2 X exit 1 Xfi SHAR-EOF chmod 444 sccsinst.sh if [ `wc -c sccsmv.1 <<'SHAR-EOF' X.\" @(#)$Id: sccsmv.1,v 1.2 1997/02/13 14:37:30 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for SCCSMV(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:30 $) X.TH SCCSMV 1J "SCCS ToolKit" X.SH NAME Xsccsmv \(em rename or move SCCS files X.SH SYNOPSIS X\fBsccsmv\fP file [...] [directory] X.SH DESCRIPTION X\fBSccsmv\fP is used to rename an SCCS file, or to move one or Xmore SCCS files from one place to another. XWhen an SCCS file is moved or renamed, the g-file (if it exists), Xthe s-file and the p-file (if it exists) are all moved or renamed. XIf a single g-file is specified on the command line, it is moved Xfrom its current location to the current directory. XIf two g-files are specified, then the first SCCS file is renamed Xas the second name. XIf a g-file and a directory are specified, then the SCCS file is Xmoved to the named directory. XIf more than two g-files are specified and the last name is a Xdirectory name, the SCCS files are moved to the specified Xdirectory; if the last name is not a directory, they are moved to Xthe current directory. X.SH FILES Xsfile(1J), gfile(1J), la(1J) X.SH BUGS XDoesn't move anything if the specified name is an s-file, not a g-file. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 sccsmv.1 if [ `wc -c sccsmv.sh <<'SHAR-EOF' X: "@(#)$Id: sccsmv.sh,v 1.7 1992/12/29 11:12:20 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Rename a file -- including SCCS versions of it X Xcase $# in X0) echo "Usage: $0 oldfile newfile" >&2 X exit 1 X ;; X1) # Move to current directory X $0 $1 . X ;; X2) # Basic move of SCCS file X gfile1=$1 # Name of g-file X gname1=`basename $1` # Filename of g-file X sfile1=`sfile $1` # Fullname of s-file X sname1=s.$gname1 # Filename of s-file X spath1=`dirname $sfile1` # Pathname of s-file X pfile1=`echo $sfile1 | sed 's%/s\.%/p.%'` # Fullname of p-file X if [ -d $2 ] X then X gfile2=$2/$gname1 X gname2=$gname1 X sfile2=$2/SCCS/s.$gname2 X sname2=s.$gname2 X spath2=$2/SCCS X pfile2=`echo $sfile2 | sed 's%/s\.%/p.%'` X else X gfile2=$2 X gname2=`basename $2` X spath2=`dirname $2`/SCCS X sname2=s.$gname2 X sfile2=$spath2/$sname2 X pfile2=`echo $sfile2 | sed 's%/s\.%/p.%'` X fi X X # Move g-file, move s-file, move p-file X MV=${MV:-mv} X if [ -f $gfile1 ] ; then ${MV} $gfile1 $gfile2 ; fi X if [ -f $sfile1 ] ; then ${MV} $sfile1 $sfile2 ; fi X if [ -f $pfile1 ] ; then ${MV} $pfile1 $pfile2 ; fi X ;; X X*) where=`la $*` X if [ -d $where ] X then X min=1 X else X min=0 X where=. X fi X while [ $# -gt $min ] X do X $0 $1 $where X shift X done Xesac SHAR-EOF chmod 444 sccsmv.sh if [ `wc -c sccssid.1 <<'SHAR-EOF' X.\" @(#)$Id: sccssid.1,v 1.2 1997/02/13 14:37:31 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for SCCSSID(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:31 $) X.TH SCCSSID 1J "SCCS ToolKit" X.SH NAME Xsccssid \(em print latest version at each release of each SCCS file X.SH SYNOPSIS X\fBsccssid\fP file [...] X.SH DESCRIPTION X\fBSccssid\fP prints the file name and the version number (SID) Xfor the latest version in each release of each SCCS file. XFor example: X.sp X.nf Xs.project.sh 4.2 Xs.project.sh 3.4 Xs.project.sh 2.5 Xs.project.sh 1.10 X.fi X.sp XIt assumes that the names given can be resolved by \fIprs\fP and Xuses \fIawk\fP to process the output from \fIprs\fP. X.SH BUGS XNone known. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 sccssid.1 if [ `wc -c sccssid.sh <<'SHAR-EOF' X: "@(#)$Id: sccssid.sh,v 1.3 1992/12/29 11:17:02 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Print highest level number in each release for each SCCS file X Xcutoff=`date +%y%m%d` X Xprs -e -c$cutoff -d':F: :R: :L:' ${*:-.} | Xawk '{ if ($1 != file) { X printf("%s\t%d.%d\n", $1, $2, $3); X file = $1; X rlse = $2; X } X else if ($2 != rlse) { X printf("%s\t%d.%d\n", $1, $2, $3); X rlse = $2; X } X }' SHAR-EOF chmod 444 sccssid.sh if [ `wc -c sfile.1 <<'SHAR-EOF' X.\" @(#)$Id: sfile.1,v 1.2 1997/02/13 14:37:31 johnl Exp $ X'\" @(#)$Product: SCCS ToolKit Version 2 (1997-06-09) $ X'\" @(#)Manual page for SFILE(1J) X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:31 $) X.TH SFILE 1J "SCCS ToolKit" X.SH NAME Xsfile \(em print names of s-files corresponding to g-files X.SH SYNOPSIS X\fBsfile\fP file [...] X.SH DESCRIPTION X\fBSfile\fP is a program which converts each of the Xg-file names it is given into the name of the corresponding s-file. XIt adds the `\*cs.\*d' prefix to the basename of the g-file X(assuming it is not specified; if it is included, then a second Xprefix is not added). XIt then tries to locate the s-file in the directory containing the g-file, and Xthen in the `\*cSCCS\*d' subdirectory, and then `\*csccs\*d' subdirectory. XIt prints out the name of the s-file, or the name of the g-file unchanged. X.SH "SEE ALSO" Xsccsfile(1J) X.SH BUGS XNone known. X.SH AUTHOR XJonathan Leffler X.br XJLSS X.br X29th December 1992 SHAR-EOF chmod 444 sfile.1 if [ `wc -c sfile.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: sfile.c,v $ X@(#)Version: $Revision: 2.5 $ X@(#)Last changed: $Date: 1997/02/13 15:23:47 $ X@(#)Purpose: Print name of SCCS file X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1988,1990,1992,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X#include X#include X#include X#include X#include X#include X#include X#include "stderr.h" X X#define NIL(x) ((x)0) X X#define SCCSFILESIZE 256 /* Max length for SCCS file name */ X#define SCCSSUBDIR "SCCS/" /* Directory containing SCCS files */ X X#ifndef PATH_MAX X#define PATH_MAX 1024 X#endif X X#ifndef NAME_MAX X#define NAME_MAX 256 X#endif X X#ifndef MAXSCCSPATHNUM X#define MAXSCCSPATHNUM 9 /* Max directory elements in SCCSPATH */ X#endif X X#ifndef DEFSCCSPATH X#define DEFSCCSPATH ".:SCCS" X#endif X Xextern char *vstrcpy(char *dst, int n, char *s1, ...); X X/* X** List of directories to try. X** Note that these are inserted between the directory name and X** the base name of the SCCS filename. X*/ Xstatic char *sccsdirectories[MAXSCCSPATHNUM + 1] = X{ X NIL(char *) X}; Xstatic char **endp = &sccsdirectories[MAXSCCSPATHNUM]; Xstatic char sccspath[PATH_MAX]; X X/* X** Storage for name -- overwritten on successive calls X*/ X X#ifndef lint Xstatic const char sccs[] = "@(#)$Id: sfile.c,v 2.5 1997/02/13 15:23:47 johnl Exp $"; X#endif X X/* X** sccsinit -- initialise SCCS directory list X*/ Xstatic void sccsinit(void) X{ X char *p; X char *q; X char *e; X char **d; X X d = sccsdirectories; X p = getenv("SCCSPATH"); X if (p == NIL(char *) || *p == '\0') X p = DEFSCCSPATH; X strcpy(sccspath, p); X p = sccspath; X e = p + strlen(p); X while (strlen(p) != 0) X { X if ((q = strchr(p, ':')) != NIL(char *)) X *q = '\0'; X if (strlen(p) == 0) X p = "."; X *d++ = p; X if (q == NIL(char *) || d >= endp) X break; X p = q + 1; X } X *d = NIL(char *); X} X X/* X** split_name -- break name into base and directory X** name is shortened by any trailing slashes. X*/ Xstatic void split_name(char *name, char *base, char *dir) X{ X int l; X char *p; X X l = strlen(name); X X /* Remove trailing slashes -- and worry about "/" */ X while (name[l - 1] == '/' && l > 1) X name[--l] = '\0'; X X /* Split name into directory and basename */ X if ((p = strrchr(name, '/')) == name && name[1] == '\0') X { /* Using root -- and the best of British */ X *dir = '\0'; X *base++ = '/'; X *base = '\0'; X } X else if (p != NIL(char *)) X { X /* Ordinary path name */ X /* Insert s. if missing */ X if (strncmp(p + 1, "s.", 2) == 0) X strcpy(base, p + 1); X else X (void) vstrcpy(base, 2, "s.", p + 1); X *p = '\0'; X (void) vstrcpy(dir, 2, name, "/"); X *p = '/'; X } X else X { X /* Plain file name */ X /* Insert s. if missing */ X if (strncmp(name, "s.", 2) == 0) X strcpy(base, name); X else X (void) vstrcpy(base, 2, "s.", name); X *dir = '\0'; X } X} X X/* X** sccsfile -- try to find an SCCS file corresponding to name X** X** name is InOut because split_name() strips trailing slashes X*/ Xstatic char *sccsfile(char *name) X{ X static char sccsname[PATH_MAX]; X char work1[PATH_MAX]; X char work2[PATH_MAX]; X char *base = work1; X char *dir = work2; X char *end; X char **p; X X split_name(name, base, dir); X X if (strlen(base) > (size_t) NAME_MAX) X stop("base name of file is too large.\n"); X X sccsname[0] = '\0'; X for (p = sccsdirectories; *p != NIL(char *); p++) X { X end = vstrcpy(sccsname, 3, dir, *p, "/"); X if (end >= &sccsname[sizeof(sccsname)]) X stop("SCCS name is too long.\n"); X /* Try to locate file */ X sprintf(end, "%s", base); X if (access(sccsname, 0) == 0) X return (sccsname); X sprintf(end, "%s%s", SCCSSUBDIR, base); X if (access(sccsname, 0) == 0) X return (sccsname); X } X X return (name); X} X Xint main(int argc, char **argv) X{ X setarg0(argv[0]); X X sccsinit(); X X while (*++argv) X puts(sccsfile(*argv)); X X return (0); X} SHAR-EOF chmod 444 sfile.c if [ `wc -c stderr.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: stderr.c,v $ X@(#)Version: $Revision: 6.16 $ X@(#)Last changed: $Date: 1997/06/06 19:28:50 $ X@(#)Purpose: Error reporting routines -- using stdio X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1988-91,1996-97 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X#include X#include X#include X#include X#include "stderr.h" X Xstatic char arg0[15] = "**undefined**"; Xstatic FILE *errout = stderr; X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: stderr.c,v 6.16 1997/06/06 19:28:50 johnl Exp $"; X#endif /* lint */ X X/* Change the definition of 'stderr', reporting on the old one too */ XFILE *err_stderr(FILE *newerr) X{ X FILE *old = errout; X if (newerr != (FILE *)0) X errout = newerr; X return(old); X} X Xconst char *getarg0(void) X{ X return(arg0); X} X Xvoid remark2(const char *s1, const char *s2) X{ X err_report(ERR_REM, ERR_STAT, "%s %s\n", (s1), (s2)); X} X Xvoid remark(const char *s1) X{ X err_report(ERR_REM, ERR_STAT, "%s\n", (s1)); X} X Xvoid error2(const char *s1, const char *s2) X{ X err_report(ERR_ERR, ERR_STAT, "%s %s\n", (s1), (s2)); X} X Xvoid error(const char *s1) X{ X err_report(ERR_ERR, ERR_STAT, "%s\n", (s1)); X} X Xvoid stop(const char *s1) X{ X err_report(ERR_ABT, ERR_STAT, "%s\n", (s1)); X} X Xvoid usage(const char *s1) X{ X err_report(ERR_USE, ERR_STAT, (s1)); X} X Xconst char *err_rcs_string(const char *s2, char *buffer, size_t buflen) X{ X const char *src = s2; X char *dst = buffer; X char *end = buffer + buflen - 1; X X /* X ** Bother RCS! We've probably been given something like: X ** "$Revision: 6.16 $ ($Date: 1997/06/06 19:28:50 $)" X ** We only want to emit the revision number and the date/time. X ** Skip the components between '$' and ': ', copy up to ' $', X ** repeating as necessary. And we have to test for overflow! X */ X while (*src != '\0' && dst < end) X { X while (*src != '\0' && *src != '$') X { X *dst++ = *src++; X if (dst >= end) X break; X } X if (*src == '$') X src++; X while (*src != '\0' && *src != ':' && *src != '$') X src++; X if (*src == '\0') X break; X if (*src == '$') X { X /* Unexpanded keyword '$Keyword$' notation */ X src++; X break; X } X if (*src == ':') X src++; X if (*src == ' ') X src++; X while (*src != '\0' && *src != '$') X { X *dst++ = *src++; X if (dst >= end) X break; X } X if (*src == '$') X { X if (*(dst-1) == ' ') X dst--; X src++; X } X } X *dst = '\0'; X return(buffer); X} X Xvoid version(const char *s1, const char *s2) X{ X char buffer[64]; X X if (strchr(s2, '$')) X s2 = err_rcs_string(s2, buffer, sizeof(buffer)); X (void)err_stderr(stdout); X err_report(ERR_ERR, EXIT_SUCCESS, "%s Version %s\n", s1, s2); X} X X/* Store basename of command, excluding trailing slashes */ X/* Doesn't handle two pathological cases -- "/" and "" */ Xvoid setarg0(const char *argv0) X{ X const char *cp; X size_t nbytes = sizeof(arg0) - 1; X X if ((cp = strrchr(argv0, '/')) != (char *)0 && *(cp + 1) == '\0') X { X /* Skip backwards over trailing slashes */ X const char *ep = cp; X while (ep > argv0 && *ep == '/') X ep--; X /* Skip backwards over non-slashes */ X cp = ep; X while (cp > argv0 && *cp != '/') X cp--; X cp++; X nbytes = ep - cp + 1; X if (nbytes > sizeof(arg0) - 1) X nbytes = sizeof(arg0) - 1; X } X else if (cp != (char *)0) X { X /* Regular pathname containing slashes */ X cp++; X } X else X { X /* Basename of file only */ X cp = argv0; X } X strncpy(arg0, cp, nbytes); X arg0[nbytes] = '\0'; X} X Xstatic void err_print(int flags, int estat, const char *string, va_list args) X{ X if (flags & ERR_FLUSH) X (void)fflush(stdout); X if (flags & ERR_USAGE) X (void)fprintf(errout, "Usage: %s %s\n", arg0, string); X else if (flags & ERR_COMM) X { X (void)fprintf(errout, "%s: ", arg0); X (void)vfprintf(errout, string, args); X } X (void)fflush(errout); X if (flags & ERR_ABORT) X abort(); X if (flags & ERR_EXIT) X exit(estat); X} X Xvoid err_remark(const char *format, ...) X{ X va_list args; X X va_start(args, format); X err_print(ERR_REM, ERR_STAT, format, args); X va_end(args); X} X Xvoid err_error(const char *format, ...) X{ X va_list args; X X va_start(args, format); X err_print(ERR_ERR, ERR_STAT, format, args); X va_end(args); X} X Xvoid err_report(int flags, int estat, const char *string, ...) X{ X va_list args; X X va_start(args, string); X err_print(flags, estat, string, args); X va_end(args); X} X X#ifdef TEST X Xstatic const char *list[] = X{ X "/usr/fred/bloggs", X "/usr/fred/bloggs/", X "/usr/fred/bloggs////", X "bloggs", X "/.", X ".", X "/", X "//", X "///", X "////", X "", X (char *)0 X}; X Xint main(int argc, char **argv) X{ X const char **name; X char *data; X X setarg0(argv[0]); X remark("testing values for argv[0]"); X X for (name = list; *name != (char *)0; name++) X { X data = malloc(strlen(*name) + 1); X strcpy(data, *name); X printf("name = <<%s>>; ", *name); X setarg0(*name); X printf(" (<<%s>>) arg0 = <<%s>>\n", *name, getarg0()); X free(data); X } X X setarg0(argv[0]); X remark("reporting arguments to program"); X while (*++argv != (char *)0) X remark2("next argument", *argv); X return(0); X} X X#endif /* TEST */ SHAR-EOF chmod 444 stderr.c if [ `wc -c stderr.h <<'SHAR-EOF' X/* X@(#)File: $RCSfile: stderr.h,v $ X@(#)Version: $Revision: 6.12 $ X@(#)Last changed: $Date: 1997/06/05 23:34:52 $ X@(#)Purpose: Header file for standard error functions X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1989-93,1996-97 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X#ifndef STDERR_H X#define STDERR_H X X#ifdef MAIN_PROGRAM X#ifndef lint Xstatic const char stderr_h[] = "@(#)$Id: stderr.h,v 6.12 1997/06/05 23:34:52 johnl Exp $"; X#endif X#endif X X#include X X/* -- Definitions for error handling */ X X#define ERR_STAT (1) /* Default exit status */ X X#define ERR_COMM (0x01) /* Print message on stderr */ X#define ERR_USAGE (0x02) /* Print usage on stderr */ X#define ERR_EXIT (0x04) /* Exit -- do not return */ X#define ERR_ABORT (0x08) /* Abort -- do not return */ X#define ERR_FLUSH (0x10) /* Flush stdout */ X#define ERR_STAMP (0x20) /* Timestamp messages */ X X/* -- Standard combinations of flags */ X X#define ERR_USE (ERR_USAGE|ERR_EXIT|ERR_FLUSH) X#define ERR_REM (ERR_COMM|ERR_FLUSH) X#define ERR_ERR (ERR_COMM|ERR_EXIT|ERR_FLUSH) X#define ERR_ABT (ERR_COMM|ERR_ABORT|ERR_FLUSH) X X/* -- Global definitions */ X Xextern const char *getarg0(void); Xextern void setarg0(const char *argv0); X Xextern FILE *err_stderr(FILE *new); Xextern const char *err_rcs_string(const char *s, char *buffer, size_t buflen); X Xextern void err_report(int flags, int estat, const char *string, ...); Xextern void err_error(const char *format, ...); Xextern void err_remark(const char *format, ...); X Xextern void error(const char *s1); Xextern void error2(const char *s1, const char *s2); Xextern void remark(const char *s1); Xextern void remark2(const char *s1, const char *s2); Xextern void stop(const char *s1); Xextern void usage(const char *s1); Xextern void version(const char *s1, const char *s2); X X#endif /* STDERR_H */ SHAR-EOF chmod 444 stderr.h if [ `wc -c undelta.1 <<'SHAR-EOF' X.\" @(#)$Id: undelta.1,v 1.2 1997/02/13 14:37:32 johnl Exp $ X'\" @(#)Manual page: UNDELTA -- remove a delta but keep the changes X.ds fC "Version: $Revision: 1.2 $ ($Date: 1997/02/13 14:37:32 $) X.TH UNDELTA 1S "Sphinx UNIX Tools" X.SH NAME Xundelta \(em remove a delta but keep the changes X.SH SYNOPSIS X\fBundelta\fP file [...] X.SH DESCRIPTION X.sp X.ce X\fBTHIS COMMAND IS DANGEROUS AND IS NOT FOOLPROOF\fP X.sp X\fBUndelta\fP is occasionally useful for over-enthusiastic users of SCCS. XIt removes the most recent delta from a file, but preserves the Xmost recent writable version of the file. XIt also ensures that the file is out for editing. XThis is normally used when a change is made and put back Xinto SCCS before the change is tested; Xthe subsequent testing shows that the change was erroneous Xand needs to be modified. X.P XIf there is already a writable file in the current directory, this is kept; Xotherwise, the most recent version is retrieved from SCCS without keyword Xexpansion (the `\*c-k\*d' option to \fBget\fP(1)). XUnless the current version is the only version in the SCCS file, Xit is removed by \fBrmdel\fP(1). XIf the delta is removed successfully, the file is retrieved for editing, Xbut the `\*c-g\*d' option is specified to preserve the writable file Xwith the most recent changes. X.P XExpert users of SCCS can detect that this script has been used; Xnot even expert users can determine what the removed changes were. X.SH "SEE ALSO" Xrmdel(1), prs(1), get(1), sccs(1) X.SH DIAGNOSTICS XVarious. X.SH BUGS XThis script is very far from bomb-proof. XIt can be broken if: X.br X\(bu named file is not in current directory X.br X\(bu named file is the s-file X.br X\(bu the named file does not exist but the file is extracted for editing X.br X\(bu etc... X.P XIt is far from clear that this should be available Xto anyone but the project manager. X.P XIt assumes that \fBprs\fP, \fBget\fP and \fBprs\fP all supply the XSCCS/s. when necessary. X.P XIf SUID front-ends for SCCS are in use, X\fBrmdel\fP should probably not be SUID. X.SH AUTHOR XJonathan Leffler X.br XSphinx Ltd. X.br X5th October 1989 SHAR-EOF chmod 444 undelta.1 if [ `wc -c undelta.sh <<'SHAR-EOF' X: "@(#)$Id: undelta.sh,v 1.4 1992/12/29 11:20:43 jl Exp $" X# X# $Product: SCCS ToolKit Version 2 (1997-06-09) $ X# X# Undo delta -- but preserve changes X# Assumes that get/unget/prs/rmdel insert SCCS/s. in file names X Xarg0=`basename $0 .sh` X X: ${GET:=get} X: ${UNGET:=unget} X: ${PRS:=prs} X: ${RMDEL:=rmdel} X Xestat=0 Xfor file in $* Xdo X if [ -w $file ] X then X # Cancel edit X ${UNGET} -n -s $file 2>/dev/null X else X # Get current version of file as if for editing X ${GET} -k -s $file 2>/dev/null X fi X X if [ $? = 0 ] X then X sid="`${PRS} -d':I:' $file 2>/dev/null`" X if [ -z "$sid" ] X then X echo "$0: $file is probably a lost cause" >&2 X estat=1 X elif [ $sid = "`${PRS} -r$sid -e -d':I:' $file`" ] X then X echo "$arg0: cannot remove base version of SCCS file" >&2 X elif ${RMDEL} -r$sid $file X then X ${GET} -e -g $file || estat=1 X else X estat=1 X fi X else X echo "$arg0: failed to sort out file $file" >&2 X estat=1 X fi Xdone Xexit $estat SHAR-EOF chmod 444 undelta.sh if [ `wc -c vstrcpy.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: vstrcpy.c,v $ X@(#)Version: $Revision: 1.10 $ X@(#)Last changed: $Date: 1997/06/02 16:41:57 $ X@(#)Purpose: Copy/concatenate variable number of strings X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1988-89,1991,1995,1997 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X/*LINTLIBRARY*/ X X/* X** vstrcpy(dst, n, src1, src2, ...); X** X** Vstrcpy copies each of its arguments src1, src2, ... into dst X** and null terminates the string. If given the value n = 0, it X** simply copies a null into dst[0]. X** Vstrcpy assumes that there is enough space in dst to contain X** the strings src1, src2, ... X** concatenated together. X** Vstrcpy returns a pointer to the terminal null. X*/ X X#include X#include "jlss.h" X X#ifndef lint Xstatic const char rcs[] = "@(#)$Id: vstrcpy.c,v 1.10 1997/06/02 16:41:57 johnl Exp $"; X#endif X Xchar *vstrcpy(char *dst, int n, ...) X{ X const char *src; X int i; X va_list args; X X va_start(args, n); X X for (i = 0; i < n; i++) X { X src = va_arg(args, const char *); X while ((*dst = *src++) != '\0') X dst++; X } X *dst = '\0'; X va_end(args); X return(dst); X} X X#ifdef TEST X X#include X#include X#include X Xstatic char *nested(char *s, int n) X{ X char *t = s; X X puts("Nested"); X while (n-- > 0) X { X t = nested(t, n); X puts(s); X } X t = vstrcpy(t, 2, "\ngoogleplex", " widget"); X return(t); X} X X/* Measurement shows that 199 bytes are necessary */ Xint main(void) X{ X char *buff; X char *cp; X X if ((buff = malloc(200)) == 0) X { X puts("memory allocation failed (dammit)"); X exit(1); X } X X cp = vstrcpy(buff, 5, "elephants", " ", "get arthritis", " ", "too easily!"); X puts(buff); X cp = vstrcpy(cp, 1, "\nelegance incarnate"); X puts(buff); X cp = vstrcpy(cp, 0); X puts(buff); X cp = nested(cp, 3); X puts(buff); X printf("Length: %ld\n", (long)strlen(buff)); X free(buff); X return(0); X} X X#endif /* TEST */ SHAR-EOF chmod 444 vstrcpy.c if [ `wc -c what.1 <<'SHAR-EOF' X.\" @(#)$Id: what.1,v 1.4 1997/02/13 14:37:33 johnl Exp $ X'\" @(#)Documentation for WHAT X.TH WHAT 1S "JLSS UNIX Tools" X.SH NAME Xwhat \(em emulation of SCCS \fBwhat\fP command X.SH SYNOPSIS X\fBwhat\fP [-hsV] file [file ...] X.SH DESCRIPTION X\fBWhat\fP is an emulation of the command of the same name Xprovided by the SCCS system, but it also identifies strings Xof the form `%\&X\&%' which are embedded in a file Xwhen it is extracted from SCCS for editing. XOne particular application of this is to enable a scrutineer Xto ensure that all source files which should have been returned to SCCS Xbefore a program was built were in fact returned. X.P XAll the options are additional to the standard interface. X.P XThe `\*c-h\*d' option is additional to the standard interface; Xit outputs the filename, a colon, and a space in front of every line Xof output which allows you to identify exactly which file the line Xcame from, even in a pipeline. XThis was found to be useful when verifying Xwhat source needed to be distributed. X.P XThe `\*c-s\*d' option does not print unexpanded version of the SCCS ID Xkeywords. XThe `\*c-V\*d' option prints the name and version number of the program Xand exits. X.SH "SEE ALSO" Xwhat(1) X.SH BUGS XThe effect of the `\*c-h\*d' option could be achieved by running the Xoutput through \fBawk\fP, but the option is useful in its own right. X.SH AUTHOR XJonathan Leffler X.br XInformix Software Inc. X.br X13th February 1997 SHAR-EOF chmod 444 what.1 if [ `wc -c what.c <<'SHAR-EOF' X/* X@(#)File: $RCSfile: what.c,v $ X@(#)Version: $Revision: 1.13 $ X@(#)Last changed: $Date: 1997/06/09 20:52:13 $ X@(#)Purpose: Simulate WHAT(1) X@(#)Author: J Leffler X@(#)Copyright: (C) JLSS 1987,1989,1990,1992,1996-97 X@(#)Product: $Product: SCCS ToolKit Version 2 (1997-06-09) $ X*/ X X/*TABSTOP=4*/ X X/* X** Test data for psychopathic cases: to use, run "./what what.c" X** NB: J is not a recognised ID keyword in standard SCCS, so the four X** GOT THIS lines should contain the characters '%', 'J', '%'. X** X** @(#@(#)GOT IT? -- 1 X** @(@(#)GOT IT? -- 2 X** @@(#)GOT IT? -- 3 X** %A@(#)GOT IT? -- 4 X** %@(#)GOT IT? -- 5 X** @(#%J%GOT THIS? -- 1 X** @(%J%GOT THIS? -- 2 X** @%J%GOT THIS? -- 3 X** %%J%GOT THIS? -- 4 X** @(#)Should have seen GOT IT 5 times X** @(#)Should have seen GOT THIS 4 times X*/ X X#include X#include X#include X#include X#include "stderr.h" X#include "getopt.h" X#include "filter.h" X Xstatic char usestr[] = "[-hsV] file [...]"; Xstatic char *filename; Xstatic int headings = 0; Xstatic int strict = 0; X X#ifndef lint Xstatic const char sccs[] = "@(#)$Id: what.c,v 1.13 1997/06/09 20:52:13 johnl Exp $"; X#endif X Xstatic void dostring(FILE *fp) X{ X int c; X X while ((c = getc(fp)) != EOF) X { X if (c == '\0' || strchr("\n\"\\>", c) || !(isprint(c) || isspace(c))) X break; X putchar(c); X } X putchar('\n'); X} X Xstatic void whatstr(FILE *fp) X{ X char c; X X if ((c = getc(fp)) != '(' || X (c = getc(fp)) != '#' || X (c = getc(fp)) != ')') X { X ungetc(c, fp); X return; X } X X if (headings) X printf("%s: ", filename); X else X putchar('\t'); X X dostring(fp); X} X Xstatic void sccsstr(FILE *fp) X{ X int c; X int c2; X X if (!isupper(c = getc(fp))) X { X ungetc(c, fp); X return; X } X if ((c2 = getc(fp)) != '%') X { X ungetc(c2, fp); X return; X } X X if (headings) X printf("%s: ", filename); X else X putchar('\t'); X X putchar('%'); X putchar(c); X putchar('%'); X dostring(fp); X} X Xstatic void what(FILE *fp, char *file) X{ X int c; X X filename = file; X if (!headings) X printf("%s:\n", filename); X while ((c = getc(fp)) != EOF) X { X if (c == '@') X whatstr(fp); X else if (c == '%' && strict == 0) X sccsstr(fp); X } X} X Xint main(int argc, char **argv) X{ X int opt; X X setarg0(argv[0]); X opterr = 0; X while ((opt = GETOPT(argc, argv, "hsV")) != EOF) X { X switch (opt) X { X case 'h': X headings = 1; X break; X case 's': X strict = 1; X break; X case 'V': X version("WHAT", "$Revision: 1.13 $ ($Date: 1997/06/09 20:52:13 $)"); X break; X default: X usage(usestr); X break; X } X } X X if (optind >= argc) X usage(usestr); X X filter(argc, argv, optind, what); X X return(EXIT_SUCCESS); X} SHAR-EOF chmod 444 what.c if [ `wc -c