home *** CD-ROM | disk | FTP | other *** search
- Subject: v22i017: Brian Berliner's concurrent RCS system, Part03/07
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 733d95c3 9eff69b1 aaa84987 3f924963
-
- Submitted-by: Brian Berliner <berliner@prisma.com>
- Posting-number: Volume 22, Issue 17
- Archive-name: cvs-berliner/part03
-
- #! /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 3 (of 7)."
- # Contents: src/checkin.csh src/collect_sets.c src/main.c
- # src/modules.c src/subr.c src/version_number.c
- # Wrapped by rsalz@litchi.bbn.com on Thu May 3 16:59:02 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/checkin.csh' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/checkin.csh'\"
- else
- echo shar: Extracting \"'src/checkin.csh'\" \(7570 characters\)
- sed "s/^X//" >'src/checkin.csh' <<'END_OF_FILE'
- X#!/bin/csh
- X#
- X# $Id: checkin.csh,v 1.8 89/11/20 13:37:33 berliner Exp $
- 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#############################################################################
- X# #
- X# This script is used to check in sources from vendors. #
- X# #
- X# Usage: checkin repository Vendor_Tag Vendor_Release_Tag #
- X# #
- X# The repository is the directory where the sources should #
- X# be deposited, the Vendor_Tag is the symbolic tag for the #
- X# vendor branch of the RCS release tree, and the Vendor_Release_Tag #
- X# is the symbolic tag for this release. #
- X# #
- X# checkin traverses the current directory, ensuring that an #
- X# identical directory structure exists in the repository directory. It #
- X# then checks the files in in the following manner: #
- X# #
- X# 1) If the file doesn't yet exist, check it in #
- X# as revision 1.1 #
- X# 2) Tag branch 1.1.1 with the vendor tag #
- X# 3) Check the file into the vendor branch, #
- X# labeling it with the Vendor_Release_Tag #
- X# 4) If the file didn't previously exist, #
- X# make the vendor branch the default branch #
- X# #
- X# The script also is somewhat verbose in letting the user know what is #
- X# going on. It prints a diagnostic when it creates a new file, or updates #
- X# a file that has been modified on the trunk. #
- X# #
- X#############################################################################
- X
- Xset vbose = 0
- Xset message = ""
- Xset cvsbin = /usr/local/bin
- Xset rcsbin = /usr/local/bin
- Xset grep = /bin/grep
- Xset message_file = /tmp/checkin.$$
- Xset got_one = 0
- X
- Xif ( $#argv < 3 ) then
- X echo "Usage: checkin [-v] [-m message] [-f message_file] repository"
- X echo " Vendor_Tag Vendor_Release_Tag [Vendor_Release_tag...]"
- X exit 1
- Xendif
- Xwhile ( $#argv )
- X switch ( $argv[1] )
- X case -v:
- X set vbose = 1
- X breaksw
- X case -m:
- X shift
- X echo $argv[1] > $message_file
- X set got_one = 1
- X breaksw
- X case -f:
- X shift
- X set message_file = $argv[1]
- X set got_one = 2
- X breaksw
- X default:
- X break
- X endsw
- X shift
- Xend
- Xif ( $#argv < 3 ) then
- X echo "Usage: checkin [-v] [-m message] [-f message_file] repository"
- X echo " Vendor_Tag Vendor_Release_Tag [Vendor_Release_tag...]"
- X exit 1
- Xendif
- Xset repository = $argv[1]
- Xshift
- Xset vendor = $argv[1]
- Xshift
- Xset release = $argv[1]
- Xshift
- Xset extra_release = ( $argv )
- X
- Xif ( ! $?CVSROOT ) then
- X echo "Please set the environmental variable CVSROOT to the root"
- X echo " of the tree you wish to update"
- X exit 1
- Xendif
- X
- Xif ( $got_one == 0 ) then
- X echo "Please Edit this file to contain the RCS log information" >$message_file
- X echo "to be associated with this file (please remove these lines)">>$message_file
- X if ( $?EDITOR ) then
- X $EDITOR $message_file > /dev/tty
- X else
- X /usr/ucb/vi $message_file > /dev/tty
- X endif
- X set got_one = 1
- Xendif
- X
- Xumask 2
- X
- Xset update_dir = ${CVSROOT}/${repository}
- Xif ( -d SCCS ) then
- X sccs get SCCS/* >& /dev/null
- Xendif
- Xif ( -d RCS ) then
- X $rcsbin/co RCS/* >& /dev/null
- Xendif
- Xforeach name ( * .[a-zA-Z0-9]* )
- X if ( $name == SCCS ) then
- X continue
- X endif
- X if ( $name == RCS ) then
- X continue
- X endif
- X if ( $vbose ) then
- X echo "Updating ${repository}/${name}"
- X endif
- X if ( -d $name ) then
- X if ( ! -d ${update_dir}/${name} ) then
- X echo "WARNING: Creating new directory ${repository}/${name}"
- X mkdir ${update_dir}/${name}
- X if ( $status ) then
- X echo "ERROR: mkdir failed - aborting"
- X exit 1
- X endif
- X endif
- X chdir $name
- X if ( $status ) then
- X echo "ERROR: Couldn\'t chdir to $name - aborting"
- X exit 1
- X endif
- X if ( $vbose ) then
- X $cvsbin/checkin -v -f $message_file ${repository}/${name} $vendor $release $extra_release
- X else
- X $cvsbin/checkin -f $message_file ${repository}/${name} $vendor $release $extra_release
- X endif
- X if ( $status ) then
- X exit 1
- X endif
- X chdir ..
- X else
- X if ( ! -f $name ) then
- X echo "WARNING: $name is neither a regular file"
- X echo " nor a directory - ignored"
- X continue
- X endif
- X set file = ${update_dir}/${name},v
- X set new = 0
- X set comment = ""
- X grep -s '\$Log.*\$' ${name}
- X if ( $status == 0 ) then
- X set myext = ${name:e}
- X set knownext = 0
- X foreach xx ( "c" "csh" "e" "f" "h" "l" "mac" "me" "mm" "ms" "p" "r" "red" "s" "sh" "sl" "cl" "ml" "el" "tex" "y" "ye" "yr" "" )
- X if ( "${myext}" == "${xx}" ) then
- X set knownext = 1
- X break
- X endif
- X end
- X if ( $knownext == 0 ) then
- X echo For file ${file}:
- X grep '\$Log.*\$' ${name}
- X echo -n "Please insert a comment leader for file ${name} > "
- X set comment = $<
- X endif
- X endif
- X if ( ! -f $file ) then
- X if ( ! -f ${update_dir}/Attic/${name},v ) then
- X echo "WARNING: Creating new file ${repository}/${name}"
- X if ( "${comment}" != "" ) then
- X $rcsbin/rcs -q -i -c"${comment}" -t/dev/null $file
- X endif
- X $rcsbin/ci -q -u1.1 -t/dev/null $file
- X if ( $status ) then
- X echo "ERROR: Initial check-in of $file failed - aborting"
- X exit 1
- X endif
- X set new = 1
- X else
- X set file = ${update_dir}/Attic/${name},v
- X echo "WARNING: Updating ${repository}/Attic/${name}"
- X set head = `head -1 $file`
- X set branch = `head -2 $file | ${grep} -w branch`
- X if ( $#head != 2 || $#branch != 2 ) then
- X echo "ERROR: corrupted RCS file $file - aborting"
- X endif
- X if ( "$head[2]" == "1.1;" && "$branch[2]" != "1.1.1;" ) then
- X ${rcsbin}/rcsdiff -q -r1.1 $file > /dev/null
- X if ( ! $status ) then
- X set new = 1
- X endif
- X else
- X if ( "$branch[2]" != "1.1.1;" ) then
- X echo -n "WARNING: Updating locally modified file "
- X echo "${repository}/Attic/${name}"
- X endif
- X endif
- X endif
- X else
- X set head = `head -1 $file`
- X set branch = `head -2 $file | ${grep} -w branch`
- X if ( $#head != 2 || $#branch != 2 ) then
- X echo "ERROR: corrupted RCS file $file - aborting"
- X endif
- X if ( "$head[2]" == "1.1;" && "$branch[2]" != "1.1.1;" ) then
- X ${rcsbin}/rcsdiff -q -r1.1 $file > /dev/null
- X if ( ! $status ) then
- X set new = 1
- X endif
- X else
- X if ( "$branch[2]" != "1.1.1;" ) then
- X echo -n "WARNING: Updating locally modified file "
- X echo "${repository}/${name}"
- X endif
- X endif
- X endif
- X $rcsbin/rcs -q -N${vendor}:1.1.1 $file
- X if ( $status ) then
- X echo "ERROR: Attempt to set Vendor_Tag in $file failed - aborting"
- X exit 1
- X endif
- X set lock_failed = 0
- X $rcsbin/rcs -q -l${vendor} $file >& /dev/null
- X if ( $status ) then
- X set lock_failed = 1
- X endif
- X if ( "${comment}" != "" ) then
- X $rcsbin/rcs -q -c"${comment}" $file
- X endif
- X $rcsbin/ci -q -f -u${vendor} -N${release} $file < $message_file
- X if ( $status ) then
- X echo "ERROR: Check-in of $file failed - aborting"
- X if ( ! $lock_failed ) then
- X $rcsbin/rcs -q -u${vendor} $file
- X endif
- X exit 1
- X endif
- X foreach tag ( $extra_release )
- X $rcsbin/rcs -q -N${tag}:${release} $file
- X if ( $status ) then
- X echo "ERROR: Couldn't add tag $tag to file $file"
- X continue
- X endif
- X end
- X if ( $new ) then
- X $rcsbin/rcs -q -b${vendor} $file
- X if ( $status ) then
- X echo "ERROR: Attempt to change default branch failed - aborting"
- X exit 1
- X endif
- X endif
- X endif
- Xend
- Xif ( $got_one == 1 ) rm $message_file
- END_OF_FILE
- if test 7570 -ne `wc -c <'src/checkin.csh'`; then
- echo shar: \"'src/checkin.csh'\" unpacked with wrong size!
- fi
- # end of 'src/checkin.csh'
- fi
- if test -f 'src/collect_sets.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/collect_sets.c'\"
- else
- echo shar: Extracting \"'src/collect_sets.c'\" \(7811 characters\)
- sed "s/^X//" >'src/collect_sets.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: collect_sets.c,v 1.15 89/11/19 23:19:51 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 * Collect Sets
- X *
- X * Collects the interesting file names from the administration and
- X * the repository in a number of variables:
- X * solved by:
- X * Clist conflict-ridden (user)
- X * Glist modified, needs merging (update)
- X * Mlist modified, needs checking in (commit)
- X * Olist needs checking out (update)
- X * Alist to be added (commit)
- X * Rlist to be removed (commit)
- X * Wlist remove entry (update)
- X * Llist locked list (commit)
- X * Blist branch list (commit)
- X * Dlist directory list (update)
- X *
- X * Returns non-zero on error.
- X */
- X
- X#include <sys/param.h>
- X#include "cvs.h"
- X
- Xextern char update_dir[];
- X
- XCollect_Sets(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X register int i;
- X char tmp[MAXPATHLEN], update_user[MAXPATHLEN];
- X int ret = 0;
- X
- X /*
- X * By default, a call here must wipe the slate clean
- X */
- X Clist[0] = Glist[0] = Mlist[0] = Olist[0] = Dlist[0] = '\0';
- X Alist[0] = Rlist[0] = Wlist[0] = Llist[0] = Blist[0] = '\0';
- X for (i = 0; i < argc; i++) {
- X (void) strcpy(User, argv[i]);
- X if (update_dir[0] != '\0')
- X (void) sprintf(update_user, "%s/%s", update_dir, User);
- X else
- X (void) strcpy(update_user, User);
- X if (force_tag_match && (Tag[0] != '\0' || Date[0] != '\0'))
- X Locate_RCS();
- X else
- X (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
- X if (isdir(User)) { /* just a directory -- add to Dlist */
- X (void) strcat(Dlist, " ");
- X (void) strcat(Dlist, User);
- X continue;
- X }
- X Version_TS(Rcs, Tag, User);
- X if (VN_User[0] == '\0') {
- X /*
- X * No entry available, TS_Rcs is invalid
- X */
- X if (VN_Rcs[0] == '\0') {
- X /*
- X * There is no RCS file either
- X */
- X if (TS_User[0] == '\0') { /* there is no user file */
- X if (!force_tag_match || !isfile(Rcs)) {
- X warn(0, "nothing known about %s", update_user);
- X ret++;
- X }
- X } else { /* there is a user file */
- X warn(0, "use `cvs add' to create entry for %s",
- X update_user);
- X ret++;
- X }
- X } else {
- X /*
- X * There is an RCS file
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file; ad it to the Olist
- X */
- X (void) strcat(Olist, " ");
- X (void) strcat(Olist, User);
- X } else {
- X /*
- X * There is a user file; print a warning and add it
- X * to the conflict list, Clist
- X */
- X warn(0, "move away %s; it is in the way", update_user);
- X (void) strcat(Clist, " ");
- X (void) strcat(Clist, User);
- X ret++;
- X }
- X }
- X } else if (VN_User[0] == '0' && VN_User[1] == '\0') {
- X /*
- X * An entry for a new-born file; TS_Rcs is dummy
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file, but there should be one;
- X * add it to the remove entry list.
- X */
- X warn(0, "warning: new-born %s has disappeared", update_user);
- X (void) strcat(Wlist, " ");
- X (void) strcat(Wlist, User);
- X } else {
- X /*
- X * There is a user file
- X */
- X if (VN_Rcs[0] == '\0') {
- X /*
- X * There is no RCS file, so add it to the add entry list
- X */
- X (void) strcat(Alist, " ");
- X (void) strcat(Alist, User);
- X } else {
- X /*
- X * There is an RCS file, so someone else must have
- X * checked one in behind our back; added to the conflict
- X * list
- X */
- X warn(0, "conflict: %s created independently by second party",
- X update_user);
- X (void) strcat(Clist, " ");
- X (void) strcat(Clist, User);
- X ret++;
- X }
- X }
- X } else if (VN_User[0] == '-') {
- X /*
- X * An entry for a removed file, TS_Rcs is invalid
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file (as it should be)
- X */
- X (void) sprintf(tmp, "-%s", VN_Rcs);
- X if (strcmp(tmp, "-") == 0) {
- X /*
- X * There is no RCS file; this is all-right, but it
- X * has been removed independently by a second party;
- X * added to the remove entry list.
- X */
- X (void) strcat(Wlist, " ");
- X (void) strcat(Wlist, User);
- X } else if (strcmp(tmp, VN_User) == 0) {
- X /*
- X * The RCS file is the same version as the user file,
- X * and that's OK; added to the to be removed list
- X */
- X (void) strcat(Rlist, " ");
- X (void) strcat(Rlist, User);
- X } else {
- X /*
- X * The RCS file is a newer version than the user file;
- X * and this is defintely not OK; make it a conflict.
- X */
- X warn(0, "conflict: removed %s was modified by second party",
- X update_user);
- X (void) strcat(Clist, " ");
- X (void) strcat(Clist, User);
- X ret++;
- X }
- X } else {
- X /*
- X * The user file shouldn't be there
- X */
- X warn(0, "%s should be removed and is still there", update_user);
- X ret++;
- X }
- X } else {
- X /*
- X * A normal entry, TS_Rcs is valid
- X */
- X if (VN_Rcs[0] == '\0') {
- X /*
- X * There is no RCS file
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file, so just remove the entry
- X */
- X warn(0, "warning: %s is not (any longer) pertinent",
- X update_user);
- X (void) strcat(Wlist, " ");
- X (void) strcat(Wlist, User);
- X } else if (strcmp(TS_User, TS_Rcs) == 0) {
- X /*
- X * The user file is still unmodified, so just remove it
- X * from the entry list
- X */
- X if (!force_tag_match || !isfile(Rcs)) {
- X warn(0, "%s is no longer in the repository",
- X update_user);
- X (void) strcat(Wlist, " ");
- X (void) strcat(Wlist, User);
- X }
- X } else {
- X /*
- X * The user file has been modified and since it is no
- X * longer in the repository, a conflict is raised
- X */
- X if (!force_tag_match) {
- X warn(0, "conflict: %s is modified but no longer in the repository",
- X update_user);
- X (void) strcat(Clist, " ");
- X (void) strcat(Clist, User);
- X ret++;
- X }
- X }
- X } else if (strcmp(VN_Rcs, VN_User) == 0) {
- X /*
- X * The RCS file is the same version as the user file
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file, so note that it was lost
- X * and extract a new version
- X */
- X if (strcmp(command, "checkout") != 0 &&
- X strcmp(command, "co") != 0 &&
- X strcmp(command, "get") != 0)
- X warn(0, "warning: %s was lost", update_user);
- X (void) strcat(Olist, " ");
- X (void) strcat(Olist, User);
- X } else if (strcmp(TS_User, TS_Rcs) == 0) {
- X /*
- X * The user file is still unmodified, so nothing
- X * special at all to do -- no lists updated
- X */
- X } else {
- X /*
- X * The user file appears to have been modified, but
- X * we call No_Difference to verify that it really
- X * has been modified -- it updates the Mlist,
- X * if necessary.
- X */
- X (void) No_Difference(0);
- X }
- X } else {
- X /*
- X * The RCS file is a newer version than the user file
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file, so just get it
- X */
- X if (strcmp(command, "checkout") != 0 &&
- X strcmp(command, "co") != 0 &&
- X strcmp(command, "get") != 0)
- X warn(0, "warning: %s was lost", update_user);
- X (void) strcat(Olist, " ");
- X (void) strcat(Olist, User);
- X } else if (strcmp(TS_User, TS_Rcs) == 0) {
- X /*
- X * The user file is still unmodified, so just get it
- X * as well
- X */
- X (void) strcat(Olist, " ");
- X (void) strcat(Olist, User);
- X } else {
- X /*
- X * The user file appears to have been modified; we call
- X * No_Difference to verify this for us, and it updates
- X * Glist if it has really been modified, and Olist if
- X * it hasn't
- X */
- X (void) No_Difference(1);
- X }
- X }
- X }
- X }
- X return (ret);
- X}
- END_OF_FILE
- if test 7811 -ne `wc -c <'src/collect_sets.c'`; then
- echo shar: \"'src/collect_sets.c'\" unpacked with wrong size!
- fi
- # end of 'src/collect_sets.c'
- fi
- if test -f 'src/main.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/main.c'\"
- else
- echo shar: Extracting \"'src/main.c'\" \(6993 characters\)
- sed "s/^X//" >'src/main.c' <<'END_OF_FILE'
- Xchar rcsid[] = "$Id: main.c,v 1.23 89/11/20 00:06:34 berliner Exp $\nPatch level ###\n";
- 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 * This is the main C driver for the CVS system.
- X *
- X * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
- X * the shell-script CVS system that this is based on.
- X *
- X * Usage:
- X * cvs [options] command [options] [files/modules...]
- X *
- X * Where "command" is composed of:
- X * checkout Check out a module/dir/file
- X * update Brings work tree in sync with repository
- X * commit Checks files into the repository
- X * diff Runs diffs between revisions
- X * log Prints to "rlog" information for files
- X * add Adds an entry to the repository
- X * remove Removes an entry from the repository
- X * status Status info on the revisions
- X * join Merge two RCS revisions
- X * patch "patch" format diff listing between releases
- X * tag Add/delete a symbolic tag to the RCS file
- X *
- X * Future:
- X * checkin Adds new *directories* to the repository
- X * Currently being done by an external shell
- X * script.
- X *
- X * Brian Berliner
- X * 4/20/89
- X */
- X
- X#include <sys/param.h>
- X#include "cvs.h"
- X#include "patchlevel.h"
- X
- Xchar *progname, *command;
- X
- Xchar *fileargv[MAXFILEPERDIR];
- Xint fileargc;
- X
- Xint use_editor = TRUE;
- Xint cvswrite = !CVSREAD_DFLT;
- Xint really_quiet = FALSE;
- Xint quiet = FALSE;
- Xint force_tag_match = FALSE;
- X
- X/*
- X * Globals for the lists created in Collect_Sets()
- X */
- Xchar Clist[MAXLISTLEN], Glist[MAXLISTLEN], Mlist[MAXLISTLEN];
- Xchar Olist[MAXLISTLEN], Alist[MAXLISTLEN], Rlist[MAXLISTLEN];
- Xchar Wlist[MAXLISTLEN], Llist[MAXLISTLEN], Blist[MAXLISTLEN];
- Xchar Dlist[MAXLISTLEN];
- X
- X/*
- X * Globals which refer to a particular file
- X */
- Xchar Repository[MAXPATHLEN];
- Xchar User[MAXPATHLEN], Rcs[MAXPATHLEN];
- Xchar VN_User[MAXPATHLEN], TS_User[MAXPATHLEN];
- Xchar VN_Rcs[MAXPATHLEN], TS_Rcs[MAXPATHLEN];
- Xchar Tag[MAXPATHLEN], Date[MAXPATHLEN];
- X
- X/*
- X * Options is used to hold options passed on to system(), while prog
- X * is alwys used in the calls to system().
- X */
- Xchar Options[MAXPATHLEN];
- Xchar prog[MAXPROGLEN];
- X
- X/*
- X * Defaults, for the environment variables that are not set
- X */
- Xchar *Rcsbin = RCSBIN_DFLT;
- Xchar *Editor = EDITOR_DFLT;
- Xchar *CVSroot = CVSROOT_DFLT;
- X
- Xmain(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X extern char *getenv();
- X register char *cp;
- X register int c;
- X int help = FALSE, err = 0;
- X
- X /*
- X * Just save the last component of the path for error messages
- X */
- X if ((progname = rindex(argv[0], '/')) == NULL)
- X progname = argv[0];
- X else
- X progname++;
- X
- X /*
- X * Query the environment variables up-front, so that
- X * they can be overridden by command line arguments
- X */
- X if ((cp = getenv(RCSBIN_ENV)) != NULL)
- X Rcsbin = cp;
- X if ((cp = getenv(EDITOR_ENV)) != NULL)
- X Editor = cp;
- X if ((cp = getenv(CVSROOT_ENV)) != NULL)
- X CVSroot = cp;
- X if (getenv(CVSREAD_ENV) != NULL)
- X cvswrite = FALSE;
- X
- X optind = 1;
- X while ((c = getopt(argc, argv, "rwvb:e:d:H")) != -1) {
- X switch (c) {
- X case 'r':
- X cvswrite = FALSE;
- X break;
- X case 'w':
- X cvswrite = TRUE;
- X break;
- X case 'v':
- X (void) sprintf(index(rcsid, '#'), "%d\n", PATCHLEVEL);
- X (void) fputs(rcsid, stdout);
- X (void) fputs("\nCopyright (c) 1989, Brian Berliner\n\n\
- XCVS may be copied only under the terms of the GNU General Public License,\n\
- Xa copy of which can be found with the CVS 1.0 distribution kit.\n", stdout);
- X exit(0);
- X break;
- X case 'b':
- X Rcsbin = optarg;
- X break;
- X case 'e':
- X Editor = optarg;
- X break;
- X case 'd':
- X CVSroot = optarg;
- X break;
- X case 'H':
- X help = TRUE;
- X break;
- X case '?':
- X default:
- X usage();
- X }
- X }
- X argc -= optind;
- X argv += optind;
- X if (argc < 1)
- X usage();
- X
- X /*
- X * Specifying just the '-H' flag to the sub-command causes a Usage
- X * message to be displayed.
- X */
- X command = cp = argv[0];
- X if (help == TRUE || (argc > 1 && strcmp(argv[1], "-H") == 0))
- X argc = -1;
- X
- X /*
- X * Make standard output line buffered, so that progress can be
- X * monitored when redirected to a file, but only when we're not
- X * running the "patch" command, as it generates lots of output
- X * to stdout -- just leave it block buffered.
- X */
- X if (strcmp(cp, "patch") != 0)
- X setlinebuf(stdout);
- X
- X if (strcmp(cp, "update") == 0)
- X err += update(argc, argv);
- X else if (strcmp(cp, "commit") == 0 || strcmp(cp, "ci") == 0)
- X commit(argc, argv);
- X else if (strcmp(cp, "diff") == 0)
- X diff(argc, argv);
- X else if (strcmp(cp, "checkout") == 0 || strcmp(cp, "co") == 0 ||
- X strcmp(cp, "get") == 0)
- X checkout(argc, argv);
- X else if (strcmp(cp, "log") == 0)
- X log(argc, argv);
- X else if (strcmp(cp, "status") == 0)
- X status(argc, argv);
- X else if (strcmp(cp, "add") == 0)
- X add(argc, argv);
- X else if (strcmp(cp, "remove") == 0)
- X remove(argc, argv);
- X else if (strcmp(cp, "join") == 0)
- X join(argc, argv);
- X else if (strcmp(cp, "patch") == 0)
- X patch(argc, argv);
- X else if (strcmp(cp, "tag") == 0)
- X tag(argc, argv);
- X else
- X usage(); /* oops.. no match */
- X Lock_Cleanup(0);
- X exit(err);
- X}
- X
- Xstatic
- Xusage()
- X{
- X (void) fprintf(stderr,
- X "Usage: %s [cvs-options] command [command-options] [files...]\n",
- X progname);
- X (void) fprintf(stderr, "\tWhere 'cvs-options' are:\n");
- X (void) fprintf(stderr, "\t\t-r\t\tMake checked-out files read-only\n");
- X (void) fprintf(stderr,
- X "\t\t-w\t\tMake checked-out files read-write (default)\n");
- X (void) fprintf(stderr, "\t\t-v\t\tCVS version and copyright\n");
- X (void) fprintf(stderr, "\t\t-b bindir\tFind RCS programs in 'bindir'\n");
- X (void) fprintf(stderr,
- X "\t\t-e editor\tUse 'editor' for editing log information\n");
- X (void) fprintf(stderr, "\t\t-d CVS_root_directory\n");
- X (void) fprintf(stderr, "\t\t\t\t\Points to the root of the CVS tree\n");
- X (void) fprintf(stderr, "\tand 'command' is:\n");
- X (void) fprintf(stderr, "\t\tcheckout\tCreates a new CVS directory\n");
- X (void) fprintf(stderr,
- X "\t\tupdate\t\tBrings work tree in sync with repository\n");
- X (void) fprintf(stderr,
- X "\t\tcommit\t\tChecks files into the repository\n");
- X (void) fprintf(stderr, "\t\tdiff\t\tRuns diffs between revisions\n");
- X (void) fprintf(stderr,
- X "\t\tlog\t\tPrints out 'rlog' information for files\n");
- X (void) fprintf(stderr, "\t\tstatus\t\tStatus info on the revisions\n");
- X (void) fprintf(stderr, "\t\tadd\t\tAdds an entry to the repository\n");
- X (void) fprintf(stderr,
- X "\t\tremove\t\tRemoves an entry from the repository\n");
- X (void) fprintf(stderr,
- X "\t\tjoin\t\tJoins an RCS revision with the head on checkout\n");
- X (void) fprintf(stderr,
- X "\t\tpatch\t\t\"patch\" format diffs between releases\n");
- X (void) fprintf(stderr, "\t\ttag\t\tAdd a symbolic tag to the RCS file\n");
- X (void) fprintf(stderr,
- X "\tSpecify the '-H' option to each command for Usage information\n");
- X exit(1);
- X}
- END_OF_FILE
- if test 6993 -ne `wc -c <'src/main.c'`; then
- echo shar: \"'src/main.c'\" unpacked with wrong size!
- fi
- # end of 'src/main.c'
- fi
- if test -f 'src/modules.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/modules.c'\"
- else
- echo shar: Extracting \"'src/modules.c'\" \(8254 characters\)
- sed "s/^X//" >'src/modules.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: modules.c,v 1.14 89/11/19 23:20: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 * Modules
- X *
- X * Functions for accessing the modules file.
- X *
- X * The modules file supports basically three formats of lines:
- X * key [options] directory files...
- X * key [options] directory
- X * key -a aliases...
- X *
- X * The -a option allows an aliasing step in the parsing of the modules
- X * file. The "aliases" listed on a line following the -a are
- X * processed one-by-one, as if they were specified as arguments on the
- X * command line.
- X */
- X
- X#include <sys/param.h>
- X#include <sys/file.h>
- X#include <ndbm.h>
- X#include "cvs.h"
- X
- Xextern int update_build_dirs;
- X
- Xint run_module_prog = 1; /* run -i/-o/-t prog by default */
- X
- X/*
- X * Open the modules file, and die if the CVSROOT environment variable
- X * was not set. If the modules file does not exist, that's fine, and
- X * a warning message is displayed and a NULL is returned.
- X */
- XDBM *
- Xopen_module()
- X{
- X char mfile[MAXPATHLEN];
- X DBM *db;
- X
- X if (CVSroot == NULL) {
- X (void) fprintf(stderr, "%s: must set the CVSROOT environment variable\n",
- X progname);
- X error(0, "or specify the '-d' option to %s", progname);
- X }
- X (void) sprintf(mfile, "%s/%s", CVSroot, CVSROOTADM_MODULES);
- X if ((db = dbm_open(mfile, O_RDONLY, 0666)) == NULL)
- X warn(0, "warning: cannot open modules file %s", mfile);
- X return (db);
- X}
- X
- X/*
- X * Close the modules file, if the open succeeded, that is
- X */
- Xclose_module(db)
- X DBM *db;
- X{
- X if (db != NULL) {
- X dbm_close(db);
- X }
- X}
- X
- X/*
- X * This is the recursive function that processes a module name.
- X * If tag is set, just tag files, otherwise, we were called to check files
- X * out.
- X */
- Xdo_module(db, mname, m_type, msg)
- X DBM *db;
- X char *mname;
- X enum mtype m_type;
- X char *msg;
- X{
- X char *checkin_prog = NULL, *checkout_prog = NULL, *tag_prog = NULL;
- X char cwd[MAXPATHLEN], file[MAXPATHLEN];
- X char *moduleargv[MAXFILEPERDIR];
- X int moduleargc, just_file;
- X datum key, val;
- X char *cp, **argv;
- X int c, alias = 0, argc, err = 0;
- X
- X just_file = FALSE;
- X update_build_dirs = FALSE;
- X /*
- X * Look the argument module name up in the database; if we found it, use
- X * it, otherwise, see if the file or directory exists relative to the
- X * root directory (CVSroot). If there is a directory there, it is
- X * extracted or tagged recursively; if there is a file there, it is
- X * extracted or tagged individually; if there is no file or directory
- X * there, we are done.
- X */
- X key.dptr = mname;
- X key.dsize = strlen(key.dptr);
- X if (db != NULL)
- X val = dbm_fetch(db, key);
- X else
- X val.dptr = NULL;
- X if (val.dptr != NULL) {
- X val.dptr[val.dsize] = '\0';
- X } else {
- X /*
- X * Need to determine if the argument module name is a directory
- X * or a file relative to the CVS root and set update_build_dirs
- X * and just_file accordingly
- X */
- X update_build_dirs = TRUE;
- X (void) sprintf(file, "%s/%s", CVSroot, key.dptr);
- X if (!isdir(file)) {
- X (void) strcat(file, RCSEXT);
- X if (!isfile(file)) {
- X warn(0, "cannot find '%s' - ignored", key.dptr);
- X err++;
- X return (err);
- X } else {
- X update_build_dirs = FALSE;
- X just_file = TRUE;
- X }
- X }
- X val = key;
- X }
- X /*
- X * If just extracting or tagging files, need to munge the
- X * passed in module name to look like an actual module entry.
- X */
- X if (just_file == TRUE) {
- X if ((cp = rindex(key.dptr, '/')) != NULL) {
- X *cp++ = '\0';
- X } else {
- X cp = key.dptr;
- X key.dptr = ".";
- X }
- X (void) sprintf(file, "%s %s %s", key.dptr, key.dptr, cp);
- X } else {
- X (void) sprintf(file, "%s %s", key.dptr, val.dptr);
- X }
- X line2argv(&moduleargc, moduleargv, file);
- X argc = moduleargc;
- X argv = moduleargv;
- X if (getwd(cwd) == NULL)
- X error(0, "cannot get current working directory: %s", cwd);
- X optind = 1;
- X while ((c = getopt(argc, argv, CVSMODULE_OPTS)) != -1) {
- X switch (c) {
- X case 'a':
- X alias = 1;
- X break;
- X case 'i':
- X checkin_prog = optarg;
- X break;
- X case 'o':
- X checkout_prog = optarg;
- X break;
- X case 't':
- X tag_prog = optarg;
- X break;
- X case '?':
- X warn(0, "modules file has invalid option for key %s value %s",
- X key.dptr, val.dptr);
- X err++;
- X return (err);
- X break;
- X }
- X }
- X argc -= optind;
- X argv += optind;
- X if (argc == 0) {
- X warn(0, "modules file missing directory for key %s value %s",
- X key.dptr, val.dptr);
- X err++;
- X return (err);
- X }
- X if (alias) {
- X register int i;
- X
- X for (i = 0; i < argc; i++) {
- X if (!quiet)
- X printf("%s %s: %s %s\n", progname, command, msg, argv[i]);
- X err += do_module(db, argv[i], m_type, msg);
- X }
- X return (err);
- X }
- X err += process_module(argc, argv, m_type, &key);
- X if (err == 0 && run_module_prog) {
- X if (m_type == CHECKOUT && checkin_prog != NULL) {
- X FILE *fp = open_file(CVSADM_CIPROG, "w+");
- X (void) fprintf(fp, "%s\n", checkin_prog);
- X (void) fclose(fp);
- X }
- X }
- X if (chdir(cwd) < 0)
- X error(1, "failed chdir to %s!", cwd);
- X if (err == 0 && run_module_prog) {
- X if ((m_type == TAG && tag_prog != NULL) ||
- X (m_type == CHECKOUT && checkout_prog != NULL)) {
- X (void) sprintf(prog, "%s %s",
- X m_type == TAG ? tag_prog : checkout_prog, key.dptr);
- X if (!quiet)
- X printf("%s %s: Executing '%s'\n", progname, command, prog);
- X err += system(prog);
- X }
- X }
- X free_names(&moduleargc, moduleargv);
- X return (err);
- X}
- X
- Xstatic
- Xprocess_module(argc, argv, m_type, keyp)
- X int argc;
- X char *argv[];
- X enum mtype m_type;
- X datum *keyp;
- X{
- X register int i, just_file;
- X int err = 0;
- X
- X just_file = argc > 1;
- X if (!just_file && update_build_dirs == FALSE && argc == 1)
- X update_build_dirs = TRUE;
- X if (m_type == TAG || m_type == PATCH) {
- X (void) sprintf(Repository, "%s/%s", CVSroot, argv[0]);
- X if (chdir(Repository) < 0) {
- X warn(1, "cannot chdir to %s", Repository);
- X err++;
- X return (err);
- X }
- X } else {
- X if (Build_Dirs_and_chdir(keyp->dptr) != 0) {
- X warn(0, "ignoring module %s", keyp->dptr);
- X err++;
- X return (err);
- X }
- X (void) sprintf(Repository, "%s/%s", CVSroot, argv[0]);
- X if (!isdir(CVSADM)) {
- X FILE *fp;
- X
- X Create_Admin(Repository, DFLT_RECORD);
- X if (just_file == TRUE) {
- X fp = open_file(CVSADM_ENTSTAT, "w+");
- X (void) fclose(fp);
- X }
- X } else {
- X char file[MAXPATHLEN];
- X
- X (void) strcpy(file, Repository);
- X Name_Repository();
- X if (strcmp(Repository, file) != 0) {
- X warn(0, "existing repository %s does not match %s",
- X Repository, file);
- X err++;
- X return (err);
- X }
- X }
- X }
- X if (update_build_dirs == TRUE) {
- X extern char update_dir[];
- X
- X (void) strcpy(update_dir, keyp->dptr);
- X if (m_type == CHECKOUT)
- X err += update(0, (char **)0);
- X else if (m_type == TAG)
- X err += tagit((char *)0);
- X else if (m_type == PATCH)
- X err += patched((char *)0);
- X else
- X error(0, "impossible module type %d", (int)m_type);
- X return (err);
- X }
- X argc--;
- X argv++;
- X for (i = 0; i < argc; i++) {
- X char line[MAXLINELEN];
- X
- X (void) strcpy(User, argv[i]);
- X (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
- X if (m_type == CHECKOUT) {
- X Version_TS(Rcs, Tag, User);
- X if (TS_User[0] == '\0') {
- X (void) sprintf(line, "Initial %s", User);
- X Register(User, VN_Rcs, line);
- X }
- X } else if (m_type == TAG) {
- X err += tagit(Rcs);
- X } else if (m_type == PATCH) {
- X err += patched(Rcs);
- X } else {
- X error(0, "impossible module type %d", (int)m_type);
- X }
- X }
- X if (m_type == CHECKOUT)
- X err += update(++argc, --argv);
- X return (err);
- X}
- X
- Xcat_module()
- X{
- X FILE *fp;
- X DBM *db;
- X datum key, val;
- X
- X if ((db = open_module()) == NULL)
- X error(0, "failed to cat the modules file");
- X if ((fp = popen(SORT, "w")) == NULL)
- X fp = stdout;
- X for (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) {
- X key.dptr[key.dsize] = '\0';
- X (void) fprintf(fp, "%-20s", key.dptr);
- X val = dbm_fetch(db, key);
- X if (val.dptr != NULL) {
- X val.dptr[val.dsize] = '\0';
- X (void) fprintf(fp, " %s\n", val.dptr);
- X } else {
- X (void) fprintf(fp, "\n");
- X }
- X }
- X if (fp != stdout)
- X (void) pclose(fp);
- X}
- END_OF_FILE
- if test 8254 -ne `wc -c <'src/modules.c'`; then
- echo shar: \"'src/modules.c'\" unpacked with wrong size!
- fi
- # end of 'src/modules.c'
- fi
- if test -f 'src/subr.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/subr.c'\"
- else
- echo shar: Extracting \"'src/subr.c'\" \(8199 characters\)
- sed "s/^X//" >'src/subr.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: subr.c,v 1.14 89/11/20 09:51:10 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 * Various useful functions for the CVS support code.
- X */
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/file.h>
- X#include <varargs.h>
- X#include "cvs.h"
- X
- X/*
- X * Send a "printf" format string to stderr and die, calling the
- X * defined exit function first, if necessary
- X */
- Xerror(doperror, fmt, va_alist)
- X int doperror;
- X char *fmt;
- X va_dcl
- X{
- X extern int errno;
- X va_list x1;
- X int err = errno;
- X
- X va_start(x1);
- X (void) fprintf(stderr, "%s: ", progname);
- X (void) vfprintf(stderr, fmt, x1);
- X if (doperror) {
- X (void) fprintf(stderr, ": ");
- X errno = err;
- X perror("");
- X errno = 0;
- X } else
- X (void) fprintf(stderr, "\n");
- X va_end(x1);
- X Lock_Cleanup(0);
- X exit(1);
- X}
- X
- X/*
- X * Like error() above, but just display the message to stderr,
- X * without dying or running the exit function.
- X */
- Xwarn(doperror, fmt, va_alist)
- X int doperror;
- X char *fmt;
- X va_dcl
- X{
- X extern int errno;
- X va_list x1;
- X int err = errno;
- X
- X va_start(x1);
- X (void) fprintf(stderr, "%s: ", progname);
- X (void) vfprintf(stderr, fmt, x1);
- X if (doperror) {
- X (void) fprintf(stderr, ": ");
- X errno = err;
- X perror("");
- X errno = 0;
- X } else
- X (void) fprintf(stderr, "\n");
- X va_end(x1);
- X}
- X
- X/*
- X * Copies "from" to "to".
- X * mallocs a buffer large enough to hold the entire file and
- X * does one read/one write to do the copy. This is reasonable,
- X * since source files are typically not too large.
- X */
- Xcopy_file(from, to)
- X char *from;
- X char *to;
- X{
- X struct stat sb;
- X int fdin, fdout;
- X char *buf;
- X
- X if ((fdin = open(from, O_RDONLY)) < 0)
- X error(1, "cannot open %s for copying", from);
- X if (fstat(fdin, &sb) < 0)
- X error(1, "cannot fstat %s", from);
- X if ((fdout = creat(to, (int) sb.st_mode & 07777)) < 0)
- X error(1, "cannot create %s for copying", to);
- X if (sb.st_size > 0) {
- X buf = xmalloc((int)sb.st_size);
- X if (read(fdin, buf, (int)sb.st_size) != (int)sb.st_size)
- X error(1, "cannot read file %s for copying", from);
- X if (write(fdout, buf, (int)sb.st_size) != (int)sb.st_size)
- X error(1, "cannot write file %s for copying", to);
- X free(buf);
- X }
- X (void) close(fdin);
- X (void) close(fdout);
- X}
- X
- X/*
- X * Returns non-zero if the argument file is a directory, or
- X * is a symbolic link which points to a directory.
- X */
- Xisdir(file)
- X char *file;
- X{
- X struct stat sb;
- X
- X if (stat(file, &sb) < 0)
- X return (0);
- X return ((sb.st_mode & S_IFMT) & S_IFDIR);
- X}
- X
- X/*
- X * Returns non-zero if the argument file is a symbolic link.
- X */
- Xislink(file)
- X char *file;
- X{
- X struct stat sb;
- X
- X if (lstat(file, &sb) < 0)
- X return (0);
- X return ((sb.st_mode & S_IFMT) & S_IFLNK);
- X}
- X
- X/*
- X * Returns non-zero if the argument file exists.
- X */
- Xisfile(file)
- X char *file;
- X{
- X struct stat sb;
- X
- X if (stat(file, &sb) < 0)
- X return (0);
- X return (1);
- X}
- X
- X/*
- X * Returns non-zero if the argument file is readable.
- X * XXX - muct be careful if "cvs" is ever made setuid!
- X */
- Xisreadable(file)
- X char *file;
- X{
- X return (access(file, R_OK) != -1);
- X}
- X
- X/*
- X * Returns non-zero if the argument file is writable
- X * XXX - muct be careful if "cvs" is ever made setuid!
- X */
- Xiswritable(file)
- X char *file;
- X{
- X return (access(file, W_OK) != -1);
- X}
- X
- X/*
- X * Open a file and die if it fails
- X */
- XFILE *
- Xopen_file(name, mode)
- X char *name;
- X char *mode;
- X{
- X FILE *fp;
- X
- X if ((fp = fopen(name, mode)) == NULL)
- X error(1, "cannot open %s", name);
- X return (fp);
- X}
- X
- X/*
- X * Make a directory and die if it fails
- X */
- Xmake_directory(name)
- X char *name;
- X{
- X if (mkdir(name, 0777) < 0)
- X error(1, "cannot make directory %s", name);
- X}
- X
- X/*
- X * malloc some data and die if it fails
- X */
- Xchar *
- Xxmalloc(bytes)
- X int bytes;
- X{
- X extern char *malloc();
- X char *cp;
- X
- X if (bytes <= 0)
- X error(0, "bad malloc size %d", bytes);
- X if ((cp = malloc((unsigned)bytes)) == NULL)
- X error(0, "malloc failed");
- X return (cp);
- X}
- X
- X
- X/*
- X * ppstrcmp() is a front-end for strcmp() when the arguments
- X * are pointers to pointers to chars.
- X */
- Xppstrcmp(pp1, pp2)
- X register char **pp1, **pp2;
- X{
- X return (strcmp(*pp1, *pp2));
- X}
- X
- X/*
- X * ppstrcmp_files() is a front-end for strcmp() when the arguments
- X * are pointers to pointers to chars.
- X * For some reason, the ppstrcmp() above sorts in reverse order when
- X * called from Entries2Files().
- X */
- Xppstrcmp_files(pp1, pp2)
- X register char **pp1, **pp2;
- X{
- X /*
- X * Reversing the arguments here cause for the
- X * correct alphabetical order sort, as we desire.
- X */
- X return (strcmp(*pp2, *pp1));
- 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 * Change the mode of a file, either adding write permissions, or
- X * removing all write permissions. Adding write permissions honors
- X * the current umask setting.
- X */
- Xxchmod(fname, writable)
- X char *fname;
- X int writable;
- X{
- X struct stat sb;
- X int mode, oumask;
- X
- X if (stat(fname, &sb) < 0) {
- X warn(1, "cannot stat %s", fname);
- X return;
- X }
- X if (writable) {
- X oumask = umask(0);
- X (void) umask(oumask);
- X mode = sb.st_mode | ((S_IWRITE|S_IWGRP|S_IWOTH) & ~oumask);
- X } else {
- X mode = sb.st_mode & ~(S_IWRITE|S_IWGRP|S_IWOTH);
- X }
- X if (chmod(fname, mode) < 0)
- X warn(1, "cannot change mode of file %s", fname);
- X}
- X
- X/*
- X * Rename a file and die if it fails
- X */
- Xrename_file(from, to)
- X char *from;
- X char *to;
- X{
- X if (rename(from, to) < 0)
- X error(1, "cannot rename file %s to %s", from, to);
- X}
- X
- X/*
- X * Compare "file1" to "file2".
- X * Return non-zero if they don't compare exactly.
- X *
- X * mallocs a buffer large enough to hold the entire file and
- X * does two reads to load the buffer and calls bcmp to do the cmp.
- X * This is reasonable, since source files are typically not too large.
- X */
- Xxcmp(file1, file2)
- X char *file1;
- X char *file2;
- X{
- X register char *buf1, *buf2;
- X struct stat sb;
- X off_t size;
- X int ret, fd1, fd2;
- X
- X if ((fd1 = open(file1, O_RDONLY)) < 0)
- X error(1, "cannot open file %s for comparing", file1);
- X if ((fd2 = open(file2, O_RDONLY)) < 0)
- X error(1, "cannot open file %s for comparing", file2);
- X if (fstat(fd1, &sb) < 0)
- X error(1, "cannot fstat %s", file1);
- X size = sb.st_size;
- X if (fstat(fd2, &sb) < 0)
- X error(1, "cannot fstat %s", file2);
- X if (size == sb.st_size) {
- X if (size == 0)
- X ret = 0;
- X else {
- X buf1 = xmalloc((int)size);
- X buf2 = xmalloc((int)size);
- X if (read(fd1, buf1, (int)size) != (int)size)
- X error(1, "cannot read file %s cor comparing", file1);
- X if (read(fd2, buf2, (int)size) != (int)size)
- X error(1, "cannot read file %s for comparing", file2);
- X ret = bcmp(buf1, buf2, (int)size);
- X free(buf1);
- X free(buf2);
- X }
- X } else
- X ret = 1;
- X (void) close(fd1);
- X (void) close(fd2);
- X return (ret);
- X}
- X
- X/*
- X * Recover the space allocated by Find_Names() and line2argv()
- X */
- Xfree_names(pargc, argv)
- X int *pargc;
- X char *argv[];
- X{
- X register int i;
- X
- X for (i = 0; i < *pargc; i++) { /* only do through *pargc */
- X free(argv[i]);
- X }
- X *pargc = 0; /* and set it to zero when done */
- X}
- X
- X/*
- X * Convert a line into argc/argv components and return the result in
- X * the arguments as passed. Use free_names() to return the memory
- X * allocated here back to the free pool.
- X */
- Xline2argv(pargc, argv, line)
- X int *pargc;
- X char *argv[];
- X char *line;
- X{
- X char *cp;
- X
- X *pargc = 0;
- X for (cp = strtok(line, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
- X argv[*pargc] = xmalloc(strlen(cp) + 1);
- X (void) strcpy(argv[*pargc], cp);
- X (*pargc)++;
- X }
- X}
- X
- X/*
- X * Returns the number of dots ('.') found in an RCS revision number
- X */
- Xnumdots(s)
- X char *s;
- X{
- X char *cp;
- X int dots = 0;
- X
- X for (cp = s; *cp; cp++) {
- X if (*cp == '.')
- X dots++;
- X }
- X return (dots);
- X}
- END_OF_FILE
- if test 8199 -ne `wc -c <'src/subr.c'`; then
- echo shar: \"'src/subr.c'\" unpacked with wrong size!
- fi
- # end of 'src/subr.c'
- fi
- if test -f 'src/version_number.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/version_number.c'\"
- else
- echo shar: Extracting \"'src/version_number.c'\" \(10526 characters\)
- sed "s/^X//" >'src/version_number.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: version_number.c,v 1.16 89/11/19 23:20:35 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 Number
- X *
- X * Returns the requested version number of the RCS file, satisfying tags
- X * and walking branches, if necessary.
- X *
- X * "rcs" is the full pathname to the ,v file which is read to determine
- X * the current head version number for the RCS file. Things are
- X * complicated by needing to walk branches and symbolic tags. The
- X * algorithm used here for branches is not quite the same as that
- X * included with RCS, but should work 99.999% of the time (or more).
- X *
- X * The result is placed in "vers"; null-string if error.
- X */
- X
- X#include <ctype.h>
- X#include "cvs.h"
- X
- XVersion_Number(rcs, tag, date, vers)
- X char *rcs;
- X char *tag;
- X char *date;
- X char *vers;
- X{
- X FILE *fpin;
- X char rev[50];
- X
- X vers[0] = rev[0] = '\0'; /* Assume failure */
- X /*
- X * Open the RCS file. If it failed, just return, as the version
- X * is already nulled.
- X */
- X if ((fpin = fopen(rcs, "r")) == NULL)
- X return;
- X get_version(fpin, tag, date, rev, vers);
- X if (vers[0] == '\0' && tag[0] != '\0') {
- X if (!isdigit(tag[0])) {
- X char *cp, temp[MAXLINELEN];
- X extern char update_dir[];
- X
- X if (CVSroot[0] != '\0' &&
- X strncmp(rcs, CVSroot, strlen(CVSroot)) == 0) {
- X cp = rcs + strlen(CVSroot) + 1;
- X } else {
- X if ((cp = index(rcs, '/')) == NULL && update_dir[0] != '\0') {
- X (void) sprintf(temp, "%s/%s", update_dir, rcs);
- X cp = temp;
- X } else {
- X cp = rcs;
- X }
- X }
- X if (force_tag_match) {
- X if (!quiet)
- X warn(0, "tag %s undefined in %s; ignored", tag, cp);
- X } else {
- X if (!quiet)
- X warn(0, "tag %s undefined in %s; using %s", tag, cp, rev);
- X (void) strcpy(vers, rev);
- X }
- X } else {
- X (void) strcpy(vers, rev);
- X }
- X }
- X (void) fclose(fpin);
- X}
- X
- X/*
- X * The main driver for doing the work of getting the required revision
- X * number. Returns computed revision in "rev" or "vers" depending
- X * on whether the "tag" could be satisfied or not.
- X */
- Xstatic
- Xget_version(fp, tag, date, rev, vers)
- X FILE *fp;
- X char *tag;
- X char *date;
- X char *rev;
- X char *vers;
- X{
- X char line[MAXLINELEN];
- X char *cp;
- X int symtag_matched = 0;
- X
- X /*
- X * Scan to find the current "head" setting,
- X * which really isn't the head if the RCS file is using a branch
- X * for the head, sigh.
- X *
- X * Assumption here is that the "head" line is always first.
- X */
- X if (fgets(line, sizeof(line), fp) == NULL)
- X return;
- X if (strncmp(line, RCSHEAD, sizeof(RCSHEAD) - 1) != 0 ||
- X (cp = rindex(line, ';')) == NULL)
- X return;
- X *cp = '\0'; /* strip the ';' */
- X if ((cp = rindex(line, ' ')) == NULL &&
- X (cp = rindex(line, '\t')) == NULL)
- X return;
- X cp++;
- X (void) strcpy(rev, cp);
- X /*
- X * The "rev" string now contains the value of the RCS "head".
- X * Read the next line to find out if we should walk the branches.
- X *
- X * Assumption here is that "branch" is always on the second line
- X * of the RCS file. If a "branch" line does not exist, we assume
- X * it is an old format RCS file, and blow it off.
- X */
- X if (fgets(line, sizeof(line), fp) == NULL)
- X return;
- X if (strncmp(line, RCSBRANCH, sizeof(RCSBRANCH) - 1) == 0 &&
- X (cp = rindex(line, ';')) != NULL) {
- X *cp = '\0'; /* strip the ';' */
- X if ((cp = rindex(line, ' ')) == NULL &&
- X (cp = rindex(line, '\t')) == NULL)
- X return;
- X cp++;
- X if (*cp != NULL)
- X (void) strcpy(rev, cp);
- X }
- X /*
- X * "rev" now contains either the "head" value, or the "branch"
- X * value (if it was set). If we're looking for a particular symbolic
- X * or numeric tag, we must find the symbol, and then do
- X * branch completion as usual, if necessary.
- X */
- X if (date[0] != '\0') {
- X get_date(fp, date, rev, vers);
- X return;
- X }
- X if (tag[0] != '\0') {
- X /* return of 0 means we found an exact match, or there was an error */
- X if ((symtag_matched = get_tag(fp, tag, rev, vers)) == 0)
- X return;
- X }
- X /*
- X * "rev" now contains either the "head" value, or the tag value,
- X * or the "branch" value. get_branch() will fill in "rev" with
- X * the highest numbered branch off "rev", if necessary.
- X */
- X get_branch(fp, rev);
- X if (tag[0] == '\0' || isdigit(tag[0]) || symtag_matched < 0)
- X (void) strcpy(vers, rev);
- X}
- X
- X/*
- X * We were requested to find a particular symbolic or numeric revision.
- X * So, scan for the "symbols" line in the RCS file, or for the first
- X * match of a line if the tag is numeric.
- X *
- X * Would really like to use strtok() here, but callers in update() are
- X * already using it.
- X *
- X * Return value of 0 means to use "vers" as it stands, while a return value
- X * of 1 means to use "rev", but to check for possible branch completions
- X * to find the head of a branch.
- X */
- Xstatic
- Xget_tag(fp, tag, rev, vers)
- X FILE *fp;
- X char *tag;
- X char *rev;
- X char *vers;
- X{
- X char line[MAXLINELEN], tagdot[50];
- X char *cp, *cprev;
- X int tagdots, tagdotlen;
- X
- X if (isdigit(tag[0])) {
- X while (tag[strlen(tag)] == '.')
- X tag[strlen(tag)] = '\0'; /* strip trailing dots */
- X (void) sprintf(tagdot, "%s.", tag);
- X tagdotlen = strlen(tagdot);
- X tagdots = numdots(tag);
- X }
- X while (fgets(line, sizeof(line), fp) != NULL) {
- X if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0) {
- X /*
- X * Use head, or a partial branch match found with the strncmp
- X * call with tagdot below
- X */
- X rewind(fp);
- X return (1);
- X }
- X /*
- X * For numeric tags, the RCS file contains the revision
- X * number all by itself on a single line, so we check for
- X * that match here.
- X */
- X if (isdigit(tag[0])) {
- X if ((cp = rindex(line, '\n')) != NULL)
- X *cp = '\0';
- X if (strcmp(tag, line) == 0) {
- X (void) strcpy(vers, line);
- X return (0); /* a match for a numeric tag */
- X }
- X if (strncmp(tagdot, line, tagdotlen) == 0) {
- X if ((tagdots & 1) == 0 && numdots(line) == tagdots+1)
- X (void) strcpy(rev, line);
- X }
- X continue;
- X }
- X if (strncmp(line, RCSSYMBOL, sizeof(RCSSYMBOL)-1)!=0 ||
- X (cp = rindex(line, ';')) == NULL)
- X continue;
- X *cp = ' '; /* strip the ';' */
- X if ((cp = index(line, ' ')) == NULL &&
- X (cp = index(line, '\t')) == NULL)
- X continue;
- X /*
- X * A rather ugly loop to process the "symbols" line. I would
- X * really rather use strtok(), but other above me already are,
- X * and strtok() blows up in this case.
- X */
- X while (cp && *cp) {
- X while (isspace(*cp))
- X cp++;
- X /* symbols and revisions are separated by a colon */
- X if ((cprev = index(cp, ':')) == NULL) {
- X while (*cp && !isspace(*cp))
- X cp++;
- X continue;
- X }
- X *cprev++ = '\0';
- X /*
- X * "cp" points to the NULL-terminated symbolic name;
- X * "cprev" points to the revision, which must be NULL-terminated;
- X */
- X if (strcmp(tag, cp) == 0) {
- X if ((cp = index(cprev, ' ')) == NULL
- X && (cp = index(cprev, ';')) == NULL
- X && (cp = index(cprev, '\n')) == NULL)
- X continue;
- X *cp = '\0';
- X (void) strcpy(rev, cprev);
- X return (-1); /* look for branches off rev */
- X } else {
- X while (!isspace(*cp))
- X cp++;
- X cp++;
- X }
- X }
- X return (1);
- X }
- X return (0);
- X}
- X
- X/*
- X * Decides if we should determine the highest branch number, and
- X * returns it in "rev". This is only done if there are
- X * an even number of dots ('.') in the revision number passed in.
- X */
- Xstatic
- Xget_branch(fp, rev)
- X FILE *fp;
- X char *rev;
- X{
- X char line[MAXLINELEN];
- X char branch[50];
- X char *cp;
- X int len, dots = numdots(rev);
- X
- X if ((dots & 1) != 0)
- X return;
- X (void) sprintf(branch, "%s.", rev);
- X len = strlen(branch);
- X while (fgets(line, sizeof(line), fp) != NULL) {
- X if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0)
- X return;
- X if (isdigit(line[0])) {
- X if ((cp = rindex(line, '\n')) != NULL)
- X *cp = '\0'; /* strip the newline */
- X if (numdots(line) == dots+1 &&
- X strncmp(line, branch, len) == 0) {
- X if (strcmp(branch, line) <= 0)
- X (void) strcpy(rev, line);
- X }
- X }
- X }
- X}
- X
- X/*
- X * Look up a the most recent revision, based on the supplied date.
- X * But do some funky stuff if necessary to follow any vendor branch.
- X */
- Xstatic
- Xget_date(fp, date, rev, version)
- X FILE *fp;
- X char *date;
- X char *rev;
- X char *version;
- X{
- X char *cp;
- X
- X if ((numdots(rev) & 1) == 0) {
- X /*
- X * A branch is the head, so get the revision from the branch
- X * specified in "rev". If we didn't get a match, try the trunk.
- X */
- X get_branch_date(fp, date, rev, version);
- X if (version[0] == '\0') {
- X if ((cp = index(rev, '.')) != NULL)
- X *cp = '\0';
- X rewind(fp);
- X get_branch_date(fp, date, rev, version);
- X }
- X } else {
- X /*
- X * The trunk is the head. Get the revision from the trunk and
- X * see if it evaluates to 1.1. If so, walk the 1.1.1 branch looking
- X * for a match and return that; if not, just return 1.1.
- X */
- X if ((cp = rindex(rev, '.')) != NULL)
- X *cp = '\0'; /* turn the revision into a branch */
- X get_branch_date(fp, date, rev, version);
- X if (strcmp(version, "1.1") == 0) {
- X rewind(fp);
- X get_branch_date(fp, date, "1.1.1", version);
- X }
- X }
- X}
- X
- Xstatic
- Xget_branch_date(fp, date, rev, version)
- X FILE *fp;
- X char *date;
- X char *rev;
- X char *version;
- X{
- X char line[MAXLINELEN], last_rev[50], curdate[50], date_dot[50];
- X int date_dots, date_dotlen;
- X char *cp, *semi;
- X
- X last_rev[0] = '\0';
- X (void) strcpy(curdate, "00"); /* what happens at 2000 ad? */
- X (void) sprintf(date_dot, "%s.", rev);
- X date_dotlen = strlen(date_dot);
- X date_dots = numdots(rev);
- X while (fgets(line, sizeof(line), fp) != NULL) {
- X if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0)
- X return;
- X if (isdigit(line[0])) {
- X if ((cp = rindex(line, '\n')) != NULL)
- X *cp = '\0'; /* strip the newline */
- X if ((date_dots == 0 || strncmp(date_dot, line, date_dotlen) == 0) &&
- X numdots(line) == date_dots+1)
- X (void) strcpy(last_rev, line);
- X else
- X last_rev[0] = '\0';
- X continue;
- X }
- X if (strncmp(line, RCSDATE, sizeof(RCSDATE) - 1) == 0 &&
- X last_rev[0] != '\0') {
- X for (cp = line; *cp && !isspace(*cp); cp++)
- X ;
- X while (*cp && isspace(*cp))
- X cp++;
- X if (*cp && (semi = index(cp, ';')) != NULL) {
- X *semi = '\0'; /* strip the semicolon */
- X if (strcmp(cp, date) <= 0 && strcmp(cp, curdate) >= 0) {
- X (void) strcpy(curdate, cp);
- X (void) strcpy(version, last_rev);
- X }
- X }
- X }
- X }
- X}
- END_OF_FILE
- if test 10526 -ne `wc -c <'src/version_number.c'`; then
- echo shar: \"'src/version_number.c'\" unpacked with wrong size!
- fi
- # end of 'src/version_number.c'
- fi
- echo shar: End of archive 3 \(of 7\).
- cp /dev/null ark3isdone
- 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...
-