home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i003: RCS source control system, Part03/12
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: db32cfc0 fb888ade 0a683c96 f996a50b
-
- Submitted-by: Adam Hammer <hammer@cs.purdue.edu>
- Posting-number: Volume 24, Issue 3
- Archive-name: rcs/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: src/Makefile src/rcs.c
- # Wrapped by rsalz@litchi.bbn.com on Thu Feb 21 14:36:55 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 3 (of 12)."'
- if test -f 'src/Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/Makefile'\"
- else
- echo shar: Extracting \"'src/Makefile'\" \(8655 characters\)
- sed "s/^X//" >'src/Makefile' <<'END_OF_FILE'
- X# $Id: Makefile,v 5.8 1990/12/13 06:54:06 eggert Exp $
- X# Copyright (C) 1982, 1988, 1989 Walter Tichy
- X# Copyright 1990 by Paul Eggert
- X# Distributed under license by the Free Software Foundation, Inc.
- X#
- X# This file is part of RCS.
- X#
- X# RCS 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# RCS 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 RCS; see the file COPYING. If not, write to
- X# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- X#
- X# Report problems and direct all questions to:
- X#
- X# rcs-bugs@cs.purdue.edu
- X#
- X# INSTRUCTIONS
- X# ============
- X
- X
- X# Figure out where to put the RCS commands; define RCSDIR accordingly.
- X
- XRCSDIR = /usr/local/bin
- X
- X
- X# Define INSTALL_SETID_FLAGS as needed to install RCS setgid or setuid.
- X# This makes sense only when setegid() and seteuid() work
- X# Setgid is better than setuid because it mixes with nonstrict locking.
- X#INSTALL_SETID_FLAGS = ${INSTALL_NORMAL_FLAGS}
- X#INSTALL_SETID_FLAGS = -g rcs -o root -m 2555
- X INSTALL_SETID_FLAGS = ${INSTALL_NORMAL_FLAGS}
- X
- X
- X# Define RCSPREFIX to be empty if you want RCS to search the PATH for
- X# subsidiary RCS commands like co. This lets you move RCS commands
- X# after building them, and permits multiple instances of setgid RCS
- X# commands on the same host for different groups.
- X#
- X# Define RCSPREFIX to a path followed by / if you want RCS to look in
- X# just one place. This makes execution faster. Also, if your host's
- X# execvp() system call does not understand the BSD #!/bin/sh convention
- X# for starting shell files, you must use a nonempty RCSPREFIX, because
- X# in this case rcsmerge invokes `/bin/sh ${RCSPREFIX}merge'.
- X
- X#RCSPREFIX =
- X#RCSPREFIX = ${RCSDIR}/
- X RCSPREFIX = ${RCSDIR}/
- X
- X# Define DIFF and DIFF3 to be the name of your diff and diff3 programs.
- X# DIFF must be an absolute path name if setgid or setuid is used.
- X# Define DIFF_FLAGS to be diff's options for RCS format output.
- X# If available, use the -a option for comparing arbitrary files.
- X# Define DIFF_L to be 1 if your diff understands GNU diff's -L option.
- X# Set DIFF3_TYPE=lib for traditional diff, =bin otherwise.
- X# If DIFF3_type=bin, make sure your diff3 understands -a, -L, and and -m.
- X# If DIFF3_type=lib, avoid the diff3 program visible to users, and
- X# use the one in /usr/lib instead; it may be called /usr/lib/diff3prog.
- X
- X# Traditional diff
- X#DIFF = /bin/diff
- X#DIFF_FLAGS = -n
- X#DIFF_L = 0
- X#DIFF3 = /usr/lib/diff3
- X#DIFF3_TYPE = lib
- X
- X# GNU diff -- must be version 1.15 or later
- X#DIFFPREFIX = ${RCSDIR}/
- X#DIFF = ${DIFFPREFIX}diff
- X#DIFF_FLAGS = -an
- X#DIFF_L = 1
- X#DIFF3 = ${DIFF}3
- X#DIFF3_TYPE = bin
- X
- X DIFF = /bin/diff
- X DIFF_FLAGS = -n
- X DIFF_L = 0
- X DIFF3 = /usr/lib/diff3
- X DIFF3_TYPE = lib
- X
- X
- X# Set SENDMAIL to be a comma-separated list of strings that are a command
- X# to send mail. The first string should be an absolute pathname.
- X# The name of the addressee will be appended as a separate argument,
- X# and the standard input will be the message (first line "Subject: xxxx",
- X# second line empty).
- X
- X#SENDMAIL = "/bin/mail"
- X#SENDMAIL = "/etc/delivermail", "-w"
- X#SENDMAIL = "/usr/lib/sendmail"
- X SENDMAIL = "/bin/mail"
- X
- X
- X# Decide what loader libraries you need.
- X# Some older hosts need -lBSD, -ljobs, or -lPW.
- X
- XLDLIBS =
- X
- X
- X# Decide what C compiler flags you need.
- X
- X# Optimize. Put in options that work well for your compiler.
- X# Options to try with GCC include -fdelayed-branch, -finline-functions,
- X# -fomit-frame-pointer, and -fstrength-reduce.
- XCC_O = -O
- X
- X# Make all initialized data read-only (not just string literals).
- X# This option can improve performance by making initialized data shared.
- X# It's not worth worrying about if your compiler supports the `const' keyword.
- X# 4.3BSD-based compilers
- X#CC_R = -R
- X# most other compilers
- X#CC_R =
- X CC_R =
- X
- X# Add this for SunOS 4.1 + GCC 1.37.1.
- X#COMPILE.c = ${CC} ${CFLAGS} ${CPPFLAGS} -c
- X
- X
- X# for GCC
- X#CC = gcc
- X#CC_W = -Wall -Wcast-qual -Wpointer-arith -Wshadow -Wwrite-strings
- X#CFLAGS = ${CC_O} ${CC_R} ${CC_W}
- X
- X# for traditional C compilers
- X#CC = cc
- X#CFLAGS = ${CC_O} ${CC_R}
- X
- X CC = cc
- X CFLAGS = ${CC_O} ${CC_R}
- X
- X
- XLINT = lint
- X
- X# For traditional and BSD lint, use
- X#LINTFLAGS = -abchx
- X# For USG lint, use
- X#LINTFLAGS =
- X LINTFLAGS = -abchx
- X
- X
- X# If you have version 2 RCS files around, define COMPAT2 to be 1.
- X# (Version 2 became obsolete in 1982.) This assures that version 2
- X# RCS files can still be read. After all version 2 RCS files have
- X# been updated with later versions of ci or rcs, you can remake RCS with
- X# COMPAT2=0.
- XCOMPAT2 = 0
- X# When you have RCS installed, rename old version 2 RCS files as follows
- X# (if you have any). If the working file was "f.c" and the RCS file
- X# "f.c.v", rename the RCS file to "f.c,v". If the working file was "f.c"
- X# and the RCS file "f.v", rename the RCS file "f.c,v". Thus, suffixes
- X# are no longer dropped and RCS files end in ",v" rather than ".v".
- X
- X
- X# Now you are ready. Try to make "conf.h".
- X# Check the resulting conf.h for plausibility.
- X# If it's wrong, there is a bug in conf.sh; please report it.
- X# You can patch conf.h if you're in a hurry, but it's better to fix it;
- X# look at a.h and conf.error for ideas.
- X# If all else fails, copy conf.heg to conf.h and edit it by hand.
- X
- X# Make "all".
- X# If all went well, make "install".
- X# If installation succeeds, make "installtest";
- X# if this fails, make "installdebug" for detailed info.
- X
- X# If you want to maintain RCS with itself, be sure you preserve the
- X# original revision numbers, dates, etc. by checking the
- X# files in with the -k option.
- X
- X# Avoid brain damage in some versions of 'make'.
- XSHELL = /bin/sh
- X
- X# binary commands
- XBCOMMANDS = ci ident rcs rcsdiff rcsmerge rlog co
- X
- X# all commands
- XRCSCOMMANDS = merge ${BCOMMANDS}
- X
- Xall :: ${RCSCOMMANDS}
- X
- XINSTALL = install -c
- XINSTALL_NORMAL_FLAGS = -g staff -m 775
- X
- Xinstall :: all
- X ${INSTALL} ${INSTALL_SETID_FLAGS} ci ${RCSDIR}
- X ${INSTALL} ${INSTALL_SETID_FLAGS} co ${RCSDIR}
- X ${INSTALL} ${INSTALL_SETID_FLAGS} rcsdiff ${RCSDIR}
- X ${INSTALL} ${INSTALL_SETID_FLAGS} rcsmerge ${RCSDIR}
- X ${INSTALL} ${INSTALL_SETID_FLAGS} rlog ${RCSDIR}
- X ${INSTALL} ${INSTALL_NORMAL_FLAGS} ident ${RCSDIR}
- X ${INSTALL} ${INSTALL_NORMAL_FLAGS} rcs ${RCSDIR}
- X ${INSTALL} ${INSTALL_NORMAL_FLAGS} merge ${RCSDIR}
- X
- Xinstalltest ::
- X sh rcstest
- X
- Xinstalldebug ::
- X sh rcstest -v
- X
- Xclean ::
- X rm -f a.* *.o conf.h conf.error ${RCSCOMMANDS}
- X
- Xconf.h : conf.sh # Makefile
- X C='${CC} ${CFLAGS}' \
- X COMPAT2='${COMPAT2}' \
- X DIFF='${DIFF}' \
- X DIFF_L='${DIFF_L}' \
- X DIFF_FLAGS='${DIFF_FLAGS}' \
- X RCSPREFIX='${RCSPREFIX}' \
- X SENDMAIL='${SENDMAIL}' \
- X L='${LDLIBS}' \
- X sh -x conf.sh 2>conf.error
- X mv a.h $@
- X rm -f a.*
- X
- XCIFILES = ci.o rcslex.o rcssyn.o rcsgen.o rcsedit.o rcskeys.o rcsmap.o \
- X rcsrev.o rcsutil.o rcsfnms.o partime.o maketime.o rcskeep.o rcsfcmp.o
- Xci : ${CIFILES}
- X ${CC} ${CFLAGS} ${CIFILES} ${LDLIBS} -o $@
- X
- XCOFILES = co.o rcslex.o rcssyn.o rcsgen.o rcsedit.o rcskeys.o rcsmap.o \
- X rcsrev.o rcsutil.o rcsfnms.o partime.o maketime.o
- Xco : ${COFILES}
- X ${CC} ${CFLAGS} ${COFILES} ${LDLIBS} -o $@
- X
- Xident : ident.o rcsmap.o
- X ${CC} ${CFLAGS} ident.o rcsmap.o ${LDLIBS} -o $@
- X
- Xmerge : merge.sh
- X DIFF=${DIFF} DIFF3=${DIFF3} DIFF3_TYPE=${DIFF3_TYPE} sh $@.sh >$@.o
- X chmod +x $@.o
- X mv $@.o $@
- X
- XRLOG = rlog.o rcslex.o rcsmap.o rcssyn.o rcsrev.o rcsutil.o partime.o \
- X maketime.o rcsfnms.o
- Xrlog : ${RLOG}
- X ${CC} ${CFLAGS} ${RLOG} ${LDLIBS} -o $@
- X
- XRCS = rcs.o rcslex.o rcssyn.o rcsrev.o rcsutil.o rcsgen.o rcsedit.o rcskeys.o \
- X rcsmap.o rcsfnms.o
- Xrcs : ${RCS}
- X ${CC} ${CFLAGS} ${RCS} ${LDLIBS} -o $@
- X
- XRCSDIFF = rcsdiff.o rcsutil.o rcsfnms.o rcsmap.o rcsrev.o rcssyn.o rcslex.o \
- X maketime.o partime.o
- Xrcsdiff : ${RCSDIFF}
- X ${CC} ${CFLAGS} ${RCSDIFF} ${LDLIBS} -o $@
- X
- XRCSMERGE = rcsmerge.o rcsutil.o rcsfnms.o rcsmap.o rcsrev.o rcssyn.o rcslex.o
- Xrcsmerge : ${RCSMERGE}
- X ${CC} ${CFLAGS} ${RCSMERGE} ${LDLIBS} -o $@
- X
- XSOURCE= ci.c co.c ident.c maketime.c partime.c rcs.c \
- X rcsdiff.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c \
- X rcskeep.c rcskeys.c rcslex.c rcsmap.c rcsmerge.c rcsrev.c rcssyn.c \
- X rcsutil.c rlog.c
- XOBJECT= ci.o co.o ident.o maketime.o partime.o rcs.o \
- X rcsdiff.o rcsedit.o rcsfcmp.o rcsfnms.o rcsgen.o \
- X rcskeep.o rcskeys.o rcslex.o rcsmap.o rcsmerge.o rcsrev.o rcssyn.o \
- X rcsutil.o rlog.o
- X
- Xlint : conf.h
- X ${LINT} ${LINTFLAGS} -Dlint=1 ${SOURCE}
- X
- X${OBJECT} : conf.h rcsbase.h
- END_OF_FILE
- if test 8655 -ne `wc -c <'src/Makefile'`; then
- echo shar: \"'src/Makefile'\" unpacked with wrong size!
- fi
- # end of 'src/Makefile'
- fi
- if test -f 'src/rcs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/rcs.c'\"
- else
- echo shar: Extracting \"'src/rcs.c'\" \(42394 characters\)
- sed "s/^X//" >'src/rcs.c' <<'END_OF_FILE'
- X/*
- X * RCS create/change operation
- X */
- X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- X Copyright 1990 by Paul Eggert
- X Distributed under license by the Free Software Foundation, Inc.
- X
- XThis file is part of RCS.
- X
- XRCS is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XRCS is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with RCS; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- XReport problems and direct all questions to:
- X
- X rcs-bugs@cs.purdue.edu
- X
- X*/
- X
- X
- X
- X
- X/* $Log: rcs.c,v $
- X * Revision 5.7 1990/12/18 17:19:21 eggert
- X * Fix bug with multiple -n and -N options.
- X *
- X * Revision 5.6 1990/12/04 05:18:40 eggert
- X * Use -I for prompts and -q for diagnostics.
- X *
- X * Revision 5.5 1990/11/11 00:06:35 eggert
- X * Fix `rcs -e' core dump.
- X *
- X * Revision 5.4 1990/11/01 05:03:33 eggert
- X * Add -I and new -t behavior. Permit arbitrary data in logs.
- X *
- X * Revision 5.3 1990/10/04 06:30:16 eggert
- X * Accumulate exit status across files.
- X *
- X * Revision 5.2 1990/09/04 08:02:17 eggert
- X * Standardize yes-or-no procedure.
- X *
- X * Revision 5.1 1990/08/29 07:13:51 eggert
- X * Remove unused setuid support. Clean old log messages too.
- X *
- X * Revision 5.0 1990/08/22 08:12:42 eggert
- X * Don't lose names when applying -a option to multiple files.
- X * Remove compile-time limits; use malloc instead. Add setuid support.
- X * Permit dates past 1999/12/31. Make lock and temp files faster and safer.
- X * Ansify and Posixate. Add -V. Fix umask bug. Make linting easier. Tune.
- X * Yield proper exit status. Check diff's output.
- X *
- X * Revision 4.11 89/05/01 15:12:06 narten
- X * changed copyright header to reflect current distribution rules
- X *
- X * Revision 4.10 88/11/08 16:01:54 narten
- X * didn't install previous patch correctly
- X *
- X * Revision 4.9 88/11/08 13:56:01 narten
- X * removed include <sysexits.h> (not needed)
- X * minor fix for -A option
- X *
- X * Revision 4.8 88/08/09 19:12:27 eggert
- X * Don't access freed storage.
- X * Use execv(), not system(); yield proper exit status; remove lint.
- X *
- X * Revision 4.7 87/12/18 11:37:17 narten
- X * lint cleanups (Guy Harris)
- X *
- X * Revision 4.6 87/10/18 10:28:48 narten
- X * Updating verison numbers. Changes relative to 1.1 are actually
- X * relative to 4.3
- X *
- X * Revision 1.4 87/09/24 13:58:52 narten
- X * Sources now pass through lint (if you ignore printf/sprintf/fprintf
- X * warnings)
- X *
- X * Revision 1.3 87/03/27 14:21:55 jenkins
- X * Port to suns
- X *
- X * Revision 1.2 85/12/17 13:59:09 albitz
- X * Changed setstate to rcs_setstate because of conflict with random.o.
- X *
- X * Revision 4.3 83/12/15 12:27:33 wft
- X * rcs -u now breaks most recent lock if it can't find a lock by the caller.
- X *
- X * Revision 4.2 83/12/05 10:18:20 wft
- X * Added conditional compilation for sending mail.
- X * Alternatives: V4_2BSD, V6, USG, and other.
- X *
- X * Revision 4.1 83/05/10 16:43:02 wft
- X * Simplified breaklock(); added calls to findlock() and getcaller().
- X * Added option -b (default branch). Updated -s and -w for -b.
- X * Removed calls to stat(); now done by pairfilenames().
- X * Replaced most catchints() calls with restoreints().
- X * Removed check for exit status of delivermail().
- X * Directed all interactive output to stderr.
- X *
- X * Revision 3.9.1.1 83/12/02 22:08:51 wft
- X * Added conditional compilation for 4.2 sendmail and 4.1 delivermail.
- X *
- X * Revision 3.9 83/02/15 15:38:39 wft
- X * Added call to fastcopy() to copy remainder of RCS file.
- X *
- X * Revision 3.8 83/01/18 17:37:51 wft
- X * Changed sendmail(): now uses delivermail, and asks whether to break the lock.
- X *
- X * Revision 3.7 83/01/15 18:04:25 wft
- X * Removed putree(); replaced with puttree() in rcssyn.c.
- X * Combined putdellog() and scanlogtext(); deleted putdellog().
- X * Cleaned up diagnostics and error messages. Fixed problem with
- X * mutilated files in case of deletions in 2 files in a single command.
- X * Changed marking of selector from 'D' to DELETE.
- X *
- X * Revision 3.6 83/01/14 15:37:31 wft
- X * Added ignoring of interrupts while new RCS file is renamed;
- X * Avoids deletion of RCS files by interrupts.
- X *
- X * Revision 3.5 82/12/10 21:11:39 wft
- X * Removed unused variables, fixed checking of return code from diff,
- X * introduced variant COMPAT2 for skipping Suffix on -A files.
- X *
- X * Revision 3.4 82/12/04 13:18:20 wft
- X * Replaced getdelta() with gettree(), changed breaklock to update
- X * field lockedby, added some diagnostics.
- X *
- X * Revision 3.3 82/12/03 17:08:04 wft
- X * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
- X * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x).
- X * fixed -u for missing revno. Disambiguated structure members.
- X *
- X * Revision 3.2 82/10/18 21:05:07 wft
- X * rcs -i now generates a file mode given by the umask minus write permission;
- X * otherwise, rcs keeps the mode, but removes write permission.
- X * I added a check for write error, fixed call to getlogin(), replaced
- X * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed
- X * conflicting, long identifiers.
- X *
- X * Revision 3.1 82/10/13 16:11:07 wft
- X * fixed type of variables receiving from getc() (char -> int).
- X */
- X
- X
- X#include "rcsbase.h"
- X
- Xstruct Lockrev {
- X const char *revno;
- X struct Lockrev * nextrev;
- X};
- X
- Xstruct Symrev {
- X const char *revno;
- X const char *ssymbol;
- X int override;
- X struct Symrev * nextsym;
- X};
- X
- Xstruct Status {
- X const char *revno;
- X const char *status;
- X struct Status * nextstatus;
- X};
- X
- Xenum changeaccess {append, erase};
- Xstruct chaccess {
- X const char *login;
- X enum changeaccess command;
- X struct chaccess *nextchaccess;
- X};
- X
- Xstruct delrevpair {
- X const char *strt;
- X const char *end;
- X int code;
- X};
- X
- Xstatic int buildeltatext P((const struct hshentries*));
- Xstatic int removerevs P((void));
- Xstatic int sendmail P((const char*,const char*));
- Xstatic struct Lockrev *rmnewlocklst P((const struct Lockrev*));
- Xstatic void breaklock P((const struct hshentry*));
- Xstatic void buildtree P((void));
- Xstatic void cleanup P((void));
- Xstatic void getaccessor P((char*,enum changeaccess));
- Xstatic void getassoclst P((int,char*));
- Xstatic void getchaccess P((const char*,enum changeaccess));
- Xstatic void getdelrev P((char*));
- Xstatic void getstates P((char*));
- Xstatic void rcs_setstate P((const char*,const char*));
- Xstatic void scanlogtext P((struct hshentry*,int));
- Xstatic void setlock P((const char*));
- Xstatic void updateaccess P((void));
- Xstatic void updateassoc P((void));
- Xstatic void updatelocks P((void));
- X
- Xstatic struct buf numrev;
- Xstatic const char *headstate;
- Xstatic int chgheadstate, exitstatus, lockhead, unlockcaller;
- Xstatic struct Lockrev *newlocklst, *rmvlocklst;
- Xstatic struct Status *statelst, *laststate;
- Xstatic struct Symrev *assoclst, *lastassoc;
- Xstatic struct chaccess *chaccess, **nextchaccess;
- Xstatic struct delrevpair delrev;
- Xstatic struct hshentry *cuthead, *cuttail, *delstrt;
- Xstatic struct hshentries *gendeltas;
- X
- XmainProg(rcsId, "rcs", "$Id: rcs.c,v 5.7 1990/12/18 17:19:21 eggert Exp $")
- X{
- X static const char cmdusage[] =
- X "\nrcs usage: rcs -alogins -Aoldfile -{blu}[rev] -cstring -e[logins] -i -{LU} -{nN}name[:rev] -orange -sstate[:rev] -t[textfile] -Vn file ...";
- X
- X const char *branchsym, *commsyml, *textfile;
- X int branchflag, expmode, initflag;
- X int r, strictlock, strict_selected, textflag;
- X mode_t defaultRCSmode; /* default mode for new RCS files */
- X struct buf branchnum;
- X struct Lockrev *curlock, * rmvlock, *lockpt;
- X struct Status * curstate;
- X
- X initid();
- X catchints();
- X
- X nextchaccess = &chaccess;
- X branchsym = commsyml = textfile = nil;
- X branchflag = strictlock = false;
- X bufautobegin(&branchnum);
- X curlock = rmvlock = nil;
- X defaultRCSmode = 0;
- X expmode = -1;
- X initflag= textflag = false;
- X strict_selected = 0;
- X
- X /* preprocessing command options */
- X while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
- X switch ((*argv)[1]) {
- X
- X case 'i': /* initial version */
- X initflag = true;
- X break;
- X
- X case 'b': /* change default branch */
- X if (branchflag) redefined('b');
- X branchflag= true;
- X branchsym = (*argv)+2;
- X break;
- X
- X case 'c': /* change comment symbol */
- X if (commsyml) redefined('c');
- X commsyml = (*argv)+2;
- X break;
- X
- X case 'a': /* add new accessor */
- X getaccessor(*argv+1, append);
- X break;
- X
- X case 'A': /* append access list according to accessfile */
- X *argv += 2;
- X if (!**argv) {
- X error("missing file name after -A");
- X break;
- X }
- X if (0 < pairfilenames(1,argv,rcsreadopen,true,false)) {
- X while (AccessList) {
- X getchaccess(strsave(AccessList->login), append);
- X AccessList = AccessList->nextaccess;
- X }
- X ffclose(finptr);
- X }
- X break;
- X
- X case 'e': /* remove accessors */
- X getaccessor(*argv+1, erase);
- X break;
- X
- X case 'l': /* lock a revision if it is unlocked */
- X if ( (*argv)[2] == '\0'){ /* lock head or def. branch */
- X lockhead = true;
- X break;
- X }
- X lockpt = talloc(struct Lockrev);
- X lockpt->revno = (*argv)+2;
- X lockpt->nextrev = nil;
- X if ( curlock )
- X curlock->nextrev = lockpt;
- X else
- X newlocklst = lockpt;
- X curlock = lockpt;
- X break;
- X
- X case 'u': /* release lock of a locked revision */
- X if ( (*argv)[2] == '\0'){ /* unlock head */
- X unlockcaller=true;
- X break;
- X }
- X lockpt = talloc(struct Lockrev);
- X lockpt->revno = (*argv)+2;
- X lockpt->nextrev = nil;
- X if (rmvlock)
- X rmvlock->nextrev = lockpt;
- X else
- X rmvlocklst = lockpt;
- X rmvlock = lockpt;
- X
- X curlock = rmnewlocklst(lockpt);
- X break;
- X
- X case 'L': /* set strict locking */
- X if (strict_selected++) { /* Already selected L or U? */
- X if (!strictlock) /* Already selected -U? */
- X warn("-L overrides -U.");
- X }
- X strictlock = true;
- X break;
- X
- X case 'U': /* release strict locking */
- X if (strict_selected++) { /* Already selected L or U? */
- X if (strictlock) /* Already selected -L? */
- X warn("-L overrides -U.");
- X }
- X else
- X strictlock = false;
- X break;
- X
- X case 'n': /* add new association: error, if name exists */
- X if ( (*argv)[2] == '\0') {
- X error("missing symbolic name after -n");
- X break;
- X }
- X getassoclst(false, (*argv)+1);
- X break;
- X
- X case 'N': /* add or change association */
- X if ( (*argv)[2] == '\0') {
- X error("missing symbolic name after -N");
- X break;
- X }
- X getassoclst(true, (*argv)+1);
- X break;
- X
- X case 'o': /* delete revisions */
- X if (delrev.strt) redefined('o');
- X if ( (*argv)[2] == '\0' ) {
- X error("missing revision range after -o");
- X break;
- X }
- X getdelrev( (*argv)+1 );
- X break;
- X
- X case 's': /* change state attribute of a revision */
- X if ( (*argv)[2] == '\0') {
- X error("state missing after -s");
- X break;
- X }
- X getstates( (*argv)+1);
- X break;
- X
- X case 't': /* change descriptive text */
- X textflag=true;
- X if ((*argv)[2]!='\0'){
- X if (textfile) redefined('t');
- X textfile = (*argv)+2;
- X }
- X break;
- X
- X case 'I':
- X interactiveflag = true;
- X break;
- X
- X case 'q':
- X quietflag = true;
- X break;
- X
- X case 'V':
- X setRCSversion(*argv);
- X break;
- X
- X case 'k': /* set keyword expand mode */
- X if (0 <= expmode) redefined('k');
- X if (0 <= (expmode = str2expmode(*argv+2)))
- X break;
- X /* fall into */
- X default:
- X faterror("unknown option: %s%s", *argv, cmdusage);
- X };
- X } /* end processing of options */
- X
- X if (argc<1) faterror("no input file%s", cmdusage);
- X if (nerror) {
- X diagnose("%s aborted\n",cmdid);
- X exitmain(EXIT_FAILURE);
- X }
- X if (initflag) {
- X defaultRCSmode = umask((mode_t)0);
- X VOID umask(defaultRCSmode);
- X defaultRCSmode = ~defaultRCSmode & 0444;
- X }
- X
- X /* now handle all filenames */
- X do {
- X foutptr = NULL;
- X finptr=frewrite=NULL;
- X ffree();
- X
- X if ( initflag ) {
- X switch (pairfilenames(argc, argv, rcswriteopen, false, false)) {
- X case -1: break; /* not exist; ok */
- X case 0: continue; /* error */
- X case 1: error("file %s exists already", RCSfilename);
- X continue;
- X }
- X }
- X else {
- X switch (pairfilenames(argc, argv, rcswriteopen, true, false)) {
- X case -1: continue; /* not exist */
- X case 0: continue; /* errors */
- X case 1: break; /* file exists; ok*/
- X }
- X }
- X
- X
- X /* now RCSfilename contains the name of the RCS file, and
- X * workfilename contains the name of the working file.
- X * if !initflag, finptr contains the file descriptor for the
- X * RCS file. The admin node is initialized.
- X */
- X
- X diagnose("RCS file: %s\n", RCSfilename);
- X
- X if (initflag && !getworkstat()) continue; /* give up */
- X if (!initflag && !checkaccesslist()) continue; /* give up */
- X
- X gettree(); /* read in delta tree */
- X
- X /* update admin. node */
- X if (strict_selected) StrictLocks = strictlock;
- X if (commsyml) {
- X Comment.string = commsyml;
- X Comment.size = strlen(commsyml);
- X }
- X if (0 <= expmode) Expand = expmode;
- X
- X /* update default branch */
- X if (branchflag && expandsym(branchsym, &branchnum)) {
- X if (countnumflds(branchnum.string)) {
- X Dbranch = branchnum.string;
- X } else
- X Dbranch = nil;
- X }
- X
- X updateaccess(); /* update access list */
- X
- X updateassoc(); /* update association list */
- X
- X updatelocks(); /* update locks */
- X
- X /* update state attribution */
- X if (chgheadstate) {
- X /* change state of default branch or head */
- X if (Dbranch==nil) {
- X if (Head==nil)
- X warn("can't change states in an empty tree");
- X else Head->state = headstate;
- X } else {
- X rcs_setstate(Dbranch,headstate); /* Can't set directly */
- X }
- X }
- X curstate = statelst;
- X while( curstate ) {
- X rcs_setstate(curstate->revno,curstate->status);
- X curstate = curstate->nextstatus;
- X }
- X
- X cuthead = cuttail = nil;
- X if (delrev.strt && removerevs()) {
- X /* rebuild delta tree if some deltas are deleted */
- X if ( cuttail )
- X VOID genrevs(cuttail->num, (char *)nil,(char *)nil,
- X (char *)nil, &gendeltas);
- X buildtree();
- X }
- X
- X
- X putadmin(frewrite);
- X if ( Head )
- X puttree(Head, frewrite);
- X putdesc(textflag,textfile);
- X foutptr = NULL;
- X
- X if ( Head) {
- X if (!delrev.strt) {
- X /* no revision deleted */
- X fastcopy(finptr,frewrite);
- X } else {
- X if (!cuttail || buildeltatext(gendeltas))
- X scanlogtext((struct hshentry *)nil,nil);
- X /* copy rest of delta text nodes that are not deleted */
- X }
- X }
- X if (finptr) {ffclose(finptr); finptr=NULL;} /* Help the file system. */
- X ffclose(frewrite); frewrite = NULL;
- X if ( ! nerror ) { /* move temporary file to RCS file if no error */
- X /* update mode */
- X seteid();
- X r = chmod(newRCSfilename,
- X (
- X !initflag ? RCSstat.st_mode
- X : haveworkstat==0 ? workstat.st_mode
- X : defaultRCSmode
- X ) & ~(S_IWUSR|S_IWGRP|S_IWOTH)
- X );
- X if (r == 0) {
- X ignoreints();
- X r = re_name(newRCSfilename,RCSfilename);
- X keepdirtemp(newRCSfilename);
- X restoreints();
- X }
- X setrid();
- X if (r != 0) {
- X eerror(RCSfilename);
- X error("saved in %s", newRCSfilename);
- X dirtempunlink();
- X break;
- X }
- X diagnose("done\n");
- X } else {
- X diagnose("%s aborted; %s unchanged.\n",cmdid,RCSfilename);
- X }
- X } while (cleanup(),
- X ++argv, --argc >=1);
- X
- X tempunlink();
- X exitmain(exitstatus);
- X} /* end of main (rcs) */
- X
- X static void
- Xcleanup()
- X{
- X if (nerror) exitstatus = EXIT_FAILURE;
- X if (finptr) ffclose(finptr);
- X if (frewrite) ffclose(frewrite);
- X dirtempunlink();
- X}
- X
- X exiting void
- Xexiterr()
- X{
- X dirtempunlink();
- X tempunlink();
- X _exit(EXIT_FAILURE);
- X}
- X
- X
- X static void
- Xgetassoclst(flag, sp)
- Xint flag;
- Xchar * sp;
- X/* Function: associate a symbolic name to a revision or branch, */
- X/* and store in assoclst */
- X
- X{
- X struct Symrev * pt;
- X const char *temp;
- X int c;
- X
- X while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n') ;
- X temp = sp;
- X sp = checkid(sp, ':'); /* check for invalid symbolic name */
- X c = *sp; *sp = '\0';
- X while( c == ' ' || c == '\t' || c == '\n') c = *++sp;
- X
- X if ( c != ':' && c != '\0') {
- X error("invalid string %s after option -n or -N",sp);
- X return;
- X }
- X
- X pt = talloc(struct Symrev);
- X pt->ssymbol = temp;
- X pt->override = flag;
- X if (c == '\0') /* delete symbol */
- X pt->revno = nil;
- X else {
- X while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ;
- X if ( c == '\0' )
- X pt->revno = nil;
- X else
- X pt->revno = sp;
- X }
- X pt->nextsym = nil;
- X if (lastassoc)
- X lastassoc->nextsym = pt;
- X else
- X assoclst = pt;
- X lastassoc = pt;
- X return;
- X}
- X
- X
- X static void
- Xgetchaccess(login, command)
- X const char *login;
- X enum changeaccess command;
- X{
- X register struct chaccess *pt;
- X
- X *nextchaccess = pt = talloc(struct chaccess);
- X pt->login = login;
- X pt->command = command;
- X pt->nextchaccess = nil;
- X nextchaccess = &pt->nextchaccess;
- X}
- X
- X
- X
- X static void
- Xgetaccessor(opt, command)
- X char *opt;
- X enum changeaccess command;
- X/* Function: get the accessor list of options -e and -a, */
- X/* and store in chaccess */
- X
- X
- X{
- X register c;
- X register char *sp;
- X
- X sp = opt;
- X while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ;
- X if ( c == '\0') {
- X if (command == erase && sp-opt == 1) {
- X getchaccess((const char*)nil, command);
- X return;
- X }
- X error("missing login name after option -a or -e");
- X return;
- X }
- X
- X while( c != '\0') {
- X getchaccess(sp, command);
- X sp = checkid(sp,',');
- X c = *sp; *sp = '\0';
- X while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp);
- X }
- X}
- X
- X
- X
- X static void
- Xgetstates(sp)
- Xchar *sp;
- X/* Function: get one state attribute and the corresponding */
- X/* revision and store in statelst */
- X
- X{
- X const char *temp;
- X struct Status *pt;
- X register c;
- X
- X while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n') ;
- X temp = sp;
- X sp = checkid(sp,':'); /* check for invalid state attribute */
- X c = *sp; *sp = '\0';
- X while( c == ' ' || c == '\t' || c == '\n' ) c = *++sp;
- X
- X if ( c == '\0' ) { /* change state of def. branch or Head */
- X chgheadstate = true;
- X headstate = temp;
- X return;
- X }
- X else if ( c != ':' ) {
- X error("missing ':' after state in option -s");
- X return;
- X }
- X
- X while( (c = *++sp) == ' ' || c == '\t' || c == '\n') ;
- X pt = talloc(struct Status);
- X pt->status = temp;
- X pt->revno = sp;
- X pt->nextstatus = nil;
- X if (laststate)
- X laststate->nextstatus = pt;
- X else
- X statelst = pt;
- X laststate = pt;
- X}
- X
- X
- X
- X static void
- Xgetdelrev(sp)
- Xchar *sp;
- X/* Function: get revision range or branch to be deleted, */
- X/* and place in delrev */
- X{
- X int c;
- X struct delrevpair *pt;
- X
- X pt = &delrev;
- X while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
- X
- X if ( c == '<' || c == '-' ) { /* -o -rev or <rev */
- X while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
- X pt->strt = sp; pt->code = 1;
- X while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp);
- X *sp = '\0';
- X pt->end = nil;
- X return;
- X }
- X else {
- X pt->strt = sp;
- X while( c != ' ' && c != '\n' && c != '\t' && c != '\0'
- X && c != '-' && c != '<' ) c = *++sp;
- X *sp = '\0';
- X while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp;
- X if ( c == '\0' ) { /* -o rev or branch */
- X pt->end = nil; pt->code = 0;
- X return;
- X }
- X if ( c != '-' && c != '<') {
- X faterror("invalid range %s %s after -o", pt->strt, sp);
- X }
- X while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ;
- X if ( c == '\0') { /* -o rev- or rev< */
- X pt->end = nil; pt->code = 2;
- X return;
- X }
- X }
- X /* -o rev1-rev2 or rev1<rev2 */
- X pt->end = sp; pt->code = 3;
- X while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp;
- X *sp = '\0';
- X}
- X
- X
- X
- X
- X static void
- Xscanlogtext(delta,edit)
- X struct hshentry *delta;
- X int edit;
- X/* Function: Scans delta text nodes up to and including the one given
- X * by delta, or up to last one present, if delta==nil.
- X * For the one given by delta (if delta!=nil), the log message is saved into
- X * curlogmsg and the text is edited if 'edit' is set, copied otherwise.
- X * Assumes the initial lexeme must be read in first.
- X * Does not advance nexttok after it is finished, except if delta==nil.
- X */
- X{
- X const struct hshentry *nextdelta;
- X struct cbuf cb;
- X
- X for (;;) {
- X foutptr = NULL;
- X nextlex();
- X if (!(nextdelta=getnum())) {
- X if(delta)
- X faterror("can't find delta for revision %s", delta->num);
- X if (nexttok != EOFILE)
- X fatserror("expecting EOF");
- X return; /* no more delta text nodes */
- X }
- X if (nextdelta->selector) {
- X foutptr = frewrite;
- X aprintf(frewrite,DELNUMFORM,nextdelta->num,Klog);
- X }
- X getkeystring(Klog);
- X if (delta==nextdelta) {
- X cb = savestring(&curlogbuf);
- X delta->log = curlogmsg =
- X cleanlogmsg(curlogbuf.string, cb.size);
- X } else {readstring();
- X }
- X nextlex();
- X while (nexttok==ID && strcmp(NextString,Ktext)!=0)
- X ignorephrase();
- X getkeystring(Ktext);
- X
- X if (delta==nextdelta)
- X break;
- X readstring(); /* skip over it */
- X
- X }
- X /* got the one we're looking for */
- X if (edit)
- X editstring((struct hshentry *)nil);
- X else
- X copystring();
- X}
- X
- X
- X
- X static struct Lockrev *
- Xrmnewlocklst(which)
- X const struct Lockrev *which;
- X/* Function: remove lock to revision which->revno from newlocklst */
- X
- X{
- X struct Lockrev * pt, *pre;
- X
- X while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){
- X struct Lockrev *pn = newlocklst->nextrev;
- X tfree(newlocklst);
- X newlocklst = pn;
- X }
- X
- X pt = pre = newlocklst;
- X while( pt ) {
- X if ( ! strcmp(pt->revno, which->revno) ) {
- X pre->nextrev = pt->nextrev;
- X tfree(pt);
- X pt = pre->nextrev;
- X }
- X else {
- X pre = pt;
- X pt = pt->nextrev;
- X }
- X }
- X return pre;
- X}
- X
- X
- X
- X static void
- Xupdateaccess()
- X{
- X register struct chaccess *ch;
- X register struct access **p, *t;
- X
- X for (ch = chaccess; ch; ch = ch->nextchaccess) {
- X switch (ch->command) {
- X case erase:
- X if (!ch->login)
- X AccessList = nil;
- X else
- X for (p = &AccessList; (t = *p); )
- X if (strcmp(ch->login, t->login) == 0)
- X *p = t->nextaccess;
- X else
- X p = &t->nextaccess;
- X break;
- X case append:
- X for (p = &AccessList; ; p = &t->nextaccess)
- X if (!(t = *p)) {
- X *p = t = ftalloc(struct access);
- X t->login = ch->login;
- X t->nextaccess = nil;
- X break;
- X } else if (strcmp(ch->login, t->login) == 0)
- X break;
- X break;
- X }
- X }
- X}
- X
- X
- X static int
- Xsendmail(Delta, who)
- X const char *Delta, *who;
- X/* Function: mail to who, informing him that his lock on delta was
- X * broken by caller. Ask first whether to go ahead. Return false on
- X * error or if user decides not to break the lock.
- X */
- X{
- X const char *messagefile;
- X int old1, old2, c;
- X FILE * mailmess;
- X
- X
- X aprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
- X if (!yesorno(false, "Do you want to break the lock? [ny](n): "))
- X return false;
- X
- X /* go ahead with breaking */
- X messagefile = maketemp(0);
- X errno = 0;
- X if ( (mailmess = fopen(messagefile, "w")) == NULL) {
- X efaterror(messagefile);
- X }
- X
- X aprintf(mailmess, "Subject: Broken lock on %s\n\nYour lock on revision %s of file %s\nhas been broken by %s for the following reason:\n",
- X bindex(RCSfilename,SLASH), Delta, getfullRCSname(), getcaller()
- X );
- X aputs("State the reason for breaking the lock:\n(terminate with single '.' or end of file)\n>> ", stderr);
- X
- X old1 = '\n'; old2 = ' ';
- X for (; ;) {
- X c = getcstdin();
- X if ( c == EOF ) {
- X aprintf(mailmess, "%c\n", old1);
- X break;
- X }
- X else if ( c == '\n' && old1 == '.' && old2 == '\n')
- X break;
- X else {
- X afputc(old1, mailmess);
- X old2 = old1; old1 = c;
- X if (c=='\n') aputs(">> ", stderr);
- X }
- X }
- X ffclose(mailmess);
- X
- X /* ignore the exit status, even if delivermail unsuccessful */
- X VOID run(messagefile, (char*)nil, SENDMAIL, who, (char*)nil);
- X return(true);
- X}
- X
- X
- X
- X static void
- Xbreaklock(delta)
- X const struct hshentry *delta;
- X/* function: Finds the lock held by caller on delta,
- X * and removes it.
- X * Sends mail if a lock different from the caller's is broken.
- X * Prints an error message if there is no such lock or error.
- X */
- X{
- X register struct lock * next, * trail;
- X const char *num;
- X struct lock dummy;
- X
- X num=delta->num;
- X dummy.nextlock=next=Locks;
- X trail = &dummy;
- X while (next!=nil) {
- X if (strcmp(num, next->delta->num) == 0) {
- X if (
- X strcmp(getcaller(),next->login) != 0
- X && !sendmail(num, next->login)
- X ) {
- X error("%s still locked by %s", num, next->login);
- X return;
- X }
- X break; /* exact match */
- X }
- X trail=next;
- X next=next->nextlock;
- X }
- X if (next!=nil) {
- X /*found one */
- X diagnose("%s unlocked\n",next->delta->num);
- X trail->nextlock=next->nextlock;
- X next->delta->lockedby=nil;
- X Locks=dummy.nextlock;
- X } else {
- X error("no lock set on revision %s", num);
- X }
- X}
- X
- X
- X
- X static struct hshentry *
- Xsearchcutpt(object, length, store)
- X const char *object;
- X unsigned length;
- X struct hshentries *store;
- X/* Function: Search store and return entry with number being object. */
- X/* cuttail = nil, if the entry is Head; otherwise, cuttail */
- X/* is the entry point to the one with number being object */
- X
- X{
- X cuthead = nil;
- X while (compartial(store->first->num, object, length)) {
- X cuthead = store->first;
- X store = store->rest;
- X }
- X return store->first;
- X}
- X
- X
- X
- X static int
- Xbranchpoint(strt, tail)
- Xstruct hshentry *strt, *tail;
- X/* Function: check whether the deltas between strt and tail */
- X/* are locked or branch point, return 1 if any is */
- X/* locked or branch point; otherwise, return 0 and */
- X/* mark deleted */
- X
- X{
- X struct hshentry *pt;
- X const struct lock *lockpt;
- X int flag;
- X
- X
- X pt = strt;
- X flag = false;
- X while( pt != tail) {
- X if ( pt->branches ){ /* a branch point */
- X flag = true;
- X error("can't remove branch point %s", pt->num);
- X }
- X lockpt = Locks;
- X while(lockpt && lockpt->delta != pt)
- X lockpt = lockpt->nextlock;
- X if ( lockpt ) {
- X flag = true;
- X error("can't remove locked revision %s",pt->num);
- X }
- X pt = pt->next;
- X }
- X
- X if ( ! flag ) {
- X pt = strt;
- X while( pt != tail ) {
- X pt->selector = false;
- X diagnose("deleting revision %s\n",pt->num);
- X pt = pt->next;
- X }
- X }
- X return flag;
- X}
- X
- X
- X
- X static int
- Xremoverevs()
- X/* Function: get the revision range to be removed, and place the */
- X/* first revision removed in delstrt, the revision before */
- X/* delstrt in cuthead( nil, if delstrt is head), and the */
- X/* revision after the last removed revision in cuttail(nil */
- X/* if the last is a leaf */
- X
- X{
- X struct hshentry *target, *target2, *temp;
- X unsigned length;
- X int flag;
- X
- X flag = false;
- X if (!expandsym(delrev.strt, &numrev)) return 0;
- X target = genrevs(numrev.string, (char*)nil, (char*)nil, (char*)nil, &gendeltas);
- X if ( ! target ) return 0;
- X if (cmpnum(target->num, numrev.string)) flag = true;
- X length = countnumflds(numrev.string);
- X
- X if (delrev.code == 0) { /* -o rev or -o branch */
- X if (length & 1)
- X temp=searchcutpt(target->num,length+1,gendeltas);
- X else if (flag) {
- X error("Revision %s doesn't exist.", numrev.string);
- X return 0;
- X }
- X else
- X temp = searchcutpt(numrev.string, length, gendeltas);
- X cuttail = target->next;
- X if ( branchpoint(temp, cuttail) ) {
- X cuttail = nil;
- X return 0;
- X }
- X delstrt = temp; /* first revision to be removed */
- X return 1;
- X }
- X
- X if (length & 1) { /* invalid branch after -o */
- X error("invalid branch range %s after -o", numrev.string);
- X return 0;
- X }
- X
- X if (delrev.code == 1) { /* -o -rev */
- X if ( length > 2 ) {
- X temp = searchcutpt( target->num, length-1, gendeltas);
- X cuttail = target->next;
- X }
- X else {
- X temp = searchcutpt(target->num, length, gendeltas);
- X cuttail = target;
- X while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) )
- X cuttail = cuttail->next;
- X }
- X if ( branchpoint(temp, cuttail) ){
- X cuttail = nil;
- X return 0;
- X }
- X delstrt = temp;
- X return 1;
- X }
- X
- X if (delrev.code == 2) { /* -o rev- */
- X if ( length == 2 ) {
- X temp = searchcutpt(target->num, 1,gendeltas);
- X if ( flag)
- X cuttail = target;
- X else
- X cuttail = target->next;
- X }
- X else {
- X if ( flag){
- X cuthead = target;
- X if ( !(temp = target->next) ) return 0;
- X }
- X else
- X temp = searchcutpt(target->num, length, gendeltas);
- X getbranchno(temp->num, &numrev); /* get branch number */
- X target = genrevs(numrev.string, (char*)nil, (char*)nil, (char*)nil, &gendeltas);
- X }
- X if ( branchpoint( temp, cuttail ) ) {
- X cuttail = nil;
- X return 0;
- X }
- X delstrt = temp;
- X return 1;
- X }
- X
- X /* -o rev1-rev2 */
- X if (!expandsym(delrev.end, &numrev)) return 0;
- X if (
- X length != countnumflds(numrev.string)
- X || length>2 && compartial(numrev.string, target->num, length-1)
- X ) {
- X error("invalid revision range %s-%s", target->num, numrev.string);
- X return 0;
- X }
- X
- X target2 = genrevs(numrev.string,(char*)nil,(char*)nil,(char*)nil,&gendeltas);
- X if ( ! target2 ) return 0;
- X
- X if ( length > 2) { /* delete revisions on branches */
- X if ( cmpnum(target->num, target2->num) > 0) {
- X if (cmpnum(target2->num, numrev.string))
- X flag = true;
- X else
- X flag = false;
- X temp = target;
- X target = target2;
- X target2 = temp;
- X }
- X if ( flag ) {
- X if ( ! cmpnum(target->num, target2->num) ) {
- X error("Revisions %s-%s don't exist.", delrev.strt,delrev.end);
- X return 0;
- X }
- X cuthead = target;
- X temp = target->next;
- X }
- X else
- X temp = searchcutpt(target->num, length, gendeltas);
- X cuttail = target2->next;
- X }
- X else { /* delete revisions on trunk */
- X if ( cmpnum( target->num, target2->num) < 0 ) {
- X temp = target;
- X target = target2;
- X target2 = temp;
- X }
- X else
- X if (cmpnum(target2->num, numrev.string))
- X flag = true;
- X else
- X flag = false;
- X if ( flag ) {
- X if ( ! cmpnum(target->num, target2->num) ) {
- X error("Revisions %s-%s don't exist.", delrev.strt, delrev.end);
- X return 0;
- X }
- X cuttail = target2;
- X }
- X else
- X cuttail = target2->next;
- X temp = searchcutpt(target->num, length, gendeltas);
- X }
- X if ( branchpoint(temp, cuttail) ) {
- X cuttail = nil;
- X return 0;
- X }
- X delstrt = temp;
- X return 1;
- X}
- X
- X
- X
- X static void
- Xupdateassoc()
- X/* Function: add or delete(if revno is nil) association */
- X/* which is stored in assoclst */
- X
- X{
- X const struct Symrev *curassoc;
- X struct assoc * pre, * pt;
- X
- X /* add new associations */
- X curassoc = assoclst;
- X while( curassoc ) {
- X if ( curassoc->revno == nil ) { /* delete symbol */
- X pre = pt = Symbols;
- X while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) {
- X pre = pt;
- X pt = pt->nextassoc;
- X }
- X if ( pt )
- X if ( pre == pt )
- X Symbols = pt->nextassoc;
- X else
- X pre->nextassoc = pt->nextassoc;
- X else
- X warn("can't delete nonexisting symbol %s",curassoc->ssymbol);
- X }
- X else if (expandsym(curassoc->revno, &numrev)) {
- X /* add symbol */
- X VOID addsymbol(fstrsave(numrev.string), curassoc->ssymbol, curassoc->override);
- X }
- X curassoc = curassoc->nextsym;
- X }
- X
- X}
- X
- X
- X
- X static void
- Xupdatelocks()
- X/* Function: remove lock for caller or first lock if unlockcaller is set;
- X * remove locks which are stored in rmvlocklst,
- X * add new locks which are stored in newlocklst,
- X * add lock for Dbranch or Head if lockhead is set.
- X */
- X{
- X const struct Lockrev *lockpt;
- X struct hshentry *target;
- X
- X if (unlockcaller) { /* find lock for caller */
- X if ( Head ) {
- X if (Locks) {
- X switch (findlock(true, &target)) {
- X case 0:
- X breaklock(Locks->delta); /* remove most recent lock */
- X break;
- X case 1:
- X diagnose("%s unlocked\n",target->num);
- X break;
- X }
- X } else {
- X warn("No locks are set.");
- X }
- X } else {
- X warn("can't unlock an empty tree");
- X }
- X }
- X
- X /* remove locks which are stored in rmvlocklst */
- X lockpt = rmvlocklst;
- X while( lockpt ) {
- X if (expandsym(lockpt->revno, &numrev)) {
- X target = genrevs(numrev.string, (char *)nil, (char *)nil, (char *)nil, &gendeltas);
- X if ( target )
- X if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
- X error("can't unlock nonexisting revision %s",lockpt->revno);
- X else
- X breaklock(target);
- X /* breaklock does its own diagnose */
- X }
- X lockpt = lockpt->nextrev;
- X }
- X
- X /* add new locks which stored in newlocklst */
- X lockpt = newlocklst;
- X while( lockpt ) {
- X setlock(lockpt->revno);
- X lockpt = lockpt->nextrev;
- X }
- X
- X if (lockhead) { /* lock default branch or head */
- X if (Dbranch) {
- X setlock(Dbranch);
- X } else if (Head) {
- X if (0 <= addlock(Head))
- X diagnose("%s locked\n",Head->num);
- X } else {
- X warn("can't lock an empty tree");
- X }
- X }
- X
- X}
- X
- X
- X
- X static void
- Xsetlock(rev)
- X const char *rev;
- X/* Function: Given a revision or branch number, finds the corresponding
- X * delta and locks it for caller.
- X */
- X{
- X struct hshentry *target;
- X
- X if (expandsym(rev, &numrev)) {
- X target = genrevs(numrev.string, (char*)nil, (char*)nil,
- X (char*)nil, &gendeltas);
- X if ( target )
- X if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
- X error("can't lock nonexisting revision %s", numrev.string);
- X else
- X if (0 <= addlock(target))
- X diagnose("%s locked\n", target->num);
- X }
- X}
- X
- X
- X
- X static void
- Xrcs_setstate(rev,status)
- X const char *rev, *status;
- X/* Function: Given a revision or branch number, finds the corresponding delta
- X * and sets its state to status.
- X */
- X{
- X struct hshentry *target;
- X
- X if (expandsym(rev, &numrev)) {
- X target = genrevs(numrev.string, (char*)nil, (char*)nil,
- X (char*)nil, &gendeltas);
- X if ( target )
- X if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string))
- X error("can't set state of nonexisting revision %s to %s",
- X numrev.string, status);
- X else
- X target->state = status;
- X }
- X}
- X
- X
- X
- X
- X
- X static int
- Xbuildeltatext(deltas)
- X const struct hshentries *deltas;
- X/* Function: put the delta text on frewrite and make necessary */
- X/* change to delta text */
- X{
- X int exit_stats;
- X register FILE *fcut; /* temporary file to rebuild delta tree */
- X const char *cutfilename, *diffilename;
- X
- X cutfilename = nil;
- X cuttail->selector = false;
- X inittmpeditfiles();
- X scanlogtext(deltas->first, false);
- X if ( cuthead ) {
- X cutfilename = maketemp(3);
- X errno = 0;
- X if ( (fcut = fopen(cutfilename, "w")) == NULL) {
- X efaterror(cutfilename);
- X }
- X
- X while (deltas->first != cuthead) {
- X deltas = deltas->rest;
- X scanlogtext(deltas->first, true);
- X }
- X
- X finishedit((struct hshentry *)nil);
- X arewind(fcopy);
- X fastcopy(fcopy, fcut);
- X swapeditfiles(false);
- X ffclose(fcut);
- X }
- X
- X while (deltas->first != cuttail)
- X scanlogtext((deltas = deltas->rest)->first, true);
- X finishedit((struct hshentry *)nil); ffclose(fcopy);
- X
- X if ( cuthead ) {
- X diffilename = maketemp(0);
- X exit_stats = run((char*)nil,diffilename,
- X DIFF DIFF_FLAGS, cutfilename, resultfile, (char*)nil);
- X if (!WIFEXITED(exit_stats) || 1<WEXITSTATUS(exit_stats))
- X faterror ("diff failed");
- X return putdtext(cuttail->num,curlogmsg,diffilename,frewrite,true);
- X } else
- X return putdtext(cuttail->num,curlogmsg,resultfile,frewrite,false);
- X}
- X
- X
- X
- X static void
- Xbuildtree()
- X/* Function: actually removes revisions whose selector field */
- X/* is false, and rebuilds the linkage of deltas. */
- X/* asks for reconfirmation if deleting last revision*/
- X{
- X struct hshentry * Delta;
- X struct branchhead *pt, *pre;
- X
- X if ( cuthead )
- X if ( cuthead->next == delstrt )
- X cuthead->next = cuttail;
- X else {
- X pre = pt = cuthead->branches;
- X while( pt && pt->hsh != delstrt ) {
- X pre = pt;
- X pt = pt->nextbranch;
- X }
- X if ( cuttail )
- X pt->hsh = cuttail;
- X else if ( pt == pre )
- X cuthead->branches = pt->nextbranch;
- X else
- X pre->nextbranch = pt->nextbranch;
- X }
- X else {
- X if ( cuttail == nil && !quietflag) {
- X if (!yesorno(false, "Do you really want to delete all revisions? [ny](n): ")) {
- X error("No revision deleted");
- X Delta = delstrt;
- X while( Delta) {
- X Delta->selector = true;
- X Delta = Delta->next;
- X }
- X return;
- X }
- X }
- X Head = cuttail;
- X }
- X return;
- X}
- X
- X#if lint
- X/* This lets us lint everything all at once. */
- X
- Xconst char cmdid[] = "";
- X
- X#define go(p,e) {int p P((int,char**)); void e P((void)); if(*argv)return p(argc,argv);if(*argv[1])e();return 0;}
- X
- X int
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X switch (argc) {
- X case 0: go(ciId, ciExit);
- X case 1: go(coId, coExit);
- X case 2: go(identId, identExit);
- X case 3: go(rcsdiffId, rdiffExit);
- X case 4: go(rcsmergeId, rmergeExit);
- X case 5: go(rlogId, rlogExit);
- X case 6: go(rcsId, exiterr);
- X default: return 0;
- X }
- X}
- X#endif
- END_OF_FILE
- if test 42394 -ne `wc -c <'src/rcs.c'`; then
- echo shar: \"'src/rcs.c'\" unpacked with wrong size!
- fi
- # end of 'src/rcs.c'
- fi
- echo shar: End of archive 3 \(of 12\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 12 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-