[comp.sources.unix] v22i015: Brian Berliner's concurrent RCS system, Part01/07

rsalz@uunet.uu.net (Rich Salz) (05/04/90)

Submitted-by: Brian Berliner <berliner@prisma.com>
Posting-number: Volume 22, Issue 15
Archive-name: cvs-berliner/part01

[ Brian has the patience of a saint.  If you don't have PIC you'll have
  to rip some lines out of the paper in the doc directory.  --r$ ]

CVS is a freely available collection of programs that provide for software
release and revision control functions in a UNIX environment.  It is
designed to work on top of the RCS distribution, V4 (uses the V4 branch
support).  CVS does understand how to parse older RCS formats, but cannot
do any of the fancier features (like vendor branch support) without RCS
branch support.

The conflict-resolution algorithms and much of the administrative file
definitions of CVS were based on the original package written by Dick Grune
at Vrije Universiteit in Amsterdam, and posted to comp.sources.unix in the
volume 6 release sometime in 1986.  This original version was a collection
of shell scripts. 

Brian Berliner from Prisma, Inc. converted the original CVS shell scripts
into reasonably fast C and added many, many features to support software
release control functions.  See the manual page in the "man" directory, and
a copy of the USENIX article presented at the Winter 1990 USENIX
Conference, Washington D.C., is included in the "doc" directory.


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 7)."
# Contents:  MANIFEST Makefile README doc doc/Makefile examples
#   examples/Makefile examples/loginfo man man/Makefile
#   man/checkin.man man/mkmodules.man src src/build_entry.c
#   src/create_admin.c src/entries_file.c src/find_names.c src/join.c
#   src/locate_rcs.c src/log.c src/name_repository.c
#   src/no_difference.c src/options.c src/patchlevel.h src/rcstime.h
#   src/register.c src/remove.c src/scratch_entry.c src/status.c
#   src/version_ts.c
# Wrapped by rsalz@litchi.bbn.com on Thu May  3 16:58:59 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1770 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X COPYING                    4	
X MANIFEST                   1	
X Makefile                   1	
X README                     1	
X doc                        1	
X doc/Makefile               1	
X doc/cvs.ms                 6	
X examples                   1	
X examples/Makefile          1	
X examples/loginfo           1	
X examples/modules           5	
X man                        1	
X man/Makefile               1	
X man/checkin.man            1	
X man/cvs.man                7	
X man/mkmodules.man          1	
X src                        1	
X src/Makefile               4	
X src/add.c                  2	
X src/build_entry.c          1	
X src/checkin.c              2	
X src/checkin.csh            3	
X src/checkout.c             2	
X src/collect_sets.c         3	
X src/commit.c               5	
X src/create_admin.c         1	
X src/cvs.h                  2	
X src/diff.c                 2	
X src/entries_file.c         1	
X src/find_names.c           1	
X src/join.c                 1	
X src/locate_rcs.c           1	
X src/log.c                  1	
X src/main.c                 3	
X src/maketime.c             2	
X src/mkmodules.c            2	
X src/modules.c              3	
X src/name_repository.c      1	
X src/no_difference.c        1	
X src/options.c              1	
X src/partime.c              5	
X src/patch.c                4	
X src/patchlevel.h           1	
X src/rcstime.h              1	
X src/register.c             1	
X src/remove.c               1	
X src/scratch_entry.c        1	
X src/set_lock.c             2	
X src/status.c               1	
X src/subr.c                 3	
X src/tag.c                  2	
X src/update.c               4	
X src/version_number.c       3	
X src/version_ts.c           1	
END_OF_FILE
if test 1770 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1109 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X#	$Id: Makefile,v 1.1 89/11/19 23:15:10 berliner Exp $
X#
X# Master Makefile for CVS
X#
X
XDESTDIR=	/usr/local/bin
XCFLAGS=		-O # -g
XLDFLAGS=	# -Bstatic
XSUBDIRS=	doc examples man src
X
XFILES=		README Makefile COPYING
XSHAR=		shar
X
Xall:
X	@for i in ${SUBDIRS}; do\
X		(cd $$i; ${MAKE} ${MFLAGS} DESTDIR="${DESTDIR}"\
X			CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}");\
X	done
X
Xinstall:
X	@for i in ${SUBDIRS}; do\
X		(cd $$i; ${MAKE} ${MFLAGS} DESTDIR="${DESTDIR}"\
X			CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" install);\
X	done
X
Xclean:
X	@for i in ${SUBDIRS}; do\
X		echo $$i:;\
X		(cd $$i; ${MAKE} ${MFLAGS} DESTDIR="${DESTDIR}"\
X			CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" clean);\
X	done
X
Xshar:
X	@rm -f ${SHAR}.[0-9]*
X	makekit -p -s45k -n${SHAR}. `make -s list`
X
Xlist:
X	@for i in ${FILES}; do\
X		echo $$i;\
X	done
X	@for i in ${SUBDIRS}; do\
X		echo $$i;\
X		(cd $$i; ${MAKE} ${MFLAGS} DESTDIR="${DESTDIR}"\
X			CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" list) |\
X		sed -e "s1^1$$i/1";\
X	done
X
Xdepend:
X	@for i in ${SUBDIRS}; do\
X		(cd $$i; ${MAKE} ${MFLAGS} DESTDIR="${DESTDIR}"\
X			CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" depend);\
X	done
END_OF_FILE
if test 1109 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(6170 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X$Id: README,v 1.3 89/11/19 23:15:11 berliner Exp $
X
X
X			   CVS Kit, Version 1.0
X
X		    Copyright (c) 1989, Brian Berliner
X
X    This program is free software; you can redistribute it and/or modify
X    it under the terms of the GNU General Public License as published by
X    the Free Software Foundation; either version 1, or (at your option)
X    any later version.
X
X    This program is distributed in the hope that it will be useful,
X    but WITHOUT ANY WARRANTY; without even the implied warranty of
X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X    GNU General Public License for more details.
X
X    You should have received a copy of the GNU General Public License
X    along with this program; if not, write to the Free Software
X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
X--------------------------------------------------------------------------
X
XThis is the first release of CVS -- Concurrent Version System.
X
XCVS is a freely available collection of programs that provide for software
Xrelease and revision control functions in a UNIX environment.  It is
Xdesigned to work on top of the RCS distribution, V4 (uses the V4 branch
Xsupport).  CVS does understand how to parse older RCS formats, but cannot
Xdo any of the fancier features (like vendor branch support) without RCS
Xbranch support.
X
XThe conflict-resolution algorithms and much of the administrative file
Xdefinitions of CVS were based on the original package written by Dick Grune
Xat Vrije Universiteit in Amsterdam, and posted to comp.sources.unix in the
Xvolume 6 release sometime in 1986.  This original version was a collection
Xof shell scripts. 
X
XBrian Berliner from Prisma, Inc. converted the original CVS shell scripts
Xinto reasonably fast C and added many, many features to support software
Xrelease control functions.  See the manual page in the "man" directory, and
Xa copy of the USENIX article presented at the Winter 1990 USENIX
XConference, Washington D.C., is included in the "doc" directory.
X
XThis code has been tested extensively on Sun-4 and Sun-3 platforms, all
Xrunning SunOS 4.X.  Your mileage may vary for other systems, and I would
Xreally appreciate hearing back on what was necessary to get this beast
Xworking on other platforms.
X
XInstallation:
X
X1)  Edit the top-level Makefile (in this directory) and set DESTDIR to the
X    location of local binaries.  Also adjust CFLAGS and LDFLAGS
X    appropriately as well.  May also need to edit the man/Makefile file to
X    be sure that manual pages will be dropped in the correct place for your
X    system.
X
X2)  Edit the src/cvs.h header file.  Appropriate things to look at may be
X    the hard-coded locations of programs like DIFF, GREP, RM, and SORT.
X    Also glance at the default values for the environment variables that
X    CVS uses, in particular, the RCSBIN variable, which holds the path to
X    where the RCS programs live on your system.
X
X3)  make depend
X
X    To get the Makefiles to use *your* include dependencies, not mine.
X
X4)  make
X
X    This will (hopefully) make the needed CVS binaries within the "src"
X    directory.
X
X5)  make install
X
X    If all goes well above, install the binaries and manual pages.
X    Depending on your instrallation's configuration, you may need to be
X    root to do this.
X
X6)  man cvs
X
X    Take a look at the CVS manual page to see what it can do for you, and
X    if it fits your environment (or can possibly be made to fit your
X    environment).  If things look good, continue on...
X
X7)  Setup the master source repository.  Choose a directory with ample disk
X    space available for source files.  This is where the RCS ",v" files
X    will be stored.  Say you choose "/src/master" as the root of your
X    source repository.  Make the CVSROOT.adm directory in the root of the
X    source repository:  "mkdir /src/master/CVSROOT.adm".  Populate this
X    directory with the files from the "examples" directory included with
X    this release (loginfo and modules).  Edit these files
X    (/src/master/CVSROOT.adm/{loginfo,modules}) to reflect your local
X    source repository environment -- they may be quite small initially, but
X    will grow as sources are added to your source repository.  Turn these
X    files into RCS controlled files:
X
X		cd /src/master/CVSROOT.adm
X		ci -m'Initial loginfo file' loginfo
X		ci -m'Initial modules file' modules
X
X8)  mkmodules /src/master/CVSROOT.adm
X
X    This will build the ndbm(3) file for the modules database.  mkmodules
X    should have been installed above by the "make install" done in step 5.
X    If mkmodules cannot be found, check your PATH or try "rehash".
X
X9)  Have all users of the CVS system set the CVSROOT environment variable
X    appropriately to reflect the placement of your source repository.  If
X    the above example is used, the following commands can be placed in
X    user's ~/.login or ~/.profile file:
X
X		setenv CVSROOT /src/master
X    for csh users, and
X		CVSROOT=/src/master; export CVSROOT
X    for sh users.
X
X10) It might be a good idea to jump right in and put the CVS distribution
X    directly under CVS control.  From within the top-level directory of the
X    CVS distribution (the one that contains this README file) do the
X    following commands:
X
X		mkdir $CVSROOT/cvs
X		checkin -m 'CVS 1.0 distribution' cvs CVS CVS1_0
X
X11) Having done step 10, one should be able to checkout a copy of the CVS
X    distribution and hack away at the sources with the following command:
X
X		cvs checkout cvs
X
X    This will make the directory "cvs" in your current directory and
X    populate it with the appropriate CVS files and directories.
X
X12) Remember to edit the modules file manually when sources are checked in
X    with "checkin" or "cvs add".  A copy of the modules file for editing
X    can usually be retrieved with the "cvs checkout modules" command, and
X    definitely with the "cvs checkout CVSROOT.adm" command.
X
X13) PLEASE report any problems to me, berliner@prisma.com (Brian Berliner)
X    and I will try to collect patches and enhancements into future CVS
X    distributions.  "patch" format files are best, using context diffs,
X    if you will.
X
X14) GOOD LUCK!
X
X					Brian Berliner
X					berliner@prisma.com
END_OF_FILE
if test 6170 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test ! -d 'doc' ; then
    echo shar: Creating directory \"'doc'\"
    mkdir 'doc'
fi
if test -f 'doc/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/Makefile'\"
else
echo shar: Extracting \"'doc/Makefile'\" \(401 characters\)
sed "s/^X//" >'doc/Makefile' <<'END_OF_FILE'
X#
X#	$Id: Makefile,v 1.1 89/11/19 23:16:41 berliner Exp $
X#
X# Makefile for CVS document for the Winter 1990 USENIX Conference,
X# Washington D.C.
X#
X
XTROFF=		nitroff
XTROFFOPTS=	-ms
XPIC=		pic
XTBL=		tbl
X
XCVSDOC=		cvs.ms
XFILES=		Makefile ${CVSDOC}
X
Xall:
X
Xprint:
X	${PIC} ${CVSDOC} | ${TBL} | ${TROFF} ${TROFFOPTS}
X
Xinstall:
X
Xclean:
X	rm -f *.o core
X
Xlist:
X	@for i in ${FILES}; do\
X		echo $$i;\
X	done
X
Xdepend:
END_OF_FILE
if test 401 -ne `wc -c <'doc/Makefile'`; then
    echo shar: \"'doc/Makefile'\" unpacked with wrong size!
fi
# end of 'doc/Makefile'
fi
if test ! -d 'examples' ; then
    echo shar: Creating directory \"'examples'\"
    mkdir 'examples'
fi
if test -f 'examples/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'examples/Makefile'\"
else
echo shar: Extracting \"'examples/Makefile'\" \(279 characters\)
sed "s/^X//" >'examples/Makefile' <<'END_OF_FILE'
X#
X#	$Id: Makefile,v 1.1 89/11/19 23:17:17 berliner Exp $
X#
X# Makefile for CVS sample files that reside in the $CVSROOT/CVSROOT.adm
X# directory
X#
X
XFILES=		Makefile loginfo modules
X
Xall:
X
Xinstall:
X
Xclean:
X	rm -f *.o core
X
Xlist:
X	@for i in ${FILES}; do\
X		echo $$i;\
X	done
X
Xdepend:
END_OF_FILE
if test 279 -ne `wc -c <'examples/Makefile'`; then
    echo shar: \"'examples/Makefile'\" unpacked with wrong size!
fi
# end of 'examples/Makefile'
fi
if test -f 'examples/loginfo' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'examples/loginfo'\"
else
echo shar: Extracting \"'examples/loginfo'\" \(1027 characters\)
sed "s/^X//" >'examples/loginfo' <<'END_OF_FILE'
X#
X# $Id: loginfo,v 1.1 89/08/24 23:59:59 berliner Exp $
X#
X# The "loginfo" file is used to control where "cvs commit" log information
X# is sent.  The first entry on a line is a regular expression which is tested
X# against the directory that the change is being made to, relative to the
X# $CVSROOT.  If a match is found, then the remainder of the line is a filter
X# program that should expect log information on its standard input.
X#
X# The filter program may use one and only one % modifier (ala printf).  If
X# %s is specified in the filter program, a brief title is included (enclosed
X# in single quotes) showing the modified file names.
X#
X# If the repository name does not match any of the regular expressions in this
X# file, the "DEFAULT" line is used, if it is specified.
X#
XDEFAULT			/usr/local/bin/nfpipe -t %s utils.updates
X^diag			/usr/local/bin/nfpipe -t %s diag.updates
X^local			/usr/local/bin/nfpipe -t %s local.updates
X^perf			/usr/local/bin/nfpipe -t %s perf.updates
X^sys			/usr/local/bin/nfpipe -t %s kernel.updates
END_OF_FILE
if test 1027 -ne `wc -c <'examples/loginfo'`; then
    echo shar: \"'examples/loginfo'\" unpacked with wrong size!
fi
# end of 'examples/loginfo'
fi
if test ! -d 'man' ; then
    echo shar: Creating directory \"'man'\"
    mkdir 'man'
fi
if test -f 'man/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/Makefile'\"
else
echo shar: Extracting \"'man/Makefile'\" \(440 characters\)
sed "s/^X//" >'man/Makefile' <<'END_OF_FILE'
X#
X#	$Id: Makefile,v 1.1 89/11/19 23:17:41 berliner Exp $
X#
X# Makefile for CVS Manual Pages
X#
XMANSEC=		l
XMANEXT=		.man
XMANDIR=		/usr/man/man${MANSEC}
XMANSRCS=	cvs${MANEXT} mkmodules${MANEXT} checkin${MANEXT}
X
XFILES=		Makefile ${MANSRCS}
X
Xall:
X
Xinstall:
X	for i in ${MANSRCS}; do\
X		install -m 644 $$i\
X			${MANDIR}/`basename $$i ${MANEXT}`.${MANSEC};\
X	done
X
Xclean:
X	rm -f *.o core
X
Xlist:
X	@for i in ${FILES}; do\
X		echo $$i;\
X	done
X
Xdepend:
END_OF_FILE
if test 440 -ne `wc -c <'man/Makefile'`; then
    echo shar: \"'man/Makefile'\" unpacked with wrong size!
fi
# end of 'man/Makefile'
fi
if test -f 'man/checkin.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/checkin.man'\"
else
echo shar: Extracting \"'man/checkin.man'\" \(3081 characters\)
sed "s/^X//" >'man/checkin.man' <<'END_OF_FILE'
X.\"
X.\"	$Id: checkin.man,v 1.2 89/11/19 23:17:43 berliner Exp $
X.\"
X.TH CHECKIN L "16 November 1989"
X.SH "NAME"
Xcheckin \- Check a vendor source distribution into CVS
X.SH "SYNOPSIS"
X.B checkin 
X[
X.I \-v
X] [
X.I \-m message
X] [
X.I \-f message_file
X] 
X.I repository vendor_tag vendor_release_tag
X.SH "DESCRIPTION"
X.LP
X.B checkin
Xtraverses the tree rooted at the current directory checking all files 
Xinto the vendor branch of the repository directory located at 
X.IR CVSROOT/repository .
XIf 
X.I SCCS 
Xor 
X.I RCS 
Xdirectories exist under the current directory, 
X.B checkin 
Xchecks out all files before committing them to the repository.  Any 
X.I RCS
Xor
X.I SCCS 
Xdirectories are then ignored when the files are checked in.
X.LP
X.B checkin
Xlogs all updates to locally modified files, new files, and new 
Xdirectories to the standard output. If the 
X.I \-v
Xoption is specified it will log all updates instead of just the
Xinteresting ones.
X.LP
XWhen invoked with the 
X.I \-m
Xflag, 
X.B checkin 
Xtakes the next argument to be the log message to use when 
Xchecking in the files.  The 
X.I \-f
Xflag specifies the name of a file to use as the log message.  If 
Xneither 
X.I \-m
Xor 
X.I \-f
Xis specified, 
X.B checkin 
Xinvokes your favorite editor for you to create a log message.
X.LP
XEach file is checked into the vendor branch specified by the 
X.I vendor_tag 
Xon the command line.  If the specified branch does not exist, 
X.B checkin
Xcreates the branch 1.1.1 and labels it with the specified tag.  As
Xeach file is checked in, it is labeled with the 
X.I vendor_release_tag 
Xand logged with the specified log message.
X.LP 
X.B checkin 
Xalso understands about the way 
X.B cvs
Xremoves files from a repository by moving them to an 
X.I attic
Xsub-directory.
XIf a new version of a removed file is encountered, 
X.B checkin 
Xwill update the copy of the file in the attic and will log 
Xthe update to the standard output.  The file can be brought back 
Xinto existence with the 
X.B cvs
X.I add
Xcommand (see the 
X.B cvs
Xman page for more details).
X.LP
XIf 
X.B checkin
Xencounters a file with an extension that 
X.BI rcs (l)
Xdoesn't recognize that contains the 
X.BI rcs (l)
X.I $log$ 
Xheader, it will prompt the terminal for a comment leader for that
Xtype of file.
X.SH "OPTIONS"
X.TP
X.I \-v
Xcauses 
X.B checkin
Xto print a message as all files are updated instead of only printing 
Xthem for 
X.I interesting
Xones.
X.TP
X.I \-m message
Xspecifies the string to use as the log message for each update.
X.TP
X.I \-f file
Xspecifies a file containing the log message to use for each update.
X.SH "ENVIRONMENT VARIABLES"
X.TP
X.SM CVSROOT
Xspecifies the location of the root of the source repository.
XThis variable must be present for 
X.B checkin 
Xto continue.
X.TP
X.SM EDITOR
Xspecifies your favorite editor (defaults to 
X.BR vi ).
X.SH "SEE ALSO"
X.BR ci (l),
X.BR cvs (l),
X.BR rcs (l).
X.SH "BUGS"
X.LP
XShould know how to parse the 
X.I CVSROOT/CVSROOT.adm/loginfo 
Xfile to log all updates according to the same scheme as 
X.B cvs 
Xitself.
X.LP
XIts a real CPU pig, but it works okay and isn't used nearly 
Xas much as other portions of 
X.BR cvs .
X
END_OF_FILE
if test 3081 -ne `wc -c <'man/checkin.man'`; then
    echo shar: \"'man/checkin.man'\" unpacked with wrong size!
fi
# end of 'man/checkin.man'
fi
if test -f 'man/mkmodules.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/mkmodules.man'\"
else
echo shar: Extracting \"'man/mkmodules.man'\" \(1113 characters\)
sed "s/^X//" >'man/mkmodules.man' <<'END_OF_FILE'
X.\"
X.\"	$Id: mkmodules.man,v 1.1 89/10/18 11:16:41 berliner Exp $
X.\"
X.TH MKMODULES L "9 October 1989"
X.SH "NAME"
Xmkmodules \- Rebuild modules database for CVS
X.SH "SYNOPSIS"
X.B mkmodules
X.I directory
X.SH "DESCRIPTION"
X.B mkmodules
Xrebuilds the modules database that
X.BR cvs (l)
Xuses.
XThe
X.I directory
Xspecified is expected to contain the
X.BR modules,v " and " loginfo,v
Xfiles.
X.B mkmodules
Xcarefully checks out the current head revisions of each of these files and
Xreuilds the
X.BR ndbm (3)
Xformat modules database.
XA warning is generated if the modules file contains a duplicate key.
X.SH "FILES"
X.TP
Xmodules,v
XThe modules
X.SM RCS
Xfile.
X.TP
Xmodules
XThe checked out modules file.
X.TP
Xloginfo,v
XThe loginfo
X.SM RCS
Xfile.
X.TP
Xloginfo
XThe checked out loginfo file.
X.TP
Xmodules.dir, modules.pag
XThe
X.BR ndbm (l)
Xformat modules database.
X.SH "ENVIRONMENT VARIABLES"
X.TP
X.SM RCSBIN
XSpecifies the full pathname where to find
X.SM RCS
Xprograms, such as
X.BR co (l)
Xand
X.BR ci (l).
XIf not set, the default is
X.BR /usr/local/bin .
X.SH "SEE ALSO"
X.BR checkin (l),
X.BR co (l),
X.BR cvs (l),
X.BR ndbm (3),
X.BR rcs (l),
X.SH "BUGS"
END_OF_FILE
if test 1113 -ne `wc -c <'man/mkmodules.man'`; then
    echo shar: \"'man/mkmodules.man'\" unpacked with wrong size!
fi
# end of 'man/mkmodules.man'
fi
if test ! -d 'src' ; then
    echo shar: Creating directory \"'src'\"
    mkdir 'src'
fi
if test -f 'src/build_entry.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/build_entry.c'\"
else
echo shar: Extracting \"'src/build_entry.c'\" \(2581 characters\)
sed "s/^X//" >'src/build_entry.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: build_entry.c,v 1.9 89/11/19 23:19:45 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Build Entry
X *
X *	Builds an entry for a new file and sets up "CVS.adm/file",[pt] by
X *	interrogating the user.
X *
X *	Returns non-zero on error.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
XBuild_Entry(message)
X    char *message;
X{
X    char fname[MAXPATHLEN];
X    char line[MAXLINELEN];
X    FILE *fp, *fptty;
X
X    /*
X     * There may be an old file with the same name in the Attic!
X     * This is, perhaps, an awkward place to check for this, but
X     * other places are equally awkward.
X     */
X    (void) sprintf(fname, "%s/%s/%s%s", Repository, CVSATTIC, User, RCSEXT);
X    if (isreadable(fname)) {
X	warn(0, "there is an old file %s already in %s/%s", User,
X	     Repository, CVSATTIC);
X	return (1);
X    }
X    /*
X     * The options for the "add" command are store in the file CVS.adm/User,p
X     */
X    (void) sprintf(fname, "%s/%s%s", CVSADM, User, CVSEXT_OPT);
X    fp = open_file(fname, "w+");
X    if (fprintf(fp, "%s\n", Options) == EOF)
X	error(1, "cannot write %s", fname);
X    (void) fclose(fp);
X    /*
X     * And the requested log is read directly from the user and stored
X     * in the file User,t.  If the "message" argument is set, then the
X     * user specified the -m option to add, and it is not necessary to
X     * query him from the terminal.
X     */
X    (void) sprintf(fname, "%s/%s%s", CVSADM, User, CVSEXT_LOG);
X    fp = open_file(fname, "w+");
X    if (message[0] == '\0') {
X	printf("RCS file: %s\n", Rcs);
X	printf("enter description, terminated with ^D or '.':\n");
X	printf("NOTE: This is NOT the log message!\n");
X	fptty = open_file("/dev/tty", "r");
X	for (;;) {
X	    printf(">> ");
X	    (void) fflush(stdout);
X	    if (fgets(line, sizeof(line), fptty) == NULL ||
X		(line[0] == '.' && line[1] == '\n'))
X		break;
X	    if (fputs(line, fp) == EOF)
X		error(1, "cannot write to %s", fname);
X	}
X	printf("done\n");
X	(void) fclose(fptty);
X    } else {
X	if (fputs(message, fp) == EOF)
X	    error(1, "cannot write to %s", fname);
X    }
X    (void) fclose(fp);
X    /*
X     * Create the entry now, since this allows the user to interrupt
X     * us above without needing to clean anything up (well, we could
X     * clean up the ,p and ,t files, but who cares).
X     */
X    (void) sprintf(line, "Initial %s", User);
X    Register(User, "0", line);
X    return (0);
X}
END_OF_FILE
if test 2581 -ne `wc -c <'src/build_entry.c'`; then
    echo shar: \"'src/build_entry.c'\" unpacked with wrong size!
fi
# end of 'src/build_entry.c'
fi
if test -f 'src/create_admin.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/create_admin.c'\"
else
echo shar: Extracting \"'src/create_admin.c'\" \(1321 characters\)
sed "s/^X//" >'src/create_admin.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: create_admin.c,v 1.7 89/11/19 23:19:55 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Create Administration.
X *
X *	Creates a CVS administration directory based on the argument
X *	repository; the "Entries" file is prefilled from the "initrecord"
X *	argument.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
XCreate_Admin(repository, initrecord)
X    register char *repository;
X    register char *initrecord;
X{
X    register FILE *fout;
X    char *cp;
X
X    if (!isdir(repository))
X	error(0, "there is no repository %s", repository);
X    if (!isfile(initrecord))
X	error(0, "there is no file %s", initrecord);
X    if (isfile(CVSADM))
X	error(0, "there is a version here already");
X    make_directory(CVSADM);
X    fout = open_file(CVSADM_REP, "w+");
X    cp = repository;
X    if (CVSroot != NULL) {
X	char path[MAXPATHLEN];
X
X	(void) sprintf(path, "%s/", CVSroot);
X	if (strncmp(repository, path, strlen(path)) == 0)
X	    cp = repository + strlen(path);
X    }
X    if (fprintf(fout, "%s\n", cp) == EOF)
X	error(1, "write to %s failed", CVSADM_REP);
X    (void) fclose(fout);
X    copy_file(initrecord, CVSADM_ENT);
X}
END_OF_FILE
if test 1321 -ne `wc -c <'src/create_admin.c'`; then
    echo shar: \"'src/create_admin.c'\" unpacked with wrong size!
fi
# end of 'src/create_admin.c'
fi
if test -f 'src/entries_file.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/entries_file.c'\"
else
echo shar: Extracting \"'src/entries_file.c'\" \(1342 characters\)
sed "s/^X//" >'src/entries_file.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: entries_file.c,v 1.6 89/11/19 23:20:00 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Entries file to Files file
X *
X * Creates the file Files containing the names that comprise
X * the project, from the Entries file.
X */
X
X#include "cvs.h"
X
XEntries2Files()
X{
X    register FILE *fpin, *fpout;
X    register int num = 0;
X    register char *cp;
X    char line[MAXLINELEN];
X    char *fnames[MAXFILEPERDIR];
X
X    fpin = open_file(CVSADM_ENT, "r");
X    fpout = open_file(CVSADM_FILE, "w+");
X    while (fgets(line, sizeof(line), fpin) != NULL) {
X	if ((cp = rindex(line, '|')) == NULL)
X	    continue;
X	*cp = '\0';
X	if ((cp = rindex(line, ' ')) == NULL)
X	    continue;
X	cp++;
X	fnames[num] = xmalloc(strlen(cp) + 1);
X	(void) strcpy(fnames[num++], cp);
X	if (num >= MAXFILEPERDIR)
X	    error(0, "more than %d files is too many", MAXFILEPERDIR);
X    }
X    if (num) {
X	qsort((char *)&fnames[0], num, sizeof(fnames[0]), ppstrcmp_files);
X	while (num--) {
X	    if (fprintf(fpout, "%s\n", fnames[num]) == EOF)
X		error(1, "cannot write %s", CVSADM_FILE);
X	    free(fnames[num]);
X	}
X    }
X    (void) fclose(fpin);
X    (void) fclose(fpout);
X}
END_OF_FILE
if test 1342 -ne `wc -c <'src/entries_file.c'`; then
    echo shar: \"'src/entries_file.c'\" unpacked with wrong size!
fi
# end of 'src/entries_file.c'
fi
if test -f 'src/find_names.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/find_names.c'\"
else
echo shar: Extracting \"'src/find_names.c'\" \(3312 characters\)
sed "s/^X//" >'src/find_names.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: find_names.c,v 1.11 89/11/19 23:20:02 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Find Names
X *
X *	Writes all the pertinent file names, both from the administration
X *	and from the repository to the argc/argv arguments.
X *
X *	The names should be freed by callin free_names() when they are no
X *	longer needed.
X *
X *	Note that Find_Names() honors the administration Entries.Static file
X *	to indicate that the Repository should not be searched for new files.
X */
X
X#include <sys/param.h>
X#include <sys/types.h>
X#include <dirent.h>
X#include "cvs.h"
X
XFind_Names(pargc, argv, which)
X    int *pargc;
X    char *argv[];
X    enum ftype which;
X{
X    char dir[MAXPATHLEN], line[MAXLINELEN];
X    FILE *fpin;
X    char *cp;
X
X    *pargc = 0;
X    argv[0] = NULL;			/* Assume none */
X    if (which == MOD) {
X	fpin = open_file(CVSADM_MOD, "r");
X	/*
X	 * Parse the Mod file, and calling addname() for each line.
X	 */
X	while (fgets(line, sizeof(line), fpin) != NULL) {
X	    if ((cp = rindex(line, '\n')) != NULL)
X		*cp = '\0';
X	    *cp = '\0';
X	    addname(pargc, argv, line);
X	}
X	(void) fclose(fpin);
X    } else {
X	fpin = open_file(CVSADM_ENT, "r");
X	/*
X	 * Only scan for ,v files if Entries.Static does not exist
X	 */
X	if (!isfile(CVSADM_ENTSTAT)) {
X	    if (find_rcs(Repository, pargc, argv) != 0)
X		error(1, "cannot open directory %s", Repository);
X	    if (which == ALLPLUSATTIC) {
X		(void) sprintf(dir, "%s/%s", Repository, CVSATTIC);
X		(void) find_rcs(dir, pargc, argv);
X	    }
X	}
X	/*
X	 * Parse the Entries file, and calling addname() for each one.
X	 */
X	while (fgets(line, sizeof(line), fpin) != NULL) {
X	    if ((cp = rindex(line, '|')) == NULL)
X		continue;
X	    *cp = '\0';
X	    if ((cp = rindex(line, ' ')) == NULL)
X		continue;
X	    cp++;
X	    addname(pargc, argv, cp);
X	}
X	(void) fclose(fpin);
X    }
X    /*
X     * And finally, sort the names so that they look reasonable
X     * as they are processed (there *is* order in the world)
X     */
X    qsort((char *)&argv[0], *pargc, sizeof(argv[0]), ppstrcmp);
X}
X
X/*
X * Finds all the ,v files in the argument directory, and adds them to the
X * argv list.  Returns 0 for success and non-zero if the argument
X * directory cannot be opened.
X */
Xstatic
Xfind_rcs(dir, pargc, argv)
X    char *dir;
X    int *pargc;
X    char *argv[];
X{
X    char *cp, line[50];
X    struct dirent *dp;
X    DIR *dirp;
X
X    if ((dirp = opendir(dir)) == NULL)
X	return (1);
X    (void) sprintf(line, ".*%s$", RCSEXT);
X    if ((cp = re_comp(line)) != NULL)
X	error(0, "%s", cp);
X    while ((dp = readdir(dirp)) != NULL) {
X	if (re_exec(dp->d_name)) {
X	    /* strip the ,v */
X	    *rindex(dp->d_name, ',') = '\0';
X	    addname(pargc, argv, dp->d_name);
X	}
X    }
X    (void) closedir(dirp);
X    return (0);
X}
X
X/*
X * addname() adds a name to the argv array, only if it is not in
X * the array already
X */
Xstatic
Xaddname(pargc, argv, name)
X    int *pargc;
X    char *argv[];
X    char *name;
X{
X    register int i;
X
X    for (i = 0; i < *pargc; i++) {
X	if (strcmp(argv[i], name) == 0)
X	    return;
X    }
X    (*pargc)++;
X    argv[i] = xmalloc(strlen(name) + 1);
X    (void) strcpy(argv[i], name);
X}
END_OF_FILE
if test 3312 -ne `wc -c <'src/find_names.c'`; then
    echo shar: \"'src/find_names.c'\" unpacked with wrong size!
fi
# end of 'src/find_names.c'
fi
if test -f 'src/join.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/join.c'\"
else
echo shar: Extracting \"'src/join.c'\" \(3305 characters\)
sed "s/^X//" >'src/join.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: join.c,v 1.4 89/11/19 23:40:36 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Join
X *
X *	Do an implicit checkout and merge between RCS revisions in the
X *	RCS file.  This is most always used after the "checkin" script
X *	has added new revisions to files that have been locally modified.
X *	A manual "join" command can be run on the files listed in the
X *	"checkin" output to produce an "rcsmerge" of the current revision
X *	and the specified vendor branch revision.
X *
X *	Need to be careful if the local user file has been checked out and
X *	is modified.  Don't want to mess with it in this case.
X */
X
X#include "cvs.h"
X
Xextern char update_dir[];
Xextern int force_tag_match;
X
Xjoin(argc, argv)
X    int argc;
X    char *argv[];
X{
X    register int i;
X    int c, err = 0;
X
X    if (argc == -1)
X	join_usage();
X    optind = 1;
X    while ((c = getopt(argc, argv, "fQqD:r:")) != -1) {
X	switch (c) {
X	case 'Q':
X	    really_quiet = 1;
X	    /* FALL THROUGH */
X	case 'q':
X	    quiet = 1;
X	    break;
X	case 'f':
X	    force_tag_match = 1;
X	    break;
X	case 'D':
X	    if (Tag[0] != '\0' || Date[0] != '\0')
X		error(0, "no more than one revision/date can be specified");
X	    Make_Date(optarg, Date);
X	    break;
X	case 'r':
X	    if (Tag[0] != '\0' || Date[0] != '\0')
X		error(0, "no more than one revision/date can be specified");
X	    (void) strcpy(Tag, optarg);
X	    break;
X	case '?':
X	default:
X	    join_usage();
X	    break;
X	}
X    }
X    argc -= optind;
X    argv += optind;
X    if (argc < 1)
X	join_usage();
X    if (Tag[0] == '\0' && Date[0] == '\0')
X	error(0, "must specify one revision/date!");
X    Name_Repository();
X    Reader_Lock();
X    (void) Collect_Sets(argc, argv);
X    if (Clist[0] || Glist[0] || Mlist[0] || Alist[0] || Rlist[0] || Wlist[0])
X	error(0, "conflicts exist; cannot join a modified file");
X    if (Dlist[0])
X	error(0, "cannot join directories -%s", Dlist);
X    for (i = 0; i < argc; i++)
X	err += join_file(argv[i]);
X    Lock_Cleanup(0);
X    exit(err);
X}
X
X/*
X * Called for each file that is to be "join"ed.  Need to find out if the
X * file is modified or not, and blow it off if it is.
X */
Xstatic
Xjoin_file(file)
X    char *file;
X{
X    char vers[50];
X
X    (void) strcpy(User, file);
X    (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
X    Version_Number(Rcs, Tag, Date, vers);
X    if (vers[0] == '\0') {
X	if (!quiet)
X	    warn(0, "cannot find revision %s for %s", Tag[0] ? Tag:Date, Rcs);
X	return (1);
X    }
X    (void) unlink(User);
X    Scratch_Entry(User);
X    (void) sprintf(prog, "%s/%s -j%s %s %s", Rcsbin, RCS_CO, vers, Rcs, User);
X    if (system(prog) != 0) {
X	if (!quiet)
X	    warn(0, "co of revision %s for %s failed", VN_Rcs, Rcs);
X	return (1);
X    }
X    if (!really_quiet)
X	printf("J %s\n", User);
X    if (cvswrite == TRUE)
X	xchmod(User, 1);
X    Version_TS(Rcs, "", User);		/* For head */
X    (void) sprintf(TS_User, "joined %s", User);	/* To appear to be modified */
X    Register(User, VN_Rcs, TS_User);
X    return (0);
X}
X
Xstatic
Xjoin_usage()
X{
X    (void) fprintf(stderr, "%s %s [-Qqf] [-r tag|-D date] files...\n",
X		   progname, command);
X    exit(1);
X}
END_OF_FILE
if test 3305 -ne `wc -c <'src/join.c'`; then
    echo shar: \"'src/join.c'\" unpacked with wrong size!
fi
# end of 'src/join.c'
fi
if test -f 'src/locate_rcs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/locate_rcs.c'\"
else
echo shar: Extracting \"'src/locate_rcs.c'\" \(845 characters\)
sed "s/^X//" >'src/locate_rcs.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: locate_rcs.c,v 1.5 89/11/19 23:20:05 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Locate RCS File
X *
X * Called when the RCS file sought may be in the Attic directory.
X * Sets the global Rcs variable to the correct file.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
XLocate_RCS()
X{
X    char old[MAXPATHLEN];
X
X    (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
X    (void) sprintf(old, "%s/%s/%s%s", Repository, CVSATTIC, User, RCSEXT);
X    if (!isreadable(Rcs)) {
X	if (isreadable(old)) {
X	    (void) strcpy(Rcs, old);
X	} else {
X	    /*
X	     * it is treated as if it were in the repository
X	     */
X	}
X    }
X}
END_OF_FILE
if test 845 -ne `wc -c <'src/locate_rcs.c'`; then
    echo shar: \"'src/locate_rcs.c'\" unpacked with wrong size!
fi
# end of 'src/locate_rcs.c'
fi
if test -f 'src/log.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/log.c'\"
else
echo shar: Extracting \"'src/log.c'\" \(1360 characters\)
sed "s/^X//" >'src/log.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: log.c,v 1.9 89/11/19 23:40:37 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Print Log Information
X *
X *	Prints the RCS "log" (rlog) information for the specified
X *	files.  With no argument, prints the log information for
X *	all the files in the directory.
X */
X
X#include "cvs.h"
X
Xlog(argc, argv)
X    int argc;
X    char *argv[];
X{
X    register int i;
X    int numopt, err = 0;
X    char *cp;
X
X    if (argc == -1)
X	log_usage();
X    Name_Repository();
X    /*
X     * All 'log' command options are passed directly on to 'rlog'
X     */
X    numopt = Get_Options(--argc, ++argv);
X    argc -= numopt;
X    argv += numopt;
X    if (argc == 0) {
X	Find_Names(&fileargc, fileargv, ALL);
X	argc = fileargc;
X	argv = fileargv;
X    }
X    (void) sprintf(prog, "%s/%s %s", Rcsbin, RCS_RLOG, Options);
X    cp = prog + strlen(prog);
X    for (i = 0; i < argc; i++) {
X	(void) strcpy(User, argv[i]);
X	Locate_RCS();
X	(void) strcpy(cp, " ");
X	(void) strcpy(cp+1, Rcs);
X	cp += strlen(Rcs) + 1;
X    }
X    err = system(prog);
X    exit(err);
X}
X
Xstatic
Xlog_usage()
X{
X    (void) fprintf(stderr,
X		   "%s %s [rlog-options] [files...]\n", progname, command);
X    exit(1);
X}
END_OF_FILE
if test 1360 -ne `wc -c <'src/log.c'`; then
    echo shar: \"'src/log.c'\" unpacked with wrong size!
fi
# end of 'src/log.c'
fi
if test -f 'src/name_repository.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/name_repository.c'\"
else
echo shar: Extracting \"'src/name_repository.c'\" \(1740 characters\)
sed "s/^X//" >'src/name_repository.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: name_repository.c,v 1.9 89/11/19 23:20:13 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Name of Repository
X *
X *	Determine the name of the RCS repository and sets "Repository"
X *	accordingly.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
XName_Repository()
X{
X    FILE *fpin;
X    char path[MAXPATHLEN];
X    char *cp;
X
X    if (!isdir(CVSADM))
X	error(0, "there is no version here; do '%s checkout' first", progname);
X    if (!isreadable(CVSADM_REP) || !isreadable(CVSADM_ENT))
X	error(0, "*PANIC* administration files missing");
X    /*
X     * The assumption here is the the repository is always contained
X     * in the first line of the "Repository" file.
X     */
X    fpin = open_file(CVSADM_REP, "r");
X    if (fgets(Repository, MAXPATHLEN, fpin) == NULL)
X	error(1, "cannot read %s", CVSADM_REP);
X    (void) fclose(fpin);
X    if ((cp = rindex(Repository, '\n')) != NULL)
X	*cp = '\0';			/* strip the newline */
X    /*
X     * If this is a relative repository pathname, turn it into
X     * an absolute one by tacking on the CVSROOT environment variable.
X     * If the CVSROOT environment variable is not set, die now.
X     */
X    if (Repository[0] != '/') {
X	if (CVSroot == NULL) {
X	    (void) fprintf(stderr,
X			   "%s: must set the CVSROOT environment variable\n",
X			   progname);
X	    error(0, "or specify the '-d' option to %s", progname);
X	}
X	(void) strcpy(path, Repository);
X	(void) sprintf(Repository, "%s/%s", CVSroot, path);
X    }
X    if (!isdir(Repository))
X	error(0, "there is no repository %s", Repository);
X}
END_OF_FILE
if test 1740 -ne `wc -c <'src/name_repository.c'`; then
    echo shar: \"'src/name_repository.c'\" unpacked with wrong size!
fi
# end of 'src/name_repository.c'
fi
if test -f 'src/no_difference.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/no_difference.c'\"
else
echo shar: Extracting \"'src/no_difference.c'\" \(1789 characters\)
sed "s/^X//" >'src/no_difference.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: no_difference.c,v 1.7 89/11/19 23:20:16 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * No Difference
X *
X * The user file looks modified judging from its time stamp; however
X * it needn't be.  No_difference() finds out whether it is or not.
X * If it is, it adds its name to the Mlist.
X * If it is not, it updates the administration.
X *
X * If we're deciding if a modified file that is to be merged is really
X * modified (doGlist is set), we add the name to the Glist if it really
X * is modified, otherwise it is added to the Olist to be simply extracted.
X *
X * Returns non-zero on error.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
XNo_Difference(doGlist)
X    int doGlist;
X{
X    char tmp[MAXPATHLEN];
X
X    (void) sprintf(tmp, "%s/%s%s", CVSADM, CVSPREFIX, User);
X    (void) sprintf(prog, "%s/%s -p -q -r%s %s > %s", Rcsbin, RCS_CO,
X		   VN_User, Rcs, tmp);
X    if (system(prog) == 0) {
X	if (xcmp(User, tmp) == 0) {
X	    if (cvswrite == FALSE)
X		xchmod(User, 0);
X	    Version_TS(Rcs, Tag, User);
X	    (void) strcpy(TS_Rcs, TS_User);
X	    Register(User, VN_Rcs, TS_User);
X	    if (doGlist) {
X		(void) strcat(Olist, " ");
X		(void) strcat(Olist, User);
X	    }
X	} else {
X	    if (!iswritable(User))
X		xchmod(User, 1);
X	    Version_TS(Rcs, Tag, User);
X	    if (doGlist) {
X		(void) strcat(Glist, " ");
X		(void) strcat(Glist, User);
X	    } else {
X		(void) strcat(Mlist, " ");
X		(void) strcat(Mlist, User);
X	    }
X	}
X	(void) unlink(tmp);
X    } else {
X	warn(0, "could not check out revision %s of %s", VN_User, User);
X	(void) unlink(tmp);
X	return (1);
X    }
X    return (0);
X}
END_OF_FILE
if test 1789 -ne `wc -c <'src/no_difference.c'`; then
    echo shar: \"'src/no_difference.c'\" unpacked with wrong size!
fi
# end of 'src/no_difference.c'
fi
if test -f 'src/options.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/options.c'\"
else
echo shar: Extracting \"'src/options.c'\" \(830 characters\)
sed "s/^X//" >'src/options.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: options.c,v 1.5 89/11/19 23:20:18 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Get Options
X *
X * Collects options from argc/argv and stuffs them into the
X * global Options variable.
X *
X * Returns the number of options grabbed.
X */
X
X#include "cvs.h"
X
XGet_Options(argc, argv)
X    int argc;
X    char *argv[];
X{
X    register int i;
X    register int numopts = 0;
X
X    Options[0] = '\0';			/* Assume none */
X    for (i = 0; i < argc; i++) {
X	if (argv[i][0] == '-' || argv[i][0] == '\0') {
X	    numopts++;
X	    (void) strcat(Options, " ");
X	    (void) strcat(Options, argv[i]);
X	}
X    }
X    return (numopts);
X}
END_OF_FILE
if test 830 -ne `wc -c <'src/options.c'`; then
    echo shar: \"'src/options.c'\" unpacked with wrong size!
fi
# end of 'src/options.c'
fi
if test -f 'src/patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/patchlevel.h'\"
else
echo shar: Extracting \"'src/patchlevel.h'\" \(85 characters\)
sed "s/^X//" >'src/patchlevel.h' <<'END_OF_FILE'
X/*	$Id: patchlevel.h,v 1.1 89/11/20 00:06:30 berliner Exp $	*/
X
X#define	PATCHLEVEL	0
END_OF_FILE
if test 85 -ne `wc -c <'src/patchlevel.h'`; then
    echo shar: \"'src/patchlevel.h'\" unpacked with wrong size!
fi
# end of 'src/patchlevel.h'
fi
if test -f 'src/rcstime.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/rcstime.h'\"
else
echo shar: Extracting \"'src/rcstime.h'\" \(1351 characters\)
sed "s/^X//" >'src/rcstime.h' <<'END_OF_FILE'
X#define TIMEID "$Id: rcstime.h,v 1.1 89/05/09 11:51:03 berliner Exp $"
X
X/* Structure for use by time manipulating subroutines.
X * The following library routines use it:
X *	libc: ctime, localtime, gmtime, asctime
X *	libcx: partime, maketime (may not be installed yet)
X */
X
Xstruct tm {     /* See defines below for allowable ranges */
X	int tm_sec;
X	int tm_min;
X	int tm_hour;
X	int tm_mday;
X	int tm_mon;
X	int tm_year;
X	int tm_wday;
X	int tm_yday;
X	int tm_isdst;
X	int tm_zon;	/* NEW: mins westward of Greenwich */
X	int tm_ampm;	/* NEW: 1 if AM, 2 if PM */
X};
X
X#define LCLZONE (5*60)	/* Until V7 ftime(2) works, this defines local zone*/
X#define TMNULL (-1)	/* Items not specified are given this value
X			 * in order to distinguish null specs from zero
X			 * specs.  This is only used by partime and
X			 * maketime. */
X
X	/* Indices into TM structure */
X#define TM_SEC 0	/* 0-59			*/
X#define TM_MIN 1	/* 0-59			*/
X#define TM_HOUR 2	/* 0-23			*/
X#define TM_MDAY 3	/* 1-31			day of month */
X#define TM_DAY TM_MDAY	/*  "			synonym      */
X#define TM_MON 4	/* 0-11			*/
X#define TM_YEAR 5	/* (year-1900) (year)	*/
X#define TM_WDAY 6	/* 0-6			day of week (0 = Sunday) */
X#define TM_YDAY 7	/* 0-365		day of year */
X#define TM_ISDST 8	/* 0 Std, 1 DST		*/
X	/* New stuff */
X#define TM_ZON 9	/* 0-(24*60) minutes west of Greenwich */
X#define TM_AMPM 10	/* 1 AM, 2 PM		*/
END_OF_FILE
if test 1351 -ne `wc -c <'src/rcstime.h'`; then
    echo shar: \"'src/rcstime.h'\" unpacked with wrong size!
fi
# end of 'src/rcstime.h'
fi
if test -f 'src/register.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/register.c'\"
else
echo shar: Extracting \"'src/register.c'\" \(737 characters\)
sed "s/^X//" >'src/register.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: register.c,v 1.5 89/11/19 23:20:21 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Register
X *
X *	Enters the given file name/version/time-stamp into the administration,
X *	removing the old entry first, if necessary.
X */
X
X#include "cvs.h"
X
XRegister(fname, vn, ts)
X    char *fname;
X    char *vn;
X    char *ts;
X{
X    FILE *fpin;
X
X    Scratch_Entry(fname);
X    fpin = open_file(CVSADM_ENT, "a");
X    if (fprintf(fpin, "%s|%s|\n", vn, ts) == EOF)
X	error(1, "cannot write to file %s", fname);
X    (void) fclose(fpin);
X}
END_OF_FILE
if test 737 -ne `wc -c <'src/register.c'`; then
    echo shar: \"'src/register.c'\" unpacked with wrong size!
fi
# end of 'src/register.c'
fi
if test -f 'src/remove.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/remove.c'\"
else
echo shar: Extracting \"'src/remove.c'\" \(2134 characters\)
sed "s/^X//" >'src/remove.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: remove.c,v 1.9 89/11/19 23:40:43 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Remove a File
X *
X *	Removes entries from the present version.
X *	The entries will be removed from the RCS repository upon the
X *	next "commit".
X *
X *	"remove" accepts no options, only file names that are to be
X *	removed.  The file must not exist in the current directory
X *	for "remove" to work correctly.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
Xremove(argc, argv)
X    int argc;
X    char *argv[];
X{
X    register int i;
X    char fname[MAXPATHLEN];
X    int err = 0;
X
X    if (argc == 1 || argc == -1)
X	remove_usage();
X    argc--;
X    argv++;
X    Name_Repository();
X    for (i = 0; i < argc; i++) {
X	(void) strcpy(User, argv[i]);
X	Version_TS(Rcs, Tag, User);
X	if (TS_User[0] != '\0') {
X	    warn(0, "%s still exists", User);
X	    err++;
X	    continue;
X	}
X	if (VN_User[0] == '\0') {
X	    warn(0, "there is no entry for %s", User);
X	    err++;
X	} else if (VN_User[0] == '0' && VN_User[1] == '\0') {
X	    /*
X	     * It's a file that has been added, but not commited yet.
X	     * So, remove the ,p and ,t file for it and scratch it from
X	     * the entries file.
X	     */
X	    Scratch_Entry(User);
X	    (void) sprintf(fname, "%s/%s%s", CVSADM, User, CVSEXT_OPT);
X	    (void) unlink(fname);
X	    (void) sprintf(fname, "%s/%s%s", CVSADM, User, CVSEXT_LOG);
X	    (void) unlink(fname);
X	} else if (VN_User[0] == '-') {
X	    /*
X	     * It's already been flagged for removal, nothing more to do.
X	     */
X	    warn(0, "%s was already removed", User);
X	    err++;
X	} else {
X	    /*
X	     * Re-register it with a negative version number.
X	     */
X	    (void) strcpy(fname, "-");
X	    (void) strcat(fname, VN_User);
X	    Register(User, fname, TS_Rcs);
X	}
X    }
X    Entries2Files();			/* and update the Files file */
X    exit(err);
X}
X
Xstatic
Xremove_usage()
X{
X    (void) fprintf(stderr, "%s %s files...\n", progname, command);
X    exit(1);
X}
END_OF_FILE
if test 2134 -ne `wc -c <'src/remove.c'`; then
    echo shar: \"'src/remove.c'\" unpacked with wrong size!
fi
# end of 'src/remove.c'
fi
if test -f 'src/scratch_entry.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/scratch_entry.c'\"
else
echo shar: Extracting \"'src/scratch_entry.c'\" \(1085 characters\)
sed "s/^X//" >'src/scratch_entry.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: scratch_entry.c,v 1.5 89/11/19 23:20:24 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Scratch Entry
X *
X * Removes the argument file from the Entries file.  A backup of the previous
X * Entries file is placed in Entries.backup.
X */
X
X#include <sys/param.h>
X#include "cvs.h"
X
XScratch_Entry(fname)
X    char *fname;
X{
X    FILE *fpin, *fpout;
X    char line[MAXLINELEN];
X    char *cp, *cpend;
X
X    rename_file(CVSADM_ENT, CVSADM_ENTBAK);
X    fpin = open_file(CVSADM_ENTBAK, "r");
X    fpout = open_file(CVSADM_ENT, "w+");
X    while (fgets(line, sizeof(line), fpin) != NULL) {
X	if ((cpend = rindex(line, '|')) && (cp = rindex(line, ' ')) &&
X	    (cp++) && strncmp(fname, cp, MAX((cpend-cp), strlen(fname))) == 0)
X	    continue;
X	if (fputs(line, fpout) == EOF)
X	    error(1, "cannot write file %s", CVSADM_ENT);
X    }
X    (void) fclose(fpin);
X    (void) fclose(fpout);
X}
END_OF_FILE
if test 1085 -ne `wc -c <'src/scratch_entry.c'`; then
    echo shar: \"'src/scratch_entry.c'\" unpacked with wrong size!
fi
# end of 'src/scratch_entry.c'
fi
if test -f 'src/status.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/status.c'\"
else
echo shar: Extracting \"'src/status.c'\" \(2073 characters\)
sed "s/^X//" >'src/status.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: status.c,v 1.13 89/11/19 23:40:44 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Status Information
X *
X *	Prints three lines of information for each of its arguments,
X *	one for the user file (line 1), one for the newest RCS file
X *	(line 3) and one for the RCS file both derive from (line 2).
X */
X
X#include "cvs.h"
X
Xstatus(argc, argv)
X    int argc;
X    char *argv[];
X{
X    register int i;
X    int c;
X    int long_format = 0;
X
X    if (argc == -1)
X	status_usage();
X    optind = 1;
X    while ((c = getopt(argc, argv, "l")) != -1) {
X	switch (c) {
X	case 'l':
X	    /*
X	     * XXX - long format not done yet; should probably display
X	     * other people that have checked out the current repository,
X	     * or pieces thereof.
X	     */
X	    long_format = 1;
X	    break;
X	case '?':
X	default:
X	    status_usage();
X	    break;
X	}
X    }
X    argc -= optind;
X    argv += optind;
X    Name_Repository();
X    if (long_format)
X	error(0, "long format status output not done yet");
X    if (argc == 0) {
X	Find_Names(&fileargc, fileargv, ALL);
X	argc = fileargc;
X	argv = fileargv;
X    }
X    for (i = 0; i < argc; i++) {
X	(void) strcpy(User, argv[i]);
X	Locate_RCS();
X	Version_TS(Rcs, Tag, User);
X	if (TS_User[0] == '\0') {
X	    printf("File:\tno file %s\n", User);
X	} else {
X	    printf("File:\t%s\n", User);
X	}
X	if (VN_User[0] == '\0') {
X	    printf("From:\tno entry for %s\n", User);
X	} else if (VN_User[0] == '0' && VN_User[1] == '\0') {
X	    printf("From:\tNew file!\n");
X	} else {
X	    /*
X	     * Only print the modification time
X	     */
X	    printf("From:\t%s\t%s\n", VN_User, &TS_Rcs[25]);
X	}
X	if (VN_Rcs[0] == '\0') {
X	    printf("RCS:\tno %s\n", Rcs);
X	} else {
X	    printf("RCS:\t%s\t%s\n", VN_Rcs, Rcs);
X	}
X	printf("\n");
X    }
X    exit(0);
X}
X
Xstatic
Xstatus_usage()
X{
X    (void) fprintf(stderr, "Usage: %s %s [files...]\n", progname, command);
X    exit(1);
X}
END_OF_FILE
if test 2073 -ne `wc -c <'src/status.c'`; then
    echo shar: \"'src/status.c'\" unpacked with wrong size!
fi
# end of 'src/status.c'
fi
if test -f 'src/version_ts.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/version_ts.c'\"
else
echo shar: Extracting \"'src/version_ts.c'\" \(3315 characters\)
sed "s/^X//" >'src/version_ts.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char rcsid[] = "$Id: version_ts.c,v 1.8 89/11/20 09:51:12 berliner Exp $";
X#endif !lint
X
X/*
X *    Copyright (c) 1989, Brian Berliner
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the CVS 1.0 kit.
X *
X * Version and Time Stamp
X *
X *	Sets the following global variables:
X *	VN_User		version # of the RCS file the user file derives from;
X *			may also be:
X *				empty:		no entry for user file
X *				0:		user file is new
X *				-$VN_User:	user file is to be removed
X *	VN_Rcs		version # of active RCS file
X *				is empty for absent RCS file
X *	TS_User		present time stamp of the user file
X *				is empty for absent user file
X *	TS_Rcs		time stamp of the lastest check-out of the RCS file.
X *
X *	The syntax of an entry is
X *		<version-number>|<time-stamp>|
X *	and the time-stamp currently includes the file change and modify 
X *	times as well as the User file name.
X */
X
X#include <sys/types.h>
X#include <sys/timeb.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <grp.h>
X#include <pwd.h>
X#include <utmp.h>
X#include "cvs.h"
X
X/*
X * "rcs" is the full pathname to the ,v file; "user" is the name of
X * the local file.
X */
XVersion_TS(rcs, tag, user)
X    char *rcs;
X    char *tag;
X    char *user;
X{
X    FILE *fpin;
X    char line[MAXLINELEN];
X    char *cp;
X    int found = 0;
X
X    /*
X     * Get RCS version number in VN_Rcs
X     */
X    Version_Number(rcs, tag, Date, VN_Rcs);
X    time_stamp(user, TS_User);		/* get time-stamp in TS_User */
X    /*
X     * Now read through the "Entries" file to find the
X     * version number of the user file, and the time-stamp
X     * of the RCS file
X     */
X    fpin = open_file(CVSADM_ENT, "r");
X    while (fgets(line, sizeof(line), fpin) != NULL) {
X	if ((cp = rindex(line, '|')) == NULL)
X	    continue;
X	*cp = '\0';
X	if ((cp = rindex(line, ' ')) == NULL)
X	    continue;
X	cp++;
X	if (strcmp(user, cp) == 0) {
X	    found = 1;
X	    break;
X	}
X    }
X    if (found) {
X	if ((cp = index(line, '|')) != NULL) {
X	    *cp++ = '\0';
X	    (void) strcpy(VN_User, line);
X	    (void) strcpy(TS_Rcs, cp);
X	} else {
X	    VN_User[0] = '\0';
X	    TS_Rcs[0] = '\0';
X	}
X    } else {
X	VN_User[0] = '\0';
X	TS_Rcs[0] = '\0';
X    }
X    (void) fclose(fpin);
X}
X
X/* Some UNIX distributions don't include these in their stat.h */
X#ifndef S_IWRITE
X#define	S_IWRITE	0000200		/* write permission, owner */
X#endif !S_IWRITE
X#ifndef S_IWGRP
X#define	S_IWGRP		0000020		/* write permission, grougroup */
X#endif !S_IWGRP
X#ifndef S_IWOTH
X#define	S_IWOTH		0000002		/* write permission, other */
X#endif !S_IWOTH
X
X/*
X * Gets the time-stamp for the file "file" and puts it in the already
X * allocated string "ts".
X *
X * As a side effect, if the user wants writable files and the file
X * currently has no write bits on, the file is made writable now.
X */
Xstatic
Xtime_stamp(file, ts)
X    char *file;
X    char *ts;
X{
X    struct stat sb;
X    char *ctime();
X    char *cp;
X
X    if (stat(file, &sb) < 0) {
X		ts[0] = '\0';
X    } else {
X	if (cvswrite == TRUE &&
X	    (sb.st_mode & (S_IWRITE|S_IWGRP|S_IWOTH)) == 0) {
X	    xchmod(file, 1);
X	    (void) stat(file, &sb);
X	}
X	cp = ctime(&sb.st_ctime);
X	cp[24] = ' ';
X	(void) strcpy(ts, cp);
X	cp = ctime(&sb.st_mtime);
X	cp[24] = ' ';
X	(void) strcat(ts, cp);
X	(void) strcat(ts, file);
X    }
X}
END_OF_FILE
if test 3315 -ne `wc -c <'src/version_ts.c'`; then
    echo shar: \"'src/version_ts.c'\" unpacked with wrong size!
fi
# end of 'src/version_ts.c'
fi
echo shar: End of archive 1 \(of 7\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.