[comp.sources.unix] v24i010: RCS source control system, Part10/12

rsalz@bbn.com (Rich Salz) (02/23/91)

Submitted-by: Adam Hammer <hammer@cs.purdue.edu>
Posting-number: Volume 24, Issue 10
Archive-name: rcs/part10

#! /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:  man/rcsintro.1 rcs_func.ms src/maketime.c src/rcsdiff.c
#   src/rcskeep.c src/rcsmerge.c
# Wrapped by rsalz@litchi.bbn.com on Thu Feb 21 14:37:09 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 10 (of 12)."'
if test -f 'man/rcsintro.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/rcsintro.1'\"
else
  echo shar: Extracting \"'man/rcsintro.1'\" \(9209 characters\)
  sed "s/^X//" >'man/rcsintro.1' <<'END_OF_FILE'
X.de Id
X.ds Rv \\$3
X.ds Dt \\$4
X..
X.Id $Id: rcsintro.1,v 5.0 1990/08/22 09:11:00 eggert Exp $
X.ds r \s-1RCS\s0
X.if n .ds - \%--
X.if t .ds - \(em
X.am SS
X.LP
X..
X.TH RCSINTRO 1 \*(Dt GNU
X.SH NAME
Xrcsintro \- introduction to RCS commands
X.SH DESCRIPTION
XThe Revision Control System (\*r) manages multiple revisions of files.
X\*r automates the storing, retrieval, logging, identification, and merging
Xof revisions.  \*r is useful for text that is revised frequently, for example
Xprograms, documentation, graphics, papers, and form letters.
X.PP
XThe basic user interface is extremely simple.  The novice only needs
Xto learn two commands:
X.BR ci (1)
Xand
X.BR co (1).
X.BR ci ,
Xshort for \*(lqcheck in\*(rq, deposits the contents of a
Xfile into an archival file called an \*r file.  An \*r file
Xcontains all revisions of a particular file.
X.BR co ,
Xshort for \*(lqcheck out\*(rq, retrieves revisions from an \*r file.
X.SS "Functions of \*r"
X.IP \(bu
XStore and retrieve multiple revisions of text.  \*r saves all old
Xrevisions in a space efficient way.
XChanges no longer destroy the original, because the
Xprevious revisions remain accessible.  Revisions can be retrieved according to
Xranges of revision numbers, symbolic names, dates, authors, and
Xstates.
X.IP \(bu
XMaintain a complete history of changes.
X\*r logs all changes automatically.
XBesides the text of each revision, \*r stores the author, the date and time of
Xcheck-in, and a log message summarizing the change.
XThe logging makes it easy to find out
Xwhat happened to a module, without having to compare
Xsource listings or having to track down colleagues.
X.IP \(bu
XResolve access conflicts.  When two or more programmers wish to
Xmodify the same revision, \*r alerts the programmers and prevents one
Xmodification from corrupting the other.
X.IP \(bu
XMaintain a tree of revisions.  \*r can maintain separate lines of development
Xfor each module.  It stores a tree structure that represents the
Xancestral relationships among revisions.
X.IP \(bu
XMerge revisions and resolve conflicts.
XTwo separate lines of development of a module can be coalesced by merging.
XIf the revisions to be merged affect the same sections of code, \*r alerts the
Xuser about the overlapping changes.
X.IP \(bu
XControl releases and configurations.
XRevisions can be assigned symbolic names
Xand marked as released, stable, experimental, etc.
XWith these facilities, configurations of modules can be
Xdescribed simply and directly.
X.IP \(bu
XAutomatically identify each revision with name, revision number,
Xcreation time, author, etc.
XThe identification is like a stamp that can be embedded at an appropriate place
Xin the text of a revision.
XThe identification makes it simple to determine which
Xrevisions of which modules make up a given configuration.
X.IP \(bu
XMinimize secondary storage.  \*r needs little extra space for
Xthe revisions (only the differences).  If intermediate revisions are
Xdeleted, the corresponding deltas are compressed accordingly.
X.SS "Getting Started with \*r"
XSuppose you have a file
X.B f.c
Xthat you wish to put under control of \*r.
XInvoke the check-in command
X.IP
X.B "ci  f.c"
X.LP
XThis command creates the \*r file
X.BR f.c,v ,
Xstores
X.B f.c
Xinto it as revision 1.1, and
Xdeletes
X.BR f.c .
XIt also asks you for a description.  The description
Xshould be a synopsis of the contents of the file.  All later check-in
Xcommands will ask you for a log entry, which should summarize the
Xchanges that you made.
X.PP
XFiles ending in
X.B ,v
Xare called \*r files (\*(lqv\*(rq stands for \*(lqversions\*(rq);
Xthe others are called working files.
XTo get back the working file
X.B f.c
Xin the previous example, use the check-out
Xcommand
X.IP
X.B "co  f.c"
X.LP
XThis command extracts the latest revision from
X.B f.c,v
Xand writes
Xit into
X.BR f.c .
XIf you want to edit
X.BR f.c ,
Xyou must lock it as you check it out with the command
X.IP
X.B "co  \-l  f.c"
X.LP
XYou can now edit
X.BR f.c .
X.PP
XSuppose after some editing you want to know what changes that you have made.
XThe command
X.IP
X.B "rcsdiff  f.c"
X.LP
Xtells you the difference between the most recently checked-in version
Xand the working file.
XYou can check the file back in by invoking
X.IP
X.B "ci  f.c"
X.LP
XThis increments the revision number properly.
X.PP
XIf
X.B ci
Xcomplains with the message
X.IP
X.BI "ci error: no lock set by " "your name"
X.LP
Xthen you have tried to check in a file even though you did not
Xlock it when you checked it out.
XOf course, it is too late now to do the check-out with locking, because
Xanother check-out would
Xoverwrite your modifications.  Instead, invoke
X.IP
X.B "rcs  \-l  f.c"
X.LP
XThis command will lock the latest revision for you, unless somebody
Xelse got ahead of you already.  In this case, you'll have to negotiate with
Xthat person.
X.PP
XLocking assures that you, and only you, can check in the next update, and
Xavoids nasty problems if several people work on the same file.
XEven if a revision is locked, it can still be checked out for
Xreading, compiling, etc.  All that locking
Xprevents is a
X.I "check-in"
Xby anybody but the locker.
X.PP
XIf your \*r file is private, i.e., if you are the only person who is going
Xto deposit revisions into it, strict locking is not needed and you
Xcan turn it off.
XIf strict locking is turned off,
Xthe owner of the \*r file need not have a lock for check-in; all others
Xstill do.  Turning strict locking off and on is done with the commands
X.IP
X.BR "rcs  \-U  f.c" "     and     " "rcs  \-L  f.c"
X.LP
XIf you don't want to clutter your working directory with \*r files, create
Xa subdirectory called
X.B RCS
Xin your working directory, and move all your \*r
Xfiles there.  \*r commands will look first into that directory to find
Xneeded files.  All the commands discussed above will still work, without any
Xmodification.
X(Actually, pairs of \*r and working files can be specified in three ways:
X(a) both are given, (b) only the working file is given, (c) only the
X\*r file is given.  Both \*r and working files may have arbitrary path prefixes;
X\*r commands pair them up intelligently.)
X.PP
XTo avoid the deletion of the working file during check-in (in case you want to
Xcontinue editing or compiling), invoke
X.IP
X.BR "ci  \-l  f.c" "     or     " "ci  \-u  f.c"
X.LP
XThese commands check in
X.B f.c
Xas usual, but perform an implicit
Xcheck-out.  The first form also locks the checked in revision, the second one
Xdoesn't.  Thus, these options save you one check-out operation.
XThe first form is useful if you want to continue editing,
Xthe second one if you just want to read the file.
XBoth update the identification markers in your working file (see below).
X.PP
XYou can give
X.B ci
Xthe number you want assigned to a checked in
Xrevision.  Assume all your revisions were numbered 1.1, 1.2, 1.3, etc.,
Xand you would like to start release 2.
XThe command
X.IP
X.BR "ci  \-r2  f.c" "     or     " "ci  \-r2.1  f.c"
X.LP
Xassigns the number 2.1 to the new revision.
XFrom then on,
X.B ci
Xwill number the subsequent revisions
Xwith 2.2, 2.3, etc.  The corresponding
X.B co
Xcommands
X.IP
X.BR "co  \-r2  f.c" "     and     " "co  \-r2.1  f.c"
X.PP
Xretrieve the latest revision numbered
X.RI 2. x
Xand the revision 2.1,
Xrespectively.
X.B co
Xwithout a revision number selects
Xthe latest revision on the
X.IR trunk ,
Xi.e. the highest
Xrevision with a number consisting of two fields.  Numbers with more than two
Xfields are needed for branches.
XFor example, to start a branch at revision 1.3, invoke
X.IP
X.B "ci  \-r1.3.1  f.c"
X.LP
XThis command starts a branch numbered 1 at revision 1.3, and assigns
Xthe number 1.3.1.1 to the new revision.  For more information about
Xbranches, see
X.BR rcsfile (5).
X.SS "Automatic Identification"
X\*r can put special strings for identification into your source and object
Xcode.  To obtain such identification, place the marker
X.IP
X.B "$\&Id$"
X.LP
Xinto your text, for instance inside a comment.
X\*r will replace this marker with a string of the form
X.IP
X.BI $\&Id: "  filename  revision  date  time  author  state  " $
X.LP
XWith such a marker on the first page of each module, you can
Xalways see with which revision you are working.
X\*r keeps the markers up to date automatically.
XTo propagate the markers into your object code, simply put
Xthem into literal character strings.  In C, this is done as follows:
X.IP
X.ft 3
Xstatic char rcsid[] = \&"$\&Id$\&";
X.ft
X.LP
XThe command
X.B ident
Xextracts such markers from any file, even object code
Xand dumps.
XThus,
X.B ident
Xlets you find out
Xwhich revisions of which modules were used in a given program.
X.PP
XYou may also find it useful to put the marker
X.B $\&Log$
Xinto your text, inside a comment.  This marker accumulates
Xthe log messages that are requested during check-in.
XThus, you can maintain the complete history of your file directly inside it.
XThere are several additional identification markers; see
X.BR co (1)
Xfor
Xdetails.
X.SH IDENTIFICATION
XAuthor: Walter F. Tichy.
X.br
XRevision Number: \*(Rv; Release Date: \*(Dt.
X.br
XCopyright \(co 1982, 1988, 1989 by Walter F. Tichy.
X.br
XCopyright \(co 1990 by Paul Eggert.
X.SH "SEE ALSO"
Xci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1)
X.br
XWalter F. Tichy,
X\*r\*-A System for Version Control,
X.I "Software\*-Practice & Experience"
X.BR 15 ,
X7 (July 1985), 637-654.
END_OF_FILE
  if test 9209 -ne `wc -c <'man/rcsintro.1'`; then
    echo shar: \"'man/rcsintro.1'\" unpacked with wrong size!
  fi
  # end of 'man/rcsintro.1'
fi
if test -f 'rcs_func.ms' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rcs_func.ms'\"
else
  echo shar: Extracting \"'rcs_func.ms'\" \(3683 characters\)
  sed "s/^X//" >'rcs_func.ms' <<'END_OF_FILE'
X.SH
XFunctions of RCS (Revision Control System)
X.PP
XRCS manages software libraries. It greatly increases programmer productivity
Xby providing the following functions.
X.IP 1.
XRCS stores and retrieves multiple revisions of program and other text.
XThus, one can maintain one or more releases while developing the next
Xrelease, with a minimum of space overhead. Changes no longer destroy the
Xoriginal -- previous revisions remain accessible.
X.RS
X.IP a.
XMaintains each module as a tree of revisions.
X.IP b.
XProject libraries can
Xbe organized centrally, decentralized, or any way you like.
X.IP c.
XRCS works for any type of text: programs, documentation, memos, papers,
Xgraphics, VLSI layouts, form letters, etc.
X.RE
X.IP 2.
XRCS maintains a complete history of changes.
XThus, one can find out what happened to a module easily
Xand quickly, without having to compare source listings or
Xhaving to track down colleagues.
X.RS
X.IP a.
XRCS performs automatic record keeping.
X.IP b.
XRCS logs all changes automatically.
X.IP c.
XRCS guarantees project continuity.
X.RE
X.IP 3.
XRCS manages multiple lines of development.
X.IP 4.
XRCS can merge multiple lines of development.
XThus, when several parallel lines of development must be consolidated
Xinto one line, the merging of changes is automatic.
X.IP 5.
XRCS flags coding conflicts.
XIf two or more lines of development modify the same section of code,
XRCS can alert programmers about overlapping changes.
X.IP 6.
XRCS resolves access conflicts.
XWhen two or more programmers wish to modify the same revision,
XRCS alerts the programmers and makes sure that one modification won't wipe
Xout the other one.
X.IP 7.
XRCS provides high-level retrieval functions.
XRevisions can be retrieved according to ranges of revision numbers,
Xsymbolic names, dates, authors, and states.
X.IP 8.
XRCS provides release and configuration control.
XRevisions can be marked as released, stable, experimental, etc.
XConfigurations of modules can be described simply and directly.
X.IP 9.
XRCS performs automatic identification of modules with name, revision
Xnumber, creation time, author, etc.
XThus, it is always possible to determine which revisions of which
Xmodules make up a given configuration.
X.IP 10.
XProvides high-level management visibility.
XThus, it is easy to track the status of a software project.
X.RS
X.IP a.
XRCS provides a complete change history.
X.IP b.
XRCS records who did what when to which revision of which module.
X.RE
X.IP 11.
XRCS is fully compatible with existing software development tools.
XRCS is unobtrusive -- its interface to the file system is such that
Xall your existing software tools can be used as before.
X.IP 12.
XRCS' basic user interface is extremely simple. The novice need to learn
Xonly two commands. Its more sophisticated features have been
Xtuned towards advanced software development environments and the
Xexperienced software professional.
X.IP 13.
XRCS simplifies software distribution if customers
Xmaintain sources with RCS also. This technique assures proper
Xidentification of versions and configurations, and tracking of customer
Xmodifications. Customer modifications can be merged into distributed
Xversions locally or by the development group.
X.IP 14.
XRCS needs little extra space for the revisions (only the differences).
XIf intermediate revisions are deleted, the corresponding
Xdifferences are compressed into the shortest possible form.
X.IP 15.
XRCS is implemented with reverse deltas. This means that
Xthe latest revision, which is the one that is accessed most often,
Xis stored intact. All others are regenerated from the latest one
Xby applying reverse deltas (backward differences). This
Xresults in fast access time for the revision needed most often.
END_OF_FILE
  if test 3683 -ne `wc -c <'rcs_func.ms'`; then
    echo shar: \"'rcs_func.ms'\" unpacked with wrong size!
  fi
  # end of 'rcs_func.ms'
fi
if test -f 'src/maketime.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/maketime.c'\"
else
  echo shar: Extracting \"'src/maketime.c'\" \(8733 characters\)
  sed "s/^X//" >'src/maketime.c' <<'END_OF_FILE'
X#
X/*
X * MAKETIME		derive 32-bit time value from TM structure.
X *
X * Usage:
X *	int zone;	Minutes west of GMT, or
X *			48*60 for localtime
X *	time_t t;
X *	struct tm *tp;	Pointer to TM structure from <time.h>
X *	t = maketime(tp,zone);
X *
X * Returns:
X *	-1 if failure; parameter out of range or nonsensical.
X *	else time-value.
X * Notes:
X *	This code is quasi-public; it may be used freely in like software.
X *	It is not to be sold, nor used in licensed software without
X *	permission of the author.
X *	For everyone's benefit, please report bugs and improvements!
X * 	Copyright 1981 by Ken Harrenstien, SRI International.
X *	(ARPANET: KLH @ SRI)
X */
X/* $Log: maketime.c,v $
X * Revision 5.2  1990/11/01  05:03:30  eggert
X * Remove lint.
X *
X * Revision 5.1  1990/10/04  06:30:13  eggert
X * Calculate the GMT offset of 'xxx LT' as of xxx, not as of now.
X * Don't assume time_t is 32 bits.  Fix bugs near epoch and near end of time.
X *
X * Revision 5.0  1990/08/22  08:12:38  eggert
X * Switch to GMT and fix the bugs exposed thereby.
X * Permit dates past 1999/12/31.  Ansify and Posixate.
X *
X * Revision 1.8  88/11/08  13:54:53  narten
X * allow negative timezones (-24h <= x <= 24h)
X * 
X * Revision 1.7  88/08/28  14:47:52  eggert
X * Allow cc -R.  Remove unportable "#endif XXX"s.
X * 
X * Revision 1.6  87/12/18  17:05:58  narten
X * include rcsparam.h
X * 
X * Revision 1.5  87/12/18  11:35:51  narten
X * maketime.c: fixed USG code - you have tgo call "tzset" in order to have
X * "timezone" set. ("localtime" calls it, but it's probably better not to 
X * count on "localtime" having been called.)
X * 
X * Revision 1.4  87/10/18  10:26:57  narten
X * Updating version numbers. Changes relative to 1.0 are actually 
X * relative to 1.2
X * 
X * Revision 1.3  87/09/24  13:58:45  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:21:48  jenkins
X * Port to suns
X * 
X * Revision 1.2  83/12/05  10:12:56  wft
X * added cond. compilation for USG Unix; long timezone;
X * 
X * Revision 1.1  82/05/06  11:38:00  wft
X * Initial revision
X * 
X */
X
X
X#include "rcsbase.h"
X
XlibId(maketId, "$Id: maketime.c,v 5.2 1990/11/01 05:03:30 eggert Exp $")
X
Xstatic const struct tm *time2tm P((time_t));
X
X#define given(v) (0 <= (v)) /* Negative values are unspecified. */
X
Xstatic const int daytb[] = {
X	/* # days in year thus far, indexed by month (0-12!!) */
X	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
X};
X
X	static time_t
Xmaketime(atm,zone)
X	const struct tm *atm;
X	int zone;
X{
X    register const struct tm *tp;
X    register int i;
X    int year, yday, mon, day, hour, min, sec, leap, localzone;
X    int attempts;
X    time_t t, tres;
X
X    attempts = 2;
X    localzone = zone==48*60;
X    tres = -1;
X    year = mon = day = 0;  /* Keep lint happy.  */
X
X    do {
X
X	if (localzone || !given(atm->tm_year)) {
X		if (tres == -1)
X			if ((tres = time((time_t*)0))  ==  -1)
X				return -1;
X		tp = time2tm(tres);
X		/* Get breakdowns of default time, adjusting to zone. */
X		year = tp->tm_year;		/* Use to set up defaults */
X		yday = tp->tm_yday;
X		mon = tp->tm_mon;
X		day = tp->tm_mday;
X		hour = tp->tm_hour;
X		min = tp->tm_min;
X		if (localzone) {
X		    tp = localtime(&tres);
X		    zone =
X			min - tp->tm_min + 60*(
X				hour - tp->tm_hour + 24*(
X					/* If years differ, it's by one day. */
X						year - tp->tm_year
X					?	year - tp->tm_year
X					:	yday - tp->tm_yday));
X		}
X		/* Adjust the default day, month and year according to zone.  */
X		if ((min -= zone) < 0) {
X		    if (hour-(59-min)/60 < 0  &&  --day <= 0) {
X			if (--mon < 0) {
X				--year;
X				mon = 11;
X			}
X			day  =  daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3));
X		    }
X		} else
X		    if (
X		      24 <= hour+min/60  &&
X		      daytb[mon+1] - daytb[mon] + (mon==1&&!(year&3))  <  ++day
X		    ) {
X			    if (11 < ++mon) {
X				    ++year;
X				    mon = 0;
X			    }
X			    day = 1;
X		    }
X	}
X	if (zone < -24*60  ||  24*60 < zone)
X		return -1;
X
X
X#ifdef DEBUG
Xprintf("first YMD: %d %d %d\n",year,mon,day);
X#endif
X	tp = atm;
X
X	/* First must find date, using specified year, month, day.
X	 * If one of these is unspecified, it defaults either to the
X	 * current date (if no more global spec was given) or to the
X	 * zero-value for that spec (i.e. a more global spec was seen).
X	 * Reject times that do not fit in time_t,
X	 * without assuming that time_t is 32 bits or is signed.
X	 */
X	if (given(tp->tm_year))
X	  {
X		year = tp->tm_year;
X		mon = 0;		/* Since year was given, default */
X		day = 1;		/* for remaining specs is zero */
X	  }
X	if (year < 69)			/* 1969/12/31 OK in some timezones.  */
X		return -1;		/* ERR: year out of range */
X	leap   =   !(year&3)  &&  (year%100 || !((year+300)%400));
X	year -= 70;			/* UNIX time starts at 1970 */
X
X	/*
X	 * Find day of year.
X	 */
X	{
X		if (given(tp->tm_mon))
X		  {	mon = tp->tm_mon;	/* Month was specified */
X			day = 1;		/* so set remaining default */
X		  }
X		if (11 < (unsigned)mon)
X			return -1;		/* ERR: bad month */
X		if (given(tp->tm_mday)) day = tp->tm_mday;
X		if(day < 1
X		 || (((daytb[mon+1]-daytb[mon]) < day)
X			&& (day!=29 || mon!=1 || !leap) ))
X				return -1;	/* ERR: bad day */
X		yday = daytb[mon]	/* Add # of days in months so far */
X		  + ((leap		/* Leap year, and past Feb?  If */
X		      && mon>1)? 1:0)	/* so, add leap day for this year */
X		  + day-1;		/* And finally add # days this mon */
X
X	}
X	if (leap+365 <= (unsigned)yday)
X		return -1;		/* ERR: bad YDAY */
X
X	if (year < 0) {
X	    if (yday != 364)
X		return -1;		/* ERR: too early */
X	    t = -1;
X	} else {
X	    tres = year*365;		/* Get # days of years so far */
X	    if (tres/365 != year)
X		    return -1;		/* ERR: overflow */
X	    t = tres
X		+ ((year+1)>>2)		/* plus # of leap days since 1970 */
X		+ yday;			/* and finally add # days this year */
X	    if (t+4 < tres)
X		    return -1;		/* ERR: overflow */
X	}
X	tres = t;
X
X	if (given(i = tp->tm_wday)) /* Check WDAY if present */
X		if (i != (tres+4)%7)	/* 1970/01/01 was Thu = 4 */
X			return -1;	/* ERR: bad WDAY */
X
X#ifdef DEBUG
Xprintf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
X#endif
X	/*
X	 * Now determine time.  If not given, default to zeros
X	 * (since time is always the least global spec)
X	 */
X	tres *= 86400L;			/* Get # seconds (24*60*60) */
X	if (tres/86400L != t)
X		return -1;		/* ERR: overflow */
X	hour = min = sec = 0;
X	if (given(tp->tm_hour)) hour = tp->tm_hour;
X	if (given(tp->tm_min )) min  = tp->tm_min;
X	if (given(tp->tm_sec )) sec  = tp->tm_sec;
X	if (60 <= (unsigned)min  ||  60 < (unsigned)sec)
X		return -1;		/* ERR: MS out of range */
X	if (24 <= (unsigned)hour)
X		if(hour != 24 || (min+sec) !=0)	/* Allow 24:00 */
X			return -1;	/* ERR: H out of range */
X
X	t = tres;
X	tres += sec + 60L*(zone + min + 60*hour);
X
X#ifdef DEBUG
Xprintf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
X#endif
X
X	if (!localzone)			/* check for overflow */
X	    return (year<0 ? (tres<0||86400L<=tres) : tres<t)  ?  -1  :  tres;
X
X	/* Check results; LT may have had a different GMT offset back then.  */
X	tp = localtime(&tres);
X	if (given(atm->tm_sec)  &&  atm->tm_sec != tp->tm_sec)
X		return -1; /* If seconds don't match, we're in trouble.  */
X	if (!(
X	    given(atm->tm_min)  &&  atm->tm_min != tp->tm_min  ||
X	    given(atm->tm_hour)  &&  atm->tm_hour != tp->tm_hour  ||
X	    given(atm->tm_mday)  &&  atm->tm_mday != tp->tm_mday  ||
X	    given(atm->tm_mon)  &&  atm->tm_mon != tp->tm_mon  ||
X	    given(atm->tm_year)  &&  atm->tm_year != tp->tm_year
X	))
X		return tres; /* Everything matches.  */
X
X    } while (--attempts);
X
X    return -1;
X}
X
X/*
X* Convert Unix time to struct tm format.
X* Use Coordinated Universal Time (UTC) if available and if version 5 or newer;
X* use local time otherwise.
X*/
X	static const struct tm *
Xtime2tm(unixtime)
X	time_t unixtime;
X{
X	const struct tm *tm;
X	return
X			VERSION(5)<=RCSversion && (tm = gmtime(&unixtime))
X		?	tm
X		:	localtime(&unixtime);
X}
X
X/*
X* Convert Unix time to RCS format.
X* For compatibility with older versions of RCS,
X* dates before AD 2000 are stored without the leading "19".
X*/
X	void
Xtime2date(unixtime,date)
X	time_t unixtime;
X	char date[datesize];
X{
X	register const struct tm *tm = time2tm(unixtime);
X	VOID sprintf(date, DATEFORM,
X		tm->tm_year  +  (tm->tm_year<100 ? 0 : 1900),
X		tm->tm_mon+1, tm->tm_mday,
X		tm->tm_hour, tm->tm_min, tm->tm_sec
X	);
X}
X
X
X
X	void
Xstr2date(source, target)
X	const char *source;
X	char target[datesize];
X/* Parse a free-format date in SOURCE, convert it
X * into RCS internal format, and store the result into TARGET.
X */
X{
X	int zone;
X	time_t unixtime;
X	struct tm parseddate;
X
X	if (!partime(source, &parseddate, &zone))
X	    faterror("can't parse date/time: %s", source);
X	if ((unixtime = maketime(&parseddate, zone))  ==  -1)
X	    faterror("bad date/time: %s", source);
X	time2date(unixtime, target);
X}
END_OF_FILE
  if test 8733 -ne `wc -c <'src/maketime.c'`; then
    echo shar: \"'src/maketime.c'\" unpacked with wrong size!
  fi
  # end of 'src/maketime.c'
fi
if test -f 'src/rcsdiff.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/rcsdiff.c'\"
else
  echo shar: Extracting \"'src/rcsdiff.c'\" \(10976 characters\)
  sed "s/^X//" >'src/rcsdiff.c' <<'END_OF_FILE'
X/*
X *                     RCS rcsdiff operation
X */
X/*****************************************************************************
X *                       generate difference between RCS revisions
X *****************************************************************************
X */
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: rcsdiff.c,v $
X * Revision 5.7  1990/12/13  06:54:07  eggert
X * GNU diff 1.15 has -u.
X *
X * Revision 5.6  1990/11/01  05:03:39  eggert
X * Remove unneeded setid check.
X *
X * Revision 5.5  1990/10/04  06:30:19  eggert
X * Accumulate exit status across files.
X *
X * Revision 5.4  1990/09/27  01:31:43  eggert
X * Yield 1, not EXIT_FAILURE, when diffs are found.
X *
X * Revision 5.3  1990/09/11  02:41:11  eggert
X * Simplify -kkvl test.
X *
X * Revision 5.2  1990/09/04  17:07:19  eggert
X * Diff's argv was too small by 1.
X *
X * Revision 5.1  1990/08/29  07:13:55  eggert
X * Add -kkvl.
X *
X * Revision 5.0  1990/08/22  08:12:46  eggert
X * Add -k, -V.  Don't use access().  Add setuid support.
X * Remove compile-time limits; use malloc instead.
X * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options.
X * Add GNU diff's flags.  Make lock and temp files faster and safer.
X * Ansify and Posixate.
X *
X * Revision 4.6  89/05/01  15:12:27  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.5  88/08/09  19:12:41  eggert
X * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R.
X * 
X * Revision 4.4  87/12/18  11:37:46  narten
X * changes Jay Lepreau made in the 4.3 BSD version, to add support for
X * "-i", "-w", and "-t" flags and to permit flags to be bundled together,
X * merged in.
X * 
X * Revision 4.3  87/10/18  10:31:42  narten
X * Updating version numbers. Changes relative to 1.1 actually
X * relative to 4.1
X * 
X * Revision 1.3  87/09/24  13:59:21  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:15  jenkins
X * Port to suns
X * 
X * Revision 4.1  83/05/03  22:13:19  wft
X * Added default branch, option -q, exit status like diff.
X * Added fterror() to replace faterror().
X * 
X * Revision 3.6  83/01/15  17:52:40  wft
X * Expanded mainprogram to handle multiple RCS files.
X *
X * Revision 3.5  83/01/06  09:33:45  wft
X * Fixed passing of -c (context) option to diff.
X *
X * Revision 3.4  82/12/24  15:28:38  wft
X * Added call to catchsig().
X *
X * Revision 3.3  82/12/10  16:08:17  wft
X * Corrected checking of return code from diff; improved error msgs.
X *
X * Revision 3.2  82/12/04  13:20:09  wft
X * replaced getdelta() with gettree(). Changed diagnostics.
X *
X * Revision 3.1  82/11/28  19:25:04  wft
X * Initial revision.
X *
X */
X#include "rcsbase.h"
X
X#if DIFF_L
Xstatic const char *setup_label P((struct buf*,const char*,const char[datesize]));
X#endif
Xstatic void cleanup P((void));
X
Xstatic const char co[] = CO;
X
Xstatic int exitstatus;
X
XmainProg(rcsdiffId, "rcsdiff", "$Id: rcsdiff.c,v 5.7 1990/12/13 06:54:07 eggert Exp $")
X{
X    static const char cmdusage[] =
X	    "\nrcsdiff usage: rcsdiff [-q] [-rrev1 [-rrev2]] [-Vn] [diff options] file ...";
X    static const char quietarg[] = "-q";
X
X    int  revnums;                 /* counter for revision numbers given */
X    const char *rev1, *rev2;	/* revision numbers from command line */
X    const char *xrev1, *xrev2;	/* expanded revision numbers */
X    const char *expandarg, *lexpandarg, *versionarg;
X#if DIFF_L
X    static struct buf labelbuf[2];
X    int file_labels;
X    const char **diff_label1, **diff_label2;
X    char date2[datesize];
X#endif
X    const char **diffv, **diffp;	/* argv for subsidiary diff */
X    const char **pp, *p, *diffvstr;
X    struct buf commarg;
X    struct buf numericrev;	/* expanded revision number */
X    struct hshentries *gendeltas;	/* deltas to be generated */
X    struct hshentry * target;
X    int  exit_stats;
X    char *argp, *dcp;
X    register c;
X
X    initid();
X    catchints();
X
X    bufautobegin(&commarg);
X    bufautobegin(&numericrev);
X    revnums = 0;
X    rev1 = rev2 = xrev2 = nil;
X#if DIFF_L
X    file_labels = 0;
X#endif
X    expandarg = versionarg = quietarg; /* i.e. a no-op */
X
X    /* Room for args + 2 i/o [+ 2 labels] + 1 file + 1 trailing null.  */
X    diffp = diffv = tnalloc(const char*, argc + 4 + 2*DIFF_L);
X    *diffp++ = nil;
X    *diffp++ = nil;
X    *diffp++ = DIFF;
X
X    while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
X	dcp = argp = *argv + 1;
X	while (c = *argp++) switch (c) {
X	    case 'r':
X		    if (*argp!='\0') {
X			if (revnums==0) {
X				rev1= argp; revnums=1;
X			} else if (revnums==1) {
X				rev2= argp; revnums=2;
X			} else {
X				faterror("too many revision numbers");
X			}
X		    } /* do nothing for empty -r */
X		    goto option_handled;
X#if DIFF_L
X	    case 'L':
X		    if (++file_labels == 2)
X			faterror("too many -L options");
X		    /* fall into */
X#endif
X	    case 'C': case 'D': case 'F': case 'I':
X		    *dcp++ = c;
X		    if (*argp)
X			do *dcp++ = *argp;
X			while (*++argp);
X		    else {
X			if (!--argc)
X			    faterror("-%c needs following argument%s",
X				    c, cmdusage
X			    );
X			*diffp++ = *argv++;
X		    }
X		    break;
X	    case 'B': case 'H': case 'T':
X	    case '0': case '1': case '2': case '3': case '4':
X	    case '5': case '6': case '7': case '8': case '9':
X	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
X	    case 'h': case 'i': case 'n': case 'p':
X	    case 't': case 'u': case 'w':
X		    *dcp++ = c;
X		    break;
X	    case 'q':
X		    quietflag=true;
X		    break;
X	    case 'V':
X		    versionarg = *argv;
X		    setRCSversion(versionarg);
X		    goto option_handled;
X	    case 'k':
X		    expandarg = *argv;
X		    if (0 <= str2expmode(expandarg+2))
X			goto option_handled;
X		    /* fall into */
X	    default:
X		    faterror("unknown option: %s%s", *argv, cmdusage);
X	    };
X      option_handled:
X	if (dcp != *argv+1) {
X	    *dcp = 0;
X	    *diffp++ = *argv;
X	}
X    } /* end of option processing */
X
X    if (argc<1) faterror("no input file%s", cmdusage);
X
X    for (pp = diffv+3, c = 0;  pp<diffp;  )
X	    c += strlen(*pp++) + 1;
X    diffvstr = argp = tnalloc(char, c + 1);
X    for (pp = diffv+3;  pp<diffp;  ) {
X	    p = *pp++;
X	    *argp++ = ' ';
X	    while ((*argp = *p++))
X		    argp++;
X    }
X    *argp = 0;
X
X#if DIFF_L
X    diff_label1 = diff_label2 = nil;
X    if (file_labels < 2) {
X	    if (!file_labels)
X		    diff_label1 = diffp++;
X	    diff_label2 = diffp++;
X    }
X#endif
X    diffp[2] = nil;
X
X    /* now handle all filenames */
X    do {
X	    finptr=NULL;
X	    ffree();
X
X	    if (pairfilenames(argc, argv, rcsreadopen, true, false) != 1)
X		    continue;
X	    diagnose("===================================================================\nRCS file: %s\n",RCSfilename);
X	    if (!rev2) {
X		/* Make sure work file is readable, and get its status.  */
X		if ((c = open(workfilename,O_RDONLY,0)) < 0) {
X		    eerror(workfilename);
X		    continue;
X		}
X		if (!getfworkstat(c)) continue;
X		VOID close(c);
X	    }
X
X
X	    gettree(); /* reads in the delta tree */
X
X	    if (Head==nil) {
X		    error("no revisions present");
X		    continue;
X	    }
X	    if (revnums==0)
X		    rev1  =  Dbranch ? Dbranch : Head->num;
X
X	    if (!expandsym(rev1,&numericrev)) continue;
X	    if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
X	    xrev1=target->num;
X#if DIFF_L
X	    if (diff_label1)
X		*diff_label1 = setup_label(&labelbuf[0], target->num, target->date);
X#endif
X
X	    lexpandarg = expandarg;
X	    if (revnums==2) {
X		    if (!expandsym(rev2, &numericrev)) continue;
X		    if (!(target=genrevs(numericrev.string,(char *)nil,(char *)nil,(char *)nil,&gendeltas))) continue;
X		    xrev2=target->num;
X	    } else if (
X			target->lockedby
X		&&	lexpandarg == quietarg
X		&&	Expand == KEYVAL_EXPAND
X		&&	WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
X	    )
X		    lexpandarg = "-kkvl";
X#if DIFF_L
X	    if (diff_label2)
X		if (revnums == 2)
X		    *diff_label2 = setup_label(&labelbuf[1], target->num, target->date);
X		else {
X		    time2date(workstat.st_mtime, date2);
X		    *diff_label2 = setup_label(&labelbuf[1], workfilename, date2);
X		}
X#endif
X
X	    diffp[0] = maketemp(0);
X	    diagnose("retrieving revision %s\n", xrev1);
X	    bufscpy(&commarg, "-p");
X	    bufscat(&commarg, xrev1);
X	    if (run((char*)nil,diffp[0], co,quietarg,commarg.string,lexpandarg,versionarg,RCSfilename,(char*)nil)){
X		    error("co failed");
X		    continue;
X	    }
X	    if (!rev2) {
X		    diffp[1] = workfilename;
X		    if (workfilename[0] == '+') {
X			    /* Some diffs have options with leading '+'. */
X			    diffp[1] = argp =
X				    ftnalloc(char, strlen(workfilename)+3);
X			    *argp++ = '.';
X			    *argp++ = SLASH;
X			    VOID strcpy(argp, workfilename);
X		    }
X	    } else {
X		    diffp[1] = maketemp(1);
X		    diagnose("retrieving revision %s\n",xrev2);
X		    bufscpy(&commarg, "-p");
X		    bufscat(&commarg, xrev2);
X		    if (run((char*)nil,diffp[1], co,quietarg,commarg.string,expandarg,versionarg,RCSfilename,(char *)nil)){
X			    error("co failed");
X			    continue;
X		    }
X	    }
X	    if (!rev2)
X		    diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workfilename);
X	    else
X		    diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2);
X
X	    exit_stats = runv(diffv);
X
X	    if (exit_stats)
X		    if (WIFEXITED(exit_stats) && WEXITSTATUS(exit_stats)==1) {
X			    if (!exitstatus)
X				    exitstatus = 1;
X		    } else
X			    error("diff failed");
X    } while (cleanup(),
X	     ++argv, --argc >=1);
X
X
X    tempunlink();
X    exitmain(exitstatus);
X}
X
X    static void
Xcleanup()
X{
X    if (nerror) exitstatus = EXIT_TROUBLE;
X    if (finptr) ffclose(finptr);
X}
X
X#if lint
X#	define exiterr rdiffExit
X#endif
X    exiting void
Xexiterr()
X{
X    tempunlink();
X    _exit(EXIT_TROUBLE);
X}
X
X#if DIFF_L
X	static const char *
Xsetup_label(b, name, date)
X	struct buf *b;
X	const char *name;
X	const char date[datesize];
X{
X	const char *p;
X
X	bufalloc(b,  2+strlen(name)+1+datesize);
X	for (p = date;  *p++ != '.';  )
X		;
X	VOID sprintf(b->string, "-L%s\t%s%.*s/%.2s/%.2s %.2s:%.2s:%s",
X		name,
X		date[2]=='.' ? "19" : "",
X		p-date-1, date, p, p+3, p+6, p+9, p+12
X	);
X	return b->string;
X}
X#endif
END_OF_FILE
  if test 10976 -ne `wc -c <'src/rcsdiff.c'`; then
    echo shar: \"'src/rcsdiff.c'\" unpacked with wrong size!
  fi
  # end of 'src/rcsdiff.c'
fi
if test -f 'src/rcskeep.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/rcskeep.c'\"
else
  echo shar: Extracting \"'src/rcskeep.c'\" \(9239 characters\)
  sed "s/^X//" >'src/rcskeep.c' <<'END_OF_FILE'
X/*
X *                     RCS keyword extraction
X */
X/*****************************************************************************
X *                       main routine: getoldkeys()
X *                       Testprogram: define KEEPTEST
X *****************************************************************************
X */
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/* $Log: rcskeep.c,v $
X * Revision 5.2  1990/10/04  06:30:20  eggert
X * Parse time zone offsets; future RCS versions may output them.
X *
X * Revision 5.1  1990/09/20  02:38:56  eggert
X * ci -k now checks dates more thoroughly.
X *
X * Revision 5.0  1990/08/22  08:12:53  eggert
X * Retrieve old log message if there is one.
X * Don't require final newline.
X * Remove compile-time limits; use malloc instead.  Tune.
X * Permit dates past 1999/12/31.  Ansify and Posixate.
X *
X * Revision 4.6  89/05/01  15:12:56  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.5  88/08/09  19:13:03  eggert
X * Remove lint and speed up by making FILE *fp local, not global.
X * 
X * Revision 4.4  87/12/18  11:44:21  narten
X * more lint cleanups (Guy Harris)
X * 
X * Revision 4.3  87/10/18  10:35:50  narten
X * Updating version numbers. Changes relative to 1.1 actually relative
X * to 4.1
X * 
X * Revision 1.3  87/09/24  14:00:00  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:29  jenkins
X * Port to suns
X * 
X * Revision 4.1  83/05/10  16:26:44  wft
X * Added new markers Id and RCSfile; extraction added.
X * Marker matching with trymatch().
X * 
X * Revision 3.2  82/12/24  12:08:26  wft
X * added missing #endif.
X *
X * Revision 3.1  82/12/04  13:22:41  wft
X * Initial revision.
X *
X */
X
X/*
X#define KEEPTEST
X*/
X/* Testprogram; prints out the keyword values found. */
X
X#include  "rcsbase.h"
X
XlibId(keepId, "$Id: rcskeep.c,v 5.2 1990/10/04 06:30:20 eggert Exp $")
X
Xstatic int checknum P((const char*,int));
Xstatic int getprevdate P((FILE*));
Xstatic int getprevid P((int,FILE*,struct buf*));
Xstatic int getprevrev P((FILE*));
Xstatic int getval P((FILE*,struct buf*,int));
Xstatic int get0val P((int,FILE*,struct buf*,int));
X
Xstruct buf prevauthor, prevrev, prevstate;
Xchar prevdate[datesize];
X
X	int
Xgetoldkeys(fp)
X	register FILE *fp;
X/* Function: Tries to read keyword values for author, date,
X * revision number, and state out of the file fp.
X * The results are placed into
X * prevauthor, prevdate, prevrev, prevstate.
X * Aborts immediately if it finds an error and returns false.
X * If it returns true, it doesn't mean that any of the
X * values were found; instead, check to see whether the corresponding arrays
X * contain the empty string.
X */
X{
X    register int c;
X    char keyword[keylength+1];
X    register char * tp;
X
X    /* initialize to empty */
X    bufscpy(&prevauthor, "");
X    bufscpy(&prevrev, "");
X    bufscpy(&prevstate, "");
X    *prevdate = 0;
X
X    while( (c=getc(fp)) != EOF) {
X        if ( c==KDELIM) {
X	    do {
X		/* try to get keyword */
X		tp = keyword;
X		while ((c=getc(fp))!=EOF && c!='\n' && c!=KDELIM && c!=VDELIM 
X		       && tp<keyword+keylength
X		)
X		    *tp++ = c;
X	    } while (c==KDELIM);
X	    if (c==EOF)
X		break;
X            if (c!=VDELIM) continue;
X	    *tp = c;
X	    if ((c=getc(fp))!=' ' && c!='\t')
X		continue;
X
X	    switch (trymatch(keyword)) {
X            case Author:
X		if (!getprevid(0, fp, &prevauthor))
X		    return false;
X		c = getc(fp);
X                break;
X            case Date:
X		if (!(c = getprevdate(fp)))
X		    return false;
X                break;
X            case Header:
X            case Id:
X		if (!(
X		      getval(fp, (struct buf*)nil, false) &&
X		      getprevrev(fp) &&
X		      (c = getprevdate(fp)) &&
X		      getprevid(c, fp, &prevauthor) &&
X		      getprevid(0, fp, &prevstate)
X		))
X		    return false;
X		/* Skip either ``who'' (new form) or ``Locker: who'' (old).  */
X		if (getval(fp, (struct buf*)nil, true) &&
X		    getval(fp, (struct buf*)nil, true))
X			c = getc(fp);
X		else if (nerror)
X			return false;
X		else
X			c = KDELIM;
X		break;
X            case Locker:
X            case Log:
X            case RCSfile:
X            case Source:
X		if (!getval(fp, (struct buf*)nil, false))
X		    return false;
X		c = getc(fp);
X                break;
X            case Revision:
X		if (!getprevrev(fp))
X		    return false;
X		c = getc(fp);
X                break;
X            case State:
X		if (!getprevid(0, fp, &prevstate))
X		    return false;
X		c = getc(fp);
X                break;
X            default:
X               continue;
X            }
X	    if (c != KDELIM) {
X		error("closing %c missing on keyword", KDELIM);
X		return false;
X	    }
X	    if (*prevauthor.string && *prevdate && *prevrev.string && *prevstate.string) {
X                break;
X           }
X        }
X    }
X
X    arewind(fp);
X    return true;
X}
X
X
X	static int
Xgetval(fp, target, optional)
X	register FILE *fp;
X	struct buf *target;
X	int optional;
X/* Reads a keyword value from FP into TARGET.
X * Returns true if one is found, false otherwise.
X * Does not modify target if it is nil.
X * Do not report an error if OPTIONAL is set and KDELIM is found instead.
X */
X{
X	return get0val(getc(fp), fp, target, optional);
X}
X
X	static int
Xget0val(c, fp, target, optional)
X	register int c;
X	register FILE *fp;
X	struct buf *target;
X	int optional;
X/* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly.
X * Same as getval, except C is the lookahead character.
X */
X{   register char * tp;
X    const char *tlim;
X    register int got1;
X
X    if (target) {
X	bufalloc(target, 1);
X	tp = target->string;
X	tlim = tp + target->size;
X    } else
X	tlim = tp = 0;
X    got1 = false;
X    for (;;  c = getc(fp))
X	switch (c) {
X	    default:
X		got1 = true;
X		if (tp) {
X		    *tp++ = c;
X		    if (tlim <= tp)
X			tp = bufenlarge(target, &tlim);
X		}
X		continue;
X
X	    case ' ':
X	    case '\t':
X		if (tp) {
X		    *tp = 0;
X#		    ifdef KEEPTEST
X			VOID printf("getval: %s\n", target);
X#		    endif
X		}
X		if (!got1)
X		    error("too much white space in keyword value");
X		return got1;
X
X	    case KDELIM:
X		if (!got1 && optional)
X		    return false;
X		/* fall into */
X	    case '\n':
X	    case 0:
X	    case EOF:
X		error("badly terminated keyword value");
X		return false;
X	}
X}
X
X
X	static int
Xgetprevdate(fp)
XFILE *fp;
X/* Function: reads a date prevdate; checks format
X * Return 0 on error, lookahead character otherwise.
X */
X{
X    struct buf prevday, prevtime, prevzone, prev;
X    register const char *p;
X    register int c;
X
X    c = 0;
X    bufautobegin(&prevday);
X    if (getval(fp,&prevday,false)) {
X	bufautobegin(&prevtime);
X	if (getval(fp,&prevtime,false)) {
X	    bufautobegin(&prevzone);
X	    bufscpy(&prevzone, "");
X	    c = getc(fp);
X	    if (c=='-' || c=='+')
X		c = get0val(c,fp,&prevzone,false) ? getc(fp) : 0;
X	    if (c) {
X		bufautobegin(&prev);
X		p = prevday.string;
X		bufalloc(&prev, strlen(p) + strlen(prevtime.string) + strlen(prevzone.string) + 5);
X		VOID sprintf(prev.string, "%s%s %s %s", 
X		    /* Parse dates put out by old versions of RCS.  */
X		    isdigit(p[0]) && isdigit(p[1]) && p[2]=='/'  ?  "19"  :  "",
X		    p, prevtime.string, prevzone.string
X		);
X		str2date(prev.string, prevdate);
X		bufautoend(&prev);
X	    }
X	    bufautoend(&prevzone);
X	}
X	bufautoend(&prevtime);
X    }
X    bufautoend(&prevday);
X    return c;
X}
X
X	static int
Xgetprevid(c, fp, b)
X	int c;
X	FILE *fp;
X	struct buf *b;
X/* Get previous identifier from C+FP into B.  */
X{
X	if (!get0val(c?c:getc(fp), fp, b, false))
X	    return false;
X	checksid(b->string);
X	return true;
X}
X
X	static int
Xgetprevrev(fp)
X	FILE *fp;
X/* Get previous revision from FP into prevrev.  */
X{
X	return getval(fp,&prevrev,false) && checknum(prevrev.string,-1);
X}
X
X
X	static int
Xchecknum(sp,fields)
X	register const char *sp;
X	int fields;
X{    register int dotcount;
X     dotcount=0;
X     while(*sp) {
X        if (*sp=='.') dotcount++;
X	else if (!isdigit(*sp)) return false;
X        sp++;
X     }
X     return fields<0 ? dotcount&1 : dotcount==fields;
X}
X
X
X
X#ifdef KEEPTEST
X
Xconst char cmdid[] ="keeptest";
X
X	int
Xmain(argc, argv)
Xint  argc; char  *argv[];
X{
X        while (*(++argv)) {
X		FILE *f;
X		if (!(f = fopen(*argv,"r"))) {
X			perror(f);
X			exit(1);
X		}
X		getoldkeys(f);
X		VOID fclose(f);
X                VOID printf("%s:  revision: %s, date: %s, author: %s, state: %s\n",
X			    *argv, prevrev.string, prevdate.string, prevauthor.string, prevstate.string);
X	}
X	exitmain(EXIT_SUCCESS);
X}
X#endif
END_OF_FILE
  if test 9239 -ne `wc -c <'src/rcskeep.c'`; then
    echo shar: \"'src/rcskeep.c'\" unpacked with wrong size!
  fi
  # end of 'src/rcskeep.c'
fi
if test -f 'src/rcsmerge.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/rcsmerge.c'\"
else
  echo shar: Extracting \"'src/rcsmerge.c'\" \(7291 characters\)
  sed "s/^X//" >'src/rcsmerge.c' <<'END_OF_FILE'
X/*
X *                       rcsmerge operation
X */
X/*****************************************************************************
X *                       join 2 revisions with respect to a third
X *****************************************************************************
X */
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/* $Log: rcsmerge.c,v $
X * Revision 5.3  1990/11/01  05:03:50  eggert
X * Remove unneeded setid check.
X *
X * Revision 5.2  1990/09/04  08:02:28  eggert
X * Check for I/O error when reading working file.
X *
X * Revision 5.1  1990/08/29  07:14:04  eggert
X * Add -q.  Pass -L options to merge.
X *
X * Revision 5.0  1990/08/22  08:13:41  eggert
X * Propagate merge's exit status.
X * Remove compile-time limits; use malloc instead.
X * Make lock and temp files faster and safer.  Ansify and Posixate.  Add -V.
X * Don't use access().  Tune.
X *
X * Revision 4.5  89/05/01  15:13:16  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.4  88/08/09  19:13:13  eggert
X * Beware merging into a readonly file.
X * Beware merging a revision to itself (no change).
X * Use execv(), not system(); yield exit status like diff(1)'s.
X * 
X * Revision 4.3  87/10/18  10:38:02  narten
X * Updating version numbers. Changes relative to version 1.1 
X * actually relative to 4.1
X * 
X * Revision 1.3  87/09/24  14:00:31  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:36  jenkins
X * Port to suns
X * 
X * Revision 4.1  83/03/28  11:14:57  wft
X * Added handling of default branch.
X * 
X * Revision 3.3  82/12/24  15:29:00  wft
X * Added call to catchsig().
X *
X * Revision 3.2  82/12/10  21:32:02  wft
X * Replaced getdelta() with gettree(); improved error messages.
X *
X * Revision 3.1  82/11/28  19:27:44  wft
X * Initial revision.
X *
X */
X#include "rcsbase.h"
X
Xstatic exiting void nowork P((void));
X
Xstatic const char co[] = CO;
X
XmainProg(rcsmergeId, "rcsmerge", "$Id: rcsmerge.c,v 5.3 1990/11/01 05:03:50 eggert Exp $")
X{
X	static const char cmdusage[] =
X		"\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] [-p] [-Vn] file";
X	static const char quietarg[] = "-q";
X
X	const char *rev1, *rev2; /*revision numbers*/
X	const char *temp1file, *temp2file;
X	const char *expandarg, *versionarg;
X	const char *mergearg[13], **a;
X        int tostdout;
X	int status, workfd;
X	struct buf commarg;
X	struct buf numericrev; /* holds expanded revision number */
X	struct hshentries *gendeltas; /* deltas to be generated */
X        struct hshentry * target;
X
X	initid();
X        catchints();
X
X	bufautobegin(&commarg);
X	bufautobegin(&numericrev);
X	rev1 = rev2 = nil;
X	status = 0; /* Keep lint happy.  */
X	tostdout = false;
X	expandarg = versionarg = quietarg; /* i.e. a no-op */
X
X        while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
X                switch ((*argv)[1]) {
X                case 'p':
X                        tostdout=true;
X			goto revno;
X		case 'q':
X			quietflag = true;
X                        /* falls into -r */
X                case 'r':
X		revno:
X                        if ((*argv)[2]!='\0') {
X			    if (!rev1)
X				    rev1 = *argv + 2;
X			    else if (!rev2)
X				    rev2 = *argv + 2;
X			    else
X                                    faterror("too many revision numbers");
X                        } /* do nothing for empty -r or -p */
X                        break;
X		case 'V':
X			versionarg = *argv;
X			setRCSversion(versionarg);
X			break;
X
X		case 'k':
X			expandarg = *argv;
X			if (0 <= str2expmode(expandarg+2))
X			    break;
X			/* fall into */
X                default:
X			faterror("unknown option: %s%s", *argv, cmdusage);
X                };
X        } /* end of option processing */
X
X	if (argc<1) faterror("no input file%s", cmdusage);
X	if (!rev1) faterror("no base revision number given");
X
X        /* now handle all filenames */
X
X	if (pairfilenames(argc, argv, rcsreadopen, true, false) == 1) {
X
X                if (argc>2 || (argc==2&&argv[1]!=nil))
X                        warn("too many arguments");
X		diagnose("RCS file: %s\n", RCSfilename);
X		if ((workfd = open(workfilename, tostdout?O_RDONLY:O_RDWR)) < 0)
X			nowork();
X
X                gettree();  /* reads in the delta tree */
X
X                if (Head==nil) faterror("no revisions present");
X
X
X		if (!expandsym(rev1,&numericrev)) goto end;
X		if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
X                rev1=target->num;
X		if (!rev2)
X			rev2  =  Dbranch ? Dbranch : Head->num;
X		if (!expandsym(rev2,&numericrev)) goto end;
X		if (!(target=genrevs(numericrev.string, (char *)nil, (char *)nil, (char *)nil,&gendeltas))) goto end;
X                rev2=target->num;
X
X		if (strcmp(rev1,rev2) == 0) {
X			error("merging revision %s to itself (no change)",
X				rev1
X			);
X			if (tostdout) {
X				FILE *w;
X				errno = 0;
X				if (!(w = fdopen(workfd,"r")))
X					nowork();
X				fastcopy(w,stdout);
X				ffclose(w);
X			}
X			goto end;
X		}
X		if (close(workfd) < 0)
X			nowork();
X
X		temp1file = maketemp(0);
X		temp2file = maketemp(1);
X
X		diagnose("retrieving revision %s\n", rev1);
X		bufscpy(&commarg, "-p");
X		bufscat(&commarg, rev1);
X		if (run((char*)nil,temp1file, co,quietarg,commarg.string,expandarg,versionarg,RCSfilename,(char*)nil)){
X                        faterror("co failed");
X                }
X		diagnose("retrieving revision %s\n",rev2);
X		bufscpy(&commarg, "-p");
X		bufscat(&commarg, rev2);
X		if (run((char*)nil,temp2file, co,quietarg,commarg.string,expandarg,versionarg,RCSfilename,(char*)nil)){
X                        faterror("co failed");
X                }
X		diagnose("Merging differences between %s and %s into %s%s\n",
X                         rev1, rev2, workfilename,
X                         tostdout?"; result to stdout":"");
X
X		a = mergearg;
X		*a++ = nil;
X		*a++ = nil;
X		*a++ = MERGE;
X		if (tostdout)
X		    *a++ = "-p";
X		if (quietflag)
X		    *a++ = quietarg;
X		*a++ = "-L";  *a++ = workfilename;
X		*a++ = "-L";  *a++ = rev2;
X		*a++ = workfilename;
X		*a++ = temp1file;
X		*a++ = temp2file;
X		*a = nil;
X
X		status = runv(mergearg);
X		if (!WIFEXITED(status)  ||  1 < WEXITSTATUS(status)) {
X                        faterror("merge failed");
X                }
X        }
X
Xend:
X	tempunlink();
X	exitmain(nerror ? EXIT_TROUBLE : WEXITSTATUS(status));
X}
X
X#if lint
X#	define exiterr rmergeExit
X#endif
X	exiting void
Xexiterr()
X{
X	tempunlink();
X	_exit(EXIT_TROUBLE);
X}
X
X
X	static exiting void
Xnowork()
X{
X	efaterror(workfilename);
X}
END_OF_FILE
  if test 7291 -ne `wc -c <'src/rcsmerge.c'`; then
    echo shar: \"'src/rcsmerge.c'\" unpacked with wrong size!
  fi
  # end of 'src/rcsmerge.c'
fi
echo shar: End of archive 10 \(of 12\).
cp /dev/null ark10isdone
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...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.