home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume7
/
sccs.sh
< prev
next >
Wrap
Text File
|
1989-08-07
|
19KB
|
830 lines
Newsgroups: comp.sources.misc
organization: Cetia, Toulon, France
keywords: SCCS, sources
subject: v07i123: functions to maintain SCCS'ed source trees
from: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Reply-To: chris@cetia.UUCP (Chris Bertin)
Posting-number: Volume 7, Issue 123
Submitted-by: chris@cetia.UUCP (Chris Bertin)
Archive-name: sccs.sh
This is a file I keep in my home directory under the name '.shrc.sccs'. It
contains quite a few functions that I use to manage SCCS, to do source tree
comparisons, etc... This stuff has evolved over the years and some of the
functions have gotten quite large; in fact, several of them should probably
be turned into separate shell scripts. All these functions assume that the
SCCS files are kept in an 'SCCS' directory. If you have the BSD 'sccs' command,
several of these functions will lose some of their usefulness. I have never
bothered with 'sccs' because I started to use these functions before the 'sccs'
command came out.
----------------------------------- cut here ---------------------------------
##
## ex:set sw=4: # set shiftwidth to 4 when editing this file
##
##
## SCCS functions
##
## Chris Bertin
##
##
Company=YOUR_SITE # Used for header functions
# Files matching the following patterns will be skipped by 'recdiff'
RECSKIP="tags *.out llib*.ln lib.*"
# admin files
adm()
{
[ ${#} -eq 0 ] && {
echo "Usage: adm files" >&2
return 1
}
[ -d SCCS ] || {
echo "Creating SCCS directory"
mkdir SCCS || return 1
}
for AFile do
admin -i${AFile} SCCS/s.${AFile} && {
rm -f ${AFile}
get SCCS/s.${AFile}
}
shift
done
unset AFile
}
# admin all files in the current directory
adminall()
{
[ -f *.mk ] && AFile=`echo *.mk` || {
[ -f Makefile ] && AFile=Makefile || {
[ -f makefile ] && AFile=makefile
}
}
[ -f "${AFile}" ] && {
echo "Warning: doing a 'make clobber'"
sleep 5
make -f ${AFile} clobber
}
adm `ls | grep -v SCCS`
ls -l *
}
# handle pending files in directory trees (default '.') using delall (see below)
recdel()
{
[ ${#} -gt 0 ] && List="$*" || List=`pwd`
CurDir=`pwd`
trap "cd ${CurDir}; echo '...Aborted'; trap 1 2 3; return -1 >&- 2>&-" 1 2 3
for Tree in ${List}; do
echo "Doing ${Tree}"
cd ${Tree} || continue
for Dir in `find . -type d ! -name SCCS -print | sed "s/^\.\///"` ; do
cd ${Dir} && delall || { cd ${CurDir}; trap 1 2 3; return 1; }
cd ${CurDir} && cd ${Tree}
done
cd ${CurDir}
done
unset CurDir Tree Dir List
trap 1 2 3
}
# handle all pending files in the current directory (delta or unget or nothing)
delall()
{
[ ${#} -ne 0 ] && {
echo "Usage: delall" >&2
return 1
}
[ -z "`pend`" ] && {
echo "Nothing pending in `pwd`" >&2
return 0
}
for DLFile in `pend` ; do
echo ">> `pwd`/${DLFile}"
xdiff ${DLFile}
[ ! -t 1 ] && { echo "-----------------------------"; continue; }
while : ; do
echo "${DLFile}: [dacpqrsuv] (or '?' for help): \c"
read ANSWER < /dev/tty
# Note that there is no 'shift' here. They are handled by the
# functions called in each case. This is a major uglyness in 'sh'.
case "${ANSWER}" in
c*|C*)
CoMMent="`echo ${ANSWER} | sed 's/[a-zA-Z]* //'`"
echo "New comment is \"${CoMMent}\""
continue
;;
a*|A*)
echo "Autodelta with comment: \"${CoMMent}\""
sleep 1
chkpfile ${DLFile} || continue
delta -y"${CoMMent}" SCCS/s.${DLFile}
getn ${DLFile}
;;
d*|D*)
del ${DLFile}
;;
p*|P*)
echo "Current autocomment is: \"${CoMMent}\""
continue
;;
u*|U*)
ung ${DLFile}
;;
r*|R*)
xdiff ${DLFile}
continue
;;
v*|V*)
vi ${DLFile}
xdiff ${DLFile}
continue
;;
s*|S*)
${SHELL:-/bin/sh}
echo "exited"
continue
;;
q*|Q*)
return 1
;;
"")
echo "${DLFile} unchanged..."
;;
?*|*)
echo "Usage:\t\"c new auto comment\" (enter new comment)" >&2
echo "\t\"a\" (auto delta with previous auto comment)" >&2
echo "\t\"d\" (delta file manually)" >&2
echo "\t\"p\" (print autocomment)" >&2
echo "\t\"q\" (quit)" >&2
echo "\t\"r\" (redo)" >&2
echo "\t\"s\" (sub-shell)" >&2
echo "\t\"u\" (unget file)" >&2
echo "\t\"v\" (vi file)" >&2
echo "\t\"\" (do nothing)" >&2
continue
;;
esac
break
done
done
return 0
}
# check if there is an 'SCCS' directory. Args are passed because 'sh' doesn't
# stack arguments to functions.
chkSCCSdir()
{
[ -d SCCS ] || {
echo "No SCCS directory" >&2
return 1
}
return 0
}
# check if file is SCCS'ed.
chkSCCSfile()
{
[ -f SCCS/s.${1} ] && return 0
echo "${1} not SCCS'ed" >&2
return 1
}
# delta files
del()
{
[ ${#} -eq 0 ] && {
echo "Usage: del files" >&2
return 1
}
for DFile do
chkpfile ${DFile} || continue
delta SCCS/s.${DFile} && get SCCS/s.${DFile}
shift
done
unset DFile
}
# check whether p file is valid
chkpfile()
{
[ ${#} -eq 0 ] && {
echo "Usage: chkpfile files" >&2
return 1
}
[ $# -ne 1 ] && { echo "Arg count"; return 1; }
[ -r SCCS/p.${1} ] || { echo "${1} not pending"; return 1; }
WhoAmI=`whoami`
WhoIsIt="`awk '{print $3}' < SCCS/p.${1}`"
[ "${WhoAmI}" != "${WhoIsIt}" ] && {
echo "You didn't get ${1} -- (`cat SCCS/p.${1}`)"
if [ -t 1 ]; then
echo "Fix it? \c"
read ANSWER < /dev/tty
else
ANSWER="${DEFCHKP}"
fi
case "${ANSWER}" in
y*|Y*)
echo "s/${WhoIsIt}/${WhoAmI}/\nw\nq" | ed - SCCS/p.${1}
[ ${?} -ne 0 ] && {
echo "Can't fix SCCS/p.${1} -- Sorry";
return 1;
}
[ -t 1 ] || echo "Pfile fixed"
return 0
;;
*)
return 1
;;
esac
}
return 0
}
# get an SCCS file in edit mode
gete()
{
[ ${#} -eq 0 ] && {
echo "Usage: gete files" >&2
return 1
}
chkSCCSdir $* || return 1
for GEFile do
chkSCCSfile ${GEFile} && get -e SCCS/s.${GEFile}
shift
done
unset GEFile
}
# get an SCCS file without editing
getn()
{
[ ${#} -eq 0 ] && {
echo "Usage: getn files" >&2
return 1
}
chkSCCSdir $* || return 1
for GNFile do
chkSCCSfile ${GNFile} && get SCCS/s.${GNFile}
shift
done
unset GNFile
}
# get an SCCS file into standard output
getp()
{
[ ${#} -eq 0 ] && {
echo "Usage: getp files" >&2
return 1
}
chkSCCSdir $* || return 1
for GPFile do
chkSCCSfile ${GPFile} && get -p SCCS/s.${GPFile}
shift
done
unset GPFile
}
# get given version of an SCCS file into standard output
getv()
{
[ ${#} -ne 2 ] && {
echo "Usage: getv version file" >&2
return 1
}
chkSCCSdir $* || return 1
VeRs=${1}
shift
chkSCCSfile ${1} && get -p -r${VeRs} SCCS/s.${1}
unset VeRs
}
# unget SCCS files that have been get'ed but not modified (in current directory)
cleanget()
{
[ ${#} -ne 0 ] && {
echo "Usage: cleanget" >&2
return 1
}
CurDir=`pwd`
trap "cd ${CurDir}; echo '...Aborted'; trap 1 2 3; return -1 >&- 2>&-" 1 2 3
find . -type f -name "p.*" -print | while read CGfile; do
BaseName=`basename ${CGfile} | sed "s/p.//"`
cd `dirname ${CGfile}`/.. || continue
echo ${BaseName}: pending in directory `pwd`
get -k -p SCCS/s.${BaseName} 2>&- | ${DIFF:-diff} - ${BaseName} >&- 2>&- && {
echo No differences for SCCS/s.${BaseName}
CurDate=`/src/uts/m68k/bin/curdate ${BaseName}`
chkpfile ${BaseName} || continue
ung ${BaseName}
touch -m ${CurDate} ${BaseName}
}
cd ${CurDir}
done
unset CurDir CGfile CurDate BaseName
trap 1 2 3
}
# SCCS history for SCCS files
hist()
{
[ ${#} -eq 0 ] && {
echo "Usage: hist files" >&2
return 1
}
chkSCCSdir $* || return 1
for HFile do
chkSCCSfile ${HFile} && prs -e \
-d'Delta for :M:: -- :I: --, Date: :D:\nUpdate: :C:' SCCS/s.${HFile}
shift
done
unset HFile
}
# examine SCCS files
m()
{
[ ${#} -eq 0 ] && {
echo "Usage: m files" >&2
return 1
}
chkSCCSdir $* || return 1
for MFile do
chkSCCSfile ${MFile} && get -s -p SCCS/s.${MFile} | ${PAGER:-pg}
shift
done
unset MFile
}
# show which SCCS files are pending. Optionnal args limit the name expansion
pend()
{
chkSCCSdir $* || return 1
[ -f SCCS/p.* ] && echo `ls SCCS/p.*${1} 2>&- | sed "s/^SCCS\/p.//"`
}
# show all pending files in the given directory trees (default '.')
pendall()
{
[ ${#} -gt 0 ] && List="$*" || List=.
for Tree in ${List}; do
find ${Tree} -type f -name 'p.*' -print | \
sed -e 's/^\.\///' -e 's/SCCS\/p\.//'
done
unset Tree List
}
# add a SCCS header to the given C files
shead()
{
[ ${#} -eq 0 ] && {
echo "Usage: shead files" >&2
return 1
}
for SFile do
echo '1i\n#ifndef lint\nstatic char ID[] = "%W% ${Company} %E%";\n#endif lint\n.\nw\nq' | ed - ${SFile}
done
unset SFile
}
# add a SCCS header to the given header files
shhead()
{
[ ${#} -eq 0 ] && {
echo "Usage: shhead files" >&2
return 1
}
for SHFile do
echo '1i\n/* %W% ${Company} %E% */\n.\nw\nq' | ed - ${SHFile}
done
unset SHFile
}
# add a SCCS header to the given FORTRAN files
sfhead()
{
[ ${#} -eq 0 ] && {
echo "Usage: sfhead files" >&2
return 1
}
for SFFile do
echo '1i\n* %W% ${Company} %Z%\n.\nw\nq' | ed - ${SFFile}
done
unset SFFile
}
# add a SCCS header to the given SHELL (or MAKEFILE) files
sshead() { smhead $*; }
smhead()
{
[ ${#} -eq 0 ] && {
echo "Usage: smhead files" >&2
return 1
}
for MHFile do
echo '1i\n# %W% ${Company} %Z%\nw\nq' | ed - ${MHFile}
done
unset MHFile
}
# unget files
ung()
{
[ ${#} -eq 0 ] && {
echo "Usage: ung files" >&2
return 1
}
chkSCCSdir $* || return 1
for UFile do
chkSCCSfile ${UFile} && chkpfile ${UFile} && \
unget SCCS/s.${UFile} && get SCCS/s.${UFile}
shift
done
unset UFile
}
# unget files without reextracting them
ungn()
{
[ ${#} -eq 0 ] && {
echo "Usage: ungn files" >&2
return 1
}
chkSCCSdir $* || return 1
for UNFile do
chkSCCSfile ${UNFile} && chkpfile ${UNFile} && unget SCCS/s.${UNFile}
shift
done
unset UNFile
}
# show SCCS versions
vs()
{
[ ${#} -eq 0 ] && {
echo "Usage: vs files" >&2
return 1
}
chkSCCSdir $* || return 1
for VFile do
chkSCCSfile ${VFile} && prs -d"Current delta for :M:: -- :I: --, Date: :D:\nLast update: :C:" SCCS/s.${VFile}
shift
done
unset VFile
}
# show SCCS versions of a full directory
vss()
{
[ ${#} -eq 0 ] && {
echo "Usage: vss sccs_directory" >&2
return 1
}
prs -d"Current delta for :M:: -- :I: --, Date: :D:\nLast update: :C:" $1
}
# diff an SCCS file and its extracted counterpart
xdiff()
{
[ ${#} -eq 0 ] && {
echo "Usage: xdiff files" >&2
return 1
}
chkSCCSdir $* || return 1
for XFile do
chkSCCSfile ${XFile} || continue
[ ! -f ${XFile} ] && {
ls ${XFile}
continue
}
vs ${XFile} && get -p SCCS/s.${XFile} | ${DIFF:-diff} - ${XFile} 2>&1 | ${PAGER:-pg}
done
unset XFile
}
## sccsdiff between 2 versions
scdiff()
{
[ ${#} -lt 3 ] && {
echo "Usage: scdiff rel1 rel2 files" >&2
return 1
}
R1=$1; shift
R2=$1; shift
chkSCCSdir $* || return 1
for SFiLE do
chkSCCSfile ${SFiLE} || continue
sccsdiff -r${R1} -r${R2} SCCS/s.${SFiLE} | ${PAGER:-pg}
done
unset R1 R2 SFiLE
}
# recursive difference between 2 trees, using diffall (See below)
recdiff()
{
Skip=
Flag=
for Opt in "$@"; do
case ${Opt} in
-F|-f) Flag="${Flag} -f"
[ ${Opt} = "-f" ] && Fopt="-o -type l"; shift
;;
-o) Flag="${Flag} -o"; shift
;;
-s) Skip="! -name SCCS" ;shift
;;
*) break
;;
esac
done
[ \( ${#} -eq 1 -a ${1} = '-' \) -o ${#} -eq 2 ] && {
:
} || {
echo "Usage:\trecdiff [-f] [-F] [-o] [-s] ['-' or dir1] dir2" >&2
echo "\t-f: follow symbolic links in destination" >&2
echo "\t-F: follow symbolic links both in source and destination" >&2
echo "\t-o: compare non ascii files" >&2
echo "\t-s: skip SCCS directories" >&2
echo "\t- : If first argument is '-', do recursive SCCS diffs" >&2
return 1
}
BaseDir="."
Arg1=${1}
Arg2=${2}
if [ ${Arg1} = "-" ]; then
Skip="! -name SCCS"
[ ${#} = 1 ] && set - "." || BaseDir=${2}
Sdiff=true
shift
else
Sdiff=false
fi
CurDir=`pwd`
for Dir do
[ ! -d ${Dir} ] && {
echo "${Dir}: not a directory"
unset Dir
return 1
}
done
if [ ${Sdiff} = false ]; then
cd ${Arg2} || return 1
Dest=`pwd`
cd ${CurDir} || return 1
fi
if [ ${Sdiff} = false ]; then
cd ${Arg1} || return 1
fi
trap "cd ${CurDir}; echo '...Aborted'; trap 1 2 3; return -1 >&- 2>&-" 1 2 3
find ${BaseDir} ${Skip} \( -type d ${Fopt} \) -print | sed "s/^\.\///" | \
while read Dir; do
[ -d ${Dir} ] || continue
echo "------ Directory: ${CurDir}/${Dir} ------"
cd ${Dir} || continue
if [ ${Sdiff} = true ]; then
if [ -d SCCS ]; then
Pending="`pend`"
if [ "${Pending}" != "" ]; then
diffall ${Flag} - ${Pending} || break
fi
fi
cd ${CurDir}
continue
fi
if [ ! -d ${Dest}/${Dir} ]; then
diffall ${Flag} ${Dir} ${Dest} # for error handling
else
List=""
for F in `ls -a`; do
[ -z "${RECSKIP}" ] || {
for FF in `echo ${RECSKIP}` ; do
[ ${FF} = ${F} ] && {
echo "===== ${F} ===== Skipped"
continue 2
}
done
}
[ -f ${F} ] && List="${List} ${F}"
done
[ -z "${List}" ] || diffall ${Flag} ${List} ${Dest}/${Dir} || break
fi
cd ${CurDir}
cd ${Arg1}
done
cd ${CurDir}
unset Arg1 Arg2 CurDir Skip Dir Dest Flag Fopt F List Opt Pending Sdiff
trap 1 2 3
}
# diff a series of files with their SCCS counterpart or another directory
diffall()
{
Dusage() {
echo "Usage:\tdiffall [-f] [-o] ['-' or files] [directory]" >&2
echo "\t-f: follow symbolic links" >&2
echo "\t-o: compare non ascii files" >&2
}
Nodiff() { REDO=0; echo "$* No differences"; }
Follow=false
Dotos=false
for Opt in "$@"; do
case ${Opt} in
-f) Follow=true; shift
;;
-o) Dotos=true; shift
;;
*) break
;;
esac
done
[ "$1" = "" ] && { Dusage; return 1; }
if [ "$1" = "-" ]; then
XdIfF=true
DiR="."
shift
chkSCCSdir $*
else
Args=$*
XdIfF=false
DiR=`echo $* | sed "s/.* //"`
[ ! -d "${DiR}" ] && {
echo "${DiR}: not a directory" >&2
Dusage
return 1
}
ls ${DiR} > /tmp/di$$
More=`ls | ${DIFF:-diff} - /tmp/di$$ | grep "^> " | sed "s/^> //"`
rm -f /tmp/di$$
[ -z "${More}" ] || echo "\nWARNING: `echo ${More}` only in ${DiR}\n"
set ${Args}
unset More Args
fi
Dcheckread() {
for FIle do
[ -d ${FIle} -o -c ${FIle} -o -b ${FIle} -o ! -r ${FIle} ] && {
echo "skipping `file ${FIle}`"
unset FIle
return 1
}
done
unset FIle
return 0
}
for FiLe do
[ "${FiLe}" = "${DiR}" ] && break
REDO=1
while [ ${REDO} -gt 0 ] ; do
[ ${REDO} -eq 1 ] && echo "====== ${FiLe} ===== \c"
if [ ${REDO} -eq 2 ]; then
: do nothing. We got here because of wrong answer below
elif [ "${XdIfF}" = "true" ] ; then
[ -d ${FiLe} ] && {
echo "${FiLe}: Directory"
REDO=0
continue
}
if Dcheckread ${FiLe} SCCS/s.${FiLe} ; then
get -p -s SCCS/s.${FiLe} 2>&- | ${CMP:-cmp} - ${FiLe} 2>&1 && {
Nodiff
continue
}
get -p -s SCCS/s.${FiLe}| ${DIFF:-diff} - ${FiLe} | \
${PAGER:-pg}
fi
else
if [ ${Follow} = false -a \
`ls -l ${FiLe} 2>&- | grep -c " -> "` -eq 1 ] ; then
echo "${FiLe}: Symbolic link\c"
if [ "`ls -d ${DiR}/${FiLe} 2>&-`" != "${DiR}/${FiLe}" ]; then
echo "s differ: ${DiR}/${FiLe} doesn't exist"
elif [ `ls -l ${DiR}/${FiLe} | grep -c " -> "` -eq 1 ]; then
ls -l ${FiLe} 2>&- | sed "s/.* -> //" > /tmp/dall.$$
ls -l ${DiR}/${FiLe} 2>&- | sed "s/.* -> //" | \
${DIFF:-diff} - /tmp/dall.$$ >&- 2>&-
[ ${?} = 0 ] && {
rm -f /tmp/dall.$$
Nodiff "s,"
continue
} || {
rm -f /tmp/dall.$$
echo "s differ:"
ls -l ${FiLe} ${DiR}/${FiLe}
}
else
echo " but ${FiLe} differ: `file ${DiR}/${FiLe}`"
fi
else
if Dcheckread ${FiLe} ${DiR}/${FiLe}; then
if file ${FiLe} | \
egrep " executable| archive| object| data" >&-; then
echo "`file ${FiLe} | \
sed 's/[ ][ ]*/ /g'` -> \c"
[ ${Dotos} = false ] && {
echo "Ignored"
REDO=0
continue
}
${CMP:-cmp} ${FiLe} ${DiR}/${FiLe} 2>&1 && {
Nodiff
continue
}
else
${CMP:-cmp} ${FiLe} ${DiR}/`basename ${FiLe}` 2>&1 && {
Nodiff
continue
}
${DIFF:-diff} ${FiLe} ${DiR} | ${PAGER:-pg}
fi
fi
fi
fi
[ ! -t 1 ] && { REDO=0; continue; }
echo "====== ${FiLe} done ===== Hit return to continue: \c"
REDO=0
read a < /dev/tty
[ -z "${a}" ] && continue
case ${a} in
vi|e|v) REDO=1 ; vi ${FiLe} ;;
mod) REDO=2 ; echo "cpio: -m option will be used"; Dopt=m ;;
nomod) REDO=2 ; echo "cpio: no -m option"; Dopt="" ;;
redo|r) REDO=1 ;;
quit|q) return 1 ;;
put|PUT) REDO=1
[ ${XdIfF} = true ] && {
echo "Cannot put with '-' option" >&2
REDO=2
continue;
}
if [ ${a} = PUT ]; then
rm -r ${DiR}/${FiLe} || {
REDO=2
continue
}
fi
if [ -f ${FiLe} ] ; then
find ${FiLe} -print | cpio -pduvv${Dopt} ${DiR}
elif [ -d ../${FiLe} ] ; then
mkdir ${DiR}/${FiLe} || {
REDO=2
continue
}
cd ..; find ${FiLe} -print | cpio -pduvv${Dopt} ${DiR}
else
echo "case not handled"
REDO=2
fi
;;
get|GET) REDO=1
if [ ${XdIfF} = true ]; then
if [ -f SCCS/p.${FiLe} ]; then
if [ ${a} = GET ]; then
ung ${FiLe} || REDO=2
else
echo "File is out being edited. Use GET to overwrite"
REDO=2
fi
fi
[ ${REDO} -gt 0 ] && continue
get SCCS/s.${FiLe} || REDO=2
else
[ ${a} = GET ] && rm -rf ${FiLe}
export Dopt
( Here=`pwd`; chdir ${DiR} && \
find ${FiLe} -print | cpio -pduvv${Dopt} ${Here} )
fi
;;
sh) ${SHELL:-/bin/sh}
REDO=2 ;;
'?'|*) echo "Usage:\tvi|e|v:\tedit local file" >&2
echo "\tr|redo:\tredo file" >&2
echo "\tq|quit:\tquit" >&2
echo "\tput:\tcopy local file to remote file" >&2
echo "\tPUT:\tsame but forcibly" >&2
echo "\t[no]mod:\t[don't] use -m option for put/get" >&2
echo "\tget:\tcopy remote file to local file (or get SCCS file)" >&2
echo "\tGET:\tsame but forcibly" >&2
echo "\tsh:\tsub-shell" >&2
echo "\t'?':\thelp" >&2
REDO=2 ;;
esac
unset a
done
done
unset FiLe Opt Follow Skip Dotos Follow REDO More Dopt Nodiff Dusage
return 0
}
----------------------------------- cut here ---------------------------------
--
Chris Bertin | -- CETIA -- 150, Av Marcelin Berthelot, Z.I. Toulon-Est
+33(94)212005 | 83088 Toulon Cedex, France
| inria!cetia!chris