rsalz@bbn.com (Rich Salz) (02/23/91)
Submitted-by: Adam Hammer <hammer@cs.purdue.edu> Posting-number: Volume 24, Issue 9 Archive-name: rcs/part09 #! /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/ci.1 man/co.1 src/conf.sh src/rcsgen.c # Wrapped by rsalz@litchi.bbn.com on Thu Feb 21 14:37:07 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 9 (of 12)."' if test -f 'man/ci.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'man/ci.1'\" else echo shar: Extracting \"'man/ci.1'\" \(10006 characters\) sed "s/^X//" >'man/ci.1' <<'END_OF_FILE' X.de Id X.ds Rv \\$3 X.ds Dt \\$4 X.. X.Id $Id: ci.1,v 5.4 1990/12/04 05:18:31 eggert Exp $ X.ds r \s-1RCS\s0 X.if n .ds - \%-- X.if t .ds - \(em X.TH CI 1 \*(Dt GNU X.SH NAME Xci \- check in RCS revisions X.SH SYNOPSIS X.B ci X.RI [ options ] " file " .\|.\|. X.SH DESCRIPTION X.B ci Xstores new revisions into \*r files. XEach file name ending in X.B ,v Xis taken to be an \*r file. XAll others Xare assumed to be working files containing new revisions. X.B ci Xdeposits the contents of each working file Xinto the corresponding \*r file. XIf only a working file is given, X.B ci Xtries to find the corresponding \*r file in an \*r subdirectory Xand then in the working file's directory. XFor more details, see X.SM "FILE NAMING" Xbelow. X.PP XFor X.B ci Xto work, the caller's login must be on the access list, Xexcept if the access list is empty or the caller is the superuser or the Xowner of the file. XTo append a new revision to an existing branch, the tip revision on Xthat branch must be locked by the caller. Otherwise, only a Xnew branch can be created. This restriction is not enforced Xfor the owner of the file if non-strict locking is used X(see X.BR rcs (1)). XA lock held by someone else may be broken with the X.B rcs Xcommand. X.PP XNormally, X.B ci Xchecks whether the revision to be deposited is different Xfrom the preceding one. If it is not different, X.B ci Xaborts the deposit, asking beforehand if possible. XA deposit can be forced with the X.B \-f Xoption. X.PP XFor each revision deposited, X.B ci Xprompts for a log message. XThe log message should summarize the change and must be terminated by Xend-of-file or by a line containing X.BR \&. "\ by" Xitself. XIf several files are checked in X.B ci Xasks whether to reuse the Xprevious log message. XIf the standard input is not a terminal, X.B ci Xsuppresses the prompt Xand uses the same log message for all files. XSee also X.BR \-m . X.PP XThe number of the deposited revision can be given by any of the options X.BR \-f , X.BR \-I , X.BR \-k , X.BR \-l , X.BR \-q , X.BR \-r , Xor X.BR \-u . X.PP XIf the \*r file does not exist, X.B ci Xcreates it and Xdeposits the contents of the working file as the initial revision X(default number: X.BR 1.1 ). XThe access list is initialized to empty. XInstead of the log message, X.B ci Xrequests descriptive text (see X.B \-t Xbelow). X.SH OPTIONS X.TP X.BR \-r [\f2rev\fP] Xassigns the revision number X.I rev Xto the checked-in revision, releases the corresponding lock, and Xdeletes the working file. This is the default. X.I rev Xmay be symbolic, numeric, or mixed. X.RS X.PP XIf X.I rev Xis a revision number, it must be higher than the latest Xone on the branch to which X.I rev Xbelongs, or must start a new branch. X.PP XIf X.I rev Xis a branch rather than a revision number, Xthe new revision is appended to that branch. The level number is obtained Xby incrementing the tip revision number of that branch. XIf X.I rev Xindicates a non-existing branch, Xthat branch is created with the initial revision numbered X.IB rev .1\f1.\fP X.br X.ne 8 X.PP XIf X.I rev Xis omitted, X.B ci Xtries to derive the new revision number from Xthe caller's last lock. If the caller has locked the tip revision of a branch, Xthe new revision is appended to that branch. XThe new revision number is obtained Xby incrementing the tip revision number. XIf the caller locked a non-tip revision, a new branch is started at Xthat revision by incrementing the highest branch number at that revision. XThe default initial branch and level numbers are X.BR 1 . X.PP XIf X.I rev Xis omitted and the caller has no lock, but owns Xthe file and locking Xis not set to X.IR strict , Xthen the revision is appended to the Xdefault branch (normally the trunk; see the X.B \-b Xoption of X.BR rcs (1)). X.PP XException: On the trunk, revisions can be appended to the end, but Xnot inserted. X.RE X.TP X.BR \-f [\f2rev\fP] Xforces a deposit; the new revision is deposited even it is not different Xfrom the preceding one. X.TP X.BR \-k [\f2rev\fP] Xsearches the working file for keyword values to determine its revision number, Xcreation date, state, and author (see X.BR co (1)), Xand assigns these Xvalues to the deposited revision, rather than computing them locally. XIt also generates a default login message noting the login of the caller Xand the actual checkin date. XThis option is useful for software distribution. A revision that is sent to Xseveral sites should be checked in with the X.B \-k Xoption at these sites to Xpreserve the original number, date, author, and state. XThe extracted keyword values and the default log message may be overridden Xwith the options X.BR \-d , X.BR \-m , X.BR \-s , X.BR \-w , Xand any option that carries a revision number. X.TP X.BR \-l [\f2rev\fP] Xworks like X.BR \-r , Xexcept it performs an additional X.B "co\ \-l" Xfor the Xdeposited revision. Thus, the deposited revision is immediately Xchecked out again and locked. XThis is useful for saving a revision although one wants to continue Xediting it after the checkin. X.TP X.BR \-u [\f2rev\fP] Xworks like X.BR \-l , Xexcept that the deposited revision is not locked. XThis lets one read the working file Ximmediately after checkin. X.TP X.BR \-q [\f2rev\fP] Xquiet mode; diagnostic output is not printed. XA revision that is not different from the preceding one is not deposited, Xunless X.B \-f Xis given. X.TP X.BR \-I [\f2rev\fP] Xinteractive mode; Xthe user is prompted and questioned Xeven if the standard input is not a terminal. X.TP X.BR \-d "[\f2date\fP]" Xuses X.I date Xfor the checkin date and time. XThe X.I date Xis specified in free format as explained in X.BR co (1). XThis is useful for lying about the checkin date, and for X.B \-k Xif no date is available. XIf X.I date Xis empty, the working file's time of last modification is used. X.TP X.BI \-m "msg" Xuses the string X.I msg Xas the log message for all revisions checked in. X.TP X.BI \-n "name" Xassigns the symbolic name X.I name Xto the number of the checked-in revision. X.B ci Xprints an error message if X.I name Xis already assigned to another Xnumber. X.TP X.BI \-N "name" Xsame as X.BR \-n , Xexcept that it overrides a previous assignment of X.IR name . X.TP X.BI \-s "state" Xsets the state of the checked-in revision to the identifier X.IR state . XThe default state is X.BR Exp . X.TP X.BI \-t file Xwrites descriptive text from the contents of the named X.I file Xinto the \*r file, Xdeleting the existing text. XThe X.I file Xname may not begin with X.BR \- . X.TP X.BI \-t\- string XWrite descriptive text from the X.I string Xinto the \*r file, deleting the existing text. X.RS X.PP XThe X.B \-t Xoption, in both its forms, has effect only during an initial checkin; Xit is silently ignored otherwise. X.PP XDuring the initial checkin, if X.B \-t Xis not given, X.B ci Xobtains the text from standard input, Xterminated by end-of-file or by a line containing X.BR \&. "\ by" Xitself. XThe user is prompted for the text if interaction is possible; see X.BR \-I . X.PP XFor backward compatibility with older versions of \*r, a bare X.B \-t Xoption is ignored. X.RE X.TP X.BI \-w "login" Xuses X.I login Xfor the author field of the deposited revision. XUseful for lying about the author, and for X.B \-k Xif no author is available. X.TP X.BI \-V n XEmulate \*r version X.IR n . XSee X.BR co (1) Xfor details. X.SH "FILE NAMING" XPairs of \*r files and working files may be specified in three ways X(see also the Xexample section of X.BR co (1)). X.PP X1) Both the \*r file and the working file are given. The \*r file name is of Xthe form X.IB path1 / workfile ,v Xand the working file name is of the form X.IB path2 / workfile Xwhere X.IB path1 / Xand X.IB path2 / Xare (possibly different or empty) paths and X.I workfile Xis a file name. X.PP X2) Only the \*r file is given. Then the working file is created in the current Xdirectory and its name is derived from the name of the \*r file Xby removing X.IB path1 / Xand the suffix X.BR ,v . X.PP X3) Only the working file is given. XThen X.B ci Xlooks for an \*r file of the form X.IB path2 /RCS/ workfile ,v Xor X.IB path2 / workfile ,v X(in this order). X.PP XIf the \*r file is specified without a path in 1) and 2), then X.B ci Xlooks for the \*r file first in the directory X.B ./RCS Xand then in the current Xdirectory. X.SH "FILE MODES" XAn \*r file created by X.B ci Xinherits the read and execute permissions Xfrom the working file. If the \*r file exists already, X.B ci Xpreserves its read and execute permissions. X.B ci Xalways turns off all write permissions of \*r files. X.SH FILES XSeveral temporary files may be created. XA semaphore file is created in the directory containing the \*r file. XThe effective user+group must be able to read the \*r file Xand to search and write the directory containing the \*r file. XNormally, the real user+group must be able to read the working file Xand to search and write the directory containing the working file; Xhowever, some older hosts that do not conform to Posix 1003.1-1990 Xcannot easily switch between real and effective ids, Xso on these hosts the effective user+group is used for all accesses. XThe effective user+group is the same as the real user+group Xunless your copy of \*r has setuid or setgid privileges. XThese privileges yield extra security if \*r files are protected so that Xonly the effective user+group can write \*r directories. XFurther protection can be achieved by granting access Xonly to the effective user+group. X.PP X.B ci Xnever changes an \*r or working file; Xinstead, it unlinks the file and creates a new one. XThis strategy breaks hard links to such files, Xbut does not affect symbolic links. X.SH DIAGNOSTICS XFor each revision, X.B ci Xprints the \*r file, the working file, and the number Xof both the deposited and the preceding revision. XThe exit status is zero if and only if all operations were successful. 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" Xco(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), Xrcsfile(5) 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 10006 -ne `wc -c <'man/ci.1'`; then echo shar: \"'man/ci.1'\" unpacked with wrong size! fi # end of 'man/ci.1' fi if test -f 'man/co.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'man/co.1'\" else echo shar: Extracting \"'man/co.1'\" \(14638 characters\) sed "s/^X//" >'man/co.1' <<'END_OF_FILE' X.de Id X.ds Rv \\$3 X.ds Dt \\$4 X.. X.Id $Id: co.1,v 5.4 1990/12/04 05:18:32 eggert Exp $ X.ds g \s-1GMT\s0 X.ds r \s-1RCS\s0 X.if n .ds - \%-- X.if t .ds - \(em X.TH CO 1 \*(Dt GNU X.SH NAME Xco \- check out RCS revisions X.SH SYNOPSIS X.B co X.RI [ options ] " file " .\|.\|. X.SH DESCRIPTION X.B co Xretrieves a revision from each \*r file and stores it into Xthe corresponding working file. XEach file name ending in X.B ,v Xis taken to be an \*r file; Xall other files are assumed to be working files. XIf only a working file is given, X.B co Xtries to find the corresponding \*r file in the directory X.B ./RCS Xand then in the current directory. XFor more details, see X.SM "FILE NAMING" Xbelow. X.PP XRevisions of an \*r file may be checked out locked or unlocked. Locking a Xrevision prevents overlapping updates. A revision checked out for reading or Xprocessing (e.g., compiling) need not be locked. A revision checked out Xfor editing and later checkin must normally be locked. Checkout with locking Xfails if the revision to be checked out is currently locked by another user. X(A lock may be broken with X.BR rcs "(1).)\ \&" XCheckout with locking also requires the caller to be on the access list of Xthe \*r file, unless he is the owner of the Xfile or the superuser, or the access list is empty. XCheckout without locking is not subject to accesslist restrictions, and is Xnot affected by the presence of locks. X.PP XA revision is selected by options for revision or branch number, Xcheckin date/time, author, or state. XWhen the selection options Xare applied in combination, X.B co Xretrieves the latest revision Xthat satisfies all of them. XIf none of the selection options Xis specified, X.B co Xretrieves the latest revision Xon the default branch (normally the trunk, see the X.B \-b Xoption of X.BR rcs (1)). XA revision or branch number may be attached Xto any of the options X.BR \-f , X.BR \-I , X.BR \-l , X.BR \-p , X.BR \-q , X.BR \-r , Xor X.BR \-u . XThe options X.B \-d X(date), X.B \-s X(state), and X.B \-w X(author) Xretrieve from a single branch, the X.I selected Xbranch, Xwhich is either specified by one of X.BR \-f, X\&.\|.\|., X.BR \-u , Xor the default branch. X.PP XA X.B co Xcommand applied to an \*r Xfile with no revisions creates a zero-length working file. X.B co Xalways performs keyword substitution (see below). X.SH OPTIONS X.TP X.BR \-r [\f2rev\fP] Xretrieves the latest revision whose number is less than or equal to X.I rev. XIf X.I rev Xindicates a branch rather than a revision, Xthe latest revision on that branch is retrieved. XIf X.I rev Xis omitted, the latest revision on the default branch X(see the X.B \-b Xoption of X.BR rcs (1)) Xis retrieved. XA revision is composed of one or more numeric or symbolic fields Xseparated by periods. The numeric equivalent of a symbolic field Xis specified with the X.B \-n Xoption of the commands X.BR ci (1) Xand X.BR rcs (1). X.TP X.BR \-l [\f2rev\fP] Xsame as X.BR \-r , Xexcept that it also locks the retrieved revision for Xthe caller. X.TP X.BR \-u [\f2rev\fP] Xsame as X.BR \-r , Xexcept that it unlocks the retrieved revision if it was Xlocked by the caller. If X.I rev Xis omitted, X.B \-u Xretrieves the latest revision locked by the caller; if no such lock exists, Xit retrieves the latest revision on the default branch. X.TP X.BR \-f [\f2rev\fP] Xforces the overwriting of the working file; Xuseful in connection with X.BR \-q . XSee also X.SM "FILE MODES" Xbelow. X.TP X.B \-kkv XGenerate keyword strings using the default form, e.g.\& X.B "$\&Revision: \*(Rv $" Xfor the X.B Revision Xkeyword. XA locker's name is inserted in the value of the X.BR Header , X.BR Id , Xand X.B Locker Xkeyword strings Xonly as a file is being locked, Xi.e. by X.B "ci\ \-l" Xand X.BR "co\ \-l". XThis is the default. X.TP X.B \-kkvl XLike X.BR \-kkv , Xexcept that a locker's name is always inserted Xif the given revision is currently locked. X.TP X.BR \-kk XGenerate only keyword names in keyword strings; omit their values. XSee X.SM "KEYWORD SUBSTITUTION" Xbelow. XFor example, for the X.B Revision Xkeyword, generate the string X.B $\&Revision$ Xinstead of X.BR "$\&Revision: \*(Rv $". XThis option is useful to ignore differences due to keyword substitution Xwhen comparing different revisions of a file. X.TP X.BR \-ko XGenerate the old keyword string, Xpresent in the working file just before it was checked in. XFor example, for the X.B Revision Xkeyword, generate the string X.B "$\&Revision: 1.1 $" Xinstead of X.B "$\&Revision: \*(Rv $" Xif that is how the string appeared when the file was checked in. XThis can be useful for binary file formats Xthat cannot tolerate any changes to substrings Xthat happen to take the form of keyword strings. X.TP X.BR \-kv XGenerate only keyword values for keyword strings. XFor example, for the X.B Revision Xkeyword, generate the string X.B \*(Rv Xinstead of X.BR "$\&Revision: \*(Rv $". XThis can help generate files in programming languages where it is hard to Xstrip keyword delimiters like X.B "$\&Revision:\ $" Xfrom a string. XHowever, further keyword substitution cannot be performed once the Xkeyword names are removed, so this option should be used with care. XBecause of this danger of losing keywords, Xthis option cannot be combined with X.BR \-l , Xand the owner write permission of the working file is turned off; Xto edit the file later, check it out again without X.BR \-kv . X.TP X.BR \-p [\f2rev\fP] Xprints the retrieved revision on the standard output rather than storing it Xin the working file. XThis option is useful when X.B co Xis part of a pipe. X.TP X.BR \-q [\f2rev\fP] Xquiet mode; diagnostics are not printed. X.TP X.BR \-I [\f2rev\fP] Xinteractive mode; Xthe user is prompted and questioned Xeven if the standard input is not a terminal. X.TP X.BI \-d date Xretrieves the latest revision on the selected branch whose checkin date/time is Xless than or equal to X.I date. XThe date and time may be given in free format. XThe time zone X.B LT Xstands for local time; Xother common time zone names are understood. XFor example, the following X.IR date s Xare equivalent Xif local time is January 11, 1990, 8pm Pacific Standard Time X(eight hours west of \*g): X.RS X.LP X.RS X.nf X.ta \w'\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP 'u X.ne 9 X\f38:00 pm lt\fP X\f34:00 AM, Jan. 12, 1990\fP note: default is \*g X\f31990/01/12 04:00:00\fP \*r date format X\f3Thu Jan 11 20:00:00 1990 LT\fP output of \f3ctime\fP(3) + \f3LT\fP X\f3Thu Jan 11 20:00:00 PST 1990\fP output of \f3date\fP(1) X\f3Fri Jan 12 04:00:00 GMT 1990\fP X\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP X\f3Fri-JST, 1990, 1pm Jan 12\fP X\f312-January-1990, 04:00-WET\fP X.ta 4n +4n +4n +4n X.fi X.RE X.LP XMost fields in the date and time may be defaulted. XThe default time zone is \*g. XThe other defaults are determined in the order year, month, day, Xhour, minute, and second (most to least significant). At least one of these Xfields must be provided. For omitted fields that are of higher significance Xthan the highest provided field, the time zone's current values are assumed. XFor all other omitted fields, Xthe lowest possible values are assumed. XFor example, the date X.B "20, 10:30" Xdefaults to X10:30:00 \*g of the 20th of the \*g time zone's current month and year. XThe date/time must be quoted if it contains spaces. X.RE X.TP X.BI \-s state Xretrieves the latest revision on the selected branch whose state is set to X.I state. X.TP X.BR \-w [\f2login\fP] Xretrieves the latest revision on the selected branch which was checked in Xby the user with login name X.I login. XIf the argument X.I login Xis Xomitted, the caller's login is assumed. X.TP X.BI \-j joinlist Xgenerates a new revision which is the join of the revisions on X.I joinlist. XThis option is largely obsoleted by X.BR rcsmerge (1) Xbut is retained for backwards compatibility. X.RS X.PP XThe X.I joinlist Xis a comma-separated list of pairs of the form X.IB rev2 : rev3, Xwhere X.I rev2 Xand X.I rev3 Xare (symbolic or numeric) Xrevision numbers. XFor the initial such pair, X.I rev1 Xdenotes the revision selected Xby the above options X.BR \-f, X\&.\|.\|., X.BR \-w . XFor all other pairs, X.I rev1 Xdenotes the revision generated by the previous pair. X(Thus, the output Xof one join becomes the input to the next.) X.PP XFor each pair, X.B co Xjoins revisions X.I rev1 Xand X.I rev3 Xwith respect to X.I rev2. XThis means that all changes that transform X.I rev2 Xinto X.I rev1 Xare applied to a copy of X.I rev3. XThis is particularly useful if X.I rev1 Xand X.I rev3 Xare the ends of two branches that have X.I rev2 Xas a common ancestor. If X.IR rev1 < rev2 < rev3 Xon the same branch, Xjoining generates a new revision which is like X.I rev3, Xbut with all changes that lead from X.I rev1 Xto X.I rev2 Xundone. XIf changes from X.I rev2 Xto X.I rev1 Xoverlap with changes from X.I rev2 Xto X.I rev3, X.B co Xprints a warning and includes the Xoverlapping sections, delimited by the lines X.BI <<<<<<< "\ rev1," X.BR ======= , Xand X.BI >>>>>>> "\ rev3." X.PP XFor the initial pair, X.I rev2 Xmay be omitted. The default is the common Xancestor. XIf any of the arguments indicate branches, the latest revisions Xon those branches are assumed. XThe options X.B \-l Xand X.B \-u Xlock or unlock X.I rev1. X.RE X.TP X.BI \-V n XEmulate \*r version X.I n, Xwhere X.I n Xmay be X.BR 3 , X.BR 4 , Xor X.BR 5 . XThis may be useful when interchanging \*r files with others who are Xrunning older versions of \*r. XTo see which version of \*r your correspondents are running, have them invoke X.B rlog Xon an \*r file; Xif none of the first few lines of output contain the string X.B branch: Xit is version 3; Xif the dates' years have just two digits, it is version 4; Xotherwise, it is version 5. XAn \*r file generated while emulating version 3 will lose its default branch. XAn \*r revision generated while emulating version 4 or earlier will have Xa timestamp that is off by up to 13 hours. XA revision extracted while emulating version 4 or earlier will contain Xdates of the form X.IB yy / mm / dd Xinstead of X.IB yyyy / mm / dd Xand may also contain different white space in the substitution for X.BR $\&Log$ . X.SH "KEYWORD SUBSTITUTION" XStrings of the form X.BI $ keyword $ Xand X.BI $ keyword : .\|.\|. $ Xembedded in Xthe text are replaced Xwith strings of the form X.BI $ keyword : value $ Xwhere X.I keyword Xand X.I value Xare pairs listed below. XKeywords may be embedded in literal strings Xor comments to identify a revision. X.PP XInitially, the user enters strings of the form X.BI $ keyword $ . XOn checkout, X.B co Xreplaces these strings with strings of the form X.BI $ keyword : value $ . XIf a revision containing strings of the latter form Xis checked back in, the value fields will be replaced during the next Xcheckout. XThus, the keyword values are automatically updated on checkout. XThis automatic substitution can be modified by the X.B \-k Xoptions. X.PP XKeywords and their corresponding values: X.TP X.B $\&Author$ XThe login name of the user who checked in the revision. X.TP X.B $\&Date$ XThe date and time (\*g) the revision was checked in. X.TP X.B $\&Header$ XA standard header containing the full pathname of the \*r file, the Xrevision number, the date (\*g), the author, the state, Xand the locker (if locked). X.TP X.B $\&Id$ XSame as X.BR $\&Header$ , Xexcept that the \*r file name is without a path. X.TP X.B $\&Locker$ XThe login name of the user who locked the revision (empty if not locked). X.TP X.B $\&Log$ XThe log message supplied during checkin, preceded by a header Xcontaining the \*r file name, the revision number, the author, and the date X(\*g). XExisting log messages are X.I not Xreplaced. XInstead, the new log message is inserted after X.BR $\&Log: .\|.\|. $ . XThis is useful for Xaccumulating a complete change log in a source file. X.TP X.B $\&RCSfile$ XThe name of the \*r file without a path. X.TP X.B $\&Revision$ XThe revision number assigned to the revision. X.TP X.B $\&Source$ XThe full pathname of the \*r file. X.TP X.B $\&State$ XThe state assigned to the revision with the X.B \-s Xoption of X.BR rcs (1) Xor X.BR ci (1). X.SH "FILE NAMING" XPairs of \*r files and working files may be specified in three ways X(see also the Xexample section). X.PP X1) Both the \*r file and the working file are given. The \*r file name is of Xthe form X.IB path1 / workfile ,v Xand the working file name is of the form X.IB path2 / workfile Xwhere X.IB path1 / Xand X.IB path2 / Xare (possibly different or empty) paths and X.I workfile Xis a file name. X.PP X2) Only the \*r file is given. Then the working file is created in the current Xdirectory and its name is derived from the name of the \*r file Xby removing X.IB path1 / Xand the suffix X.BR ,v . X.PP X3) Only the working file is given. XThen X.B co Xlooks for an \*r file of the form X.IB path2 /RCS/ workfile ,v Xor X.IB path2 / workfile ,v X(in this order). X.PP XIf the \*r file is specified without a path in 1) and 2), then X.B co Xlooks for the \*r file first in the directory X.B ./RCS Xand then in the current Xdirectory. X.SH EXAMPLES XSuppose the current directory contains a subdirectory X.B RCS Xwith an \*r file X.BR io.c,v . XThen all of the following commands retrieve the latest Xrevision from X.B RCS/io.c,v Xand store it into X.BR io.c . X.LP X.RS X.nf X.ft 3 Xco io.c; co RCS/io.c,v; co io.c,v; Xco io.c RCS/io.c,v; co io.c io.c,v; Xco RCS/io.c,v io.c; co io.c,v io.c; X.ft X.fi X.RE X.SH "FILE MODES" XThe working file inherits the read and execute permissions from the \*r Xfile. In addition, the owner write permission is turned on, unless X.B \-kv Xis set or the file Xis checked out unlocked and locking is set to strict (see X.BR rcs (1)). X.PP XIf a file with the name of the working file exists already and has write Xpermission, X.B co Xaborts the checkout, Xasking beforehand if possible. XIf the existing working file is Xnot writable or X.B \-f Xis given, the working file is deleted without asking. X.SH FILES X.B co Xaccesses files much as X.BR ci (1) Xdoes, except that it does not need to read the working file. X.SH DIAGNOSTICS XThe \*r file name, the working file name, Xand the revision number retrieved are Xwritten to the diagnostic output. XThe exit status is zero if and only if all operations were successful. 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), ctime(3), date(1), ident(1), Xrcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), Xrcsfile(5) 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. X.SH LIMITS XLinks to the \*r and working files are not preserved. X.PP XThere is no way to selectively suppress the expansion of keywords, except Xby writing them differently. In nroff and troff, this is done by embedding the Xnull-character X.B \e& Xinto the keyword. X.SH BUGS XThe X.B \-d Xoption sometimes gets confused, and accepts no date before 1970. END_OF_FILE if test 14638 -ne `wc -c <'man/co.1'`; then echo shar: \"'man/co.1'\" unpacked with wrong size! fi # end of 'man/co.1' fi if test -f 'src/conf.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/conf.sh'\" else echo shar: Extracting \"'src/conf.sh'\" \(14859 characters\) sed "s/^X//" >'src/conf.sh' <<'END_OF_FILE' X#!/bin/sh X# Output RCS compile-time configuration. XId='$Id: conf.sh,v 5.6 1990/11/01 05:03:28 eggert Exp $' 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 X# Direct standard output to "a.h"; later parts of this procedure need it. X# Standard error can be ignored if a.h is OK, X# and can be inspected for clues otherwise. Xexec >a.h || exit X X# The Makefile overrides the following defaults. X: ${C='cc -O'} X: ${COMPAT2=0} X: ${DIFF_FLAGS=-an} X: ${DIFF_L=1} X: ${RCSPREFIX=/usr/local/bin/} X: ${SENDMAIL=/usr/lib/sendmail} X: ${L=} X: ${DIFF=${RCSPREFIX}diff} X X Xcat <<EOF || exit X/* RCS compile-time configuration */ X X /* $Id */ X X/* X * This file is generated automatically. X * If you edit it by hand your changes may be lost. X * Instead, please try to fix conf.sh, X * and send your fixes to rcs-bugs@cs.purdue.edu. X */ X XEOF X X: exitmain Xcat >a.c <<EOF && $C a.c $L >&2 || exit X#include "a.h" Xint main(argc,argv) int argc; char **argv; { return argc-1; } XEOF Xe='(n) ? (exit(n),(n)) : (n) /* lint fodder */' Xif ./a.out - Xthen : Xelif ./a.out Xthen e=n Xfi Xecho "#define exitmain(n) return $e /* how to exit from main() */" X X: standard includes XstandardIncludes= Xfor h in stdio sys/types sys/stat fcntl limits stdlib string unistd vfork Xdo X cat >a.c <<EOF || exit X#include "a.h" X$standardIncludes X#include <$h.h> Xint main(){ exitmain(0); } XEOF X if ($C a.c $L && ./a.out) >&2 X then i="# include <$h.h>" X else X case $h in X string) X i='# include <strings.h>';; X *) X i=" /* #include <$h.h> does not work. */" X esac X fi || exit X standardIncludes="$standardIncludes X$i" Xdone X Xcat <<EOF || exit X#if !MAKEDEPEND$standardIncludes X#endif /* !MAKEDEPEND */ XEOF X X# has_sys_*_h Xfor H in dir param wait Xdo X : has_sys_${H}_h X cat >a.c <<EOF || exit X#include "a.h" X#include <sys/$H.h> Xint main() { exitmain(0); } XEOF X if ($C a.c $L && ./a.out) >&2 X then h=1 X else h=0 X fi X echo "#define has_sys_${H}_h $h /* Does #include <sys/$H.h> work? */" Xdone X X: const, volatile Xfor i in const volatile Xdo X cat >a.c <<EOF || exit X# include "a.h" X $i int * $i * zero; XEOF X if $C -S a.c >&2 X then echo "/* #define $i */ /* The '$i' keyword works. */" X else echo "#define $i /* The '$i' keyword does not work. */" X fi Xdone X X# *_t Xcat >a.c <<'EOF' || exit X#include "a.h" X#include <signal.h> Xt x; XEOF Xfor t in gid_t mode_t pid_t sig_atomic_t size_t time_t uid_t Xdo X : $t X case $t in X time_t) i=long;; X *) i=int;; X esac X if $C -S -Dt=$t a.c >&2 X then echo "/* typedef $i $t; */ /* Standard headers define $t. */" X else echo "typedef $i $t; /* Standard headers do not define $t. */" X fi Xdone X X: has_prototypes Xcat >a.c <<'EOF' || exit X#include "a.h" Xint main(int, char**); Xint main(int argc, char **argv) { exitmain(!argv[argc-1]); } XEOF Xif $C -S a.c >&2 Xthen h=1 Xelse h=0 Xfi Xcat <<EOF X#define has_prototypes $h /* Do function prototypes work? */ X#if has_prototypes X# define P(params) params X# if !MAKEDEPEND X# include <stdarg.h> X# endif X# define vararg_start(ap,p) va_start(ap,p) X#else X# define P(params) () X# if !MAKEDEPEND X# include <varargs.h> X# endif X# define vararg_start(ap,p) va_start(ap) X#endif XEOF X X: has_getuid Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef getuid X uid_t getuid(); X#endif Xint main() { exitmain(getuid()!=getuid()); } XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_getuid $h /* Does getuid() work? */" X X: declare_getpwuid Xcat >a.c <<'EOF' || exit X#include "a.h" X#include <pwd.h> Xd Xint main() { exitmain(!getpwuid(0)); } XEOF XD='struct passwd *getpwuid P((uid_t));' Xif ($C -Dd="$D" a.c $L && ./a.out) >&2 Xthen define="#define declare_getpwuid $D" Xelif ($C -Dd= a.c $L && ./a.out) >&2 Xthen define="#define declare_getpwuid /* $D */" Xelse define="/* #define declare_getpwuid $D */" Xfi Xecho "$define" X X: has_rename, bad_rename Xcat >a.c <<'EOF' && rm -f a.d || exit X#include "a.h" X#ifndef rename X int rename(); X#endif Xint main() { exitmain(rename("a.c","a.d")); } XEOF Xif ($C a.c $L && ./a.out && test -f a.d) >&2 Xthen X h=1 X echo x >a.c X if ./a.out && test ! -f a.c -a -f a.d X then b=0 X else b=1 X fi Xelse h=0 b=0 Xfi Xecho "#define has_rename $h /* Does rename() work? */" Xecho "#define bad_rename $b /* Does rename(A,B) fail if B exists? */" X X: void, VOID Xcat >a.c <<'EOF' || exit X#include "a.h" Xvoid f() {} Xint main() {f(); exitmain(0);} XEOF Xif $C -S a.c >&2 Xthen X v='(void) ' Xelse X v= X echo 'typedef int void;' Xfi Xecho "#define VOID $v/* 'VOID e;' discards the value of an expression 'e'. */" X X: signal_type, sig_zaps_handler Xcat >a.c <<'EOF' || exit X#include "a.h" X#include <signal.h> X#ifndef getpid X pid_t getpid(); X#endif X#ifndef kill X int kill(); X#endif X#ifndef signal X signal_type (*signal P((int,signal_type(*)P((int)))))P((int)); X#endif Xsignal_type nothing(i) int i; {} Xint main(argc, argv) int argc; char **argv; X{ X signal(SIGINT, nothing); X while (--argc) X kill(getpid(), SIGINT); X exitmain(0); X} XEOF Xfor signal_type in void int bad Xdo X case $signal_type in X bad) echo >&2 "cannot deduce signal_type"; exit 1 X esac X ($C -Dsignal_type=$signal_type a.c $L && ./a.out 1) >&2 && break Xdone Xecho "#define signal_type $signal_type /* type returned by signal handlers */" Xif ./a.out 1 2 >&2 Xthen z=0 Xelse z=1 Xfi Xecho "#define sig_zaps_handler $z /* Must a signal handler reinvoke signal()? */" X X: has_seteuid Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef geteuid X uid_t geteuid(); X#endif Xint main() { X/* Guess, don't test. Ugh. Testing would require running conf.sh setuid. */ X#if !_POSIX_VERSION || _POSIX_VERSION==198808L&&!defined(sun)&&!defined(__sun__) X exitmain(1); X#else X exitmain(seteuid(geteuid()) < 0); X#endif X} XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_seteuid $h /* Does seteuid() obey Posix 1003.1-1990? */" X X: has_sigaction Xcat >a.c <<'EOF' || exit X#include <signal.h> Xstruct sigaction s; XEOF Xif $C -S a.c >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_sigaction $h /* Does struct sigaction work? */" X X: has_sigblock Xcat >a.c <<'EOF' || exit X#include "a.h" X#include <signal.h> X#ifndef sigblock X int sigblock(); X#endif Xint main() { sigblock(0); exitmain(0); } XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_sigblock $h /* Does sigblock() work? */" X X: has_sys_siglist Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef sys_siglist X extern const char *sys_siglist[]; X#endif Xint main() { exitmain(!sys_siglist[1][0]); } XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_sys_siglist $h /* Does sys_siglist[] work? */" X X: exit_type, underscore_exit_type Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef exit X void exit(); X#endif Xint main() { exit(0); } XEOF Xif $C -S a.c >&2 Xthen t=void Xelse t=int Xfi Xecho "#define exit_type $t /* type returned by exit() */" Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef _exit X void _exit(); X#endif Xint main() { _exit(0); } XEOF Xif $C -S a.c >&2 Xthen t=void Xelse t=int Xfi Xecho "#define underscore_exit_type $t /* type returned by _exit() */" X X: fread_type Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef fread X size_t fread(); X#endif Xint main() { char b; exitmain(!(fread(&b,1,1,stdin)==1 && b=='#')); } XEOF Xif $C -S a.c $L >&2 Xthen t=size_t Xelse t=int Xfi Xecho "typedef $t fread_type; /* type returned by fread() and fwrite() */" X X: malloc_type Xcat >a.c <<'EOF' || exit X#include "a.h" Xtypedef void *malloc_type; X#ifndef malloc X malloc_type malloc(); X#endif Xint main() { exitmain(!malloc(1)); } XEOF Xif $C -S a.c >&2 Xthen t=void Xelse t=char Xfi Xecho "typedef $t *malloc_type; /* type returned by malloc() */" X X: free_type Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef malloc X malloc_type malloc(); X#endif X#ifndef free X void free(); X#endif Xint main() { free(malloc(1)); exitmain(0); } XEOF Xif $C -S a.c >&2 Xthen t=void Xelse t=int Xfi Xecho "#define free_type $t /* type returned by free() */" X X: strlen_type Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef strlen X size_t strlen(); X#endif Xint main() { exitmain(strlen("")); } XEOF Xif $C -S a.c >&2 Xthen t=size_t Xelse t=int Xfi Xecho "typedef $t strlen_type; /* type returned by strlen() */" X X: has_getcwd Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef getcwd X char *getcwd(); X#endif Xchar buf[10000]; Xint main() { exitmain(!getcwd(buf,10000)); } XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen has_getcwd=1 Xelse has_getcwd=0 Xfi Xecho "#define has_getcwd $has_getcwd /* Does getcwd() work? */" X X: has_getwd Xcase $has_getcwd in X0) X cat >a.c <<'EOF' || exit X#include "a.h" X#include <sys/param.h> X#ifndef getwd X char *getwd(); X#endif Xchar buf[MAXPATHLEN]; Xint main() { exitmain(!getwd(buf)); } XEOF X if ($C a.c $L && ./a.out) >&2 X then h=1 X else h=0 X fi X echo "#define has_getwd $h /* Does getwd() work? */";; X1) X echo "/* #define has_getwd ? */ /* Does getwd() work? */" Xesac X X: has_vfork Xcat >a.c <<'EOF' || exit X#include "a.h" X#if has_sys_wait_h X# include <sys/wait.h> X#endif X#ifndef _exit X underscore_exit_type _exit(); X#endif X#ifndef getpid X pid_t getpid(); X#endif X#ifndef wait X pid_t wait(); X#endif Xpid_t child; Xint status; Xstruct stat st; Xint main() X{ X pid_t parent = getpid(); X if (!(child = vfork())) { X /* Tickle vfork/compiler bug (e.g. sparc gcc -O (1.37.1). */ X pid_t i = getpid(), j = getpid(); X if (i!=getpid() || j!=getpid()) X _exit(!i); X /* Tickle file descriptor bug (e.g. IRIX 3.3). */ X _exit(close(1) < 0); X } else { X while (wait(&status) != child) X ; X /* Test for presence of bugs. */ X exitmain(status || parent != getpid() || fstat(1, &st) < 0); X } X} XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_vfork $h /* Does vfork() work? */" X X: has_vfprintf Xcat >a.c <<'EOF' || exit X#include "a.h" X#if has_prototypes Xint p(const char *format,...) X#else X/*VARARGS1*/ int p(format, va_alist) char *format; va_dcl X#endif X{ X int r; X va_list args; X vararg_start(args, format); X r = vfprintf(stderr, format, args); X va_end(args); X return r; X} Xint main() { exitmain(p("")); } XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen h=1 Xelse h=0 Xfi Xecho "#define has_vfprintf $h /* Does vfprintf() work? */" X X: strrchr Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef strrchr X char *strrchr(); X#endif Xint main() {exitmain(!strrchr("abc", 'c'));} XEOF X($C a.c $L && ./a.out) >&2 || X echo "#define strrchr rindex /* Use old-fashioned name for strrchr(). */" X X: CO Xecho "#define CO \"${RCSPREFIX}co\" /* name of 'co' program */" X X: COMPAT2 Xecho "#define COMPAT2 $COMPAT2 /* Are version 2 files supported? */" X X: DATEFORM Xcat >a.c <<'EOF' || exit X#include "a.h" Xint main() { printf("%.2d", 1); exitmain(0); } XEOF X$C a.c $L >&2 && r=`./a.out` || exit Xcase $r in X01) f=%.2d;; X*) f=%02d Xesac Xecho "#define DATEFORM \"$f.$f.$f.$f.$f.$f\" /* e.g. 01.01.01.01.01.01 */" X X: DIFF Xecho "#define DIFF \"$DIFF\" /* name of 'diff' program */" X X: DIFF_FLAGS Xdfs= Xfor df in $DIFF_FLAGS Xdo dfs="$dfs, \"$df\"" Xdone Xecho "#define DIFF_FLAGS $dfs /* Make diff output suitable for RCS. */" X X: DIFF_L Xecho "#define DIFF_L $DIFF_L /* Does diff -L work? */" X X: EXECRCS Xe=execv Xfor i in "$DIFF" "$RCSPREFIX" "$SENDMAIL" Xdo X case $i in X */*) ;; X *) e=execvp break X esac Xdone Xecho "#define EXECRCS $e /* variant of execv() to use on subprograms */" X X: MERGE Xecho "#define MERGE \"${RCSPREFIX}merge\" /* name of 'merge' program */" X X: RCSDIR, SLASH, TMPDIR Xrm -fr a.RCS && mkdir a.RCS && echo x >a.RCS/x && Xcat >a.c <<'EOF' || exit X#include "a.h" Xmain() { exitmain(!fopen(NAME,"r")); } XEOF Xfor NAME in a.RCS/x 'a.rcs/x' 'A.RCS\\x' bad Xdo ($C -DNAME="\"$NAME\"" a.c $L && ./a.out) && break Xdone Xcase $NAME in Xa.RCS/x) RCSDIR=RCS/ SLASH=/ TMPDIR=/tmp/;; Xa.rcs/x) RCSDIR=rcs/ SLASH=/ TMPDIR=/tmp/;; X'A.RCS\\X') RCSDIR='RCS\\' SLASH='\\' TMPDIR='\\TMP\\';; X*) echo >&2 "cannot deduce RCSDIR"; exit 1;; Xesac Xrm -fr a.RCS Xecho "#define RCSDIR \"$RCSDIR\" /* subdirectory for RCS files */" Xecho "#define SLASH '$SLASH' /* path name separator */" Xecho "#define TMPDIR \"$TMPDIR\" /* default directory for temporary files */" X X: DIFF_PATH_HARDWIRED Xcase $DIFF in X"$SLASH"*) h=1;; X*) h=0 Xesac Xecho "#define DIFF_PATH_HARDWIRED $h /* Is DIFF absolute, not relative? */" X X: ROOTPATH Xcase `pwd` in X[/\\]*) X echo '#define ROOTPATH(p) ((p)[0]==SLASH)';; X?:[/\\]*) X echo '#define ROOTPATH(p) ((p)[0] && (p)[1]==':' && (p)[2]==SLASH)';; X*) X echo >&2 "cannot deduce ROOTPATH"; exit 1;; Xesac X X: RCSSEP Xif echo x >a.1234567890,v && ($C -DNAME=\"a.1234567890,v\" a.c $L && ./a.out) Xthen RCSSEP=',' Xelse RCSSEP='\0' Xfi Xecho "#define RCSSEP '$RCSSEP' /* separator for RCSSUF */" X X: SENDMAIL Xecho "#define SENDMAIL $SENDMAIL /* how to send mail */" X X: fprintf, printf, vfprintf Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef printf X int printf P((const char*,...)); X#endif Xint main() { printf(""); exitmain(0); } XEOF Xif $C -S a.c >&2 Xthen a='1 /* These agree with <stdio.h>. */' Xelse a='0 /* These conflict with <stdio.h>. */' Xfi Xcat <<EOF || exit X#if $a X int fprintf P((FILE*,const char*,...)); X int printf P((const char*,...)); X# if has_vfprintf X int vfprintf P((FILE*,const char*,...)); X# else X void _doprnt P((const char*,...)); X# endif X#endif XEOF X X: sprintf and other routines with '...' and default promotion problems Xcat >a.c <<'EOF' || exit X#include "a.h" X#ifndef sprintf X int sprintf(); X#endif Xint main() X{ X char buf[1]; X exitmain(sprintf(buf, "") != 0); X} XEOF Xif ($C a.c $L && ./a.out) >&2 Xthen t='int ' Xelse t='char *' Xfi Xcat >a.c <<'EOF' || exit X#include "a.h" X#if has_sys_wait_h X# include <sys/wait.h> X#endif Xdeclaration Xint main() { exitmain(0); } XEOF Xfor declaration in \ X "${t}sprintf P((char*,const char*,...));" \ X 'int chmod P((const char*,mode_t));' \ X 'int fcntl P((int,int,...));' \ X 'int open P((const char*,int,...));' \ X 'mode_t umask P((mode_t));' \ X 'pid_t wait P((int*));' Xdo X if $C -S -Ddeclaration="$declaration" a.c >&2 X then echo "$declaration" X else echo "/* $declaration */" X fi Xdone Xfor i in ' X#ifndef O_CREAT X int creat P((const char*,mode_t)); X#endif' ' X#if has_seteuid X int setegid P((gid_t)); X int seteuid P((uid_t)); X#endif' X # See declare_getpwuid for how getpwuid() is handled. Xdo X echo '#include "a.h" X int main() { exitmain(0); }'"$i" >a.c || exit X if $C -S a.c >&2 X then sed 1,2d a.c X else sed '1,2d; s|.*|/* & */|' a.c X fi Xdone END_OF_FILE if test 14859 -ne `wc -c <'src/conf.sh'`; then echo shar: \"'src/conf.sh'\" unpacked with wrong size! fi # end of 'src/conf.sh' fi if test -f 'src/rcsgen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/rcsgen.c'\" else echo shar: Extracting \"'src/rcsgen.c'\" \(11524 characters\) sed "s/^X//" >'src/rcsgen.c' <<'END_OF_FILE' X/* X * RCS revision generation 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: rcsgen.c,v $ X * Revision 5.6 1990/12/27 19:54:26 eggert X * Fix bug: rcs -t inserted \n, making RCS file grow. X * X * Revision 5.5 1990/12/04 05:18:45 eggert X * Use -I for prompts and -q for diagnostics. X * X * Revision 5.4 1990/11/01 05:03:47 eggert X * Add -I and new -t behavior. Permit arbitrary data in logs. X * X * Revision 5.3 1990/09/21 06:12:43 hammer X * made putdesc() treat stdin the same whether or not it was from a terminal X * by making it recognize that a single '.' was then end of the X * description always X * X * Revision 5.2 1990/09/04 08:02:25 eggert X * Fix `co -p1.1 -ko' bug. Standardize yes-or-no procedure. X * X * Revision 5.1 1990/08/29 07:14:01 eggert X * Clean old log messages too. X * X * Revision 5.0 1990/08/22 08:12:52 eggert X * Remove compile-time limits; use malloc instead. X * Ansify and Posixate. X * X * Revision 4.7 89/05/01 15:12:49 narten X * changed copyright header to reflect current distribution rules X * X * Revision 4.6 88/08/28 14:59:10 eggert X * Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin() X * X * Revision 4.5 87/12/18 11:43:25 narten X * additional lint cleanups, and a bug fix from the 4.3BSD version that X * keeps "ci" from sticking a '\377' into the description if you run it X * with a zero-length file as the description. (Guy Harris) X * X * Revision 4.4 87/10/18 10:35:10 narten X * Updating version numbers. Changes relative to 1.1 actually relative to X * 4.2 X * X * Revision 1.3 87/09/24 13:59:51 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:27 jenkins X * Port to suns X * X * Revision 4.2 83/12/02 23:01:39 wft X * merged 4.1 and 3.3.1.1 (clearerr(stdin)). X * X * Revision 4.1 83/05/10 16:03:33 wft X * Changed putamin() to abort if trying to reread redirected stdin. X * Fixed getdesc() to output a prompt on initial newline. X * X * Revision 3.3.1.1 83/10/19 04:21:51 lepreau X * Added clearerr(stdin) for re-reading description from stdin. X * X * Revision 3.3 82/11/28 21:36:49 wft X * 4.2 prerelease X * X * Revision 3.3 82/11/28 21:36:49 wft X * Replaced ferror() followed by fclose() with ffclose(). X * Putdesc() now suppresses the prompts if stdin X * is not a terminal. A pointer to the current log message is now X * inserted into the corresponding delta, rather than leaving it in a X * global variable. X * X * Revision 3.2 82/10/18 21:11:26 wft X * I added checks for write errors during editing, and improved X * the prompt on putdesc(). X * X * Revision 3.1 82/10/13 15:55:09 wft X * corrected type of variables assigned to by getc (char --> int) X */ X X X X X#include "rcsbase.h" X XlibId(genId, "$Id: rcsgen.c,v 5.6 1990/12/27 19:54:26 eggert Exp $") X Xint interactiveflag; /* Should we act as if stdin is a tty? */ Xstruct cbuf curlogmsg; /* buffer for current log message */ Xstruct buf curlogbuf; /* same, including allocated but unused bytes */ X Xenum stringwork {copy, edit, expand, edit_expand }; X Xstatic void scandeltatext P((struct hshentry*,enum stringwork)); X X X X X const char * Xbuildrevision(deltas, target, tostdout, expandflag) X const struct hshentries *deltas; X struct hshentry *target; X int tostdout; X int expandflag; X/* Function: Generates the revision given by target X * by retrieving all deltas given by parameter deltas and combining them. X * If tostdout is set, the revision is printed on the standard output, X * otherwise written into a temporary file. X * Temporary files are put into tmp unless the caller has already set up X * the temp file directory by invoking initeditfiles(), which sets fcopy. X * if expandflag is set, keyword expansion is performed. X * Returns nil on errors, the name of the file with the revision otherwise. X * X * Algorithm: Copy initial revision unchanged. Then edit all revisions but X * the last one into it, alternating input and output files (resultfile and X * editfile). The last revision is then edited in, performing simultaneous X * keyword substitution (this saves one extra pass). X * All this simplifies if only one revision needs to be generated, X * or no keyword expansion is necessary, or if output goes to stdout. X */ X{ X static const char nonnil[] = ""; /* some char* value that isn't nil */ X X if (deltas->first == target) { X /* only latest revision to generate */ X if (tostdout) { X fcopy=stdout; X scandeltatext(target, expandflag?expand:copy); X return nonnil; X } else { X if (!fcopy) X inittmpeditfiles(); X scandeltatext(target,expandflag?expand:copy); X ffclose(fcopy); X return(resultfile); X } X } else { X /* several revisions to generate */ X if (!fcopy) X inittmpeditfiles(); X /* write initial revision into fcopy, no keyword expansion */ X scandeltatext(deltas->first, copy); X while ((deltas=deltas->rest)->rest) { X /* do all deltas except last one */ X scandeltatext(deltas->first, edit); X } X if (expandflag | tostdout) { X /* first, get to beginning of file*/ X finishedit((struct hshentry *)nil); X swapeditfiles(tostdout); X } X scandeltatext(deltas->first, expandflag ? edit_expand : edit); X finishedit(expandflag ? deltas->first : (struct hshentry*)nil); X if (tostdout) X return nonnil; X ffclose(fcopy); X return resultfile; X } X} X X X X static void Xscandeltatext(delta,func) Xstruct hshentry * delta; enum stringwork func; X/* Function: Scans delta text nodes up to and including the one given X * by delta. For the one given by delta, the log message is saved into X * curlogmsg and the text is processed according to parameter func. X * Assumes the initial lexeme must be read in first. X * Does not advance nexttok after it is finished. X */ X{ X const struct hshentry *nextdelta; X struct cbuf cb; X X for (;;) { X nextlex(); X if (!(nextdelta=getnum())) { X fatserror("can't find delta for revision %s", delta->num); 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 switch (func) { X case copy: copystring(); break; X case expand: xpandstring(delta); break; X case edit: editstring((struct hshentry *)nil); break; X case edit_expand: editstring(delta); break; X } X} X X struct cbuf Xcleanlogmsg(m, s) X char *m; X size_t s; X{ X register char *t = m; X register const char *f = t; X struct cbuf r; X while (s) { X --s; X if ((*t++ = *f++) == '\n') X while (m < --t) X if (t[-1]!=' ' && t[-1]!='\t') { X *t++ = '\n'; X break; X } X } X while (m < t && (t[-1]==' ' || t[-1]=='\t' || t[-1]=='\n')) X --t; X r.string = m; X r.size = t - m; X return r; X} X X Xint ttystdin() X{ X static int initialized; X if (!initialized) { X if (!interactiveflag) X interactiveflag = isatty(STDIN_FILENO); X initialized = true; X } X return interactiveflag; X} X X int Xgetcstdin() X{ X register int c = getchar(); X if (c == EOF) { X if (ferror(stdin)) X IOerror(); X if (ttystdin()) { X clearerr(stdin); X afputc('\n',stderr); X } X } X return c; X} X X#if has_prototypes X int Xyesorno(int default_answer, const char *question, ...) X#else X /*VARARGS2*/ int X yesorno(default_answer, question, va_alist) X int default_answer; const char *question; va_dcl X#endif X{ X va_list args; X register int c, r; X if (!quietflag && ttystdin()) { X oflush(); X vararg_start(args, question); X fvfprintf(stderr, question, args); X va_end(args); X eflush(); X r = c = getcstdin(); X while (c!='\n' && c!=EOF) X c = getcstdin(); X if (r=='y' || r=='Y') X return true; X if (r=='n' || r=='N') X return false; X } X return default_answer; X} X X X void Xputdesc(textflag, textfile) X int textflag; X const char *textfile; X/* Function: puts the descriptive text into file frewrite. X * if finptr && !textflag, the text is copied from the old description. X * Otherwise, if the textfile!=nil, the text is read from that X * file, or from stdin, if textfile==nil. X * A textfile with a leading '-' is treated as a string, not a file name. X * If finptr, the old descriptive text is discarded. X */ X{ register FILE * txt; register int c, old1, old2; X register FILE * frew; X X frew = frewrite; X if (finptr && !textflag) { X /* copy old description */ X aprintf(frew,"\n\n%s%c",Kdesc,nextc); X foutptr = frewrite; X getdesc(false); X } else { X /* get new description */ X if (finptr) { X /*skip old description*/ X foutptr = NULL; X getdesc(false); X } X aprintf(frew,"\n\n%s\n%c",Kdesc,SDELIM); X if (textfile) { X old1='\n'; X /* copy textfile */ X txt = NULL; X if (*textfile=='-' || (txt=fopen(textfile,"r"))) { X while (txt ? (c=getc(txt))!=EOF : (c = *++textfile)) { X if (c==SDELIM) afputc(c,frew); /*double up*/ X afputc(c,frew); X old1=c; X } X if (old1!='\n') afputc('\n',frew); X if (txt) ffclose(txt); X aprintf(frew, "%c\n", SDELIM); X return; X } else { X efaterror(textfile); X } X } X /* read text from stdin */ X if (feof(stdin)) X faterror("can't reread redirected stdin for description; use -t-<description>"); X if (ttystdin()) X aputs("enter description, terminated with single '.' or end of file:\nNOTE: This is NOT the log message!\n>> ",stderr); X if ((old1=getcstdin()) != EOF) { X old2 = '\n'; X for (;;) { X if (old1=='\n' && ttystdin()) X aputs(">> ",stderr); X c = getcstdin(); X if (c==EOF) { X afputc(old1,frew); X if (old1!='\n') afputc('\n',frew); X break; X } X if (c=='\n' && old1=='.' && old2=='\n') { X break; X } X if (old1==SDELIM) afputc(old1,frew); /* double up*/ X afputc(old1,frew); X old2=old1; X old1=c; X } /* end for */ X } X aprintf(frew, "%c\n", SDELIM); X } X} END_OF_FILE if test 11524 -ne `wc -c <'src/rcsgen.c'`; then echo shar: \"'src/rcsgen.c'\" unpacked with wrong size! fi # end of 'src/rcsgen.c' fi echo shar: End of archive 9 \(of 12\). cp /dev/null ark9isdone 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.