Index: ObsoleteFiles.inc =================================================================== --- ObsoleteFiles.inc (revision 255904) +++ ObsoleteFiles.inc (working copy) @@ -38,6 +38,31 @@ # xargs -n1 | sort | uniq -d; # done + +# 20130926: removal of RCS +OLD_FILES+=usr/bin/ci +OLD_FILES+=usr/bin/co +OLD_FILES+=usr/bin/ident +OLD_FILES+=usr/bin/merge +OLD_FILES+=usr/bin/rcs +OLD_FILES+=usr/bin/rcsclean +OLD_FILES+=usr/bin/rcsdiff +OLD_FILES+=usr/bin/rcsfreeze +OLD_FILES+=usr/bin/rcsmerge +OLD_FILES+=usr/bin/rlog +OLD_FILES+=usr/share/man/man1/ci.1.gz +OLD_FILES+=usr/share/man/man1/co.1.gz +OLD_FILES+=usr/share/man/man1/ident.1.gz +OLD_FILES+=usr/share/man/man1/merge.1.gz +OLD_FILES+=usr/share/man/man1/rcs.1.gz +OLD_FILES+=usr/share/man/man1/rcsclean.1.gz +OLD_FILES+=usr/share/man/man1/rcsdiff.1.gz +OLD_FILES+=usr/share/man/man1/rcsfreeze.1.gz +OLD_FILES+=usr/share/man/man1/rcsintro.1.gz +OLD_FILES+=usr/share/man/man1/rcsmerge.1.gz +OLD_FILES+=usr/share/man/man1/rlog.1.gz +OLD_FILES+=usr/share/man/man5/rcsfile.5.gz + # 20130908: libssh becomes private OLD_FILES+=usr/lib/libssh.a OLD_FILES+=usr/lib/libssh.so Index: gnu/usr.bin/Makefile =================================================================== --- gnu/usr.bin/Makefile (revision 255904) +++ gnu/usr.bin/Makefile (working copy) @@ -12,7 +12,6 @@ SUBDIR= ${_binutils} \ ${_gperf} \ grep \ ${_groff} \ - ${_rcs} \ sdiff \ send-pr \ ${_texinfo} Index: gnu/usr.bin/rcs/CREDITS =================================================================== --- gnu/usr.bin/rcs/CREDITS (revision 255904) +++ gnu/usr.bin/rcs/CREDITS (working copy) @@ -1,24 +0,0 @@ -RCS was designed and built by Walter F. Tichy of Purdue University. -RCS version 3 was released in 1983. - -Adam Hammer, Thomas Narten, and Daniel Trinkle of Purdue supported RCS through -version 4.3, released in 1990. Guy Harris of Sun contributed many porting -fixes. Paul Eggert of System Development Corporation contributed bug fixes -and tuneups. Jay Lepreau contributed 4.3BSD support. - -Paul Eggert of Twin Sun wrote the changes for RCS versions 5.5 and 5.6 (1991). -Rich Braun of Kronos and Andy Glew of Intel contributed ideas for new options. -Bill Hahn of Stratus contributed ideas for setuid support. -Ideas for piece tables came from Joe Berkovitz of Stratus and Walter F. Tichy. -Matt Cross of Stratus contributed test case ideas. -Adam Hammer of Purdue QAed. - -Paul Eggert wrote most of the changes for this version of RCS, -currently in beta test. K. Richard Pixley of Cygnus Support -contributed several bug fixes. Robert Lupton of Princeton -and Daniel Trinkle contributed ideas for $Name expansion. -Brendan Kehoe of Cygnus Support suggested rlog's -N option. -Paul D. Smith of Data General suggested improvements in option -and error processing. Adam Hammer of Purdue QAed. - -$FreeBSD$ Index: gnu/usr.bin/rcs/Makefile =================================================================== --- gnu/usr.bin/rcs/Makefile (revision 255904) +++ gnu/usr.bin/rcs/Makefile (working copy) @@ -1,3 +0,0 @@ -SUBDIR= lib ci co ident merge rcs rcsclean rcsdiff rcsmerge rlog rcsfreeze - -.include Index: gnu/usr.bin/rcs/Makefile.inc =================================================================== --- gnu/usr.bin/rcs/Makefile.inc (revision 255904) +++ gnu/usr.bin/rcs/Makefile.inc (working copy) @@ -1,3 +0,0 @@ -# $FreeBSD$ - -LIBRCS= ${.OBJDIR}/../lib/librcs.a Index: gnu/usr.bin/rcs/NEWS =================================================================== --- gnu/usr.bin/rcs/NEWS (revision 255904) +++ gnu/usr.bin/rcs/NEWS (working copy) @@ -1,548 +0,0 @@ -Recent changes to RCS (and possible future changes) - - $FreeBSD$ - - Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - - This file is part of RCS. - - RCS is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your - option) any later version. - - RCS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RCS; see the file COPYING. - If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - - -Here is a brief summary of user-visible changes since 5.6. - - New options: - `-kb' supports binary files. - `-T' preserves the modification time of RCS files. - `-V' prints the version number. - `-zLT' causes RCS to use local time in working files and logs. - `rcsclean -n' outputs what rcsclean would do, without actually doing it. - `rlog -N' omits symbolic names. - There is a new keyword `Name'. - Inserted log lines now have the same prefix as the preceding `$Log' line. - -Most changes for RCS version 5.7 are to fix bugs and improve portability. -RCS now conforms to GNU configuration standards and to Posix 1003.1b-1993. - - -Features new to RCS version 5.7, and possibly incompatible -in minor ways with previous practice, include: - - Inserted log lines now have the same prefix as the preceding `$Log' line. - E.g. if a $Log line starts with `// $Log', log lines are prefixed with `// '. - RCS still records the (now obsolescent) comment leader inside RCS files, - but it ignores the comment leader unless it is emulating older RCS versions. - If you plan to access a file with both old and new versions of RCS, - make sure its comment leader matches its `$Log' line prefix. - For backwards compatibility with older versions of RCS, - if the log prefix is `/*' or `(*' surrounded by optional white space, - inserted log lines contain ` *' instead of `/*' or `(*'; - however, this usage is obsolescent and should not be relied on. - - $Log string `Revision' times now use the same format as other times. - - Log lines are now inserted even if -kk is specified; this simplifies merging. - - ci's -rR option (with a nonempty R) now just specifies a revision number R. - In some beta versions, it also reestablished the default behavior of - releasing a lock and removing the working file. - Now, only the bare -r option does this. - - With an empty extension, any appearance of a directory named `RCS' - in a pathname identifies the pathname as being that of an RCS file. - For example, `a/RCS/b/c' is now an RCS file with an empty extension. - Formerly, `RCS' had to be the last directory in the pathname. - - rlog's -d option by default now uses exclusive time ranges. - E.g. `rlog -d" - - for software engineering; e.g. see - . - - - - for configuration management - - - - for CVS (see below) - - -RCS and related GNU project software - - - The RCS project distribution directory also contains beta versions, - ports, and prebuilt documentation. - - - The GNU project distribution directory contains: - diffutils-N-tar.gz - the latest diffutils release; recommended for RCS - emacs-N-tar.gz - The latest Emacs release contains VC, a version-control package - that makes RCS easier to use. - make-N-tar.gz - GNU Make, which can automatically build from RCS files. - rcs-N-tar.gz - the latest RCS release - cvs-N-tar.gz - the latest official CVS release (see below) - - DOS, OS/2 ports - NT port - - -CVS - -CVS, the Concurrent Versions System, keeps tracks of source changes -made by groups of developers working on the same files concurrently, -allowing them to resync as needed. - - - - These pages have useful information about CVS. - - - CVS 1.3 is the latest released version. - - - CVS 1.4 is in alpha test, but it is recommended if you are installing CVS - for the first time, or on a recent operating system. - - DOS, OS/2 ports - NT port - - - Cyclic CVS adds network transparency to CVS; it supports efficient, - reliable, and authenticated repository access via TCP/IP. - - -Other software that uses RCS - - - Aegis manages revisions, baselines, mandatory reviews, and mandatory testing. - - - BCS, the Baseline Configuration System, - manages revisions, baselines, and staging areas. - - - ODE, the Open Software Foundation Development Environment, - manages revisions, builds, and sandboxes. - OSF uses it for their own development. - - - Odin, a `make' replacement, can build directly from arbitrary revisions - without requiring checkouts of working copies. It also handles - parallel builds on multiple remote hosts and of multiple variants. Index: gnu/usr.bin/rcs/ci/Makefile =================================================================== --- gnu/usr.bin/rcs/ci/Makefile (revision 255904) +++ gnu/usr.bin/rcs/ci/Makefile (working copy) @@ -1,8 +0,0 @@ -PROG= ci -SRCS= ci.c -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/ci/ci.1 =================================================================== --- gnu/usr.bin/rcs/ci/ci.1 (revision 255904) +++ gnu/usr.bin/rcs/ci/ci.1 (working copy) @@ -1,898 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds i \&\s-1ISO\s0 -.ds r \&\s-1RCS\s0 -.ds u \&\s-1UTC\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH CI 1 \*(Dt GNU -.SH NAME -ci \- check in RCS revisions -.SH SYNOPSIS -.B ci -.RI [ options ] " file " .\|.\|. -.SH DESCRIPTION -.B ci -stores new revisions into \*r files. -Each pathname matching an \*r suffix -is taken to be an \*r file. -All others -are assumed to be working files containing new revisions. -.B ci -deposits the contents of each working file -into the corresponding \*r file. -If only a working file is given, -.B ci -tries to find the corresponding \*r file in an \*r subdirectory -and then in the working file's directory. -For more details, see -.SM "FILE NAMING" -below. -.PP -For -.B ci -to work, the caller's login must be on the access list, -except if the access list is empty or the caller is the superuser or the -owner of the file. -To append a new revision to an existing branch, the tip revision on -that branch must be locked by the caller. Otherwise, only a -new branch can be created. This restriction is not enforced -for the owner of the file if non-strict locking is used -(see -.BR rcs (1)). -A lock held by someone else can be broken with the -.B rcs -command. -.PP -Unless the -.B \-f -option is given, -.B ci -checks whether the revision to be deposited differs from the preceding one. -If not, instead of creating a new revision -.B ci -reverts to the preceding one. -To revert, ordinary -.B ci -removes the working file and any lock; -.B "ci\ \-l" -keeps and -.B "ci\ \-u" -removes any lock, and then they both generate a new working file much as if -.B "co\ \-l" -or -.B "co\ \-u" -had been applied to the preceding revision. -When reverting, any -.B \-n -and -.B \-s -options apply to the preceding revision. -.PP -For each revision deposited, -.B ci -prompts for a log message. -The log message should summarize the change and must be terminated by -end-of-file or by a line containing -.BR \&. "\ by" -itself. -If several files are checked in -.B ci -asks whether to reuse the -previous log message. -If the standard input is not a terminal, -.B ci -suppresses the prompt -and uses the same log message for all files. -See also -.BR \-m . -.PP -If the \*r file does not exist, -.B ci -creates it and -deposits the contents of the working file as the initial revision -(default number: -.BR 1.1 ). -The access list is initialized to empty. -Instead of the log message, -.B ci -requests descriptive text (see -.B \-t -below). -.PP -The number -.I rev -of the deposited revision can be given by any of the options -.BR \-f , -.BR \-i , -.BR \-I , -.BR \-j , -.BR \-k , -.BR \-l , -.BR \-M , -.BR \-q , -.BR \-r , -or -.BR \-u . -.I rev -can be symbolic, numeric, or mixed. -Symbolic names in -.I rev -must already be defined; -see the -.B \-n -and -.B \-N -options for assigning names during checkin. -If -.I rev -is -.BR $ , -.B ci -determines the revision number from keyword values in the working file. -.PP -If -.I rev -begins with a period, -then the default branch (normally the trunk) is prepended to it. -If -.I rev -is a branch number followed by a period, -then the latest revision on that branch is used. -.PP -If -.I rev -is a revision number, it must be higher than the latest -one on the branch to which -.I rev -belongs, or must start a new branch. -.PP -If -.I rev -is a branch rather than a revision number, -the new revision is appended to that branch. The level number is obtained -by incrementing the tip revision number of that branch. -If -.I rev -indicates a non-existing branch, -that branch is created with the initial revision numbered -.IB rev .1\f1.\fP -.br -.ne 8 -.PP -If -.I rev -is omitted, -.B ci -tries to derive the new revision number from -the caller's last lock. If the caller has locked the tip revision of a branch, -the new revision is appended to that branch. -The new revision number is obtained -by incrementing the tip revision number. -If the caller locked a non-tip revision, a new branch is started at -that revision by incrementing the highest branch number at that revision. -The default initial branch and level numbers are -.BR 1 . -.PP -If -.I rev -is omitted and the caller has no lock, but owns -the file and locking -is not set to -.IR strict , -then the revision is appended to the -default branch (normally the trunk; see the -.B \-b -option of -.BR rcs (1)). -.PP -Exception: On the trunk, revisions can be appended to the end, but -not inserted. -.SH OPTIONS -.TP -.BI \-r rev -Check in revision -.IR rev . -.TP -.BR \-r -The bare -.B \-r -option (without any revision) has an unusual meaning in -.BR ci . -With other \*r commands, a bare -.B \-r -option specifies the most recent revision on the default branch, -but with -.BR ci , -a bare -.B \-r -option reestablishes the default behavior of releasing a lock and -removing the working file, and is used to override any default -.B \-l -or -.B \-u -options established by shell aliases or scripts. -.TP -.BR \-l [\f2rev\fP] -works like -.BR \-r , -except it performs an additional -.B "co\ \-l" -for the -deposited revision. Thus, the deposited revision is immediately -checked out again and locked. -This is useful for saving a revision although one wants to continue -editing it after the checkin. -.TP -.BR \-u [\f2rev\fP] -works like -.BR \-l , -except that the deposited revision is not locked. -This lets one read the working file -immediately after checkin. -.RS -.PP -The -.BR \-l , -bare -.BR \-r , -and -.B \-u -options are mutually exclusive and silently override each other. -For example, -.B "ci\ \-u\ \-r" -is equivalent to -.B "ci\ \-r" -because bare -.B \-r -overrides -.BR \-u . -.RE -.TP -.BR \-f [\f2rev\fP] -forces a deposit; the new revision is deposited even it is not different -from the preceding one. -.TP -.BR \-k [\f2rev\fP] -searches the working file for keyword values to determine its revision number, -creation date, state, and author (see -.BR co (1)), -and assigns these -values to the deposited revision, rather than computing them locally. -It also generates a default login message noting the login of the caller -and the actual checkin date. -This option is useful for software distribution. A revision that is sent to -several sites should be checked in with the -.B \-k -option at these sites to -preserve the original number, date, author, and state. -The extracted keyword values and the default log message can be overridden -with the options -.BR \-d , -.BR \-m , -.BR \-s , -.BR \-w , -and any option that carries a revision number. -.TP -.BR \-q [\f2rev\fP] -quiet mode; diagnostic output is not printed. -A revision that is not different from the preceding one is not deposited, -unless -.B \-f -is given. -.TP -.BR \-i [\f2rev\fP] -initial checkin; report an error if the \*r file already exists. -This avoids race conditions in certain applications. -.TP -.BR \-j [\f2rev\fP] -just checkin and do not initialize; -report an error if the \*r file does not already exist. -.TP -.BR \-I [\f2rev\fP] -interactive mode; -the user is prompted and questioned -even if the standard input is not a terminal. -.TP -.BR \-d "[\f2date\fP]" -uses -.I date -for the checkin date and time. -The -.I date -is specified in free format as explained in -.BR co (1). -This is useful for lying about the checkin date, and for -.B \-k -if no date is available. -If -.I date -is empty, the working file's time of last modification is used. -.TP -.BR \-M [\f2rev\fP] -Set the modification time on any new working file -to be the date of the retrieved revision. -For example, -.BI "ci\ \-d\ \-M\ \-u" "\ f" -does not alter -.IR f 's -modification time, even if -.IR f 's -contents change due to keyword substitution. -Use this option with care; it can confuse -.BR make (1). -.TP -.BI \-m "msg" -uses the string -.I msg -as the log message for all revisions checked in. -By convention, log messages that start with -.B # -are comments and are ignored by programs like GNU Emacs's -.B vc -package. -Also, log messages that start with -.BI { clumpname } -(followed by white space) are meant to be clumped together if possible, -even if they are associated with different files; the -.BI { clumpname } -label is used only for clumping, -and is not considered to be part of the log message itself. -.TP -.BI \-n "name" -assigns the symbolic name -.I name -to the number of the checked-in revision. -.B ci -prints an error message if -.I name -is already assigned to another -number. -.TP -.BI \-N "name" -same as -.BR \-n , -except that it overrides a previous assignment of -.IR name . -.TP -.BI \-s "state" -sets the state of the checked-in revision to the identifier -.IR state . -The default state is -.BR Exp . -.TP -.BI \-t file -writes descriptive text from the contents of the named -.I file -into the \*r file, -deleting the existing text. -The -.I file -cannot begin with -.BR \- . -.TP -.BI \-t\- string -Write descriptive text from the -.I string -into the \*r file, deleting the existing text. -.RS -.PP -The -.B \-t -option, in both its forms, has effect only during an initial checkin; -it is silently ignored otherwise. -.PP -During the initial checkin, if -.B \-t -is not given, -.B ci -obtains the text from standard input, -terminated by end-of-file or by a line containing -.BR \&. "\ by" -itself. -The user is prompted for the text if interaction is possible; see -.BR \-I . -.PP -For backward compatibility with older versions of \*r, a bare -.B \-t -option is ignored. -.RE -.TP -.B \-T -Set the \*r file's modification time to the new revision's time -if the former precedes the latter and there is a new revision; -preserve the \*r file's modification time otherwise. -If you have locked a revision, -.B ci -usually updates the \*r file's modification time to the current time, -because the lock is stored in the \*r file -and removing the lock requires changing the \*r file. -This can create an \*r file newer than the working file in one of two ways: -first, -.B "ci\ \-M" -can create a working file with a date before the current time; -second, when reverting to the previous revision -the \*r file can change while the working file remains unchanged. -These two cases can cause excessive recompilation caused by a -.BR make (1) -dependency of the working file on the \*r file. -The -.B \-T -option inhibits this recompilation by lying about the \*r file's date. -Use this option with care; it can suppress recompilation even when -a checkin of one working file should affect -another working file associated with the same \*r file. -For example, suppose the \*r file's time is 01:00, -the (changed) working file's time is 02:00, -some other copy of the working file has a time of 03:00, -and the current time is 04:00. -Then -.B "ci\ \-d\ \-T" -sets the \*r file's time to 02:00 instead of the usual 04:00; -this causes -.BR make (1) -to think (incorrectly) that the other copy is newer than the \*r file. -.TP -.BI \-w "login" -uses -.I login -for the author field of the deposited revision. -Useful for lying about the author, and for -.B \-k -if no author is available. -.TP -.BI \-V -Print \*r's version number. -.TP -.BI \-V n -Emulate \*r version -.IR n . -See -.BR co (1) -for details. -.TP -.BI \-x "suffixes" -specifies the suffixes for \*r files. -A nonempty suffix matches any pathname ending in the suffix. -An empty suffix matches any pathname of the form -.BI RCS/ path -or -.IB path1 /RCS/ path2. -The -.B \-x -option can specify a list of suffixes -separated by -.BR / . -For example, -.B \-x,v/ -specifies two suffixes: -.B ,v -and the empty suffix. -If two or more suffixes are specified, -they are tried in order when looking for an \*r file; -the first one that works is used for that file. -If no \*r file is found but an \*r file can be created, -the suffixes are tried in order -to determine the new \*r file's name. -The default for -.IR suffixes -is installation-dependent; normally it is -.B ,v/ -for hosts like Unix that permit commas in filenames, -and is empty (i.e. just the empty suffix) for other hosts. -.TP -.BI \-z zone -specifies the date output format in keyword substitution, -and specifies the default time zone for -.I date -in the -.BI \-d date -option. -The -.I zone -should be empty, a numeric \*u offset, or the special string -.B LT -for local time. -The default is an empty -.IR zone , -which uses the traditional \*r format of \*u without any time zone indication -and with slashes separating the parts of the date; -otherwise, times are output in \*i 8601 format with time zone indication. -For example, if local time is January 11, 1990, 8pm Pacific Standard Time, -eight hours west of \*u, -then the time is output as follows: -.RS -.LP -.RS -.nf -.ta \w'\f3\-z+05:30\fP 'u +\w'\f31990-01-11 09:30:00+05:30\fP 'u -.ne 4 -\f2option\fP \f2time output\fP -\f3\-z\fP \f31990/01/12 04:00:00\fP \f2(default)\fP -\f3\-zLT\fP \f31990-01-11 20:00:00\-08\fP -\f3\-z+05:30\fP \f31990-01-12 09:30:00+05:30\fP -.ta 4n +4n +4n +4n -.fi -.RE -.LP -The -.B \-z -option does not affect dates stored in \*r files, -which are always \*u. -.SH "FILE NAMING" -Pairs of \*r files and working files can be specified in three ways -(see also the -example section). -.PP -1) Both the \*r file and the working file are given. The \*r pathname is of -the form -.IB path1 / workfileX -and the working pathname is of the form -.IB path2 / workfile -where -.IB path1 / -and -.IB path2 / -are (possibly different or empty) paths, -.I workfile -is a filename, and -.I X -is an \*r suffix. -If -.I X -is empty, -.IB path1 / -must start with -.B RCS/ -or must contain -.BR /RCS/ . -.PP -2) Only the \*r file is given. Then the working file is created in the current -directory and its name is derived from the name of the \*r file -by removing -.IB path1 / -and the suffix -.IR X . -.PP -3) Only the working file is given. -Then -.B ci -considers each \*r suffix -.I X -in turn, looking for an \*r file of the form -.IB path2 /RCS/ workfileX -or (if the former is not found and -.I X -is nonempty) -.IB path2 / workfileX. -.PP -If the \*r file is specified without a path in 1) and 2), -.B ci -looks for the \*r file first in the directory -.B ./RCS -and then in the current -directory. -.PP -.B ci -reports an error if an attempt to open an \*r file fails for an unusual reason, -even if the \*r file's pathname is just one of several possibilities. -For example, to suppress use of \*r commands in a directory -.IR d , -create a regular file named -.IB d /RCS -so that casual attempts to use \*r commands in -.I d -fail because -.IB d /RCS -is not a directory. -.SH EXAMPLES -Suppose -.B ,v -is an \*r suffix and the current directory contains a subdirectory -.B RCS -with an \*r file -.BR io.c,v . -Then each of the following commands check in a copy of -.B io.c -into -.B RCS/io.c,v -as the latest revision, removing -.BR io.c . -.LP -.RS -.nf -.ft 3 -ci io.c; ci RCS/io.c,v; ci io.c,v; -ci io.c RCS/io.c,v; ci io.c io.c,v; -ci RCS/io.c,v io.c; ci io.c,v io.c; -.ft -.fi -.RE -.PP -Suppose instead that the empty suffix -is an \*r suffix and the current directory contains a subdirectory -.B RCS -with an \*r file -.BR io.c . -The each of the following commands checks in a new revision. -.LP -.RS -.nf -.ft 3 -ci io.c; ci RCS/io.c; -ci io.c RCS/io.c; -ci RCS/io.c io.c; -.ft -.fi -.RE -.SH "FILE MODES" -An \*r file created by -.B ci -inherits the read and execute permissions -from the working file. If the \*r file exists already, -.B ci -preserves its read and execute permissions. -.B ci -always turns off all write permissions of \*r files. -.SH FILES -Temporary files are created in the directory containing -the working file, and also in the temporary directory (see -.B \s-1TMPDIR\s0 -under -.BR \s-1ENVIRONMENT\s0 ). -A semaphore file or files are created in the directory containing the \*r file. -With a nonempty suffix, the semaphore names begin with -the first character of the suffix; therefore, do not specify an suffix -whose first character could be that of a working filename. -With an empty suffix, the semaphore names end with -.B _ -so working filenames should not end in -.BR _ . -.PP -.B ci -never changes an \*r or working file. -Normally, -.B ci -unlinks the file and creates a new one; -but instead of breaking a chain of one or more symbolic links to an \*r file, -it unlinks the destination file instead. -Therefore, -.B ci -breaks any hard or symbolic links to any working file it changes; -and hard links to \*r files are ineffective, -but symbolic links to \*r files are preserved. -.PP -The effective user must be able to -search and write the directory containing the \*r file. -Normally, the real user must be able to -read the \*r and working files -and to search and write the directory containing the working file; -however, some older hosts -cannot easily switch between real and effective users, -so on these hosts the effective user is used for all accesses. -The effective user is the same as the real user -unless your copies of -.B ci -and -.B co -have setuid privileges. -As described in the next section, -these privileges yield extra security if -the effective user owns all \*r files and directories, -and if only the effective user can write \*r directories. -.PP -Users can control access to \*r files by setting the permissions -of the directory containing the files; only users with write access -to the directory can use \*r commands to change its \*r files. -For example, in hosts that allow a user to belong to several groups, -one can make a group's \*r directories writable to that group only. -This approach suffices for informal projects, -but it means that any group member can arbitrarily change the group's \*r files, -and can even remove them entirely. -Hence more formal projects sometimes distinguish between an \*r administrator, -who can change the \*r files at will, and other project members, -who can check in new revisions but cannot otherwise change the \*r files. -.SH "SETUID USE" -To prevent anybody but their \*r administrator from deleting revisions, -a set of users can employ setuid privileges as follows. -.nr n \w'\(bu'+2n-1/1n -.ds n \nn -.if \n(.g .if r an-tag-sep .ds n \w'\(bu'u+\n[an-tag-sep]u -.IP \(bu \*n -Check that the host supports \*r setuid use. -Consult a trustworthy expert if there are any doubts. -It is best if the -.B seteuid -system call works as described in Posix 1003.1a Draft 5, -because \*r can switch back and forth easily -between real and effective users, even if the real user is -.BR root . -If not, the second best is if the -.B setuid -system call supports saved setuid -(the {\s-1_POSIX_SAVED_IDS\s0} behavior of Posix 1003.1-1990); -this fails only if the real or effective user is -.BR root . -If \*r detects any failure in setuid, it quits immediately. -.IP \(bu \nn -Choose a user -.I A -to serve as \*r administrator for the set of users. -Only -.I A -can invoke the -.B rcs -command on the users' \*r files. -.I A -should not be -.B root -or any other user with special powers. -Mutually suspicious sets of users should use different administrators. -.IP \(bu \nn -Choose a pathname -.I B -to be a directory of files to be executed by the users. -.IP \(bu \nn -Have -.I A -set up -.I B -to contain copies of -.B ci -and -.B co -that are setuid to -.I A -by copying the commands from their standard installation directory -.I D -as follows: -.LP -.RS -.nf -.ne 3 -\f3mkdir\fP \f2B\fP -\f3cp\fP \f2D\fP\^\f3/c[io]\fP \f2B\fP -\f3chmod go\-w,u+s\fP \f2B\fP\f3/c[io]\fP -.fi -.RE -.IP \(bu \nn -Have each user prepend -.I B -to their path as follows: -.LP -.RS -.nf -.ne 2 -\f3PATH=\fP\f2B\fP\f3:$PATH; export PATH\fP # ordinary shell -\f3set path=(\fP\f2B\fP \f3$path)\fP # C shell -.fi -.RE -.IP \(bu \nn -Have -.I A -create each \*r directory -.I R -with write access only to -.I A -as follows: -.LP -.RS -.nf -.ne 2 -\f3mkdir\fP \f2R\fP -\f3chmod go\-w\fP \f2R\fP -.fi -.RE -.IP \(bu \nn -If you want to let only certain users read the \*r files, -put the users into a group -.IR G , -and have -.I A -further protect the \*r directory as follows: -.LP -.RS -.nf -.ne 2 -\f3chgrp\fP \f2G R\fP -\f3chmod g\-w,o\-rwx\fP \f2R\fP -.fi -.RE -.IP \(bu \nn -Have -.I A -copy old \*r files (if any) into -.IR R , -to ensure that -.I A -owns them. -.IP \(bu \nn -An \*r file's access list limits who can check in and lock revisions. -The default access list is empty, -which grants checkin access to anyone who can read the \*r file. -If you want limit checkin access, -have -.I A -invoke -.B "rcs\ \-a" -on the file; see -.BR rcs (1). -In particular, -.BI "rcs\ \-e\ \-a" A -limits access to just -.IR A . -.IP \(bu \nn -Have -.I A -initialize any new \*r files with -.B "rcs\ \-i" -before initial checkin, adding the -.B \-a -option if you want to limit checkin access. -.IP \(bu \nn -Give setuid privileges only to -.BR ci , -.BR co , -and -.BR rcsclean ; -do not give them to -.B rcs -or to any other command. -.IP \(bu \nn -Do not use other setuid commands to invoke \*r commands; -setuid is trickier than you think! -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -A backslash escapes spaces within an option. -The -.B \s-1RCSINIT\s0 -options are prepended to the argument lists of most \*r commands. -Useful -.B \s-1RCSINIT\s0 -options include -.BR \-q , -.BR \-V , -.BR \-x , -and -.BR \-z . -.TP -.B \s-1TMPDIR\s0 -Name of the temporary directory. -If not set, the environment variables -.B \s-1TMP\s0 -and -.B \s-1TEMP\s0 -are inspected instead and the first value found is taken; -if none of them are set, -a host-dependent default is used, typically -.BR /tmp . -.SH DIAGNOSTICS -For each revision, -.B ci -prints the \*r file, the working file, and the number -of both the deposited and the preceding revision. -The exit status is zero if and only if all operations were successful. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH "SEE ALSO" -co(1), -ident(1), make(1), rcs(1), rcsclean(1), rcsdiff(1), -rcsintro(1), rcsmerge(1), rlog(1), setuid(2), rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.br Index: gnu/usr.bin/rcs/ci/ci.c =================================================================== --- gnu/usr.bin/rcs/ci/ci.c (revision 255904) +++ gnu/usr.bin/rcs/ci/ci.c (working copy) @@ -1,1318 +0,0 @@ -/* Check in revisions of RCS files from working files. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.30 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.29 1995/06/01 16:23:43 eggert - * (main): Add -kb. - * Use `cmpdate', not `cmpnum', to compare dates. - * This is for MKS RCS's incompatible 20th-century date format. - * Don't worry about errno after ftruncate fails. - * Fix input file rewinding bug when large_memory && !maps_memory - * and checking in a branch tip. - * - * (fixwork): Fall back on chmod if fchmod fails, since it might be ENOSYS. - * - * Revision 5.28 1994/03/20 04:52:58 eggert - * Do not generate a corrupted RCS file if the user modifies the working file - * while `ci' is running. - * Do not remove the lock when `ci -l' reverts. - * Move buffer-flushes out of critical sections, since they aren't critical. - * Use ORCSerror to clean up after a fatal error. - * Specify subprocess input via file descriptor, not file name. - * - * Revision 5.27 1993/11/09 17:40:15 eggert - * -V now prints version on stdout and exits. Don't print usage twice. - * - * Revision 5.26 1993/11/03 17:42:27 eggert - * Add -z. Don't subtract from RCS file timestamp even if -T. - * Scan for and use Name keyword if -k. - * Don't discard ignored phrases. Improve quality of diagnostics. - * - * Revision 5.25 1992/07/28 16:12:44 eggert - * Add -i, -j, -V. Check that working and RCS files are distinct. - * - * Revision 5.24 1992/02/17 23:02:06 eggert - * `-rREV' now just specifies a revision REV; only bare `-r' reverts to default. - * Add -T. - * - * Revision 5.23 1992/01/27 16:42:51 eggert - * Always unlock branchpoint if caller has a lock. - * Add support for bad_chmod_close, bad_creat0. lint -> RCS_lint - * - * Revision 5.22 1992/01/06 02:42:34 eggert - * Invoke utime() before chmod() to keep some buggy systems happy. - * - * Revision 5.21 1991/11/20 17:58:07 eggert - * Don't read the delta tree from a nonexistent RCS file. - * - * Revision 5.20 1991/10/07 17:32:46 eggert - * Fix log bugs. Remove lint. - * - * Revision 5.19 1991/09/26 23:10:30 eggert - * Plug file descriptor leak. - * - * Revision 5.18 1991/09/18 07:29:10 eggert - * Work around a common ftruncate() bug. - * - * Revision 5.17 1991/09/10 22:15:46 eggert - * Fix test for redirected stdin. - * - * Revision 5.16 1991/08/19 23:17:54 eggert - * When there are no changes, revert to previous revision instead of aborting. - * Add piece tables, -M, -r$. Tune. - * - * Revision 5.15 1991/04/21 11:58:14 eggert - * Ensure that working file is newer than RCS file after ci -[lu]. - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.14 1991/02/28 19:18:47 eggert - * Don't let a setuid ci create a new RCS file; rcs -i -a must be run first. - * Fix ci -ko -l mode bug. Open work file at most once. - * - * Revision 5.13 1991/02/25 07:12:33 eggert - * getdate -> getcurdate (SVR4 name clash) - * - * Revision 5.12 1990/12/31 01:00:12 eggert - * Don't use uninitialized storage when handling -{N,n}. - * - * Revision 5.11 1990/12/04 05:18:36 eggert - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.10 1990/11/05 20:30:10 eggert - * Don't remove working file when aborting due to no changes. - * - * Revision 5.9 1990/11/01 05:03:23 eggert - * Add -I and new -t behavior. Permit arbitrary data in logs. - * - * Revision 5.8 1990/10/04 06:30:09 eggert - * Accumulate exit status across files. - * - * Revision 5.7 1990/09/25 20:11:46 hammer - * fixed another small typo - * - * Revision 5.6 1990/09/24 21:48:50 hammer - * added cleanups from Paul Eggert. - * - * Revision 5.5 1990/09/21 06:16:38 hammer - * made it handle multiple -{N,n}'s. Also, made it treat re-directed stdin - * the same as the terminal - * - * Revision 5.4 1990/09/20 02:38:51 eggert - * ci -k now checks dates more thoroughly. - * - * Revision 5.3 1990/09/11 02:41:07 eggert - * Fix revision bug with `ci -k file1 file2'. - * - * Revision 5.2 1990/09/04 08:02:10 eggert - * Permit adjacent revisions with identical time stamps (possible on fast hosts). - * Improve incomplete line handling. Standardize yes-or-no procedure. - * - * Revision 5.1 1990/08/29 07:13:44 eggert - * Expand locker value like co. Clean old log messages too. - * - * Revision 5.0 1990/08/22 08:10:00 eggert - * Don't require a final newline. - * Make lock and temp files faster and safer. - * Remove compile-time limits; use malloc instead. - * Permit dates past 1999/12/31. Switch to GMT. - * Add setuid support. Don't pass +args to diff. Check diff's output. - * Ansify and Posixate. Add -k, -V. Remove snooping. Tune. - * Check diff's output. - * - * Revision 4.9 89/05/01 15:10:54 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.8 88/11/08 13:38:23 narten - * changes from root@seismo.CSS.GOV (Super User) - * -d with no arguments uses the mod time of the file it is checking in - * - * Revision 4.7 88/08/09 19:12:07 eggert - * Make sure workfile is a regular file; use its mode if RCSfile doesn't have one. - * Use execv(), not system(); allow cc -R; remove lint. - * isatty(fileno(stdin)) -> ttystdin() - * - * Revision 4.6 87/12/18 11:34:41 narten - * lint cleanups (from Guy Harris) - * - * Revision 4.5 87/10/18 10:18:48 narten - * Updating version numbers. Changes relative to revision 1.1 are actually - * relative to 4.3 - * - * Revision 1.3 87/09/24 13:57:19 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:21:33 jenkins - * Port to suns - * - * Revision 4.3 83/12/15 12:28:54 wft - * ci -u and ci -l now set mode of working file properly. - * - * Revision 4.2 83/12/05 13:40:54 wft - * Merged with 3.9.1.1: added calls to clearerr(stdin). - * made rewriteflag external. - * - * Revision 4.1 83/05/10 17:03:06 wft - * Added option -d and -w, and updated assingment of date, etc. to new delta. - * Added handling of default branches. - * Option -k generates std. log message; fixed undef. pointer in reading of log. - * Replaced getlock() with findlock(), link--unlink with rename(), - * getpwuid() with getcaller(). - * Moved all revision number generation to new routine addelta(). - * Removed calls to stat(); now done by pairfilenames(). - * Changed most calls to catchints() with restoreints(). - * Directed all interactive messages to stderr. - * - * Revision 3.9.1.1 83/10/19 04:21:03 lepreau - * Added clearerr(stdin) to getlogmsg() for re-reading stdin. - * - * Revision 3.9 83/02/15 15:25:44 wft - * 4.2 prerelease - * - * Revision 3.9 83/02/15 15:25:44 wft - * Added call to fastcopy() to copy remainder of RCS file. - * - * Revision 3.8 83/01/14 15:34:05 wft - * Added ignoring of interrupts while new RCS file is renamed; - * Avoids deletion of RCS files by interrupts. - * - * Revision 3.7 82/12/10 16:09:20 wft - * Corrected checking of return code from diff. - * - * Revision 3.6 82/12/08 21:34:49 wft - * Using DATEFORM to prepare date of checked-in revision; - * Fixed return from addbranch(). - * - * Revision 3.5 82/12/04 18:32:42 wft - * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE. Updated - * field lockedby in removelock(), moved getlogmsg() before calling diff. - * - * Revision 3.4 82/12/02 13:27:13 wft - * added option -k. - * - * Revision 3.3 82/11/28 20:53:31 wft - * Added mustcheckin() to check for redundant checkins. - * Added xpandfile() to do keyword expansion for -u and -l; - * -m appends linefeed to log message if necessary. - * getlogmsg() suppresses prompt if stdin is not a terminal. - * Replaced keeplock with lockflag, fclose() with ffclose(), - * %02d with %.2d, getlogin() with getpwuid(). - * - * Revision 3.2 82/10/18 20:57:23 wft - * An RCS file inherits its mode during the first ci from the working file, - * otherwise it stays the same, except that write permission is removed. - * Fixed ci -l, added ci -u (both do an implicit co after the ci). - * Fixed call to getlogin(), added call to getfullRCSname(), added check - * for write error. - * Changed conflicting identifiers. - * - * Revision 3.1 82/10/13 16:04:59 wft - * fixed type of variables receiving from getc() (char -> int). - * added include file dbm.h for getting BYTESIZ. This is used - * to check the return code from diff portably. - */ - -#include "rcsbase.h" - -struct Symrev { - char const *ssymbol; - int override; - struct Symrev * nextsym; -}; - -static char const *getcurdate P((void)); -static int addbranch P((struct hshentry*,struct buf*,int)); -static int addelta P((void)); -static int addsyms P((char const*)); -static int fixwork P((mode_t,time_t)); -static int removelock P((struct hshentry*)); -static int xpandfile P((RILE*,struct hshentry const*,char const**,int)); -static struct cbuf getlogmsg P((void)); -static void cleanup P((void)); -static void incnum P((char const*,struct buf*)); -static void addassoclst P((int,char const*)); - -static FILE *exfile; -static RILE *workptr; /* working file pointer */ -static struct buf newdelnum; /* new revision number */ -static struct cbuf msg; -static int exitstatus; -static int forceciflag; /* forces check in */ -static int keepflag, keepworkingfile, rcsinitflag; -static struct hshentries *gendeltas; /* deltas to be generated */ -static struct hshentry *targetdelta; /* old delta to be generated */ -static struct hshentry newdelta; /* new delta to be inserted */ -static struct stat workstat; -static struct Symrev *assoclst, **nextassoc; - -mainProg(ciId, "ci", "$FreeBSD$") -{ - static char const cmdusage[] = - "\nci usage: ci -{fIklMqru}[rev] -d[date] -mmsg -{nN}name -sstate -ttext -T -Vn -wwho -xsuff -zzone file ..."; - static char const default_state[] = DEFAULTSTATE; - - char altdate[datesize]; - char olddate[datesize]; - char newdatebuf[datesize + zonelenmax]; - char targetdatebuf[datesize + zonelenmax]; - char *a, **newargv, *textfile; - char const *author, *krev, *rev, *state; - char const *diffname, *expname; - char const *newworkname; - int initflag, mustread; - int lockflag, lockthis, mtimeflag, removedlock, Ttimeflag; - int r; - int changedRCS, changework, dolog, newhead; - int usestatdate; /* Use mod time of file for -d. */ - mode_t newworkmode; /* mode for working file */ - time_t mtime, wtime; - struct hshentry *workdelta; - - setrid(); - - author = rev = state = textfile = 0; - initflag = lockflag = mustread = false; - mtimeflag = false; - Ttimeflag = false; - altdate[0]= '\0'; /* empty alternate date for -d */ - usestatdate=false; - suffixes = X_DEFAULT; - nextassoc = &assoclst; - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - while (a = *++argv, 0<--argc && *a++=='-') { - switch (*a++) { - - case 'r': - if (*a) - goto revno; - keepworkingfile = lockflag = false; - break; - - case 'l': - keepworkingfile = lockflag = true; - revno: - if (*a) { - if (rev) warn("redefinition of revision number"); - rev = a; - } - break; - - case 'u': - keepworkingfile=true; lockflag=false; - goto revno; - - case 'i': - initflag = true; - goto revno; - - case 'j': - mustread = true; - goto revno; - - case 'I': - interactiveflag = true; - goto revno; - - case 'q': - quietflag=true; - goto revno; - - case 'f': - forceciflag=true; - goto revno; - - case 'k': - keepflag=true; - goto revno; - - case 'm': - if (msg.size) redefined('m'); - msg = cleanlogmsg(a, strlen(a)); - if (!msg.size) - error("missing message for -m option"); - break; - - case 'n': - if (!*a) { - error("missing symbolic name after -n"); - break; - } - checkssym(a); - addassoclst(false, a); - break; - - case 'N': - if (!*a) { - error("missing symbolic name after -N"); - break; - } - checkssym(a); - addassoclst(true, a); - break; - - case 's': - if (*a) { - if (state) redefined('s'); - checksid(a); - state = a; - } else - error("missing state for -s option"); - break; - - case 't': - if (*a) { - if (textfile) redefined('t'); - textfile = a; - } - break; - - case 'd': - if (altdate[0] || usestatdate) - redefined('d'); - altdate[0] = '\0'; - if (!(usestatdate = !*a)) - str2date(a, altdate); - break; - - case 'M': - mtimeflag = true; - goto revno; - - case 'w': - if (*a) { - if (author) redefined('w'); - checksid(a); - author = a; - } else - error("missing author for -w option"); - break; - - case 'x': - suffixes = a; - break; - - case 'V': - setRCSversion(*argv); - break; - - case 'z': - zone_set(a); - break; - - case 'T': - if (!*a) { - Ttimeflag = true; - break; - } - /* fall into */ - default: - error("unknown option: %s%s", *argv, cmdusage); - }; - } /* end processing of options */ - - /* Handle all pathnames. */ - if (nerror) cleanup(); - else if (argc < 1) faterror("no input file%s", cmdusage); - else for (; 0 < argc; cleanup(), ++argv, --argc) { - targetdelta = 0; - ffree(); - - switch (pairnames(argc, argv, rcswriteopen, mustread, false)) { - - case -1: /* New RCS file */ -# if has_setuid && has_getuid - if (euid() != ruid()) { - workerror("setuid initial checkin prohibited; use `rcs -i -a' first"); - continue; - } -# endif - rcsinitflag = true; - break; - - case 0: /* Error */ - continue; - - case 1: /* Normal checkin with prev . RCS file */ - if (initflag) { - rcserror("already exists"); - continue; - } - rcsinitflag = !Head; - } - - /* - * RCSname contains the name of the RCS file, and - * workname contains the name of the working file. - * If the RCS file exists, finptr contains the file descriptor for the - * RCS file, and RCSstat is set. The admin node is initialized. - */ - - diagnose("%s <-- %s\n", RCSname, workname); - - if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) { - eerror(workname); - continue; - } - - if (finptr) { - if (same_file(RCSstat, workstat, 0)) { - rcserror("RCS file is the same as working file %s.", - workname - ); - continue; - } - if (!checkaccesslist()) - continue; - } - - krev = rev; - if (keepflag) { - /* get keyword values from working file */ - if (!getoldkeys(workptr)) continue; - if (!rev && !*(krev = prevrev.string)) { - workerror("can't find a revision number"); - continue; - } - if (!*prevdate.string && *altdate=='\0' && usestatdate==false) - workwarn("can't find a date"); - if (!*prevauthor.string && !author) - workwarn("can't find an author"); - if (!*prevstate.string && !state) - workwarn("can't find a state"); - } /* end processing keepflag */ - - /* Read the delta tree. */ - if (finptr) - gettree(); - - /* expand symbolic revision number */ - if (!fexpandsym(krev, &newdelnum, workptr)) - continue; - - /* splice new delta into tree */ - if ((removedlock = addelta()) < 0) - continue; - - newdelta.num = newdelnum.string; - newdelta.branches = 0; - newdelta.lockedby = 0; /* This might be changed by addlock(). */ - newdelta.selector = true; - newdelta.name = 0; - clear_buf(&newdelta.ig); - clear_buf(&newdelta.igtext); - /* set author */ - if (author) - newdelta.author=author; /* set author given by -w */ - else if (keepflag && *prevauthor.string) - newdelta.author=prevauthor.string; /* preserve old author if possible*/ - else newdelta.author=getcaller();/* otherwise use caller's id */ - newdelta.state = default_state; - if (state) - newdelta.state=state; /* set state given by -s */ - else if (keepflag && *prevstate.string) - newdelta.state=prevstate.string; /* preserve old state if possible */ - if (usestatdate) { - time2date(workstat.st_mtime, altdate); - } - if (*altdate!='\0') - newdelta.date=altdate; /* set date given by -d */ - else if (keepflag && *prevdate.string) { - /* Preserve old date if possible. */ - str2date(prevdate.string, olddate); - newdelta.date = olddate; - } else - newdelta.date = getcurdate(); /* use current date */ - /* now check validity of date -- needed because of -d and -k */ - if (targetdelta && - cmpdate(newdelta.date,targetdelta->date) < 0) { - rcserror("Date %s precedes %s in revision %s.", - date2str(newdelta.date, newdatebuf), - date2str(targetdelta->date, targetdatebuf), - targetdelta->num - ); - continue; - } - - - if (lockflag && addlock(&newdelta, true) < 0) continue; - - if (keepflag && *prevname.string) - if (addsymbol(newdelta.num, prevname.string, false) < 0) - continue; - if (!addsyms(newdelta.num)) - continue; - - - putadmin(); - puttree(Head,frewrite); - putdesc(false,textfile); - - changework = Expand < MIN_UNCHANGED_EXPAND; - dolog = true; - lockthis = lockflag; - workdelta = &newdelta; - - /* build rest of file */ - if (rcsinitflag) { - diagnose("initial revision: %s\n", newdelta.num); - /* get logmessage */ - newdelta.log=getlogmsg(); - putdftext(&newdelta, workptr, frewrite, false); - RCSstat.st_mode = workstat.st_mode; - RCSstat.st_nlink = 0; - changedRCS = true; - } else { - diffname = maketemp(0); - newhead = Head == &newdelta; - if (!newhead) - foutptr = frewrite; - expname = buildrevision( - gendeltas, targetdelta, (FILE*)0, false - ); - if ( - !forceciflag && - strcmp(newdelta.state, targetdelta->state) == 0 && - (changework = rcsfcmp( - workptr, &workstat, expname, targetdelta - )) <= 0 - ) { - diagnose("file is unchanged; reverting to previous revision %s\n", - targetdelta->num - ); - if (removedlock < lockflag) { - diagnose("previous revision was not locked; ignoring -l option\n"); - lockthis = 0; - } - dolog = false; - if (! (changedRCS = lockflagnum, (char*)0, (char*)0, (char*)0, - &gendeltas - ))) - continue; - workdelta->log = targetdelta->log; - if (newdelta.state != default_state) - workdelta->state = newdelta.state; - if (lockthisnum)) - continue; - if (dorewrite(true, true) != 0) - continue; - fastcopy(finptr, frewrite); - if (bad_truncate) - while (ftell(frewrite) < hwm) - /* White out any earlier mistake with '\n's. */ - /* This is unlikely. */ - afputc('\n', frewrite); - } - } else { - int wfd = Ifileno(workptr); - struct stat checkworkstat; - char const *diffv[6 + !!OPEN_O_BINARY], **diffp; -# if large_memory && !maps_memory - FILE *wfile = workptr->stream; - long wfile_off; -# endif -# if !has_fflush_input && !(large_memory && maps_memory) - off_t wfd_off; -# endif - - diagnose("new revision: %s; previous revision: %s\n", - newdelta.num, targetdelta->num - ); - newdelta.log = getlogmsg(); -# if !large_memory - Irewind(workptr); -# if has_fflush_input - if (fflush(workptr) != 0) - Ierror(); -# endif -# else -# if !maps_memory - if ( - (wfile_off = ftell(wfile)) == -1 - || fseek(wfile, 0L, SEEK_SET) != 0 -# if has_fflush_input - || fflush(wfile) != 0 -# endif - ) - Ierror(); -# endif -# endif -# if !has_fflush_input && !(large_memory && maps_memory) - wfd_off = lseek(wfd, (off_t)0, SEEK_CUR); - if (wfd_off == -1 - || (wfd_off != 0 - && lseek(wfd, (off_t)0, SEEK_SET) != 0)) - Ierror(); -# endif - diffp = diffv; - *++diffp = DIFF; - *++diffp = DIFFFLAGS; -# if OPEN_O_BINARY - if (Expand == BINARY_EXPAND) - *++diffp = "--binary"; -# endif - *++diffp = newhead ? "-" : expname; - *++diffp = newhead ? expname : "-"; - *++diffp = 0; - switch (runv(wfd, diffname, diffv)) { - case DIFF_FAILURE: case DIFF_SUCCESS: break; - default: rcsfaterror("diff failed"); - } -# if !has_fflush_input && !(large_memory && maps_memory) - if (lseek(wfd, wfd_off, SEEK_CUR) == -1) - Ierror(); -# endif -# if large_memory && !maps_memory - if (fseek(wfile, wfile_off, SEEK_SET) != 0) - Ierror(); -# endif - if (newhead) { - Irewind(workptr); - putdftext(&newdelta, workptr, frewrite, false); - if (!putdtext(targetdelta,diffname,frewrite,true)) continue; - } else - if (!putdtext(&newdelta,diffname,frewrite,true)) continue; - - /* - * Check whether the working file changed during checkin, - * to avoid producing an inconsistent RCS file. - */ - if ( - fstat(wfd, &checkworkstat) != 0 - || workstat.st_mtime != checkworkstat.st_mtime - || workstat.st_size != checkworkstat.st_size - ) { - workerror("file changed during checkin"); - continue; - } - - changedRCS = true; - } - } - - /* Deduce time_t of new revision if it is needed later. */ - wtime = (time_t)-1; - if (mtimeflag | Ttimeflag) - wtime = date2time(workdelta->date); - - if (donerewrite(changedRCS, - !Ttimeflag ? (time_t)-1 - : finptr && wtime < RCSstat.st_mtime ? RCSstat.st_mtime - : wtime - ) != 0) - continue; - - if (!keepworkingfile) { - Izclose(&workptr); - r = un_link(workname); /* Get rid of old file */ - } else { - newworkmode = WORKMODE(RCSstat.st_mode, - ! (Expand==VAL_EXPAND || lockthis < StrictLocks) - ); - mtime = mtimeflag ? wtime : (time_t)-1; - - /* Expand if it might change or if we can't fix mode, time. */ - if (changework || (r=fixwork(newworkmode,mtime)) != 0) { - Irewind(workptr); - /* Expand keywords in file. */ - locker_expansion = lockthis; - workdelta->name = - namedrev( - assoclst ? assoclst->ssymbol - : keepflag && *prevname.string ? prevname.string - : rev, - workdelta - ); - switch (xpandfile( - workptr, workdelta, &newworkname, dolog - )) { - default: - continue; - - case 0: - /* - * No expansion occurred; try to reuse working file - * unless we already tried and failed. - */ - if (changework) - if ((r=fixwork(newworkmode,mtime)) == 0) - break; - /* fall into */ - case 1: - Izclose(&workptr); - aflush(exfile); - ignoreints(); - r = chnamemod(&exfile, newworkname, - workname, 1, newworkmode, mtime - ); - keepdirtemp(newworkname); - restoreints(); - } - } - } - if (r != 0) { - eerror(workname); - continue; - } - diagnose("done\n"); - - } - - tempunlink(); - exitmain(exitstatus); -} /* end of main (ci) */ - - static void -cleanup() -{ - if (nerror) exitstatus = EXIT_FAILURE; - Izclose(&finptr); - Izclose(&workptr); - Ozclose(&exfile); - Ozclose(&fcopy); - ORCSclose(); - dirtempunlink(); -} - -#if RCS_lint -# define exiterr ciExit -#endif - void -exiterr() -{ - ORCSerror(); - dirtempunlink(); - tempunlink(); - _exit(EXIT_FAILURE); -} - -/*****************************************************************/ -/* the rest are auxiliary routines */ - - - static int -addelta() -/* Function: Appends a delta to the delta tree, whose number is - * given by newdelnum. Updates Head, newdelnum, newdelnumlength, - * and the links in newdelta. - * Return -1 on error, 1 if a lock is removed, 0 otherwise. - */ -{ - register char *tp; - register int i; - int removedlock; - int newdnumlength; /* actual length of new rev. num. */ - - newdnumlength = countnumflds(newdelnum.string); - - if (rcsinitflag) { - /* this covers non-existing RCS file and a file initialized with rcs -i */ - if (newdnumlength==0 && Dbranch) { - bufscpy(&newdelnum, Dbranch); - newdnumlength = countnumflds(Dbranch); - } - if (newdnumlength==0) bufscpy(&newdelnum, "1.1"); - else if (newdnumlength==1) bufscat(&newdelnum, ".1"); - else if (newdnumlength>2) { - rcserror("Branch point doesn't exist for revision %s.", - newdelnum.string - ); - return -1; - } /* newdnumlength == 2 is OK; */ - Head = &newdelta; - newdelta.next = 0; - return 0; - } - if (newdnumlength==0) { - /* derive new revision number from locks */ - switch (findlock(true, &targetdelta)) { - - default: - /* found two or more old locks */ - return -1; - - case 1: - /* found an old lock */ - /* check whether locked revision exists */ - if (!genrevs(targetdelta->num,(char*)0,(char*)0,(char*)0,&gendeltas)) - return -1; - if (targetdelta==Head) { - /* make new head */ - newdelta.next=Head; - Head= &newdelta; - } else if (!targetdelta->next && countnumflds(targetdelta->num)>2) { - /* new tip revision on side branch */ - targetdelta->next= &newdelta; - newdelta.next = 0; - } else { - /* middle revision; start a new branch */ - bufscpy(&newdelnum, ""); - return addbranch(targetdelta, &newdelnum, 1); - } - incnum(targetdelta->num, &newdelnum); - return 1; /* successful use of existing lock */ - - case 0: - /* no existing lock; try Dbranch */ - /* update newdelnum */ - if (StrictLocks || !myself(RCSstat.st_uid)) { - rcserror("no lock set by %s", getcaller()); - return -1; - } - if (Dbranch) { - bufscpy(&newdelnum, Dbranch); - } else { - incnum(Head->num, &newdelnum); - } - newdnumlength = countnumflds(newdelnum.string); - /* now fall into next statement */ - } - } - if (newdnumlength<=2) { - /* add new head per given number */ - if(newdnumlength==1) { - /* make a two-field number out of it*/ - if (cmpnumfld(newdelnum.string,Head->num,1)==0) - incnum(Head->num, &newdelnum); - else - bufscat(&newdelnum, ".1"); - } - if (cmpnum(newdelnum.string,Head->num) <= 0) { - rcserror("revision %s too low; must be higher than %s", - newdelnum.string, Head->num - ); - return -1; - } - targetdelta = Head; - if (0 <= (removedlock = removelock(Head))) { - if (!genrevs(Head->num,(char*)0,(char*)0,(char*)0,&gendeltas)) - return -1; - newdelta.next = Head; - Head = &newdelta; - } - return removedlock; - } else { - /* put new revision on side branch */ - /*first, get branch point */ - tp = newdelnum.string; - for (i = newdnumlength - ((newdnumlength&1) ^ 1); --i; ) - while (*tp++ != '.') - continue; - *--tp = 0; /* Kill final dot to get old delta temporarily. */ - if (!(targetdelta=genrevs(newdelnum.string,(char*)0,(char*)0,(char*)0,&gendeltas))) - return -1; - if (cmpnum(targetdelta->num, newdelnum.string) != 0) { - rcserror("can't find branch point %s", newdelnum.string); - return -1; - } - *tp = '.'; /* Restore final dot. */ - return addbranch(targetdelta, &newdelnum, 0); - } -} - - - - static int -addbranch(branchpoint, num, removedlock) - struct hshentry *branchpoint; - struct buf *num; - int removedlock; -/* adds a new branch and branch delta at branchpoint. - * If num is the null string, appends the new branch, incrementing - * the highest branch number (initially 1), and setting the level number to 1. - * the new delta and branchhead are in globals newdelta and newbranch, resp. - * the new number is placed into num. - * Return -1 on error, 1 if a lock is removed, 0 otherwise. - * If REMOVEDLOCK is 1, a lock was already removed. - */ -{ - struct branchhead *bhead, **btrail; - struct buf branchnum; - int result; - int field, numlength; - static struct branchhead newbranch; /* new branch to be inserted */ - - numlength = countnumflds(num->string); - - if (!branchpoint->branches) { - /* start first branch */ - branchpoint->branches = &newbranch; - if (numlength==0) { - bufscpy(num, branchpoint->num); - bufscat(num, ".1.1"); - } else if (numlength&1) - bufscat(num, ".1"); - newbranch.nextbranch = 0; - - } else if (numlength==0) { - /* append new branch to the end */ - bhead=branchpoint->branches; - while (bhead->nextbranch) bhead=bhead->nextbranch; - bhead->nextbranch = &newbranch; - bufautobegin(&branchnum); - getbranchno(bhead->hsh->num, &branchnum); - incnum(branchnum.string, num); - bufautoend(&branchnum); - bufscat(num, ".1"); - newbranch.nextbranch = 0; - } else { - /* place the branch properly */ - field = numlength - ((numlength&1) ^ 1); - /* field of branch number */ - btrail = &branchpoint->branches; - while (0 < (result=cmpnumfld(num->string,(*btrail)->hsh->num,field))) { - btrail = &(*btrail)->nextbranch; - if (!*btrail) { - result = -1; - break; - } - } - if (result < 0) { - /* insert/append new branchhead */ - newbranch.nextbranch = *btrail; - *btrail = &newbranch; - if (numlength&1) bufscat(num, ".1"); - } else { - /* branch exists; append to end */ - bufautobegin(&branchnum); - getbranchno(num->string, &branchnum); - targetdelta = genrevs( - branchnum.string, (char*)0, (char*)0, (char*)0, - &gendeltas - ); - bufautoend(&branchnum); - if (!targetdelta) - return -1; - if (cmpnum(num->string,targetdelta->num) <= 0) { - rcserror("revision %s too low; must be higher than %s", - num->string, targetdelta->num - ); - return -1; - } - if (!removedlock - && 0 <= (removedlock = removelock(targetdelta)) - ) { - if (numlength&1) - incnum(targetdelta->num,num); - targetdelta->next = &newdelta; - newdelta.next = 0; - } - return removedlock; - /* Don't do anything to newbranch. */ - } - } - newbranch.hsh = &newdelta; - newdelta.next = 0; - if (branchpoint->lockedby) - if (strcmp(branchpoint->lockedby, getcaller()) == 0) - return removelock(branchpoint); /* This returns 1. */ - return removedlock; -} - - static int -addsyms(num) - char const *num; -{ - register struct Symrev *p; - - for (p = assoclst; p; p = p->nextsym) - if (addsymbol(num, p->ssymbol, p->override) < 0) - return false; - return true; -} - - - static void -incnum(onum,nnum) - char const *onum; - struct buf *nnum; -/* Increment the last field of revision number onum by one and - * place the result into nnum. - */ -{ - register char *tp, *np; - register size_t l; - - l = strlen(onum); - bufalloc(nnum, l+2); - np = tp = nnum->string; - VOID strcpy(np, onum); - for (tp = np + l; np != tp; ) - if (isdigit(*--tp)) { - if (*tp != '9') { - ++*tp; - return; - } - *tp = '0'; - } else { - tp++; - break; - } - /* We changed 999 to 000; now change it to 1000. */ - *tp = '1'; - tp = np + l; - *tp++ = '0'; - *tp = 0; -} - - - - static int -removelock(delta) -struct hshentry * delta; -/* function: Finds the lock held by caller on delta, - * removes it, and returns nonzero if successful. - * Print an error message and return -1 if there is no such lock. - * An exception is if !StrictLocks, and caller is the owner of - * the RCS file. If caller does not have a lock in this case, - * return 0; return 1 if a lock is actually removed. - */ -{ - register struct rcslock *next, **trail; - char const *num; - - num=delta->num; - for (trail = &Locks; (next = *trail); trail = &next->nextlock) - if (next->delta == delta) - if (strcmp(getcaller(), next->login) == 0) { - /* We found a lock on delta by caller; delete it. */ - *trail = next->nextlock; - delta->lockedby = 0; - return 1; - } else { - rcserror("revision %s locked by %s", num, next->login); - return -1; - } - if (!StrictLocks && myself(RCSstat.st_uid)) - return 0; - rcserror("no lock set by %s for revision %s", getcaller(), num); - return -1; -} - - - - static char const * -getcurdate() -/* Return a pointer to the current date. */ -{ - static char buffer[datesize]; /* date buffer */ - - if (!buffer[0]) - time2date(now(), buffer); - return buffer; -} - - static int -#if has_prototypes -fixwork(mode_t newworkmode, time_t mtime) - /* The `#if has_prototypes' is needed because mode_t might promote to int. */ -#else - fixwork(newworkmode, mtime) - mode_t newworkmode; - time_t mtime; -#endif -{ - return - 1 < workstat.st_nlink - || (newworkmode&S_IWUSR && !myself(workstat.st_uid)) - || setmtime(workname, mtime) != 0 - ? -1 - : workstat.st_mode == newworkmode ? 0 -#if has_fchmod - : fchmod(Ifileno(workptr), newworkmode) == 0 ? 0 -#endif -#if bad_chmod_close - : -1 -#else - : chmod(workname, newworkmode) -#endif - ; -} - - static int -xpandfile(unexfile, delta, exname, dolog) - RILE *unexfile; - struct hshentry const *delta; - char const **exname; - int dolog; -/* - * Read unexfile and copy it to a - * file, performing keyword substitution with data from delta. - * Return -1 if unsuccessful, 1 if expansion occurred, 0 otherwise. - * If successful, stores the stream descriptor into *EXFILEP - * and its name into *EXNAME. - */ -{ - char const *targetname; - int e, r; - - targetname = makedirtemp(1); - if (!(exfile = fopenSafer(targetname, FOPEN_W_WORK))) { - eerror(targetname); - workerror("can't build working file"); - return -1; - } - r = 0; - if (MIN_UNEXPAND <= Expand) - fastcopy(unexfile,exfile); - else { - for (;;) { - e = expandline( - unexfile, exfile, delta, false, (FILE*)0, dolog - ); - if (e < 0) - break; - r |= e; - if (e <= 1) - break; - } - } - *exname = targetname; - return r & 1; -} - - - - -/* --------------------- G E T L O G M S G --------------------------------*/ - - - static struct cbuf -getlogmsg() -/* Obtain and yield a log message. - * If a log message is given with -m, yield that message. - * If this is the initial revision, yield a standard log message. - * Otherwise, reads a character string from the terminal. - * Stops after reading EOF or a single '.' on a - * line. getlogmsg prompts the first time it is called for the - * log message; during all later calls it asks whether the previous - * log message can be reused. - */ -{ - static char const - emptych[] = EMPTYLOG, - initialch[] = "Initial revision"; - static struct cbuf const - emptylog = { emptych, sizeof(emptych)-sizeof(char) }, - initiallog = { initialch, sizeof(initialch)-sizeof(char) }; - static struct buf logbuf; - static struct cbuf logmsg; - - register char *tp; - register size_t i; - char const *caller; - - if (msg.size) return msg; - - if (keepflag) { - /* generate std. log message */ - caller = getcaller(); - i = sizeof(ciklog)+strlen(caller)+3; - bufalloc(&logbuf, i + datesize + zonelenmax); - tp = logbuf.string; - VOID sprintf(tp, "%s%s at ", ciklog, caller); - VOID date2str(getcurdate(), tp+i); - logmsg.string = tp; - logmsg.size = strlen(tp); - return logmsg; - } - - if (!targetdelta && ( - cmpnum(newdelnum.string,"1.1")==0 || - cmpnum(newdelnum.string,"1.0")==0 - )) - return initiallog; - - if (logmsg.size) { - /*previous log available*/ - if (yesorno(true, "reuse log message of previous file? [yn](y): ")) - return logmsg; - } - - /* now read string from stdin */ - logmsg = getsstdin("m", "log message", "", &logbuf); - - /* now check whether the log message is not empty */ - if (logmsg.size) - return logmsg; - return emptylog; -} - -/* Make a linked list of Symbolic names */ - - static void -addassoclst(flag, sp) - int flag; - char const *sp; -{ - struct Symrev *pt; - - pt = talloc(struct Symrev); - pt->ssymbol = sp; - pt->override = flag; - pt->nextsym = 0; - *nextassoc = pt; - nextassoc = &pt->nextsym; -} Index: gnu/usr.bin/rcs/co/Makefile =================================================================== --- gnu/usr.bin/rcs/co/Makefile (revision 255904) +++ gnu/usr.bin/rcs/co/Makefile (working copy) @@ -1,8 +0,0 @@ -PROG= co -SRCS= co.c -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/co/co.1 =================================================================== --- gnu/usr.bin/rcs/co/co.1 (revision 255904) +++ gnu/usr.bin/rcs/co/co.1 (working copy) @@ -1,736 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds i \&\s-1ISO\s0 -.ds r \&\s-1RCS\s0 -.ds u \&\s-1UTC\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH CO 1 \*(Dt GNU -.SH NAME -co \- check out RCS revisions -.SH SYNOPSIS -.B co -.RI [ options ] " file " .\|.\|. -.SH DESCRIPTION -.B co -retrieves a revision from each \*r file and stores it into -the corresponding working file. -.PP -Pathnames matching an \*r suffix denote \*r files; -all others denote working files. -Names are paired as explained in -.BR ci (1). -.PP -Revisions of an \*r file can be checked out locked or unlocked. Locking a -revision prevents overlapping updates. A revision checked out for reading or -processing (e.g., compiling) need not be locked. A revision checked out -for editing and later checkin must normally be locked. Checkout with locking -fails if the revision to be checked out is currently locked by another user. -(A lock can be broken with -.BR rcs "(1).)\ \&" -Checkout with locking also requires the caller to be on the access list of -the \*r file, unless he is the owner of the -file or the superuser, or the access list is empty. -Checkout without locking is not subject to accesslist restrictions, and is -not affected by the presence of locks. -.PP -A revision is selected by options for revision or branch number, -checkin date/time, author, or state. -When the selection options -are applied in combination, -.B co -retrieves the latest revision -that satisfies all of them. -If none of the selection options -is specified, -.B co -retrieves the latest revision -on the default branch (normally the trunk, see the -.B \-b -option of -.BR rcs (1)). -A revision or branch number can be attached -to any of the options -.BR \-f , -.BR \-I , -.BR \-l , -.BR \-M , -.BR \-p , -.BR \-q , -.BR \-r , -or -.BR \-u . -The options -.B \-d -(date), -.B \-s -(state), and -.B \-w -(author) -retrieve from a single branch, the -.I selected -branch, -which is either specified by one of -.BR \-f , -\&.\|.\|., -.BR \-u , -or the default branch. -.PP -A -.B co -command applied to an \*r -file with no revisions creates a zero-length working file. -.B co -always performs keyword substitution (see below). -.SH OPTIONS -.TP -.BR \-r [\f2rev\fP] -retrieves the latest revision whose number is less than or equal to -.IR rev . -If -.I rev -indicates a branch rather than a revision, -the latest revision on that branch is retrieved. -If -.I rev -is omitted, the latest revision on the default branch -(see the -.B \-b -option of -.BR rcs (1)) -is retrieved. -If -.I rev -is -.BR $ , -.B co -determines the revision number from keyword values in the working file. -Otherwise, a revision is composed of one or more numeric or symbolic fields -separated by periods. -If -.I rev -begins with a period, -then the default branch (normally the trunk) is prepended to it. -If -.I rev -is a branch number followed by a period, -then the latest revision on that branch is used. -The numeric equivalent of a symbolic field -is specified with the -.B \-n -option of the commands -.BR ci (1) -and -.BR rcs (1). -.TP -.BR \-l [\f2rev\fP] -same as -.BR \-r , -except that it also locks the retrieved revision for -the caller. -.TP -.BR \-u [\f2rev\fP] -same as -.BR \-r , -except that it unlocks the retrieved revision if it was -locked by the caller. If -.I rev -is omitted, -.B \-u -retrieves the revision locked by the caller, if there is one; otherwise, -it retrieves the latest revision on the default branch. -.TP -.BR \-f [\f2rev\fP] -forces the overwriting of the working file; -useful in connection with -.BR \-q . -See also -.SM "FILE MODES" -below. -.TP -.B \-kkv -Generate keyword strings using the default form, e.g.\& -.B "$\&Revision: \*(Rv $" -for the -.B Revision -keyword. -A locker's name is inserted in the value of the -.BR Header , -.BR Id , -and -.B Locker -keyword strings -only as a file is being locked, -i.e. by -.B "ci\ \-l" -and -.BR "co\ \-l". -This is the default. -.TP -.B \-kkvl -Like -.BR \-kkv , -except that a locker's name is always inserted -if the given revision is currently locked. -.TP -.B \-kk -Generate only keyword names in keyword strings; omit their values. -See -.SM "KEYWORD SUBSTITUTION" -below. -For example, for the -.B Revision -keyword, generate the string -.B $\&Revision$ -instead of -.BR "$\&Revision: \*(Rv $" . -This option is useful to ignore differences due to keyword substitution -when comparing different revisions of a file. -Log messages are inserted after -.B $\&Log$ -keywords even if -.B \-kk -is specified, -since this tends to be more useful when merging changes. -.TP -.B \-ko -Generate the old keyword string, -present in the working file just before it was checked in. -For example, for the -.B Revision -keyword, generate the string -.B "$\&Revision: 1.1 $" -instead of -.B "$\&Revision: \*(Rv $" -if that is how the string appeared when the file was checked in. -This can be useful for file formats -that cannot tolerate any changes to substrings -that happen to take the form of keyword strings. -.TP -.B \-kb -Generate a binary image of the old keyword string. -This acts like -.BR \-ko , -except it performs all working file input and output in binary mode. -This makes little difference on Posix and Unix hosts, -but on DOS-like hosts one should use -.B "rcs\ \-i\ \-kb" -to initialize an \*r file intended to be used for binary files. -Also, on all hosts, -.BR rcsmerge (1) -normally refuses to merge files when -.B \-kb -is in effect. -.TP -.B \-kv -Generate only keyword values for keyword strings. -For example, for the -.B Revision -keyword, generate the string -.B \*(Rv -instead of -.BR "$\&Revision: \*(Rv $" . -This can help generate files in programming languages where it is hard to -strip keyword delimiters like -.B "$\&Revision:\ $" -from a string. -However, further keyword substitution cannot be performed once the -keyword names are removed, so this option should be used with care. -Because of this danger of losing keywords, -this option cannot be combined with -.BR \-l , -and the owner write permission of the working file is turned off; -to edit the file later, check it out again without -.BR \-kv . -.TP -.BR \-p [\f2rev\fP] -prints the retrieved revision on the standard output rather than storing it -in the working file. -This option is useful when -.B co -is part of a pipe. -.TP -.BR \-q [\f2rev\fP] -quiet mode; diagnostics are not printed. -.TP -.BR \-I [\f2rev\fP] -interactive mode; -the user is prompted and questioned -even if the standard input is not a terminal. -.TP -.BI \-d date -retrieves the latest revision on the selected branch whose checkin date/time is -less than or equal to -.IR date . -The date and time can be given in free format. -The time zone -.B LT -stands for local time; -other common time zone names are understood. -For example, the following -.IR date s -are equivalent -if local time is January 11, 1990, 8pm Pacific Standard Time, -eight hours west of Coordinated Universal Time (\*u): -.RS -.LP -.RS -.nf -.ta \w'\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP 'u -.ne 10 -\f38:00 pm lt\fP -\f34:00 AM, Jan. 12, 1990\fP default is \*u -\f31990-01-12 04:00:00+00\fP \*i 8601 (\*u) -\f31990-01-11 20:00:00\-08\fP \*i 8601 (local time) -\f31990/01/12 04:00:00\fP traditional \*r format -\f3Thu Jan 11 20:00:00 1990 LT\fP output of \f3ctime\fP(3) + \f3LT\fP -\f3Thu Jan 11 20:00:00 PST 1990\fP output of \f3date\fP(1) -\f3Fri Jan 12 04:00:00 GMT 1990\fP -\f3Thu, 11 Jan 1990 20:00:00 \-0800\fP Internet RFC 822 -\f312-January-1990, 04:00 WET\fP -.ta 4n +4n +4n +4n -.fi -.RE -.LP -Most fields in the date and time can be defaulted. -The default time zone is normally \*u, but this can be overridden by the -.B \-z -option. -The other defaults are determined in the order year, month, day, -hour, minute, and second (most to least significant). At least one of these -fields must be provided. For omitted fields that are of higher significance -than the highest provided field, the time zone's current values are assumed. -For all other omitted fields, -the lowest possible values are assumed. -For example, without -.BR \-z , -the date -.B "20, 10:30" -defaults to -10:30:00 \*u of the 20th of the \*u time zone's current month and year. -The date/time must be quoted if it contains spaces. -.RE -.TP -.BR \-M [\f2rev\fP] -Set the modification time on the new working file -to be the date of the retrieved revision. -Use this option with care; it can confuse -.BR make (1). -.TP -.BI \-s state -retrieves the latest revision on the selected branch whose state is set to -.IR state . -.TP -.B \-T -Preserve the modification time on the \*r file -even if the \*r file changes because a lock is added or removed. -This option can suppress extensive recompilation caused by a -.BR make (1) -dependency of some other copy of the working file on the \*r file. -Use this option with care; it can suppress recompilation even when it is needed, -i.e. when the change of lock -would mean a change to keyword strings in the other working file. -.TP -.BR \-w [\f2login\fP] -retrieves the latest revision on the selected branch which was checked in -by the user with login name -.IR login . -If the argument -.I login -is -omitted, the caller's login is assumed. -.TP -.BI \-j joinlist -generates a new revision which is the join of the revisions on -.IR joinlist . -This option is largely obsoleted by -.BR rcsmerge (1) -but is retained for backwards compatibility. -.RS -.PP -The -.I joinlist -is a comma-separated list of pairs of the form -.IB rev2 : rev3, -where -.I rev2 -and -.I rev3 -are (symbolic or numeric) -revision numbers. -For the initial such pair, -.I rev1 -denotes the revision selected -by the above options -.BR \-f , -\&.\|.\|., -.BR \-w . -For all other pairs, -.I rev1 -denotes the revision generated by the previous pair. -(Thus, the output -of one join becomes the input to the next.) -.PP -For each pair, -.B co -joins revisions -.I rev1 -and -.I rev3 -with respect to -.IR rev2 . -This means that all changes that transform -.I rev2 -into -.I rev1 -are applied to a copy of -.IR rev3 . -This is particularly useful if -.I rev1 -and -.I rev3 -are the ends of two branches that have -.I rev2 -as a common ancestor. If -.IR rev1 < rev2 < rev3 -on the same branch, -joining generates a new revision which is like -.I rev3, -but with all changes that lead from -.I rev1 -to -.I rev2 -undone. -If changes from -.I rev2 -to -.I rev1 -overlap with changes from -.I rev2 -to -.I rev3, -.B co -reports overlaps as described in -.BR merge (1). -.PP -For the initial pair, -.I rev2 -can be omitted. The default is the common -ancestor. -If any of the arguments indicate branches, the latest revisions -on those branches are assumed. -The options -.B \-l -and -.B \-u -lock or unlock -.IR rev1 . -.RE -.TP -.BI \-V -Print \*r's version number. -.TP -.BI \-V n -Emulate \*r version -.I n, -where -.I n -can be -.BR 3 , -.BR 4 , -or -.BR 5 . -This can be useful when interchanging \*r files with others who are -running older versions of \*r. -To see which version of \*r your correspondents are running, have them invoke -.BR "rcs \-V" ; -this works with newer versions of \*r. -If it doesn't work, have them invoke -.B rlog -on an \*r file; -if none of the first few lines of output contain the string -.B branch: -it is version 3; -if the dates' years have just two digits, it is version 4; -otherwise, it is version 5. -An \*r file generated while emulating version 3 loses its default branch. -An \*r revision generated while emulating version 4 or earlier has -a time stamp that is off by up to 13 hours. -A revision extracted while emulating version 4 or earlier contains -abbreviated dates of the form -.IB yy / mm / dd -and can also contain different white space and line prefixes -in the substitution for -.BR $\&Log$ . -.TP -.BI \-x "suffixes" -Use -.I suffixes -to characterize \*r files. -See -.BR ci (1) -for details. -.TP -.BI \-z zone -specifies the date output format in keyword substitution, -and specifies the default time zone for -.I date -in the -.BI \-d date -option. -The -.I zone -should be empty, a numeric \*u offset, or the special string -.B LT -for local time. -The default is an empty -.IR zone , -which uses the traditional \*r format of \*u without any time zone indication -and with slashes separating the parts of the date; -otherwise, times are output in \*i 8601 format with time zone indication. -For example, if local time is January 11, 1990, 8pm Pacific Standard Time, -eight hours west of \*u, -then the time is output as follows: -.RS -.LP -.RS -.nf -.ta \w'\f3\-z+05:30\fP 'u +\w'\f31990-01-11 09:30:00+05:30\fP 'u -.ne 4 -\f2option\fP \f2time output\fP -\f3\-z\fP \f31990/01/12 04:00:00\fP \f2(default)\fP -\f3\-zLT\fP \f31990-01-11 20:00:00\-08\fP -\f3\-z+05:30\fP \f31990-01-12 09:30:00+05:30\fP -.ta 4n +4n +4n +4n -.fi -.RE -.LP -The -.B \-z -option does not affect dates stored in \*r files, -which are always \*u. -.RE -.SH "KEYWORD SUBSTITUTION" -Strings of the form -.BI $ keyword $ -and -.BI $ keyword : .\|.\|. $ -embedded in -the text are replaced -with strings of the form -.BI $ keyword : value $ -where -.I keyword -and -.I value -are pairs listed below. -Keywords can be embedded in literal strings -or comments to identify a revision. -.PP -Initially, the user enters strings of the form -.BI $ keyword $ . -On checkout, -.B co -replaces these strings with strings of the form -.BI $ keyword : value $ . -If a revision containing strings of the latter form -is checked back in, the value fields will be replaced during the next -checkout. -Thus, the keyword values are automatically updated on checkout. -This automatic substitution can be modified by the -.B \-k -options. -.PP -Keywords and their corresponding values: -.TP -.B $\&Author$ -The login name of the user who checked in the revision. -.TP -.B $\&Date$ -The date and time the revision was checked in. -With -.BI \-z zone -a numeric time zone offset is appended; otherwise, the date is \*u. -.TP -.B $\&Header$ -A standard header containing the full pathname of the \*r file, the -revision number, the date and time, the author, the state, -and the locker (if locked). -With -.BI \-z zone -a numeric time zone offset is appended to the date; otherwise, the date is \*u. -.TP -.B $\&Id$ -Same as -.BR $\&Header$ , -except that the \*r filename is without a path. -.TP -.B $\&Locker$ -The login name of the user who locked the revision (empty if not locked). -.TP -.B $\&Log$ -The log message supplied during checkin, preceded by a header -containing the \*r filename, the revision number, the author, and the date -and time. -With -.BI \-z zone -a numeric time zone offset is appended; otherwise, the date is \*u. -Existing log messages are -.I not -replaced. -Instead, the new log message is inserted after -.BR $\&Log: .\|.\|. $ . -This is useful for -accumulating a complete change log in a source file. -.RS -.LP -Each inserted line is prefixed by the string that prefixes the -.B $\&Log$ -line. For example, if the -.B $\&Log$ -line is -.RB \*(lq "//\ $\&Log: tan.cc\ $" \*(rq, -\*r prefixes each line of the log with -.RB \*(lq "//\ " \*(rq. -This is useful for languages with comments that go to the end of the line. -The convention for other languages is to use a -.RB \*(lq " \(** " \(rq -prefix inside a multiline comment. -For example, the initial log comment of a C program -conventionally is of the following form: -.RS -.LP -.nf -.ft 3 -.ne 3 -/\(** -.in +\w'/'u -\(** $\&Log$ -\(**/ -.in -.ft -.fi -.RE -.LP -For backwards compatibility with older versions of \*r, if the log prefix is -.B /\(** -or -.B (\(** -surrounded by optional white space, inserted log lines contain a space -instead of -.B / -or -.BR ( ; -however, this usage is obsolescent and should not be relied on. -.RE -.TP -.B $\&Name$ -The symbolic name used to check out the revision, if any. -For example, -.B "co\ \-rJoe" -generates -.BR "$\&Name:\ Joe\ $" . -Plain -.B co -generates just -.BR "$\&Name:\ \ $" . -.TP -.B $\&RCSfile$ -The name of the \*r file without a path. -.TP -.B $\&Revision$ -The revision number assigned to the revision. -.TP -.B $\&Source$ -The full pathname of the \*r file. -.TP -.B $\&State$ -The state assigned to the revision with the -.B \-s -option of -.BR rcs (1) -or -.BR ci (1). -.PP -The following characters in keyword values are represented by escape sequences -to keep keyword strings well-formed. -.LP -.RS -.nf -.ne 6 -.ta \w'newline 'u -\f2char escape sequence\fP -tab \f3\et\fP -newline \f3\en\fP -space \f3\e040 -$ \e044 -\e \e\e\fP -.fi -.RE -.SH "FILE MODES" -The working file inherits the read and execute permissions from the \*r -file. In addition, the owner write permission is turned on, unless -.B \-kv -is set or the file -is checked out unlocked and locking is set to strict (see -.BR rcs (1)). -.PP -If a file with the name of the working file exists already and has write -permission, -.B co -aborts the checkout, -asking beforehand if possible. -If the existing working file is -not writable or -.B \-f -is given, the working file is deleted without asking. -.SH FILES -.B co -accesses files much as -.BR ci (1) -does, except that it does not need to read the working file -unless a revision number of -.B $ -is specified. -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -See -.BR ci (1) -for details. -.SH DIAGNOSTICS -The \*r pathname, the working pathname, -and the revision number retrieved are -written to the diagnostic output. -The exit status is zero if and only if all operations were successful. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH "SEE ALSO" -rcsintro(1), ci(1), ctime(3), date(1), ident(1), make(1), -rcs(1), rcsclean(1), rcsdiff(1), rcsmerge(1), rlog(1), -rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.SH LIMITS -Links to the \*r and working files are not preserved. -.PP -There is no way to selectively suppress the expansion of keywords, except -by writing them differently. In nroff and troff, this is done by embedding the -null-character -.B \e& -into the keyword. -.br Index: gnu/usr.bin/rcs/co/co.c =================================================================== --- gnu/usr.bin/rcs/co/co.c (revision 255904) +++ gnu/usr.bin/rcs/co/co.c (working copy) @@ -1,826 +0,0 @@ -/* Check out working files from revisions of RCS files. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.18 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.17 1995/06/01 16:23:43 eggert - * (main, preparejoin): Pass argument instead of using `join' static variable. - * (main): Add -kb. - * - * Revision 5.16 1994/03/17 14:05:48 eggert - * Move buffer-flushes out of critical sections, since they aren't critical. - * Use ORCSerror to clean up after a fatal error. Remove lint. - * Specify subprocess input via file descriptor, not file name. - * - * Revision 5.15 1993/11/09 17:40:15 eggert - * -V now prints version on stdout and exits. Don't print usage twice. - * - * Revision 5.14 1993/11/03 17:42:27 eggert - * Add -z. Generate a value for the Name keyword. - * Don't arbitrarily limit the number of joins. - * Improve quality of diagnostics. - * - * Revision 5.13 1992/07/28 16:12:44 eggert - * Add -V. Check that working and RCS files are distinct. - * - * Revision 5.12 1992/02/17 23:02:08 eggert - * Add -T. - * - * Revision 5.11 1992/01/24 18:44:19 eggert - * Add support for bad_creat0. lint -> RCS_lint - * - * Revision 5.10 1992/01/06 02:42:34 eggert - * Update usage string. - * - * Revision 5.9 1991/10/07 17:32:46 eggert - * -k affects just working file, not RCS file. - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Warn before removing somebody else's file. - * Add -M. Fix co -j bugs. Tune. - * - * Revision 5.7 1991/04/21 11:58:15 eggert - * Ensure that working file is newer than RCS file after co -[lu]. - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.6 1990/12/04 05:18:38 eggert - * Don't checkaccesslist() unless necessary. - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.5 1990/11/01 05:03:26 eggert - * Fix -j. Add -I. - * - * Revision 5.4 1990/10/04 06:30:11 eggert - * Accumulate exit status across files. - * - * Revision 5.3 1990/09/11 02:41:09 eggert - * co -kv yields a readonly working file. - * - * Revision 5.2 1990/09/04 08:02:13 eggert - * Standardize yes-or-no procedure. - * - * Revision 5.0 1990/08/22 08:10:02 eggert - * Permit multiple locks by same user. Add setuid support. - * Remove compile-time limits; use malloc instead. - * Permit dates past 1999/12/31. Switch to GMT. - * Make lock and temp files faster and safer. - * Ansify and Posixate. Add -k, -V. Remove snooping. Tune. - * - * Revision 4.7 89/05/01 15:11:41 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.6 88/08/09 19:12:15 eggert - * Fix "co -d" core dump; rawdate wasn't always initialized. - * Use execv(), not system(); fix putchar('\0') and diagnose() botches; remove lint - * - * Revision 4.5 87/12/18 11:35:40 narten - * lint cleanups (from Guy Harris) - * - * Revision 4.4 87/10/18 10:20:53 narten - * Updating version numbers changes relative to 1.1, are actually - * relative to 4.2 - * - * Revision 1.3 87/09/24 13:58:30 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:21:38 jenkins - * Port to suns - * - * Revision 4.2 83/12/05 13:39:48 wft - * made rewriteflag external. - * - * Revision 4.1 83/05/10 16:52:55 wft - * Added option -u and -f. - * Added handling of default branch. - * Replaced getpwuid() with getcaller(). - * Removed calls to stat(); now done by pairfilenames(). - * Changed and renamed rmoldfile() to rmworkfile(). - * Replaced catchints() calls with restoreints(), unlink()--link() with rename(); - * - * Revision 3.7 83/02/15 15:27:07 wft - * Added call to fastcopy() to copy remainder of RCS file. - * - * Revision 3.6 83/01/15 14:37:50 wft - * Added ignoring of interrupts while RCS file is renamed; this avoids - * deletion of RCS files during the unlink/link window. - * - * Revision 3.5 82/12/08 21:40:11 wft - * changed processing of -d to use DATEFORM; removed actual from - * call to preparejoin; re-fixed printing of done at the end. - * - * Revision 3.4 82/12/04 18:40:00 wft - * Replaced getdelta() with gettree(), SNOOPDIR with SNOOPFILE. - * Fixed printing of "done". - * - * Revision 3.3 82/11/28 22:23:11 wft - * Replaced getlogin() with getpwuid(), flcose() with ffclose(), - * %02d with %.2d, mode generation for working file with WORKMODE. - * Fixed nil printing. Fixed -j combined with -l and -p, and exit - * for non-existing revisions in preparejoin(). - * - * Revision 3.2 82/10/18 20:47:21 wft - * Mode of working file is now maintained even for co -l, but write permission - * is removed. - * The working file inherits its mode from the RCS file, plus write permission - * for the owner. The write permission is not given if locking is strict and - * co does not lock. - * An existing working file without write permission is deleted automatically. - * Otherwise, co asks (empty answer: abort co). - * Call to getfullRCSname() added, check for write error added, call - * for getlogin() fixed. - * - * Revision 3.1 82/10/13 16:01:30 wft - * fixed type of variables receiving from getc() (char -> int). - * removed unused variables. - */ - - - - -#include "rcsbase.h" - -static char *addjoin P((char*)); -static char const *getancestor P((char const*,char const*)); -static int buildjoin P((char const*)); -static int preparejoin P((char*)); -static int rmlock P((struct hshentry const*)); -static int rmworkfile P((void)); -static void cleanup P((void)); - -static char const quietarg[] = "-q"; - -static char const *expandarg, *suffixarg, *versionarg, *zonearg; -static char const **joinlist; /* revisions to be joined */ -static int joinlength; -static FILE *neworkptr; -static int exitstatus; -static int forceflag; -static int lastjoin; /* index of last element in joinlist */ -static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */ -static int mtimeflag; -static struct hshentries *gendeltas; /* deltas to be generated */ -static struct hshentry *targetdelta; /* final delta to be generated */ -static struct stat workstat; - -mainProg(coId, "co", "$FreeBSD$") -{ - static char const cmdusage[] = - "\nco usage: co -{fIlMpqru}[rev] -ddate -jjoins -ksubst -sstate -T -w[who] -Vn -xsuff -zzone file ..."; - - char *a, *joinflag, **newargv; - char const *author, *date, *rev, *state; - char const *joinname, *newdate, *neworkname; - int changelock; /* 1 if a lock has been changed, -1 if error */ - int expmode, r, tostdout, workstatstat; - int Ttimeflag; - struct buf numericrev; /* expanded revision number */ - char finaldate[datesize]; -# if OPEN_O_BINARY - int stdout_mode = 0; -# endif - - setrid(); - author = date = rev = state = 0; - joinflag = 0; - bufautobegin(&numericrev); - expmode = -1; - suffixes = X_DEFAULT; - tostdout = false; - Ttimeflag = false; - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - while (a = *++argv, 0<--argc && *a++=='-') { - switch (*a++) { - - case 'r': - revno: - if (*a) { - if (rev) warn("redefinition of revision number"); - rev = a; - } - break; - - case 'f': - forceflag=true; - goto revno; - - case 'l': - if (lockflag < 0) { - warn("-u overridden by -l."); - } - lockflag = 1; - goto revno; - - case 'u': - if (0 < lockflag) { - warn("-l overridden by -u."); - } - lockflag = -1; - goto revno; - - case 'p': - tostdout = true; - goto revno; - - case 'I': - interactiveflag = true; - goto revno; - - case 'q': - quietflag=true; - goto revno; - - case 'd': - if (date) - redefined('d'); - str2date(a, finaldate); - date=finaldate; - break; - - case 'j': - if (*a) { - if (joinflag) redefined('j'); - joinflag = a; - } - break; - - case 'M': - mtimeflag = true; - goto revno; - - case 's': - if (*a) { - if (state) redefined('s'); - state = a; - } - break; - - case 'T': - if (*a) - goto unknown; - Ttimeflag = true; - break; - - case 'w': - if (author) redefined('w'); - if (*a) - author = a; - else - author = getcaller(); - break; - - case 'x': - suffixarg = *argv; - suffixes = a; - break; - - case 'V': - versionarg = *argv; - setRCSversion(versionarg); - break; - - case 'z': - zonearg = *argv; - zone_set(a); - break; - - case 'k': /* set keyword expand mode */ - expandarg = *argv; - if (0 <= expmode) redefined('k'); - if (0 <= (expmode = str2expmode(a))) - break; - /* fall into */ - default: - unknown: - error("unknown option: %s%s", *argv, cmdusage); - - }; - } /* end of option processing */ - - /* Now handle all pathnames. */ - if (nerror) cleanup(); - else if (argc < 1) faterror("no input file%s", cmdusage); - else for (; 0 < argc; cleanup(), ++argv, --argc) { - ffree(); - - if (pairnames(argc, argv, lockflag?rcswriteopen:rcsreadopen, true, false) <= 0) - continue; - - /* - * RCSname contains the name of the RCS file, and finptr - * points at it. workname contains the name of the working file. - * Also, RCSstat has been set. - */ - diagnose("%s --> %s\n", RCSname, tostdout?"standard output":workname); - - workstatstat = -1; - if (tostdout) { -# if OPEN_O_BINARY - int newmode = Expand==BINARY_EXPAND ? OPEN_O_BINARY : 0; - if (stdout_mode != newmode) { - stdout_mode = newmode; - oflush(); - VOID setmode(STDOUT_FILENO, newmode); - } -# endif - neworkname = 0; - neworkptr = workstdout = stdout; - } else { - workstatstat = stat(workname, &workstat); - if (workstatstat == 0 && same_file(RCSstat, workstat, 0)) { - rcserror("RCS file is the same as working file %s.", - workname - ); - continue; - } - neworkname = makedirtemp(1); - if (!(neworkptr = fopenSafer(neworkname, FOPEN_W_WORK))) { - if (errno == EACCES) - workerror("permission denied on parent directory"); - else - eerror(neworkname); - continue; - } - } - - gettree(); /* reads in the delta tree */ - - if (!Head) { - /* no revisions; create empty file */ - diagnose("no revisions present; generating empty revision 0.0\n"); - if (lockflag) - warn( - "no revisions, so nothing can be %slocked", - lockflag < 0 ? "un" : "" - ); - Ozclose(&fcopy); - if (workstatstat == 0) - if (!rmworkfile()) continue; - changelock = 0; - newdate = 0; - } else { - int locks = lockflag ? findlock(false, &targetdelta) : 0; - if (rev) { - /* expand symbolic revision number */ - if (!expandsym(rev, &numericrev)) - continue; - } else { - switch (locks) { - default: - continue; - case 0: - bufscpy(&numericrev, Dbranch?Dbranch:""); - break; - case 1: - bufscpy(&numericrev, targetdelta->num); - break; - } - } - /* get numbers of deltas to be generated */ - if (!(targetdelta=genrevs(numericrev.string,date,author,state,&gendeltas))) - continue; - /* check reservations */ - changelock = - lockflag < 0 ? - rmlock(targetdelta) - : lockflag == 0 ? - 0 - : - addlock(targetdelta, true); - - if ( - changelock < 0 - || (changelock && !checkaccesslist()) - || dorewrite(lockflag, changelock) != 0 - ) - continue; - - if (0 <= expmode) - Expand = expmode; - if (0 < lockflag && Expand == VAL_EXPAND) { - rcserror("cannot combine -kv and -l"); - continue; - } - - if (joinflag && !preparejoin(joinflag)) - continue; - - diagnose("revision %s%s\n",targetdelta->num, - 0name = namedrev(rev, targetdelta); - joinname = buildrevision( - gendeltas, targetdelta, - joinflag&&tostdout ? (FILE*)0 : neworkptr, - Expand < MIN_UNEXPAND - ); -# if !large_memory - if (fcopy == neworkptr) - fcopy = 0; /* Don't close it twice. */ -# endif - if_advise_access(changelock && gendeltas->first!=targetdelta, - finptr, MADV_SEQUENTIAL - ); - - if (donerewrite(changelock, - Ttimeflag ? RCSstat.st_mtime : (time_t)-1 - ) != 0) - continue; - - if (changelock) { - locks += lockflag; - if (1 < locks) - rcswarn("You now have %d locks.", locks); - } - - newdate = targetdelta->date; - if (joinflag) { - newdate = 0; - if (!joinname) { - aflush(neworkptr); - joinname = neworkname; - } - if (Expand == BINARY_EXPAND) - workerror("merging binary files"); - if (!buildjoin(joinname)) - continue; - } - } - if (!tostdout) { - mode_t m = WORKMODE(RCSstat.st_mode, - ! (Expand==VAL_EXPAND || (lockflag<=0 && StrictLocks)) - ); - time_t t = mtimeflag&&newdate ? date2time(newdate) : (time_t)-1; - aflush(neworkptr); - ignoreints(); - r = chnamemod(&neworkptr, neworkname, workname, 1, m, t); - keepdirtemp(neworkname); - restoreints(); - if (r != 0) { - eerror(workname); - error("see %s", neworkname); - continue; - } - diagnose("done\n"); - } - } - - tempunlink(); - Ofclose(workstdout); - exitmain(exitstatus); - -} /* end of main (co) */ - - static void -cleanup() -{ - if (nerror) exitstatus = EXIT_FAILURE; - Izclose(&finptr); - ORCSclose(); -# if !large_memory - if (fcopy!=workstdout) Ozclose(&fcopy); -# endif - if (neworkptr!=workstdout) Ozclose(&neworkptr); - dirtempunlink(); -} - -#if RCS_lint -# define exiterr coExit -#endif - void -exiterr() -{ - ORCSerror(); - dirtempunlink(); - tempunlink(); - _exit(EXIT_FAILURE); -} - - -/***************************************************************** - * The following routines are auxiliary routines - *****************************************************************/ - - static int -rmworkfile() -/* - * Prepare to remove workname, if it exists, and if - * it is read-only. - * Otherwise (file writable): - * if !quietmode asks the user whether to really delete it (default: fail); - * otherwise failure. - * Returns true if permission is gotten. - */ -{ - if (workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH) && !forceflag) { - /* File is writable */ - if (!yesorno(false, "writable %s exists%s; remove it? [ny](n): ", - workname, - myself(workstat.st_uid) ? "" : ", and you do not own it" - )) { - error(!quietflag && ttystdin() - ? "checkout aborted" - : "writable %s exists; checkout aborted", workname); - return false; - } - } - /* Actual unlink is done later by caller. */ - return true; -} - - - static int -rmlock(delta) - struct hshentry const *delta; -/* Function: removes the lock held by caller on delta. - * Returns -1 if someone else holds the lock, - * 0 if there is no lock on delta, - * and 1 if a lock was found and removed. - */ -{ register struct rcslock * next, * trail; - char const *num; - struct rcslock dummy; - int whomatch, nummatch; - - num=delta->num; - dummy.nextlock=next=Locks; - trail = &dummy; - while (next) { - whomatch = strcmp(getcaller(), next->login); - nummatch=strcmp(num,next->delta->num); - if ((whomatch==0) && (nummatch==0)) break; - /*found a lock on delta by caller*/ - if ((whomatch!=0)&&(nummatch==0)) { - rcserror("revision %s locked by %s; use co -r or rcs -u", - num, next->login - ); - return -1; - } - trail=next; - next=next->nextlock; - } - if (next) { - /*found one; delete it */ - trail->nextlock=next->nextlock; - Locks=dummy.nextlock; - next->delta->lockedby = 0; - return 1; /*success*/ - } else return 0; /*no lock on delta*/ -} - - - - -/***************************************************************** - * The rest of the routines are for handling joins - *****************************************************************/ - - - static char * -addjoin(joinrev) - char *joinrev; -/* Add joinrev's number to joinlist, yielding address of char past joinrev, - * or 0 if no such revision exists. - */ -{ - register char *j; - register struct hshentry *d; - char terminator; - struct buf numrev; - struct hshentries *joindeltas; - - j = joinrev; - for (;;) { - switch (*j++) { - default: - continue; - case 0: - case ' ': case '\t': case '\n': - case ':': case ',': case ';': - break; - } - break; - } - terminator = *--j; - *j = 0; - bufautobegin(&numrev); - d = 0; - if (expandsym(joinrev, &numrev)) - d = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&joindeltas); - bufautoend(&numrev); - *j = terminator; - if (d) { - joinlist[++lastjoin] = d->num; - return j; - } - return 0; -} - - static int -preparejoin(j) - register char *j; -/* Parse join list J and place pointers to the - * revision numbers into joinlist. - */ -{ - lastjoin= -1; - for (;;) { - while ((*j==' ')||(*j=='\t')||(*j==',')) j++; - if (*j=='\0') break; - if (lastjoin>=joinlength-2) { - joinlist = - (joinlength *= 2) == 0 - ? tnalloc(char const *, joinlength = 16) - : trealloc(char const *, joinlist, joinlength); - } - if (!(j = addjoin(j))) return false; - while ((*j==' ') || (*j=='\t')) j++; - if (*j == ':') { - j++; - while((*j==' ') || (*j=='\t')) j++; - if (*j!='\0') { - if (!(j = addjoin(j))) return false; - } else { - rcsfaterror("join pair incomplete"); - } - } else { - if (lastjoin==0) { /* first pair */ - /* common ancestor missing */ - joinlist[1]=joinlist[0]; - lastjoin=1; - /*derive common ancestor*/ - if (!(joinlist[0] = getancestor(targetdelta->num,joinlist[1]))) - return false; - } else { - rcsfaterror("join pair incomplete"); - } - } - } - if (lastjoin < 1) - rcsfaterror("empty join"); - return true; -} - - - - static char const * -getancestor(r1, r2) - char const *r1, *r2; -/* Yield the common ancestor of r1 and r2 if successful, 0 otherwise. - * Work reliably only if r1 and r2 are not branch numbers. - */ -{ - static struct buf t1, t2; - - int l1, l2, l3; - char const *r; - - l1 = countnumflds(r1); - l2 = countnumflds(r2); - if ((22 ? 2 : l1); - VOID partialno(&t2, r2, l2>2 ? 2 : l2); - r = cmpnum(t1.string,t2.string)<0 ? t1.string : t2.string; - if (cmpnum(r,r1)!=0 && cmpnum(r,r2)!=0) - return r; - } else if (cmpnumfld(r1, r2, l3+1)!=0) - return partialno(&t1,r1,l3); - } - rcserror("common ancestor of %s and %s undefined", r1, r2); - return 0; -} - - - - static int -buildjoin(initialfile) - char const *initialfile; -/* Function: merge pairs of elements in joinlist into initialfile - * If workstdout is set, copy result to stdout. - * All unlinking of initialfile, rev2, and rev3 should be done by tempunlink(). - */ -{ - struct buf commarg; - struct buf subs; - char const *rev2, *rev3; - int i; - char const *cov[10], *mergev[11]; - char const **p; - - bufautobegin(&commarg); - bufautobegin(&subs); - rev2 = maketemp(0); - rev3 = maketemp(3); /* buildrevision() may use 1 and 2 */ - - cov[1] = CO; - /* cov[2] setup below */ - p = &cov[3]; - if (expandarg) *p++ = expandarg; - if (suffixarg) *p++ = suffixarg; - if (versionarg) *p++ = versionarg; - if (zonearg) *p++ = zonearg; - *p++ = quietarg; - *p++ = RCSname; - *p = 0; - - mergev[1] = MERGE; - mergev[2] = mergev[4] = "-L"; - /* rest of mergev setup below */ - - i=0; - while (inum); - else { - bufscat(&subs, ","); - bufscat(&subs, joinlist[i-2]); - bufscat(&subs, ":"); - bufscat(&subs, joinlist[i-1]); - } - diagnose("revision %s\n",joinlist[i]); - bufscpy(&commarg, "-p"); - bufscat(&commarg, joinlist[i]); - cov[2] = commarg.string; - if (runv(-1, rev2, cov)) - goto badmerge; - diagnose("revision %s\n",joinlist[i+1]); - bufscpy(&commarg, "-p"); - bufscat(&commarg, joinlist[i+1]); - cov[2] = commarg.string; - if (runv(-1, rev3, cov)) - goto badmerge; - diagnose("merging...\n"); - mergev[3] = subs.string; - mergev[5] = joinlist[i+1]; - p = &mergev[6]; - if (quietflag) *p++ = quietarg; - if (lastjoin<=i+2 && workstdout) *p++ = "-p"; - *p++ = initialfile; - *p++ = rev2; - *p++ = rev3; - *p = 0; - switch (runv(-1, (char*)0, mergev)) { - case DIFF_FAILURE: case DIFF_SUCCESS: - break; - default: - goto badmerge; - } - i=i+2; - } - bufautoend(&commarg); - bufautoend(&subs); - return true; - - badmerge: - nerror++; - bufautoend(&commarg); - bufautoend(&subs); - return false; -} Index: gnu/usr.bin/rcs/doc/rcs.ms =================================================================== --- gnu/usr.bin/rcs/doc/rcs.ms (revision 255904) +++ gnu/usr.bin/rcs/doc/rcs.ms (working copy) @@ -1,1518 +0,0 @@ -.\" Format this file with: -.\" pic file | tbl | troff -ms -.\" -.\" \*s stands for $, and avoids problems when this file is checked in. -.ds s $ -.de D( -.DS -.nr VS 12p -.vs 12p -.I -.. -.de D) -.DE -.nr VS 18p -.vs 18p -.R -.. -.de Id -.ND \\$4 -.. -.Id $FreeBSD$ -.RP -.TL -RCS\*-A System for Version Control -.sp -.AU -Walter F. Tichy -.AI -Department of Computer Sciences -Purdue University -West Lafayette, Indiana 47907 -.sp -.AB -An important problem in program development and maintenance is version control, -i.e., the task of keeping a software system consisting of many versions and -configurations well organized. -The Revision Control System (RCS) -is a software tool that assists with that task. -RCS manages revisions of text documents, in particular source programs, -documentation, and test data. -It automates the storing, retrieval, logging and identification of revisions, -and it provides selection mechanisms for composing configurations. -This paper introduces basic version control concepts and -discusses the practice of version control -using RCS. -For conserving space, RCS stores deltas, i.e., differences between -successive revisions. Several delta storage methods are discussed. -Usage statistics show that RCS's delta storage method is -space and time efficient. -The paper concludes with a detailed survey of version control tools. -.sp -\fBKeywords\fR: configuration management, history management, -version control, revisions, deltas. -.AE -.FS -An earlier version of this paper was published in -.I "Software\*-Practice & Experience" -.B 15 , -7 (July 1985), 637-654. -.FE -.nr VS 18p -.LP -.NH -Introduction -.PP -Version control is the task of keeping software -systems consisting of many versions and configurations well organized. -The Revision Control System (RCS) is a set of UNIX -commands that assist with that task. -.PP -RCS' primary function is to manage \fIrevision groups\fR. -A revision group is a set of text documents, called \fIrevisions\fR, -that evolved from each other. A new revision is -created by manually editing an existing one. -RCS organizes the revisions into an ancestral tree. The initial revision -is the root of the tree, and the tree edges indicate -from which revision a given one evolved. -Besides managing individual revision groups, RCS provides -flexible selection functions for composing configurations. -RCS may be combined with MAKE\u1\d, -resulting in a powerful package for version control. -.PP -RCS also offers facilities for -merging updates with customer modifications, -for distributed software development, and -for automatic identification. -Identification is the `stamping' -of revisions and configurations with unique markers. -These markers are akin to serial numbers, -telling software maintainers unambiguously which configuration -is before them. -.PP -RCS is designed for both production and experimental -environments. -In production environments, -access controls detect update conflicts and prevent overlapping changes. -In experimental environments, where strong controls are -counterproductive, it is possible to loosen the controls. -.PP -Although RCS was originally intended for programs, it is useful for any -text that is revised frequently and whose previous revisions must be -preserved. RCS has been applied successfully to store the source -text for drawings, VLSI layouts, documentation, specifications, -test data, form letters and articles. -.PP -This paper discusses the practice of -version control using RCS. -It also introduces basic version control concepts, -useful for clarifying current practice and designing similar systems. -Revision groups of individual components are treated in the next three sections, -and the extensions to configurations follow. -Because of its size, a survey of version control tools -appears at the end of the paper. -.NH -Getting started with RCS -.PP -Suppose a text file \fIf.c\fR is to be placed under control of RCS. -Invoking the check-in command -.D( -ci f.c -.D) -creates a new revision group with the contents of -\fIf.c\fR as the initial -revision (numbered 1.1) -and stores the group into the file \fIf.c,v\fR. -Unless told otherwise, the command deletes \fIf.c\fR. -It also asks for a description of the group. -The description should state the common purpose of all revisions in the group, -and becomes part of the group's documentation. -All later check-in commands will ask for a log entry, -which should summarize the changes made. -(The first revision is assigned a default log message, -which just records the fact that it is the initial revision.) -.PP -Files ending in \fI,v\fR -are called \fIRCS files\fR (\fIv\fR stands for \fIv\fRersions); -the others are called working files. -To get back the working file \fIf.c\fR in the previous example, -execute the check-out command: -.D( -co f.c -.D) -.R -This command extracts the latest revision from -the revision group \fIf.c,v\fR and writes -it into \fIf.c\fR. -The file \fIf.c\fR can now be edited and, when finished, -checked back in with \fIci\fR: -.D( -ci f.c -.D) -\fICi\fR assigns number 1.2 to -the new revision. -If \fIci\fR complains with the message -.D( -ci error: no lock set by -.D) -then the system administrator has decided to configure RCS for a -production environment by enabling the `strict locking feature'. -If this feature is enabled, all RCS files are initialized -such that check-in operations require a lock on the previous revision -(the one from which the current one evolved). -Locking prevents overlapping modifications if several people work on the same file. -If locking is required, the revision should -have been locked during the check-out by using -the option \fI\-l\fR: -.D( -co \-l f.c -.D) -Of course it is too late now for the check-out with locking, because -\fIf.c\fR has already been changed; checking out the file again -would overwrite the modifications. -(To prevent accidental overwrites, \fIco\fR senses the presence -of a working file and asks whether the user really intended to overwrite it. -The overwriting check-out is sometimes useful for -backing up to the previous revision.) -To be able to proceed with the check-in in the present case, first execute -.D( -rcs \-l f.c -.D) -This command retroactively locks the latest revision, unless someone -else locked it in the meantime. In this case, the two programmers -involved have to negotiate whose -modifications should take precedence. -.PP -If an RCS file is private, i.e., if only the owner of the file is expected -to deposit revisions into it, the strict locking feature is unnecessary and -may be disabled. -If strict locking is disabled, -the owner of the RCS file need not have a lock for check-in. -For safety reasons, all others -still do. Turning strict locking off and on is done with the commands: -.D( -rcs \-U f.c \fRand\fP rcs \-L f.c -.D) -These commands enable or disable the strict locking feature for each RCS file -individually. -The system administrator only decides whether strict locking is -enabled initially. -.PP -To reduce the clutter in a working directory, all RCS files can be moved -to a subdirectory with the name \fIRCS\fR. -RCS commands look first into that directory for RCS files. -All the commands presented above work -with the \fIRCS\fR subdirectory without change.\(dg -.FS \(dg -Pairs of RCS and working files can actually be specified in 3 ways: -a) both are given, b) only the working file is given, c) only the -RCS file is given. -If a pair is given, both files may have arbitrary path prefixes; -RCS commands pair them up intelligently. -.FE -.PP -It may be undesirable that \fIci\fR deletes the working file. -For instance, sometimes one would like to save the current revision, -but continue editing. -Invoking -.D( -ci \-l f.c -.D) -checks in \fIf.c\fR as usual, but performs an additional -check-out with locking afterwards. Thus, the working file does -not disappear after the check-in. -Similarly, the option -\fI\-u\fR does a check-in followed by a check-out without -locking. This option is useful if the file is needed for compilation after the check-in. -Both options update the identification markers in the working file -(see below). -.PP -Besides the operations \fIci\fR and \fIco\fR, RCS provides the following -commands: -.sp 0 -.nr VS 12p -.vs 12p -.TS -tab(%); -li l. -ident%extract identification markers -rcs%change RCS file attributes -rcsclean%remove unchanged working files (optional) -rcsdiff%compare revisions -rcsfreeze%record a configuration (optional) -rcsmerge%merge revisions -rlog%read log messages and other information in RCS files -.TE -A synopsis of these commands appears in the Appendix. -.NH 2 -Automatic Identification -.PP -RCS can stamp source and object code with special identification strings, -similar to product and serial numbers. -To obtain such identification, place the marker -.D( -\*sId\*s -.D) -into the text of a revision, for instance inside a comment. -The check-out operation will replace this marker with a string of the form -.D( -\*sId: filename revisionnumber date time author state locker \*s -.D) -This string need never be touched, because \fIco\fR keeps it -up to date automatically. -To propagate the marker into object code, simply put -it into a literal character string. In C, this is done as follows: -.D( -static char rcsid[] = \&"\*sId\*s\&"; -.D) -The command \fIident\fR extracts such markers from any file, in particular from -object code. -\fIIdent\fR helps to find out -which revisions of which modules were used in a given program. -It returns a complete and unambiguous component list, -from which a copy of the program can be reconstructed. -This facility is invaluable for program maintenance. -.PP -There are several additional identification markers, one for each component -of \*sId\*s. -The marker -.D( -\*sLog\*s -.D) -has a similar function. It accumulates -the log messages that are requested during check-in. -Thus, one can maintain the complete history of a revision directly inside it, -by enclosing it in a comment. -Figure 1 is an edited version of a log contained in revision 4.1 of -the file \fIci.c\fR. The log appears at the beginning of the file, -and makes it easy to determine what the recent modifications were. -.sp -.nr VS 12p -.vs 12p -.ne 18 -.nf -.in +0.5i -/* -.in +\w'/'u -* \*sLog: ci.c,v \*s -* Revision 4.1 1983/05/10 17:03:06 wft -* Added option \-d and \-w, and updated assignment of date, etc. to new delta. -* Added handling of default branches. -* -* Revision 3.9 1983/02/15 15:25:44 wft -* Added call to fastcopy() to copy remainder of RCS file. -* -* Revision 3.8 1983/01/14 15:34:05 wft -* Added ignoring of interrupts while new RCS file is renamed; -* avoids deletion of RCS files by interrupts. -* -* Revision 3.7 1982/12/10 16:09:20 wft -* Corrected checking of return code from diff. -* An RCS file now inherits its mode during the first ci from the working file, -* except that write permission is removed. -*/ -.in 0 -.ce 1 -Figure 1. Log entries produced by the marker \*sLog\*s. -.fi -.nr VS 18p -.vs 18p -.sp 0 -.LP -Since revisions are stored in the form of differences, -each log message is -physically stored once, -independent of the number of revisions present. -Thus, the \*sLog\*s marker incurs negligible space overhead. -.NH -The RCS Revision Tree -.PP -RCS arranges revisions in an ancestral tree. -The \fIci\fR command builds this tree; the auxiliary command \fIrcs\fR -prunes it. -The tree has a root revision, normally numbered 1.1, and successive revisions -are numbered 1.2, 1.3, etc. The first field of a revision number -is called the \fIrelease number\fR and the second one -the \fIlevel number\fR. Unless given explicitly, -the \fIci\fR command assigns a new revision number -by incrementing the level number of the previous revision. -The release number must be incremented explicitly, using the -\fI\-r\fR option of \fIci\fR. -Assuming there are revisions 1.1, 1.2, and 1.3 in the RCS file f.c,v, the command -.D( -ci \-r2.1 f.c \fRor\fP ci \-r2 f.c -.D) -assigns the number 2.1 to the new revision. -Later check-ins without the \fI\-r\fR option will assign the numbers 2.2, 2.3, -and so on. -The release number should be incremented only at major transition points -in the development, for instance when a new release of a software product has -been completed. -.NH 2 -When are branches needed? -.PP -A young revision tree is slender: -It consists of only one branch, called the trunk. -As the tree ages, side branches may form. -Branches are needed in the following 4 situations. -.IP "\fITemporary fixes\fR" -.sp 0 -Suppose a tree has 5 revisions grouped in 2 releases, -as illustrated in Figure 2. -Revision 1.3, the last one of release 1, is in operation at customer sites, -while release 2 is in active development. -.ne 4 -.PS 4i -.ps -2 -box "1.1" -arrow -box "1.2" -arrow -box "1.3" -arrow -box "2.1" -arrow -box "2.2" -arrow dashed -.ps +2 -.PE -.ce 1 -Figure 2. A slender revision tree. -.sp 0 -Now imagine a customer requesting a fix of -a problem in revision 1.3, although actual development has moved on -to release 2. RCS does not permit an extra -revision to be spliced in between 1.3 and 2.1, since that would not reflect -the actual development history. Instead, create a branch -at revision 1.3, and check in the fix on that branch. -The first branch starting at 1.3 has number 1.3.1, and -the revisions on that branch are numbered 1.3.1.1, 1.3.1.2, etc. -The double numbering is needed to allow for another -branch at 1.3, say 1.3.2. -Revisions on the second branch would be numbered -1.3.2.1, 1.3.2.2, and so on. -The following steps create -branch 1.3.1 and add revision 1.3.1.1: -.sp 0 -.I -.nr VS 12p -.vs 12p -.TS -tab(%); -l l l. - %co \-r1.3 f.c% \*- check out revision 1.3 - %edit f.c% \*- change it - %ci \-r1.3.1 f.c% \*- check it in on branch 1.3.1 -.TE -.nr VS 18p -.vs 18p -.R -This sequence of commands transforms the tree of Figure 2 into -the one in Figure 3. -Note that it may be necessary to incorporate the differences -between 1.3 and 1.3.1.1 -into a revision at level 2. The operation \fIrcsmerge\fR automates this -process (see the Appendix). -.ne 7 -.PS 4i -.ps -2 - box "1.1" - arrow - box "1.2" - arrow -R13: box "1.3" - arrow -R21: box "2.1" - arrow -R22: box "2.2" - arrow dashed - line invis down from R21.s -RB1: box "1.3.1.1" - arrow dashed right from RB1.e - arrow from R13.s to RB1.w -.ps +2 -.PE -.ce 1 -Figure 3. A revision tree with one side branch -.sp -.IP "\fIDistributed development and customer modifications\fR" -.sp 0 -Assume a situation as in Figure 2, where revision 1.3 is in operation -at several customer sites, -while release 2 is in development. -Customer sites should use RCS to store the distributed software. -However, customer modifications should not be placed on the same branch -as the distributed source; instead, they should be placed on a side branch. -When the next software distribution arrives, -it should be appended to the trunk of -the customer's RCS file, and the customer -can then merge the local modifications back into the new release. -In the above example, a -customer's RCS file would contain the following tree, assuming -that the customer has received revision 1.3, added his local modifications -as revision 1.3.1.1, then received revision 2.4, and merged -2.4 and 1.3.1.1, resulting in 2.4.1.1. -.ne 7 -.PS 4i -.ps -2 -R13: box "1.3" - line invis -R21: box invis - line invis -R22: box invis - line invis -R24: box "2.4" - line invis -R25: box invis - line invis - arrow from R13.e to R24.w - line invis down from R21.s -RB1: box "1.3.1.1" - arrow from R13.s to RB1.w - right - line invis down from R25.s -RB2: box "2.4.1.1" - arrow from R24.s to RB2.w -.ps +2 -.PE -.ce 1 -Figure 4. A customer's revision tree with local modifications. -.sp 1 -This approach is actually practiced in the CSNET project, -where several universities and a company cooperate -in developing a national computer network. -.IP "\fIParallel development\fR" -.sp 0 -Sometimes it is desirable to explore an alternate design or -a different implementation technique in parallel with the -main line development. Such development -should be carried out on a side branch. -The experimental changes may later be moved into the main line, or abandoned. -.IP "\fIConflicting updates\fR" -.sp 0 -A common occurrence is that one programmer -has checked out a revision, but cannot complete the assignment -for some reason. In the meantime, another person -must perform another modification -immediately. In that case, the second person should check-out the same revision, -modify it, and check it in on a side branch, for later merging. -.PP -Every node in a revision tree consists of the following attributes: -a revision number, a check-in date and time, the author's identification, -a log entry, a state and the actual text. All these attributes -are determined at the time the revision is checked in. -The state attribute indicates the status of a revision. -It is set automatically to `experimental' during check-in. -A revision can later be promoted to a higher status, for example -`stable' or `released'. The set of states is user-defined. -.NH 2 -Revisions are represented as deltas -.PP -For conserving space, RCS stores revisions in the form -of deltas, i.e., as differences between revisions. -The user interface completely hides this fact. -.PP -A delta is a sequence of edit commands that transforms one string -into another. The deltas employed by RCS are line-based, which means -that the only edit commands allowed are insertion and deletion of lines. -If a single character in a line is changed, the -edit scripts consider the entire line changed. -The program \fIdiff\fR\u2\d -produces a small, line-based delta between pairs of text files. -A character-based edit script would take much longer to compute, -and would not be significantly shorter. -.PP -Using deltas is a classical space-time tradeoff: deltas reduce the -space consumed, but increase access time. -However, a version control tool should impose as little delay -as possible on programmers. -Excessive delays discourage the use of version controls, -or induce programmers to take shortcuts that compromise system integrity. -To gain reasonably fast access time for both editing and compiling, -RCS arranges deltas in the following way. -The most recent revision on the trunk is stored intact. -All other revisions on the trunk are stored as reverse deltas. -A reverse delta describes how to go backward in the development history: -it produces the desired revision if applied to the successor of that revision. -This implementation has the advantage -that extraction of the latest revision is a simple and fast copy -operation. -Adding a new revision to the trunk is also fast: \fIci\fR simply -adds the new revision intact, replaces the previous -revision with a reverse delta, and keeps the rest of the old deltas. -Thus, \fIci\fR requires the computation -of only one new delta. -.PP -Branches need special treatment. The naive solution would be to -store complete copies for the tips of all branches. -Clearly, this approach would cost too much space. Instead, -RCS uses \fIforward\fR deltas for branches. Regenerating a revision -on a side branch proceeds as follows. First, extract the latest revision -on the trunk; secondly, apply reverse deltas until the fork revision for -the branch is obtained; thirdly, apply forward deltas until the desired -branch revision is reached. Figure 5 illustrates a tree with -one side branch. Triangles pointing to the left and right represent -reverse and forward deltas, respectively. -.ne 8 -.PS 4i -.ps -2 -define BD X [line invis $1 right .5; -line up .3 then left .5 down .3 then right .5 down .3 then up .3] X - -define FD X [line invis $1 right .5; -line left .5 down .3 then up .6 then right .5 down .3;] X - -right -D11: BD(" 1.1") - arrow right from D11.e -D12: BD(" 1.2") - arrow right from D12.e -D13: BD(" 1.3") - arrow right from D13.e -D21: BD(" 2.1") - arrow right from D21.e -D22: box "2.2" - line invis down from D21.s -F1: FD("1.3.1.1 ") - arrow from D13.se to F1.w - arrow from F1.e right - right -F2: FD("1.3.1.2 ") -.ps +2 -.PE -.ce 1 -Figure 5. A revision tree with reverse and forward deltas. -.sp 0 -.PP -Although implementing fast check-out for the latest trunk revision, -this arrangement has the disadvantage that generation of other revisions -takes time proportional to the number of deltas applied. For example, -regenerating the branch tip in Figure 5 requires application of five -deltas (including the initial one). Since usage statistics show that -the latest trunk revision is the one that is retrieved in 95 per cent -of all cases (see the section on usage statistics), biasing check-out time -in favor of that revision results in significant savings. -However, careful implementation of the delta application process is -necessary to provide low retrieval overhead for other revisions, in -particular for branch tips. -.PP -There are several techniques for delta application. -The naive one is to pass each delta to a general-purpose text editor. -A prototype of RCS invoked the UNIX editor \fIed\fR both -for applying deltas and for expanding the identification markers. -Although easy to implement, performance was poor, owing to the -high start-up costs and excess generality of \fIed\fR. An intermediate -version of RCS used a special-purpose, stream-oriented editor. -This technique reduced the cost of applying a delta to the cost of -checking out the latest trunk revision. The reason for this behavior -is that each delta application involves a complete pass over -the preceding revision. -.PP -However, there is a much better algorithm. Note that the deltas are -line oriented and that most of the work of a stream editor involves -copying unchanged lines from one revision to the next. A faster -algorithm avoids unnecessary copying of character strings by using -a \fIpiece table\fR. -A piece table is a one-dimensional array, specifying how a given -revision is `pieced together' from lines in the RCS file. -Suppose piece table \fIPT\dr\u\fR represents revision \fIr\fR. -Then \fIPT\dr\u[i]\fR contains the starting position of line \fIi\fR -of revision \fIr\fR. -Application of the next delta transforms piece table \fIPT\dr\u\fR -into \fIPT\dr+1\u\fR. For instance, a delete command removes a -series of entries from the piece table. An insertion command inserts -new entries, moving the entries following the insertion point further down the -array. The inserted entries point to the text lines in the delta. -Thus, no I/O is involved except for reading the delta itself. When all -deltas have been applied to the piece table, a sequential pass -through the table looks up each line in the RCS file and copies it to -the output file, updating identification markers at the same time. -Of course, the RCS file must permit random access, since the copied -lines are scattered throughout that file. Figure 6 illustrates an -RCS file with two revisions and the corresponding piece tables. -.ne 13 -.sp 6 -.ce 1 -\fIFigure 6 is not available.\fP -.sp 5 -.ce 1 -Figure 6. An RCS file and its piece tables -.sp 0 -.PP -The piece table approach has the property that the time for applying a single -delta is roughly determined by the size of the delta, and not by the -size of the revision. For example, if a delta is -10 per cent of the size of a revision, then applying it takes only -10 per cent of the time to generate the latest trunk revision. (The stream -editor would take 100 per cent.) -.PP -There is an important alternative for representing deltas that affects -performance. SCCS\u3\d, -a precursor of RCS, uses \fIinterleaved\fR deltas. -A file containing interleaved deltas is partitioned into blocks of lines. -Each block has a header that specifies to which revision(s) the block -belongs. The blocks are sorted out in such a way that a single -pass over the file can pick up all the lines belonging to a given -revision. Thus, the regeneration time for all revisions is the same: -all headers must be inspected, and the associated blocks either copied -or skipped. As the number of revisions increases, the cost of retrieving -any revision is much higher than the cost of checking out the -latest trunk revision with reverse deltas. A detailed comparison -of SCCS's interleaved deltas and RCS's reverse deltas can be found -in Reference 4. -This reference considers the version of RCS with the -stream editor only. The piece table method improves performance -further, so that RCS is always faster than SCCS, except if 10 -or more deltas are applied. -.PP -Additional speed-up for both delta methods can be obtained by caching -the most recently generated revision, as has been implemented in DSEE.\u5\d -With caching, access time to frequently used revisions can approach normal file -access time, at the cost of some additional space. -.NH -Locking: A Controversial Issue -.PP -The locking mechanism for RCS was difficult to design. -The problem and its solution are first presented in their `pure' form, -followed by a discussion of the complications -caused by `real-world' considerations. -.PP -RCS must prevent two or more persons from depositing competing changes of the -same revision. -Suppose two programmers check out revision 2.4 and -modify it. Programmer A checks in a revision before programmer B\&. -Unfortunately, programmer B has not seen A's -changes, so the effect is that A's changes are covered up by B's deposit. -A's changes are not lost since all revisions -are saved, but they are confined to a single revision.\(dd -.FS \(dd -Note that this problem is entirely different from the atomicity problem. -Atomicity means that -concurrent update operations on the same RCS file cannot be permitted, -because that may result in inconsistent data. -Atomic updates are essential (and implemented in RCS), -but do not solve the conflict discussed here. -.FE -.PP -This conflict is prevented in RCS by locking. -Whenever someone intends to edit a revision (as opposed -to reading or compiling it), the revision should be checked out -and locked, -using the \fI\-l\fR option on \fIco\fR. On subsequent check-in, -\fIci\fR tests the lock and then removes it. -At most one programmer at a time may -lock a particular revision, and only this programmer may check in -the succeeding revision. -Thus, while a revision is locked, it is the exclusive responsibility -of the locker. -.PP -An important maxim for software tools like RCS is that they must -not stand in the way of making progress with a project. -This consideration leads to several weakenings of the locking mechanism. -First of all, even if a revision is locked, it can -still be checked out. This is necessary if other people -wish to compile or inspect the locked revision -while the next one is in preparation. The only operations they -cannot do are to lock the revision or to check in the succeeding one. Secondly, -check-in operations on other branches in the RCS file are still possible; the -locking of one revision does not affect any other revision. -Thirdly, revisions are occasionally locked for a long period of time -because a programmer is absent or otherwise unable to complete -the assignment. If another programmer has to make a pressing change, -there are the following three alternatives for making progress: -a) find out who is holding the lock and ask that person to release it; -b) check out the locked revision, modify it, check it -in on a branch, and merge the changes later; -c) break the lock. Breaking a lock leaves a highly visible -trace, namely an electronic mail message that is sent automatically to the -holder of the lock, recording the breaker and a commentary requested from him. -Thus, breaking locks is tolerated under certain circumstances, -but will not go unnoticed. -Experience has shown that the automatic mail message attaches a high enough -stigma to lock breaking, -such that programmers break locks only in real emergencies, -or when a co-worker resigns and leaves locked revisions behind. -.PP -If an RCS file is private, i.e., when a programmer owns an RCS file -and does not expect anyone else to perform check-in operations, -locking is an unnecessary nuisance. -In this case, -the `strict locking feature' discussed earlier may be disabled, -provided that file protection -is set such that only the owner may write the RCS file. -This has the effect that only the owner can check-in revisions, -and that no lock is needed for doing so. -.PP -As added protection, -each RCS file contains an access list that specifies the users -who may execute update operations. If an access list is empty, -only normal UNIX file protection applies. Thus, the access list is -useful for restricting the set of people who would otherwise have update -permission. Just as with locking, the access list -has no effect on read-only operations such as \fIco\fR. This approach -is consistent with the UNIX philosophy of openness, which contributes -to a productive software development environment. -.NH -Configuration Management -.PP -The preceding sections described how RCS deals with revisions of individual -components; this section discusses how to handle configurations. -A configuration is a set of revisions, where each revision comes -from a different revision group, and the revisions are selected -according to a certain criterion. -For example, -in order to build a functioning compiler, the `right' -revisions from the scanner, the parser, the optimizer -and the code generator must be combined. -RCS, in conjunction with MAKE, -provides a number of facilities to effect a smooth selection. -.NH 2 -RCS Selection Functions -.PP -.IP "\fIDefault selection\fR" -.sp 0 -During development, the usual selection criterion is to choose -the latest revision of all components. The \fIco\fR command -makes this selection by default. For example, the command -.D( -co *,v -.D) -retrieves the latest revision on the default branch of each RCS file -in the current directory. -The default branch is usually the trunk, but may be -set to be a side branch. -Side branches as defaults are needed in distributed software development, -as discussed in the section on the RCS revision tree. -.sp -.IP "\fIRelease based selection\fR" -.sp 0 -Specifying a release or branch number selects the latest revision in -that release or branch. -For instance, -.D( -co \-r2 *,v -.D) -retrieves the latest revision with release number 2 from each RCS file. -This selection is convenient if a release has been completed and -development has moved on to the next release. -.sp -.IP "\fIState and author based selection\fR" -.sp 0 -If the highest level number within a given release number -is not the desired one, -the state attribute can help. For example, -.D( -co \-r2 \-sReleased *,v -.D) -retrieves the latest revision with release number 2 whose state attribute -is `Released'. -Of course, the state attribute has to be set appropriately, using the -\fIci\fR or \fIrcs\fR commands. -Another alternative is to select a revision by its author, -using the \fI\-w\fR option. -.sp -.IP "\fIDate based selection\fR" -.sp 0 -Revisions may also be selected by date. -Suppose a release of an entire system was -completed and current on March 4, at 1:00 p.m. local time. Then the command -.D( -co \-d'March 4, 1:00 pm LT' *,v -.D) -checks out all the components of that release, independent of the numbering. -The \fI\-d\fR option specifies a `cutoff date', i.e., -the revision selected has a check-in date that -is closest to, but not after the date given. -.IP "\fIName based selection\fR" -.sp 0 -The most powerful selection function is based on assigning symbolic -names to revisions and branches. -In large systems, a single release number or date is not sufficient -to collect the appropriate revisions from all groups. -For example, suppose one wishes to combine release 2 -of one subsystem and release 15 of another. -Most likely, the creation dates of those releases differ also. -Thus, a single revision number or date passed to the \fIco\fR command -will not suffice to select the right revisions. -Symbolic revision numbers solve this problem. -Each RCS file may contain a set of symbolic names that are mapped -to numeric revision numbers. For example, assume -the symbol \fIV3\fR is bound to release number 2 in file \fIs,v\fR, and to -revision number 15.9 in \fIt,v\fR. -Then the single command -.D( -co \-rV3 s,v t,v -.D) -retrieves the latest revision of release 2 from \fIs,v\fR, -and revision 15.9 from \fIt,v\fR. -In a large system with many modules, checking out all -revisions with one command greatly simplifies configuration management. -.PP -Judicious use of symbolic revision numbers helps with organizing -large configurations. -A special command, \fIrcsfreeze\fR, -assigns a symbolic revision number to a selected revision -in every RCS file. -\fIRcsfreeze\fR effectively freezes a configuration. -The assigned symbolic revision number selects all components -of the configuration. -If necessary, symbolic numbers -may even be intermixed with numeric ones. Thus, \fIV3.5\fR in the -above example -would select revision 2.5 in \fIs,v\fR and branch 15.9.5 in \fIt,v\fR. -.PP -The options \fI\-r\fR, \fI\-s\fR, \fI\-w\fR and \fI\-d\fR -may be combined. If a branch is given, the latest revision -on that branch satisfying all conditions is retrieved; -otherwise, the default branch is used. -.NH 2 -Combining MAKE and RCS -.PP -MAKE\u1\d -is a program that processes configurations. -It is driven by configuration specifications -recorded in a special file, called a `Makefile'. -MAKE avoids redundant processing steps -by comparing creation dates of source and processed objects. -For example, when instructed to compile all -modules of a given system, it only recompiles -those source modules that were changed -since they were processed last. -.PP -MAKE has been extended with an auto-checkout feature for RCS.* -.FS * -This auto-checkout extension is available only in some versions of MAKE, -e.g. GNU MAKE. -.FE -When a certain file to be processed is not present, -MAKE attempts a check-out operation. -If successful, MAKE performs the required processing, and then deletes -the checked out file to conserve space. -The selection parameters discussed above can be passed to MAKE -either as parameters, or directly embedded in the Makefile. -MAKE has also been extended to search the subdirectory named \fIRCS\fR -for needed files, rather than just the current working directory. -However, if a working file is present, MAKE totally ignores the corresponding -RCS file and uses the working file. -(In newer versions of MAKE distributed by AT&T and others, -auto-checkout can be -achieved with the rule DEFAULT, instead of a special extension of MAKE. -However, a file checked out by the rule DEFAULT -will not be deleted after processing. \fIRcsclean\fR can be -used for that purpose.) -.PP -With auto-checkout, RCS/MAKE can effect a selection rule -especially tuned for multi-person software development and maintenance. -In these situations, -programmers should obtain configurations that consist of -the revisions they have personally checked out plus the latest -checked in revision of all other revision groups. -This schema can be set up as follows. -.PP -Each programmer chooses a working directory -and places into it a symbolic link, named \fIRCS\fR, -to the directory containing the relevant RCS files. -The symbolic link makes sure that \fIco\fR and \fIci\fR -operations need only specify the working files, and that -the Makefile need not be changed. -The programmer then checks out the needed files and modifies them. -If MAKE is invoked, -it composes configurations by selecting those -revisions that are checked out, and the rest from the -subdirectory \fIRCS\fR. -The latter selection may be controlled by a symbolic -revision number or any of the other selection criteria. -If there are several programmers editing in separate working directories, -they are insulated from each other's changes until checking in their -modifications. -.PP -Similarly, a maintainer can recreate an older configuration -by starting to work in an empty working directory. -During the initial MAKE invocation, all revisions are selected from RCS files. -As the maintainer checks out files and modifies them, -a new configuration is gradually built up. -Every time MAKE is invoked, it substitutes the modified revisions -into the configuration being manipulated. -.PP -A final application of RCS is to use it for storing Makefiles. -Revision groups of Makefiles represent -multiple versions of configurations. -Whenever a configuration is baselined or distributed, -the best approach is to unambiguously fix -the configuration with a symbolic revision number by calling -\fIrcsfreeze\fR, -to embed that symbol into the Makefile, and to -check in the Makefile (using the same symbolic revision number). -With this approach, old configurations -can be regenerated easily and reliably. -.NH -Usage Statistics -.PP -The following usage statistics were collected on two DEC VAX-11/780 -computers of the Purdue Computer Science Department. Both machines -are mainly used for research purposes. Thus, the data -reflect an environment in which the majority of projects -involve prototyping and advanced software development, -but relatively little long-term maintenance. -.PP -For the first experiment, -the \fIci\fR and \fIco\fR operations were instrumented -to log the number of backward and forward deltas applied. -The data were collected during a 13 month period -from Dec. 1982 to Dec. 1983. -Table I summarizes the results. -.sp 0 -.nr VS 12p -.vs 12p -.TS -center,box,tab(#); -c|c|c|c|c s|c s -c|c|c|c|c s|c s -l|n|n|n|n n|n n. -Operation#Total#Total deltas#Mean deltas#Operations#Branch - #operations #applied#applied#with >1 delta#operations -_ -co # 7867# 9320#1.18#509#(6%)#203#(3%) -ci # 3468# 2207#0.64# 85#(2%)# 75#(2%) -ci & co#11335#11527#1.02#594#(5%)#278#(2%) -.TE -.ce 1 -Table I. Statistics for \fIco\fR and \fIci\fR operations. -.nr VS 18p -.vs 18p -.PP -The first two lines show statistics for check-out and check-in; -the third line shows the combination. -Recall that \fIci\fR performs an implicit check-out to obtain -a revision for computing the delta. -In all measures presented, the most recent revision (stored intact) -counts as one delta. The number of deltas applied represents -the number of passes necessary, where the first `pass' is a copying step. -.PP -Note that the check-out operation is executed more than -twice as frequently as the check-in operation. -The fourth column gives the mean number of deltas -applied in all three cases. -For \fIci\fR, the mean number of deltas applied is less -than one. -The reasons are that the initial check-in requires no delta at all, and that -the only time \fIci\fR requires more than one delta is for branches. -Column 5 shows the actual number of operations that applied more than one -delta. -The last column indicates that branches were not used often. -.PP -The last three columns demonstrate that the most recent trunk revision -is by far the most frequently accessed. -For RCS, check-out of -this revision is a simple copy operation, which is the absolute minimum -given the copy-semantics of \fIco\fR. -Access to older revisions and branches -is more common in non-academic environments, -yet even if access to older deltas were an order -of magnitude more frequent, -the combined average number of deltas applied would still be below 1.2. -Since RCS is faster than SCCS until up to 10 delta applications, -reverse deltas are clearly the method of choice. -.PP -The second experiment, conducted in March of 1984, -involved surveying the existing RCS files -on our two machines. The goal was to determine the mean number of -revisions per RCS file, as well as the space consumed by them. -Table II shows the results. (Tables I and II were produced at different -times and are unrelated.) -.sp 0 -.nr VS 12p -.vs 12p -.TS -center,box,tab(#); -c | c | c | c | c | c | c -c | c | c | c | c | c | c -l | n | n | n | n | n | n. - #Total RCS#Total#Mean#Mean size of#Mean size of#Overhead - #files#revisions#revisions#RCS files#revisions -_ -All files #8033#11133#1.39#6156#5585#1.10 -Files with#1477# 4578#3.10#8074#6041#1.34 -\(>= 2 deltas -.TE -.ce 1 -Table II. Statistics for RCS files. -.nr VS 18p -.vs 18p -.PP -The mean number of revisions per RCS file is 1.39. -Columns 5 and 6 show the mean sizes (in bytes) of an RCS file -and of the latest revision of each RCS file, respectively. -The `overhead' column contains the ratio of the mean sizes. -Assuming that all revisions in an RCS file are approximately the same size, -this ratio gives a measure of the space consumed by the extra revisions. -.PP -In our sample, over 80 per cent of the RCS files contained only a single revision. -The reason is that our -systems programmers routinely check in all source files -on the distribution tapes, even though they may never touch them again. -To get a better indication of how much space savings are possible -with deltas, all measures with those files -that contained 2 or more revisions were recomputed. Only for those files -is RCS necessary. -As shown in the second line, the average number of revisions for those files is -3.10, with an overhead of 1.34. This means that the extra 2.10 deltas -require 34 per cent extra space, or -16 per cent per extra revision. -Rochkind\u3\d -measured the space consumed by SCCS, and -reported an average of 5 revisions per group -and an overhead of 1.37 (or about 9 per cent per extra revision). -In a later paper, Glasser\u6\d -observed an average of 7 revisions per group in a single, large project, -but provided no overhead figure. -In his paper on DSEE\u5\d, -Leblang reported that delta storage combined with blank compression -results in an overhead of a mere 1\-2 per cent per revision. -Since leading blanks accounted for about 20 per cent of the surveyed Pascal -programs, a revision group with 5\-10 members was smaller -than a single cleartext copy. -.PP -The above observations demonstrate clearly that the space needed -for extra revisions is small. With delta storage, the luxury of -keeping multiple revisions online is certainly affordable. -In fact, introducing a system with delta storage may reduce -storage requirements, because programmers often save back-up copies -anyway. Since back-up copies are stored much more efficiently with deltas, -introducing a system such as RCS may -actually free a considerable amount of space. -.NH -Survey of Version Control Tools -.PP -The need to keep back-up copies of software arose when -programs and data were no longer stored on paper media, but were entered -from terminals and stored on disk. -Back-up copies are desirable for reliability, and many modern editors -automatically save a back-up copy for every file touched. -This strategy -is valuable for short-term back-ups, but not suitable for long-term -version control, since an existing back-up copy is overwritten whenever the -corresponding file is edited. -.PP -Tape archives are suitable for long-term, offline storage. -If all changed files are dumped on a back-up tape once per day, old revisions -remain accessible. However, tape archives are unsatisfactory -for version control in several ways. First, backing up the file -system every 24 hours does not capture intermediate revisions. -Secondly, the old revisions are not online, -and accessing them is tedious and time-consuming. -In particular, it is impractical to -compare several old revisions of a group, -because that may require mounting and searching several tapes. -Tape archives are important fail-safe tools in the -event of catastrophic disk failures or accidental deletions, -but they are ill-suited for version control. -Conversely, version control tools do not obviate the -need for tape archives. -.PP -A natural technique for keeping several old revisions online is -to never delete a file. -Editing a file -simply creates a new file with the same -name, but with a different sequence number. -This technique, available as an option in DEC's VMS operating system, -turns out to be inadequate for version control. -First, it is prohibitively expensive in terms of storage costs, -especially since no data compression techniques are employed. -Secondly, indiscriminately storing every change produces too many -revisions, and programmers have difficulties distinguishing them. -The proliferation of revisions forces programmers to spend much time on -finding and deleting useless files. -Thirdly, most of the support functions like locking, logging, -revision selection, -and identification described in this paper are not available. -.PP -An alternative approach is to separate editing from revision control. -The user may repeatedly edit a given revision, -until freezing it with an explicit command. -Once a revision is frozen, it is stored permanently and can no longer be modified. -(In RCS, freezing a revisions is done with \fIci\fR.) -Editing a frozen revision implicitly creates a new one, which -can again be changed repeatedly until it is frozen itself. -This approach saves exactly those revisions that the user -considers important, and keeps the number of revisions manageable. -IBM's CLEAR/CASTER\u7\d, -AT&T's SCCS\u3\d, -CMU's SDC\u8\d -and DEC's CMS\u9\d, -are examples of version control systems using this approach. -CLEAR/CASTER maintains a data base of programs, specifications, -documentation and messages, using deltas. -Its goal is to provide control over the development process from a -management viewpoint. -SCCS stores multiple revisions of source text in an ancestral tree, -records a log entry for each revision, -provides access control, and has facilities -for uniquely identifying each revision. -An efficient delta technique -reduces the space consumed by each revision group. -SDC is much simpler than SCCS because it stores not more than -two revisions. However, it maintains a complete log for all old -revisions, some of which may be on back-up tape. -CMS, like SCCS, manages tree-structured revision groups, -but offers no identification mechanism. -.PP -Tools for dealing with configurations are still in a state of flux. -SCCS, SDC and CMS can be combined with MAKE or MAKE-like programs. -Since flexible selection rules are missing from all these tools, -it is sometimes difficult -to specify precisely which revision of each group -should be passed to MAKE for building a desired configuration. -The Xerox Cedar system\u10\d -provides a `System Modeller' that can rebuild -a configuration from an arbitrary set of module revisions. -The revisions of a module are only distinguished by creation time, -and there is no tool for managing groups. -Since the selection rules are primitive, -the System Modeller appears to be somewhat tedious to use. -Apollo's DSEE\u5\d -is a sophisticated software engineering environment. -It manages revision groups in a way similar to SCCS and CMS. Configurations -are built using `configuration threads'. -A configuration thread states which revision of each group -named in a configuration should be chosen. -A configuration thread may contain dynamic specifiers -(e.g., `choose the revisions I am currently working on, -and the most recent revisions otherwise'), which are bound -automatically at build time. -It also provides a notification mechanism for alerting -maintainers about the need to rebuild a system after a change. -.PP -RCS is based on a general model for describing -multi-version/multi-configuration systems\u11\d. -The model describes systems using AND/OR graphs, where AND nodes represent -configurations, and OR nodes represent version groups. -The model gives rise to a suit of selection rules for -composing configurations, almost all of which are implemented in RCS. -The revisions selected by RCS are passed to MAKE for configuration building. -Revision group management is modelled after SCCS. -RCS retains SCCS's best features, -but offers a significantly simpler user interface, -flexible selection rules, adequate integration with MAKE -and improved identification. -A detailed comparison of RCS and SCCS appears in Reference 4. -.PP -An important component of all revision control systems -is a program for computing deltas. -SCCS and RCS use the program \fIdiff\fR\u2\d, -which first computes the longest common substring of two -revisions, and then produces the delta from that substring. -The delta is simply an edit script consisting of deletion and -insertion commands that generate one revision from the other. -.PP -A delta based on a longest common substring is not necessarily minimal, -because it does not take advantage of crossing block moves. -Crossing block moves arise if two or more blocks of lines -(e.g., procedures) -appear in a different order in two revisions. -An edit script derived from a longest common substring -first deletes the shorter of the two blocks, and then reinserts it. -Heckel\u12\d -proposed an algorithm for detecting block moves, but -since the algorithm is based on heuristics, -there are conditions -under which the generated delta is far from minimal. -DSEE uses this algorithm combined with blank compression, -apparently with satisfactory overall results. -A new algorithm that is guaranteed to produce a minimal delta based on -block moves appears in Reference 13. -A future release of RCS will use this algorithm. -.PP -\fIAcknowledgements\fR: -Many people have helped make RCS a success by contributed criticisms, suggestions, -corrections, and even whole new commands (including manual pages). -The list of people is too long to be -reproduced here, but my sincere thanks for their help and -goodwill goes to all of them. -.sp -.nr VS 12p -.vs 12p -.SH -Appendix: Synopsis of RCS Operations -.LP -.IP "\fIci\fP \fB\- check in revisions\fP" -.sp 0 -\fICi\fR stores the contents of a working file into the -corresponding RCS file as a new revision. -If the RCS file doesn't exist, \fIci\fR creates it. -\fICi\fR removes the working file, unless one of the options -\fI\-u\fR or \fI\-l\fR is present. -For each check-in, \fIci\fR asks for a commentary -describing the changes relative to the previous revision. -.sp 1 -\fICi\fR assigns the revision number given by the \fI\-r\fR option; -if that option is missing, it derives the number from the -lock held by the user; if there is no lock and locking is not strict, -\fIci\fR increments the number of the latest revision on the trunk. -A side branch can only be started by explicitly specifying its -number with the \fI\-r\fR option during check-in. -.sp 1 -\fICi\fR also determines -whether the revision to be checked in is different from the -previous one, and asks whether to proceed if not. -This facility simplifies check-in operations for large systems, -because one need not remember which files were changed. -.sp 1 -The option \fI\-k\fR searches the checked in file for identification -markers containing -the attributes -revision number, check-in date, author and state, and assigns these -to the new revision rather than computing them. This option is -useful for software distribution: Recipients of distributed software -using RCS should check in updates with the \fI\-k\fR option. -This convention guarantees that revision numbers, check-in dates, -etc., are the same at all sites. -.IP "\fIco\fP \fB\- check out revisions\fP" -.sp 0 -\fICo\fR retrieves revisions according to revision number, -date, author and state attributes. It either places the revision -into the working file, or prints it on the standard output. -\fICo\fR always expands the identification markers. -.IP "\fIident\fP \fB\- extract identification markers\fP" -.sp 0 -\fIIdent\fR extracts the identification markers expanded by \fIco\fR -from any file and prints them. -.IP "\fIrcs\fP \fB\- change RCS file attributes\fP" -.sp 0 -\fIRcs\fR is an administrative operation that changes access lists, -locks, unlocks, breaks locks, toggles the strict-locking feature, -sets state attributes and symbolic revision numbers, changes the -description, and deletes revisions. A revision can -only be deleted if it is not the fork of a side branch. -.br -.ne 10 -.IP "\fIrcsclean\fP \fB\- clean working directory\fP" -.sp 0 -\fIRcsclean\fR removes working files that were checked out but never changed.* -.FS * -The \fIrcsclean\fP and \fIrcsfreeze\fP commands -are optional and are not always installed. -.FE -.IP "\fIrcsdiff\fP \fB\- compare revisions\fP" -.sp 0 -\fIRcsdiff\fR compares two revisions and prints their -difference, using the UNIX tool \fIdiff\fR. -One of the revisions compared may be checked out. -This command is useful for finding out about changes. -.IP "\fIrcsfreeze\fP \fB\- freeze a configuration\fP" -.sp 0 -\fIRcsfreeze\fR assigns the same symbolic revision number -to a given revision in all RCS files. -This command is useful for accurately recording a configuration.* -.IP "\fIrcsmerge\fP \fB\- merge revisions\fP" -.sp 0 -\fIRcsmerge\fR merges two revisions, \fIrev1\fR and \fIrev2\fR, -with respect to a common ancestor. -A 3-way file comparison determines the segments of lines that -are (a) the same in all three revisions, or (b) the same in 2 revisions, -or (c) different in all three. For all segments of type (b) where -\fIrev1\fR is the differing revision, -the segment in \fIrev1\fR replaces the corresponding segment of \fIrev2\fR. -Type (c) indicates an overlapping change, is flagged as an error, and requires user -intervention to select the correct alternative. -.IP "\fIrlog\fP \fB\- read log messages\fP" -.sp 0 -\fIRlog\fR prints the log messages and other information in an RCS file. -.bp -.LP -.nr VS 12p -.vs 12p -.]< -.ds [F 1 -.]- -.ds [K FELD02 -.ds [K MakeArticle -.ds [A Feldman, Stuart I. -.ds [D March 1979 -.ds [T Make\*-A Program for Maintaining Computer Programs -.ds [J Software\*-Practice & Experience -.ds [V 9 -.ds [N 3 -.ds [P 255-265 -.nr [P 1 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 1 journal-article -.ds [F 2 -.]- -.ds [K HUNT01 -.ds [T An Algorithm for Differential File Comparison -.ds [A Hunt, James W. -.as [A " and McIlroy, M. D. -.ds [I Computing Science Technical Report, Bell Laboratories -.ds [R 41 -.ds [D June 1976 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 4 tech-report -.ds [F 3 -.]- -.ds [K SCCS -.ds [A Rochkind, Marc J. -.ds [D Dec. 1975 -.ds [T The Source Code Control System -.ds [J IEEE Transactions on Software Engineering -.ds [V SE-1 -.ds [N 4 -.ds [P 364-370 -.nr [P 1 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 1 journal-article -.ds [F 4 -.]- -.ds [K TICH08 -.ds [T Design, Implementation, and Evaluation of a Revision Control System -.ds [A Tichy, Walter F. -.ds [B Proceedings of the 6th International Conference on Software Engineering -.ds [I ACM, IEEE, IPS, NBS -.ds [D September 1982 -.ds [P 58-67 -.nr [P 1 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 3 article-in-book -.ds [F 5 -.]- -.ds [K LEBL01 -.ds [A Leblang, David B. -.as [A " and Chase, Robert P. -.ds [T Computer-Aided Software Engineering in a Distributed Workstation Environment -.ds [O Proceedings of the ACM SIGSOFT/SIGPLAN Software Engineering Symposium -.as [O " on Practical Software Development Environments. -.ds [J SIGPLAN Notices -.ds [V 19 -.ds [N 5 -.ds [D May 1984 -.ds [P 104-112 -.nr [P 1 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 1 journal-article -.ds [F 1 -.ds [F 3 -.ds [F 6 -.]- -.ds [K SCCSEval -.ds [A Glasser, Alan L. -.ds [D Nov. 1978 -.ds [T The Evolution of a Source Code Control System -.ds [J Software Engineering Notes -.ds [V 3 -.ds [N 5 -.ds [P 122-125 -.nr [P 1 -.ds [O Proceedings of the Software Quality and Assurance Workshop. -.nr [T 0 -.nr [A 1 -.nr [O 1 -.][ 1 journal-article -.ds [F 5 -.ds [F 7 -.]- -.ds [K IBMClearCaster -.ds [A Brown, H.B. -.ds [D 1970 -.ds [T The Clear/Caster System -.ds [J Nato Conference on Software Engineering, Rome -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 1 journal-article -.ds [F 3 -.ds [F 8 -.]- -.ds [K HabermannSDC -.ds [A Habermann, A. Nico -.ds [D Jan. 1979 -.ds [T A Software Development Control System -.ds [I Technical Report, Carnegie-Mellon University, Department of Computer Science -.nr [T 0 -.nr [A 0 -.nr [O 0 -.][ 2 book -.ds [F 9 -.]- -.ds [K CMS -.ds [A DEC -.ds [T Code Management System -.ds [I Digital Equipment Corporation -.ds [O Document No.\ EA-23134-82 -.ds [D 1982 -.nr [T 0 -.nr [A 0 -.nr [O 0 -.][ 2 book -.ds [F 10 -.]- -.ds [K LAMP01 -.ds [A Lampson, Butler W. -.as [A " and Schmidt, Eric E. -.ds [T Practical Use of a Polymorphic Applicative Language -.ds [B Proceedings of the 10th Symposium on Principles of Programming Languages -.ds [I ACM -.ds [P 237-255 -.nr [P 1 -.ds [D January 1983 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 3 article-in-book -.ds [F 5 -.ds [F 11 -.]- -.ds [K TICH07 -.ds [T A Data Model for Programming Support Environments and its Application -.ds [A Tichy, Walter F. -.ds [B Automated Tools for Information System Design and Development -.ds [E Hans-Jochen Schneider and Anthony I. Wasserman -.ds [C Amsterdam -.ds [I North-Holland Publishing Company -.ds [D 1982 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 3 article-in-book -.ds [F 4 -.ds [F 2 -.ds [F 12 -.]- -.ds [K HECK01 -.ds [T A Technique for Isolating Differences Between Files -.ds [A Heckel, Paul -.ds [J Communications of the ACM -.ds [D April 1978 -.ds [V 21 -.ds [N 4 -.ds [P 264-268 -.nr [P 1 -.nr [T 0 -.nr [A 0 -.nr [O 0 -.][ 1 journal-article -.ds [F 13 -.]- -.ds [K TICH11 -.ds [T The String-to-String Correction Problem with Block Moves -.ds [A Tichy, Walter F. -.ds [D Nov. 1984 -.ds [J ACM Transactions on Computer Systems -.ds [V 2 -.ds [N 4 -.ds [P 309-321 -.nr [P 1 -.nr [T 0 -.nr [A 1 -.nr [O 0 -.][ 1 journal-article -.]> Index: gnu/usr.bin/rcs/doc/rcs_func.ms =================================================================== --- gnu/usr.bin/rcs/doc/rcs_func.ms (revision 255904) +++ gnu/usr.bin/rcs/doc/rcs_func.ms (working copy) @@ -1,95 +0,0 @@ -.SH -Functions of RCS (Revision Control System) -.PP -RCS manages software libraries. It greatly increases programmer productivity -by providing the following functions. -.IP 1. -RCS stores and retrieves multiple revisions of program and other text. -Thus, one can maintain one or more releases while developing the next -release, with a minimum of space overhead. Changes no longer destroy the -original -- previous revisions remain accessible. -.RS -.IP a. -Maintains each module as a tree of revisions. -.IP b. -Project libraries can -be organized centrally, decentralized, or any way you like. -.IP c. -RCS works for any type of text: programs, documentation, memos, papers, -graphics, VLSI layouts, form letters, etc. -.RE -.IP 2. -RCS maintains a complete history of changes. -Thus, one can find out what happened to a module easily -and quickly, without having to compare source listings or -having to track down colleagues. -.RS -.IP a. -RCS performs automatic record keeping. -.IP b. -RCS logs all changes automatically. -.IP c. -RCS guarantees project continuity. -.RE -.IP 3. -RCS manages multiple lines of development. -.IP 4. -RCS can merge multiple lines of development. -Thus, when several parallel lines of development must be consolidated -into one line, the merging of changes is automatic. -.IP 5. -RCS flags coding conflicts. -If two or more lines of development modify the same section of code, -RCS can alert programmers about overlapping changes. -.IP 6. -RCS resolves access conflicts. -When two or more programmers wish to modify the same revision, -RCS alerts the programmers and makes sure that one modification won't wipe -out the other one. -.IP 7. -RCS provides high-level retrieval functions. -Revisions can be retrieved according to ranges of revision numbers, -symbolic names, dates, authors, and states. -.IP 8. -RCS provides release and configuration control. -Revisions can be marked as released, stable, experimental, etc. -Configurations of modules can be described simply and directly. -.IP 9. -RCS performs automatic identification of modules with name, revision -number, creation time, author, etc. -Thus, it is always possible to determine which revisions of which -modules make up a given configuration. -.IP 10. -Provides high-level management visibility. -Thus, it is easy to track the status of a software project. -.RS -.IP a. -RCS provides a complete change history. -.IP b. -RCS records who did what when to which revision of which module. -.RE -.IP 11. -RCS is fully compatible with existing software development tools. -RCS is unobtrusive -- its interface to the file system is such that -all your existing software tools can be used as before. -.IP 12. -RCS' basic user interface is extremely simple. The novice need to learn -only two commands. Its more sophisticated features have been -tuned towards advanced software development environments and the -experienced software professional. -.IP 13. -RCS simplifies software distribution if customers -maintain sources with RCS also. This technique assures proper -identification of versions and configurations, and tracking of customer -modifications. Customer modifications can be merged into distributed -versions locally or by the development group. -.IP 14. -RCS needs little extra space for the revisions (only the differences). -If intermediate revisions are deleted, the corresponding -differences are compressed into the shortest possible form. -.IP 15. -RCS is implemented with reverse deltas. This means that -the latest revision, which is the one that is accessed most often, -is stored intact. All others are regenerated from the latest one -by applying reverse deltas (backward differences). This -results in fast access time for the revision needed most often. Index: gnu/usr.bin/rcs/ident/Makefile =================================================================== --- gnu/usr.bin/rcs/ident/Makefile (revision 255904) +++ gnu/usr.bin/rcs/ident/Makefile (working copy) @@ -1,8 +0,0 @@ -PROG= ident -SRCS= ident.c -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/ident/ident.1 =================================================================== --- gnu/usr.bin/rcs/ident/ident.1 (revision 255904) +++ gnu/usr.bin/rcs/ident/ident.1 (working copy) @@ -1,182 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.ds iD \\$3 \\$4 \\$5 \\$6 \\$7 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.ds u \&\s-1UTC\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH IDENT 1 \*(Dt GNU -.SH NAME -ident \- identify RCS keyword strings in files -.SH SYNOPSIS -.B ident -[ -.B \-q -] [ -.B \-V -] [ -.I file -\&.\|.\|. ] -.SH DESCRIPTION -.B ident -searches for all instances of the pattern -.BI $ keyword : "\ text\ " $ -in the named files or, if no files are named, the standard input. -.PP -These patterns are normally inserted automatically by the \*r command -.BR co (1), -but can also be inserted manually. -The option -.B \-q -suppresses -the warning given if there are no patterns in a file. -The option -.B \-V -prints -.BR ident 's -version number. -.PP -.B ident -works on text files as well as object files and dumps. -For example, if the C program in -.B f.c -contains -.IP -.ft 3 -#include -.br -static char const rcsid[] = -.br - \&"$\&Id: f.c,v \*(iD $\&"; -.br -int main() { return printf(\&"%s\en\&", rcsid) == EOF; } -.ft P -.LP -and -.B f.c -is compiled into -.BR f.o , -then the command -.IP -.B "ident f.c f.o" -.LP -will output -.nf -.IP -.ft 3 -f.c: - $\&Id: f.c,v \*(iD $ -f.o: - $\&Id: f.c,v \*(iD $ -.ft -.fi -.PP -If a C program defines a string like -.B rcsid -above but does not use it, -.BR lint (1) -may complain, and some C compilers will optimize away the string. -The most reliable solution is to have the program use the -.B rcsid -string, as shown in the example above. -.PP -.B ident -finds all instances of the -.BI $ keyword : "\ text\ " $ -pattern, even if -.I keyword -is not actually an \*r-supported keyword. -This gives you information about nonstandard keywords like -.BR $\&XConsortium$ . -.SH KEYWORDS -Here is the list of keywords currently maintained by -.BR co (1). -All times are given in Coordinated Universal Time (\*u, -sometimes called \&\s-1GMT\s0) by default, but if the files -were checked out with -.BR co 's -.BI \-z zone -option, times are given with a numeric time zone indication appended. -.TP -.B $\&Author$ -The login name of the user who checked in the revision. -.TP -.B $\&Date$ -The date and time the revision was checked in. -.TP -.B $\&Header$ -A standard header containing the full pathname of the \*r file, the -revision number, the date and time, the author, the state, -and the locker (if locked). -.TP -.B $\&Id$ -Same as -.BR $\&Header$ , -except that the \*r filename is without a path. -.TP -.B $\&Locker$ -The login name of the user who locked the revision (empty if not locked). -.TP -.B $\&Log$ -The log message supplied during checkin. -For -.BR ident 's -purposes, this is equivalent to -.BR $\&RCSfile$ . -.TP -.B $\&Name$ -The symbolic name used to check out the revision, if any. -.TP -.B $\&RCSfile$ -The name of the \*r file without a path. -.TP -.B $\&Revision$ -The revision number assigned to the revision. -.TP -.B $\&Source$ -The full pathname of the \*r file. -.TP -.B $\&State$ -The state assigned to the revision with the -.B \-s -option of -.BR rcs (1) -or -.BR ci (1). -.PP -.BR co (1) -represents the following characters in keyword values by escape sequences -to keep keyword strings well-formed. -.LP -.RS -.nf -.ne 6 -.ta \w'newline 'u -\f2char escape sequence\fP -tab \f3\et\fP -newline \f3\en\fP -space \f3\e040 -$ \e044 -\e \e\e\fP -.fi -.RE -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1992, 1993 Paul Eggert. -.SH "SEE ALSO" -ci(1), co(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), -rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. Index: gnu/usr.bin/rcs/ident/ident.c =================================================================== --- gnu/usr.bin/rcs/ident/ident.c (revision 255904) +++ gnu/usr.bin/rcs/ident/ident.c (working copy) @@ -1,270 +0,0 @@ -/* Identify RCS keyword strings in files. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.9 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.8 1995/06/01 16:23:43 eggert - * (exiterr, reportError): New functions, needed for DOS and OS/2 ports. - * (scanfile): Use them. - * - * Revision 5.7 1994/03/20 04:52:58 eggert - * Remove `exiting' from identExit. - * - * Revision 5.6 1993/11/09 17:40:15 eggert - * Add -V. - * - * Revision 5.5 1993/11/03 17:42:27 eggert - * Test for char == EOF, not char < 0. - * - * Revision 5.4 1992/01/24 18:44:19 eggert - * lint -> RCS_lint - * - * Revision 5.3 1991/09/10 22:15:46 eggert - * Open files with FOPEN_R, not FOPEN_R_WORK, - * because they might be executables, not working files. - * - * Revision 5.2 1991/08/19 03:13:55 eggert - * Report read errors immediately. - * - * Revision 5.1 1991/02/25 07:12:37 eggert - * Don't report empty keywords. Check for I/O errors. - * - * Revision 5.0 1990/08/22 08:12:37 eggert - * Don't limit output to known keywords. - * Remove arbitrary limits and lint. Ansify and Posixate. - * - * Revision 4.5 89/05/01 15:11:54 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.4 87/10/23 17:09:57 narten - * added exit(0) so exit return code would be non random - * - * Revision 4.3 87/10/18 10:23:55 narten - * Updating version numbers. Changes relative to 1.1 are actually relative - * to 4.1 - * - * Revision 1.3 87/07/09 09:20:52 trinkle - * Added check to make sure there is at least one arg before comparing argv[1] - * with "-q". This necessary on machines that don't allow dereferncing null - * pointers (i.e. Suns). - * - * Revision 1.2 87/03/27 14:21:47 jenkins - * Port to suns - * - * Revision 4.1 83/05/10 16:31:02 wft - * Added option -q and input from reading stdin. - * Marker matching is now done with trymatch() (independent of keywords). - * - * Revision 3.4 83/02/18 17:37:49 wft - * removed printing of new line after last file. - * - * Revision 3.3 82/12/04 12:48:55 wft - * Added LOCKER. - * - * Revision 3.2 82/11/28 18:24:17 wft - * removed Suffix; added ungetc to avoid skipping over trailing KDELIM. - * - * Revision 3.1 82/10/13 15:58:51 wft - * fixed type of variables receiving from getc() (char-->int). -*/ - -#include "rcsbase.h" - -static int match P((FILE*)); -static int scanfile P((FILE*,char const*,int)); -static void reportError P((char const*)); - -mainProg(identId, "ident", "$FreeBSD$") -/* Ident searches the named files for all occurrences - * of the pattern $@: text $ where @ is a keyword. - */ - -{ - FILE *fp; - int quiet = 0; - int status = EXIT_SUCCESS; - char const *a; - - while ((a = *++argv) && *a=='-') - while (*++a) - switch (*a) { - case 'q': - quiet = 1; - break; - - case 'V': - VOID printf("RCS version %s\n", RCS_version_string); - quiet = -1; - break; - - default: - VOID fprintf(stderr, - "ident: usage: ident -{qV} [file...]\n" - ); - exitmain(EXIT_FAILURE); - break; - } - - if (0 <= quiet) - if (!a) - VOID scanfile(stdin, (char*)0, quiet); - else - do { - if (!(fp = fopen(a, FOPEN_RB))) { - reportError(a); - status = EXIT_FAILURE; - } else if ( - scanfile(fp, a, quiet) != 0 - || (argv[1] && putchar('\n') == EOF) - ) - break; - } while ((a = *++argv)); - - if (ferror(stdout) || fclose(stdout)!=0) { - reportError("standard output"); - status = EXIT_FAILURE; - } - exitmain(status); -} - -#if RCS_lint -# define exiterr identExit -#endif - void -exiterr() -{ - _exit(EXIT_FAILURE); -} - - static void -reportError(s) - char const *s; -{ - int e = errno; - VOID fprintf(stderr, "%s error: ", cmdid); - errno = e; - perror(s); -} - - - static int -scanfile(file, name, quiet) - register FILE *file; - char const *name; - int quiet; -/* Function: scan an open file with descriptor file for keywords. - * Return -1 if there's a write error; exit immediately on a read error. - */ -{ - register int c; - - if (name) { - VOID printf("%s:\n", name); - if (ferror(stdout)) - return -1; - } else - name = "standard input"; - c = 0; - while (c != EOF || ! (feof(file)|ferror(file))) { - if (c == KDELIM) { - if ((c = match(file))) - continue; - if (ferror(stdout)) - return -1; - quiet = true; - } - c = getc(file); - } - if (ferror(file) || fclose(file) != 0) { - reportError(name); - /* - * The following is equivalent to exit(EXIT_FAILURE), but we invoke - * exiterr to keep lint happy. The DOS and OS/2 ports need exiterr. - */ - VOID fflush(stderr); - VOID fflush(stdout); - exiterr(); - } - if (!quiet) - VOID fprintf(stderr, "%s warning: no id keywords in %s\n", cmdid, name); - return 0; -} - - - - static int -match(fp) /* group substring between two KDELIM's; then do pattern match */ - register FILE *fp; -{ - char line[BUFSIZ]; - register int c; - register char * tp; - - tp = line; - while ((c = getc(fp)) != VDELIM) { - if (c == EOF && feof(fp) | ferror(fp)) - return c; - switch (ctab[c]) { - case LETTER: case Letter: case DIGIT: - *tp++ = c; - if (tp < line+sizeof(line)-4) - break; - /* fall into */ - default: - return c ? c : '\n'/* anything but 0 or KDELIM or EOF */; - } - } - if (tp == line) - return c; - *tp++ = c; - if ((c = getc(fp)) != ' ') - return c ? c : '\n'; - *tp++ = c; - while( (c = getc(fp)) != KDELIM ) { - if (c == EOF && feof(fp) | ferror(fp)) - return c; - switch (ctab[c]) { - default: - *tp++ = c; - if (tp < line+sizeof(line)-2) - break; - /* fall into */ - case NEWLN: case UNKN: - return c ? c : '\n'; - } - } - if (tp[-1] != ' ') - return c; - *tp++ = c; /*append trailing KDELIM*/ - *tp = '\0'; - VOID printf(" %c%s\n", KDELIM, line); - return 0; -} Index: gnu/usr.bin/rcs/lib/Makefile =================================================================== --- gnu/usr.bin/rcs/lib/Makefile (revision 255904) +++ gnu/usr.bin/rcs/lib/Makefile (working copy) @@ -1,14 +0,0 @@ -# $FreeBSD$ - -# Define FSYNC_ALL to get slower but safer writes in case of crashes in -# the middle of CVS/RCS changes -#CFLAGS += -DFSYNC_ALL - -LIB = rcs -SRCS = maketime.c partime.c rcsedit.c rcsfcmp.c rcsfnms.c rcsgen.c \ - rcskeep.c rcskeys.c rcslex.c rcsmap.c rcsrev.c rcssyn.c rcstime.c \ - rcsutil.c merger.c version.c - -INTERNALLIB= - -.include Index: gnu/usr.bin/rcs/lib/conf.h =================================================================== --- gnu/usr.bin/rcs/lib/conf.h (revision 255904) +++ gnu/usr.bin/rcs/lib/conf.h (working copy) @@ -1,400 +0,0 @@ -/* RCS compile-time configuration */ - - /* $FreeBSD$ */ - -/* - * This file is generated automatically. - * If you edit it by hand your changes may be lost. - * Instead, please try to fix conf.sh, - * and send your fixes to rcs-bugs@cs.purdue.edu. - */ - -#define exitmain(n) return n /* how to exit from main() */ -/* #define _POSIX_C_SOURCE 2147483647L */ /* if strict C + Posix 1003.1b-1993 or later */ -/* #define _POSIX_SOURCE */ /* if strict C + Posix 1003.1-1990 */ - -#include -#include -#include - -/* Comment out #include lines below that do not work. */ -#include -#include -#include -#include -#include -/* #include */ -/* #include */ -#include -/* #include */ -#include -#include -#include -#include -#include -/* #include */ -#include -#include -/* #include */ - -/* Define boolean symbols to be 0 (false, the default), or 1 (true). */ -#define has_sys_param_h 1 /* Does #include work? */ -/* extern int errno; */ /* Uncomment if doesn't declare errno. */ -#define has_readlink 1 /* Does readlink() work? */ -#define readlink_isreg_errno EINVAL /* errno after readlink on regular file */ - -#if has_readlink && !defined(MAXSYMLINKS) -# if has_sys_param_h -# include -# endif -# ifndef MAXSYMLINKS -# define MAXSYMLINKS 20 /* BSD; not standard yet */ -# endif -#endif - -/* Comment out the typedefs below if the types are already declared. */ -/* Fix any uncommented typedefs that are wrong. */ -/* typedef int mode_t; */ -/* typedef long off_t; */ -/* typedef int pid_t; */ -/* typedef int sig_atomic_t; */ -/* typedef unsigned size_t; */ -/* typedef int ssize_t; */ -/* typedef long time_t; */ -/* typedef int uid_t; */ - -/* Comment out the keyword definitions below if the keywords work. */ -/* #define const */ -/* #define volatile */ - -/* Define boolean symbols to be 0 (false, the default), or 1 (true). */ -#define has_prototypes 1 /* Do function prototypes work? */ -#define has_stdarg 1 /* Does work? */ -/* #define has_varargs ? */ /* Does work? */ -#define va_start_args 2 /* How many args does va_start() take? */ - -#if O_BINARY - /* Text and binary i/o behave differently. */ - /* This is incompatible with Posix and Unix. */ -# define FOPEN_RB "rb" -# define FOPEN_R_WORK (Expand==BINARY_EXPAND ? "r" : "rb") -# define FOPEN_WB "wb" -# define FOPEN_W_WORK (Expand==BINARY_EXPAND ? "w" : "wb") -# define FOPEN_WPLUS_WORK (Expand==BINARY_EXPAND ? "w+" : "w+b") -# define OPEN_O_BINARY O_BINARY -#else - /* - * Text and binary i/o behave the same. - * Omit "b", since some nonstandard hosts reject it. - */ -# define FOPEN_RB "r" -# define FOPEN_R_WORK "r" -# define FOPEN_WB "w" -# define FOPEN_W_WORK "w" -# define FOPEN_WPLUS_WORK "w+" -# define OPEN_O_BINARY 0 -#endif - -/* This may need changing on non-Unix systems (notably DOS). */ -#define OPEN_CREAT_READONLY (S_IRUSR|S_IRGRP|S_IROTH) /* lock file mode */ -#define OPEN_O_LOCK 0 /* extra open flags for creating lock file */ -#define OPEN_O_WRONLY O_WRONLY /* main open flag for creating a lock file */ - -/* Define or comment out the following symbols as needed. */ -#if has_prototypes -# define P(params) params -#else -# define P(params) () -#endif -#if has_stdarg -# include -#else -# if has_varargs -# include -# else - typedef char *va_list; -# define va_dcl int va_alist; -# define va_start(ap) ((ap) = (va_list)&va_alist) -# define va_arg(ap,t) (((t*) ((ap)+=sizeof(t))) [-1]) -# define va_end(ap) -# endif -#endif -#if va_start_args == 2 -# define vararg_start va_start -#else -# define vararg_start(ap,p) va_start(ap) -#endif -#define bad_chmod_close 0 /* Can chmod() close file descriptors? */ -#define bad_creat0 0 /* Do writes fail after creat(f,0)? */ -#define bad_fopen_wplus 0 /* Does fopen(f,"w+") fail to truncate f? */ -#define getlogin_is_secure 0 /* Is getlogin() secure? Usually it's not. */ -#define has_attribute_noreturn 1 /* Does __attribute__((noreturn)) work? */ -#if has_attribute_noreturn -# define exiting __attribute__((noreturn)) -#else -# define exiting -#endif -#define has_dirent 1 /* Do opendir(), readdir(), closedir() work? */ -#define void_closedir 0 /* Does closedir() yield void? */ -#define has_fchmod 1 /* Does fchmod() work? */ -#define has_fflush_input 0 /* Does fflush() work on input files? */ -#define has_fputs 1 /* Does fputs() work? */ -#define has_ftruncate 1 /* Does ftruncate() work? */ -#define has_getuid 1 /* Does getuid() work? */ -#define has_getpwuid 1 /* Does getpwuid() work? */ -#define has_memcmp 1 /* Does memcmp() work? */ -#define has_memcpy 1 /* Does memcpy() work? */ -#define has_memmove 1 /* Does memmove() work? */ -#define has_map_fd 0 /* Does map_fd() work? */ -#define has_mmap 1 /* Does mmap() work on regular files? */ -#define has_madvise 0 /* Does madvise() work? */ -#define mmap_signal SIGBUS /* signal received if you reference nonexistent part of mmapped file */ -#define has_rename 1 /* Does rename() work? */ -#define bad_a_rename 0 /* Does rename(A,B) fail if A is unwritable? */ -#define bad_b_rename 0 /* Does rename(A,B) fail if B is unwritable? */ -#define bad_NFS_rename 0 /* Can rename(A,B) falsely report success? */ -/* typedef int void; */ /* Some ancient compilers need this. */ -#define VOID (void) /* 'VOID e;' discards the value of an expression 'e'. */ -#define has_seteuid 1 /* Does seteuid() work? See ../INSTALL.RCS. */ -#define has_setreuid 0 /* Does setreuid() work? See ../INSTALL.RCS. */ -#define has_setuid 1 /* Does setuid() exist? */ -#define has_sigaction 1 /* Does struct sigaction work? */ -#define has_sa_sigaction 1 /* Does struct sigaction have sa_sigaction? */ -#define has_signal 1 /* Does signal() work? */ -#define signal_type void /* type returned by signal handlers */ -#define sig_zaps_handler 0 /* Must a signal handler reinvoke signal()? */ -/* #define has_sigblock ? */ /* Does sigblock() work? */ -/* #define sigmask(s) (1 << ((s)-1)) */ /* Yield mask for signal number. */ -typedef size_t fread_type; /* type returned by fread() and fwrite() */ -typedef size_t freadarg_type; /* type of their size arguments */ -typedef void *malloc_type; /* type returned by malloc() */ -#define has_getcwd 1 /* Does getcwd() work? */ -/* #define has_getwd ? */ /* Does getwd() work? */ -#define needs_getabsname 0 /* Must we define getabsname? */ -#define has_mktemp 1 /* Does mktemp() work? */ -#define has_mkstemp 1 /* Does mkstemp() work? */ -#define has_NFS 1 /* Might NFS be used? */ -#define has_psiginfo 0 /* Does psiginfo() work? */ -#define has_psignal 1 /* Does psignal() work? */ -/* #define has_si_errno ? */ /* Does siginfo_t have si_errno? */ -/* #define has_sys_siglist ? */ /* Does sys_siglist[] work? */ -/* #define strchr index */ /* Use old-fashioned name for strchr()? */ -/* #define strrchr rindex */ /* Use old-fashioned name for strrchr()? */ -#define bad_unlink 0 /* Does unlink() fail on unwritable files? */ -#define has_vfork 1 /* Does vfork() work? */ -#define has_fork 1 /* Does fork() work? */ -#define has_spawn 0 /* Does spawn*() work? */ -#define has_waitpid 1 /* Does waitpid() work? */ -#define bad_wait_if_SIGCHLD_ignored 0 /* Does ignoring SIGCHLD break wait()? */ -#define RCS_SHELL "/bin/sh" /* shell to run RCS subprograms */ -#define has_printf_dot 1 /* Does "%.2d" print leading 0? */ -#define has_vfprintf 1 /* Does vfprintf() work? */ -#define has_attribute_format_printf 1 /* Does __attribute__((format(printf,N,N+1))) work? */ -#if has_attribute_format_printf -# define printf_string(m, n) __attribute__((format(printf, m, n))) -#else -# define printf_string(m, n) -#endif -#if has_attribute_format_printf && has_attribute_noreturn - /* Work around a bug in GCC 2.5.x. */ -# define printf_string_exiting(m, n) __attribute__((format(printf, m, n), noreturn)) -#else -# define printf_string_exiting(m, n) printf_string(m, n) exiting -#endif -/* #define has__doprintf ? */ /* Does _doprintf() work? */ -/* #define has__doprnt ? */ /* Does _doprnt() work? */ -/* #undef EXIT_FAILURE */ /* Uncomment this if EXIT_FAILURE is broken. */ -#define large_memory 1 /* Can main memory hold entire RCS files? */ -#ifndef LONG_MAX -#define LONG_MAX 2147483647L /* long maximum */ -#endif -/* Do struct stat s and t describe the same file? Answer d if unknown. */ -#define same_file(s,t,d) ((s).st_ino==(t).st_ino && (s).st_dev==(t).st_dev) -#define has_utimbuf 1 /* Does struct utimbuf work? */ -#define CO "/usr/bin/co" /* name of 'co' program */ -#define COMPAT2 0 /* Are version 2 files supported? */ -#define DIFF "/usr/bin/diff" /* name of 'diff' program */ -#define DIFF3 "/usr/bin/diff3" /* name of 'diff3' program */ -#define DIFF3_BIN 1 /* Is diff3 user-visible (not the /usr/lib auxiliary)? */ -#define DIFFFLAGS "-an" /* Make diff output suitable for RCS. */ -#define DIFF_L 1 /* Does diff -L work? */ -#define DIFF_SUCCESS 0 /* DIFF status if no differences are found */ -#define DIFF_FAILURE 1 /* DIFF status if differences are found */ -#define DIFF_TROUBLE 2 /* DIFF status if trouble */ -#define ED "/bin/ed" /* name of 'ed' program (used only if !DIFF3_BIN) */ -#define MERGE "/usr/bin/merge" /* name of 'merge' program */ -#define TMPDIR "/tmp" /* default directory for temporary files */ -#define SLASH '/' /* principal filename separator */ -#define SLASHes '/' /* `case SLASHes:' labels all filename separators */ -#define isSLASH(c) ((c) == SLASH) /* Is arg a filename separator? */ -#define ROOTPATH(p) isSLASH((p)[0]) /* Is p an absolute pathname? */ -#define X_DEFAULT ",v/" /* default value for -x option */ -#define SLASHSLASH_is_SLASH 1 /* Are // and / the same directory? */ -#define ALL_ABSOLUTE 1 /* Do all subprograms satisfy ROOTPATH? */ -#define DIFF_ABSOLUTE 1 /* Is ROOTPATH(DIFF) true? */ -#define SENDMAIL "/usr/sbin/sendmail" /* how to send mail */ -#define TZ_must_be_set 0 /* Must TZ be set for gmtime() to work? */ - - - -/* Adjust the following declarations as needed. */ - - -/* The rest is for the benefit of non-standard, traditional hosts. */ -/* Don't bother to declare functions that in traditional hosts do not appear, */ -/* or are declared in .h files, or return int or void. */ - - -/* traditional BSD */ - -#if has_sys_siglist && !defined(sys_siglist) - extern char const * const sys_siglist[]; -#endif - - -/* Posix (ISO/IEC 9945-1: 1990 / IEEE Std 1003.1-1990) */ - -/* */ -#ifdef O_CREAT -# define open_can_creat 1 -#else -# define open_can_creat 0 -# define O_RDONLY 0 -# define O_WRONLY 1 -# define O_RDWR 2 -# define O_CREAT 01000 -# define O_TRUNC 02000 -#endif -#ifndef O_EXCL -#define O_EXCL 0 -#endif - -/* */ -#ifndef S_IRUSR -# ifdef S_IREAD -# define S_IRUSR S_IREAD -# else -# define S_IRUSR 0400 -# endif -# ifdef S_IWRITE -# define S_IWUSR S_IWRITE -# else -# define S_IWUSR (S_IRUSR/2) -# endif -#endif -#ifndef S_IRGRP -# if has_getuid -# define S_IRGRP (S_IRUSR / 0010) -# define S_IWGRP (S_IWUSR / 0010) -# define S_IROTH (S_IRUSR / 0100) -# define S_IWOTH (S_IWUSR / 0100) -# else - /* single user OS -- not Posix or Unix */ -# define S_IRGRP 0 -# define S_IWGRP 0 -# define S_IROTH 0 -# define S_IWOTH 0 -# endif -#endif -#ifndef S_ISREG -#define S_ISREG(n) (((n) & S_IFMT) == S_IFREG) -#endif - -/* */ -#ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */ -#endif -#ifndef WIFEXITED -#define WIFEXITED(stat_val) (((stat_val) & 0377) == 0) -#endif -#ifndef WTERMSIG -#define WTERMSIG(stat_val) ((stat_val) & 0177) -#undef WIFSIGNALED /* Avoid 4.3BSD incompatibility with Posix. */ -#endif -#ifndef WIFSIGNALED -#define WIFSIGNALED(stat_val) ((unsigned)(stat_val) - 1 < 0377) -#endif - -/* */ -char *getlogin P((void)); -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -# define STDOUT_FILENO 1 -# define STDERR_FILENO 2 -#endif -#if has_fork && !has_vfork -# undef vfork -# define vfork fork -#endif -#if has_getcwd || !has_getwd - char *getcwd P((char*,size_t)); -#else - char *getwd P((char*)); -#endif -#if has_setuid && !has_seteuid -# undef seteuid -# define seteuid setuid -#endif -#if has_spawn -# if ALL_ABSOLUTE -# define spawn_RCS spawnv -# else -# define spawn_RCS spawnvp -# endif -#else -# if ALL_ABSOLUTE -# define exec_RCS execv -# else -# define exec_RCS execvp -# endif -#endif - -/* utime.h */ -#if !has_utimbuf - struct utimbuf { time_t actime, modtime; }; -#endif - - -/* Standard C library */ - -/* */ -#ifndef L_tmpnam -#define L_tmpnam 32 /* power of 2 > sizeof("/usr/tmp/xxxxxxxxxxxxxxx") */ -#endif -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif -#if has_mktemp - char *mktemp P((char*)); /* traditional */ -#else - char *tmpnam P((char*)); -#endif - -/* */ -char *getenv P((char const*)); -void _exit P((int)) exiting; -void exit P((int)) exiting; -malloc_type malloc P((size_t)); -malloc_type realloc P((malloc_type,size_t)); -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif - -/* */ -char *strcpy P((char*,char const*)); -char *strchr P((char const*,int)); -char *strrchr P((char const*,int)); -void *memcpy P((void*,void const*,size_t)); -#if has_memmove - void *memmove P((void*,void const*,size_t)); -#endif - -/* */ -time_t time P((time_t*)); Index: gnu/usr.bin/rcs/lib/maketime.c =================================================================== --- gnu/usr.bin/rcs/lib/maketime.c (revision 255904) +++ gnu/usr.bin/rcs/lib/maketime.c (working copy) @@ -1,344 +0,0 @@ -/* Convert struct partime into time_t. */ - -/* Copyright 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#if has_conf_h -# include "conf.h" -#else -# ifdef __STDC__ -# define P(x) x -# else -# define const -# define P(x) () -# endif -# include -# include -#endif - -#include "partime.h" -#include "maketime.h" - -char const maketId[] - = "$FreeBSD$"; - -static int isleap P((int)); -static int month_days P((struct tm const*)); -static time_t maketime P((struct partime const*,time_t)); - -/* -* For maximum portability, use only localtime and gmtime. -* Make no assumptions about the time_t epoch or the range of time_t values. -* Avoid mktime because it's not universal and because there's no easy, -* portable way for mktime to yield the inverse of gmtime. -*/ - -#define TM_YEAR_ORIGIN 1900 - - static int -isleap(y) - int y; -{ - return (y&3) == 0 && (y%100 != 0 || y%400 == 0); -} - -static int const month_yday[] = { - /* days in year before start of months 0-12 */ - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 -}; - -/* Yield the number of days in TM's month. */ - static int -month_days(tm) - struct tm const *tm; -{ - int m = tm->tm_mon; - return month_yday[m+1] - month_yday[m] - + (m==1 && isleap(tm->tm_year + TM_YEAR_ORIGIN)); -} - -/* -* Convert UNIXTIME to struct tm form. -* Use gmtime if available and if !LOCALZONE, localtime otherwise. -*/ - struct tm * -time2tm(unixtime, localzone) - time_t unixtime; - int localzone; -{ - struct tm *tm; -# if TZ_must_be_set - static char const *TZ; - if (!TZ && !(TZ = getenv("TZ"))) - faterror("The TZ environment variable is not set; please set it to your timezone"); -# endif - if (localzone || !(tm = gmtime(&unixtime))) - tm = localtime(&unixtime); - return tm; -} - -/* Yield A - B, measured in seconds. */ - time_t -difftm(a, b) - struct tm const *a, *b; -{ - int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); - int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int difference_in_day_of_year = a->tm_yday - b->tm_yday; - int intervening_leap_days = ( - ((ay >> 2) - (by >> 2)) - - (ay/100 - by/100) - + ((ay/100 >> 2) - (by/100 >> 2)) - ); - time_t difference_in_years = ay - by; - time_t difference_in_days = ( - difference_in_years*365 - + (intervening_leap_days + difference_in_day_of_year) - ); - return - ( - ( - 24*difference_in_days - + (a->tm_hour - b->tm_hour) - )*60 + (a->tm_min - b->tm_min) - )*60 + (a->tm_sec - b->tm_sec); -} - -/* -* Adjust time T by adding SECONDS. SECONDS must be at most 24 hours' worth. -* Adjust only T's year, mon, mday, hour, min and sec members; -* plus adjust wday if it is defined. -*/ - void -adjzone(t, seconds) - register struct tm *t; - long seconds; -{ - /* - * This code can be off by a second if SECONDS is not a multiple of 60, - * if T is local time, and if a leap second happens during this minute. - * But this bug has never occurred, and most likely will not ever occur. - * Liberia, the last country for which SECONDS % 60 was nonzero, - * switched to UTC in May 1972; the first leap second was in June 1972. - */ - int leap_second = t->tm_sec == 60; - long sec = seconds + (t->tm_sec - leap_second); - if (sec < 0) { - if ((t->tm_min -= (59-sec)/60) < 0) { - if ((t->tm_hour -= (59-t->tm_min)/60) < 0) { - t->tm_hour += 24; - if (TM_DEFINED(t->tm_wday) && --t->tm_wday < 0) - t->tm_wday = 6; - if (--t->tm_mday <= 0) { - if (--t->tm_mon < 0) { - --t->tm_year; - t->tm_mon = 11; - } - t->tm_mday = month_days(t); - } - } - t->tm_min += 24 * 60; - } - sec += 24L * 60 * 60; - } else - if (60 <= (t->tm_min += sec/60)) - if (24 <= (t->tm_hour += t->tm_min/60)) { - t->tm_hour -= 24; - if (TM_DEFINED(t->tm_wday) && ++t->tm_wday == 7) - t->tm_wday = 0; - if (month_days(t) < ++t->tm_mday) { - if (11 < ++t->tm_mon) { - ++t->tm_year; - t->tm_mon = 0; - } - t->tm_mday = 1; - } - } - t->tm_min %= 60; - t->tm_sec = (int) (sec%60) + leap_second; -} - -/* -* Convert TM to time_t, using localtime if LOCALZONE and gmtime otherwise. -* Use only TM's year, mon, mday, hour, min, and sec members. -* Ignore TM's old tm_yday and tm_wday, but fill in their correct values. -* Yield -1 on failure (e.g. a member out of range). -* Posix 1003.1-1990 doesn't allow leap seconds, but some implementations -* have them anyway, so allow them if localtime/gmtime does. -*/ - time_t -tm2time(tm, localzone) - struct tm *tm; - int localzone; -{ - /* Cache the most recent t,tm pairs; 1 for gmtime, 1 for localtime. */ - static time_t t_cache[2]; - static struct tm tm_cache[2]; - - time_t d, gt; - struct tm const *gtm; - /* - * The maximum number of iterations should be enough to handle any - * combinations of leap seconds, time zone rule changes, and solar time. - * 4 is probably enough; we use a bigger number just to be safe. - */ - int remaining_tries = 8; - - /* Avoid subscript errors. */ - if (12 <= (unsigned)tm->tm_mon) - return -1; - - tm->tm_yday = month_yday[tm->tm_mon] + tm->tm_mday - - (tm->tm_mon<2 || ! isleap(tm->tm_year + TM_YEAR_ORIGIN)); - - /* Make a first guess. */ - gt = t_cache[localzone]; - gtm = gt ? &tm_cache[localzone] : time2tm(gt,localzone); - - /* Repeatedly use the error from the guess to improve the guess. */ - while ((d = difftm(tm, gtm)) != 0) { - if (--remaining_tries == 0) - return -1; - gt += d; - gtm = time2tm(gt,localzone); - } - t_cache[localzone] = gt; - tm_cache[localzone] = *gtm; - - /* - * Check that the guess actually matches; - * overflow can cause difftm to yield 0 even on differing times, - * or tm may have members out of range (e.g. bad leap seconds). - */ - if ( (tm->tm_year ^ gtm->tm_year) - | (tm->tm_mon ^ gtm->tm_mon) - | (tm->tm_mday ^ gtm->tm_mday) - | (tm->tm_hour ^ gtm->tm_hour) - | (tm->tm_min ^ gtm->tm_min) - | (tm->tm_sec ^ gtm->tm_sec)) - return -1; - - tm->tm_wday = gtm->tm_wday; - return gt; -} - -/* -* Check *PT and convert it to time_t. -* If it is incompletely specified, use DEFAULT_TIME to fill it out. -* Use localtime if PT->zone is the special value TM_LOCAL_ZONE. -* Yield -1 on failure. -* ISO 8601 day-of-year and week numbers are not yet supported. -*/ - static time_t -maketime(pt, default_time) - struct partime const *pt; - time_t default_time; -{ - int localzone, wday; - struct tm tm; - struct tm *tm0 = 0; - time_t r; - - tm0 = 0; /* Keep gcc -Wall happy. */ - localzone = pt->zone==TM_LOCAL_ZONE; - - tm = pt->tm; - - if (TM_DEFINED(pt->ymodulus) || !TM_DEFINED(tm.tm_year)) { - /* Get tm corresponding to current time. */ - tm0 = time2tm(default_time, localzone); - if (!localzone) - adjzone(tm0, pt->zone); - } - - if (TM_DEFINED(pt->ymodulus)) - tm.tm_year += - (tm0->tm_year + TM_YEAR_ORIGIN)/pt->ymodulus * pt->ymodulus; - else if (!TM_DEFINED(tm.tm_year)) { - /* Set default year, month, day from current time. */ - tm.tm_year = tm0->tm_year + TM_YEAR_ORIGIN; - if (!TM_DEFINED(tm.tm_mon)) { - tm.tm_mon = tm0->tm_mon; - if (!TM_DEFINED(tm.tm_mday)) - tm.tm_mday = tm0->tm_mday; - } - } - - /* Convert from partime year (Gregorian) to Posix year. */ - tm.tm_year -= TM_YEAR_ORIGIN; - - /* Set remaining default fields to be their minimum values. */ - if (!TM_DEFINED(tm.tm_mon)) tm.tm_mon = 0; - if (!TM_DEFINED(tm.tm_mday)) tm.tm_mday = 1; - if (!TM_DEFINED(tm.tm_hour)) tm.tm_hour = 0; - if (!TM_DEFINED(tm.tm_min)) tm.tm_min = 0; - if (!TM_DEFINED(tm.tm_sec)) tm.tm_sec = 0; - - if (!localzone) - adjzone(&tm, -pt->zone); - wday = tm.tm_wday; - - /* Convert and fill in the rest of the tm. */ - r = tm2time(&tm, localzone); - - /* Check weekday. */ - if (r != -1 && TM_DEFINED(wday) && wday != tm.tm_wday) - return -1; - - return r; -} - -/* Parse a free-format date in SOURCE, yielding a Unix format time. */ - time_t -str2time(source, default_time, default_zone) - char const *source; - time_t default_time; - long default_zone; -{ - struct partime pt; - - if (*partime(source, &pt)) - return -1; - if (pt.zone == TM_UNDEFINED_ZONE) - pt.zone = default_zone; - return maketime(&pt, default_time); -} - -#if TEST -#include - int -main(argc, argv) int argc; char **argv; -{ - time_t default_time = time((time_t *)0); - long default_zone = argv[1] ? atol(argv[1]) : 0; - char buf[1000]; - while (fgets(buf, 1000, stdin)) { - time_t t = str2time(buf, default_time, default_zone); - printf("%s", asctime(gmtime(&t))); - } - return 0; -} -#endif Index: gnu/usr.bin/rcs/lib/maketime.h =================================================================== --- gnu/usr.bin/rcs/lib/maketime.h (revision 255904) +++ gnu/usr.bin/rcs/lib/maketime.h (working copy) @@ -1,39 +0,0 @@ -/* Yield time_t from struct partime yielded by partime. */ - -/* Copyright 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#if defined(__STDC__) || has_prototypes -# define __MAKETIME_P(x) x -#else -# define __MAKETIME_P(x) () -#endif - -struct tm *time2tm __MAKETIME_P((time_t,int)); -time_t difftm __MAKETIME_P((struct tm const *, struct tm const *)); -time_t str2time __MAKETIME_P((char const *, time_t, long)); -time_t tm2time __MAKETIME_P((struct tm *, int)); -void adjzone __MAKETIME_P((struct tm *, long)); Index: gnu/usr.bin/rcs/lib/merger.c =================================================================== --- gnu/usr.bin/rcs/lib/merger.c (revision 255904) +++ gnu/usr.bin/rcs/lib/merger.c (working copy) @@ -1,148 +0,0 @@ -/* three-way file merge internals */ - -/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#include "rcsbase.h" - -libId(mergerId, "$FreeBSD$") - - static char const *normalize_arg P((char const*,char**)); - static char const * -normalize_arg(s, b) - char const *s; - char **b; -/* - * If S looks like an option, prepend ./ to it. Yield the result. - * Set *B to the address of any storage that was allocated. - */ -{ - char *t; - if (*s == '-') { - *b = t = testalloc(strlen(s) + 3); - VOID sprintf(t, ".%c%s", SLASH, s); - return t; - } else { - *b = 0; - return s; - } -} - - int -merge(tostdout, edarg, label, argv) - int tostdout; - char const *edarg; - char const *const label[3]; - char const *const argv[3]; -/* - * Do `merge [-p] EDARG -L l0 -L l1 -L l2 a0 a1 a2', - * where TOSTDOUT specifies whether -p is present, - * EDARG gives the editing type (e.g. "-A", or null for the default), - * LABEL gives l0, l1 and l2, and ARGV gives a0, a1 and a2. - * Yield DIFF_SUCCESS or DIFF_FAILURE. - */ -{ - register int i; - FILE *f; - RILE *rt; - char const *a[3], *t; - char *b[3]; - int s; -#if !DIFF3_BIN - char const *d[2]; -#endif - - for (i=3; 0<=--i; ) - a[i] = normalize_arg(argv[i], &b[i]); - - if (!edarg) - edarg = "-E"; - -#if DIFF3_BIN - t = 0; - if (!tostdout) - t = maketemp(0); - s = run( - -1, t, - DIFF3, edarg, "-am", - "-L", label[0], - "-L", label[1], - "-L", label[2], - a[0], a[1], a[2], (char*)0 - ); - switch (s) { - case DIFF_SUCCESS: - break; - case DIFF_FAILURE: - warn("conflicts during merge"); - break; - default: - exiterr(); - } - if (t) { - if (!(f = fopenSafer(argv[0], "w"))) - efaterror(argv[0]); - if (!(rt = Iopen(t, "r", (struct stat*)0))) - efaterror(t); - fastcopy(rt, f); - Ifclose(rt); - Ofclose(f); - } -#else - for (i=0; i<2; i++) - switch (run( - -1, d[i]=maketemp(i), - DIFF, a[i], a[2], (char*)0 - )) { - case DIFF_FAILURE: case DIFF_SUCCESS: break; - default: faterror("diff failed"); - } - t = maketemp(2); - s = run( - -1, t, - DIFF3, edarg, d[0], d[1], a[0], a[1], a[2], - label[0], label[2], (char*)0 - ); - if (s != DIFF_SUCCESS) { - s = DIFF_FAILURE; - warn("overlaps or other problems during merge"); - } - if (!(f = fopenSafer(t, "a+"))) - efaterror(t); - aputs(tostdout ? "1,$p\n" : "w\n", f); - Orewind(f); - aflush(f); - if (run(fileno(f), (char*)0, ED, "-", a[0], (char*)0)) - exiterr(); - Ofclose(f); -#endif - - tempunlink(); - for (i=3; 0<=--i; ) - if (b[i]) - tfree(b[i]); - return s; -} Index: gnu/usr.bin/rcs/lib/partime.c =================================================================== --- gnu/usr.bin/rcs/lib/partime.c (revision 255904) +++ gnu/usr.bin/rcs/lib/partime.c (working copy) @@ -1,701 +0,0 @@ -/* Parse a string, yielding a struct partime that describes it. */ - -/* Copyright 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#if has_conf_h -# include "conf.h" -#else -# ifdef __STDC__ -# define P(x) x -# else -# define const -# define P(x) () -# endif -# include -# include -#endif - -#include -#undef isdigit -#define isdigit(c) (((unsigned)(c)-'0') <= 9) /* faster than stock */ - -#include "partime.h" - -char const partimeId[] - = "$FreeBSD$"; - - -/* Lookup tables for names of months, weekdays, time zones. */ - -#define NAME_LENGTH_MAXIMUM 4 - -struct name_val { - char name[NAME_LENGTH_MAXIMUM]; - int val; -}; - - -static char const *parse_decimal P((char const*,int,int,int,int,int*,int*)); -static char const *parse_fixed P((char const*,int,int*)); -static char const *parse_pattern_letter P((char const*,int,struct partime*)); -static char const *parse_prefix P((char const*,struct partime*,int*)); -static char const *parse_ranged P((char const*,int,int,int,int*)); -static int lookup P((char const*,struct name_val const[])); -static int merge_partime P((struct partime*, struct partime const*)); -static void undefine P((struct partime*)); - - -static struct name_val const month_names[] = { - {"jan",0}, {"feb",1}, {"mar",2}, {"apr",3}, {"may",4}, {"jun",5}, - {"jul",6}, {"aug",7}, {"sep",8}, {"oct",9}, {"nov",10}, {"dec",11}, - {"", TM_UNDEFINED} -}; - -static struct name_val const weekday_names[] = { - {"sun",0}, {"mon",1}, {"tue",2}, {"wed",3}, {"thu",4}, {"fri",5}, {"sat",6}, - {"", TM_UNDEFINED} -}; - -#define hr60nonnegative(t) ((t)/100 * 60 + (t)%100) -#define hr60(t) ((t)<0 ? -hr60nonnegative(-(t)) : hr60nonnegative(t)) -#define zs(t,s) {s, hr60(t)} -#define zd(t,s,d) zs(t, s), zs((t)+100, d) - -static struct name_val const zone_names[] = { - zs(-1000, "hst"), /* Hawaii */ - zd(-1000,"hast","hadt"),/* Hawaii-Aleutian */ - zd(- 900,"akst","akdt"),/* Alaska */ - zd(- 800, "pst", "pdt"),/* Pacific */ - zd(- 700, "mst", "mdt"),/* Mountain */ - zd(- 600, "cst", "cdt"),/* Central */ - zd(- 500, "est", "edt"),/* Eastern */ - zd(- 400, "ast", "adt"),/* Atlantic */ - zd(- 330, "nst", "ndt"),/* Newfoundland */ - zs( 000, "utc"), /* Coordinated Universal */ - zs( 000, "cut"), /* " */ - zs( 000, "ut"), /* Universal */ - zs( 000, "z"), /* Zulu (required by ISO 8601) */ - zd( 000, "gmt", "bst"),/* Greenwich Mean, British Summer */ - zs( 000, "wet"), /* Western Europe */ - zs( 100, "met"), /* Middle Europe */ - zs( 100, "cet"), /* Central Europe */ - zs( 200, "eet"), /* Eastern Europe */ - zs( 530, "ist"), /* India */ - zd( 900, "jst", "jdt"),/* Japan */ - zd( 900, "kst", "kdt"),/* Korea */ - zd( 1200,"nzst","nzdt"),/* New Zealand */ - { "lt", 1 }, -#if 0 - /* The following names are duplicates or are not well attested. */ - zs(-1100, "sst"), /* Samoa */ - zs(-1000, "tht"), /* Tahiti */ - zs(- 930, "mqt"), /* Marquesas */ - zs(- 900, "gbt"), /* Gambier */ - zd(- 900, "yst", "ydt"),/* Yukon - name is no longer used */ - zs(- 830, "pit"), /* Pitcairn */ - zd(- 500, "cst", "cdt"),/* Cuba */ - zd(- 500, "ast", "adt"),/* Acre */ - zd(- 400, "wst", "wdt"),/* Western Brazil */ - zd(- 400, "ast", "adt"),/* Andes */ - zd(- 400, "cst", "cdt"),/* Chile */ - zs(- 300, "wgt"), /* Western Greenland */ - zd(- 300, "est", "edt"),/* Eastern South America */ - zs(- 300, "mgt"), /* Middle Greenland */ - zd(- 200, "fst", "fdt"),/* Fernando de Noronha */ - zs(- 100, "egt"), /* Eastern Greenland */ - zs(- 100, "aat"), /* Atlantic Africa */ - zs(- 100, "act"), /* Azores and Canaries */ - zs( 000, "wat"), /* West Africa */ - zs( 100, "cat"), /* Central Africa */ - zd( 100, "mez","mesz"),/* Mittel-Europaeische Zeit */ - zs( 200, "sat"), /* South Africa */ - zd( 200, "ist", "idt"),/* Israel */ - zs( 300, "eat"), /* East Africa */ - zd( 300, "ast", "adt"),/* Arabia */ - zd( 300, "msk", "msd"),/* Moscow */ - zd( 330, "ist", "idt"),/* Iran */ - zs( 400, "gst"), /* Gulf */ - zs( 400, "smt"), /* Seychelles & Mascarene */ - zd( 400, "esk", "esd"),/* Yekaterinburg */ - zd( 400, "bsk", "bsd"),/* Baku */ - zs( 430, "aft"), /* Afghanistan */ - zd( 500, "osk", "osd"),/* Omsk */ - zs( 500, "pkt"), /* Pakistan */ - zd( 500, "tsk", "tsd"),/* Tashkent */ - zs( 545, "npt"), /* Nepal */ - zs( 600, "bgt"), /* Bangladesh */ - zd( 600, "nsk", "nsd"),/* Novosibirsk */ - zs( 630, "bmt"), /* Burma */ - zs( 630, "cct"), /* Cocos */ - zs( 700, "ict"), /* Indochina */ - zs( 700, "jvt"), /* Java */ - zd( 700, "isk", "isd"),/* Irkutsk */ - zs( 800, "hkt"), /* Hong Kong */ - zs( 800, "pst"), /* Philippines */ - zs( 800, "sgt"), /* Singapore */ - zd( 800, "cst", "cdt"),/* China */ - zd( 800, "ust", "udt"),/* Ulan Bator */ - zd( 800, "wst", "wst"),/* Western Australia */ - zd( 800, "ysk", "ysd"),/* Yakutsk */ - zs( 900, "blt"), /* Belau */ - zs( 900, "mlt"), /* Moluccas */ - zd( 900, "vsk", "vsd"),/* Vladivostok */ - zd( 930, "cst", "cst"),/* Central Australia */ - zs( 1000, "gst"), /* Guam */ - zd( 1000, "gsk", "gsd"),/* Magadan */ - zd( 1000, "est", "est"),/* Eastern Australia */ - zd( 1100,"lhst","lhst"),/* Lord Howe */ - zd( 1100, "psk", "psd"),/* Petropavlovsk-Kamchatski */ - zs( 1100,"ncst"), /* New Caledonia */ - zs( 1130,"nrft"), /* Norfolk */ - zd( 1200, "ask", "asd"),/* Anadyr */ - zs( 1245,"nz-chat"), /* Chatham */ - zs( 1300, "tgt"), /* Tongatapu */ -#endif - {"", -1} -}; - - static int -lookup (s, table) - char const *s; - struct name_val const table[]; -/* Look for a prefix of S in TABLE, returning val for first matching entry. */ -{ - int j; - char buf[NAME_LENGTH_MAXIMUM]; - - for (j = 0; j < NAME_LENGTH_MAXIMUM; j++) { - unsigned char c = *s++; - buf[j] = isupper (c) ? tolower (c) : c; - if (!isalpha (c)) - break; - } - for (; table[0].name[0]; table++) - for (j = 0; buf[j] == table[0].name[j]; ) - if (++j == NAME_LENGTH_MAXIMUM || !table[0].name[j]) - goto done; - done: - return table[0].val; -} - - - static void -undefine (t) struct partime *t; -/* Set *T to ``undefined'' values. */ -{ - t->tm.tm_sec = t->tm.tm_min = t->tm.tm_hour = t->tm.tm_mday = t->tm.tm_mon - = t->tm.tm_year = t->tm.tm_wday = t->tm.tm_yday - = t->ymodulus = t->yweek - = TM_UNDEFINED; - t->zone = TM_UNDEFINED_ZONE; -} - -/* -* Array of patterns to look for in a date string. -* Order is important: we look for the first matching pattern -* whose values do not contradict values that we already know about. -* See `parse_pattern_letter' below for the meaning of the pattern codes. -*/ -static char const * const patterns[] = { - /* - * These traditional patterns must come first, - * to prevent an ISO 8601 format from misinterpreting their prefixes. - */ - "E_n_y", "x", /* RFC 822 */ - "E_n", "n_E", "n", "t:m:s_A", "t:m_A", "t_A", /* traditional */ - "y/N/D$", /* traditional RCS */ - - /* ISO 8601:1988 formats, generalized a bit. */ - "y-N-D$", "4ND$", "Y-N$", - "RND$", "-R=N$", "-R$", "--N=D$", "N=DT", - "--N$", "---D$", "DT", - "Y-d$", "4d$", "R=d$", "-d$", "dT", - "y-W-X", "yWX", "y=W", - "-r-W-X", "r-W-XT", "-rWX", "rWXT", "-W=X", "W=XT", "-W", - "-w-X", "w-XT", "---X$", "XT", "4$", - "T", - "h:m:s$", "hms$", "h:m$", "hm$", "h$", "-m:s$", "-ms$", "-m$", "--s$", - "Y", "Z", - - 0 -}; - - static char const * -parse_prefix (str, t, pi) char const *str; struct partime *t; int *pi; -/* -* Parse an initial prefix of STR, setting *T accordingly. -* Return the first character after the prefix, or 0 if it couldn't be parsed. -* Start with pattern *PI; if success, set *PI to the next pattern to try. -* Set *PI to -1 if we know there are no more patterns to try; -* if *PI is initially negative, give up immediately. -*/ -{ - int i = *pi; - char const *pat; - unsigned char c; - - if (i < 0) - return 0; - - /* Remove initial noise. */ - while (!isalnum (c = *str) && c != '-' && c != '+') { - if (!c) { - undefine (t); - *pi = -1; - return str; - } - str++; - } - - /* Try a pattern until one succeeds. */ - while ((pat = patterns[i++]) != 0) { - char const *s = str; - undefine (t); - do { - if (!(c = *pat++)) { - *pi = i; - return s; - } - } while ((s = parse_pattern_letter (s, c, t)) != 0); - } - - return 0; -} - - static char const * -parse_fixed (s, digits, res) char const *s; int digits, *res; -/* -* Parse an initial prefix of S of length DIGITS; it must be a number. -* Store the parsed number into *RES. -* Return the first character after the prefix, or 0 if it couldn't be parsed. -*/ -{ - int n = 0; - char const *lim = s + digits; - while (s < lim) { - unsigned d = *s++ - '0'; - if (9 < d) - return 0; - n = 10*n + d; - } - *res = n; - return s; -} - - static char const * -parse_ranged (s, digits, lo, hi, res) char const *s; int digits, lo, hi, *res; -/* -* Parse an initial prefix of S of length DIGITS; -* it must be a number in the range LO through HI. -* Store the parsed number into *RES. -* Return the first character after the prefix, or 0 if it couldn't be parsed. -*/ -{ - s = parse_fixed (s, digits, res); - return s && lo<=*res && *res<=hi ? s : 0; -} - - static char const * -parse_decimal (s, digits, lo, hi, resolution, res, fres) - char const *s; - int digits, lo, hi, resolution, *res, *fres; -/* -* Parse an initial prefix of S of length DIGITS; -* it must be a number in the range LO through HI -* and it may be followed by a fraction that is to be computed using RESOLUTION. -* Store the parsed number into *RES; store the fraction times RESOLUTION, -* rounded to the nearest integer, into *FRES. -* Return the first character after the prefix, or 0 if it couldn't be parsed. -*/ -{ - s = parse_fixed (s, digits, res); - if (s && lo<=*res && *res<=hi) { - int f = 0; - if ((s[0]==',' || s[0]=='.') && isdigit ((unsigned char) s[1])) { - char const *s1 = ++s; - int num10 = 0, denom10 = 10, product; - while (isdigit ((unsigned char) *++s)) - denom10 *= 10; - s = parse_fixed (s1, s - s1, &num10); - product = num10*resolution; - f = (product + (denom10>>1)) / denom10; - f -= f & (product%denom10 == denom10>>1); /* round to even */ - if (f < 0 || product/resolution != num10) - return 0; /* overflow */ - } - *fres = f; - return s; - } - return 0; -} - - char * -parzone (s, zone) char const *s; long *zone; -/* -* Parse an initial prefix of S; it must denote a time zone. -* Set *ZONE to the number of seconds east of GMT, -* or to TM_LOCAL_ZONE if it is the local time zone. -* Return the first character after the prefix, or 0 if it couldn't be parsed. -*/ -{ - char sign; - int hh, mm, ss; - int minutesEastOfUTC; - long offset, z; - - /* - * The formats are LT, n, n DST, nDST, no, o - * where n is a time zone name - * and o is a time zone offset of the form [-+]hh[:mm[:ss]]. - */ - switch (*s) { - case '-': case '+': - z = 0; - break; - - default: - minutesEastOfUTC = lookup (s, zone_names); - if (minutesEastOfUTC == -1) - return 0; - - /* Don't bother to check rest of spelling. */ - while (isalpha ((unsigned char) *s)) - s++; - - /* Don't modify LT. */ - if (minutesEastOfUTC == 1) { - *zone = TM_LOCAL_ZONE; - return (char *) s; - } - - z = minutesEastOfUTC * 60L; - - /* Look for trailing " DST". */ - if ( - (s[-1]=='T' || s[-1]=='t') && - (s[-2]=='S' || s[-2]=='s') && - (s[-3]=='D' || s[-3]=='t') - ) - goto trailing_dst; - while (isspace ((unsigned char) *s)) - s++; - if ( - (s[0]=='D' || s[0]=='d') && - (s[1]=='S' || s[1]=='s') && - (s[2]=='T' || s[2]=='t') - ) { - s += 3; - trailing_dst: - *zone = z + 60*60; - return (char *) s; - } - - switch (*s) { - case '-': case '+': break; - default: return (char *) s; - } - } - sign = *s++; - - if (!(s = parse_ranged (s, 2, 0, 23, &hh))) - return 0; - mm = ss = 0; - if (*s == ':') - s++; - if (isdigit ((unsigned char) *s)) { - if (!(s = parse_ranged (s, 2, 0, 59, &mm))) - return 0; - if (*s==':' && s[-3]==':' && isdigit ((unsigned char) s[1])) { - if (!(s = parse_ranged (s + 1, 2, 0, 59, &ss))) - return 0; - } - } - if (isdigit ((unsigned char) *s)) - return 0; - offset = (hh*60 + mm)*60L + ss; - *zone = z + (sign=='-' ? -offset : offset); - /* - * ?? Are fractions allowed here? - * If so, they're not implemented. - */ - return (char *) s; -} - - static char const * -parse_pattern_letter (s, c, t) char const *s; int c; struct partime *t; -/* -* Parse an initial prefix of S, matching the pattern whose code is C. -* Set *T accordingly. -* Return the first character after the prefix, or 0 if it couldn't be parsed. -*/ -{ - switch (c) { - case '$': /* The next character must be a non-digit. */ - if (isdigit ((unsigned char) *s)) - return 0; - break; - - case '-': case '/': case ':': - /* These characters stand for themselves. */ - if (*s++ != c) - return 0; - break; - - case '4': /* 4-digit year */ - s = parse_fixed (s, 4, &t->tm.tm_year); - break; - - case '=': /* optional '-' */ - s += *s == '-'; - break; - - case 'A': /* AM or PM */ - /* - * This matches the regular expression [AaPp][Mm]?. - * It must not be followed by a letter or digit; - * otherwise it would match prefixes of strings like "PST". - */ - switch (*s++) { - case 'A': case 'a': - if (t->tm.tm_hour == 12) - t->tm.tm_hour = 0; - break; - - case 'P': case 'p': - if (t->tm.tm_hour != 12) - t->tm.tm_hour += 12; - break; - - default: return 0; - } - switch (*s) { - case 'M': case 'm': s++; break; - } - if (isalnum (*s)) - return 0; - break; - - case 'D': /* day of month [01-31] */ - s = parse_ranged (s, 2, 1, 31, &t->tm.tm_mday); - break; - - case 'd': /* day of year [001-366] */ - s = parse_ranged (s, 3, 1, 366, &t->tm.tm_yday); - t->tm.tm_yday--; - break; - - case 'E': /* extended day of month [1-9, 01-31] */ - s = parse_ranged (s, ( - isdigit ((unsigned char) s[0]) && - isdigit ((unsigned char) s[1]) - ) + 1, 1, 31, &t->tm.tm_mday); - break; - - case 'h': /* hour [00-23 followed by optional fraction] */ - { - int frac; - s = parse_decimal (s, 2, 0, 23, 60*60, &t->tm.tm_hour, &frac); - t->tm.tm_min = frac / 60; - t->tm.tm_sec = frac % 60; - } - break; - - case 'm': /* minute [00-59 followed by optional fraction] */ - s = parse_decimal (s, 2, 0, 59, 60, &t->tm.tm_min, &t->tm.tm_sec); - break; - - case 'n': /* month name [e.g. "Jan"] */ - if (!TM_DEFINED (t->tm.tm_mon = lookup (s, month_names))) - return 0; - /* Don't bother to check rest of spelling. */ - while (isalpha ((unsigned char) *s)) - s++; - break; - - case 'N': /* month [01-12] */ - s = parse_ranged (s, 2, 1, 12, &t->tm.tm_mon); - t->tm.tm_mon--; - break; - - case 'r': /* year % 10 (remainder in origin-0 decade) [0-9] */ - s = parse_fixed (s, 1, &t->tm.tm_year); - t->ymodulus = 10; - break; - - case_R: - case 'R': /* year % 100 (remainder in origin-0 century) [00-99] */ - s = parse_fixed (s, 2, &t->tm.tm_year); - t->ymodulus = 100; - break; - - case 's': /* second [00-60 followed by optional fraction] */ - { - int frac; - s = parse_decimal (s, 2, 0, 60, 1, &t->tm.tm_sec, &frac); - t->tm.tm_sec += frac; - } - break; - - case 'T': /* 'T' or 't' */ - switch (*s++) { - case 'T': case 't': break; - default: return 0; - } - break; - - case 't': /* traditional hour [1-9 or 01-12] */ - s = parse_ranged (s, ( - isdigit ((unsigned char) s[0]) && isdigit ((unsigned char) s[1]) - ) + 1, 1, 12, &t->tm.tm_hour); - break; - - case 'w': /* 'W' or 'w' only (stands for current week) */ - switch (*s++) { - case 'W': case 'w': break; - default: return 0; - } - break; - - case 'W': /* 'W' or 'w', followed by a week of year [00-53] */ - switch (*s++) { - case 'W': case 'w': break; - default: return 0; - } - s = parse_ranged (s, 2, 0, 53, &t->yweek); - break; - - case 'X': /* weekday (1=Mon ... 7=Sun) [1-7] */ - s = parse_ranged (s, 1, 1, 7, &t->tm.tm_wday); - t->tm.tm_wday--; - break; - - case 'x': /* weekday name [e.g. "Sun"] */ - if (!TM_DEFINED (t->tm.tm_wday = lookup (s, weekday_names))) - return 0; - /* Don't bother to check rest of spelling. */ - while (isalpha ((unsigned char) *s)) - s++; - break; - - case 'y': /* either R or Y */ - if ( - isdigit ((unsigned char) s[0]) && - isdigit ((unsigned char) s[1]) && - !isdigit ((unsigned char) s[2]) - ) - goto case_R; - /* fall into */ - case 'Y': /* year in full [4 or more digits] */ - { - int len = 0; - while (isdigit ((unsigned char) s[len])) - len++; - if (len < 4) - return 0; - s = parse_fixed (s, len, &t->tm.tm_year); - } - break; - - case 'Z': /* time zone */ - s = parzone (s, &t->zone); - break; - - case '_': /* possibly empty sequence of non-alphanumerics */ - while (!isalnum (*s) && *s) - s++; - break; - - default: /* bad pattern */ - return 0; - } - return s; -} - - static int -merge_partime (t, u) struct partime *t; struct partime const *u; -/* -* If there is no conflict, merge into *T the additional information in *U -* and return 0. Otherwise do nothing and return -1. -*/ -{ -# define conflict(a,b) ((a) != (b) && TM_DEFINED (a) && TM_DEFINED (b)) - if ( - conflict (t->tm.tm_sec, u->tm.tm_sec) || - conflict (t->tm.tm_min, u->tm.tm_min) || - conflict (t->tm.tm_hour, u->tm.tm_hour) || - conflict (t->tm.tm_mday, u->tm.tm_mday) || - conflict (t->tm.tm_mon, u->tm.tm_mon) || - conflict (t->tm.tm_year, u->tm.tm_year) || - conflict (t->tm.tm_wday, u->tm.tm_yday) || - conflict (t->ymodulus, u->ymodulus) || - conflict (t->yweek, u->yweek) || - ( - t->zone != u->zone && - t->zone != TM_UNDEFINED_ZONE && - u->zone != TM_UNDEFINED_ZONE - ) - ) - return -1; -# undef conflict -# define merge_(a,b) if (TM_DEFINED (b)) (a) = (b); - merge_ (t->tm.tm_sec, u->tm.tm_sec) - merge_ (t->tm.tm_min, u->tm.tm_min) - merge_ (t->tm.tm_hour, u->tm.tm_hour) - merge_ (t->tm.tm_mday, u->tm.tm_mday) - merge_ (t->tm.tm_mon, u->tm.tm_mon) - merge_ (t->tm.tm_year, u->tm.tm_year) - merge_ (t->tm.tm_wday, u->tm.tm_yday) - merge_ (t->ymodulus, u->ymodulus) - merge_ (t->yweek, u->yweek) -# undef merge_ - if (u->zone != TM_UNDEFINED_ZONE) t->zone = u->zone; - return 0; -} - - char * -partime (s, t) char const *s; struct partime *t; -/* -* Parse a date/time prefix of S, putting the parsed result into *T. -* Return the first character after the prefix. -* The prefix may contain no useful information; -* in that case, *T will contain only undefined values. -*/ -{ - struct partime p; - - undefine (t); - while (*s) { - int i = 0; - char const *s1; - do { - if (!(s1 = parse_prefix (s, &p, &i))) - return (char *) s; - } while (merge_partime (t, &p) != 0); - s = s1; - } - return (char *) s; -} Index: gnu/usr.bin/rcs/lib/partime.h =================================================================== --- gnu/usr.bin/rcs/lib/partime.h (revision 255904) +++ gnu/usr.bin/rcs/lib/partime.h (working copy) @@ -1,71 +0,0 @@ -/* Parse a string, yielding a struct partime that describes it. */ - -/* Copyright 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#define TM_UNDEFINED (-1) -#define TM_DEFINED(x) (0 <= (x)) - -#define TM_UNDEFINED_ZONE ((long) -24 * 60 * 60) -#define TM_LOCAL_ZONE (TM_UNDEFINED_ZONE - 1) - -struct partime { - /* - * This structure describes the parsed time. - * Only the following tm_* values in it are used: - * sec, min, hour, mday, mon, year, wday, yday. - * If TM_UNDEFINED(value), the parser never found the value. - * The tm_year field is the actual year, not the year - 1900; - * but see ymodulus below. - */ - struct tm tm; - - /* - * If !TM_UNDEFINED(ymodulus), - * then tm.tm_year is actually modulo ymodulus. - */ - int ymodulus; - - /* - * Week of year, ISO 8601 style. - * If TM_UNDEFINED(yweek), the parser never found yweek. - * Weeks start on Mondays. - * Week 1 includes Jan 4. - */ - int yweek; - - /* Seconds east of UTC; or TM_LOCAL_ZONE or TM_UNDEFINED_ZONE. */ - long zone; -}; - -#if defined(__STDC__) || has_prototypes -# define __PARTIME_P(x) x -#else -# define __PARTIME_P(x) () -#endif - -char *partime __PARTIME_P((char const *, struct partime *)); -char *parzone __PARTIME_P((char const *, long *)); Index: gnu/usr.bin/rcs/lib/rcsbase.h =================================================================== --- gnu/usr.bin/rcs/lib/rcsbase.h (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsbase.h (working copy) @@ -1,762 +0,0 @@ -/* RCS common definitions and data structures */ - -#define RCSBASE "$FreeBSD$" - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.20 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.19 1995/06/01 16:23:43 eggert - * (SIZEABLE_PATH): Don't depend on PATH_MAX: it's not worth configuring. - * (Ioffset_type,BINARY_EXPAND,MIN_UNEXPAND,MIN_UNCHANGED_EXPAND): New macros. - * (maps_memory): New macro; replaces many instances of `has_mmap'. - * (cacheptr): Renamed from cachetell. - * (struct RILE): New alternate name for RILE; the type is now recursive. - * (deallocate): New member for RILE, used for generic buffer deallocation. - * (cacheunget_): No longer take a failure arg; just call Ierror on failure. - * (struct rcslock): Renamed from struct lock, to avoid collisions with - * system headers on some hosts. All users changed. - * (basefilename): Renamed from basename, likewise. - * (dirtpname): Remove; no longer external. - * (dirlen, dateform): Remove; no longer used. - * (cmpdate, fopenSafer, fdSafer, readAccessFilenameBuffer): New functions. - * (zonelenmax): Increase to 9 for full ISO 8601 format. - * (catchmmapints): Depend on has_NFS. - * - * Revision 5.18 1994/03/17 14:05:48 eggert - * Add primitives for reading backwards from a RILE; - * this is needed to go back and find the $Log prefix. - * Specify subprocess input via file descriptor, not file name. Remove lint. - * - * Revision 5.17 1993/11/09 17:40:15 eggert - * Move RCS-specific time handling into rcstime.c. - * printf_string now takes two arguments, alas. - * - * Revision 5.16 1993/11/03 17:42:27 eggert - * Don't arbitrarily limit the number of joins. Remove `nil'. - * Add Name keyword. Don't discard ignored phrases. - * Add support for merge -A vs -E, and allow up to three labels. - * Improve quality of diagnostics and prototypes. - * - * Revision 5.15 1992/07/28 16:12:44 eggert - * Statement macro names now end in _. - * - * Revision 5.14 1992/02/17 23:02:22 eggert - * Add -T support. Work around NFS mmap SIGBUS problem. - * - * Revision 5.13 1992/01/24 18:44:19 eggert - * Add support for bad_creat0. lint -> RCS_lint - * - * Revision 5.12 1992/01/06 02:42:34 eggert - * while (E) ; -> while (E) continue; - * - * Revision 5.11 1991/10/07 17:32:46 eggert - * Support piece tables even if !has_mmap. - * - * Revision 5.10 1991/09/24 00:28:39 eggert - * Remove unexported functions. - * - * Revision 5.9 1991/08/19 03:13:55 eggert - * Add piece tables and other tuneups, and NFS workarounds. - * - * Revision 5.8 1991/04/21 11:58:20 eggert - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.7 1991/02/28 19:18:50 eggert - * Try setuid() if seteuid() doesn't work. - * - * Revision 5.6 1991/02/26 17:48:37 eggert - * Support new link behavior. Move ANSI C / Posix declarations into conf.sh. - * - * Revision 5.5 1990/12/04 05:18:43 eggert - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.4 1990/11/01 05:03:35 eggert - * Don't assume that builtins are functions; they may be macros. - * Permit arbitrary data in logs. - * - * Revision 5.3 1990/09/26 23:36:58 eggert - * Port wait() to non-Posix ANSI C hosts. - * - * Revision 5.2 1990/09/04 08:02:20 eggert - * Don't redefine NAME_MAX, PATH_MAX. - * Improve incomplete line handling. Standardize yes-or-no procedure. - * - * Revision 5.1 1990/08/29 07:13:53 eggert - * Add -kkvl. Fix type typos exposed by porting. Clean old log messages too. - * - * Revision 5.0 1990/08/22 08:12:44 eggert - * Adjust ANSI C / Posix support. Add -k, -V, setuid. Don't call access(). - * Remove compile-time limits; use malloc instead. - * Ansify and Posixate. Add support for ISO 8859. - * Remove snoop and v2 support. - * - * Revision 4.9 89/05/01 15:17:14 narten - * botched previous USG fix - * - * Revision 4.8 89/05/01 14:53:05 narten - * changed #include -> string.h for USG systems. - * - * Revision 4.7 88/11/08 15:58:45 narten - * removed defs for functions loaded from libraries - * - * Revision 4.6 88/08/09 19:12:36 eggert - * Shrink stdio code size; remove lint; permit -Dhshsize=nn. - * - * Revision 4.5 87/12/18 17:06:41 narten - * made removed BSD ifdef, now uses V4_2BSD - * - * Revision 4.4 87/10/18 10:29:49 narten - * Updating version numbers - * Changes relative to 1.1 are actually relative to 4.2 - * - * Revision 1.3 87/09/24 14:02:25 narten - * changes for lint - * - * Revision 1.2 87/03/27 14:22:02 jenkins - * Port to suns - * - * Revision 4.2 83/12/20 16:04:20 wft - * merged 3.6.1.1 and 4.1 (SMALLOG, logsize). - * moved setting of STRICT_LOCKING to Makefile. - * changed DOLLAR to UNKN (conflict with KDELIM). - * - * Revision 4.1 83/05/04 09:12:41 wft - * Added markers Id and RCSfile. - * Added Dbranch for default branches. - * - * Revision 3.6.1.1 83/12/02 21:56:22 wft - * Increased logsize, added macro SMALLOG. - * - * Revision 3.6 83/01/15 16:43:28 wft - * 4.2 prerelease - * - * Revision 3.6 83/01/15 16:43:28 wft - * Replaced dbm.h with BYTESIZ, fixed definition of rindex(). - * Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD. - * Added macro DELNUMFORM to have uniform format for printing delta text nodes. - * Added macro DELETE to mark deleted deltas. - * - * Revision 3.5 82/12/10 12:16:56 wft - * Added two forms of DATEFORM, one using %02d, the other %.2d. - * - * Revision 3.4 82/12/04 20:01:25 wft - * added LOCKER, Locker, and USG (redefinition of rindex). - * - * Revision 3.3 82/12/03 12:22:04 wft - * Added dbm.h, stdio.h, RCSBASE, RCSSEP, RCSSUF, WORKMODE, TMPFILE3, - * PRINTDATE, PRINTTIME, map, and ctab; removed Suffix. Redefined keyvallength - * using NCPPN. Changed putc() to abort on write error. - * - * Revision 3.2 82/10/18 15:03:52 wft - * added macro STRICT_LOCKING, removed RCSUMASK. - * renamed JOINFILE[1,2] to JOINFIL[1,2]. - * - * Revision 3.1 82/10/11 19:41:17 wft - * removed NBPW, NBPC, NCPW. - * added typdef int void to aid compiling - */ - - -#include "conf.h" - - -#define EXIT_TROUBLE DIFF_TROUBLE - -#ifdef _POSIX_PATH_MAX -# define SIZEABLE_PATH _POSIX_PATH_MAX -#else -# define SIZEABLE_PATH 255 /* size of a large path; not a hard limit */ -#endif - -/* for traditional C hosts with unusual size arguments */ -#define Fread(p,s,n,f) fread(p, (freadarg_type)(s), (freadarg_type)(n), f) -#define Fwrite(p,s,n,f) fwrite(p, (freadarg_type)(s), (freadarg_type)(n), f) - - -/* - * Parameters - */ - -/* backwards compatibility with old versions of RCS */ -#define VERSION_min 3 /* old output RCS format supported */ -#define VERSION_max 5 /* newest output RCS format supported */ -#ifndef VERSION_DEFAULT /* default RCS output format */ -# define VERSION_DEFAULT VERSION_max -#endif -#define VERSION(n) ((n) - VERSION_DEFAULT) /* internally, 0 is the default */ - -#ifndef STRICT_LOCKING -#define STRICT_LOCKING 1 -#endif - /* 0 sets the default locking to non-strict; */ - /* used in experimental environments. */ - /* 1 sets the default locking to strict; */ - /* used in production environments. */ - -#define yearlength 16 /* (good through AD 9,999,999,999,999,999) */ -#define datesize (yearlength+16) /* size of output of time2date */ -#define RCSTMPPREFIX '_' /* prefix for temp files in working dir */ -#define KDELIM '$' /* delimiter for keywords */ -#define VDELIM ':' /* separates keywords from values */ -#define DEFAULTSTATE "Exp" /* default state of revisions */ - - - -#define true 1 -#define false 0 - - -/* - * RILE - readonly file - * declarecache; - declares local cache for RILE variable(s) - * setupcache - sets up the local RILE cache, but does not initialize it - * cache, uncache - caches and uncaches the local RILE; - * (uncache,cache) is needed around functions that advance the RILE pointer - * Igeteof_(f,c,s) - get a char c from f, executing statement s at EOF - * cachegeteof_(c,s) - Igeteof_ applied to the local RILE - * Iget_(f,c) - like Igeteof_, except EOF is an error - * cacheget_(c) - Iget_ applied to the local RILE - * cacheunget_(f,c,s) - read c backwards from cached f, executing s at BOF - * Ifileno, Ioffset_type, Irewind, Itell - analogs to stdio routines - * - * By conventions, macros whose names end in _ are statements, not expressions. - * Following such macros with `; else' results in a syntax error. - */ - -#define maps_memory (has_map_fd || has_mmap) - -#if large_memory - typedef unsigned char const *Iptr_type; - typedef struct RILE { - Iptr_type ptr, lim; - unsigned char *base; /* not Iptr_type for lint's sake */ - unsigned char *readlim; - int fd; -# if maps_memory - void (*deallocate) P((struct RILE *)); -# else - FILE *stream; -# endif - } RILE; -# if maps_memory -# define declarecache register Iptr_type ptr, lim -# define setupcache(f) (lim = (f)->lim) -# define Igeteof_(f,c,s) if ((f)->ptr==(f)->lim) s else (c)= *(f)->ptr++; -# define cachegeteof_(c,s) if (ptr==lim) s else (c)= *ptr++; -# else - int Igetmore P((RILE*)); -# define declarecache register Iptr_type ptr; register RILE *rRILE -# define setupcache(f) (rRILE = (f)) -# define Igeteof_(f,c,s) if ((f)->ptr==(f)->readlim && !Igetmore(f)) s else (c)= *(f)->ptr++; -# define cachegeteof_(c,s) if (ptr==rRILE->readlim && !Igetmore(rRILE)) s else (c)= *ptr++; -# endif -# define uncache(f) ((f)->ptr = ptr) -# define cache(f) (ptr = (f)->ptr) -# define Iget_(f,c) Igeteof_(f,c,Ieof();) -# define cacheget_(c) cachegeteof_(c,Ieof();) -# define cacheunget_(f,c) (c)=(--ptr)[-1]; -# define Ioffset_type size_t -# define Itell(f) ((f)->ptr - (f)->base) -# define Irewind(f) ((f)->ptr = (f)->base) -# define cacheptr() ptr -# define Ifileno(f) ((f)->fd) -#else -# define RILE FILE -# define declarecache register FILE *ptr -# define setupcache(f) (ptr = (f)) -# define uncache(f) -# define cache(f) -# define Igeteof_(f,c,s) {if(((c)=getc(f))==EOF){testIerror(f);if(feof(f))s}} -# define cachegeteof_(c,s) Igeteof_(ptr,c,s) -# define Iget_(f,c) { if (((c)=getc(f))==EOF) testIeof(f); } -# define cacheget_(c) Iget_(ptr,c) -# define cacheunget_(f,c) if(fseek(ptr,-2L,SEEK_CUR))Ierror();else cacheget_(c) -# define Ioffset_type long -# define Itell(f) ftell(f) -# define Ifileno(f) fileno(f) -#endif - -/* Print a char, but abort on write error. */ -#define aputc_(c,o) { if (putc(c,o)==EOF) testOerror(o); } - -/* Get a character from an RCS file, perhaps copying to a new RCS file. */ -#define GETCeof_(o,c,s) { cachegeteof_(c,s) if (o) aputc_(c,o) } -#define GETC_(o,c) { cacheget_(c) if (o) aputc_(c,o) } - - -#define WORKMODE(RCSmode, writable) (((RCSmode)&(mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH)) | ((writable)?S_IWUSR:0)) -/* computes mode of working file: same as RCSmode, but write permission */ -/* determined by writable */ - - -/* character classes and token codes */ -enum tokens { -/* classes */ DELIM, DIGIT, IDCHAR, NEWLN, LETTER, Letter, - PERIOD, SBEGIN, SPACE, UNKN, -/* tokens */ COLON, ID, NUM, SEMI, STRING -}; - -#define SDELIM '@' /* the actual character is needed for string handling*/ -/* SDELIM must be consistent with ctab[], so that ctab[SDELIM]==SBEGIN. - * there should be no overlap among SDELIM, KDELIM, and VDELIM - */ - -#define isdigit(c) (((unsigned)(c)-'0') <= 9) /* faster than ctab[c]==DIGIT */ - - - - - -/*************************************** - * Data structures for the symbol table - ***************************************/ - -/* Buffer of arbitrary data */ -struct buf { - char *string; - size_t size; -}; -struct cbuf { - char const *string; - size_t size; -}; - -/* Hash table entry */ -struct hshentry { - char const * num; /* pointer to revision number (ASCIZ) */ - char const * date; /* pointer to date of checkin */ - char const * author; /* login of person checking in */ - char const * lockedby; /* who locks the revision */ - char const * state; /* state of revision (Exp by default) */ - char const * name; /* name (if any) by which retrieved */ - struct cbuf log; /* log message requested at checkin */ - struct branchhead * branches; /* list of first revisions on branches*/ - struct cbuf ig; /* ignored phrases in admin part */ - struct cbuf igtext; /* ignored phrases in deltatext part */ - struct hshentry * next; /* next revision on same branch */ - struct hshentry * nexthsh; /* next revision with same hash value */ - long insertlns;/* lines inserted (computed by rlog) */ - long deletelns;/* lines deleted (computed by rlog) */ - char selector; /* true if selected, false if deleted */ -}; - -/* list of hash entries */ -struct hshentries { - struct hshentries *rest; - struct hshentry *first; -}; - -/* list element for branch lists */ -struct branchhead { - struct hshentry * hsh; - struct branchhead * nextbranch; -}; - -/* accesslist element */ -struct access { - char const * login; - struct access * nextaccess; -}; - -/* list element for locks */ -struct rcslock { - char const * login; - struct hshentry * delta; - struct rcslock * nextlock; -}; - -/* list element for symbolic names */ -struct assoc { - char const * symbol; - char const * num; - struct assoc * nextassoc; -}; - - -#define mainArgs (argc,argv) int argc; char **argv; - -#if RCS_lint -# define libId(name,rcsid) -# define mainProg(name,cmd,rcsid) int name mainArgs -#else -# define libId(name,rcsid) char const name[] = rcsid; -# define mainProg(n,c,i) char const Copyright[] = "Copyright 1982,1988,1989 Walter F. Tichy, Purdue CS\nCopyright 1990,1991,1992,1993,1994,1995 Paul Eggert", baseid[] = RCSBASE, cmdid[] = c; libId(n,i) int main P((int,char**)); int main mainArgs -#endif - -/* - * Markers for keyword expansion (used in co and ident) - * Every byte must have class LETTER or Letter. - */ -#define AUTHOR "Author" -#define DATE "Date" -#define HEADER "Header" -#define IDH "Id" -#define LOCKER "Locker" -#define LOG "Log" -#define NAME "Name" -#define RCSFILE "RCSfile" -#define REVISION "Revision" -#define SOURCE "Source" -#define STATE "State" -#define CVSHEADER "CVSHeader" -#define keylength 9 /* max length of any of the above keywords */ - -enum markers { Nomatch, Author, Date, Header, Id, - Locker, Log, Name, RCSfile, Revision, Source, State, CVSHeader, - LocalId }; - /* This must be in the same order as rcskeys.c's Keyword[] array. */ - -#define DELNUMFORM "\n\n%s\n%s\n" -/* used by putdtext and scanlogtext */ - -#define EMPTYLOG "*** empty log message ***" /* used by ci and rlog */ - -/* main program */ -extern char const cmdid[]; -void exiterr P((void)) exiting; - -/* merge */ -int merge P((int,char const*,char const*const[3],char const*const[3])); - -/* rcsedit */ -#define ciklogsize 23 /* sizeof("checked in with -k by ") */ -extern FILE *fcopy; -extern char const *resultname; -extern char const ciklog[ciklogsize]; -extern int locker_expansion; -RILE *rcswriteopen P((struct buf*,struct stat*,int)); -char const *makedirtemp P((int)); -char const *getcaller P((void)); -int addlock P((struct hshentry*,int)); -int addsymbol P((char const*,char const*,int)); -int checkaccesslist P((void)); -int chnamemod P((FILE**,char const*,char const*,int,mode_t,time_t)); -int donerewrite P((int,time_t)); -int dorewrite P((int,int)); -int expandline P((RILE*,FILE*,struct hshentry const*,int,FILE*,int)); -int findlock P((int,struct hshentry**)); -int setmtime P((char const*,time_t)); -void ORCSclose P((void)); -void ORCSerror P((void)); -void copystring P((void)); -void dirtempunlink P((void)); -void enterstring P((void)); -void finishedit P((struct hshentry const*,FILE*,int)); -void keepdirtemp P((char const*)); -void openfcopy P((FILE*)); -void snapshotedit P((FILE*)); -void xpandstring P((struct hshentry const*)); -#if has_NFS || bad_unlink - int un_link P((char const*)); -#else -# define un_link(s) unlink(s) -#endif -#if large_memory - void edit_string P((void)); -# define editstring(delta) edit_string() -#else - void editstring P((struct hshentry const*)); -#endif - -/* rcsfcmp */ -int rcsfcmp P((RILE*,struct stat const*,char const*,struct hshentry const*)); - -/* rcsfnms */ -#define bufautobegin(b) clear_buf(b) -#define clear_buf(b) (VOID ((b)->string = 0, (b)->size = 0)) -extern FILE *workstdout; -extern char *workname; -extern char const *RCSname; -extern char const *suffixes; -extern int fdlock; -extern struct stat RCSstat; -RILE *rcsreadopen P((struct buf*,struct stat*,int)); -char *bufenlarge P((struct buf*,char const**)); -char const *basefilename P((char const*)); -char const *getfullRCSname P((void)); -char const *getfullCVSname P((void)); -char const *maketemp P((int)); -char const *rcssuffix P((char const*)); -int pairnames P((int,char**,RILE*(*)P((struct buf*,struct stat*,int)),int,int)); -struct cbuf bufremember P((struct buf*,size_t)); -void bufalloc P((struct buf*,size_t)); -void bufautoend P((struct buf*)); -void bufrealloc P((struct buf*,size_t)); -void bufscat P((struct buf*,char const*)); -void bufscpy P((struct buf*,char const*)); -void tempunlink P((void)); - -/* rcsgen */ -extern int interactiveflag; -extern struct buf curlogbuf; -char const *buildrevision P((struct hshentries const*,struct hshentry*,FILE*,int)); -int getcstdin P((void)); -int putdtext P((struct hshentry const*,char const*,FILE*,int)); -int ttystdin P((void)); -int yesorno P((int,char const*,...)) printf_string(2,3); -struct cbuf cleanlogmsg P((char*,size_t)); -struct cbuf getsstdin P((char const*,char const*,char const*,struct buf*)); -void putdesc P((int,char*)); -void putdftext P((struct hshentry const*,RILE*,FILE*,int)); - -/* rcskeep */ -extern int prevkeys; -extern struct buf prevauthor, prevdate, prevname, prevrev, prevstate; -int getoldkeys P((RILE*)); - -/* rcskeys */ -extern char const *Keyword[]; -extern enum markers LocalIdMode; -enum markers trymatch P((char const*)); -void setRCSLocalId(char const *); -void setIncExc(char const *); - -/* rcslex */ -extern FILE *foutptr; -extern FILE *frewrite; -extern RILE *finptr; -extern char const *NextString; -extern enum tokens nexttok; -extern int hshenter; -extern int nerror; -extern int nextc; -extern int quietflag; -extern long rcsline; -char const *getid P((void)); -void efaterror P((char const*)) exiting; -void enfaterror P((int,char const*)) exiting; -void fatcleanup P((int)) exiting; -void faterror P((char const*,...)) printf_string_exiting(1,2); -void fatserror P((char const*,...)) printf_string_exiting(1,2); -void rcsfaterror P((char const*,...)) printf_string_exiting(1,2); -void Ieof P((void)) exiting; -void Ierror P((void)) exiting; -void Oerror P((void)) exiting; -char *checkid P((char*,int)); -char *checksym P((char*,int)); -int eoflex P((void)); -int getkeyopt P((char const*)); -int getlex P((enum tokens)); -struct cbuf getphrases P((char const*)); -struct cbuf savestring P((struct buf*)); -struct hshentry *getnum P((void)); -void Ifclose P((RILE*)); -void Izclose P((RILE**)); -void Lexinit P((void)); -void Ofclose P((FILE*)); -void Orewind P((FILE*)); -void Ozclose P((FILE**)); -void aflush P((FILE*)); -void afputc P((int,FILE*)); -void aprintf P((FILE*,char const*,...)) printf_string(2,3); -void aputs P((char const*,FILE*)); -void checksid P((char*)); -void checkssym P((char*)); -void diagnose P((char const*,...)) printf_string(1,2); -void eerror P((char const*)); -void eflush P((void)); -void enerror P((int,char const*)); -void error P((char const*,...)) printf_string(1,2); -void fvfprintf P((FILE*,char const*,va_list)); -void getkey P((char const*)); -void getkeystring P((char const*)); -void nextlex P((void)); -void oflush P((void)); -void printstring P((void)); -void readstring P((void)); -void redefined P((int)); -void rcserror P((char const*,...)) printf_string(1,2); -void rcswarn P((char const*,...)) printf_string(1,2); -void testIerror P((FILE*)); -void testOerror P((FILE*)); -void warn P((char const*,...)) printf_string(1,2); -void warnignore P((void)); -void workerror P((char const*,...)) printf_string(1,2); -void workwarn P((char const*,...)) printf_string(1,2); -#if has_madvise && has_mmap && large_memory - void advise_access P((RILE*,int)); -# define if_advise_access(p,f,advice) if (p) advise_access(f,advice) -#else -# define advise_access(f,advice) -# define if_advise_access(p,f,advice) -#endif -#if large_memory && maps_memory - RILE *I_open P((char const*,struct stat*)); -# define Iopen(f,m,s) I_open(f,s) -#else - RILE *Iopen P((char const*,char const*,struct stat*)); -#endif -#if !large_memory - void testIeof P((FILE*)); - void Irewind P((RILE*)); -#endif - -/* rcsmap */ -extern enum tokens const ctab[]; - -/* rcsrev */ -char *partialno P((struct buf*,char const*,int)); -char const *namedrev P((char const*,struct hshentry*)); -char const *tiprev P((void)); -int cmpdate P((char const*,char const*)); -int cmpnum P((char const*,char const*)); -int cmpnumfld P((char const*,char const*,int)); -int compartial P((char const*,char const*,int)); -int expandsym P((char const*,struct buf*)); -int fexpandsym P((char const*,struct buf*,RILE*)); -struct hshentry *genrevs P((char const*,char const*,char const*,char const*,struct hshentries**)); -int countnumflds P((char const*)); -void getbranchno P((char const*,struct buf*)); - -/* rcssyn */ -/* These expand modes must agree with Expand_names[] in rcssyn.c. */ -#define KEYVAL_EXPAND 0 /* -kkv `$Keyword: value $' */ -#define KEYVALLOCK_EXPAND 1 /* -kkvl `$Keyword: value locker $' */ -#define KEY_EXPAND 2 /* -kk `$Keyword$' */ -#define VAL_EXPAND 3 /* -kv `value' */ -#define OLD_EXPAND 4 /* -ko use old string, omitting expansion */ -#define BINARY_EXPAND 5 /* -kb like -ko, but use binary mode I/O */ -#define MIN_UNEXPAND OLD_EXPAND /* min value for no logical expansion */ -#define MIN_UNCHANGED_EXPAND (OPEN_O_BINARY ? BINARY_EXPAND : OLD_EXPAND) - /* min value guaranteed to yield an identical file */ -struct diffcmd { - long - line1, /* number of first line */ - nlines, /* number of lines affected */ - adprev, /* previous 'a' line1+1 or 'd' line1 */ - dafter; /* sum of previous 'd' line1 and previous 'd' nlines */ -}; -extern char const * Dbranch; -extern struct access * AccessList; -extern struct assoc * Symbols; -extern struct cbuf Comment; -extern struct cbuf Ignored; -extern struct rcslock *Locks; -extern struct hshentry * Head; -extern int Expand; -extern int StrictLocks; -extern int TotalDeltas; -extern char const *const expand_names[]; -extern char const - Kaccess[], Kauthor[], Kbranch[], Kcomment[], - Kdate[], Kdesc[], Kexpand[], Khead[], Klocks[], Klog[], - Knext[], Kstate[], Kstrict[], Ksymbols[], Ktext[]; -void unexpected_EOF P((void)) exiting; -int getdiffcmd P((RILE*,int,FILE*,struct diffcmd*)); -int str2expmode P((char const*)); -void getadmin P((void)); -void getdesc P((int)); -void gettree P((void)); -void ignorephrases P((char const*)); -void initdiffcmd P((struct diffcmd*)); -void putadmin P((void)); -void putstring P((FILE*,int,struct cbuf,int)); -void puttree P((struct hshentry const*,FILE*)); - -/* rcstime */ -#define zonelenmax 9 /* maxiumum length of time zone string, e.g. "+12:34:56" */ -char const *date2str P((char const[datesize],char[datesize + zonelenmax])); -time_t date2time P((char const[datesize])); -void str2date P((char const*,char[datesize])); -void time2date P((time_t,char[datesize])); -void zone_set P((char const*)); - -/* rcsutil */ -extern int RCSversion; -FILE *fopenSafer P((char const*,char const*)); -char *cgetenv P((char const*)); -char *fstr_save P((char const*)); -char *str_save P((char const*)); -char const *getusername P((int)); -int fdSafer P((int)); -int getRCSINIT P((int,char**,char***)); -int run P((int,char const*,...)); -int runv P((int,char const*,char const**)); -malloc_type fremember P((malloc_type)); -malloc_type ftestalloc P((size_t)); -malloc_type testalloc P((size_t)); -malloc_type testrealloc P((malloc_type,size_t)); -#define ftalloc(T) ftnalloc(T,1) -#define talloc(T) tnalloc(T,1) -#if RCS_lint - extern malloc_type lintalloc; -# define ftnalloc(T,n) (lintalloc = ftestalloc(sizeof(T)*(n)), (T*)0) -# define tnalloc(T,n) (lintalloc = testalloc(sizeof(T)*(n)), (T*)0) -# define trealloc(T,p,n) (lintalloc = testrealloc((malloc_type)0, sizeof(T)*(n)), p) -# define tfree(p) -#else -# define ftnalloc(T,n) ((T*) ftestalloc(sizeof(T)*(n))) -# define tnalloc(T,n) ((T*) testalloc(sizeof(T)*(n))) -# define trealloc(T,p,n) ((T*) testrealloc((malloc_type)(p), sizeof(T)*(n))) -# define tfree(p) free((malloc_type)(p)) -#endif -time_t now P((void)); -void awrite P((char const*,size_t,FILE*)); -void fastcopy P((RILE*,FILE*)); -void ffree P((void)); -void ffree1 P((char const*)); -void setRCSversion P((char const*)); -#if has_signal - void catchints P((void)); - void ignoreints P((void)); - void restoreints P((void)); -#else -# define catchints() -# define ignoreints() -# define restoreints() -#endif -#if has_mmap && large_memory -# if has_NFS && mmap_signal - void catchmmapints P((void)); - void readAccessFilenameBuffer P((char const*,unsigned char const*)); -# else -# define catchmmapints() -# endif -#endif -#if has_getuid - uid_t ruid P((void)); -# define myself(u) ((u) == ruid()) -#else -# define myself(u) true -#endif -#if has_setuid - uid_t euid P((void)); - void nosetid P((void)); - void seteid P((void)); - void setrid P((void)); -#else -# define nosetid() -# define seteid() -# define setrid() -#endif - -/* version */ -extern char const RCS_version_string[]; Index: gnu/usr.bin/rcs/lib/rcsedit.c =================================================================== --- gnu/usr.bin/rcs/lib/rcsedit.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsedit.c (working copy) @@ -1,1958 +0,0 @@ -/* RCS stream editor */ - -/****************************************************************************** - * edits the input file according to a - * script from stdin, generated by diff -n - * performs keyword expansion - ****************************************************************************** - */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.19 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.18 1995/06/01 16:23:43 eggert - * (dirtpname): No longer external. - * (do_link): Simplify logic. - * (finisheditline, finishedit): Replace Iseek/Itell with what they stand for. - * (fopen_update_truncate): Replace `#if' with `if'. - * (keyreplace, makedirtemp): dirlen(x) -> basefilename(x)-x. - * - * (edit_string): Fix bug: if !large_memory, a bogus trailing `@' was output - * at the end of incomplete lines. - * - * (keyreplace): Do not assume that seeking backwards - * at the start of a file will fail; on some systems it succeeds. - * Convert C- and Pascal-style comment starts to ` *' in comment leader. - * - * (rcswriteopen): Use fdSafer to get safer file descriptor. - * Open RCS file with FOPEN_RB. - * - * (chnamemod): Work around bad_NFS_rename bug; don't ignore un_link result. - * Fall back on chmod if fchmod fails, since it might be ENOSYS. - * - * (aflush): Move to rcslex.c. - * - * Revision 5.17 1994/03/20 04:52:58 eggert - * Normally calculate the $Log prefix from context, not from RCS file. - * Move setmtime here from rcsutil.c. Add ORCSerror. Remove lint. - * - * Revision 5.16 1993/11/03 17:42:27 eggert - * Add -z. Add Name keyword. If bad_unlink, ignore errno when unlink fails. - * Escape white space, $, and \ in keyword string file names. - * Don't output 2 spaces between date and time after Log. - * - * Revision 5.15 1992/07/28 16:12:44 eggert - * Some hosts have readlink but not ELOOP. Avoid `unsigned'. - * Preserve dates more systematically. Statement macro names now end in _. - * - * Revision 5.14 1992/02/17 23:02:24 eggert - * Add -T support. - * - * Revision 5.13 1992/01/24 18:44:19 eggert - * Add support for bad_chmod_close, bad_creat0. - * - * Revision 5.12 1992/01/06 02:42:34 eggert - * Add setmode parameter to chnamemod. addsymbol now reports changes. - * while (E) ; -> while (E) continue; - * - * Revision 5.11 1991/11/03 01:11:44 eggert - * Move the warning about link breaking to where they're actually being broken. - * - * Revision 5.10 1991/10/07 17:32:46 eggert - * Support piece tables even if !has_mmap. Fix rare NFS bugs. - * - * Revision 5.9 1991/09/17 19:07:40 eggert - * SGI readlink() yields ENXIO, not EINVAL, for nonlinks. - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Add piece tables, NFS bug workarounds. Catch odd filenames. Tune. - * - * Revision 5.7 1991/04/21 11:58:21 eggert - * Fix errno bugs. Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.6 1991/02/25 07:12:40 eggert - * Fix setuid bug. Support new link behavior. Work around broken "w+" fopen. - * - * Revision 5.5 1990/12/30 05:07:35 eggert - * Fix report of busy RCS files when !defined(O_CREAT) | !defined(O_EXCL). - * - * Revision 5.4 1990/11/01 05:03:40 eggert - * Permit arbitrary data in comment leaders. - * - * Revision 5.3 1990/09/11 02:41:13 eggert - * Tune expandline(). - * - * Revision 5.2 1990/09/04 08:02:21 eggert - * Count RCS lines better. Improve incomplete line handling. - * - * Revision 5.1 1990/08/29 07:13:56 eggert - * Add -kkvl. - * Fix bug when getting revisions to files ending in incomplete lines. - * Fix bug in comment leader expansion. - * - * Revision 5.0 1990/08/22 08:12:47 eggert - * Don't require final newline. - * Don't append "checked in with -k by " to logs, - * so that checking in a program with -k doesn't change it. - * Don't generate trailing white space for empty comment leader. - * Remove compile-time limits; use malloc instead. Add -k, -V. - * Permit dates past 1999/12/31. Make lock and temp files faster and safer. - * Ansify and Posixate. Check diff's output. - * - * Revision 4.8 89/05/01 15:12:35 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.7 88/11/08 13:54:14 narten - * misplaced semicolon caused infinite loop - * - * Revision 4.6 88/08/09 19:12:45 eggert - * Shrink stdio code size; allow cc -R. - * - * Revision 4.5 87/12/18 11:38:46 narten - * Changes from the 43. version. Don't know the significance of the - * first change involving "rewind". Also, additional "lint" cleanup. - * (Guy Harris) - * - * Revision 4.4 87/10/18 10:32:21 narten - * Updating version numbers. Changes relative to version 1.1 actually - * relative to 4.1 - * - * Revision 1.4 87/09/24 13:59:29 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.3 87/09/15 16:39:39 shepler - * added an initializatin of the variables editline and linecorr - * this will be done each time a file is processed. - * (there was an obscure bug where if co was used to retrieve multiple files - * it would dump) - * fix attributed to Roy Morris @FileNet Corp ...!felix!roy - * - * Revision 1.2 87/03/27 14:22:17 jenkins - * Port to suns - * - * Revision 4.1 83/05/12 13:10:30 wft - * Added new markers Id and RCSfile; added locker to Header and Id. - * Overhauled expandline completely() (problem with $01234567890123456789@). - * Moved trymatch() and marker table to rcskeys.c. - * - * Revision 3.7 83/05/12 13:04:39 wft - * Added retry to expandline to resume after failed match which ended in $. - * Fixed truncation problem for $19chars followed by@@. - * Log no longer expands full path of RCS file. - * - * Revision 3.6 83/05/11 16:06:30 wft - * added retry to expandline to resume after failed match which ended in $. - * Fixed truncation problem for $19chars followed by@@. - * - * Revision 3.5 82/12/04 13:20:56 wft - * Added expansion of keyword Locker. - * - * Revision 3.4 82/12/03 12:26:54 wft - * Added line number correction in case editing does not start at the - * beginning of the file. - * Changed keyword expansion to always print a space before closing KDELIM; - * Expansion for Header shortened. - * - * Revision 3.3 82/11/14 14:49:30 wft - * removed Suffix from keyword expansion. Replaced fclose with ffclose. - * keyreplace() gets log message from delta, not from curlogmsg. - * fixed expression overflow in while(c=putc(GETC.... - * checked nil printing. - * - * Revision 3.2 82/10/18 21:13:39 wft - * I added checks for write errors during the co process, and renamed - * expandstring() to xpandstring(). - * - * Revision 3.1 82/10/13 15:52:55 wft - * changed type of result of getc() from char to int. - * made keyword expansion loop in expandline() portable to machines - * without sign-extension. - */ - - -#include "rcsbase.h" - -libId(editId, "$FreeBSD$") - -static void editEndsPrematurely P((void)) exiting; -static void editLineNumberOverflow P((void)) exiting; -static void escape_string P((FILE*,char const*)); -static void keyreplace P((enum markers,struct hshentry const*,int,RILE*,FILE*,int)); - -FILE *fcopy; /* result file descriptor */ -char const *resultname; /* result pathname */ -int locker_expansion; /* should the locker name be appended to Id val? */ -#if !large_memory - static RILE *fedit; /* edit file descriptor */ - static char const *editname; /* edit pathname */ -#endif -static long editline; /* edit line counter; #lines before cursor */ -static long linecorr; /* #adds - #deletes in each edit run. */ - /*used to correct editline in case file is not rewound after */ - /* applying one delta */ - -/* indexes into dirtpname */ -#define lockdirtp_index 0 -#define newRCSdirtp_index bad_creat0 -#define newworkdirtp_index (newRCSdirtp_index+1) -#define DIRTEMPNAMES (newworkdirtp_index + 1) - -enum maker {notmade, real, effective}; -static struct buf dirtpname[DIRTEMPNAMES]; /* unlink these when done */ -static enum maker volatile dirtpmaker[DIRTEMPNAMES]; /* if these are set */ -#define lockname (dirtpname[lockdirtp_index].string) -#define newRCSname (dirtpname[newRCSdirtp_index].string) - - -#if has_NFS || bad_unlink - int -un_link(s) - char const *s; -/* - * Remove S, even if it is unwritable. - * Ignore unlink() ENOENT failures; NFS generates bogus ones. - */ -{ -# if bad_unlink - if (unlink(s) == 0) - return 0; - else { - int e = errno; - /* - * Forge ahead even if errno == ENOENT; some completely - * brain-damaged hosts (e.g. PCTCP 2.2) yield ENOENT - * even for existing unwritable files. - */ - if (chmod(s, S_IWUSR) != 0) { - errno = e; - return -1; - } - } -# endif -# if has_NFS - return unlink(s)==0 || errno==ENOENT ? 0 : -1; -# else - return unlink(s); -# endif -} -#endif - -#if !has_rename -# if !has_NFS -# define do_link(s,t) link(s,t) -# else - static int do_link P((char const*,char const*)); - static int -do_link(s, t) - char const *s, *t; -/* Link S to T, ignoring bogus EEXIST problems due to NFS failures. */ -{ - int r = link(s, t); - - if (r != 0 && errno == EEXIST) { - struct stat sb, tb; - if ( - stat(s, &sb) == 0 && - stat(t, &tb) == 0 && - same_file(sb, tb, 0) - ) - r = 0; - errno = EEXIST; - } - return r; -} -# endif -#endif - - - static void -editEndsPrematurely() -{ - fatserror("edit script ends prematurely"); -} - - static void -editLineNumberOverflow() -{ - fatserror("edit script refers to line past end of file"); -} - - -#if large_memory - -#if has_memmove -# define movelines(s1, s2, n) VOID memmove(s1, s2, (n)*sizeof(Iptr_type)) -#else - static void movelines P((Iptr_type*,Iptr_type const*,long)); - static void -movelines(s1, s2, n) - register Iptr_type *s1; - register Iptr_type const *s2; - register long n; -{ - if (s1 < s2) - do { - *s1++ = *s2++; - } while (--n); - else { - s1 += n; - s2 += n; - do { - *--s1 = *--s2; - } while (--n); - } -} -#endif - -static void deletelines P((long,long)); -static void finisheditline P((RILE*,FILE*,Iptr_type,struct hshentry const*)); -static void insertline P((long,Iptr_type)); -static void snapshotline P((FILE*,Iptr_type)); - -/* - * `line' contains pointers to the lines in the currently `edited' file. - * It is a 0-origin array that represents linelim-gapsize lines. - * line[0 .. gap-1] and line[gap+gapsize .. linelim-1] hold pointers to lines. - * line[gap .. gap+gapsize-1] contains garbage. - * - * Any @s in lines are duplicated. - * Lines are terminated by \n, or (for a last partial line only) by single @. - */ -static Iptr_type *line; -static size_t gap, gapsize, linelim; - - static void -insertline(n, l) - long n; - Iptr_type l; -/* Before line N, insert line L. N is 0-origin. */ -{ - if (linelim-gapsize < n) - editLineNumberOverflow(); - if (!gapsize) - line = - !linelim ? - tnalloc(Iptr_type, linelim = gapsize = 1024) - : ( - gap = gapsize = linelim, - trealloc(Iptr_type, line, linelim <<= 1) - ); - if (n < gap) - movelines(line+n+gapsize, line+n, gap-n); - else if (gap < n) - movelines(line+gap, line+gap+gapsize, n-gap); - - line[n] = l; - gap = n + 1; - gapsize--; -} - - static void -deletelines(n, nlines) - long n, nlines; -/* Delete lines N through N+NLINES-1. N is 0-origin. */ -{ - long l = n + nlines; - if (linelim-gapsize < l || l < n) - editLineNumberOverflow(); - if (l < gap) - movelines(line+l+gapsize, line+l, gap-l); - else if (gap < n) - movelines(line+gap, line+gap+gapsize, n-gap); - - gap = n; - gapsize += nlines; -} - - static void -snapshotline(f, l) - register FILE *f; - register Iptr_type l; -{ - register int c; - do { - if ((c = *l++) == SDELIM && *l++ != SDELIM) - return; - aputc_(c, f) - } while (c != '\n'); -} - - void -snapshotedit(f) - FILE *f; -/* Copy the current state of the edits to F. */ -{ - register Iptr_type *p, *lim, *l=line; - for (p=l, lim=l+gap; pptr = l; - if (expandline(fin, fout, delta, true, (FILE*)0, true) < 0) - faterror("finisheditline internal error"); -} - - void -finishedit(delta, outfile, done) - struct hshentry const *delta; - FILE *outfile; - int done; -/* - * Doing expansion if DELTA is set, output the state of the edits to OUTFILE. - * But do nothing unless DONE is set (which means we are on the last pass). - */ -{ - if (done) { - openfcopy(outfile); - outfile = fcopy; - if (!delta) - snapshotedit(outfile); - else { - register Iptr_type *p, *lim, *l = line; - register RILE *fin = finptr; - Iptr_type here = fin->ptr; - for (p=l, lim=l+gap; pptr = here; - } - } -} - -/* Open a temporary NAME for output, truncating any previous contents. */ -# define fopen_update_truncate(name) fopenSafer(name, FOPEN_W_WORK) -#else /* !large_memory */ - static FILE * fopen_update_truncate P((char const*)); - static FILE * -fopen_update_truncate(name) - char const *name; -{ - if (bad_fopen_wplus && un_link(name) != 0) - efaterror(name); - return fopenSafer(name, FOPEN_WPLUS_WORK); -} -#endif - - - void -openfcopy(f) - FILE *f; -{ - if (!(fcopy = f)) { - if (!resultname) - resultname = maketemp(2); - if (!(fcopy = fopen_update_truncate(resultname))) - efaterror(resultname); - } -} - - -#if !large_memory - - static void swapeditfiles P((FILE*)); - static void -swapeditfiles(outfile) - FILE *outfile; -/* Function: swaps resultname and editname, assigns fedit=fcopy, - * and rewinds fedit for reading. Set fcopy to outfile if nonnull; - * otherwise, set fcopy to be resultname opened for reading and writing. - */ -{ - char const *tmpptr; - - editline = 0; linecorr = 0; - Orewind(fcopy); - fedit = fcopy; - tmpptr=editname; editname=resultname; resultname=tmpptr; - openfcopy(outfile); -} - - void -snapshotedit(f) - FILE *f; -/* Copy the current state of the edits to F. */ -{ - finishedit((struct hshentry *)0, (FILE*)0, false); - fastcopy(fedit, f); - Irewind(fedit); -} - - void -finishedit(delta, outfile, done) - struct hshentry const *delta; - FILE *outfile; - int done; -/* copy the rest of the edit file and close it (if it exists). - * if delta, perform keyword substitution at the same time. - * If DONE is set, we are finishing the last pass. - */ -{ - register RILE *fe; - register FILE *fc; - - fe = fedit; - if (fe) { - fc = fcopy; - if (delta) { - while (1 < expandline(fe,fc,delta,false,(FILE*)0,true)) - ; - } else { - fastcopy(fe,fc); - } - Ifclose(fe); - } - if (!done) - swapeditfiles(outfile); -} -#endif - - - -#if large_memory -# define copylines(upto,delta) (editline = (upto)) -#else - static void copylines P((long,struct hshentry const*)); - static void -copylines(upto, delta) - register long upto; - struct hshentry const *delta; -/* - * Copy input lines editline+1..upto from fedit to fcopy. - * If delta, keyword expansion is done simultaneously. - * editline is updated. Rewinds a file only if necessary. - */ -{ - register int c; - declarecache; - register FILE *fc; - register RILE *fe; - - if (upto < editline) { - /* swap files */ - finishedit((struct hshentry *)0, (FILE*)0, false); - /* assumes edit only during last pass, from the beginning*/ - } - fe = fedit; - fc = fcopy; - if (editline < upto) - if (delta) - do { - if (expandline(fe,fc,delta,false,(FILE*)0,true) <= 1) - editLineNumberOverflow(); - } while (++editline < upto); - else { - setupcache(fe); cache(fe); - do { - do { - cachegeteof_(c, editLineNumberOverflow();) - aputc_(c, fc) - } while (c != '\n'); - } while (++editline < upto); - uncache(fe); - } -} -#endif - - - - void -xpandstring(delta) - struct hshentry const *delta; -/* Function: Reads a string terminated by SDELIM from finptr and writes it - * to fcopy. Double SDELIM is replaced with single SDELIM. - * Keyword expansion is performed with data from delta. - * If foutptr is nonnull, the string is also copied unchanged to foutptr. - */ -{ - while (1 < expandline(finptr,fcopy,delta,true,foutptr,true)) - continue; -} - - - void -copystring() -/* Function: copies a string terminated with a single SDELIM from finptr to - * fcopy, replacing all double SDELIM with a single SDELIM. - * If foutptr is nonnull, the string also copied unchanged to foutptr. - * editline is incremented by the number of lines copied. - * Assumption: next character read is first string character. - */ -{ register c; - declarecache; - register FILE *frew, *fcop; - register int amidline; - register RILE *fin; - - fin = finptr; - setupcache(fin); cache(fin); - frew = foutptr; - fcop = fcopy; - amidline = false; - for (;;) { - GETC_(frew,c) - switch (c) { - case '\n': - ++editline; - ++rcsline; - amidline = false; - break; - case SDELIM: - GETC_(frew,c) - if (c != SDELIM) { - /* end of string */ - nextc = c; - editline += amidline; - uncache(fin); - return; - } - /* fall into */ - default: - amidline = true; - break; - } - aputc_(c,fcop) - } -} - - - void -enterstring() -/* Like copystring, except the string is put into the edit data structure. */ -{ -#if !large_memory - editname = 0; - fedit = 0; - editline = linecorr = 0; - resultname = maketemp(1); - if (!(fcopy = fopen_update_truncate(resultname))) - efaterror(resultname); - copystring(); -#else - register int c; - declarecache; - register FILE *frew; - register long e, oe; - register int amidline, oamidline; - register Iptr_type optr; - register RILE *fin; - - e = 0; - gap = 0; - gapsize = linelim; - fin = finptr; - setupcache(fin); cache(fin); - advise_access(fin, MADV_NORMAL); - frew = foutptr; - amidline = false; - for (;;) { - optr = cacheptr(); - GETC_(frew,c) - oamidline = amidline; - oe = e; - switch (c) { - case '\n': - ++e; - ++rcsline; - amidline = false; - break; - case SDELIM: - GETC_(frew,c) - if (c != SDELIM) { - /* end of string */ - nextc = c; - editline = e + amidline; - linecorr = 0; - uncache(fin); - return; - } - /* fall into */ - default: - amidline = true; - break; - } - if (!oamidline) - insertline(oe, optr); - } -#endif -} - - - - - void -#if large_memory -edit_string() -#else - editstring(delta) - struct hshentry const *delta; -#endif -/* - * Read an edit script from finptr and applies it to the edit file. -#if !large_memory - * The result is written to fcopy. - * If delta, keyword expansion is performed simultaneously. - * If running out of lines in fedit, fedit and fcopy are swapped. - * editname is the name of the file that goes with fedit. -#endif - * If foutptr is set, the edit script is also copied verbatim to foutptr. - * Assumes that all these files are open. - * resultname is the name of the file that goes with fcopy. - * Assumes the next input character from finptr is the first character of - * the edit script. Resets nextc on exit. - */ -{ - int ed; /* editor command */ - register int c; - declarecache; - register FILE *frew; -# if !large_memory - register FILE *f; - long line_lim = LONG_MAX; - register RILE *fe; -# endif - register long i; - register RILE *fin; -# if large_memory - register long j; -# endif - struct diffcmd dc; - - editline += linecorr; linecorr=0; /*correct line number*/ - frew = foutptr; - fin = finptr; - setupcache(fin); - initdiffcmd(&dc); - while (0 <= (ed = getdiffcmd(fin,true,frew,&dc))) -#if !large_memory - if (line_lim <= dc.line1) - editLineNumberOverflow(); - else -#endif - if (!ed) { - copylines(dc.line1-1, delta); - /* skip over unwanted lines */ - i = dc.nlines; - linecorr -= i; - editline += i; -# if large_memory - deletelines(editline+linecorr, i); -# else - fe = fedit; - do { - /*skip next line*/ - do { - Igeteof_(fe, c, { if (i!=1) editLineNumberOverflow(); line_lim = dc.dafter; break; } ) - } while (c != '\n'); - } while (--i); -# endif - } else { - /* Copy lines without deleting any. */ - copylines(dc.line1, delta); - i = dc.nlines; -# if large_memory - j = editline+linecorr; -# endif - linecorr += i; -#if !large_memory - f = fcopy; - if (delta) - do { - switch (expandline(fin,f,delta,true,frew,true)){ - case 0: case 1: - if (i==1) - return; - /* fall into */ - case -1: - editEndsPrematurely(); - } - } while (--i); - else -#endif - { - cache(fin); - do { -# if large_memory - insertline(j++, cacheptr()); -# endif - for (;;) { - GETC_(frew, c) - if (c==SDELIM) { - GETC_(frew, c) - if (c!=SDELIM) { - if (--i) - editEndsPrematurely(); - nextc = c; - uncache(fin); - return; - } - } -# if !large_memory - aputc_(c, f) -# endif - if (c == '\n') - break; - } - ++rcsline; - } while (--i); - uncache(fin); - } - } -} - - - -/* The rest is for keyword expansion */ - - - - int -expandline(infile, outfile, delta, delimstuffed, frewfile, dolog) - RILE *infile; - FILE *outfile, *frewfile; - struct hshentry const *delta; - int delimstuffed, dolog; -/* - * Read a line from INFILE and write it to OUTFILE. - * Do keyword expansion with data from DELTA. - * If DELIMSTUFFED is true, double SDELIM is replaced with single SDELIM. - * If FREWFILE is set, copy the line unchanged to FREWFILE. - * DELIMSTUFFED must be true if FREWFILE is set. - * Append revision history to log only if DOLOG is set. - * Yields -1 if no data is copied, 0 if an incomplete line is copied, - * 2 if a complete line is copied; adds 1 to yield if expansion occurred. - */ -{ - register c; - declarecache; - register FILE *out, *frew; - register char * tp; - register int e, ds, r; - char const *tlim; - static struct buf keyval; - enum markers matchresult; - - setupcache(infile); cache(infile); - out = outfile; - frew = frewfile; - ds = delimstuffed; - bufalloc(&keyval, keylength+3); - e = 0; - r = -1; - - for (;;) { - if (ds) - GETC_(frew, c) - else - cachegeteof_(c, goto uncache_exit;) - for (;;) { - switch (c) { - case SDELIM: - if (ds) { - GETC_(frew, c) - if (c != SDELIM) { - /* end of string */ - nextc=c; - goto uncache_exit; - } - } - /* fall into */ - default: - aputc_(c,out) - r = 0; - break; - - case '\n': - rcsline += ds; - aputc_(c,out) - r = 2; - goto uncache_exit; - - case KDELIM: - r = 0; - /* check for keyword */ - /* first, copy a long enough string into keystring */ - tp = keyval.string; - *tp++ = KDELIM; - for (;;) { - if (ds) - GETC_(frew, c) - else - cachegeteof_(c, goto keystring_eof;) - if (tp <= &keyval.string[keylength]) - switch (ctab[c]) { - case LETTER: case Letter: - *tp++ = c; - continue; - default: - break; - } - break; - } - *tp++ = c; *tp = '\0'; - matchresult = trymatch(keyval.string+1); - if (matchresult==Nomatch) { - tp[-1] = 0; - aputs(keyval.string, out); - continue; /* last c handled properly */ - } - - /* Now we have a keyword terminated with a K/VDELIM */ - if (c==VDELIM) { - /* try to find closing KDELIM, and replace value */ - tlim = keyval.string + keyval.size; - for (;;) { - if (ds) - GETC_(frew, c) - else - cachegeteof_(c, goto keystring_eof;) - if (c=='\n' || c==KDELIM) - break; - *tp++ =c; - if (tlim <= tp) - tp = bufenlarge(&keyval, &tlim); - if (c==SDELIM && ds) { /*skip next SDELIM */ - GETC_(frew, c) - if (c != SDELIM) { - /* end of string before closing KDELIM or newline */ - nextc = c; - goto keystring_eof; - } - } - } - if (c!=KDELIM) { - /* couldn't find closing KDELIM -- give up */ - *tp = 0; - aputs(keyval.string, out); - continue; /* last c handled properly */ - } - } - /* now put out the new keyword value */ - uncache(infile); - keyreplace(matchresult, delta, ds, infile, out, dolog); - cache(infile); - e = 1; - break; - } - break; - } - } - - keystring_eof: - *tp = 0; - aputs(keyval.string, out); - uncache_exit: - uncache(infile); - return r + e; -} - - - static void -escape_string(out, s) - register FILE *out; - register char const *s; -/* Output to OUT the string S, escaping chars that would break `ci -k'. */ -{ - register char c; - for (;;) - switch ((c = *s++)) { - case 0: return; - case '\t': aputs("\\t", out); break; - case '\n': aputs("\\n", out); break; - case ' ': aputs("\\040", out); break; - case KDELIM: aputs("\\044", out); break; - case '\\': if (VERSION(5)<=RCSversion) {aputs("\\\\", out); break;} - /* fall into */ - default: aputc_(c, out) break; - } -} - -char const ciklog[ciklogsize] = "checked in with -k by "; - - static void -keyreplace(marker, delta, delimstuffed, infile, out, dolog) - enum markers marker; - register struct hshentry const *delta; - int delimstuffed; - RILE *infile; - register FILE *out; - int dolog; -/* function: outputs the keyword value(s) corresponding to marker. - * Attributes are derived from delta. - */ -{ - register char const *sp, *cp, *date; - register int c; - register size_t cs, cw, ls; - char const *sp1; - char datebuf[datesize + zonelenmax]; - int RCSv; - int exp; - - sp = Keyword[(int)marker]; - exp = Expand; - date = delta->date; - RCSv = RCSversion; - - if (exp != VAL_EXPAND) - aprintf(out, "%c%s", KDELIM, sp); - if (exp != KEY_EXPAND) { - - if (exp != VAL_EXPAND) - aprintf(out, "%c%c", VDELIM, - marker==Log && RCSvauthor, out); - break; - case Date: - aputs(date2str(date,datebuf), out); - break; - case Id: - case LocalId: - case Header: - case CVSHeader: - if (marker == Id || RCSv < VERSION(4) || - (marker == LocalId && LocalIdMode == Id)) - escape_string(out, basefilename(RCSname)); - else if (marker == CVSHeader || - (marker == LocalId && LocalIdMode == CVSHeader)) - escape_string(out, getfullCVSname()); - else - escape_string(out, getfullRCSname()); - aprintf(out, " %s %s %s %s", - delta->num, - date2str(date, datebuf), - delta->author, - RCSv==VERSION(3) && delta->lockedby ? "Locked" - : delta->state - ); - if (delta->lockedby) - if (VERSION(5) <= RCSv) { - if (locker_expansion || exp==KEYVALLOCK_EXPAND) - aprintf(out, " %s", delta->lockedby); - } else if (RCSv == VERSION(4)) - aprintf(out, " Locker: %s", delta->lockedby); - break; - case Locker: - if (delta->lockedby) - if ( - locker_expansion - || exp == KEYVALLOCK_EXPAND - || RCSv <= VERSION(4) - ) - aputs(delta->lockedby, out); - break; - case Log: - case RCSfile: - escape_string(out, basefilename(RCSname)); - break; - case Name: - if (delta->name) - aputs(delta->name, out); - break; - case Revision: - aputs(delta->num, out); - break; - case Source: - escape_string(out, getfullRCSname()); - break; - case State: - aputs(delta->state, out); - break; - default: - break; - } - if (exp != VAL_EXPAND) - afputc(' ', out); - } - if (exp != VAL_EXPAND) - afputc(KDELIM, out); - - if (marker == Log && dolog) { - struct buf leader; - - sp = delta->log.string; - ls = delta->log.size; - if (sizeof(ciklog)-1<=ls && !memcmp(sp,ciklog,sizeof(ciklog)-1)) - return; - bufautobegin(&leader); - if (RCSversion < VERSION(5)) { - cp = Comment.string; - cs = Comment.size; - } else { - int kdelim_found = 0; - Ioffset_type chars_read = Itell(infile); - declarecache; - setupcache(infile); cache(infile); - - c = 0; /* Pacify `gcc -Wall'. */ - - /* - * Back up to the start of the current input line, - * setting CS to the number of characters before `$Log'. - */ - cs = 0; - for (;;) { - if (!--chars_read) - goto done_backing_up; - cacheunget_(infile, c) - if (c == '\n') - break; - if (c == SDELIM && delimstuffed) { - if (!--chars_read) - break; - cacheunget_(infile, c) - if (c != SDELIM) { - cacheget_(c) - break; - } - } - cs += kdelim_found; - kdelim_found |= c==KDELIM; - } - cacheget_(c) - done_backing_up:; - - /* Copy characters before `$Log' into LEADER. */ - bufalloc(&leader, cs); - cp = leader.string; - for (cw = 0; cw < cs; cw++) { - leader.string[cw] = c; - if (c == SDELIM && delimstuffed) - cacheget_(c) - cacheget_(c) - } - - /* Convert traditional C or Pascal leader to ` *'. */ - for (cw = 0; cw < cs; cw++) - if (ctab[(unsigned char) cp[cw]] != SPACE) - break; - if ( - cw+1 < cs - && cp[cw+1] == '*' - && (cp[cw] == '/' || cp[cw] == '(') - ) { - size_t i = cw+1; - for (;;) - if (++i == cs) { - warn( - "`%c* $Log' is obsolescent; use ` * $Log'.", - cp[cw] - ); - leader.string[cw] = ' '; - break; - } else if (ctab[(unsigned char) cp[i]] != SPACE) - break; - } - - /* Skip `$Log ... $' string. */ - do { - cacheget_(c) - } while (c != KDELIM); - uncache(infile); - } - afputc('\n', out); - awrite(cp, cs, out); - sp1 = date2str(date, datebuf); - if (VERSION(5) <= RCSv) { - aprintf(out, "Revision %s %s %s", - delta->num, sp1, delta->author - ); - } else { - /* oddity: 2 spaces between date and time, not 1 as usual */ - sp1 = strchr(sp1, ' '); - aprintf(out, "Revision %s %.*s %s %s", - delta->num, (int)(sp1-datebuf), datebuf, sp1, - delta->author - ); - } - /* Do not include state: it may change and is not updated. */ - cw = cs; - if (VERSION(5) <= RCSv) - for (; cw && (cp[cw-1]==' ' || cp[cw-1]=='\t'); --cw) - continue; - for (;;) { - afputc('\n', out); - awrite(cp, cw, out); - if (!ls) - break; - --ls; - c = *sp++; - if (c != '\n') { - awrite(cp+cw, cs-cw, out); - do { - afputc(c,out); - if (!ls) - break; - --ls; - c = *sp++; - } while (c != '\n'); - } - } - bufautoend(&leader); - } -} - -#if has_readlink - static int resolve_symlink P((struct buf*)); - static int -resolve_symlink(L) - struct buf *L; -/* - * If L is a symbolic link, resolve it to the name that it points to. - * If unsuccessful, set errno and yield -1. - * If it points to an existing file, yield 1. - * Otherwise, set errno=ENOENT and yield 0. - */ -{ - char *b, a[SIZEABLE_PATH]; - int e; - size_t s; - ssize_t r; - struct buf bigbuf; - int linkcount = MAXSYMLINKS; - - b = a; - s = sizeof(a); - bufautobegin(&bigbuf); - while ((r = readlink(L->string,b,s)) != -1) - if (r == s) { - bufalloc(&bigbuf, s<<1); - b = bigbuf.string; - s = bigbuf.size; - } else if (!linkcount--) { -# ifndef ELOOP - /* - * Some pedantic Posix 1003.1-1990 hosts have readlink - * but not ELOOP. Approximate ELOOP with EMLINK. - */ -# define ELOOP EMLINK -# endif - errno = ELOOP; - return -1; - } else { - /* Splice symbolic link into L. */ - b[r] = '\0'; - L->string[ - ROOTPATH(b) ? 0 : basefilename(L->string) - L->string - ] = '\0'; - bufscat(L, b); - } - e = errno; - bufautoend(&bigbuf); - errno = e; - switch (e) { - case readlink_isreg_errno: return 1; - case ENOENT: return 0; - default: return -1; - } -} -#endif - - RILE * -rcswriteopen(RCSbuf, status, mustread) - struct buf *RCSbuf; - struct stat *status; - int mustread; -/* - * Create the lock file corresponding to RCSBUF. - * Then try to open RCSBUF for reading and yield its RILE* descriptor. - * Put its status into *STATUS too. - * MUSTREAD is true if the file must already exist, too. - * If all goes well, discard any previously acquired locks, - * and set fdlock to the file descriptor of the RCS lockfile. - */ -{ - register char *tp; - register char const *sp, *RCSpath, *x; - RILE *f; - size_t l; - int e, exists, fdesc, fdescSafer, r, waslocked; - struct buf *dirt; - struct stat statbuf; - - waslocked = 0 <= fdlock; - exists = -# if has_readlink - resolve_symlink(RCSbuf); -# else - stat(RCSbuf->string, &statbuf) == 0 ? 1 - : errno==ENOENT ? 0 : -1; -# endif - if (exists < (mustread|waslocked)) - /* - * There's an unusual problem with the RCS file; - * or the RCS file doesn't exist, - * and we must read or we already have a lock elsewhere. - */ - return 0; - - RCSpath = RCSbuf->string; - sp = basefilename(RCSpath); - l = sp - RCSpath; - dirt = &dirtpname[waslocked]; - bufscpy(dirt, RCSpath); - tp = dirt->string + l; - x = rcssuffix(RCSpath); -# if has_readlink - if (!x) { - error("symbolic link to non RCS file `%s'", RCSpath); - errno = EINVAL; - return 0; - } -# endif - if (*sp == *x) { - error("RCS pathname `%s' incompatible with suffix `%s'", sp, x); - errno = EINVAL; - return 0; - } - /* Create a lock filename that is a function of the RCS filename. */ - if (*x) { - /* - * The suffix is nonempty. - * The lock filename is the first char of of the suffix, - * followed by the RCS filename with last char removed. E.g.: - * foo,v RCS filename with suffix ,v - * ,foo, lock filename - */ - *tp++ = *x; - while (*sp) - *tp++ = *sp++; - *--tp = 0; - } else { - /* - * The suffix is empty. - * The lock filename is the RCS filename - * with last char replaced by '_'. - */ - while ((*tp++ = *sp++)) - continue; - tp -= 2; - if (*tp == '_') { - error("RCS pathname `%s' ends with `%c'", RCSpath, *tp); - errno = EINVAL; - return 0; - } - *tp = '_'; - } - - sp = dirt->string; - - f = 0; - - /* - * good news: - * open(f, O_CREAT|O_EXCL|O_TRUNC|..., OPEN_CREAT_READONLY) - * is atomic according to Posix 1003.1-1990. - * bad news: - * NFS ignores O_EXCL and doesn't comply with Posix 1003.1-1990. - * good news: - * (O_TRUNC,OPEN_CREAT_READONLY) normally guarantees atomicity - * even with NFS. - * bad news: - * If you're root, (O_TRUNC,OPEN_CREAT_READONLY) doesn't - * guarantee atomicity. - * good news: - * Root-over-the-wire NFS access is rare for security reasons. - * This bug has never been reported in practice with RCS. - * So we don't worry about this bug. - * - * An even rarer NFS bug can occur when clients retry requests. - * This can happen in the usual case of NFS over UDP. - * Suppose client A releases a lock by renaming ",f," to "f,v" at - * about the same time that client B obtains a lock by creating ",f,", - * and suppose A's first rename request is delayed, so A reissues it. - * The sequence of events might be: - * A sends rename(",f,", "f,v") - * B sends create(",f,") - * A sends retry of rename(",f,", "f,v") - * server receives, does, and acknowledges A's first rename() - * A receives acknowledgment, and its RCS program exits - * server receives, does, and acknowledges B's create() - * server receives, does, and acknowledges A's retry of rename() - * This not only wrongly deletes B's lock, it removes the RCS file! - * Most NFS implementations have idempotency caches that usually prevent - * this scenario, but such caches are finite and can be overrun. - * This problem afflicts not only RCS, which uses open() and rename() - * to get and release locks; it also afflicts the traditional - * Unix method of using link() and unlink() to get and release locks, - * and the less traditional method of using mkdir() and rmdir(). - * There is no easy workaround. - * Any new method based on lockf() seemingly would be incompatible with - * the old methods; besides, lockf() is notoriously buggy under NFS. - * Since this problem afflicts scads of Unix programs, but is so rare - * that nobody seems to be worried about it, we won't worry either. - */ -# if !open_can_creat -# define create(f) creat(f, OPEN_CREAT_READONLY) -# else -# define create(f) open(f, OPEN_O_BINARY|OPEN_O_LOCK|OPEN_O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, OPEN_CREAT_READONLY) -# endif - - catchints(); - ignoreints(); - - /* - * Create a lock file for an RCS file. This should be atomic, i.e. - * if two processes try it simultaneously, at most one should succeed. - */ - seteid(); - fdesc = create(sp); - fdescSafer = fdSafer(fdesc); /* Do it now; setrid might use stderr. */ - e = errno; - setrid(); - - if (0 <= fdesc) - dirtpmaker[0] = effective; - - if (fdescSafer < 0) { - if (e == EACCES && stat(sp,&statbuf) == 0) - /* The RCS file is busy. */ - e = EEXIST; - } else { - e = ENOENT; - if (exists) { - f = Iopen(RCSpath, FOPEN_RB, status); - e = errno; - if (f && waslocked) { - /* Discard the previous lock in favor of this one. */ - ORCSclose(); - seteid(); - r = un_link(lockname); - e = errno; - setrid(); - if (r != 0) - enfaterror(e, lockname); - bufscpy(&dirtpname[lockdirtp_index], sp); - } - } - fdlock = fdescSafer; - } - - restoreints(); - - errno = e; - return f; -} - - void -keepdirtemp(name) - char const *name; -/* Do not unlink name, either because it's not there any more, - * or because it has already been unlinked. - */ -{ - register int i; - for (i=DIRTEMPNAMES; 0<=--i; ) - if (dirtpname[i].string == name) { - dirtpmaker[i] = notmade; - return; - } - faterror("keepdirtemp"); -} - - char const * -makedirtemp(isworkfile) - int isworkfile; -/* - * Create a unique pathname and store it into dirtpname. - * Because of storage in tpnames, dirtempunlink() can unlink the file later. - * Return a pointer to the pathname created. - * If ISWORKFILE is 1, put it into the working file's directory; - * if 0, put the unique file in RCSfile's directory. - */ -{ - register char *tp, *np; - register size_t dl; - register struct buf *bn; - register char const *name = isworkfile ? workname : RCSname; -# if has_mktemp - int fd; -# endif - - dl = basefilename(name) - name; - bn = &dirtpname[newRCSdirtp_index + isworkfile]; - bufalloc(bn, -# if has_mktemp - dl + 9 -# else - strlen(name) + 3 -# endif - ); - bufscpy(bn, name); - np = tp = bn->string; - tp += dl; - *tp++ = '_'; - *tp++ = '0'+isworkfile; - catchints(); -# if has_mktemp - VOID strcpy(tp, "XXXXXX"); - fd = mkstemp(np); - if (fd < 0 || !*np) - faterror("can't make temporary pathname `%.*s_%cXXXXXX'", - (int)dl, name, '0'+isworkfile - ); - close(fd); -# else - /* - * Posix 1003.1-1990 has no reliable way - * to create a unique file in a named directory. - * We fudge here. If the filename is abcde, - * the temp filename is _Ncde where N is a digit. - */ - name += dl; - if (*name) name++; - if (*name) name++; - VOID strcpy(tp, name); -# endif - dirtpmaker[newRCSdirtp_index + isworkfile] = real; - return np; -} - - void -dirtempunlink() -/* Clean up makedirtemp() files. May be invoked by signal handler. */ -{ - register int i; - enum maker m; - - for (i = DIRTEMPNAMES; 0 <= --i; ) - if ((m = dirtpmaker[i]) != notmade) { - if (m == effective) - seteid(); - VOID un_link(dirtpname[i].string); - if (m == effective) - setrid(); - dirtpmaker[i] = notmade; - } -} - - - int -#if has_prototypes -chnamemod( - FILE **fromp, char const *from, char const *to, - int set_mode, mode_t mode, time_t mtime -) - /* The `#if has_prototypes' is needed because mode_t might promote to int. */ -#else - chnamemod(fromp, from, to, set_mode, mode, mtime) - FILE **fromp; char const *from,*to; - int set_mode; mode_t mode; time_t mtime; -#endif -/* - * Rename a file (with stream pointer *FROMP) from FROM to TO. - * FROM already exists. - * If 0 < SET_MODE, change the mode to MODE, before renaming if possible. - * If MTIME is not -1, change its mtime to MTIME before renaming. - * Close and clear *FROMP before renaming it. - * Unlink TO if it already exists. - * Return -1 on error (setting errno), 0 otherwise. - */ -{ - mode_t mode_while_renaming = mode; - int fchmod_set_mode = 0; - -# if bad_a_rename || bad_NFS_rename - struct stat st; - if (bad_NFS_rename || (bad_a_rename && set_mode <= 0)) { - if (fstat(fileno(*fromp), &st) != 0) - return -1; - if (bad_a_rename && set_mode <= 0) - mode = st.st_mode; - } -# endif - -# if bad_a_rename - /* - * There's a short window of inconsistency - * during which the lock file is writable. - */ - mode_while_renaming = mode|S_IWUSR; - if (mode != mode_while_renaming) - set_mode = 1; -# endif - -# if has_fchmod - if (0nextlock) - if (strcmp(getcaller(), next->login) == 0) { - if (found) { - rcserror("multiple revisions locked by %s; please specify one", getcaller()); - return 2; - } - found = trail; - } - if (!found) - return 0; - next = *found; - *target = next->delta; - if (delete) { - next->delta->lockedby = 0; - *found = next->nextlock; - } - return 1; -} - - int -addlock(delta, verbose) - struct hshentry * delta; - int verbose; -/* - * Add a lock held by caller to DELTA and yield 1 if successful. - * Print an error message if verbose and yield -1 if no lock is added because - * DELTA is locked by somebody other than caller. - * Return 0 if the caller already holds the lock. - */ -{ - register struct rcslock *next; - - for (next = Locks; next; next = next->nextlock) - if (cmpnum(delta->num, next->delta->num) == 0) - if (strcmp(getcaller(), next->login) == 0) - return 0; - else { - if (verbose) - rcserror("Revision %s is already locked by %s.", - delta->num, next->login - ); - return -1; - } - next = ftalloc(struct rcslock); - delta->lockedby = next->login = getcaller(); - next->delta = delta; - next->nextlock = Locks; - Locks = next; - return 1; -} - - - int -addsymbol(num, name, rebind) - char const *num, *name; - int rebind; -/* - * Associate with revision NUM the new symbolic NAME. - * If NAME already exists and REBIND is set, associate NAME with NUM; - * otherwise, print an error message and return false; - * Return -1 if unsuccessful, 0 if no change, 1 if change. - */ -{ - register struct assoc *next; - - for (next = Symbols; next; next = next->nextassoc) - if (strcmp(name, next->symbol) == 0) - if (strcmp(next->num,num) == 0) - return 0; - else if (rebind) { - next->num = num; - return 1; - } else { - rcserror("symbolic name %s already bound to %s", - name, next->num - ); - return -1; - } - next = ftalloc(struct assoc); - next->symbol = name; - next->num = num; - next->nextassoc = Symbols; - Symbols = next; - return 1; -} - - - - char const * -getcaller() -/* Get the caller's login name. */ -{ -# if has_setuid - return getusername(euid()!=ruid()); -# else - return getusername(false); -# endif -} - - - int -checkaccesslist() -/* - * Return true if caller is the superuser, the owner of the - * file, the access list is empty, or caller is on the access list. - * Otherwise, print an error message and return false. - */ -{ - register struct access const *next; - - if (!AccessList || myself(RCSstat.st_uid) || strcmp(getcaller(),"root")==0) - return true; - - next = AccessList; - do { - if (strcmp(getcaller(), next->login) == 0) - return true; - } while ((next = next->nextaccess)); - - rcserror("user %s not on the access list", getcaller()); - return false; -} - - - int -dorewrite(lockflag, changed) - int lockflag, changed; -/* - * Do nothing if LOCKFLAG is zero. - * Prepare to rewrite an RCS file if CHANGED is positive. - * Stop rewriting if CHANGED is zero, because there won't be any changes. - * Fail if CHANGED is negative. - * Return 0 on success, -1 on failure. - */ -{ - int r = 0, e; - - if (lockflag) - if (changed) { - if (changed < 0) - return -1; - putadmin(); - puttree(Head, frewrite); - aprintf(frewrite, "\n\n%s%c", Kdesc, nextc); - foutptr = frewrite; - } else { -# if bad_creat0 - int nr = !!frewrite, ne = 0; -# endif - ORCSclose(); - seteid(); - ignoreints(); -# if bad_creat0 - if (nr) { - nr = un_link(newRCSname); - ne = errno; - keepdirtemp(newRCSname); - } -# endif - r = un_link(lockname); - e = errno; - keepdirtemp(lockname); - restoreints(); - setrid(); - if (r != 0) - enerror(e, lockname); -# if bad_creat0 - if (nr != 0) { - enerror(ne, newRCSname); - r = -1; - } -# endif - } - return r; -} - - int -donerewrite(changed, newRCStime) - int changed; - time_t newRCStime; -/* - * Finish rewriting an RCS file if CHANGED is nonzero. - * Set its mode if CHANGED is positive. - * Set its modification time to NEWRCSTIME unless it is -1. - * Return 0 on success, -1 on failure. - */ -{ - int r = 0, e = 0; -# if bad_creat0 - int lr, le; -# endif - - if (changed && !nerror) { - if (finptr) { - fastcopy(finptr, frewrite); - Izclose(&finptr); - } - if (1 < RCSstat.st_nlink) - rcswarn("breaking hard link"); - aflush(frewrite); - seteid(); - ignoreints(); - r = chnamemod( - &frewrite, newRCSname, RCSname, changed, - RCSstat.st_mode & (mode_t)~(S_IWUSR|S_IWGRP|S_IWOTH), - newRCStime - ); - e = errno; - keepdirtemp(newRCSname); -# if bad_creat0 - lr = un_link(lockname); - le = errno; - keepdirtemp(lockname); -# endif - restoreints(); - setrid(); - if (r != 0) { - enerror(e, RCSname); - error("saved in %s", newRCSname); - } -# if bad_creat0 - if (lr != 0) { - enerror(le, lockname); - r = -1; - } -# endif - } - return r; -} - - void -ORCSclose() -{ - if (0 <= fdlock) { - if (close(fdlock) != 0) - efaterror(lockname); - fdlock = -1; - } - Ozclose(&frewrite); -} - - void -ORCSerror() -/* -* Like ORCSclose, except we are cleaning up after an interrupt or fatal error. -* Do not report errors, since this may loop. This is needed only because -* some brain-damaged hosts (e.g. OS/2) cannot unlink files that are open, and -* some nearly-Posix hosts (e.g. NFS) work better if the files are closed first. -* This isn't a completely reliable away to work around brain-damaged hosts, -* because of the gap between actual file opening and setting frewrite etc., -* but it's better than nothing. -*/ -{ - if (0 <= fdlock) - VOID close(fdlock); - if (frewrite) - /* Avoid fclose, since stdio may not be reentrant. */ - VOID close(fileno(frewrite)); -} Index: gnu/usr.bin/rcs/lib/rcsfcmp.c =================================================================== --- gnu/usr.bin/rcs/lib/rcsfcmp.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsfcmp.c (working copy) @@ -1,354 +0,0 @@ -/* Compare working files, ignoring RCS keyword strings. */ - -/***************************************************************************** - * rcsfcmp() - * Testprogram: define FCMPTEST - ***************************************************************************** - */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - - - - - -/* - * Revision 5.14 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.13 1995/06/01 16:23:43 eggert - * (rcsfcmp): Add -kb support. - * - * Revision 5.12 1994/03/17 14:05:48 eggert - * Normally calculate the $Log prefix from context, not from RCS file. - * Calculate line numbers correctly even if the $Log prefix contains newlines. - * Remove lint. - * - * Revision 5.11 1993/11/03 17:42:27 eggert - * Fix yet another off-by-one error when comparing Log string expansions. - * - * Revision 5.10 1992/07/28 16:12:44 eggert - * Statement macro names now end in _. - * - * Revision 5.9 1991/10/07 17:32:46 eggert - * Count log lines correctly. - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Tune. - * - * Revision 5.7 1991/04/21 11:58:22 eggert - * Fix errno bug. Add MS-DOS support. - * - * Revision 5.6 1991/02/28 19:18:47 eggert - * Open work file at most once. - * - * Revision 5.5 1990/11/27 09:26:05 eggert - * Fix comment leader bug. - * - * Revision 5.4 1990/11/01 05:03:42 eggert - * Permit arbitrary data in logs and comment leaders. - * - * Revision 5.3 1990/09/11 02:41:15 eggert - * Don't ignore differences inside keyword strings if -ko is set. - * - * Revision 5.1 1990/08/29 07:13:58 eggert - * Clean old log messages too. - * - * Revision 5.0 1990/08/22 08:12:49 eggert - * Don't append "checked in with -k by " log to logs, - * so that checking in a program with -k doesn't change it. - * Ansify and Posixate. Remove lint. - * - * Revision 4.5 89/05/01 15:12:42 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.4 88/08/09 19:12:50 eggert - * Shrink stdio code size. - * - * Revision 4.3 87/12/18 11:40:02 narten - * lint cleanups (Guy Harris) - * - * Revision 4.2 87/10/18 10:33:06 narten - * updting version number. Changes relative to 1.1 actually relative to - * 4.1 - * - * Revision 1.2 87/03/27 14:22:19 jenkins - * Port to suns - * - * Revision 4.1 83/05/10 16:24:04 wft - * Marker matching now uses trymatch(). Marker pattern is now - * checked precisely. - * - * Revision 3.1 82/12/04 13:21:40 wft - * Initial revision. - * - */ - -/* -#define FCMPTEST -*/ -/* Testprogram; prints out whether two files are identical, - * except for keywords - */ - -#include "rcsbase.h" - -libId(fcmpId, "$FreeBSD$") - - static int discardkeyval P((int,RILE*)); - static int -discardkeyval(c, f) - register int c; - register RILE *f; -{ - for (;;) - switch (c) { - case KDELIM: - case '\n': - return c; - default: - Igeteof_(f, c, return EOF;) - break; - } -} - - int -rcsfcmp(xfp, xstatp, uname, delta) - register RILE *xfp; - struct stat const *xstatp; - char const *uname; - struct hshentry const *delta; -/* Compare the files xfp and uname. Return zero - * if xfp has the same contents as uname and neither has keywords, - * otherwise -1 if they are the same ignoring keyword values, - * and 1 if they differ even ignoring - * keyword values. For the LOG-keyword, rcsfcmp skips the log message - * given by the parameter delta in xfp. Thus, rcsfcmp returns nonpositive - * if xfp contains the same as uname, with the keywords expanded. - * Implementation: character-by-character comparison until $ is found. - * If a $ is found, read in the marker keywords; if they are real keywords - * and identical, read in keyword value. If value is terminated properly, - * disregard it and optionally skip log message; otherwise, compare value. - */ -{ - register int xc, uc; - char xkeyword[keylength+2]; - int eqkeyvals; - register RILE *ufp; - register int xeof, ueof; - register char * tp; - register char const *sp; - register size_t leaderlen; - int result; - enum markers match1; - struct stat ustat; - - if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) { - efaterror(uname); - } - xeof = ueof = false; - if (MIN_UNEXPAND <= Expand) { - if (!(result = xstatp->st_size!=ustat.st_size)) { -# if large_memory && maps_memory - result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size); -# else - for (;;) { - /* get the next characters */ - Igeteof_(xfp, xc, xeof=true;) - Igeteof_(ufp, uc, ueof=true;) - if (xeof | ueof) - goto eof; - if (xc != uc) - goto return1; - } -# endif - } - } else { - xc = 0; - uc = 0; /* Keep lint happy. */ - leaderlen = 0; - result = 0; - - for (;;) { - if (xc != KDELIM) { - /* get the next characters */ - Igeteof_(xfp, xc, xeof=true;) - Igeteof_(ufp, uc, ueof=true;) - if (xeof | ueof) - goto eof; - } else { - /* try to get both keywords */ - tp = xkeyword; - for (;;) { - Igeteof_(xfp, xc, xeof=true;) - Igeteof_(ufp, uc, ueof=true;) - if (xeof | ueof) - goto eof; - if (xc != uc) - break; - switch (xc) { - default: - if (xkeyword+keylength <= tp) - break; - *tp++ = xc; - continue; - case '\n': case KDELIM: case VDELIM: - break; - } - break; - } - if ( - (xc==KDELIM || xc==VDELIM) && (uc==KDELIM || uc==VDELIM) && - (*tp = xc, (match1 = trymatch(xkeyword)) != Nomatch) - ) { -#ifdef FCMPTEST - VOID printf("found common keyword %s\n",xkeyword); -#endif - result = -1; - for (;;) { - if (xc != uc) { - xc = discardkeyval(xc, xfp); - uc = discardkeyval(uc, ufp); - if ((xeof = xc==EOF) | (ueof = uc==EOF)) - goto eof; - eqkeyvals = false; - break; - } - switch (xc) { - default: - Igeteof_(xfp, xc, xeof=true;) - Igeteof_(ufp, uc, ueof=true;) - if (xeof | ueof) - goto eof; - continue; - - case '\n': case KDELIM: - eqkeyvals = true; - break; - } - break; - } - if (xc != uc) - goto return1; - if (xc==KDELIM) { - /* Skip closing KDELIM. */ - Igeteof_(xfp, xc, xeof=true;) - Igeteof_(ufp, uc, ueof=true;) - if (xeof | ueof) - goto eof; - /* if the keyword is LOG, also skip the log message in xfp*/ - if (match1==Log) { - /* first, compute the number of line feeds in log msg */ - int lncnt; - size_t ls, ccnt; - sp = delta->log.string; - ls = delta->log.size; - if (ls31 chars) name. - * while (E) ; -> while (E) continue; - * - * Revision 5.8 1991/09/24 00:28:40 eggert - * Don't export bindex(). - * - * Revision 5.7 1991/08/19 03:13:55 eggert - * Fix messages when rcswriteopen fails. - * Look in $TMP and $TEMP if $TMPDIR isn't set. Tune. - * - * Revision 5.6 1991/04/21 11:58:23 eggert - * Fix errno bugs. Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.5 1991/02/26 17:48:38 eggert - * Fix setuid bug. Support new link behavior. - * Define more portable getcwd(). - * - * Revision 5.4 1990/11/01 05:03:43 eggert - * Permit arbitrary data in comment leaders. - * - * Revision 5.3 1990/09/14 22:56:16 hammer - * added more filename extensions and their comment leaders - * - * Revision 5.2 1990/09/04 08:02:23 eggert - * Fix typo when !RCSSEP. - * - * Revision 5.1 1990/08/29 07:13:59 eggert - * Work around buggy compilers with defective argument promotion. - * - * Revision 5.0 1990/08/22 08:12:50 eggert - * Ignore signals when manipulating the semaphore file. - * Modernize list of filename extensions. - * Permit paths of arbitrary length. Beware filenames beginning with "-". - * Remove compile-time limits; use malloc instead. - * Permit dates past 1999/12/31. Make lock and temp files faster and safer. - * Ansify and Posixate. - * Don't use access(). Fix test for non-regular files. Tune. - * - * Revision 4.8 89/05/01 15:09:41 narten - * changed getwd to not stat empty directories. - * - * Revision 4.7 88/08/09 19:12:53 eggert - * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint. - * - * Revision 4.6 87/12/18 11:40:23 narten - * additional file types added from 4.3 BSD version, and SPARC assembler - * comment character added. Also, more lint cleanups. (Guy Harris) - * - * Revision 4.5 87/10/18 10:34:16 narten - * Updating version numbers. Changes relative to 1.1 actually relative - * to verion 4.3 - * - * Revision 1.3 87/03/27 14:22:21 jenkins - * Port to suns - * - * Revision 1.2 85/06/26 07:34:28 svb - * Comment leader '% ' for '*.tex' files added. - * - * Revision 4.3 83/12/15 12:26:48 wft - * Added check for KDELIM in filenames to pairfilenames(). - * - * Revision 4.2 83/12/02 22:47:45 wft - * Added csh, red, and sl filename suffixes. - * - * Revision 4.1 83/05/11 16:23:39 wft - * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames(): - * 1. added copying of path from workfile to RCS file, if RCS file is omitted; - * 2. added getting the file status of RCS and working files; - * 3. added ignoring of directories. - * - * Revision 3.7 83/05/11 15:01:58 wft - * Added comtable[] which pairs filename suffixes with comment leaders; - * updated InitAdmin() accordingly. - * - * Revision 3.6 83/04/05 14:47:36 wft - * fixed Suffix in InitAdmin(). - * - * Revision 3.5 83/01/17 18:01:04 wft - * Added getwd() and rename(); these can be removed by defining - * V4_2BSD, since they are not needed in 4.2 bsd. - * Changed sys/param.h to sys/types.h. - * - * Revision 3.4 82/12/08 21:55:20 wft - * removed unused variable. - * - * Revision 3.3 82/11/28 20:31:37 wft - * Changed mktempfile() to store the generated filenames. - * Changed getfullRCSname() to store the file and pathname, and to - * delete leading "../" and "./". - * - * Revision 3.2 82/11/12 14:29:40 wft - * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(), - * checksuffix(), checkfullpath(). Semaphore name generation updated. - * mktempfile() now checks for nil path; freefilename initialized properly. - * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST. - * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here. - * - * Revision 3.1 82/10/18 14:51:28 wft - * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h). - * renamed checkpath() to checkfullpath(). - */ - - -#include "rcsbase.h" - -libId(fnmsId, "$FreeBSD$") - -static char const *bindex P((char const*,int)); -static int fin2open P((char const*, size_t, char const*, size_t, char const*, size_t, RILE*(*)P((struct buf*,struct stat*,int)), int)); -static int finopen P((RILE*(*)P((struct buf*,struct stat*,int)), int)); -static int suffix_matches P((char const*,char const*)); -static size_t dir_useful_len P((char const*)); -static size_t suffixlen P((char const*)); -static void InitAdmin P((void)); - -char const *RCSname; -char *workname; -int fdlock; -FILE *workstdout; -struct stat RCSstat; -char const *suffixes; - -static char const rcsdir[] = "RCS"; -#define rcslen (sizeof(rcsdir)-1) - -static struct buf RCSbuf, RCSb; -static int RCSerrno; - - -/* Temp names to be unlinked when done, if they are not 0. */ -#define TEMPNAMES 5 /* must be at least DIRTEMPNAMES (see rcsedit.c) */ -static char *volatile tpnames[TEMPNAMES]; - - -struct compair { - char const *suffix, *comlead; -}; - -/* -* This table is present only for backwards compatibility. -* Normally we ignore this table, and use the prefix of the `$Log' line instead. -*/ -static struct compair const comtable[] = { - { "a" , "-- " }, /* Ada */ - { "ada" , "-- " }, - { "adb" , "-- " }, - { "ads" , "-- " }, - { "asm" , ";; " }, /* assembler (MS-DOS) */ - { "bat" , ":: " }, /* batch (MS-DOS) */ - { "body", "-- " }, /* Ada */ - { "c" , " * " }, /* C */ - { "c++" , "// " }, /* C++ in all its infinite guises */ - { "cc" , "// " }, - { "cpp" , "// " }, - { "cxx" , "// " }, - { "cl" , ";;; "}, /* Common Lisp */ - { "cmd" , ":: " }, /* command (OS/2) */ - { "cmf" , "c " }, /* CM Fortran */ - { "cs" , " * " }, /* C* */ - { "el" , "; " }, /* Emacs Lisp */ - { "f" , "c " }, /* Fortran */ - { "for" , "c " }, - { "h" , " * " }, /* C-header */ - { "hpp" , "// " }, /* C++ header */ - { "hxx" , "// " }, - { "l" , " * " }, /* lex (NOTE: franzlisp disagrees) */ - { "lisp", ";;; "}, /* Lucid Lisp */ - { "lsp" , ";; " }, /* Microsoft Lisp */ - { "m" , "// " }, /* Objective C */ - { "mac" , ";; " }, /* macro (DEC-10, MS-DOS, PDP-11, VMS, etc) */ - { "me" , ".\\\" "}, /* troff -me */ - { "ml" , "; " }, /* mocklisp */ - { "mm" , ".\\\" "}, /* troff -mm */ - { "ms" , ".\\\" "}, /* troff -ms */ - { "p" , " * " }, /* Pascal */ - { "pas" , " * " }, - { "ps" , "% " }, /* PostScript */ - { "spec", "-- " }, /* Ada */ - { "sty" , "% " }, /* LaTeX style */ - { "tex" , "% " }, /* TeX */ - { "y" , " * " }, /* yacc */ - { 0 , "# " } /* default for unknown suffix; must be last */ -}; - -#if has_mktemp - static char const *tmp P((void)); - static char const * -tmp() -/* Yield the name of the tmp directory. */ -{ - static char const *s; - if (!s - && !(s = cgetenv("TMPDIR")) /* Unix tradition */ - && !(s = cgetenv("TMP")) /* DOS tradition */ - && !(s = cgetenv("TEMP")) /* another DOS tradition */ - ) - s = TMPDIR; - return s; -} -#endif - - char const * -maketemp(n) - int n; -/* Create a unique pathname using n and the process id and store it - * into the nth slot in tpnames. - * Because of storage in tpnames, tempunlink() can unlink the file later. - * Return a pointer to the pathname created. - */ -{ - char *p; - char const *t = tpnames[n]; -# if has_mktemp - int fd; -# endif - - if (t) - return t; - - catchints(); - { -# if has_mktemp - char const *tp = tmp(); - size_t tplen = dir_useful_len(tp); - p = testalloc(tplen + 10); - VOID sprintf(p, "%.*s%cT%cXXXXXX", (int)tplen, tp, SLASH, '0'+n); - fd = mkstemp(p); - if (fd < 0 || !*p) - faterror("can't make temporary pathname `%.*s%cT%cXXXXXX'", - (int)tplen, tp, SLASH, '0'+n - ); - close(fd); -# else - static char tpnamebuf[TEMPNAMES][L_tmpnam]; - p = tpnamebuf[n]; - if (!tmpnam(p) || !*p) -# ifdef P_tmpdir - faterror("can't make temporary pathname `%s...'",P_tmpdir); -# else - faterror("can't make temporary pathname"); -# endif -# endif - } - - tpnames[n] = p; - return p; -} - - void -tempunlink() -/* Clean up maketemp() files. May be invoked by signal handler. - */ -{ - register int i; - register char *p; - - for (i = TEMPNAMES; 0 <= --i; ) - if ((p = tpnames[i])) { - VOID unlink(p); - /* - * We would tfree(p) here, - * but this might dump core if we're handing a signal. - * We're about to exit anyway, so we won't bother. - */ - tpnames[i] = 0; - } -} - - - static char const * -bindex(sp, c) - register char const *sp; - register int c; -/* Function: Finds the last occurrence of character c in string sp - * and returns a pointer to the character just beyond it. If the - * character doesn't occur in the string, sp is returned. - */ -{ - register char const *r; - r = sp; - while (*sp) { - if (*sp++ == c) r=sp; - } - return r; -} - - - - static int -suffix_matches(suffix, pattern) - register char const *suffix, *pattern; -{ - register int c; - if (!pattern) - return true; - for (;;) - switch (*suffix++ - (c = *pattern++)) { - case 0: - if (!c) - return true; - break; - - case 'A'-'a': - if (ctab[c] == Letter) - break; - /* fall into */ - default: - return false; - } -} - - - static void -InitAdmin() -/* function: initializes an admin node */ -{ - register char const *Suffix; - register int i; - - Head=0; Dbranch=0; AccessList=0; Symbols=0; Locks=0; - StrictLocks=STRICT_LOCKING; - - /* guess the comment leader from the suffix*/ - Suffix = bindex(workname, '.'); - if (Suffix==workname) Suffix= ""; /* empty suffix; will get default*/ - for (i=0; !suffix_matches(Suffix,comtable[i].suffix); i++) - continue; - Comment.string = comtable[i].comlead; - Comment.size = strlen(comtable[i].comlead); - Expand = KEYVAL_EXPAND; - clear_buf(&Ignored); - Lexinit(); /* note: if !finptr, reads nothing; only initializes */ -} - - - - void -bufalloc(b, size) - register struct buf *b; - size_t size; -/* Ensure *B is a name buffer of at least SIZE bytes. - * *B's old contents can be freed; *B's new contents are undefined. - */ -{ - if (b->size < size) { - if (b->size) - tfree(b->string); - else - b->size = sizeof(malloc_type); - while (b->size < size) - b->size <<= 1; - b->string = tnalloc(char, b->size); - } -} - - void -bufrealloc(b, size) - register struct buf *b; - size_t size; -/* like bufalloc, except *B's old contents, if any, are preserved */ -{ - if (b->size < size) { - if (!b->size) - bufalloc(b, size); - else { - while ((b->size <<= 1) < size) - continue; - b->string = trealloc(char, b->string, b->size); - } - } -} - - void -bufautoend(b) - struct buf *b; -/* Free an auto buffer at block exit. */ -{ - if (b->size) - tfree(b->string); -} - - struct cbuf -bufremember(b, s) - struct buf *b; - size_t s; -/* - * Free the buffer B with used size S. - * Yield a cbuf with identical contents. - * The cbuf will be reclaimed when this input file is finished. - */ -{ - struct cbuf cb; - - if ((cb.size = s)) - cb.string = fremember(trealloc(char, b->string, s)); - else { - bufautoend(b); /* not really auto */ - cb.string = ""; - } - return cb; -} - - char * -bufenlarge(b, alim) - register struct buf *b; - char const **alim; -/* Make *B larger. Set *ALIM to its new limit, and yield the relocated value - * of its old limit. - */ -{ - size_t s = b->size; - bufrealloc(b, s + 1); - *alim = b->string + b->size; - return b->string + s; -} - - void -bufscat(b, s) - struct buf *b; - char const *s; -/* Concatenate S to B's end. */ -{ - size_t blen = b->string ? strlen(b->string) : 0; - bufrealloc(b, blen+strlen(s)+1); - VOID strcpy(b->string+blen, s); -} - - void -bufscpy(b, s) - struct buf *b; - char const *s; -/* Copy S into B. */ -{ - bufalloc(b, strlen(s)+1); - VOID strcpy(b->string, s); -} - - - char const * -basefilename(p) - char const *p; -/* Yield the address of the base filename of the pathname P. */ -{ - register char const *b = p, *q = p; - for (;;) - switch (*q++) { - case SLASHes: b = q; break; - case 0: return b; - } -} - - - static size_t -suffixlen(x) - char const *x; -/* Yield the length of X, an RCS pathname suffix. */ -{ - register char const *p; - - p = x; - for (;;) - switch (*p) { - case 0: case SLASHes: - return p - x; - - default: - ++p; - continue; - } -} - - char const * -rcssuffix(name) - char const *name; -/* Yield the suffix of NAME if it is an RCS pathname, 0 otherwise. */ -{ - char const *x, *p, *nz; - size_t nl, xl; - - nl = strlen(name); - nz = name + nl; - x = suffixes; - do { - if ((xl = suffixlen(x))) { - if (xl <= nl && memcmp(p = nz-xl, x, xl) == 0) - return p; - } else - for (p = name; p < nz - rcslen; p++) - if ( - isSLASH(p[rcslen]) - && (p==name || isSLASH(p[-1])) - && memcmp(p, rcsdir, rcslen) == 0 - ) - return nz; - x += xl; - } while (*x++); - return 0; -} - - /*ARGSUSED*/ RILE * -rcsreadopen(RCSpath, status, mustread) - struct buf *RCSpath; - struct stat *status; - int mustread; -/* Open RCSPATH for reading and yield its FILE* descriptor. - * If successful, set *STATUS to its status. - * Pass this routine to pairnames() for read-only access to the file. */ -{ - return Iopen(RCSpath->string, FOPEN_RB, status); -} - - static int -finopen(rcsopen, mustread) - RILE *(*rcsopen)P((struct buf*,struct stat*,int)); - int mustread; -/* - * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. - * Set finptr to the result and yield true if successful. - * RCSb holds the file's name. - * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. - * Yield true if successful or if an unusual failure. - */ -{ - int interesting, preferold; - - /* - * We prefer an old name to that of a nonexisting new RCS file, - * unless we tried locking the old name and failed. - */ - preferold = RCSbuf.string[0] && (mustread||0<=fdlock); - - finptr = (*rcsopen)(&RCSb, &RCSstat, mustread); - interesting = finptr || errno!=ENOENT; - if (interesting || !preferold) { - /* Use the new name. */ - RCSerrno = errno; - bufscpy(&RCSbuf, RCSb.string); - } - return interesting; -} - - static int -fin2open(d, dlen, base, baselen, x, xlen, rcsopen, mustread) - char const *d, *base, *x; - size_t dlen, baselen, xlen; - RILE *(*rcsopen)P((struct buf*,struct stat*,int)); - int mustread; -/* - * D is a directory name with length DLEN (including trailing slash). - * BASE is a filename with length BASELEN. - * X is an RCS pathname suffix with length XLEN. - * Use RCSOPEN to open an RCS file; MUSTREAD is set if the file must be read. - * Yield true if successful. - * Try dRCS/basex first; if that fails and x is nonempty, try dbasex. - * Put these potential names in RCSb. - * Set RCSbuf to the best RCS name found so far, and RCSerrno to its errno. - * Yield true if successful or if an unusual failure. - */ -{ - register char *p; - - bufalloc(&RCSb, dlen + rcslen + 1 + baselen + xlen + 1); - - /* Try dRCS/basex. */ - VOID memcpy(p = RCSb.string, d, dlen); - VOID memcpy(p += dlen, rcsdir, rcslen); - p += rcslen; - *p++ = SLASH; - VOID memcpy(p, base, baselen); - VOID memcpy(p += baselen, x, xlen); - p[xlen] = 0; - if (xlen) { - if (finopen(rcsopen, mustread)) - return true; - - /* Try dbasex. */ - /* Start from scratch, because finopen() may have changed RCSb. */ - VOID memcpy(p = RCSb.string, d, dlen); - VOID memcpy(p += dlen, base, baselen); - VOID memcpy(p += baselen, x, xlen); - p[xlen] = 0; - } - return finopen(rcsopen, mustread); -} - - int -pairnames(argc, argv, rcsopen, mustread, quiet) - int argc; - char **argv; - RILE *(*rcsopen)P((struct buf*,struct stat*,int)); - int mustread, quiet; -/* - * Pair the pathnames pointed to by argv; argc indicates - * how many there are. - * Place a pointer to the RCS pathname into RCSname, - * and a pointer to the pathname of the working file into workname. - * If both are given, and workstdout - * is set, a warning is printed. - * - * If the RCS file exists, places its status into RCSstat. - * - * If the RCS file exists, it is RCSOPENed for reading, the file pointer - * is placed into finptr, and the admin-node is read in; returns 1. - * If the RCS file does not exist and MUSTREAD, - * print an error unless QUIET and return 0. - * Otherwise, initialize the admin node and return -1. - * - * 0 is returned on all errors, e.g. files that are not regular files. - */ -{ - static struct buf tempbuf; - - register char *p, *arg, *RCS1; - char const *base, *RCSbase, *x; - int paired; - size_t arglen, dlen, baselen, xlen; - - fdlock = -1; - - if (!(arg = *argv)) return 0; /* already paired pathname */ - if (*arg == '-') { - error("%s option is ignored after pathnames", arg); - return 0; - } - - base = basefilename(arg); - paired = false; - - /* first check suffix to see whether it is an RCS file or not */ - if ((x = rcssuffix(arg))) - { - /* RCS pathname given */ - RCS1 = arg; - RCSbase = base; - baselen = x - base; - if ( - 1 < argc && - !rcssuffix(workname = p = argv[1]) && - baselen <= (arglen = strlen(p)) && - ((p+=arglen-baselen) == workname || isSLASH(p[-1])) && - memcmp(base, p, baselen) == 0 - ) { - argv[1] = 0; - paired = true; - } else { - bufscpy(&tempbuf, base); - workname = p = tempbuf.string; - p[baselen] = 0; - } - } else { - /* working file given; now try to find RCS file */ - workname = arg; - baselen = strlen(base); - /* Derive RCS pathname. */ - if ( - 1 < argc && - (x = rcssuffix(RCS1 = argv[1])) && - baselen <= x - RCS1 && - ((RCSbase=x-baselen)==RCS1 || isSLASH(RCSbase[-1])) && - memcmp(base, RCSbase, baselen) == 0 - ) { - argv[1] = 0; - paired = true; - } else - RCSbase = RCS1 = 0; - } - /* Now we have a (tentative) RCS pathname in RCS1 and workname. */ - /* Second, try to find the right RCS file */ - if (RCSbase!=RCS1) { - /* a path for RCSfile is given; single RCS file to look for */ - bufscpy(&RCSbuf, RCS1); - finptr = (*rcsopen)(&RCSbuf, &RCSstat, mustread); - RCSerrno = errno; - } else { - bufscpy(&RCSbuf, ""); - if (RCS1) - /* RCS filename was given without path. */ - VOID fin2open(arg, (size_t)0, RCSbase, baselen, - x, strlen(x), rcsopen, mustread - ); - else { - /* No RCS pathname was given. */ - /* Try each suffix in turn. */ - dlen = base-arg; - x = suffixes; - while (! fin2open(arg, dlen, base, baselen, - x, xlen=suffixlen(x), rcsopen, mustread - )) { - x += xlen; - if (!*x++) - break; - } - } - } - RCSname = p = RCSbuf.string; - if (finptr) { - if (!S_ISREG(RCSstat.st_mode)) { - error("%s isn't a regular file -- ignored", p); - return 0; - } - Lexinit(); getadmin(); - } else { - if (RCSerrno!=ENOENT || mustread || fdlock<0) { - if (RCSerrno == EEXIST) - error("RCS file %s is in use", p); - else if (!quiet || RCSerrno!=ENOENT) - enerror(RCSerrno, p); - return 0; - } - InitAdmin(); - }; - - if (paired && workstdout) - workwarn("Working file ignored due to -p option"); - - prevkeys = false; - return finptr ? 1 : -1; -} - - - char const * -getfullRCSname() -/* - * Return a pointer to the full pathname of the RCS file. - * Remove leading `./'. - */ -{ - if (ROOTPATH(RCSname)) { - return RCSname; - } else { - static struct buf rcsbuf; -# if needs_getabsname - bufalloc(&rcsbuf, SIZEABLE_PATH + 1); - while (getabsname(RCSname, rcsbuf.string, rcsbuf.size) != 0) - if (errno == ERANGE) - bufalloc(&rcsbuf, rcsbuf.size<<1); - else - efaterror("getabsname"); -# else - static char const *wdptr; - static struct buf wdbuf; - static size_t wdlen; - - register char const *r; - register size_t dlen; - register char *d; - register char const *wd; - - if (!(wd = wdptr)) { - /* Get working directory for the first time. */ - char *PWD = cgetenv("PWD"); - struct stat PWDstat, dotstat; - if (! ( - (d = PWD) && - ROOTPATH(PWD) && - stat(PWD, &PWDstat) == 0 && - stat(".", &dotstat) == 0 && - same_file(PWDstat, dotstat, 1) - )) { - bufalloc(&wdbuf, SIZEABLE_PATH + 1); -# if has_getcwd || !has_getwd - while (!(d = getcwd(wdbuf.string, wdbuf.size))) - if (errno == ERANGE) - bufalloc(&wdbuf, wdbuf.size<<1); - else if ((d = PWD)) - break; - else - efaterror("getcwd"); -# else - d = getwd(wdbuf.string); - if (!d && !(d = PWD)) - efaterror("getwd"); -# endif - } - wdlen = dir_useful_len(d); - d[wdlen] = 0; - wdptr = wd = d; - } - /* - * Remove leading `./'s from RCSname. - * Do not try to handle `../', since removing it may yield - * the wrong answer in the presence of symbolic links. - */ - for (r = RCSname; r[0]=='.' && isSLASH(r[1]); r += 2) - /* `.////' is equivalent to `./'. */ - while (isSLASH(r[2])) - r++; - /* Build full pathname. */ - dlen = wdlen; - bufalloc(&rcsbuf, dlen + strlen(r) + 2); - d = rcsbuf.string; - VOID memcpy(d, wd, dlen); - d += dlen; - *d++ = SLASH; - VOID strcpy(d, r); -# endif - return rcsbuf.string; - } -} - -/* Derived from code from the XFree86 project */ - char const * -getfullCVSname() -/* Function: returns a pointer to the path name of the RCS file with the - * CVSROOT part stripped off, and with 'Attic/' stripped off (if present). - */ -{ - -#define ATTICDIR "/Attic" - - char const *namebuf = getfullRCSname(); - char *cvsroot = cgetenv("CVSROOT"); - int cvsrootlen; - char *c = NULL; - int alen = strlen(ATTICDIR); - - if ((c = strrchr(namebuf, '/')) != NULL) { - if (namebuf - c >= alen) { - if (!strncmp(c - alen, ATTICDIR, alen)) { - while(*c != '\0') { - *(c - alen) = *c; - c++; - } - *(c - alen) = '\0'; - } - } - } - - if (!cvsroot) - return(namebuf); - else - { - cvsrootlen = strlen(cvsroot); - if (!strncmp(namebuf, cvsroot, cvsrootlen) && - namebuf[cvsrootlen] == '/') - return(namebuf + cvsrootlen + 1); - else - return(namebuf); - } -} - - static size_t -dir_useful_len(d) - char const *d; -/* -* D names a directory; yield the number of characters of D's useful part. -* To create a file in D, append a SLASH and a file name to D's useful part. -* Ignore trailing slashes if possible; not only are they ugly, -* but some non-Posix systems misbehave unless the slashes are omitted. -*/ -{ -# ifndef SLASHSLASH_is_SLASH -# define SLASHSLASH_is_SLASH 0 -# endif - size_t dlen = strlen(d); - if (!SLASHSLASH_is_SLASH && dlen==2 && isSLASH(d[0]) && isSLASH(d[1])) - --dlen; - else - while (dlen && isSLASH(d[dlen-1])) - --dlen; - return dlen; -} - -#ifndef isSLASH - int -isSLASH(c) - int c; -{ - switch (c) { - case SLASHes: - return true; - default: - return false; - } -} -#endif - - -#if !has_getcwd && !has_getwd - - char * -getcwd(path, size) - char *path; - size_t size; -{ - static char const usrbinpwd[] = "/usr/bin/pwd"; -# define binpwd (usrbinpwd+4) - - register FILE *fp; - register int c; - register char *p, *lim; - int closeerrno, closeerror, e, fd[2], readerror, toolong, wstatus; - pid_t child; - - if (!size) { - errno = EINVAL; - return 0; - } - if (pipe(fd) != 0) - return 0; -# if bad_wait_if_SIGCHLD_ignored -# ifndef SIGCHLD -# define SIGCHLD SIGCLD -# endif - VOID signal(SIGCHLD, SIG_DFL); -# endif - if (!(child = vfork())) { - if ( - close(fd[0]) == 0 && - (fd[1] == STDOUT_FILENO || -# ifdef F_DUPFD - (VOID close(STDOUT_FILENO), - fcntl(fd[1], F_DUPFD, STDOUT_FILENO)) -# else - dup2(fd[1], STDOUT_FILENO) -# endif - == STDOUT_FILENO && - close(fd[1]) == 0 - ) - ) { - VOID close(STDERR_FILENO); - VOID execl(binpwd, binpwd, (char *)0); - VOID execl(usrbinpwd, usrbinpwd, (char *)0); - } - _exit(EXIT_FAILURE); - } - e = errno; - closeerror = close(fd[1]); - closeerrno = errno; - fp = 0; - readerror = toolong = wstatus = 0; - p = path; - if (0 <= child) { - fp = fdopen(fd[0], "r"); - e = errno; - if (fp) { - lim = p + size; - for (p = path; ; *p++ = c) { - if ((c=getc(fp)) < 0) { - if (feof(fp)) - break; - if (ferror(fp)) { - readerror = 1; - e = errno; - break; - } - } - if (p == lim) { - toolong = 1; - break; - } - } - } -# if has_waitpid - if (waitpid(child, &wstatus, 0) < 0) - wstatus = 1; -# else - { - pid_t w; - do { - if ((w = wait(&wstatus)) < 0) { - wstatus = 1; - break; - } - } while (w != child); - } -# endif - } - if (!fp) { - VOID close(fd[0]); - errno = e; - return 0; - } - if (fclose(fp) != 0) - return 0; - if (readerror) { - errno = e; - return 0; - } - if (closeerror) { - errno = closeerrno; - return 0; - } - if (toolong) { - errno = ERANGE; - return 0; - } - if (wstatus || p == path || *--p != '\n') { - errno = EACCES; - return 0; - } - *p = '\0'; - return path; -} -#endif - - -#ifdef PAIRTEST -/* test program for pairnames() and getfullRCSname() */ - -char const cmdid[] = "pair"; - -main(argc, argv) -int argc; char *argv[]; -{ - int result; - int initflag; - quietflag = initflag = false; - - while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) { - switch ((*argv)[1]) { - - case 'p': workstdout = stdout; - break; - case 'i': initflag=true; - break; - case 'q': quietflag=true; - break; - default: error("unknown option: %s", *argv); - break; - } - } - - do { - RCSname = workname = 0; - result = pairnames(argc,argv,rcsreadopen,!initflag,quietflag); - if (result!=0) { - diagnose("RCS pathname: %s; working pathname: %s\nFull RCS pathname: %s\n", - RCSname, workname, getfullRCSname() - ); - } - switch (result) { - case 0: continue; /* already paired file */ - - case 1: if (initflag) { - rcserror("already exists"); - } else { - diagnose("RCS file %s exists\n", RCSname); - } - Ifclose(finptr); - break; - - case -1:diagnose("RCS file doesn't exist\n"); - break; - } - - } while (++argv, --argc>=1); - -} - - void -exiterr() -{ - dirtempunlink(); - tempunlink(); - _exit(EXIT_FAILURE); -} -#endif Index: gnu/usr.bin/rcs/lib/rcsgen.c =================================================================== --- gnu/usr.bin/rcs/lib/rcsgen.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsgen.c (working copy) @@ -1,681 +0,0 @@ -/* Generate RCS revisions. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.16 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.15 1995/06/01 16:23:43 eggert - * (putadmin): Open RCS file with FOPEN_WB. - * - * Revision 5.14 1994/03/17 14:05:48 eggert - * Work around SVR4 stdio performance bug. - * Flush stderr after prompt. Remove lint. - * - * Revision 5.13 1993/11/03 17:42:27 eggert - * Don't discard ignored phrases. Improve quality of diagnostics. - * - * Revision 5.12 1992/07/28 16:12:44 eggert - * Statement macro names now end in _. - * Be consistent about pathnames vs filenames. - * - * Revision 5.11 1992/01/24 18:44:19 eggert - * Move put routines here from rcssyn.c. - * Add support for bad_creat0. - * - * Revision 5.10 1991/10/07 17:32:46 eggert - * Fix log bugs, e.g. ci -t/dev/null when has_mmap. - * - * Revision 5.9 1991/09/10 22:15:46 eggert - * Fix test for redirected stdin. - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Add piece tables. Tune. - * - * Revision 5.7 1991/04/21 11:58:24 eggert - * Add MS-DOS support. - * - * Revision 5.6 1990/12/27 19:54:26 eggert - * Fix bug: rcs -t inserted \n, making RCS file grow. - * - * Revision 5.5 1990/12/04 05:18:45 eggert - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.4 1990/11/01 05:03:47 eggert - * Add -I and new -t behavior. Permit arbitrary data in logs. - * - * Revision 5.3 1990/09/21 06:12:43 hammer - * made putdesc() treat stdin the same whether or not it was from a terminal - * by making it recognize that a single '.' was then end of the - * description always - * - * Revision 5.2 1990/09/04 08:02:25 eggert - * Fix `co -p1.1 -ko' bug. Standardize yes-or-no procedure. - * - * Revision 5.1 1990/08/29 07:14:01 eggert - * Clean old log messages too. - * - * Revision 5.0 1990/08/22 08:12:52 eggert - * Remove compile-time limits; use malloc instead. - * Ansify and Posixate. - * - * Revision 4.7 89/05/01 15:12:49 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.6 88/08/28 14:59:10 eggert - * Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin() - * - * Revision 4.5 87/12/18 11:43:25 narten - * additional lint cleanups, and a bug fix from the 4.3BSD version that - * keeps "ci" from sticking a '\377' into the description if you run it - * with a zero-length file as the description. (Guy Harris) - * - * Revision 4.4 87/10/18 10:35:10 narten - * Updating version numbers. Changes relative to 1.1 actually relative to - * 4.2 - * - * Revision 1.3 87/09/24 13:59:51 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:27 jenkins - * Port to suns - * - * Revision 4.2 83/12/02 23:01:39 wft - * merged 4.1 and 3.3.1.1 (clearerr(stdin)). - * - * Revision 4.1 83/05/10 16:03:33 wft - * Changed putamin() to abort if trying to reread redirected stdin. - * Fixed getdesc() to output a prompt on initial newline. - * - * Revision 3.3.1.1 83/10/19 04:21:51 lepreau - * Added clearerr(stdin) for re-reading description from stdin. - * - * Revision 3.3 82/11/28 21:36:49 wft - * 4.2 prerelease - * - * Revision 3.3 82/11/28 21:36:49 wft - * Replaced ferror() followed by fclose() with ffclose(). - * Putdesc() now suppresses the prompts if stdin - * is not a terminal. A pointer to the current log message is now - * inserted into the corresponding delta, rather than leaving it in a - * global variable. - * - * Revision 3.2 82/10/18 21:11:26 wft - * I added checks for write errors during editing, and improved - * the prompt on putdesc(). - * - * Revision 3.1 82/10/13 15:55:09 wft - * corrected type of variables assigned to by getc (char --> int) - */ - - - - -#include "rcsbase.h" - -libId(genId, "$FreeBSD$") - -int interactiveflag; /* Should we act as if stdin is a tty? */ -struct buf curlogbuf; /* buffer for current log message */ - -enum stringwork { enter, copy, edit, expand, edit_expand }; - -static void putdelta P((struct hshentry const*,FILE*)); -static void scandeltatext P((struct hshentry*,enum stringwork,int)); - - - - - char const * -buildrevision(deltas, target, outfile, expandflag) - struct hshentries const *deltas; - struct hshentry *target; - FILE *outfile; - int expandflag; -/* Function: Generates the revision given by target - * by retrieving all deltas given by parameter deltas and combining them. - * If outfile is set, the revision is output to it, - * otherwise written into a temporary file. - * Temporary files are allocated by maketemp(). - * if expandflag is set, keyword expansion is performed. - * Return 0 if outfile is set, the name of the temporary file otherwise. - * - * Algorithm: Copy initial revision unchanged. Then edit all revisions but - * the last one into it, alternating input and output files (resultname and - * editname). The last revision is then edited in, performing simultaneous - * keyword substitution (this saves one extra pass). - * All this simplifies if only one revision needs to be generated, - * or no keyword expansion is necessary, or if output goes to stdout. - */ -{ - if (deltas->first == target) { - /* only latest revision to generate */ - openfcopy(outfile); - scandeltatext(target, expandflag?expand:copy, true); - if (outfile) - return 0; - else { - Ozclose(&fcopy); - return resultname; - } - } else { - /* several revisions to generate */ - /* Get initial revision without keyword expansion. */ - scandeltatext(deltas->first, enter, false); - while ((deltas=deltas->rest)->rest) { - /* do all deltas except last one */ - scandeltatext(deltas->first, edit, false); - } - if (expandflag || outfile) { - /* first, get to beginning of file*/ - finishedit((struct hshentry*)0, outfile, false); - } - scandeltatext(target, expandflag?edit_expand:edit, true); - finishedit( - expandflag ? target : (struct hshentry*)0, - outfile, true - ); - if (outfile) - return 0; - Ozclose(&fcopy); - return resultname; - } -} - - - - static void -scandeltatext(delta, func, needlog) - struct hshentry *delta; - enum stringwork func; - int needlog; -/* Function: Scans delta text nodes up to and including the one given - * by delta. For the one given by delta, the log message is saved into - * delta->log if needlog is set; func specifies how to handle the text. - * Similarly, if needlog, delta->igtext is set to the ignored phrases. - * Assumes the initial lexeme must be read in first. - * Does not advance nexttok after it is finished. - */ -{ - struct hshentry const *nextdelta; - struct cbuf cb; - - for (;;) { - if (eoflex()) - fatserror("can't find delta for revision %s", delta->num); - nextlex(); - if (!(nextdelta=getnum())) { - fatserror("delta number corrupted"); - } - getkeystring(Klog); - if (needlog && delta==nextdelta) { - cb = savestring(&curlogbuf); - delta->log = cleanlogmsg(curlogbuf.string, cb.size); - nextlex(); - delta->igtext = getphrases(Ktext); - } else {readstring(); - ignorephrases(Ktext); - } - getkeystring(Ktext); - - if (delta==nextdelta) - break; - readstring(); /* skip over it */ - - } - switch (func) { - case enter: enterstring(); break; - case copy: copystring(); break; - case expand: xpandstring(delta); break; - case edit: editstring((struct hshentry *)0); break; - case edit_expand: editstring(delta); break; - } -} - - struct cbuf -cleanlogmsg(m, s) - char *m; - size_t s; -{ - register char *t = m; - register char const *f = t; - struct cbuf r; - while (s) { - --s; - if ((*t++ = *f++) == '\n') - while (m < --t) - if (t[-1]!=' ' && t[-1]!='\t') { - *t++ = '\n'; - break; - } - } - while (m < t && (t[-1]==' ' || t[-1]=='\t' || t[-1]=='\n')) - --t; - r.string = m; - r.size = t - m; - return r; -} - - -int ttystdin() -{ - static int initialized; - if (!initialized) { - if (!interactiveflag) - interactiveflag = isatty(STDIN_FILENO); - initialized = true; - } - return interactiveflag; -} - - int -getcstdin() -{ - register FILE *in; - register int c; - - in = stdin; - if (feof(in) && ttystdin()) - clearerr(in); - c = getc(in); - if (c == EOF) { - testIerror(in); - if (feof(in) && ttystdin()) - afputc('\n',stderr); - } - return c; -} - -#if has_prototypes - int -yesorno(int default_answer, char const *question, ...) -#else - /*VARARGS2*/ int - yesorno(default_answer, question, va_alist) - int default_answer; char const *question; va_dcl -#endif -{ - va_list args; - register int c, r; - if (!quietflag && ttystdin()) { - oflush(); - vararg_start(args, question); - fvfprintf(stderr, question, args); - va_end(args); - eflush(); - r = c = getcstdin(); - while (c!='\n' && !feof(stdin)) - c = getcstdin(); - if (r=='y' || r=='Y') - return true; - if (r=='n' || r=='N') - return false; - } - return default_answer; -} - - - void -putdesc(textflag, textfile) - int textflag; - char *textfile; -/* Function: puts the descriptive text into file frewrite. - * if finptr && !textflag, the text is copied from the old description. - * Otherwise, if textfile, the text is read from that - * file, or from stdin, if !textfile. - * A textfile with a leading '-' is treated as a string, not a pathname. - * If finptr, the old descriptive text is discarded. - * Always clears foutptr. - */ -{ - static struct buf desc; - static struct cbuf desclean; - - register FILE *txt; - register int c; - register FILE * frew; - register char *p; - register size_t s; - char const *plim; - - frew = frewrite; - if (finptr && !textflag) { - /* copy old description */ - aprintf(frew, "\n\n%s%c", Kdesc, nextc); - foutptr = frewrite; - getdesc(false); - foutptr = 0; - } else { - foutptr = 0; - /* get new description */ - if (finptr) { - /*skip old description*/ - getdesc(false); - } - aprintf(frew,"\n\n%s\n%c",Kdesc,SDELIM); - if (!textfile) - desclean = getsstdin( - "t-", "description", - "NOTE: This is NOT the log message!\n", &desc - ); - else if (!desclean.string) { - if (*textfile == '-') { - p = textfile + 1; - s = strlen(p); - } else { - if (!(txt = fopenSafer(textfile, "r"))) - efaterror(textfile); - bufalloc(&desc, 1); - p = desc.string; - plim = p + desc.size; - for (;;) { - if ((c=getc(txt)) == EOF) { - testIerror(txt); - if (feof(txt)) - break; - } - if (plim <= p) - p = bufenlarge(&desc, &plim); - *p++ = c; - } - if (fclose(txt) != 0) - Ierror(); - s = p - desc.string; - p = desc.string; - } - desclean = cleanlogmsg(p, s); - } - putstring(frew, false, desclean, true); - aputc_('\n', frew) - } -} - - struct cbuf -getsstdin(option, name, note, buf) - char const *option, *name, *note; - struct buf *buf; -{ - register int c; - register char *p; - register size_t i; - register int tty = ttystdin(); - - if (tty) { - aprintf(stderr, - "enter %s, terminated with single '.' or end of file:\n%s>> ", - name, note - ); - eflush(); - } else if (feof(stdin)) - rcsfaterror("can't reread redirected stdin for %s; use -%s<%s>", - name, option, name - ); - - for ( - i = 0, p = 0; - c = getcstdin(), !feof(stdin); - bufrealloc(buf, i+1), p = buf->string, p[i++] = c - ) - if (c == '\n') - if (i && p[i-1]=='.' && (i==1 || p[i-2]=='\n')) { - /* Remove trailing '.'. */ - --i; - break; - } else if (tty) { - aputs(">> ", stderr); - eflush(); - } - return cleanlogmsg(p, i); -} - - - void -putadmin() -/* Output the admin node. */ -{ - register FILE *fout; - struct assoc const *curassoc; - struct rcslock const *curlock; - struct access const *curaccess; - - if (!(fout = frewrite)) { -# if bad_creat0 - ORCSclose(); - fout = fopenSafer(makedirtemp(0), FOPEN_WB); -# else - int fo = fdlock; - fdlock = -1; - fout = fdopen(fo, FOPEN_WB); -# endif - - if (!(frewrite = fout)) - efaterror(RCSname); - } - - /* - * Output the first character with putc, not printf. - * Otherwise, an SVR4 stdio bug buffers output inefficiently. - */ - aputc_(*Khead, fout) - aprintf(fout, "%s\t%s;\n", Khead + 1, Head?Head->num:""); - if (Dbranch && VERSION(4)<=RCSversion) - aprintf(fout, "%s\t%s;\n", Kbranch, Dbranch); - - aputs(Kaccess, fout); - curaccess = AccessList; - while (curaccess) { - aprintf(fout, "\n\t%s", curaccess->login); - curaccess = curaccess->nextaccess; - } - aprintf(fout, ";\n%s", Ksymbols); - curassoc = Symbols; - while (curassoc) { - aprintf(fout, "\n\t%s:%s", curassoc->symbol, curassoc->num); - curassoc = curassoc->nextassoc; - } - aprintf(fout, ";\n%s", Klocks); - curlock = Locks; - while (curlock) { - aprintf(fout, "\n\t%s:%s", curlock->login, curlock->delta->num); - curlock = curlock->nextlock; - } - if (StrictLocks) aprintf(fout, "; %s", Kstrict); - aprintf(fout, ";\n"); - if (Comment.size) { - aprintf(fout, "%s\t", Kcomment); - putstring(fout, true, Comment, false); - aprintf(fout, ";\n"); - } - if (Expand != KEYVAL_EXPAND) - aprintf(fout, "%s\t%c%s%c;\n", - Kexpand, SDELIM, expand_names[Expand], SDELIM - ); - awrite(Ignored.string, Ignored.size, fout); - aputc_('\n', fout) -} - - - static void -putdelta(node, fout) - register struct hshentry const *node; - register FILE * fout; -/* Output the delta NODE to FOUT. */ -{ - struct branchhead const *nextbranch; - - if (!node) return; - - aprintf(fout, "\n%s\n%s\t%s;\t%s %s;\t%s %s;\nbranches", - node->num, - Kdate, node->date, - Kauthor, node->author, - Kstate, node->state?node->state:"" - ); - nextbranch = node->branches; - while (nextbranch) { - aprintf(fout, "\n\t%s", nextbranch->hsh->num); - nextbranch = nextbranch->nextbranch; - } - - aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:""); - awrite(node->ig.string, node->ig.size, fout); -} - - - void -puttree(root, fout) - struct hshentry const *root; - register FILE *fout; -/* Output the delta tree with base ROOT in preorder to FOUT. */ -{ - struct branchhead const *nextbranch; - - if (!root) return; - - if (root->selector) - putdelta(root, fout); - - puttree(root->next, fout); - - nextbranch = root->branches; - while (nextbranch) { - puttree(nextbranch->hsh, fout); - nextbranch = nextbranch->nextbranch; - } -} - - - int -putdtext(delta, srcname, fout, diffmt) - struct hshentry const *delta; - char const *srcname; - FILE *fout; - int diffmt; -/* - * Output a deltatext node with delta number DELTA->num, log message DELTA->log, - * ignored phrases DELTA->igtext and text SRCNAME to FOUT. - * Double up all SDELIMs in both the log and the text. - * Make sure the log message ends in \n. - * Return false on error. - * If DIFFMT, also check that the text is valid diff -n output. - */ -{ - RILE *fin; - if (!(fin = Iopen(srcname, "r", (struct stat*)0))) { - eerror(srcname); - return false; - } - putdftext(delta, fin, fout, diffmt); - Ifclose(fin); - return true; -} - - void -putstring(out, delim, s, log) - register FILE *out; - struct cbuf s; - int delim, log; -/* - * Output to OUT one SDELIM if DELIM, then the string S with SDELIMs doubled. - * If LOG is set then S is a log string; append a newline if S is nonempty. - */ -{ - register char const *sp; - register size_t ss; - - if (delim) - aputc_(SDELIM, out) - sp = s.string; - for (ss = s.size; ss; --ss) { - if (*sp == SDELIM) - aputc_(SDELIM, out) - aputc_(*sp++, out) - } - if (s.size && log) - aputc_('\n', out) - aputc_(SDELIM, out) -} - - void -putdftext(delta, finfile, foutfile, diffmt) - struct hshentry const *delta; - RILE *finfile; - FILE *foutfile; - int diffmt; -/* like putdtext(), except the source file is already open */ -{ - declarecache; - register FILE *fout; - register int c; - register RILE *fin; - int ed; - struct diffcmd dc; - - fout = foutfile; - aprintf(fout, DELNUMFORM, delta->num, Klog); - - /* put log */ - putstring(fout, true, delta->log, true); - aputc_('\n', fout) - - /* put ignored phrases */ - awrite(delta->igtext.string, delta->igtext.size, fout); - - /* put text */ - aprintf(fout, "%s\n%c", Ktext, SDELIM); - - fin = finfile; - setupcache(fin); - if (!diffmt) { - /* Copy the file */ - cache(fin); - for (;;) { - cachegeteof_(c, break;) - if (c==SDELIM) aputc_(SDELIM, fout) /*double up SDELIM*/ - aputc_(c, fout) - } - } else { - initdiffcmd(&dc); - while (0 <= (ed = getdiffcmd(fin, false, fout, &dc))) - if (ed) { - cache(fin); - while (dc.nlines--) - do { - cachegeteof_(c, { if (!dc.nlines) goto OK_EOF; unexpected_EOF(); }) - if (c == SDELIM) - aputc_(SDELIM, fout) - aputc_(c, fout) - } while (c != '\n'); - uncache(fin); - } - } - OK_EOF: - aprintf(fout, "%c\n", SDELIM); -} Index: gnu/usr.bin/rcs/lib/rcskeep.c =================================================================== --- gnu/usr.bin/rcs/lib/rcskeep.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcskeep.c (working copy) @@ -1,452 +0,0 @@ -/* Extract RCS keyword string values from working files. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.10 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.9 1995/06/01 16:23:43 eggert - * (getoldkeys): Don't panic if a Name: is empty. - * - * Revision 5.8 1994/03/17 14:05:48 eggert - * Remove lint. - * - * Revision 5.7 1993/11/09 17:40:15 eggert - * Use simpler timezone parsing strategy now that we're using ISO 8601 format. - * - * Revision 5.6 1993/11/03 17:42:27 eggert - * Scan for Name keyword. Improve quality of diagnostics. - * - * Revision 5.5 1992/07/28 16:12:44 eggert - * Statement macro names now end in _. - * - * Revision 5.4 1991/08/19 03:13:55 eggert - * Tune. - * - * Revision 5.3 1991/04/21 11:58:25 eggert - * Shorten names to keep them distinct on shortname hosts. - * - * Revision 5.2 1990/10/04 06:30:20 eggert - * Parse time zone offsets; future RCS versions may output them. - * - * Revision 5.1 1990/09/20 02:38:56 eggert - * ci -k now checks dates more thoroughly. - * - * Revision 5.0 1990/08/22 08:12:53 eggert - * Retrieve old log message if there is one. - * Don't require final newline. - * Remove compile-time limits; use malloc instead. Tune. - * Permit dates past 1999/12/31. Ansify and Posixate. - * - * Revision 4.6 89/05/01 15:12:56 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.5 88/08/09 19:13:03 eggert - * Remove lint and speed up by making FILE *fp local, not global. - * - * Revision 4.4 87/12/18 11:44:21 narten - * more lint cleanups (Guy Harris) - * - * Revision 4.3 87/10/18 10:35:50 narten - * Updating version numbers. Changes relative to 1.1 actually relative - * to 4.1 - * - * Revision 1.3 87/09/24 14:00:00 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:29 jenkins - * Port to suns - * - * Revision 4.1 83/05/10 16:26:44 wft - * Added new markers Id and RCSfile; extraction added. - * Marker matching with trymatch(). - * - * Revision 3.2 82/12/24 12:08:26 wft - * added missing #endif. - * - * Revision 3.1 82/12/04 13:22:41 wft - * Initial revision. - * - */ - -#include "rcsbase.h" - -libId(keepId, "$FreeBSD$") - -static int badly_terminated P((void)); -static int checknum P((char const*)); -static int get0val P((int,RILE*,struct buf*,int)); -static int getval P((RILE*,struct buf*,int)); -static int keepdate P((RILE*)); -static int keepid P((int,RILE*,struct buf*)); -static int keeprev P((RILE*)); - -int prevkeys; -struct buf prevauthor, prevdate, prevname, prevrev, prevstate; - - int -getoldkeys(fp) - register RILE *fp; -/* Function: Tries to read keyword values for author, date, - * revision number, and state out of the file fp. - * If fp is null, workname is opened and closed instead of using fp. - * The results are placed into - * prevauthor, prevdate, prevname, prevrev, prevstate. - * Aborts immediately if it finds an error and returns false. - * If it returns true, it doesn't mean that any of the - * values were found; instead, check to see whether the corresponding arrays - * contain the empty string. - */ -{ - register int c; - char keyword[keylength+1]; - register char * tp; - int needs_closing; - int prevname_found; - - if (prevkeys) - return true; - - needs_closing = false; - if (!fp) { - if (!(fp = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) { - eerror(workname); - return false; - } - needs_closing = true; - } - - /* initialize to empty */ - bufscpy(&prevauthor, ""); - bufscpy(&prevdate, ""); - bufscpy(&prevname, ""); prevname_found = 0; - bufscpy(&prevrev, ""); - bufscpy(&prevstate, ""); - - c = '\0'; /* anything but KDELIM */ - for (;;) { - if ( c==KDELIM) { - do { - /* try to get keyword */ - tp = keyword; - for (;;) { - Igeteof_(fp, c, goto ok;) - switch (c) { - default: - if (keyword+keylength <= tp) - break; - *tp++ = c; - continue; - - case '\n': case KDELIM: case VDELIM: - break; - } - break; - } - } while (c==KDELIM); - if (c!=VDELIM) continue; - *tp = c; - Igeteof_(fp, c, break;) - switch (c) { - case ' ': case '\t': break; - default: continue; - } - - switch (trymatch(keyword)) { - case Author: - if (!keepid(0, fp, &prevauthor)) - return false; - c = 0; - break; - case Date: - if (!(c = keepdate(fp))) - return false; - break; - case Header: - case Id: - case LocalId: - if (!( - getval(fp, (struct buf*)0, false) && - keeprev(fp) && - (c = keepdate(fp)) && - keepid(c, fp, &prevauthor) && - keepid(0, fp, &prevstate) - )) - return false; - /* Skip either ``who'' (new form) or ``Locker: who'' (old). */ - if (getval(fp, (struct buf*)0, true) && - getval(fp, (struct buf*)0, true)) - c = 0; - else if (nerror) - return false; - else - c = KDELIM; - break; - case Locker: - (void) getval(fp, (struct buf*)0, false); - c = 0; - break; - case Log: - case RCSfile: - case Source: - if (!getval(fp, (struct buf*)0, false)) - return false; - c = 0; - break; - case Name: - if (getval(fp, &prevname, false)) { - if (*prevname.string) - checkssym(prevname.string); - prevname_found = 1; - } - c = 0; - break; - case Revision: - if (!keeprev(fp)) - return false; - c = 0; - break; - case State: - if (!keepid(0, fp, &prevstate)) - return false; - c = 0; - break; - default: - continue; - } - if (!c) - Igeteof_(fp, c, c=0;) - if (c != KDELIM) { - workerror("closing %c missing on keyword", KDELIM); - return false; - } - if (prevname_found && - *prevauthor.string && *prevdate.string && - *prevrev.string && *prevstate.string - ) - break; - } - Igeteof_(fp, c, break;) - } - - ok: - if (needs_closing) - Ifclose(fp); - else - Irewind(fp); - prevkeys = true; - return true; -} - - static int -badly_terminated() -{ - workerror("badly terminated keyword value"); - return false; -} - - static int -getval(fp, target, optional) - register RILE *fp; - struct buf *target; - int optional; -/* Reads a keyword value from FP into TARGET. - * Returns true if one is found, false otherwise. - * Does not modify target if it is 0. - * Do not report an error if OPTIONAL is set and KDELIM is found instead. - */ -{ - int c; - Igeteof_(fp, c, return badly_terminated();) - return get0val(c, fp, target, optional); -} - - static int -get0val(c, fp, target, optional) - register int c; - register RILE *fp; - struct buf *target; - int optional; -/* Reads a keyword value from C+FP into TARGET, perhaps OPTIONALly. - * Same as getval, except C is the lookahead character. - */ -{ register char * tp; - char const *tlim; - register int got1; - - if (target) { - bufalloc(target, 1); - tp = target->string; - tlim = tp + target->size; - } else - tlim = tp = 0; - got1 = false; - for (;;) { - switch (c) { - default: - got1 = true; - if (tp) { - *tp++ = c; - if (tlim <= tp) - tp = bufenlarge(target, &tlim); - } - break; - - case ' ': - case '\t': - if (tp) { - *tp = 0; -# ifdef KEEPTEST - VOID printf("getval: %s\n", target); -# endif - } - return got1; - - case KDELIM: - if (!got1 && optional) - return false; - /* fall into */ - case '\n': - case 0: - return badly_terminated(); - } - Igeteof_(fp, c, return badly_terminated();) - } -} - - - static int -keepdate(fp) - RILE *fp; -/* Function: reads a date prevdate; checks format - * Return 0 on error, lookahead character otherwise. - */ -{ - struct buf prevday, prevtime; - register int c; - - c = 0; - bufautobegin(&prevday); - if (getval(fp,&prevday,false)) { - bufautobegin(&prevtime); - if (getval(fp,&prevtime,false)) { - Igeteof_(fp, c, c=0;) - if (c) { - register char const *d = prevday.string, *t = prevtime.string; - bufalloc(&prevdate, strlen(d) + strlen(t) + 9); - VOID sprintf(prevdate.string, "%s%s %s%s", - /* Parse dates put out by old versions of RCS. */ - isdigit(d[0]) && isdigit(d[1]) && !isdigit(d[2]) - ? "19" : "", - d, t, - strchr(t,'-') || strchr(t,'+') ? "" : "+0000" - ); - } - } - bufautoend(&prevtime); - } - bufautoend(&prevday); - return c; -} - - static int -keepid(c, fp, b) - int c; - RILE *fp; - struct buf *b; -/* Get previous identifier from C+FP into B. */ -{ - if (!c) - Igeteof_(fp, c, return false;) - if (!get0val(c, fp, b, false)) - return false; - checksid(b->string); - return !nerror; -} - - static int -keeprev(fp) - RILE *fp; -/* Get previous revision from FP into prevrev. */ -{ - return getval(fp,&prevrev,false) && checknum(prevrev.string); -} - - - static int -checknum(s) - char const *s; -{ - register char const *sp; - register int dotcount = 0; - for (sp=s; ; sp++) { - switch (*sp) { - case 0: - if (dotcount & 1) - return true; - else - break; - - case '.': - dotcount++; - continue; - - default: - if (isdigit(*sp)) - continue; - break; - } - break; - } - workerror("%s is not a revision number", s); - return false; -} - - - -#ifdef KEEPTEST - -/* Print the keyword values found. */ - -char const cmdid[] ="keeptest"; - - int -main(argc, argv) -int argc; char *argv[]; -{ - while (*(++argv)) { - workname = *argv; - getoldkeys((RILE*)0); - VOID printf("%s: revision: %s, date: %s, author: %s, name: %s, state: %s\n", - *argv, prevrev.string, prevdate.string, prevauthor.string, prevname.string, prevstate.string); - } - exitmain(EXIT_SUCCESS); -} -#endif Index: gnu/usr.bin/rcs/lib/rcskeys.c =================================================================== --- gnu/usr.bin/rcs/lib/rcskeys.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcskeys.c (working copy) @@ -1,186 +0,0 @@ -/* RCS keyword table and match operation */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.4 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.3 1993/11/03 17:42:27 eggert - * Add Name keyword. - * - * Revision 5.2 1991/08/19 03:13:55 eggert - * Say `T const' instead of `const T'; it's less confusing for pointer types. - * (This change was made in other source files too.) - * - * Revision 5.1 1991/04/21 11:58:25 eggert - * Don't put , just before } in initializer. - * - * Revision 5.0 1990/08/22 08:12:54 eggert - * Add -k. Ansify and Posixate. - * - * Revision 4.3 89/05/01 15:13:02 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.2 87/10/18 10:36:33 narten - * Updating version numbers. Changes relative to 1.1 actuallyt - * relative to 4.1 - * - * Revision 1.2 87/09/24 14:00:10 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 4.1 83/05/04 10:06:53 wft - * Initial revision. - * - */ - - -#include "rcsbase.h" - -libId(keysId, "$FreeBSD$") - - -char const *Keyword[] = { - /* This must be in the same order as rcsbase.h's enum markers type. */ - 0, - AUTHOR, DATE, HEADER, IDH, - LOCKER, LOG, NAME, RCSFILE, REVISION, SOURCE, STATE, CVSHEADER, - NULL -}; - -/* Expand all keywords by default */ -static int ExpandKeyword[] = { - false, - true, true, true, true, - true, true, true, true, true, true, true, true, - true -}; -enum markers LocalIdMode = Id; - - enum markers -trymatch(string) - char const *string; -/* function: Checks whether string starts with a keyword followed - * by a KDELIM or a VDELIM. - * If successful, returns the appropriate marker, otherwise Nomatch. - */ -{ - register int j; - register char const *p, *s; - for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) { - if (!ExpandKeyword[j]) - continue; - /* try next keyword */ - p = Keyword[j]; - if (p == NULL) - continue; - s = string; - while (*p++ == *s++) { - if (!*p) - switch (*s) { - case KDELIM: - case VDELIM: - return (enum markers)j; - default: - return Nomatch; - } - } - } - return(Nomatch); -} - - void -setIncExc(arg) - char const *arg; -/* Sets up the ExpandKeyword table according to command-line flags */ -{ - char *key; - char *copy, *next; - int include = 0, j; - - copy = strdup(arg); - next = copy; - switch (*next++) { - case 'e': - include = false; - break; - case 'i': - include = true; - break; - default: - free(copy); - return; - } - if (include) - for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) - ExpandKeyword[j] = false; - key = strtok(next, ","); - while (key) { - for (j = sizeof(Keyword)/sizeof(*Keyword); (--j); ) { - if (Keyword[j] == NULL) - continue; - if (!strcmp(key, Keyword[j])) - ExpandKeyword[j] = include; - } - key = strtok(NULL, ","); - } - free(copy); - return; -} - - void -setRCSLocalId(string) - char const *string; -/* function: sets local RCS id and RCSLOCALID envariable */ -{ - static char local_id[keylength+1]; - char *copy, *next, *key; - int j; - - copy = strdup(string); - next = copy; - key = strtok(next, "="); - if (strlen(key) > keylength) - faterror("LocalId is too long"); - VOID strcpy(local_id, key); - Keyword[LocalId] = local_id; - - /* options? */ - while (key = strtok(NULL, ",")) { - if (!strcmp(key, Keyword[Id])) - LocalIdMode=Id; - else if (!strcmp(key, Keyword[Header])) - LocalIdMode=Header; - else if (!strcmp(key, Keyword[CVSHeader])) - LocalIdMode=CVSHeader; - else - error("Unknown LocalId mode"); - } - free(copy); -} Index: gnu/usr.bin/rcs/lib/rcslex.c =================================================================== --- gnu/usr.bin/rcs/lib/rcslex.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcslex.c (working copy) @@ -1,1568 +0,0 @@ -/* lexical analysis of RCS files */ - -/****************************************************************************** - * Lexical Analysis. - * hashtable, Lexinit, nextlex, getlex, getkey, - * getid, getnum, readstring, printstring, savestring, - * checkid, fatserror, error, faterror, warn, diagnose - * Testprogram: define LEXDB - ****************************************************************************** - */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - - - -/* - * Revision 5.19 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.18 1995/06/01 16:23:43 eggert - * (map_fd_deallocate,mmap_deallocate,read_deallocate,nothing_to_deallocate): - * New functions. - * (Iclose): If large_memory and maps_memory, use them to deallocate mapping. - * (fd2RILE): Use map_fd if available. - * If one mapping method fails, try the next instead of giving up; - * if they all fail, fall back on ordinary read. - * Work around bug: root mmap over NFS succeeds, but accessing dumps core. - * Use MAP_FAILED macro for mmap failure, and `char *' instead of caddr_t. - * (advise_access): Use madvise only if this instance used mmap. - * (Iopen): Use fdSafer to get safer file descriptor. - * (aflush): Moved here from rcsedit.c. - * - * Revision 5.17 1994/03/20 04:52:58 eggert - * Don't worry if madvise fails. Add Orewind. Remove lint. - * - * Revision 5.16 1993/11/09 17:55:29 eggert - * Fix `label: }' typo. - * - * Revision 5.15 1993/11/03 17:42:27 eggert - * Improve quality of diagnostics by putting file names in them more often. - * Don't discard ignored phrases. - * - * Revision 5.14 1992/07/28 16:12:44 eggert - * Identifiers may now start with a digit and (unless they are symbolic names) - * may contain `.'. Avoid `unsigned'. Statement macro names now end in _. - * - * Revision 5.13 1992/02/17 23:02:27 eggert - * Work around NFS mmap SIGBUS problem. - * - * Revision 5.12 1992/01/06 02:42:34 eggert - * Use OPEN_O_BINARY if mode contains 'b'. - * - * Revision 5.11 1991/11/03 03:30:44 eggert - * Fix porting bug to ancient hosts lacking vfprintf. - * - * Revision 5.10 1991/10/07 17:32:46 eggert - * Support piece tables even if !has_mmap. - * - * Revision 5.9 1991/09/24 00:28:42 eggert - * Don't export errsay(). - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Add eoflex(), mmap support. Tune. - * - * Revision 5.7 1991/04/21 11:58:26 eggert - * Add MS-DOS support. - * - * Revision 5.6 1991/02/25 07:12:42 eggert - * Work around fputs bug. strsave -> str_save (DG/UX name clash) - * - * Revision 5.5 1990/12/04 05:18:47 eggert - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.4 1990/11/19 20:05:28 hammer - * no longer gives warning about unknown keywords if -q is specified - * - * Revision 5.3 1990/11/01 05:03:48 eggert - * When ignoring unknown phrases, copy them to the output RCS file. - * - * Revision 5.2 1990/09/04 08:02:27 eggert - * Count RCS lines better. - * - * Revision 5.1 1990/08/29 07:14:03 eggert - * Work around buggy compilers with defective argument promotion. - * - * Revision 5.0 1990/08/22 08:12:55 eggert - * Remove compile-time limits; use malloc instead. - * Report errno-related errors with perror(). - * Ansify and Posixate. Add support for ISO 8859. - * Use better hash function. - * - * Revision 4.6 89/05/01 15:13:07 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.5 88/08/28 15:01:12 eggert - * Don't loop when writing error messages to a full filesystem. - * Flush stderr/stdout when mixing output. - * Yield exit status compatible with diff(1). - * Shrink stdio code size; allow cc -R; remove lint. - * - * Revision 4.4 87/12/18 11:44:47 narten - * fixed to use "varargs" in "fprintf"; this is required if it is to - * work on a SPARC machine such as a Sun-4 - * - * Revision 4.3 87/10/18 10:37:18 narten - * Updating version numbers. Changes relative to 1.1 actually relative - * to version 4.1 - * - * Revision 1.3 87/09/24 14:00:17 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:33 jenkins - * Port to suns - * - * Revision 4.1 83/03/25 18:12:51 wft - * Only changed $Header to $Id. - * - * Revision 3.3 82/12/10 16:22:37 wft - * Improved error messages, changed exit status on error to 1. - * - * Revision 3.2 82/11/28 21:27:10 wft - * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h. - * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations - * properly in case there is an IO-error (e.g., file system full). - * - * Revision 3.1 82/10/11 19:43:56 wft - * removed unused label out:; - * made sure all calls to getc() return into an integer, not a char. - */ - - -/* -#define LEXDB -*/ -/* version LEXDB is for testing the lexical analyzer. The testprogram - * reads a stream of lexemes, enters the revision numbers into the - * hashtable, and prints the recognized tokens. Keywords are recognized - * as identifiers. - */ - - - -#include "rcsbase.h" - -libId(lexId, "$FreeBSD$") - -static char *checkidentifier P((char*,int,int)); -static void errsay P((char const*)); -static void fatsay P((char const*)); -static void lookup P((char const*)); -static void startsay P((const char*,const char*)); -static void warnsay P((char const*)); - -static struct hshentry *nexthsh; /*pointer to next hash entry, set by lookup*/ - -enum tokens nexttok; /*next token, set by nextlex */ - -int hshenter; /*if true, next suitable lexeme will be entered */ - /*into the symbol table. Handle with care. */ -int nextc; /*next input character, initialized by Lexinit */ - -long rcsline; /*current line-number of input */ -int nerror; /*counter for errors */ -int quietflag; /*indicates quiet mode */ -RILE * finptr; /*input file descriptor */ - -FILE * frewrite; /*file descriptor for echoing input */ - -FILE * foutptr; /* copy of frewrite, but 0 to suppress echo */ - -static struct buf tokbuf; /* token buffer */ - -char const * NextString; /* next token */ - -/* - * Our hash algorithm is h[0] = 0, h[i+1] = 4*h[i] + c, - * so hshsize should be odd. - * See B J McKenzie, R Harries & T Bell, Selecting a hashing algorithm, - * Software--practice & experience 20, 2 (Feb 1990), 209-224. - */ -#ifndef hshsize -# define hshsize 511 -#endif - -static struct hshentry *hshtab[hshsize]; /*hashtable */ - -static int ignored_phrases; /* have we ignored phrases in this RCS file? */ - - void -warnignore() -{ - if (!ignored_phrases) { - ignored_phrases = true; - rcswarn("Unknown phrases like `%s ...;' are present.", NextString); - } -} - - - - static void -lookup(str) - char const *str; -/* Function: Looks up the character string pointed to by str in the - * hashtable. If the string is not present, a new entry for it is created. - * In any case, the address of the corresponding hashtable entry is placed - * into nexthsh. - */ -{ - register unsigned ihash; /* index into hashtable */ - register char const *sp; - register struct hshentry *n, **p; - - /* calculate hash code */ - sp = str; - ihash = 0; - while (*sp) - ihash = (ihash<<2) + *sp++; - ihash %= hshsize; - - for (p = &hshtab[ihash]; ; p = &n->nexthsh) - if (!(n = *p)) { - /* empty slot found */ - *p = n = ftalloc(struct hshentry); - n->num = fstr_save(str); - n->nexthsh = 0; -# ifdef LEXDB - VOID printf("\nEntered: %s at %u ", str, ihash); -# endif - break; - } else if (strcmp(str, n->num) == 0) - /* match found */ - break; - nexthsh = n; - NextString = n->num; -} - - - - - - - void -Lexinit() -/* Function: Initialization of lexical analyzer: - * initializes the hashtable, - * initializes nextc, nexttok if finptr != 0 - */ -{ register int c; - - for (c = hshsize; 0 <= --c; ) { - hshtab[c] = 0; - } - - nerror = 0; - if (finptr) { - foutptr = 0; - hshenter = true; - ignored_phrases = false; - rcsline = 1; - bufrealloc(&tokbuf, 2); - Iget_(finptr, nextc) - nextlex(); /*initial token*/ - } -} - - - - - - - - void -nextlex() - -/* Function: Reads the next token and sets nexttok to the next token code. - * Only if hshenter is set, a revision number is entered into the - * hashtable and a pointer to it is placed into nexthsh. - * This is useful for avoiding that dates are placed into the hashtable. - * For ID's and NUM's, NextString is set to the character string. - * Assumption: nextc contains the next character. - */ -{ register c; - declarecache; - register FILE *frew; - register char * sp; - char const *limit; - register enum tokens d; - register RILE *fin; - - fin=finptr; frew=foutptr; - setupcache(fin); cache(fin); - c = nextc; - - for (;;) { switch ((d = ctab[c])) { - - default: - fatserror("unknown character `%c'", c); - /*NOTREACHED*/ - - case NEWLN: - ++rcsline; -# ifdef LEXDB - afputc('\n',stdout); -# endif - /* Note: falls into next case */ - - case SPACE: - GETC_(frew, c) - continue; - - case IDCHAR: - case LETTER: - case Letter: - d = ID; - /* fall into */ - case DIGIT: - case PERIOD: - sp = tokbuf.string; - limit = sp + tokbuf.size; - *sp++ = c; - for (;;) { - GETC_(frew, c) - switch (ctab[c]) { - case IDCHAR: - case LETTER: - case Letter: - d = ID; - /* fall into */ - case DIGIT: - case PERIOD: - *sp++ = c; - if (limit <= sp) - sp = bufenlarge(&tokbuf, &limit); - continue; - - default: - break; - } - break; - } - *sp = 0; - if (d == DIGIT || d == PERIOD) { - d = NUM; - if (hshenter) { - lookup(tokbuf.string); - break; - } - } - NextString = fstr_save(tokbuf.string); - break; - - case SBEGIN: /* long string */ - d = STRING; - /* note: only the initial SBEGIN has been read*/ - /* read the string, and reset nextc afterwards*/ - break; - - case COLON: - case SEMI: - GETC_(frew, c) - break; - } break; } - nextc = c; - nexttok = d; - uncache(fin); -} - - int -eoflex() -/* - * Yield true if we look ahead to the end of the input, false otherwise. - * nextc becomes undefined at end of file. - */ -{ - register int c; - declarecache; - register FILE *fout; - register RILE *fin; - - c = nextc; - fin = finptr; - fout = foutptr; - setupcache(fin); cache(fin); - - for (;;) { - switch (ctab[c]) { - default: - nextc = c; - uncache(fin); - return false; - - case NEWLN: - ++rcsline; - /* fall into */ - case SPACE: - cachegeteof_(c, {uncache(fin);return true;}) - break; - } - if (fout) - aputc_(c, fout) - } -} - - -int getlex(token) -enum tokens token; -/* Function: Checks if nexttok is the same as token. If so, - * advances the input by calling nextlex and returns true. - * otherwise returns false. - * Doesn't work for strings and keywords; loses the character string for ids. - */ -{ - if (nexttok==token) { - nextlex(); - return(true); - } else return(false); -} - - int -getkeyopt(key) - char const *key; -/* Function: If the current token is a keyword identical to key, - * advances the input by calling nextlex and returns true; - * otherwise returns false. - */ -{ - if (nexttok==ID && strcmp(key,NextString) == 0) { - /* match found */ - ffree1(NextString); - nextlex(); - return(true); - } - return(false); -} - - void -getkey(key) - char const *key; -/* Check that the current input token is a keyword identical to key, - * and advance the input by calling nextlex. - */ -{ - if (!getkeyopt(key)) - fatserror("missing '%s' keyword", key); -} - - void -getkeystring(key) - char const *key; -/* Check that the current input token is a keyword identical to key, - * and advance the input by calling nextlex; then look ahead for a string. - */ -{ - getkey(key); - if (nexttok != STRING) - fatserror("missing string after '%s' keyword", key); -} - - - char const * -getid() -/* Function: Checks if nexttok is an identifier. If so, - * advances the input by calling nextlex and returns a pointer - * to the identifier; otherwise returns 0. - * Treats keywords as identifiers. - */ -{ - register char const *name; - if (nexttok==ID) { - name = NextString; - nextlex(); - return name; - } else - return 0; -} - - -struct hshentry * getnum() -/* Function: Checks if nexttok is a number. If so, - * advances the input by calling nextlex and returns a pointer - * to the hashtable entry. Otherwise returns 0. - * Doesn't work if hshenter is false. - */ -{ - register struct hshentry * num; - if (nexttok==NUM) { - num=nexthsh; - nextlex(); - return num; - } else - return 0; -} - - struct cbuf -getphrases(key) - char const *key; -/* -* Get a series of phrases that do not start with KEY. Yield resulting buffer. -* Stop when the next phrase starts with a token that is not an identifier, -* or is KEY. Copy input to foutptr if it is set. Unlike ignorephrases(), -* this routine assumes nextlex() has already been invoked before we start. -*/ -{ - declarecache; - register int c; - register char const *kn; - struct cbuf r; - register RILE *fin; - register FILE *frew; -# if large_memory -# define savech_(c) ; -# else - register char *p; - char const *limit; - struct buf b; -# define savech_(c) {if (limit<=p)p=bufenlarge(&b,&limit); *p++ =(c);} -# endif - - if (nexttok!=ID || strcmp(NextString,key) == 0) - clear_buf(&r); - else { - warnignore(); - fin = finptr; - frew = foutptr; - setupcache(fin); cache(fin); -# if large_memory - r.string = (char const*)cacheptr() - strlen(NextString) - 1; -# else - bufautobegin(&b); - bufscpy(&b, NextString); - p = b.string + strlen(b.string); - limit = b.string + b.size; -# endif - ffree1(NextString); - c = nextc; - for (;;) { - for (;;) { - savech_(c) - switch (ctab[c]) { - default: - fatserror("unknown character `%c'", c); - /*NOTREACHED*/ - case NEWLN: - ++rcsline; - /* fall into */ - case COLON: case DIGIT: case LETTER: case Letter: - case PERIOD: case SPACE: - GETC_(frew, c) - continue; - case SBEGIN: /* long string */ - for (;;) { - for (;;) { - GETC_(frew, c) - savech_(c) - switch (c) { - case '\n': - ++rcsline; - /* fall into */ - default: - continue; - - case SDELIM: - break; - } - break; - } - GETC_(frew, c) - if (c != SDELIM) - break; - savech_(c) - } - continue; - case SEMI: - cacheget_(c) - if (ctab[c] == NEWLN) { - if (frew) - aputc_(c, frew) - ++rcsline; - savech_(c) - cacheget_(c) - } -# if large_memory - r.size = (char const*)cacheptr() - 1 - r.string; -# endif - for (;;) { - switch (ctab[c]) { - case NEWLN: - ++rcsline; - /* fall into */ - case SPACE: - cacheget_(c) - continue; - - default: break; - } - break; - } - if (frew) - aputc_(c, frew) - break; - } - break; - } - if (ctab[c] == Letter) { - for (kn = key; c && *kn==c; kn++) - GETC_(frew, c) - if (!*kn) - switch (ctab[c]) { - case DIGIT: case LETTER: case Letter: - case IDCHAR: case PERIOD: - break; - default: - nextc = c; - NextString = fstr_save(key); - nexttok = ID; - uncache(fin); - goto returnit; - } -# if !large_memory - { - register char const *ki; - for (ki=key; kistring; limit = tp + target->size; - for (;;) { - GETC_(frew, c) - switch (c) { - case '\n': - ++rcsline; - break; - case SDELIM: - GETC_(frew, c) - if (c != SDELIM) { - /* end of string */ - nextc=c; - r.string = target->string; - r.size = tp - r.string; - uncache(fin); - return r; - } - break; - } - if (tp == limit) - tp = bufenlarge(target, &limit); - *tp++ = c; - } -} - - - static char * -checkidentifier(id, delimiter, dotok) - register char *id; - int delimiter; - register int dotok; -/* Function: check whether the string starting at id is an */ -/* identifier and return a pointer to the delimiter*/ -/* after the identifier. White space, delim and 0 */ -/* are legal delimiters. Aborts the program if not*/ -/* a legal identifier. Useful for checking commands*/ -/* If !delim, the only delimiter is 0. */ -/* Allow '.' in identifier only if DOTOK is set. */ -{ - register char *temp; - register char c; - register char delim = delimiter; - int isid = false; - - temp = id; - for (;; id++) { - switch (ctab[(unsigned char)(c = *id)]) { - case IDCHAR: - case LETTER: - case Letter: - isid = true; - continue; - - case DIGIT: - continue; - - case PERIOD: - if (dotok) - continue; - break; - - default: - break; - } - break; - } - if ( ! isid - || (c && (!delim || (c!=delim && c!=' ' && c!='\t' && c!='\n'))) - ) { - /* append \0 to end of id before error message */ - while ((c = *id) && c!=' ' && c!='\t' && c!='\n' && c!=delim) - id++; - *id = '\0'; - faterror("invalid %s `%s'", - dotok ? "identifier" : "symbol", temp - ); - } - return id; -} - - char * -checkid(id, delimiter) - char *id; - int delimiter; -{ - return checkidentifier(id, delimiter, true); -} - - char * -checksym(sym, delimiter) - char *sym; - int delimiter; -{ - return checkidentifier(sym, delimiter, false); -} - - void -checksid(id) - char *id; -/* Check whether the string ID is an identifier. */ -{ - VOID checkid(id, 0); -} - - void -checkssym(sym) - char *sym; -{ - VOID checksym(sym, 0); -} - - -#if !large_memory -# define Iclose(f) fclose(f) -#else -# if !maps_memory - static int Iclose P((RILE *)); - static int - Iclose(f) - register RILE *f; - { - tfree(f->base); - f->base = 0; - return fclose(f->stream); - } -# else - static int Iclose P((RILE *)); - static int - Iclose(f) - register RILE *f; - { - (* f->deallocate) (f); - f->base = 0; - return close(f->fd); - } - -# if has_map_fd - static void map_fd_deallocate P((RILE *)); - static void - map_fd_deallocate(f) - register RILE *f; - { - if (vm_deallocate( - task_self(), - (vm_address_t) f->base, - (vm_size_t) (f->lim - f->base) - ) != KERN_SUCCESS) - efaterror("vm_deallocate"); - } -# endif -# if has_mmap - static void mmap_deallocate P((RILE *)); - static void - mmap_deallocate(f) - register RILE *f; - { - if (munmap((char *) f->base, (size_t) (f->lim - f->base)) != 0) - efaterror("munmap"); - } -# endif - static void read_deallocate P((RILE *)); - static void - read_deallocate(f) - RILE *f; - { - tfree(f->base); - } - - static void nothing_to_deallocate P((RILE *)); - static void - nothing_to_deallocate(f) - RILE *f; - { - } -# endif -#endif - - -#if large_memory && maps_memory - static RILE *fd2_RILE P((int,char const*,struct stat*)); - static RILE * -fd2_RILE(fd, name, status) -#else - static RILE *fd2RILE P((int,char const*,char const*,struct stat*)); - static RILE * -fd2RILE(fd, name, type, status) - char const *type; -#endif - int fd; - char const *name; - register struct stat *status; -{ - struct stat st; - - if (!status) - status = &st; - if (fstat(fd, status) != 0) - efaterror(name); - if (!S_ISREG(status->st_mode)) { - error("`%s' is not a regular file", name); - VOID close(fd); - errno = EINVAL; - return 0; - } else { - -# if !(large_memory && maps_memory) - FILE *stream; - if (!(stream = fdopen(fd, type))) - efaterror(name); -# endif - -# if !large_memory - return stream; -# else -# define RILES 3 - { - static RILE rilebuf[RILES]; - - register RILE *f; - size_t s = status->st_size; - - if (s != status->st_size) - faterror("%s: too large", name); - for (f = rilebuf; f->base; f++) - if (f == rilebuf+RILES) - faterror("too many RILEs"); -# if maps_memory - f->deallocate = nothing_to_deallocate; -# endif - if (!s) { - static unsigned char nothing; - f->base = ¬hing; /* Any nonzero address will do. */ - } else { - f->base = 0; -# if has_map_fd - map_fd( - fd, (vm_offset_t)0, (vm_address_t*) &f->base, - TRUE, (vm_size_t)s - ); - f->deallocate = map_fd_deallocate; -# endif -# if has_mmap - if (!f->base) { - catchmmapints(); - f->base = (unsigned char *) mmap( - (char *)0, s, PROT_READ, MAP_SHARED, - fd, (off_t)0 - ); -# ifndef MAP_FAILED -# define MAP_FAILED (-1) -# endif - if (f->base == (unsigned char *) MAP_FAILED) - f->base = 0; - else { -# if has_NFS && mmap_signal - /* - * On many hosts, the superuser - * can mmap an NFS file it can't read. - * So access the first page now, and print - * a nice message if a bus error occurs. - */ - readAccessFilenameBuffer(name, f->base); -# endif - } - f->deallocate = mmap_deallocate; - } -# endif - if (!f->base) { - f->base = tnalloc(unsigned char, s); -# if maps_memory - { - /* - * We can't map the file into memory for some reason. - * Read it into main memory all at once; this is - * the simplest substitute for memory mapping. - */ - char *bufptr = (char *) f->base; - size_t bufsiz = s; - do { - ssize_t r = read(fd, bufptr, bufsiz); - switch (r) { - case -1: - efaterror(name); - - case 0: - /* The file must have shrunk! */ - status->st_size = s -= bufsiz; - bufsiz = 0; - break; - - default: - bufptr += r; - bufsiz -= r; - break; - } - } while (bufsiz); - if (lseek(fd, (off_t)0, SEEK_SET) == -1) - efaterror(name); - f->deallocate = read_deallocate; - } -# endif - } - } - f->ptr = f->base; - f->lim = f->base + s; - f->fd = fd; -# if !maps_memory - f->readlim = f->base; - f->stream = stream; -# endif - if_advise_access(s, f, MADV_SEQUENTIAL); - return f; - } -# endif - } -} - -#if !maps_memory && large_memory - int -Igetmore(f) - register RILE *f; -{ - register fread_type r; - register size_t s = f->lim - f->readlim; - - if (BUFSIZ < s) - s = BUFSIZ; - if (!(r = Fread(f->readlim, sizeof(*f->readlim), s, f->stream))) { - testIerror(f->stream); - f->lim = f->readlim; /* The file might have shrunk! */ - return 0; - } - f->readlim += r; - return 1; -} -#endif - -#if has_madvise && has_mmap && large_memory - void -advise_access(f, advice) - register RILE *f; - int advice; -{ - if (f->deallocate == mmap_deallocate) - VOID madvise((char *)f->base, (size_t)(f->lim - f->base), advice); - /* Don't worry if madvise fails; it's only advisory. */ -} -#endif - - RILE * -#if large_memory && maps_memory -I_open(name, status) -#else -Iopen(name, type, status) - char const *type; -#endif - char const *name; - struct stat *status; -/* Open NAME for reading, yield its descriptor, and set *STATUS. */ -{ - int fd = fdSafer(open(name, O_RDONLY -# if OPEN_O_BINARY - | (strchr(type,'b') ? OPEN_O_BINARY : 0) -# endif - )); - - if (fd < 0) - return 0; -# if large_memory && maps_memory - return fd2_RILE(fd, name, status); -# else - return fd2RILE(fd, name, type, status); -# endif -} - - -static int Oerrloop; - - void -Oerror() -{ - if (Oerrloop) - exiterr(); - Oerrloop = true; - efaterror("output error"); -} - -void Ieof() { fatserror("unexpected end of file"); } -void Ierror() { efaterror("input error"); } -void testIerror(f) FILE *f; { if (ferror(f)) Ierror(); } -void testOerror(o) FILE *o; { if (ferror(o)) Oerror(); } - -void Ifclose(f) RILE *f; { if (f && Iclose(f)!=0) Ierror(); } -void Ofclose(f) FILE *f; { if (f && fclose(f)!=0) Oerror(); } -void Izclose(p) RILE **p; { Ifclose(*p); *p = 0; } -void Ozclose(p) FILE **p; { Ofclose(*p); *p = 0; } - -#if !large_memory - void -testIeof(f) - FILE *f; -{ - testIerror(f); - if (feof(f)) - Ieof(); -} -void Irewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Ierror(); } -#endif - -void Orewind(f) FILE *f; { if (fseek(f,0L,SEEK_SET) != 0) Oerror(); } - -void aflush(f) FILE *f; { if (fflush(f) != 0) Oerror(); } -void eflush() { if (fflush(stderr)!=0 && !Oerrloop) Oerror(); } -void oflush() -{ - if (fflush(workstdout ? workstdout : stdout) != 0 && !Oerrloop) - Oerror(); -} - - void -fatcleanup(already_newline) - int already_newline; -{ - VOID fprintf(stderr, already_newline+"\n%s aborted\n", cmdid); - exiterr(); -} - - static void -startsay(s, t) - const char *s, *t; -{ - oflush(); - if (s) - aprintf(stderr, "%s: %s: %s", cmdid, s, t); - else - aprintf(stderr, "%s: %s", cmdid, t); -} - - static void -fatsay(s) - char const *s; -{ - startsay(s, ""); -} - - static void -errsay(s) - char const *s; -{ - fatsay(s); - nerror++; -} - - static void -warnsay(s) - char const *s; -{ - startsay(s, "warning: "); -} - -void eerror(s) char const *s; { enerror(errno,s); } - - void -enerror(e,s) - int e; - char const *s; -{ - errsay((char const*)0); - errno = e; - perror(s); - eflush(); -} - -void efaterror(s) char const *s; { enfaterror(errno,s); } - - void -enfaterror(e,s) - int e; - char const *s; -{ - fatsay((char const*)0); - errno = e; - perror(s); - fatcleanup(true); -} - -#if has_prototypes - void -error(char const *format,...) -#else - /*VARARGS1*/ void error(format, va_alist) char const *format; va_dcl -#endif -/* non-fatal error */ -{ - va_list args; - errsay((char const*)0); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - afputc('\n',stderr); - eflush(); -} - -#if has_prototypes - void -rcserror(char const *format,...) -#else - /*VARARGS1*/ void rcserror(format, va_alist) char const *format; va_dcl -#endif -/* non-fatal RCS file error */ -{ - va_list args; - errsay(RCSname); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - afputc('\n',stderr); - eflush(); -} - -#if has_prototypes - void -workerror(char const *format,...) -#else - /*VARARGS1*/ void workerror(format, va_alist) char const *format; va_dcl -#endif -/* non-fatal working file error */ -{ - va_list args; - errsay(workname); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - afputc('\n',stderr); - eflush(); -} - -#if has_prototypes - void -fatserror(char const *format,...) -#else - /*VARARGS1*/ void - fatserror(format, va_alist) char const *format; va_dcl -#endif -/* fatal RCS file syntax error */ -{ - va_list args; - oflush(); - VOID fprintf(stderr, "%s: %s:%ld: ", cmdid, RCSname, rcsline); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - fatcleanup(false); -} - -#if has_prototypes - void -faterror(char const *format,...) -#else - /*VARARGS1*/ void faterror(format, va_alist) - char const *format; va_dcl -#endif -/* fatal error, terminates program after cleanup */ -{ - va_list args; - fatsay((char const*)0); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - fatcleanup(false); -} - -#if has_prototypes - void -rcsfaterror(char const *format,...) -#else - /*VARARGS1*/ void rcsfaterror(format, va_alist) - char const *format; va_dcl -#endif -/* fatal RCS file error, terminates program after cleanup */ -{ - va_list args; - fatsay(RCSname); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - fatcleanup(false); -} - -#if has_prototypes - void -warn(char const *format,...) -#else - /*VARARGS1*/ void warn(format, va_alist) char const *format; va_dcl -#endif -/* warning */ -{ - va_list args; - if (!quietflag) { - warnsay((char *)0); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - afputc('\n', stderr); - eflush(); - } -} - -#if has_prototypes - void -rcswarn(char const *format,...) -#else - /*VARARGS1*/ void rcswarn(format, va_alist) char const *format; va_dcl -#endif -/* RCS file warning */ -{ - va_list args; - if (!quietflag) { - warnsay(RCSname); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - afputc('\n', stderr); - eflush(); - } -} - -#if has_prototypes - void -workwarn(char const *format,...) -#else - /*VARARGS1*/ void workwarn(format, va_alist) char const *format; va_dcl -#endif -/* working file warning */ -{ - va_list args; - if (!quietflag) { - warnsay(workname); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - afputc('\n', stderr); - eflush(); - } -} - - void -redefined(c) - int c; -{ - warn("redefinition of -%c option", c); -} - -#if has_prototypes - void -diagnose(char const *format,...) -#else - /*VARARGS1*/ void diagnose(format, va_alist) char const *format; va_dcl -#endif -/* prints a diagnostic message */ -/* Unlike the other routines, it does not append a newline. */ -/* This lets some callers suppress the newline, and is faster */ -/* in implementations that flush stderr just at the end of each printf. */ -{ - va_list args; - if (!quietflag) { - oflush(); - vararg_start(args, format); - fvfprintf(stderr, format, args); - va_end(args); - eflush(); - } -} - - - - void -afputc(c, f) -/* afputc(c,f); acts like aputc_(c,f) but is smaller and slower. */ - int c; - register FILE *f; -{ - aputc_(c,f) -} - - - void -aputs(s, iop) - char const *s; - FILE *iop; -/* Function: Put string s on file iop, abort on error. - */ -{ -#if has_fputs - if (fputs(s, iop) < 0) - Oerror(); -#else - awrite(s, strlen(s), iop); -#endif -} - - - - void -#if has_prototypes -fvfprintf(FILE *stream, char const *format, va_list args) -#else - fvfprintf(stream,format,args) FILE *stream; char *format; va_list args; -#endif -/* like vfprintf, except abort program on error */ -{ -#if has_vfprintf - if (vfprintf(stream, format, args) < 0) - Oerror(); -#else -# if has__doprintf - _doprintf(stream, format, args); -# else -# if has__doprnt - _doprnt(format, args, stream); -# else - int *a = (int *)args; - VOID fprintf(stream, format, - a[0], a[1], a[2], a[3], a[4], - a[5], a[6], a[7], a[8], a[9] - ); -# endif -# endif - if (ferror(stream)) - Oerror(); -#endif -} - -#if has_prototypes - void -aprintf(FILE *iop, char const *fmt, ...) -#else - /*VARARGS2*/ void -aprintf(iop, fmt, va_alist) -FILE *iop; -char const *fmt; -va_dcl -#endif -/* Function: formatted output. Same as fprintf in stdio, - * but aborts program on error - */ -{ - va_list ap; - vararg_start(ap, fmt); - fvfprintf(iop, fmt, ap); - va_end(ap); -} - - - -#ifdef LEXDB -/* test program reading a stream of lexemes and printing the tokens. - */ - - - - int -main(argc,argv) -int argc; char * argv[]; -{ - cmdid="lextest"; - if (argc<2) { - aputs("No input file\n",stderr); - exitmain(EXIT_FAILURE); - } - if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) { - faterror("can't open input file %s",argv[1]); - } - Lexinit(); - while (!eoflex()) { - switch (nexttok) { - - case ID: - VOID printf("ID: %s",NextString); - break; - - case NUM: - if (hshenter) - VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab); - else - VOID printf("NUM, unentered: %s",NextString); - hshenter = !hshenter; /*alternate between dates and numbers*/ - break; - - case COLON: - VOID printf("COLON"); break; - - case SEMI: - VOID printf("SEMI"); break; - - case STRING: - readstring(); - VOID printf("STRING"); break; - - case UNKN: - VOID printf("UNKN"); break; - - default: - VOID printf("DEFAULT"); break; - } - VOID printf(" | "); - nextlex(); - } - exitmain(EXIT_SUCCESS); -} - -void exiterr() { _exit(EXIT_FAILURE); } - - -#endif Index: gnu/usr.bin/rcs/lib/rcsmap.c =================================================================== --- gnu/usr.bin/rcs/lib/rcsmap.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsmap.c (working copy) @@ -1,69 +0,0 @@ -/* RCS map of character types */ - -/* Copyright (C) 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1995 by Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#include "rcsbase.h" - -libId(mapId, "$FreeBSD$") - -/* map of character types */ -/* ISO 8859/1 (Latin-1) */ -enum tokens const ctab[] = { - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - SPACE, SPACE, NEWLN, SPACE, SPACE, SPACE, UNKN, UNKN, - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - SPACE, IDCHAR, IDCHAR, IDCHAR, DELIM, IDCHAR, IDCHAR, IDCHAR, - IDCHAR, IDCHAR, IDCHAR, IDCHAR, DELIM, IDCHAR, PERIOD, IDCHAR, - DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, - DIGIT, DIGIT, COLON, SEMI, IDCHAR, IDCHAR, IDCHAR, IDCHAR, - SBEGIN, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, - LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, - LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, - LETTER, LETTER, LETTER, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, - IDCHAR, Letter, Letter, Letter, Letter, Letter, Letter, Letter, - Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, - Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, - Letter, Letter, Letter, IDCHAR, IDCHAR, IDCHAR, IDCHAR, UNKN, - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, - IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, - IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, - IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, - IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, IDCHAR, - LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, - LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, - LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, IDCHAR, - LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, Letter, - Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, - Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, - Letter, Letter, Letter, Letter, Letter, Letter, Letter, IDCHAR, - Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter -}; Index: gnu/usr.bin/rcs/lib/rcsrev.c =================================================================== --- gnu/usr.bin/rcs/lib/rcsrev.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsrev.c (working copy) @@ -1,911 +0,0 @@ -/* Handle RCS revision numbers. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.10 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.9 1995/06/01 16:23:43 eggert - * (cmpdate, normalizeyear): New functions work around MKS RCS incompatibility. - * (cmpnum, compartial): s[d] -> *(s+d) to work around Cray compiler bug. - * (genrevs, genbranch): cmpnum -> cmpdate - * - * Revision 5.8 1994/03/17 14:05:48 eggert - * Remove lint. - * - * Revision 5.7 1993/11/09 17:40:15 eggert - * Fix format string typos. - * - * Revision 5.6 1993/11/03 17:42:27 eggert - * Revision number `.N' now stands for `D.N', where D is the default branch. - * Add -z. Improve quality of diagnostics. Add `namedrev' for Name support. - * - * Revision 5.5 1992/07/28 16:12:44 eggert - * Identifiers may now start with a digit. Avoid `unsigned'. - * - * Revision 5.4 1992/01/06 02:42:34 eggert - * while (E) ; -> while (E) continue; - * - * Revision 5.3 1991/08/19 03:13:55 eggert - * Add `-r$', `-rB.'. Remove botches like `' from messages. Tune. - * - * Revision 5.2 1991/04/21 11:58:28 eggert - * Add tiprev(). - * - * Revision 5.1 1991/02/25 07:12:43 eggert - * Avoid overflow when comparing revision numbers. - * - * Revision 5.0 1990/08/22 08:13:43 eggert - * Remove compile-time limits; use malloc instead. - * Ansify and Posixate. Tune. - * Remove possibility of an internal error. Remove lint. - * - * Revision 4.5 89/05/01 15:13:22 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.4 87/12/18 11:45:22 narten - * more lint cleanups. Also, the NOTREACHED comment is no longer necessary, - * since there's now a return value there with a value. (Guy Harris) - * - * Revision 4.3 87/10/18 10:38:42 narten - * Updating version numbers. Changes relative to version 1.1 actually - * relative to 4.1 - * - * Revision 1.3 87/09/24 14:00:37 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:37 jenkins - * Port to suns - * - * Revision 4.1 83/03/25 21:10:45 wft - * Only changed $Header to $Id. - * - * Revision 3.4 82/12/04 13:24:08 wft - * Replaced getdelta() with gettree(). - * - * Revision 3.3 82/11/28 21:33:15 wft - * fixed compartial() and compnum() for nil-parameters; fixed nils - * in error messages. Testprogram output shortenend. - * - * Revision 3.2 82/10/18 21:19:47 wft - * renamed compnum->cmpnum, compnumfld->cmpnumfld, - * numericrevno->numricrevno. - * - * Revision 3.1 82/10/11 19:46:09 wft - * changed expandsym() to check for source==nil; returns zero length string - * in that case. - */ - -#include "rcsbase.h" - -libId(revId, "$FreeBSD$") - -static char const *branchtip P((char const*)); -static char const *lookupsym P((char const*)); -static char const *normalizeyear P((char const*,char[5])); -static struct hshentry *genbranch P((struct hshentry const*,char const*,int,char const*,char const*,char const*,struct hshentries**)); -static void absent P((char const*,int)); -static void cantfindbranch P((char const*,char const[datesize],char const*,char const*)); -static void store1 P((struct hshentries***,struct hshentry*)); - - - - int -countnumflds(s) - char const *s; -/* Given a pointer s to a dotted number (date or revision number), - * countnumflds returns the number of digitfields in s. - */ -{ - register char const *sp; - register int count; - if (!(sp=s) || !*sp) - return 0; - count = 1; - do { - if (*sp++ == '.') count++; - } while (*sp); - return(count); -} - - void -getbranchno(revno,branchno) - char const *revno; - struct buf *branchno; -/* Given a revision number revno, getbranchno copies the number of the branch - * on which revno is into branchno. If revno itself is a branch number, - * it is copied unchanged. - */ -{ - register int numflds; - register char *tp; - - bufscpy(branchno, revno); - numflds=countnumflds(revno); - if (!(numflds & 1)) { - tp = branchno->string; - while (--numflds) - while (*tp++ != '.') - continue; - *(tp-1)='\0'; - } -} - - - -int cmpnum(num1, num2) - char const *num1, *num2; -/* compares the two dotted numbers num1 and num2 lexicographically - * by field. Individual fields are compared numerically. - * returns <0, 0, >0 if num1num2, resp. - * omitted fields are assumed to be higher than the existing ones. -*/ -{ - register char const *s1, *s2; - register size_t d1, d2; - register int r; - - s1 = num1 ? num1 : ""; - s2 = num2 ? num2 : ""; - - for (;;) { - /* Give precedence to shorter one. */ - if (!*s1) - return (unsigned char)*s2; - if (!*s2) - return -1; - - /* Strip leading zeros, then find number of digits. */ - while (*s1=='0') ++s1; - while (*s2=='0') ++s2; - for (d1=0; isdigit(*(s1+d1)); d1++) continue; - for (d2=0; isdigit(*(s2+d2)); d2++) continue; - - /* Do not convert to integer; it might overflow! */ - if (d1 != d2) - return d1string; - while (length) { - while (*r1!='.' && *r1) - ++r1; - ++r1; - length--; - } - /* eliminate last '.'*/ - *(r1-1)='\0'; - return rev1->string; -} - - - - - static void -store1(store, next) - struct hshentries ***store; - struct hshentry *next; -/* - * Allocate a new list node that addresses NEXT. - * Append it to the list that **STORE is the end pointer of. - */ -{ - register struct hshentries *p; - - p = ftalloc(struct hshentries); - p->first = next; - **store = p; - *store = &p->rest; -} - -struct hshentry * genrevs(revno,date,author,state,store) - char const *revno, *date, *author, *state; - struct hshentries **store; -/* Function: finds the deltas needed for reconstructing the - * revision given by revno, date, author, and state, and stores pointers - * to these deltas into a list whose starting address is given by store. - * The last delta (target delta) is returned. - * If the proper delta could not be found, 0 is returned. - */ -{ - int length; - register struct hshentry * next; - int result; - char const *branchnum; - struct buf t; - char datebuf[datesize + zonelenmax]; - - bufautobegin(&t); - - if (!(next = Head)) { - rcserror("RCS file empty"); - goto norev; - } - - length = countnumflds(revno); - - if (length >= 1) { - /* at least one field; find branch exactly */ - while ((result=cmpnumfld(revno,next->num,1)) < 0) { - store1(&store, next); - next = next->next; - if (!next) { - rcserror("branch number %s too low", partialno(&t,revno,1)); - goto norev; - } - } - - if (result>0) { - absent(revno, 1); - goto norev; - } - } - if (length<=1){ - /* pick latest one on given branch */ - branchnum = next->num; /* works even for empty revno*/ - while (next && - cmpnumfld(branchnum,next->num,1) == 0 && - ( - (date && cmpdate(date,next->date) < 0) || - (author && strcmp(author,next->author) != 0) || - (state && strcmp(state,next->state) != 0) - ) - ) - { - store1(&store, next); - next=next->next; - } - if (!next || - (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ { - cantfindbranch( - length ? revno : partialno(&t,branchnum,1), - date, author, state - ); - goto norev; - } else { - store1(&store, next); - } - *store = 0; - return next; - } - - /* length >=2 */ - /* find revision; may go low if length==2*/ - while ((result=cmpnumfld(revno,next->num,2)) < 0 && - (cmpnumfld(revno,next->num,1)==0) ) { - store1(&store, next); - next = next->next; - if (!next) - break; - } - - if (!next || cmpnumfld(revno,next->num,1) != 0) { - rcserror("revision number %s too low", partialno(&t,revno,2)); - goto norev; - } - if ((length>2) && (result!=0)) { - absent(revno, 2); - goto norev; - } - - /* print last one */ - store1(&store, next); - - if (length>2) - return genbranch(next,revno,length,date,author,state,store); - else { /* length == 2*/ - if (date && cmpdate(date,next->date)<0) { - rcserror("Revision %s has date %s.", - next->num, - date2str(next->date, datebuf) - ); - return 0; - } - if (author && strcmp(author,next->author)!=0) { - rcserror("Revision %s has author %s.", - next->num, next->author - ); - return 0; - } - if (state && strcmp(state,next->state)!=0) { - rcserror("Revision %s has state %s.", - next->num, - next->state ? next->state : "" - ); - return 0; - } - *store = 0; - return next; - } - - norev: - bufautoend(&t); - return 0; -} - - - - - static struct hshentry * -genbranch(bpoint, revno, length, date, author, state, store) - struct hshentry const *bpoint; - char const *revno; - int length; - char const *date, *author, *state; - struct hshentries **store; -/* Function: given a branchpoint, a revision number, date, author, and state, - * genbranch finds the deltas necessary to reconstruct the given revision - * from the branch point on. - * Pointers to the found deltas are stored in a list beginning with store. - * revno must be on a side branch. - * Return 0 on error. - */ -{ - int field; - register struct hshentry * next, * trail; - register struct branchhead const *bhead; - int result; - struct buf t; - char datebuf[datesize + zonelenmax]; - - field = 3; - bhead = bpoint->branches; - - do { - if (!bhead) { - bufautobegin(&t); - rcserror("no side branches present for %s", - partialno(&t,revno,field-1) - ); - bufautoend(&t); - return 0; - } - - /*find branch head*/ - /*branches are arranged in increasing order*/ - while (0 < (result=cmpnumfld(revno,bhead->hsh->num,field))) { - bhead = bhead->nextbranch; - if (!bhead) { - bufautobegin(&t); - rcserror("branch number %s too high", - partialno(&t,revno,field) - ); - bufautoend(&t); - return 0; - } - } - - if (result<0) { - absent(revno, field); - return 0; - } - - next = bhead->hsh; - if (length==field) { - /* pick latest one on that branch */ - trail = 0; - do { if ((!date || cmpdate(date,next->date)>=0) && - (!author || strcmp(author,next->author)==0) && - (!state || strcmp(state,next->state)==0) - ) trail = next; - next=next->next; - } while (next); - - if (!trail) { - cantfindbranch(revno, date, author, state); - return 0; - } else { /* print up to last one suitable */ - next = bhead->hsh; - while (next!=trail) { - store1(&store, next); - next=next->next; - } - store1(&store, next); - } - *store = 0; - return next; - } - - /* length > field */ - /* find revision */ - /* check low */ - if (cmpnumfld(revno,next->num,field+1)<0) { - bufautobegin(&t); - rcserror("revision number %s too low", - partialno(&t,revno,field+1) - ); - bufautoend(&t); - return 0; - } - do { - store1(&store, next); - trail = next; - next = next->next; - } while (next && cmpnumfld(revno,next->num,field+1)>=0); - - if ((length>field+1) && /*need exact hit */ - (cmpnumfld(revno,trail->num,field+1) !=0)){ - absent(revno, field+1); - return 0; - } - if (length == field+1) { - if (date && cmpdate(date,trail->date)<0) { - rcserror("Revision %s has date %s.", - trail->num, - date2str(trail->date, datebuf) - ); - return 0; - } - if (author && strcmp(author,trail->author)!=0) { - rcserror("Revision %s has author %s.", - trail->num, trail->author - ); - return 0; - } - if (state && strcmp(state,trail->state)!=0) { - rcserror("Revision %s has state %s.", - trail->num, - trail->state ? trail->state : "" - ); - return 0; - } - } - bhead = trail->branches; - - } while ((field+=2) <= length); - *store = 0; - return trail; -} - - - static char const * -lookupsym(id) - char const *id; -/* Function: looks up id in the list of symbolic names starting - * with pointer SYMBOLS, and returns a pointer to the corresponding - * revision number. Return 0 if not present. - */ -{ - register struct assoc const *next; - for (next = Symbols; next; next = next->nextassoc) - if (strcmp(id, next->symbol)==0) - return next->num; - return 0; -} - -int expandsym(source, target) - char const *source; - struct buf *target; -/* Function: Source points to a revision number. Expandsym copies - * the number to target, but replaces all symbolic fields in the - * source number with their numeric values. - * Expand a branch followed by `.' to the latest revision on that branch. - * Ignore `.' after a revision. Remove leading zeros. - * returns false on error; - */ -{ - return fexpandsym(source, target, (RILE*)0); -} - - int -fexpandsym(source, target, fp) - char const *source; - struct buf *target; - RILE *fp; -/* Same as expandsym, except if FP is nonzero, it is used to expand KDELIM. */ -{ - register char const *sp, *bp; - register char *tp; - char const *tlim; - int dots; - - sp = source; - bufalloc(target, 1); - tp = target->string; - if (!sp || !*sp) { /* Accept 0 pointer as a legal value. */ - *tp='\0'; - return true; - } - if (sp[0] == KDELIM && !sp[1]) { - if (!getoldkeys(fp)) - return false; - if (!*prevrev.string) { - workerror("working file lacks revision number"); - return false; - } - bufscpy(target, prevrev.string); - return true; - } - tlim = tp + target->size; - dots = 0; - - for (;;) { - register char *p = tp; - size_t s = tp - target->string; - int id = false; - for (;;) { - switch (ctab[(unsigned char)*sp]) { - case IDCHAR: - case LETTER: - case Letter: - id = true; - /* fall into */ - case DIGIT: - if (tlim <= p) - p = bufenlarge(target, &tlim); - *p++ = *sp++; - continue; - - default: - break; - } - break; - } - if (tlim <= p) - p = bufenlarge(target, &tlim); - *p = 0; - tp = target->string + s; - - if (id) { - bp = lookupsym(tp); - if (!bp) { - rcserror("Symbolic name `%s' is undefined.",tp); - return false; - } - } else { - /* skip leading zeros */ - for (bp = tp; *bp=='0' && isdigit(bp[1]); bp++) - continue; - - if (!*bp) - if (s || *sp!='.') - break; - else { - /* Insert default branch before initial `.'. */ - char const *b; - if (Dbranch) - b = Dbranch; - else if (Head) - b = Head->num; - else - break; - getbranchno(b, target); - bp = tp = target->string; - tlim = tp + target->size; - } - } - - while ((*tp++ = *bp++)) - if (tlim <= tp) - tp = bufenlarge(target, &tlim); - - switch (*sp++) { - case '\0': - return true; - - case '.': - if (!*sp) { - if (dots & 1) - break; - if (!(bp = branchtip(target->string))) - return false; - bufscpy(target, bp); - return true; - } - ++dots; - tp[-1] = '.'; - continue; - } - break; - } - - rcserror("improper revision number: %s", source); - return false; -} - - char const * -namedrev(name, delta) - char const *name; - struct hshentry *delta; -/* Yield NAME if it names DELTA, 0 otherwise. */ -{ - if (name) { - char const *id = 0, *p, *val; - for (p = name; ; p++) - switch (ctab[(unsigned char)*p]) { - case IDCHAR: - case LETTER: - case Letter: - id = name; - break; - - case DIGIT: - break; - - case UNKN: - if (!*p && id && - (val = lookupsym(id)) && - strcmp(val, delta->num) == 0 - ) - return id; - /* fall into */ - default: - return 0; - } - } - return 0; -} - - static char const * -branchtip(branch) - char const *branch; -{ - struct hshentry *h; - struct hshentries *hs; - - h = genrevs(branch, (char*)0, (char*)0, (char*)0, &hs); - return h ? h->num : (char const*)0; -} - - char const * -tiprev() -{ - return Dbranch ? branchtip(Dbranch) : Head ? Head->num : (char const*)0; -} - - - -#ifdef REVTEST - -/* -* Test the routines that generate a sequence of delta numbers -* needed to regenerate a given delta. -*/ - -char const cmdid[] = "revtest"; - - int -main(argc,argv) -int argc; char * argv[]; -{ - static struct buf numricrevno; - char symrevno[100]; /* used for input of revision numbers */ - char author[20]; - char state[20]; - char date[20]; - struct hshentries *gendeltas; - struct hshentry * target; - int i; - - if (argc<2) { - aputs("No input file\n",stderr); - exitmain(EXIT_FAILURE); - } - if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) { - faterror("can't open input file %s", argv[1]); - } - Lexinit(); - getadmin(); - - gettree(); - - getdesc(false); - - do { - /* all output goes to stderr, to have diagnostics and */ - /* errors in sequence. */ - aputs("\nEnter revision number or or '.': ",stderr); - if (!fgets(symrevno, 100, stdin)) break; - if (*symrevno == '.') break; - aprintf(stderr,"%s;\n",symrevno); - expandsym(symrevno,&numricrevno); - aprintf(stderr,"expanded number: %s; ",numricrevno.string); - aprintf(stderr,"Date: "); - fgets(date, 20, stdin); aprintf(stderr,"%s; ",date); - aprintf(stderr,"Author: "); - fgets(author, 20, stdin); aprintf(stderr,"%s; ",author); - aprintf(stderr,"State: "); - fgets(state, 20, stdin); aprintf(stderr, "%s;\n", state); - target = genrevs(numricrevno.string, *date?date:(char *)0, *author?author:(char *)0, - *state?state:(char*)0, &gendeltas); - if (target) { - while (gendeltas) { - aprintf(stderr,"%s\n",gendeltas->first->num); - gendeltas = gendeltas->next; - } - } - } while (true); - aprintf(stderr,"done\n"); - exitmain(EXIT_SUCCESS); -} - -void exiterr() { _exit(EXIT_FAILURE); } - -#endif Index: gnu/usr.bin/rcs/lib/rcssyn.c =================================================================== --- gnu/usr.bin/rcs/lib/rcssyn.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcssyn.c (working copy) @@ -1,681 +0,0 @@ -/* RCS file syntactic analysis */ - -/****************************************************************************** - * Syntax Analysis. - * Keyword table - * Testprogram: define SYNTEST - * Compatibility with Release 2: define COMPAT2=1 - ****************************************************************************** - */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.15 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.14 1995/06/01 16:23:43 eggert - * (expand_names): Add "b" for -kb. - * (getdelta): Don't strip leading "19" from MKS RCS dates; see cmpdate. - * - * Revision 5.13 1994/03/20 04:52:58 eggert - * Remove lint. - * - * Revision 5.12 1993/11/03 17:42:27 eggert - * Parse MKS RCS dates; ignore \r in diff control lines. - * Don't discard ignored phrases. Improve quality of diagnostics. - * - * Revision 5.11 1992/07/28 16:12:44 eggert - * Avoid `unsigned'. Statement macro names now end in _. - * - * Revision 5.10 1992/01/24 18:44:19 eggert - * Move put routines to rcsgen.c. - * - * Revision 5.9 1992/01/06 02:42:34 eggert - * ULONG_MAX/10 -> ULONG_MAX_OVER_10 - * while (E) ; -> while (E) continue; - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Tune. - * - * Revision 5.7 1991/04/21 11:58:29 eggert - * Disambiguate names on shortname hosts. - * Fix errno bug. Add MS-DOS support. - * - * Revision 5.6 1991/02/28 19:18:51 eggert - * Fix null termination bug in reporting keyword expansion. - * - * Revision 5.5 1991/02/25 07:12:44 eggert - * Check diff output more carefully; avoid overflow. - * - * Revision 5.4 1990/11/01 05:28:48 eggert - * When ignoring unknown phrases, copy them to the output RCS file. - * Permit arbitrary data in logs and comment leaders. - * Don't check for nontext on initial checkin. - * - * Revision 5.3 1990/09/20 07:58:32 eggert - * Remove the test for non-text bytes; it caused more pain than it cured. - * - * Revision 5.2 1990/09/04 08:02:30 eggert - * Parse RCS files with no revisions. - * Don't strip leading white space from diff commands. Count RCS lines better. - * - * Revision 5.1 1990/08/29 07:14:06 eggert - * Add -kkvl. Clean old log messages too. - * - * Revision 5.0 1990/08/22 08:13:44 eggert - * Try to parse future RCS formats without barfing. - * Add -k. Don't require final newline. - * Remove compile-time limits; use malloc instead. - * Don't output branch keyword if there's no default branch, - * because RCS version 3 doesn't understand it. - * Tune. Remove lint. - * Add support for ISO 8859. Ansify and Posixate. - * Check that a newly checked-in file is acceptable as input to 'diff'. - * Check diff's output. - * - * Revision 4.6 89/05/01 15:13:32 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.5 88/08/09 19:13:21 eggert - * Allow cc -R; remove lint. - * - * Revision 4.4 87/12/18 11:46:16 narten - * more lint cleanups (Guy Harris) - * - * Revision 4.3 87/10/18 10:39:36 narten - * Updating version numbers. Changes relative to 1.1 actually relative to - * 4.1 - * - * Revision 1.3 87/09/24 14:00:49 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:40 jenkins - * Port to suns - * - * Revision 4.1 83/03/28 11:38:49 wft - * Added parsing and printing of default branch. - * - * Revision 3.6 83/01/15 17:46:50 wft - * Changed readdelta() to initialize selector and log-pointer. - * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM. - * - * Revision 3.5 82/12/08 21:58:58 wft - * renamed Commentleader to Commleader. - * - * Revision 3.4 82/12/04 13:24:40 wft - * Added routine gettree(), which updates keeplock after reading the - * delta tree. - * - * Revision 3.3 82/11/28 21:30:11 wft - * Reading and printing of Suffix removed; version COMPAT2 skips the - * Suffix for files of release 2 format. Fixed problems with printing nil. - * - * Revision 3.2 82/10/18 21:18:25 wft - * renamed putdeltatext to putdtext. - * - * Revision 3.1 82/10/11 19:45:11 wft - * made sure getc() returns into an integer. - */ - - - -/* version COMPAT2 reads files of the format of release 2 and 3, but - * generates files of release 3 format. Need not be defined if no - * old RCS files generated with release 2 exist. - */ - -#include "rcsbase.h" - -libId(synId, "$FreeBSD$") - -static char const *getkeyval P((char const*,enum tokens,int)); -static int getdelta P((void)); -static int strn2expmode P((char const*,size_t)); -static struct hshentry *getdnum P((void)); -static void badDiffOutput P((char const*)) exiting; -static void diffLineNumberTooLarge P((char const*)) exiting; -static void getsemi P((char const*)); - -/* keyword table */ - -char const - Kaccess[] = "access", - Kauthor[] = "author", - Kbranch[] = "branch", - Kcomment[] = "comment", - Kdate[] = "date", - Kdesc[] = "desc", - Kexpand[] = "expand", - Khead[] = "head", - Klocks[] = "locks", - Klog[] = "log", - Knext[] = "next", - Kstate[] = "state", - Kstrict[] = "strict", - Ksymbols[] = "symbols", - Ktext[] = "text"; - -static char const -#if COMPAT2 - Ksuffix[] = "suffix", -#endif - K_branches[]= "branches"; - -static struct buf Commleader; -struct cbuf Comment; -struct cbuf Ignored; -struct access * AccessList; -struct assoc * Symbols; -struct rcslock *Locks; -int Expand; -int StrictLocks; -struct hshentry * Head; -char const * Dbranch; -int TotalDeltas; - - - static void -getsemi(key) - char const *key; -/* Get a semicolon to finish off a phrase started by KEY. */ -{ - if (!getlex(SEMI)) - fatserror("missing ';' after '%s'", key); -} - - static struct hshentry * -getdnum() -/* Get a delta number. */ -{ - register struct hshentry *delta = getnum(); - if (delta && countnumflds(delta->num)&1) - fatserror("%s isn't a delta number", delta->num); - return delta; -} - - - void -getadmin() -/* Read an and initialize the appropriate global variables. */ -{ - register char const *id; - struct access * newaccess; - struct assoc * newassoc; - struct rcslock *newlock; - struct hshentry * delta; - struct access **LastAccess; - struct assoc **LastSymbol; - struct rcslock **LastLock; - struct buf b; - struct cbuf cb; - - TotalDeltas=0; - - getkey(Khead); - Head = getdnum(); - getsemi(Khead); - - Dbranch = 0; - if (getkeyopt(Kbranch)) { - if ((delta = getnum())) - Dbranch = delta->num; - getsemi(Kbranch); - } - - -#if COMPAT2 - /* read suffix. Only in release 2 format */ - if (getkeyopt(Ksuffix)) { - if (nexttok==STRING) { - readstring(); nextlex(); /* Throw away the suffix. */ - } else if (nexttok==ID) { - nextlex(); - } - getsemi(Ksuffix); - } -#endif - - getkey(Kaccess); - LastAccess = &AccessList; - while ((id = getid())) { - newaccess = ftalloc(struct access); - newaccess->login = id; - *LastAccess = newaccess; - LastAccess = &newaccess->nextaccess; - } - *LastAccess = 0; - getsemi(Kaccess); - - getkey(Ksymbols); - LastSymbol = &Symbols; - while ((id = getid())) { - if (!getlex(COLON)) - fatserror("missing ':' in symbolic name definition"); - if (!(delta=getnum())) { - fatserror("missing number in symbolic name definition"); - } else { /*add new pair to association list*/ - newassoc = ftalloc(struct assoc); - newassoc->symbol=id; - newassoc->num = delta->num; - *LastSymbol = newassoc; - LastSymbol = &newassoc->nextassoc; - } - } - *LastSymbol = 0; - getsemi(Ksymbols); - - getkey(Klocks); - LastLock = &Locks; - while ((id = getid())) { - if (!getlex(COLON)) - fatserror("missing ':' in lock"); - if (!(delta=getdnum())) { - fatserror("missing number in lock"); - } else { /*add new pair to lock list*/ - newlock = ftalloc(struct rcslock); - newlock->login=id; - newlock->delta=delta; - *LastLock = newlock; - LastLock = &newlock->nextlock; - } - } - *LastLock = 0; - getsemi(Klocks); - - if ((StrictLocks = getkeyopt(Kstrict))) - getsemi(Kstrict); - - clear_buf(&Comment); - if (getkeyopt(Kcomment)) { - if (nexttok==STRING) { - Comment = savestring(&Commleader); - nextlex(); - } - getsemi(Kcomment); - } - - Expand = KEYVAL_EXPAND; - if (getkeyopt(Kexpand)) { - if (nexttok==STRING) { - bufautobegin(&b); - cb = savestring(&b); - if ((Expand = strn2expmode(cb.string,cb.size)) < 0) - fatserror("unknown expand mode %.*s", - (int)cb.size, cb.string - ); - bufautoend(&b); - nextlex(); - } - getsemi(Kexpand); - } - Ignored = getphrases(Kdesc); -} - -char const *const expand_names[] = { - /* These must agree with *_EXPAND in rcsbase.h. */ - "kv", "kvl", "k", "v", "o", "b", - 0 -}; - - int -str2expmode(s) - char const *s; -/* Yield expand mode corresponding to S, or -1 if bad. */ -{ - return strn2expmode(s, strlen(s)); -} - - static int -strn2expmode(s, n) - char const *s; - size_t n; -{ - char const *const *p; - - for (p = expand_names; *p; ++p) - if (memcmp(*p,s,n) == 0 && !(*p)[n]) - return p - expand_names; - return -1; -} - - - void -ignorephrases(key) - const char *key; -/* -* Ignore a series of phrases that do not start with KEY. -* Stop when the next phrase starts with a token that is not an identifier, -* or is KEY. -*/ -{ - for (;;) { - nextlex(); - if (nexttok != ID || strcmp(NextString,key) == 0) - break; - warnignore(); - hshenter=false; - for (;; nextlex()) { - switch (nexttok) { - case SEMI: hshenter=true; break; - case ID: - case NUM: ffree1(NextString); continue; - case STRING: readstring(); continue; - default: continue; - } - break; - } - } -} - - - static int -getdelta() -/* Function: reads a delta block. - * returns false if the current block does not start with a number. - */ -{ - register struct hshentry * Delta, * num; - struct branchhead **LastBranch, *NewBranch; - - if (!(Delta = getdnum())) - return false; - - hshenter = false; /*Don't enter dates into hashtable*/ - Delta->date = getkeyval(Kdate, NUM, false); - hshenter=true; /*reset hshenter for revision numbers.*/ - - Delta->author = getkeyval(Kauthor, ID, false); - - Delta->state = getkeyval(Kstate, ID, true); - - getkey(K_branches); - LastBranch = &Delta->branches; - while ((num = getdnum())) { - NewBranch = ftalloc(struct branchhead); - NewBranch->hsh = num; - *LastBranch = NewBranch; - LastBranch = &NewBranch->nextbranch; - } - *LastBranch = 0; - getsemi(K_branches); - - getkey(Knext); - Delta->next = num = getdnum(); - getsemi(Knext); - Delta->lockedby = 0; - Delta->log.string = 0; - Delta->selector = true; - Delta->ig = getphrases(Kdesc); - TotalDeltas++; - return (true); -} - - - void -gettree() -/* Function: Reads in the delta tree with getdelta(), then - * updates the lockedby fields. - */ -{ - struct rcslock const *currlock; - - while (getdelta()) - continue; - currlock=Locks; - while (currlock) { - currlock->delta->lockedby = currlock->login; - currlock = currlock->nextlock; - } -} - - - void -getdesc(prdesc) -int prdesc; -/* Function: read in descriptive text - * nexttok is not advanced afterwards. - * If prdesc is set, the text is printed to stdout. - */ -{ - - getkeystring(Kdesc); - if (prdesc) - printstring(); /*echo string*/ - else readstring(); /*skip string*/ -} - - - - - - - static char const * -getkeyval(keyword, token, optional) - char const *keyword; - enum tokens token; - int optional; -/* reads a pair of the form - * ; - * where token is one of or . optional indicates whether - * is optional. A pointer to - * the actual character string of or is returned. - */ -{ - register char const *val = 0; - - getkey(keyword); - if (nexttok==token) { - val = NextString; - nextlex(); - } else { - if (!optional) - fatserror("missing %s", keyword); - } - getsemi(keyword); - return(val); -} - - - void -unexpected_EOF() -{ - rcsfaterror("unexpected EOF in diff output"); -} - - void -initdiffcmd(dc) - register struct diffcmd *dc; -/* Initialize *dc suitably for getdiffcmd(). */ -{ - dc->adprev = 0; - dc->dafter = 0; -} - - static void -badDiffOutput(buf) - char const *buf; -{ - rcsfaterror("bad diff output line: %s", buf); -} - - static void -diffLineNumberTooLarge(buf) - char const *buf; -{ - rcsfaterror("diff line number too large: %s", buf); -} - - int -getdiffcmd(finfile, delimiter, foutfile, dc) - RILE *finfile; - FILE *foutfile; - int delimiter; - struct diffcmd *dc; -/* Get a editing command output by 'diff -n' from fin. - * The input is delimited by SDELIM if delimiter is set, EOF otherwise. - * Copy a clean version of the command to fout (if nonnull). - * Yield 0 for 'd', 1 for 'a', and -1 for EOF. - * Store the command's line number and length into dc->line1 and dc->nlines. - * Keep dc->adprev and dc->dafter up to date. - */ -{ - register int c; - declarecache; - register FILE *fout; - register char *p; - register RILE *fin; - long line1, nlines, t; - char buf[BUFSIZ]; - - fin = finfile; - fout = foutfile; - setupcache(fin); cache(fin); - cachegeteof_(c, { if (delimiter) unexpected_EOF(); return -1; } ) - if (delimiter) { - if (c==SDELIM) { - cacheget_(c) - if (c==SDELIM) { - buf[0] = c; - buf[1] = 0; - badDiffOutput(buf); - } - uncache(fin); - nextc = c; - if (fout) - aprintf(fout, "%c%c", SDELIM, c); - return -1; - } - } - p = buf; - do { - if (buf+BUFSIZ-2 <= p) { - rcsfaterror("diff output command line too long"); - } - *p++ = c; - cachegeteof_(c, unexpected_EOF();) - } while (c != '\n'); - uncache(fin); - if (delimiter) - ++rcsline; - *p = '\0'; - for (p = buf+1; (c = *p++) == ' '; ) - continue; - line1 = 0; - while (isdigit(c)) { - if ( - LONG_MAX/10 < line1 || - (t = line1 * 10, (line1 = t + (c - '0')) < t) - ) - diffLineNumberTooLarge(buf); - c = *p++; - } - while (c == ' ') - c = *p++; - nlines = 0; - while (isdigit(c)) { - if ( - LONG_MAX/10 < nlines || - (t = nlines * 10, (nlines = t + (c - '0')) < t) - ) - diffLineNumberTooLarge(buf); - c = *p++; - } - if (c == '\r') - c = *p++; - if (c || !nlines) { - badDiffOutput(buf); - } - if (line1+nlines < line1) - diffLineNumberTooLarge(buf); - switch (buf[0]) { - case 'a': - if (line1 < dc->adprev) { - rcsfaterror("backward insertion in diff output: %s", buf); - } - dc->adprev = line1 + 1; - break; - case 'd': - if (line1 < dc->adprev || line1 < dc->dafter) { - rcsfaterror("backward deletion in diff output: %s", buf); - } - dc->adprev = line1; - dc->dafter = line1 + nlines; - break; - default: - badDiffOutput(buf); - } - if (fout) { - aprintf(fout, "%s\n", buf); - } - dc->line1 = line1; - dc->nlines = nlines; - return buf[0] == 'a'; -} - - - -#ifdef SYNTEST - -/* Input an RCS file and print its internal data structures. */ - -char const cmdid[] = "syntest"; - - int -main(argc,argv) -int argc; char * argv[]; -{ - - if (argc<2) { - aputs("No input file\n",stderr); - exitmain(EXIT_FAILURE); - } - if (!(finptr = Iopen(argv[1], FOPEN_R, (struct stat*)0))) { - faterror("can't open input file %s", argv[1]); - } - Lexinit(); - getadmin(); - fdlock = STDOUT_FILENO; - putadmin(); - - gettree(); - - getdesc(true); - - nextlex(); - - if (!eoflex()) { - fatserror("expecting EOF"); - } - exitmain(EXIT_SUCCESS); -} - -void exiterr() { _exit(EXIT_FAILURE); } - -#endif Index: gnu/usr.bin/rcs/lib/rcstime.c =================================================================== --- gnu/usr.bin/rcs/lib/rcstime.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcstime.c (working copy) @@ -1,191 +0,0 @@ -/* Convert between RCS time format and Posix and/or C formats. */ - -/* Copyright 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#include "rcsbase.h" -#include "partime.h" -#include "maketime.h" - -libId(rcstimeId, "$FreeBSD$") - -static long zone_offset; /* seconds east of UTC, or TM_LOCAL_ZONE */ -static int use_zone_offset; /* if zero, use UTC without zone indication */ - -/* -* Convert Unix time to RCS format. -* For compatibility with older versions of RCS, -* dates from 1900 through 1999 are stored without the leading "19". -*/ - void -time2date(unixtime,date) - time_t unixtime; - char date[datesize]; -{ - register struct tm const *tm = time2tm(unixtime, RCSversiontm_year + ((unsigned)tm->tm_year < 100 ? 0 : 1900), - tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec - ); -} - -/* Like str2time, except die if an error was found. */ -static time_t str2time_checked P((char const*,time_t,long)); - static time_t -str2time_checked(source, default_time, default_zone) - char const *source; - time_t default_time; - long default_zone; -{ - time_t t = str2time(source, default_time, default_zone); - if (t == -1) - faterror("unknown date/time: %s", source); - return t; -} - -/* -* Parse a free-format date in SOURCE, convert it -* into RCS internal format, and store the result into TARGET. -*/ - void -str2date(source, target) - char const *source; - char target[datesize]; -{ - time2date( - str2time_checked(source, now(), - use_zone_offset ? zone_offset - : RCSversiontm_year + 1900, - z->tm_mon + 1, z->tm_mday, z->tm_hour, z->tm_min, z->tm_sec, - c, (int) (zone / (60*60)) - ); - if ((non_hour = zone % (60*60))) { -# if has_printf_dot - static char const fmt[] = ":%.2d"; -# else - static char const fmt[] = ":%02d"; -# endif - VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour / 60); - if ((non_hour %= 60)) - VOID sprintf(datebuf + strlen(datebuf), fmt, non_hour); - } - } - return datebuf; -} Index: gnu/usr.bin/rcs/lib/rcsutil.c =================================================================== --- gnu/usr.bin/rcs/lib/rcsutil.c (revision 255904) +++ gnu/usr.bin/rcs/lib/rcsutil.c (working copy) @@ -1,1398 +0,0 @@ -/* RCS utility functions */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - - - - -/* - * Revision 5.20 1995/06/16 06:19:24 eggert - * (catchsig): Remove `return'. - * Update FSF address. - * - * Revision 5.19 1995/06/02 18:19:00 eggert - * (catchsigaction): New name for `catchsig', for sa_sigaction signature. - * Use nRCS even if !has_psiginfo, to remove unused variable warning. - * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction. - * Use ENOTSUP only if defined. - * - * Revision 5.18 1995/06/01 16:23:43 eggert - * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo, - * to determine whether to use SA_SIGINFO feature, - * but also check at runtime whether the feature works. - * (catchsig): If an mmap_signal occurs, report the affected file name. - * (unsupported_SA_SIGINFO, accessName): New variables. - * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler. - * If SA_SIGINFO fails, fall back on sa_handler method. - * - * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions. - * (concatenate): Remove. - * - * (runv): Work around bad_wait_if_SIGCHLD_ignored bug. - * Remove reference to OPEN_O_WORK. - * - * Revision 5.17 1994/03/20 04:52:58 eggert - * Specify subprocess input via file descriptor, not file name. - * Avoid messing with I/O buffers in the child process. - * Define dup in terms of F_DUPFD if it exists. - * Move setmtime to rcsedit.c. Remove lint. - * - * Revision 5.16 1993/11/09 17:40:15 eggert - * -V now prints version on stdout and exits. - * - * Revision 5.15 1993/11/03 17:42:27 eggert - * Use psiginfo and setreuid if available. Move date2str to maketime.c. - * - * Revision 5.14 1992/07/28 16:12:44 eggert - * Add -V. has_sigaction overrides sig_zaps_handler. Fix -M bug. - * Add mmap_signal, which minimizes signal handling for non-mmap hosts. - * - * Revision 5.13 1992/02/17 23:02:28 eggert - * Work around NFS mmap SIGBUS problem. Add -T support. - * - * Revision 5.12 1992/01/24 18:44:19 eggert - * Work around NFS mmap bug that leads to SIGBUS core dumps. lint -> RCS_lint - * - * Revision 5.11 1992/01/06 02:42:34 eggert - * O_BINARY -> OPEN_O_WORK - * while (E) ; -> while (E) continue; - * - * Revision 5.10 1991/10/07 17:32:46 eggert - * Support piece tables even if !has_mmap. - * - * Revision 5.9 1991/08/19 03:13:55 eggert - * Add spawn() support. Explicate assumptions about getting invoker's name. - * Standardize user-visible dates. Tune. - * - * Revision 5.8 1991/04/21 11:58:30 eggert - * Plug setuid security hole. - * - * Revision 5.6 1991/02/26 17:48:39 eggert - * Fix setuid bug. Use fread, fwrite more portably. - * Support waitpid. Don't assume -1 is acceptable to W* macros. - * strsave -> str_save (DG/UX name clash) - * - * Revision 5.5 1990/12/04 05:18:49 eggert - * Don't output a blank line after a signal diagnostic. - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.4 1990/11/01 05:03:53 eggert - * Remove unneeded setid check. Add awrite(), fremember(). - * - * Revision 5.3 1990/10/06 00:16:45 eggert - * Don't fread F if feof(F). - * - * Revision 5.2 1990/09/04 08:02:31 eggert - * Store fread()'s result in an fread_type object. - * - * Revision 5.1 1990/08/29 07:14:07 eggert - * Declare getpwuid() more carefully. - * - * Revision 5.0 1990/08/22 08:13:46 eggert - * Add setuid support. Permit multiple locks per user. - * Remove compile-time limits; use malloc instead. - * Switch to GMT. Permit dates past 1999/12/31. - * Add -V. Remove snooping. Ansify and Posixate. - * Tune. Some USG hosts define NSIG but not sys_siglist. - * Don't run /bin/sh if it's hopeless. - * Don't leave garbage behind if the output is an empty pipe. - * Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup. - * - * Revision 4.6 89/05/01 15:13:40 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.5 88/11/08 16:01:02 narten - * corrected use of varargs routines - * - * Revision 4.4 88/08/09 19:13:24 eggert - * Check for memory exhaustion. - * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch. - * Use execv(), not system(); yield exit status like diff(1)'s. - * - * Revision 4.3 87/10/18 10:40:22 narten - * Updating version numbers. Changes relative to 1.1 actually - * relative to 4.1 - * - * Revision 1.3 87/09/24 14:01:01 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:43 jenkins - * Port to suns - * - * Revision 4.1 83/05/10 15:53:13 wft - * Added getcaller() and findlock(). - * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal - * (needed for background jobs in older shells). Added restoreints(). - * Removed printing of full RCS path from logcommand(). - * - * Revision 3.8 83/02/15 15:41:49 wft - * Added routine fastcopy() to copy remainder of a file in blocks. - * - * Revision 3.7 82/12/24 15:25:19 wft - * added catchints(), ignoreints() for catching and ingnoring interrupts; - * fixed catchsig(). - * - * Revision 3.6 82/12/08 21:52:05 wft - * Using DATEFORM to format dates. - * - * Revision 3.5 82/12/04 18:20:49 wft - * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update - * lockedby-field. - * - * Revision 3.4 82/12/03 17:17:43 wft - * Added check to addlock() ensuring only one lock per person. - * Addlock also returns a pointer to the lock created. Deleted fancydate(). - * - * Revision 3.3 82/11/27 12:24:37 wft - * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c. - * Introduced macro SNOOP so that snoop can be placed in directory other than - * TARGETDIR. Changed %02d to %.2d for compatibility reasons. - * - * Revision 3.2 82/10/18 21:15:11 wft - * added function getfullRCSname(). - * - * Revision 3.1 82/10/13 16:17:37 wft - * Cleanup message is now suppressed in quiet mode. - */ - - - - -#include "rcsbase.h" - -libId(utilId, "$FreeBSD$") - -#if !has_memcmp - int -memcmp(s1, s2, n) - void const *s1, *s2; - size_t n; -{ - register unsigned char const - *p1 = (unsigned char const*)s1, - *p2 = (unsigned char const*)s2; - register size_t i = n; - register int r = 0; - while (i-- && !(r = (*p1++ - *p2++))) - ; - return r; -} -#endif - -#if !has_memcpy - void * -memcpy(s1, s2, n) - void *s1; - void const *s2; - size_t n; -{ - register char *p1 = (char*)s1; - register char const *p2 = (char const*)s2; - while (n--) - *p1++ = *p2++; - return s1; -} -#endif - -#if RCS_lint - malloc_type lintalloc; -#endif - -/* - * list of blocks allocated with ftestalloc() - * These blocks can be freed by ffree when we're done with the current file. - * We could put the free block inside struct alloclist, rather than a pointer - * to the free block, but that would be less portable. - */ -struct alloclist { - malloc_type alloc; - struct alloclist *nextalloc; -}; -static struct alloclist *alloced; - - - static malloc_type okalloc P((malloc_type)); - static malloc_type -okalloc(p) - malloc_type p; -{ - if (!p) - faterror("out of memory"); - return p; -} - - malloc_type -testalloc(size) - size_t size; -/* Allocate a block, testing that the allocation succeeded. */ -{ - return okalloc(malloc(size)); -} - - malloc_type -testrealloc(ptr, size) - malloc_type ptr; - size_t size; -/* Reallocate a block, testing that the allocation succeeded. */ -{ - return okalloc(realloc(ptr, size)); -} - - malloc_type -fremember(ptr) - malloc_type ptr; -/* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */ -{ - register struct alloclist *q = talloc(struct alloclist); - q->nextalloc = alloced; - alloced = q; - return q->alloc = ptr; -} - - malloc_type -ftestalloc(size) - size_t size; -/* Allocate a block, putting it in 'alloced' so it can be freed later. */ -{ - return fremember(testalloc(size)); -} - - void -ffree() -/* Free all blocks allocated with ftestalloc(). */ -{ - register struct alloclist *p, *q; - for (p = alloced; p; p = q) { - q = p->nextalloc; - tfree(p->alloc); - tfree(p); - } - alloced = 0; -} - - void -ffree1(f) - register char const *f; -/* Free the block f, which was allocated by ftestalloc. */ -{ - register struct alloclist *p, **a = &alloced; - - while ((p = *a)->alloc != f) - a = &p->nextalloc; - *a = p->nextalloc; - tfree(p->alloc); - tfree(p); -} - - char * -str_save(s) - char const *s; -/* Save s in permanently allocated storage. */ -{ - return strcpy(tnalloc(char, strlen(s)+1), s); -} - - char * -fstr_save(s) - char const *s; -/* Save s in storage that will be deallocated when we're done with this file. */ -{ - return strcpy(ftnalloc(char, strlen(s)+1), s); -} - - char * -cgetenv(name) - char const *name; -/* Like getenv(), but yield a copy; getenv() can overwrite old results. */ -{ - register char *p; - - return (p=getenv(name)) ? str_save(p) : p; -} - - char const * -getusername(suspicious) - int suspicious; -/* Get the caller's login name. Trust only getwpuid if SUSPICIOUS. */ -{ - static char *name; - - if (!name) { - if ( - /* Prefer getenv() unless suspicious; it's much faster. */ -# if getlogin_is_secure - (suspicious - || ( - !(name = cgetenv("LOGNAME")) - && !(name = cgetenv("USER")) - )) - && !(name = getlogin()) -# else - suspicious - || ( - !(name = cgetenv("LOGNAME")) - && !(name = cgetenv("USER")) - && !(name = getlogin()) - ) -# endif - ) { -#if has_getuid && has_getpwuid - struct passwd const *pw = getpwuid(ruid()); - if (!pw) - faterror("no password entry for userid %lu", - (unsigned long)ruid() - ); - name = pw->pw_name; -#else -#if has_setuid - faterror("setuid not supported"); -#else - faterror("Who are you? Please setenv LOGNAME."); -#endif -#endif - } - checksid(name); - } - return name; -} - - - - -#if has_signal - -/* - * Signal handling - * - * Standard C places too many restrictions on signal handlers. - * We obey as many of them as we can. - * Posix places fewer restrictions, and we are Posix-compatible here. - */ - -static sig_atomic_t volatile heldsignal, holdlevel; -#ifdef SA_SIGINFO - static int unsupported_SA_SIGINFO; - static siginfo_t bufsiginfo; - static siginfo_t *volatile heldsiginfo; -#endif - - -#if has_NFS && has_mmap && large_memory && mmap_signal - static char const *accessName; - - void - readAccessFilenameBuffer(filename, p) - char const *filename; - unsigned char const *p; - { - unsigned char volatile t; - accessName = filename; - t = *p; - accessName = 0; - } -#else -# define accessName ((char const *) 0) -#endif - - -#if !has_psignal - -# define psignal my_psignal - static void my_psignal P((int,char const*)); - static void -my_psignal(sig, s) - int sig; - char const *s; -{ - char const *sname = "Unknown signal"; -# if has_sys_siglist && defined(NSIG) - if ((unsigned)sig < NSIG) - sname = sys_siglist[sig]; -# else - switch (sig) { -# ifdef SIGHUP - case SIGHUP: sname = "Hangup"; break; -# endif -# ifdef SIGINT - case SIGINT: sname = "Interrupt"; break; -# endif -# ifdef SIGPIPE - case SIGPIPE: sname = "Broken pipe"; break; -# endif -# ifdef SIGQUIT - case SIGQUIT: sname = "Quit"; break; -# endif -# ifdef SIGTERM - case SIGTERM: sname = "Terminated"; break; -# endif -# ifdef SIGXCPU - case SIGXCPU: sname = "Cputime limit exceeded"; break; -# endif -# ifdef SIGXFSZ - case SIGXFSZ: sname = "Filesize limit exceeded"; break; -# endif -# if has_mmap && large_memory -# if defined(SIGBUS) && mmap_signal==SIGBUS - case SIGBUS: sname = "Bus error"; break; -# endif -# if defined(SIGSEGV) && mmap_signal==SIGSEGV - case SIGSEGV: sname = "Segmentation fault"; break; -# endif -# endif - } -# endif - - /* Avoid calling sprintf etc., in case they're not reentrant. */ - { - char const *p; - char buf[BUFSIZ], *b = buf; - for (p = s; *p; *b++ = *p++) - continue; - *b++ = ':'; - *b++ = ' '; - for (p = sname; *p; *b++ = *p++) - continue; - *b++ = '\n'; - VOID write(STDERR_FILENO, buf, b - buf); - } -} -#endif - -static signal_type catchsig P((int)); -#ifdef SA_SIGINFO - static signal_type catchsigaction P((int,siginfo_t*,void*)); -#endif - - static signal_type -catchsig(s) - int s; -#ifdef SA_SIGINFO -{ - catchsigaction(s, (siginfo_t *)0, (void *)0); -} - static signal_type -catchsigaction(s, i, c) - int s; - siginfo_t *i; - void *c; -#endif -{ -# if sig_zaps_handler - /* If a signal arrives before we reset the handler, we lose. */ - VOID signal(s, SIG_IGN); -# endif - -# ifdef SA_SIGINFO - if (!unsupported_SA_SIGINFO) - i = 0; -# endif - - if (holdlevel) { - heldsignal = s; -# ifdef SA_SIGINFO - if (i) { - bufsiginfo = *i; - heldsiginfo = &bufsiginfo; - } -# endif - return; - } - - ignoreints(); - setrid(); - if (!quietflag) { - /* Avoid calling sprintf etc., in case they're not reentrant. */ - char const *p; - char buf[BUFSIZ], *b = buf; - - if ( ! ( -# if has_mmap && large_memory && mmap_signal - /* Check whether this signal was planned. */ - s == mmap_signal && accessName -# else - 0 -# endif - )) { - char const *nRCS = "\nRCS"; -# if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal - if (s == mmap_signal && i && i->si_errno) { - errno = i->si_errno; - perror(nRCS++); - } -# endif -# if defined(SA_SIGINFO) && has_psiginfo - if (i) - psiginfo(i, nRCS); - else - psignal(s, nRCS); -# else - psignal(s, nRCS); -# endif - } - - for (p = "RCS: "; *p; *b++ = *p++) - continue; -# if has_mmap && large_memory && mmap_signal - if (s == mmap_signal) { - p = accessName; - if (!p) - p = "Was a file changed by some other process? "; - else { - char const *p1; - for (p1 = p; *p1; p1++) - continue; - VOID write(STDERR_FILENO, buf, b - buf); - VOID write(STDERR_FILENO, p, p1 - p); - b = buf; - p = ": Permission denied. "; - } - while (*p) - *b++ = *p++; - } -# endif - for (p = "Cleaning up.\n"; *p; *b++ = *p++) - continue; - VOID write(STDERR_FILENO, buf, b - buf); - } - exiterr(); -} - - void -ignoreints() -{ - ++holdlevel; -} - - void -restoreints() -{ - if (!--holdlevel && heldsignal) -# ifdef SA_SIGINFO - VOID catchsigaction(heldsignal, heldsiginfo, (void *)0); -# else - VOID catchsig(heldsignal); -# endif -} - - -static void setup_catchsig P((int const*,int)); - -#if has_sigaction - - static void check_sig P((int)); - static void - check_sig(r) - int r; - { - if (r != 0) - efaterror("signal handling"); - } - - static void - setup_catchsig(sig, sigs) - int const *sig; - int sigs; - { - register int i, j; - struct sigaction act; - - for (i=sigs; 0<=--i; ) { - check_sig(sigaction(sig[i], (struct sigaction*)0, &act)); - if (act.sa_handler != SIG_IGN) { - act.sa_handler = catchsig; -# ifdef SA_SIGINFO - if (!unsupported_SA_SIGINFO) { -# if has_sa_sigaction - act.sa_sigaction = catchsigaction; -# else - act.sa_handler = catchsigaction; -# endif - act.sa_flags |= SA_SIGINFO; - } -# endif - for (j=sigs; 0<=--j; ) - check_sig(sigaddset(&act.sa_mask, sig[j])); - if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) { -# if defined(SA_SIGINFO) && defined(ENOTSUP) - if (errno == ENOTSUP && !unsupported_SA_SIGINFO) { - /* Turn off use of SA_SIGINFO and try again. */ - unsupported_SA_SIGINFO = 1; - i++; - continue; - } -# endif - check_sig(-1); - } - } - } - } - -#else -#if has_sigblock - - static void - setup_catchsig(sig, sigs) - int const *sig; - int sigs; - { - register int i; - int mask; - - mask = 0; - for (i=sigs; 0<=--i; ) - mask |= sigmask(sig[i]); - mask = sigblock(mask); - for (i=sigs; 0<=--i; ) - if ( - signal(sig[i], catchsig) == SIG_IGN && - signal(sig[i], SIG_IGN) != catchsig - ) - faterror("signal catcher failure"); - VOID sigsetmask(mask); - } - -#else - - static void - setup_catchsig(sig, sigs) - int const *sig; - int sigs; - { - register i; - - for (i=sigs; 0<=--i; ) - if ( - signal(sig[i], SIG_IGN) != SIG_IGN && - signal(sig[i], catchsig) != SIG_IGN - ) - faterror("signal catcher failure"); - } - -#endif -#endif - - -static int const regsigs[] = { -# ifdef SIGHUP - SIGHUP, -# endif -# ifdef SIGINT - SIGINT, -# endif -# ifdef SIGPIPE - SIGPIPE, -# endif -# ifdef SIGQUIT - SIGQUIT, -# endif -# ifdef SIGTERM - SIGTERM, -# endif -# ifdef SIGXCPU - SIGXCPU, -# endif -# ifdef SIGXFSZ - SIGXFSZ, -# endif -}; - - void -catchints() -{ - static int catching_ints; - if (!catching_ints) { - catching_ints = true; - setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs))); - } -} - -#if has_mmap && large_memory && mmap_signal - - /* - * If you mmap an NFS file, and someone on another client removes the last - * link to that file, and you later reference an uncached part of that file, - * you'll get a SIGBUS or SIGSEGV (depending on the operating system). - * Catch the signal and report the problem to the user. - * Unfortunately, there's no portable way to differentiate between this - * problem and actual bugs in the program. - * This NFS problem is rare, thank goodness. - * - * This can also occur if someone truncates the file, even without NFS. - */ - - static int const mmapsigs[] = { mmap_signal }; - - void - catchmmapints() - { - static int catching_mmap_ints; - if (!catching_mmap_ints) { - catching_mmap_ints = true; - setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs))); - } - } -#endif - -#endif /* has_signal */ - - - void -fastcopy(inf,outf) - register RILE *inf; - FILE *outf; -/* Function: copies the remainder of file inf to outf. - */ -{ -#if large_memory -# if maps_memory - awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf); - inf->ptr = inf->lim; -# else - for (;;) { - awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf); - inf->ptr = inf->readlim; - if (inf->ptr == inf->lim) - break; - VOID Igetmore(inf); - } -# endif -#else - char buf[BUFSIZ*8]; - register fread_type rcount; - - /*now read the rest of the file in blocks*/ - while (!feof(inf)) { - if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) { - testIerror(inf); - return; - } - awrite(buf, (size_t)rcount, outf); - } -#endif -} - -#ifndef SSIZE_MAX - /* This does not work in #ifs, but it's good enough for us. */ - /* Underestimating SSIZE_MAX may slow us down, but it won't break us. */ -# define SSIZE_MAX ((unsigned)-1 >> 1) -#endif - - void -awrite(buf, chars, f) - char const *buf; - size_t chars; - FILE *f; -{ - /* Posix 1003.1-1990 ssize_t hack */ - while (SSIZE_MAX < chars) { - if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f) != SSIZE_MAX) - Oerror(); - buf += SSIZE_MAX; - chars -= SSIZE_MAX; - } - - if (Fwrite(buf, sizeof(*buf), chars, f) != chars) - Oerror(); -} - -/* dup a file descriptor; the result must not be stdin, stdout, or stderr. */ - static int dupSafer P((int)); - static int -dupSafer(fd) - int fd; -{ -# ifdef F_DUPFD - return fcntl(fd, F_DUPFD, STDERR_FILENO + 1); -# else - int e, f, i, used = 0; - while (STDIN_FILENO <= (f = dup(fd)) && f <= STDERR_FILENO) - used |= 1<string); - bufrealloc(b, bl + sl + 4); - p = b->string + bl; - *p++ = c; - *p++ = '\''; - while (*s) { - if (*s == '\'') { - *p++ = '\''; - *p++ = '\\'; - *p++ = '\''; - } - *p++ = *s++; - } - *p++ = '\''; - *p = 0; -} - -#endif - -#if !has_spawn && has_fork -/* -* Output the string S to stderr, without touching any I/O buffers. -* This is useful if you are a child process, whose buffers are usually wrong. -* Exit immediately if the write does not completely succeed. -*/ -static void write_stderr P((char const *)); - static void -write_stderr(s) - char const *s; -{ - size_t slen = strlen(s); - if (write(STDERR_FILENO, s, slen) != slen) - _exit(EXIT_TROUBLE); -} -#endif - -/* -* Run a command. -* infd, if not -1, is the input file descriptor. -* outname, if nonzero, is the name of the output file. -* args[1..] form the command to be run; args[0] might be modified. -*/ - int -runv(infd, outname, args) - int infd; - char const *outname, **args; -{ - int wstatus; - -#if bad_wait_if_SIGCHLD_ignored - static int fixed_SIGCHLD; - if (!fixed_SIGCHLD) { - fixed_SIGCHLD = true; -# ifndef SIGCHLD -# define SIGCHLD SIGCLD -# endif - VOID signal(SIGCHLD, SIG_DFL); - } -#endif - - oflush(); - eflush(); - { -#if has_spawn - int in, out; - char const *file; - - in = -1; - if (infd != -1 && infd != STDIN_FILENO) { - if ((in = dup(STDIN_FILENO)) < 0) { - if (errno != EBADF) - efaterror("spawn input setup"); - in = -2; - } else { -# ifdef F_DUPFD - if (close(STDIN_FILENO) != 0) - efaterror("spawn input close"); -# endif - } - if ( -# ifdef F_DUPFD - fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO -# else - dup2(infd, STDIN_FILENO) != STDIN_FILENO -# endif - ) - efaterror("spawn input redirection"); - } - - out = -1; - if (outname) { - if ((out = dup(STDOUT_FILENO)) < 0) { - if (errno != EBADF) - efaterror("spawn output setup"); - out = -2; - } - if (fdreopen( - STDOUT_FILENO, outname, - O_CREAT | O_TRUNC | O_WRONLY - ) < 0) - efaterror(outname); - } - - wstatus = spawn_RCS(0, args[1], (char**)(args + 1)); -# ifdef RCS_SHELL - if (wstatus == -1 && errno == ENOEXEC) { - args[0] = RCS_SHELL; - wstatus = spawnv(0, args[0], (char**)args); - } -# endif - redirect(in, STDIN_FILENO); - redirect(out, STDOUT_FILENO); -#else -#if has_fork - pid_t pid; - if (!(pid = vfork())) { - char const *notfound; - if (infd != -1 && infd != STDIN_FILENO && ( -# ifdef F_DUPFD - (VOID close(STDIN_FILENO), - fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO) -# else - dup2(infd, STDIN_FILENO) != STDIN_FILENO -# endif - )) { - /* Avoid perror since it may misuse buffers. */ - write_stderr(args[1]); - write_stderr(": I/O redirection failed\n"); - _exit(EXIT_TROUBLE); - } - - if (outname) - if (fdreopen( - STDOUT_FILENO, outname, - O_CREAT | O_TRUNC | O_WRONLY - ) < 0) { - /* Avoid perror since it may misuse buffers. */ - write_stderr(args[1]); - write_stderr(": "); - write_stderr(outname); - write_stderr(": cannot create\n"); - _exit(EXIT_TROUBLE); - } - VOID exec_RCS(args[1], (char**)(args + 1)); - notfound = args[1]; -# ifdef RCS_SHELL - if (errno == ENOEXEC) { - args[0] = notfound = RCS_SHELL; - VOID execv(args[0], (char**)args); - } -# endif - - /* Avoid perror since it may misuse buffers. */ - write_stderr(notfound); - write_stderr(": not found\n"); - _exit(EXIT_TROUBLE); - } - if (pid < 0) - efaterror("fork"); -# if has_waitpid - if (waitpid(pid, &wstatus, 0) < 0) - efaterror("waitpid"); -# else - { - pid_t w; - do { - if ((w = wait(&wstatus)) < 0) - efaterror("wait"); - } while (w != pid); - } -# endif -#else - static struct buf b; - char const *p; - - /* Use system(). On many hosts system() discards signals. Yuck! */ - p = args + 1; - bufscpy(&b, *p); - while (*++p) - bufargcat(&b, ' ', *p); - if (infd != -1 && infd != STDIN_FILENO) { - char redirection[32]; - VOID sprintf(redirection, "<&%d", infd); - bufscat(&b, redirection); - } - if (outname) - bufargcat(&b, '>', outname); - wstatus = system(b.string); -#endif -#endif - } - if (!WIFEXITED(wstatus)) { - if (WIFSIGNALED(wstatus)) { - psignal(WTERMSIG(wstatus), args[1]); - fatcleanup(1); - } - faterror("%s failed for unknown reason", args[1]); - } - return WEXITSTATUS(wstatus); -} - -#define CARGSMAX 20 -/* -* Run a command. -* infd, if not -1, is the input file descriptor. -* outname, if nonzero, is the name of the output file. -* The remaining arguments specify the command and its arguments. -*/ - int -#if has_prototypes -run(int infd, char const *outname, ...) -#else - /*VARARGS2*/ -run(infd, outname, va_alist) - int infd; - char const *outname; - va_dcl -#endif -{ - va_list ap; - char const *rgargs[CARGSMAX]; - register int i; - vararg_start(ap, outname); - for (i = 1; (rgargs[i++] = va_arg(ap, char const*)); ) - if (CARGSMAX <= i) - faterror("too many command arguments"); - va_end(ap); - return runv(infd, outname, rgargs); -} - - -int RCSversion; - - void -setRCSversion(str) - char const *str; -{ - static int oldversion; - - register char const *s = str + 2; - - if (*s) { - int v = VERSION_DEFAULT; - - if (oldversion) - redefined('V'); - oldversion = true; - v = 0; - while (isdigit(*s)) - v = 10*v + *s++ - '0'; - if (*s) - error("%s isn't a number", str); - else if (v < VERSION_min || VERSION_max < v) - error("%s out of range %d..%d", - str, VERSION_min, VERSION_max - ); - - RCSversion = VERSION(v); - } else { - printf("RCS version %s\n", RCS_version_string); - exit(0); - } -} - - int -getRCSINIT(argc, argv, newargv) - int argc; - char **argv, ***newargv; -{ - register char *p, *q, **pp; - char const *ev; - size_t n; - - if ((ev = cgetenv("RCSLOCALID"))) - setRCSLocalId(ev); - - if ((ev = cgetenv("RCSINCEXC"))) - setIncExc(ev); - - if (!(q = cgetenv("RCSINIT"))) - *newargv = argv; - else { - n = argc + 2; - /* - * Count spaces in RCSINIT to allocate a new arg vector. - * This is an upper bound, but it's OK even if too large. - */ - for (p = q; ; ) { - switch (*p++) { - default: - continue; - - case ' ': - case '\b': case '\f': case '\n': - case '\r': case '\t': case '\v': - n++; - continue; - - case '\0': - break; - } - break; - } - *newargv = pp = tnalloc(char*, n); - *pp++ = *argv++; /* copy program name */ - for (p = q; ; ) { - for (;;) { - switch (*q) { - case '\0': - goto copyrest; - - case ' ': - case '\b': case '\f': case '\n': - case '\r': case '\t': case '\v': - q++; - continue; - } - break; - } - *pp++ = p; - ++argc; - for (;;) { - switch ((*p++ = *q++)) { - case '\0': - goto copyrest; - - case '\\': - if (!*q) - goto copyrest; - p[-1] = *q++; - continue; - - default: - continue; - - case ' ': - case '\b': case '\f': case '\n': - case '\r': case '\t': case '\v': - break; - } - break; - } - p[-1] = '\0'; - } - copyrest: - while ((*pp++ = *argv++)) - continue; - } - return argc; -} - - -#define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i - -#if has_getuid - uid_t ruid() { cacheid(getuid()); } -#endif -#if has_setuid - uid_t euid() { cacheid(geteuid()); } -#endif - - -#if has_setuid - -/* - * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(), - * because it lets us switch back and forth between arbitrary users. - * If seteuid() doesn't work, we fall back on setuid(), - * which works if saved setuid is supported, - * unless the real or effective user is root. - * This area is such a mess that we always check switches at runtime. - */ - - static void -#if has_prototypes -set_uid_to(uid_t u) -#else - set_uid_to(u) uid_t u; -#endif -/* Become user u. */ -{ - static int looping; - - if (euid() == ruid()) - return; -#if (has_fork||has_spawn) && DIFF_ABSOLUTE -# if has_setreuid - if (setreuid(u==euid() ? ruid() : euid(), u) != 0) - efaterror("setuid"); -# else - if (seteuid(u) != 0) - efaterror("setuid"); -# endif -#endif - if (geteuid() != u) { - if (looping) - return; - looping = true; - faterror("root setuid not supported" + (u?5:0)); - } -} - -static int stick_with_euid; - - void -/* Ignore all calls to seteid() and setrid(). */ -nosetid() -{ - stick_with_euid = true; -} - - void -seteid() -/* Become effective user. */ -{ - if (!stick_with_euid) - set_uid_to(euid()); -} - - void -setrid() -/* Become real user. */ -{ - if (!stick_with_euid) - set_uid_to(ruid()); -} -#endif - - time_t -now() -{ - static time_t t; - if (!t && time(&t) == -1) - efaterror("time"); - return t; -} Index: gnu/usr.bin/rcs/lib/version.c =================================================================== --- gnu/usr.bin/rcs/lib/version.c (revision 255904) +++ gnu/usr.bin/rcs/lib/version.c (working copy) @@ -1,2 +0,0 @@ -#include "rcsbase.h" -char const RCS_version_string[] = "5.7"; Index: gnu/usr.bin/rcs/merge/Makefile =================================================================== --- gnu/usr.bin/rcs/merge/Makefile (revision 255904) +++ gnu/usr.bin/rcs/merge/Makefile (working copy) @@ -1,8 +0,0 @@ -PROG= merge -SRCS= merge.c -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/merge/merge.1 =================================================================== --- gnu/usr.bin/rcs/merge/merge.1 (revision 255904) +++ gnu/usr.bin/rcs/merge/merge.1 (working copy) @@ -1,137 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.TH MERGE 1 \*(Dt GNU -.SH NAME -merge \- three-way file merge -.SH SYNOPSIS -.B merge -[ -.I "options" -] -.I "file1 file2 file3" -.SH DESCRIPTION -.B merge -incorporates all changes that lead from -.I file2 -to -.I file3 -into -.IR file1 . -The result ordinarily goes into -.IR file1 . -.B merge -is useful for combining separate changes to an original. Suppose -.I file2 -is the original, and both -.I file1 -and -.I file3 -are modifications of -.IR file2 . -Then -.B merge -combines both changes. -.PP -A conflict occurs if both -.I file1 -and -.I file3 -have changes in a common segment of lines. -If a conflict is found, -.B merge -normally outputs a warning and brackets the conflict with -.B <<<<<<< -and -.B >>>>>>> -lines. -A typical conflict will look like this: -.LP -.RS -.nf -.BI <<<<<<< " file A" -.I "lines in file A" -.B "=======" -.I "lines in file B" -.BI >>>>>>> " file B" -.RE -.fi -.LP -If there are conflicts, the user should edit the result and delete one of the -alternatives. -.SH OPTIONS -.TP -.B \-A -Output conflicts using the -.B \-A -style of -.BR diff3 (1), -if supported by -.BR diff3 . -This merges all changes leading from -.I file2 -to -.I file3 -into -.IR file1 , -and generates the most verbose output. -.TP -\f3\-E\fP, \f3\-e\fP -These options specify conflict styles that generate less information -than -.BR \-A . -See -.BR diff3 (1) -for details. -The default is -.BR \-E . -With -.BR \-e , -.B merge -does not warn about conflicts. -.TP -.BI \-L " label" -This option may be given up to three times, and specifies labels -to be used in place of the corresponding file names in conflict reports. -That is, -.B "merge\ \-L\ x\ \-L\ y\ \-L\ z\ a\ b\ c" -generates output that looks like it came from files -.BR x , -.B y -and -.B z -instead of from files -.BR a , -.B b -and -.BR c . -.TP -.BI \-p -Send results to standard output instead of overwriting -.IR file1 . -.TP -.BI \-q -Quiet; do not warn about conflicts. -.TP -.BI \-V -Print \*r's version number. -.SH DIAGNOSTICS -Exit status is 0 for no conflicts, 1 for some conflicts, 2 for trouble. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH SEE ALSO -diff3(1), diff(1), rcsmerge(1), co(1). -.SH BUGS -It normally does not make sense to merge binary files as if they were text, but -.B merge -tries to do it anyway. -.br Index: gnu/usr.bin/rcs/merge/merge.c =================================================================== --- gnu/usr.bin/rcs/merge/merge.c (revision 255904) +++ gnu/usr.bin/rcs/merge/merge.c (working copy) @@ -1,113 +0,0 @@ -/* merge - three-way file merge */ - -/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#include "rcsbase.h" - -static void badoption P((char const*)); - -static char const usage[] = - "\nmerge: usage: merge [-AeEpqxX3] [-L lab [-L lab [-L lab]]] file1 file2 file3"; - - static void -badoption(a) - char const *a; -{ - error("unknown option: %s%s", a, usage); -} - - -mainProg(mergeId, "merge", "$FreeBSD$") -{ - register char const *a; - char const *arg[3], *label[3], *edarg = 0; - int labels, tostdout; - - labels = 0; - tostdout = false; - - for (; (a = *++argv) && *a++ == '-'; --argc) { - switch (*a++) { - case 'A': case 'E': case 'e': - if (edarg && edarg[1] != (*argv)[1]) - error("%s and %s are incompatible", - edarg, *argv - ); - edarg = *argv; - break; - - case 'p': tostdout = true; break; - case 'q': quietflag = true; break; - - case 'L': - if (3 <= labels) - faterror("too many -L options"); - if (!(label[labels++] = *++argv)) - faterror("-L needs following argument"); - --argc; - break; - - case 'V': - printf("RCS version %s\n", RCS_version_string); - exitmain(0); - - default: - badoption(a - 2); - continue; - } - if (*a) - badoption(a - 2); - } - - if (argc != 4) - faterror("%s arguments%s", - argc<4 ? "not enough" : "too many", usage - ); - - /* This copy keeps us `const'-clean. */ - arg[0] = argv[0]; - arg[1] = argv[1]; - arg[2] = argv[2]; - - for (; labels < 3; labels++) - label[labels] = arg[labels]; - - if (nerror) - exiterr(); - exitmain(merge(tostdout, edarg, label, arg)); -} - - -#if RCS_lint -# define exiterr mergeExit -#endif - void -exiterr() -{ - tempunlink(); - _exit(DIFF_TROUBLE); -} Index: gnu/usr.bin/rcs/rcs/Makefile =================================================================== --- gnu/usr.bin/rcs/rcs/Makefile (revision 255904) +++ gnu/usr.bin/rcs/rcs/Makefile (working copy) @@ -1,10 +0,0 @@ -# $FreeBSD$ - -PROG= rcs -MAN= rcs.1 rcsintro.1 rcsfile.5 -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/rcs/rcs.1 =================================================================== --- gnu/usr.bin/rcs/rcs/rcs.1 (revision 255904) +++ gnu/usr.bin/rcs/rcs/rcs.1 (working copy) @@ -1,454 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.if n .ds - \%-- -.if t .ds - \(em -.if !\n(.g \{\ -. if !\w|\*(lq| \{\ -. ds lq `` -. if \w'\(lq' .ds lq "\(lq -. \} -. if !\w|\*(rq| \{\ -. ds rq '' -. if \w'\(rq' .ds rq "\(rq -. \} -.\} -.TH RCS 1 \*(Dt GNU -.SH NAME -rcs \- change RCS file attributes -.SH SYNOPSIS -.B rcs -.IR "options file " .\|.\|. -.SH DESCRIPTION -.B rcs -creates new \*r files or changes attributes of existing ones. -An \*r file contains multiple revisions of text, -an access list, a change log, -descriptive text, -and some control attributes. -For -.B rcs -to work, the caller's login name must be on the access list, -except if the access list is empty, the caller is the owner of the file -or the superuser, or -the -.B \-i -option is present. -.PP -Pathnames matching an \*r suffix denote \*r files; -all others denote working files. -Names are paired as explained in -.BR ci (1). -Revision numbers use the syntax described in -.BR ci (1). -.SH OPTIONS -.TP -.B \-i -Create and initialize a new \*r file, but do not deposit any revision. -If the \*r file has no path prefix, try to place it -first into the subdirectory -.BR ./RCS , -and then into the current directory. -If the \*r file -already exists, print an error message. -.TP -.BI \-a "logins" -Append the login names appearing in the comma-separated list -.I logins -to the access list of the \*r file. -.TP -.BI \-A "oldfile" -Append the access list of -.I oldfile -to the access list of the \*r file. -.TP -.BR \-e [\f2logins\fP] -Erase the login names appearing in the comma-separated list -.I logins -from the access list of the \*r file. -If -.I logins -is omitted, erase the entire access list. -.TP -.BR \-b [\f2rev\fP] -Set the default branch to -.IR rev . -If -.I rev -is omitted, the default -branch is reset to the (dynamically) highest branch on the trunk. -.TP -.BI \-c string -Set the comment leader to -.IR string . -An initial -.BR ci , -or an -.B "rcs\ \-i" -without -.BR \-c , -guesses the comment leader from the suffix of the working filename. -.RS -.PP -This option is obsolescent, since \*r normally uses the preceding -.B $\&Log$ -line's prefix when inserting log lines during checkout (see -.BR co (1)). -However, older versions of \*r use the comment leader instead of the -.B $\&Log$ -line's prefix, so -if you plan to access a file with both old and new versions of \*r, -make sure its comment leader matches its -.B $\&Log$ -line prefix. -.RE -.TP -.BI \-k subst -Set the default keyword substitution to -.IR subst . -The effect of keyword substitution is described in -.BR co (1). -Giving an explicit -.B \-k -option to -.BR co , -.BR rcsdiff , -and -.B rcsmerge -overrides this default. -Beware -.BR "rcs\ \-kv", -because -.B \-kv -is incompatible with -.BR "co\ \-l". -Use -.B "rcs\ \-kkv" -to restore the normal default keyword substitution. -.TP -.BR \-l [\f2rev\fP] -Lock the revision with number -.IR rev . -If a branch is given, lock the latest revision on that branch. -If -.I rev -is omitted, lock the latest revision on the default branch. -Locking prevents overlapping changes. -If someone else already holds the lock, the lock is broken as with -.B "rcs\ \-u" -(see below). -.TP -.BR \-u [\f2rev\fP] -Unlock the revision with number -.IR rev . -If a branch is given, unlock the latest revision on that branch. -If -.I rev -is omitted, remove the latest lock held by the caller. -Normally, only the locker of a revision can unlock it. -Somebody else unlocking a revision breaks the lock. -This causes a mail message to be sent to the original locker. -The message contains a commentary solicited from the breaker. -The commentary is terminated by end-of-file or by a line containing -.BR \&. "\ by" -itself. -.TP -.B \-L -Set locking to -.IR strict . -Strict locking means that the owner -of an \*r file is not exempt from locking for checkin. -This option should be used for files that are shared. -.TP -.B \-U -Set locking to non-strict. Non-strict locking means that the owner of -a file need not lock a revision for checkin. -This option should -.I not -be used for files that are shared. -Whether default locking is strict is determined by your system administrator, -but it is normally strict. -.TP -\f3\-m\fP\f2rev\fP\f3:\fP\f2msg\fP -Replace revision -.IR rev 's -log message with -.IR msg . -.TP -.B \-M -Do not send mail when breaking somebody else's lock. -This option is not meant for casual use; -it is meant for programs that warn users by other means, and invoke -.B "rcs\ \-u" -only as a low-level lock-breaking operation. -.TP -\f3\-n\fP\f2name\fP[\f3:\fP[\f2rev\fP]] -Associate the symbolic name -.I name -with the branch or -revision -.IR rev . -Delete the symbolic name if both -.B : -and -.I rev -are omitted; otherwise, print an error message if -.I name -is already associated with -another number. -If -.I rev -is symbolic, it is expanded before association. -A -.I rev -consisting of a branch number followed by a -.B .\& -stands for the current latest revision in the branch. -A -.B : -with an empty -.I rev -stands for the current latest revision on the default branch, -normally the trunk. -For example, -.BI "rcs\ \-n" name ":\ RCS/*" -associates -.I name -with the current latest revision of all the named \*r files; -this contrasts with -.BI "rcs\ \-n" name ":$\ RCS/*" -which associates -.I name -with the revision numbers extracted from keyword strings -in the corresponding working files. -.TP -\f3\-N\fP\f2name\fP[\f3:\fP[\f2rev\fP]] -Act like -.BR \-n , -except override any previous assignment of -.IR name . -.TP -.BI \-o range -deletes (\*(lqoutdates\*(rq) the revisions given by -.IR range . -A range consisting of a single revision number means that revision. -A range consisting of a branch number means the latest revision on that -branch. -A range of the form -.IB rev1 : rev2 -means -revisions -.I rev1 -to -.I rev2 -on the same branch, -.BI : rev -means from the beginning of the branch containing -.I rev -up to and including -.IR rev , -and -.IB rev : -means -from revision -.I rev -to the end of the branch containing -.IR rev . -None of the outdated revisions can have branches or locks. -.TP -.B \-q -Run quietly; do not print diagnostics. -.TP -.B \-I -Run interactively, even if the standard input is not a terminal. -.TP -.B \-s\f2state\fP\f1[\fP:\f2rev\fP\f1]\fP -Set the state attribute of the revision -.I rev -to -.IR state . -If -.I rev -is a branch number, assume the latest revision on that branch. -If -.I rev -is omitted, assume the latest revision on the default branch. -Any identifier is acceptable for -.IR state . -A useful set of states -is -.B Exp -(for experimental), -.B Stab -(for stable), and -.B Rel -(for -released). -By default, -.BR ci (1) -sets the state of a revision to -.BR Exp . -.TP -.BR \-t [\f2file\fP] -Write descriptive text from the contents of the named -.I file -into the \*r file, deleting the existing text. -The -.IR file -pathname cannot begin with -.BR \- . -If -.I file -is omitted, obtain the text from standard input, -terminated by end-of-file or by a line containing -.BR \&. "\ by" -itself. -Prompt for the text if interaction is possible; see -.BR \-I . -With -.BR \-i , -descriptive text is obtained -even if -.B \-t -is not given. -.TP -.BI \-t\- string -Write descriptive text from the -.I string -into the \*r file, deleting the existing text. -.TP -.B \-T -Preserve the modification time on the \*r file -unless a revision is removed. -This option can suppress extensive recompilation caused by a -.BR make (1) -dependency of some copy of the working file on the \*r file. -Use this option with care; it can suppress recompilation even when it is needed, -i.e. when a change to the \*r file -would mean a change to keyword strings in the working file. -.TP -.BI \-V -Print \*r's version number. -.TP -.BI \-V n -Emulate \*r version -.IR n . -See -.BR co (1) -for details. -.TP -.BI \-x "suffixes" -Use -.I suffixes -to characterize \*r files. -See -.BR ci (1) -for details. -.TP -.BI \-z zone -Use -.I zone -as the default time zone. -This option has no effect; -it is present for compatibility with other \*r commands. -.PP -At least one explicit option must be given, -to ensure compatibility with future planned extensions -to the -.B rcs -command. -.SH COMPATIBILITY -The -.BI \-b rev -option generates an \*r file that cannot be parsed by \*r version 3 or earlier. -.PP -The -.BI \-k subst -options (except -.BR \-kkv ) -generate an \*r file that cannot be parsed by \*r version 4 or earlier. -.PP -Use -.BI "rcs \-V" n -to make an \*r file acceptable to \*r version -.I n -by discarding information that would confuse version -.IR n . -.PP -\*r version 5.5 and earlier does not support the -.B \-x -option, and requires a -.B ,v -suffix on an \*r pathname. -.SH FILES -.B rcs -accesses files much as -.BR ci (1) -does, -except that it uses the effective user for all accesses, -it does not write the working file or its directory, -and it does not even read the working file unless a revision number of -.B $ -is specified. -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -See -.BR ci (1) -for details. -.SH DIAGNOSTICS -The \*r pathname and the revisions outdated are written to -the diagnostic output. -The exit status is zero if and only if all operations were successful. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH "SEE ALSO" -rcsintro(1), co(1), ci(1), ident(1), rcsclean(1), rcsdiff(1), -rcsmerge(1), rlog(1), rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.SH BUGS -A catastrophe (e.g. a system crash) can cause \*r to leave behind -a semaphore file that causes later invocations of \*r to claim -that the \*r file is in use. -To fix this, remove the semaphore file. -A semaphore file's name typically begins with -.B , -or ends with -.BR _ . -.PP -The separator for revision ranges in the -.B \-o -option used to be -.B \- -instead of -.BR : , -but this leads to confusion when symbolic names contain -.BR \- . -For backwards compatibility -.B "rcs \-o" -still supports the old -.B \- -separator, but it warns about this obsolete use. -.PP -Symbolic names need not refer to existing revisions or branches. -For example, the -.B \-o -option does not remove symbolic names for the outdated revisions; you must use -.B \-n -to remove the names. -.br Index: gnu/usr.bin/rcs/rcs/rcs.c =================================================================== --- gnu/usr.bin/rcs/rcs/rcs.c (revision 255904) +++ gnu/usr.bin/rcs/rcs/rcs.c (working copy) @@ -1,1629 +0,0 @@ -/* Change RCS file attributes. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.21 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.20 1995/06/01 16:23:43 eggert - * (main): Warn if no options were given. Punctuate messages properly. - * - * (sendmail): Rewind mailmess before flushing it. - * Output another warning if mail should work but fails. - * - * (buildeltatext): Pass "--binary" if -kb and if --binary makes a difference. - * - * Revision 5.19 1994/03/17 14:05:48 eggert - * Use ORCSerror to clean up after a fatal error. Remove lint. - * Specify subprocess input via file descriptor, not file name. Remove lint. - * Flush stderr after prompt. - * - * Revision 5.18 1993/11/09 17:40:15 eggert - * -V now prints version on stdout and exits. Don't print usage twice. - * - * Revision 5.17 1993/11/03 17:42:27 eggert - * Add -z. Don't lose track of -m or -t when there are no other changes. - * Don't discard ignored phrases. Improve quality of diagnostics. - * - * Revision 5.16 1992/07/28 16:12:44 eggert - * rcs -l now asks whether you want to break the lock. - * Add -V. Set RCS file's mode and time at right moment. - * - * Revision 5.15 1992/02/17 23:02:20 eggert - * Add -T. - * - * Revision 5.14 1992/01/27 16:42:53 eggert - * Add -M. Avoid invoking umask(); it's one less thing to configure. - * Add support for bad_creat0. lint -> RCS_lint - * - * Revision 5.13 1992/01/06 02:42:34 eggert - * Avoid changing RCS file in common cases where no change can occur. - * - * Revision 5.12 1991/11/20 17:58:08 eggert - * Don't read the delta tree from a nonexistent RCS file. - * - * Revision 5.11 1991/10/07 17:32:46 eggert - * Remove lint. - * - * Revision 5.10 1991/08/19 23:17:54 eggert - * Add -m, -r$, piece tables. Revision separator is `:', not `-'. Tune. - * - * Revision 5.9 1991/04/21 11:58:18 eggert - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.8 1991/02/25 07:12:38 eggert - * strsave -> str_save (DG/UX name clash) - * 0444 -> S_IRUSR|S_IRGRP|S_IROTH for portability - * - * Revision 5.7 1990/12/18 17:19:21 eggert - * Fix bug with multiple -n and -N options. - * - * Revision 5.6 1990/12/04 05:18:40 eggert - * Use -I for prompts and -q for diagnostics. - * - * Revision 5.5 1990/11/11 00:06:35 eggert - * Fix `rcs -e' core dump. - * - * Revision 5.4 1990/11/01 05:03:33 eggert - * Add -I and new -t behavior. Permit arbitrary data in logs. - * - * Revision 5.3 1990/10/04 06:30:16 eggert - * Accumulate exit status across files. - * - * Revision 5.2 1990/09/04 08:02:17 eggert - * Standardize yes-or-no procedure. - * - * Revision 5.1 1990/08/29 07:13:51 eggert - * Remove unused setuid support. Clean old log messages too. - * - * Revision 5.0 1990/08/22 08:12:42 eggert - * Don't lose names when applying -a option to multiple files. - * Remove compile-time limits; use malloc instead. Add setuid support. - * Permit dates past 1999/12/31. Make lock and temp files faster and safer. - * Ansify and Posixate. Add -V. Fix umask bug. Make linting easier. Tune. - * Yield proper exit status. Check diff's output. - * - * Revision 4.11 89/05/01 15:12:06 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.10 88/11/08 16:01:54 narten - * didn't install previous patch correctly - * - * Revision 4.9 88/11/08 13:56:01 narten - * removed include (not needed) - * minor fix for -A option - * - * Revision 4.8 88/08/09 19:12:27 eggert - * Don't access freed storage. - * Use execv(), not system(); yield proper exit status; remove lint. - * - * Revision 4.7 87/12/18 11:37:17 narten - * lint cleanups (Guy Harris) - * - * Revision 4.6 87/10/18 10:28:48 narten - * Updating verison numbers. Changes relative to 1.1 are actually - * relative to 4.3 - * - * Revision 1.4 87/09/24 13:58:52 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.3 87/03/27 14:21:55 jenkins - * Port to suns - * - * Revision 1.2 85/12/17 13:59:09 albitz - * Changed setstate to rcs_setstate because of conflict with random.o. - * - * Revision 4.3 83/12/15 12:27:33 wft - * rcs -u now breaks most recent lock if it can't find a lock by the caller. - * - * Revision 4.2 83/12/05 10:18:20 wft - * Added conditional compilation for sending mail. - * Alternatives: V4_2BSD, V6, USG, and other. - * - * Revision 4.1 83/05/10 16:43:02 wft - * Simplified breaklock(); added calls to findlock() and getcaller(). - * Added option -b (default branch). Updated -s and -w for -b. - * Removed calls to stat(); now done by pairfilenames(). - * Replaced most catchints() calls with restoreints(). - * Removed check for exit status of delivermail(). - * Directed all interactive output to stderr. - * - * Revision 3.9.1.1 83/12/02 22:08:51 wft - * Added conditional compilation for 4.2 sendmail and 4.1 delivermail. - * - * Revision 3.9 83/02/15 15:38:39 wft - * Added call to fastcopy() to copy remainder of RCS file. - * - * Revision 3.8 83/01/18 17:37:51 wft - * Changed sendmail(): now uses delivermail, and asks whether to break the lock. - * - * Revision 3.7 83/01/15 18:04:25 wft - * Removed putree(); replaced with puttree() in rcssyn.c. - * Combined putdellog() and scanlogtext(); deleted putdellog(). - * Cleaned up diagnostics and error messages. Fixed problem with - * mutilated files in case of deletions in 2 files in a single command. - * Changed marking of selector from 'D' to DELETE. - * - * Revision 3.6 83/01/14 15:37:31 wft - * Added ignoring of interrupts while new RCS file is renamed; - * Avoids deletion of RCS files by interrupts. - * - * Revision 3.5 82/12/10 21:11:39 wft - * Removed unused variables, fixed checking of return code from diff, - * introduced variant COMPAT2 for skipping Suffix on -A files. - * - * Revision 3.4 82/12/04 13:18:20 wft - * Replaced getdelta() with gettree(), changed breaklock to update - * field lockedby, added some diagnostics. - * - * Revision 3.3 82/12/03 17:08:04 wft - * Replaced getlogin() with getpwuid(), flcose() with ffclose(), - * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x). - * fixed -u for missing revno. Disambiguated structure members. - * - * Revision 3.2 82/10/18 21:05:07 wft - * rcs -i now generates a file mode given by the umask minus write permission; - * otherwise, rcs keeps the mode, but removes write permission. - * I added a check for write error, fixed call to getlogin(), replaced - * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed - * conflicting, long identifiers. - * - * Revision 3.1 82/10/13 16:11:07 wft - * fixed type of variables receiving from getc() (char -> int). - */ - - -#include "rcsbase.h" - -struct Lockrev { - char const *revno; - struct Lockrev * nextrev; -}; - -struct Symrev { - char const *revno; - char const *ssymbol; - int override; - struct Symrev * nextsym; -}; - -struct Message { - char const *revno; - struct cbuf message; - struct Message *nextmessage; -}; - -struct Status { - char const *revno; - char const *status; - struct Status * nextstatus; -}; - -enum changeaccess {append, erase}; -struct chaccess { - char const *login; - enum changeaccess command; - struct chaccess *nextchaccess; -}; - -struct delrevpair { - char const *strt; - char const *end; - int code; -}; - -static int branchpoint P((struct hshentry*,struct hshentry*)); -static int breaklock P((struct hshentry const*)); -static int buildeltatext P((struct hshentries const*)); -static int doaccess P((void)); -static int doassoc P((void)); -static int dolocks P((void)); -static int domessages P((void)); -static int rcs_setstate P((char const*,char const*)); -static int removerevs P((void)); -static int sendmail P((char const*,char const*)); -static int setlock P((char const*)); -static struct Lockrev **rmnewlocklst P((char const*)); -static struct hshentry *searchcutpt P((char const*,int,struct hshentries*)); -static void buildtree P((void)); -static void cleanup P((void)); -static void getaccessor P((char*,enum changeaccess)); -static void getassoclst P((int,char*)); -static void getchaccess P((char const*,enum changeaccess)); -static void getdelrev P((char*)); -static void getmessage P((char*)); -static void getstates P((char*)); -static void scanlogtext P((struct hshentry*,int)); - -static struct buf numrev; -static char const *headstate; -static int chgheadstate, exitstatus, lockhead, unlockcaller; -static int suppress_mail; -static struct Lockrev *newlocklst, *rmvlocklst; -static struct Message *messagelst, **nextmessage; -static struct Status *statelst, **nextstate; -static struct Symrev *assoclst, **nextassoc; -static struct chaccess *chaccess, **nextchaccess; -static struct delrevpair delrev; -static struct hshentry *cuthead, *cuttail, *delstrt; -static struct hshentries *gendeltas; - -mainProg(rcsId, "rcs", "$FreeBSD$") -{ - static char const cmdusage[] = - "\nrcs usage: rcs -{ae}logins -Afile -{blu}[rev] -cstring -{iILqTU} -ksubst -mrev:msg -{nN}name[:[rev]] -orange -sstate[:rev] -t[text] -Vn -xsuff -zzone file ..."; - - char *a, **newargv, *textfile; - char const *branchsym, *commsyml; - int branchflag, changed, expmode, initflag; - int strictlock, strict_selected, textflag; - int keepRCStime, Ttimeflag; - size_t commsymlen; - struct buf branchnum; - struct Lockrev *lockpt; - struct Lockrev **curlock, **rmvlock; - struct Status * curstate; - - nosetid(); - - nextassoc = &assoclst; - nextchaccess = &chaccess; - nextmessage = &messagelst; - nextstate = &statelst; - branchsym = commsyml = textfile = 0; - branchflag = strictlock = false; - bufautobegin(&branchnum); - commsymlen = 0; - curlock = &newlocklst; - rmvlock = &rmvlocklst; - expmode = -1; - suffixes = X_DEFAULT; - initflag= textflag = false; - strict_selected = 0; - Ttimeflag = false; - - /* preprocessing command options */ - if (1 < argc && argv[1][0] != '-') - warn("No options were given; this usage is obsolescent."); - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - while (a = *++argv, 0<--argc && *a++=='-') { - switch (*a++) { - - case 'i': /* initial version */ - initflag = true; - break; - - case 'b': /* change default branch */ - if (branchflag) redefined('b'); - branchflag= true; - branchsym = a; - break; - - case 'c': /* change comment symbol */ - if (commsyml) redefined('c'); - commsyml = a; - commsymlen = strlen(a); - break; - - case 'a': /* add new accessor */ - getaccessor(*argv+1, append); - break; - - case 'A': /* append access list according to accessfile */ - if (!*a) { - error("missing pathname after -A"); - break; - } - *argv = a; - if (0 < pairnames(1,argv,rcsreadopen,true,false)) { - while (AccessList) { - getchaccess(str_save(AccessList->login),append); - AccessList = AccessList->nextaccess; - } - Izclose(&finptr); - } - break; - - case 'e': /* remove accessors */ - getaccessor(*argv+1, erase); - break; - - case 'l': /* lock a revision if it is unlocked */ - if (!*a) { - /* Lock head or default branch. */ - lockhead = true; - break; - } - *curlock = lockpt = talloc(struct Lockrev); - lockpt->revno = a; - lockpt->nextrev = 0; - curlock = &lockpt->nextrev; - break; - - case 'u': /* release lock of a locked revision */ - if (!*a) { - unlockcaller=true; - break; - } - *rmvlock = lockpt = talloc(struct Lockrev); - lockpt->revno = a; - lockpt->nextrev = 0; - rmvlock = &lockpt->nextrev; - curlock = rmnewlocklst(lockpt->revno); - break; - - case 'L': /* set strict locking */ - if (strict_selected) { - if (!strictlock) /* Already selected -U? */ - warn("-U overridden by -L"); - } - strictlock = true; - strict_selected = true; - break; - - case 'U': /* release strict locking */ - if (strict_selected) { - if (strictlock) /* Already selected -L? */ - warn("-L overridden by -U"); - } - strict_selected = true; - break; - - case 'n': /* add new association: error, if name exists */ - if (!*a) { - error("missing symbolic name after -n"); - break; - } - getassoclst(false, (*argv)+1); - break; - - case 'N': /* add or change association */ - if (!*a) { - error("missing symbolic name after -N"); - break; - } - getassoclst(true, (*argv)+1); - break; - - case 'm': /* change log message */ - getmessage(a); - break; - - case 'M': /* do not send mail */ - suppress_mail = true; - break; - - case 'o': /* delete revisions */ - if (delrev.strt) redefined('o'); - if (!*a) { - error("missing revision range after -o"); - break; - } - getdelrev( (*argv)+1 ); - break; - - case 's': /* change state attribute of a revision */ - if (!*a) { - error("state missing after -s"); - break; - } - getstates( (*argv)+1); - break; - - case 't': /* change descriptive text */ - textflag=true; - if (*a) { - if (textfile) redefined('t'); - textfile = a; - } - break; - - case 'T': /* do not update last-mod time for minor changes */ - if (*a) - goto unknown; - Ttimeflag = true; - break; - - case 'I': - interactiveflag = true; - break; - - case 'q': - quietflag = true; - break; - - case 'x': - suffixes = a; - break; - - case 'V': - setRCSversion(*argv); - break; - - case 'z': - zone_set(a); - break; - - case 'k': /* set keyword expand mode */ - if (0 <= expmode) redefined('k'); - if (0 <= (expmode = str2expmode(a))) - break; - /* fall into */ - default: - unknown: - error("unknown option: %s%s", *argv, cmdusage); - }; - } /* end processing of options */ - - /* Now handle all pathnames. */ - if (nerror) cleanup(); - else if (argc < 1) faterror("no input file%s", cmdusage); - else for (; 0 < argc; cleanup(), ++argv, --argc) { - - ffree(); - - if ( initflag ) { - switch (pairnames(argc, argv, rcswriteopen, false, false)) { - case -1: break; /* not exist; ok */ - case 0: continue; /* error */ - case 1: rcserror("already exists"); - continue; - } - } - else { - switch (pairnames(argc, argv, rcswriteopen, true, false)) { - case -1: continue; /* not exist */ - case 0: continue; /* errors */ - case 1: break; /* file exists; ok*/ - } - } - - - /* - * RCSname contains the name of the RCS file, and - * workname contains the name of the working file. - * if !initflag, finptr contains the file descriptor for the - * RCS file. The admin node is initialized. - */ - - diagnose("RCS file: %s\n", RCSname); - - changed = initflag | textflag; - keepRCStime = Ttimeflag; - if (!initflag) { - if (!checkaccesslist()) continue; - gettree(); /* Read the delta tree. */ - } - - /* update admin. node */ - if (strict_selected) { - changed |= StrictLocks ^ strictlock; - StrictLocks = strictlock; - } - if ( - commsyml && - ( - commsymlen != Comment.size || - memcmp(commsyml, Comment.string, commsymlen) != 0 - ) - ) { - Comment.string = commsyml; - Comment.size = strlen(commsyml); - changed = true; - } - if (0 <= expmode && Expand != expmode) { - Expand = expmode; - changed = true; - } - - /* update default branch */ - if (branchflag && expandsym(branchsym, &branchnum)) { - if (countnumflds(branchnum.string)) { - if (cmpnum(Dbranch, branchnum.string) != 0) { - Dbranch = branchnum.string; - changed = true; - } - } else - if (Dbranch) { - Dbranch = 0; - changed = true; - } - } - - changed |= doaccess(); /* Update access list. */ - - changed |= doassoc(); /* Update association list. */ - - changed |= dolocks(); /* Update locks. */ - - changed |= domessages(); /* Update log messages. */ - - /* update state attribution */ - if (chgheadstate) { - /* change state of default branch or head */ - if (!Dbranch) { - if (!Head) - rcswarn("can't change states in an empty tree"); - else if (strcmp(Head->state, headstate) != 0) { - Head->state = headstate; - changed = true; - } - } else - changed |= rcs_setstate(Dbranch,headstate); - } - for (curstate = statelst; curstate; curstate = curstate->nextstatus) - changed |= rcs_setstate(curstate->revno,curstate->status); - - cuthead = cuttail = 0; - if (delrev.strt && removerevs()) { - /* rebuild delta tree if some deltas are deleted */ - if ( cuttail ) - VOID genrevs( - cuttail->num, (char *)0, (char *)0, (char *)0, - &gendeltas - ); - buildtree(); - changed = true; - keepRCStime = false; - } - - if (nerror) - continue; - - putadmin(); - if ( Head ) - puttree(Head, frewrite); - putdesc(textflag,textfile); - - if ( Head) { - if (delrev.strt || messagelst) { - if (!cuttail || buildeltatext(gendeltas)) { - advise_access(finptr, MADV_SEQUENTIAL); - scanlogtext((struct hshentry *)0, false); - /* copy rest of delta text nodes that are not deleted */ - changed = true; - } - } - } - - if (initflag) { - /* Adjust things for donerewrite's sake. */ - if (stat(workname, &RCSstat) != 0) { -# if bad_creat0 - mode_t m = umask(0); - (void) umask(m); - RCSstat.st_mode = (S_IRUSR|S_IRGRP|S_IROTH) & ~m; -# else - changed = -1; -# endif - } - RCSstat.st_nlink = 0; - keepRCStime = false; - } - if (donerewrite(changed, - keepRCStime ? RCSstat.st_mtime : (time_t)-1 - ) != 0) - break; - - diagnose("done\n"); - } - - tempunlink(); - exitmain(exitstatus); -} /* end of main (rcs) */ - - static void -cleanup() -{ - if (nerror) exitstatus = EXIT_FAILURE; - Izclose(&finptr); - Ozclose(&fcopy); - ORCSclose(); - dirtempunlink(); -} - - void -exiterr() -{ - ORCSerror(); - dirtempunlink(); - tempunlink(); - _exit(EXIT_FAILURE); -} - - - static void -getassoclst(flag, sp) -int flag; -char * sp; -/* Function: associate a symbolic name to a revision or branch, */ -/* and store in assoclst */ - -{ - struct Symrev * pt; - char const *temp; - int c; - - while ((c = *++sp) == ' ' || c == '\t' || c =='\n') - continue; - temp = sp; - sp = checksym(sp, ':'); /* check for invalid symbolic name */ - c = *sp; *sp = '\0'; - while( c == ' ' || c == '\t' || c == '\n') c = *++sp; - - if ( c != ':' && c != '\0') { - error("invalid string %s after option -n or -N",sp); - return; - } - - pt = talloc(struct Symrev); - pt->ssymbol = temp; - pt->override = flag; - if (c == '\0') /* delete symbol */ - pt->revno = 0; - else { - while ((c = *++sp) == ' ' || c == '\n' || c == '\t') - continue; - pt->revno = sp; - } - pt->nextsym = 0; - *nextassoc = pt; - nextassoc = &pt->nextsym; -} - - - static void -getchaccess(login, command) - char const *login; - enum changeaccess command; -{ - register struct chaccess *pt; - - pt = talloc(struct chaccess); - pt->login = login; - pt->command = command; - pt->nextchaccess = 0; - *nextchaccess = pt; - nextchaccess = &pt->nextchaccess; -} - - - - static void -getaccessor(opt, command) - char *opt; - enum changeaccess command; -/* Function: get the accessor list of options -e and -a, */ -/* and store in chaccess */ - - -{ - register c; - register char *sp; - - sp = opt; - while ((c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') - continue; - if ( c == '\0') { - if (command == erase && sp-opt == 1) { - getchaccess((char*)0, command); - return; - } - error("missing login name after option -a or -e"); - return; - } - - while( c != '\0') { - getchaccess(sp, command); - sp = checkid(sp,','); - c = *sp; *sp = '\0'; - while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp); - } -} - - - static void -getmessage(option) - char *option; -{ - struct Message *pt; - struct cbuf cb; - char *m; - - if (!(m = strchr(option, ':'))) { - error("-m option lacks revision number"); - return; - } - *m++ = 0; - cb = cleanlogmsg(m, strlen(m)); - if (!cb.size) { - error("-m option lacks log message"); - return; - } - pt = talloc(struct Message); - pt->revno = option; - pt->message = cb; - pt->nextmessage = 0; - *nextmessage = pt; - nextmessage = &pt->nextmessage; -} - - - static void -getstates(sp) -char *sp; -/* Function: get one state attribute and the corresponding */ -/* revision and store in statelst */ - -{ - char const *temp; - struct Status *pt; - register c; - - while ((c = *++sp) ==' ' || c == '\t' || c == '\n') - continue; - temp = sp; - sp = checkid(sp,':'); /* check for invalid state attribute */ - c = *sp; *sp = '\0'; - while( c == ' ' || c == '\t' || c == '\n' ) c = *++sp; - - if ( c == '\0' ) { /* change state of def. branch or Head */ - chgheadstate = true; - headstate = temp; - return; - } - else if ( c != ':' ) { - error("missing ':' after state in option -s"); - return; - } - - while ((c = *++sp) == ' ' || c == '\t' || c == '\n') - continue; - pt = talloc(struct Status); - pt->status = temp; - pt->revno = sp; - pt->nextstatus = 0; - *nextstate = pt; - nextstate = &pt->nextstatus; -} - - - - static void -getdelrev(sp) -char *sp; -/* Function: get revision range or branch to be deleted, */ -/* and place in delrev */ -{ - int c; - struct delrevpair *pt; - int separator; - - pt = &delrev; - while ((c = (*++sp)) == ' ' || c == '\n' || c == '\t') - continue; - - /* Support old ambiguous '-' syntax; this will go away. */ - if (strchr(sp,':')) - separator = ':'; - else { - if (strchr(sp,'-') && VERSION(5) <= RCSversion) - warn("`-' is obsolete in `-o%s'; use `:' instead", sp); - separator = '-'; - } - - if (c == separator) { /* -o:rev */ - while ((c = (*++sp)) == ' ' || c == '\n' || c == '\t') - continue; - pt->strt = sp; pt->code = 1; - while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp); - *sp = '\0'; - pt->end = 0; - return; - } - else { - pt->strt = sp; - while( c != ' ' && c != '\n' && c != '\t' && c != '\0' - && c != separator ) c = *++sp; - *sp = '\0'; - while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp; - if ( c == '\0' ) { /* -o rev or branch */ - pt->code = 0; - pt->end = 0; - return; - } - if (c != separator) { - error("invalid range %s %s after -o", pt->strt, sp); - } - while ((c = *++sp) == ' ' || c == '\n' || c == '\t') - continue; - if (!c) { /* -orev: */ - pt->code = 2; - pt->end = 0; - return; - } - } - /* -orev1:rev2 */ - pt->end = sp; pt->code = 3; - while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp; - *sp = '\0'; -} - - - - - static void -scanlogtext(delta,edit) - struct hshentry *delta; - int edit; -/* Function: Scans delta text nodes up to and including the one given - * by delta, or up to last one present, if !delta. - * For the one given by delta (if delta), the log message is saved into - * delta->log if delta==cuttail; the text is edited if EDIT is set, else copied. - * Assumes the initial lexeme must be read in first. - * Does not advance nexttok after it is finished, except if !delta. - */ -{ - struct hshentry const *nextdelta; - struct cbuf cb; - - for (;;) { - foutptr = 0; - if (eoflex()) { - if(delta) - rcsfaterror("can't find delta for revision %s", - delta->num - ); - return; /* no more delta text nodes */ - } - nextlex(); - if (!(nextdelta=getnum())) - fatserror("delta number corrupted"); - if (nextdelta->selector) { - foutptr = frewrite; - aprintf(frewrite,DELNUMFORM,nextdelta->num,Klog); - } - getkeystring(Klog); - if (nextdelta == cuttail) { - cb = savestring(&curlogbuf); - if (!delta->log.string) - delta->log = cleanlogmsg(curlogbuf.string, cb.size); - nextlex(); - delta->igtext = getphrases(Ktext); - } else { - if (nextdelta->log.string && nextdelta->selector) { - foutptr = 0; - readstring(); - foutptr = frewrite; - putstring(foutptr, false, nextdelta->log, true); - afputc(nextc, foutptr); - } else - readstring(); - ignorephrases(Ktext); - } - getkeystring(Ktext); - - if (delta==nextdelta) - break; - readstring(); /* skip over it */ - - } - /* got the one we're looking for */ - if (edit) - editstring((struct hshentry*)0); - else - enterstring(); -} - - - - static struct Lockrev ** -rmnewlocklst(which) - char const *which; -/* Remove lock to revision WHICH from newlocklst. */ -{ - struct Lockrev *pt, **pre; - - pre = &newlocklst; - while ((pt = *pre)) - if (strcmp(pt->revno, which) != 0) - pre = &pt->nextrev; - else { - *pre = pt->nextrev; - tfree(pt); - } - return pre; -} - - - - static int -doaccess() -{ - register struct chaccess *ch; - register struct access **p, *t; - register int changed = false; - - for (ch = chaccess; ch; ch = ch->nextchaccess) { - switch (ch->command) { - case erase: - if (!ch->login) { - if (AccessList) { - AccessList = 0; - changed = true; - } - } else - for (p = &AccessList; (t = *p); p = &t->nextaccess) - if (strcmp(ch->login, t->login) == 0) { - *p = t->nextaccess; - changed = true; - break; - } - break; - case append: - for (p = &AccessList; ; p = &t->nextaccess) - if (!(t = *p)) { - *p = t = ftalloc(struct access); - t->login = ch->login; - t->nextaccess = 0; - changed = true; - break; - } else if (strcmp(ch->login, t->login) == 0) - break; - break; - } - } - return changed; -} - - - static int -sendmail(Delta, who) - char const *Delta, *who; -/* Function: mail to who, informing him that his lock on delta was - * broken by caller. Ask first whether to go ahead. Return false on - * error or if user decides not to break the lock. - */ -{ -#ifdef SENDMAIL - char const *messagefile; - int old1, old2, c, status; - FILE * mailmess; -#endif - - - aprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who); - if (suppress_mail) - return true; - if (!yesorno(false, "Do you want to break the lock? [ny](n): ")) - return false; - - /* go ahead with breaking */ -#ifdef SENDMAIL - messagefile = maketemp(0); - if (!(mailmess = fopenSafer(messagefile, "w+"))) { - efaterror(messagefile); - } - - aprintf(mailmess, "Subject: Broken lock on %s\n\nYour lock on revision %s of file %s\nhas been broken by %s for the following reason:\n", - basefilename(RCSname), Delta, getfullRCSname(), getcaller() - ); - aputs("State the reason for breaking the lock:\n(terminate with single '.' or end of file)\n>> ", stderr); - eflush(); - - old1 = '\n'; old2 = ' '; - for (; ;) { - c = getcstdin(); - if (feof(stdin)) { - aprintf(mailmess, "%c\n", old1); - break; - } - else if ( c == '\n' && old1 == '.' && old2 == '\n') - break; - else { - afputc(old1, mailmess); - old2 = old1; old1 = c; - if (c == '\n') { - aputs(">> ", stderr); - eflush(); - } - } - } - Orewind(mailmess); - aflush(mailmess); - status = run(fileno(mailmess), (char*)0, SENDMAIL, who, (char*)0); - Ozclose(&mailmess); - if (status == 0) - return true; - warn("Mail failed."); -#endif - warn("Mail notification of broken locks is not available."); - warn("Please tell `%s' why you broke the lock.", who); - return(true); -} - - - - static int -breaklock(delta) - struct hshentry const *delta; -/* function: Finds the lock held by caller on delta, - * and removes it. - * Sends mail if a lock different from the caller's is broken. - * Prints an error message if there is no such lock or error. - */ -{ - register struct rcslock *next, **trail; - char const *num; - - num=delta->num; - for (trail = &Locks; (next = *trail); trail = &next->nextlock) - if (strcmp(num, next->delta->num) == 0) { - if ( - strcmp(getcaller(),next->login) != 0 - && !sendmail(num, next->login) - ) { - rcserror("revision %s still locked by %s", - num, next->login - ); - return false; - } - diagnose("%s unlocked\n", next->delta->num); - *trail = next->nextlock; - next->delta->lockedby = 0; - return true; - } - rcserror("no lock set on revision %s", num); - return false; -} - - - - static struct hshentry * -searchcutpt(object, length, store) - char const *object; - int length; - struct hshentries *store; -/* Function: Search store and return entry with number being object. */ -/* cuttail = 0, if the entry is Head; otherwise, cuttail */ -/* is the entry point to the one with number being object */ - -{ - cuthead = 0; - while (compartial(store->first->num, object, length)) { - cuthead = store->first; - store = store->rest; - } - return store->first; -} - - - - static int -branchpoint(strt, tail) -struct hshentry *strt, *tail; -/* Function: check whether the deltas between strt and tail */ -/* are locked or branch point, return 1 if any is */ -/* locked or branch point; otherwise, return 0 and */ -/* mark deleted */ - -{ - struct hshentry *pt; - struct rcslock const *lockpt; - - for (pt = strt; pt != tail; pt = pt->next) { - if ( pt->branches ){ /* a branch point */ - rcserror("can't remove branch point %s", pt->num); - return true; - } - for (lockpt = Locks; lockpt; lockpt = lockpt->nextlock) - if (lockpt->delta == pt) { - rcserror("can't remove locked revision %s", pt->num); - return true; - } - pt->selector = false; - diagnose("deleting revision %s\n",pt->num); - } - return false; -} - - - - static int -removerevs() -/* Function: get the revision range to be removed, and place the */ -/* first revision removed in delstrt, the revision before */ -/* delstrt in cuthead (0, if delstrt is head), and the */ -/* revision after the last removed revision in cuttail (0 */ -/* if the last is a leaf */ - -{ - struct hshentry *target, *target2, *temp; - int length; - int cmp; - - if (!expandsym(delrev.strt, &numrev)) return 0; - target = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&gendeltas); - if ( ! target ) return 0; - cmp = cmpnum(target->num, numrev.string); - length = countnumflds(numrev.string); - - if (delrev.code == 0) { /* -o rev or -o branch */ - if (length & 1) - temp=searchcutpt(target->num,length+1,gendeltas); - else if (cmp) { - rcserror("Revision %s doesn't exist.", numrev.string); - return 0; - } - else - temp = searchcutpt(numrev.string, length, gendeltas); - cuttail = target->next; - if ( branchpoint(temp, cuttail) ) { - cuttail = 0; - return 0; - } - delstrt = temp; /* first revision to be removed */ - return 1; - } - - if (length & 1) { /* invalid branch after -o */ - rcserror("invalid branch range %s after -o", numrev.string); - return 0; - } - - if (delrev.code == 1) { /* -o -rev */ - if ( length > 2 ) { - temp = searchcutpt( target->num, length-1, gendeltas); - cuttail = target->next; - } - else { - temp = searchcutpt(target->num, length, gendeltas); - cuttail = target; - while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) ) - cuttail = cuttail->next; - } - if ( branchpoint(temp, cuttail) ){ - cuttail = 0; - return 0; - } - delstrt = temp; - return 1; - } - - if (delrev.code == 2) { /* -o rev- */ - if ( length == 2 ) { - temp = searchcutpt(target->num, 1,gendeltas); - if (cmp) - cuttail = target; - else - cuttail = target->next; - } - else { - if (cmp) { - cuthead = target; - if ( !(temp = target->next) ) return 0; - } - else - temp = searchcutpt(target->num, length, gendeltas); - getbranchno(temp->num, &numrev); /* get branch number */ - VOID genrevs(numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas); - } - if ( branchpoint( temp, cuttail ) ) { - cuttail = 0; - return 0; - } - delstrt = temp; - return 1; - } - - /* -o rev1-rev2 */ - if (!expandsym(delrev.end, &numrev)) return 0; - if ( - length != countnumflds(numrev.string) - || (length>2 && compartial(numrev.string, target->num, length-1)) - ) { - rcserror("invalid revision range %s-%s", - target->num, numrev.string - ); - return 0; - } - - target2 = genrevs(numrev.string,(char*)0,(char*)0,(char*)0,&gendeltas); - if ( ! target2 ) return 0; - - if ( length > 2) { /* delete revisions on branches */ - if ( cmpnum(target->num, target2->num) > 0) { - cmp = cmpnum(target2->num, numrev.string); - temp = target; - target = target2; - target2 = temp; - } - if (cmp) { - if ( ! cmpnum(target->num, target2->num) ) { - rcserror("Revisions %s-%s don't exist.", - delrev.strt, delrev.end - ); - return 0; - } - cuthead = target; - temp = target->next; - } - else - temp = searchcutpt(target->num, length, gendeltas); - cuttail = target2->next; - } - else { /* delete revisions on trunk */ - if ( cmpnum( target->num, target2->num) < 0 ) { - temp = target; - target = target2; - target2 = temp; - } - else - cmp = cmpnum(target2->num, numrev.string); - if (cmp) { - if ( ! cmpnum(target->num, target2->num) ) { - rcserror("Revisions %s-%s don't exist.", - delrev.strt, delrev.end - ); - return 0; - } - cuttail = target2; - } - else - cuttail = target2->next; - temp = searchcutpt(target->num, length, gendeltas); - } - if ( branchpoint(temp, cuttail) ) { - cuttail = 0; - return 0; - } - delstrt = temp; - return 1; -} - - - - static int -doassoc() -/* Add or delete (if !revno) association that is stored in assoclst. */ -{ - char const *p; - int changed = false; - struct Symrev const *curassoc; - struct assoc **pre, *pt; - - /* add new associations */ - for (curassoc = assoclst; curassoc; curassoc = curassoc->nextsym) { - char const *ssymbol = curassoc->ssymbol; - - if (!curassoc->revno) { /* delete symbol */ - for (pre = &Symbols; ; pre = &pt->nextassoc) - if (!(pt = *pre)) { - rcswarn("can't delete nonexisting symbol %s", ssymbol); - break; - } else if (strcmp(pt->symbol, ssymbol) == 0) { - *pre = pt->nextassoc; - changed = true; - break; - } - } - else { - if (curassoc->revno[0]) { - p = 0; - if (expandsym(curassoc->revno, &numrev)) - p = fstr_save(numrev.string); - } else if (!(p = tiprev())) - rcserror("no latest revision to associate with symbol %s", - ssymbol - ); - if (p) - changed |= addsymbol(p, ssymbol, curassoc->override); - } - } - return changed; -} - - - - static int -dolocks() -/* Function: remove lock for caller or first lock if unlockcaller is set; - * remove locks which are stored in rmvlocklst, - * add new locks which are stored in newlocklst, - * add lock for Dbranch or Head if lockhead is set. - */ -{ - struct Lockrev const *lockpt; - struct hshentry *target; - int changed = false; - - if (unlockcaller) { /* find lock for caller */ - if ( Head ) { - if (Locks) { - switch (findlock(true, &target)) { - case 0: - /* remove most recent lock */ - changed |= breaklock(Locks->delta); - break; - case 1: - diagnose("%s unlocked\n",target->num); - changed = true; - break; - } - } else { - rcswarn("No locks are set."); - } - } else { - rcswarn("can't unlock an empty tree"); - } - } - - /* remove locks which are stored in rmvlocklst */ - for (lockpt = rmvlocklst; lockpt; lockpt = lockpt->nextrev) - if (expandsym(lockpt->revno, &numrev)) { - target = genrevs(numrev.string, (char *)0, (char *)0, (char *)0, &gendeltas); - if ( target ) - if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string)) - rcserror("can't unlock nonexisting revision %s", - lockpt->revno - ); - else - changed |= breaklock(target); - /* breaklock does its own diagnose */ - } - - /* add new locks which stored in newlocklst */ - for (lockpt = newlocklst; lockpt; lockpt = lockpt->nextrev) - changed |= setlock(lockpt->revno); - - if (lockhead) /* lock default branch or head */ - if (Dbranch) - changed |= setlock(Dbranch); - else if (Head) - changed |= setlock(Head->num); - else - rcswarn("can't lock an empty tree"); - return changed; -} - - - - static int -setlock(rev) - char const *rev; -/* Function: Given a revision or branch number, finds the corresponding - * delta and locks it for caller. - */ -{ - struct hshentry *target; - int r; - - if (expandsym(rev, &numrev)) { - target = genrevs(numrev.string, (char*)0, (char*)0, - (char*)0, &gendeltas); - if ( target ) - if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string)) - rcserror("can't lock nonexisting revision %s", - numrev.string - ); - else { - if ((r = addlock(target, false)) < 0 && breaklock(target)) - r = addlock(target, true); - if (0 <= r) { - if (r) - diagnose("%s locked\n", target->num); - return r; - } - } - } - return 0; -} - - - static int -domessages() -{ - struct hshentry *target; - struct Message *p; - int changed = false; - - for (p = messagelst; p; p = p->nextmessage) - if ( - expandsym(p->revno, &numrev) && - (target = genrevs( - numrev.string, (char*)0, (char*)0, (char*)0, &gendeltas - )) - ) { - /* - * We can't check the old log -- it's much later in the file. - * We pessimistically assume that it changed. - */ - target->log = p->message; - changed = true; - } - return changed; -} - - - static int -rcs_setstate(rev,status) - char const *rev, *status; -/* Function: Given a revision or branch number, finds the corresponding delta - * and sets its state to status. - */ -{ - struct hshentry *target; - - if (expandsym(rev, &numrev)) { - target = genrevs(numrev.string, (char*)0, (char*)0, - (char*)0, &gendeltas); - if ( target ) - if (!(countnumflds(numrev.string)&1) && cmpnum(target->num,numrev.string)) - rcserror("can't set state of nonexisting revision %s", - numrev.string - ); - else if (strcmp(target->state, status) != 0) { - target->state = status; - return true; - } - } - return false; -} - - - - - - static int -buildeltatext(deltas) - struct hshentries const *deltas; -/* Function: put the delta text on frewrite and make necessary */ -/* change to delta text */ -{ - register FILE *fcut; /* temporary file to rebuild delta tree */ - char const *cutname; - - fcut = 0; - cuttail->selector = false; - scanlogtext(deltas->first, false); - if ( cuthead ) { - cutname = maketemp(3); - if (!(fcut = fopenSafer(cutname, FOPEN_WPLUS_WORK))) { - efaterror(cutname); - } - - while (deltas->first != cuthead) { - deltas = deltas->rest; - scanlogtext(deltas->first, true); - } - - snapshotedit(fcut); - Orewind(fcut); - aflush(fcut); - } - - while (deltas->first != cuttail) - scanlogtext((deltas = deltas->rest)->first, true); - finishedit((struct hshentry*)0, (FILE*)0, true); - Ozclose(&fcopy); - - if (fcut) { - char const *diffname = maketemp(0); - char const *diffv[6 + !!OPEN_O_BINARY]; - char const **diffp = diffv; - *++diffp = DIFF; - *++diffp = DIFFFLAGS; -# if OPEN_O_BINARY - if (Expand == BINARY_EXPAND) - *++diffp == "--binary"; -# endif - *++diffp = "-"; - *++diffp = resultname; - *++diffp = 0; - switch (runv(fileno(fcut), diffname, diffv)) { - case DIFF_FAILURE: case DIFF_SUCCESS: break; - default: rcsfaterror("diff failed"); - } - Ofclose(fcut); - return putdtext(cuttail,diffname,frewrite,true); - } else - return putdtext(cuttail,resultname,frewrite,false); -} - - - - static void -buildtree() -/* Function: actually removes revisions whose selector field */ -/* is false, and rebuilds the linkage of deltas. */ -/* asks for reconfirmation if deleting last revision*/ -{ - struct hshentry * Delta; - struct branchhead *pt, *pre; - - if ( cuthead ) - if ( cuthead->next == delstrt ) - cuthead->next = cuttail; - else { - pre = pt = cuthead->branches; - while( pt && pt->hsh != delstrt ) { - pre = pt; - pt = pt->nextbranch; - } - if ( cuttail ) - pt->hsh = cuttail; - else if ( pt == pre ) - cuthead->branches = pt->nextbranch; - else - pre->nextbranch = pt->nextbranch; - } - else { - if (!cuttail && !quietflag) { - if (!yesorno(false, "Do you really want to delete all revisions? [ny](n): ")) { - rcserror("No revision deleted"); - Delta = delstrt; - while( Delta) { - Delta->selector = true; - Delta = Delta->next; - } - return; - } - } - Head = cuttail; - } - return; -} - -#if RCS_lint -/* This lets us lint everything all at once. */ - -char const cmdid[] = ""; - -#define go(p,e) {int p P((int,char**)); void e P((void)); if(*argv)return p(argc,argv);if(*argv[1])e();} - - int -main(argc, argv) - int argc; - char **argv; -{ - go(ciId, ciExit); - go(coId, coExit); - go(identId, identExit); - go(mergeId, mergeExit); - go(rcsId, exiterr); - go(rcscleanId, rcscleanExit); - go(rcsdiffId, rdiffExit); - go(rcsmergeId, rmergeExit); - go(rlogId, rlogExit); - return 0; -} -#endif Index: gnu/usr.bin/rcs/rcs/rcsfile.5 =================================================================== --- gnu/usr.bin/rcs/rcs/rcsfile.5 (revision 255904) +++ gnu/usr.bin/rcs/rcs/rcsfile.5 (working copy) @@ -1,425 +0,0 @@ -.lf 1 ./rcsfile.5in -.\" Set p to 1 if your formatter can handle pic output. -.if t .nr p 1 -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \s-1RCS\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH RCSFILE 5 \*(Dt GNU -.SH NAME -rcsfile \- format of RCS file -.SH DESCRIPTION -An \*r file's -contents are described by the grammar -below. -.PP -The text is free format: space, backspace, tab, newline, vertical -tab, form feed, and carriage return (collectively, -.IR "white space") -have no significance except in strings. -However, white space cannot appear within an id, num, or sym, -and an \*r file must end with a newline. -.PP -Strings are enclosed by -.BR @ . -If a string contains a -.BR @ , -it must be doubled; -otherwise, strings can contain arbitrary binary data. -.PP -The meta syntax uses the following conventions: `|' (bar) separates -alternatives; `{' and `}' enclose optional phrases; `{' and `}*' enclose -phrases that can be repeated zero or more times; -`{' and '}+' enclose phrases that must appear at least once and can be -repeated; -Terminal symbols are in -.BR boldface ; -nonterminal symbols are in -.IR italics . -.LP -.nr w \w'\f3deltatext\fP ' -.nr y \w'\f3newphrase\fP ' -.if \nw<\ny .nr w \ny -.nr x \w'\f3branches\fP' -.nr y \w'{ \f3comment\fP' -.if \nx<\ny .nr x \ny -.nr y \w'\f3{ branch\fP' -.if \nx<\ny .nr x \ny -.ta \nwu +\w'::= 'u +\nxu+\w' 'u -.fc # -.nf -\f2rcstext\fP ::= \f2admin\fP {\f2delta\fP}* \f2desc\fP {\f2deltatext\fP}* -.LP -\f2admin\fP ::= \f3head\fP {\f2num\fP}\f3;\fP - { \f3branch\fP {\f2num\fP}\f3;\fP } - \f3access\fP {\f2id\fP}*\f3;\fP - \f3symbols\fP {\f2sym\fP \f3:\fP \f2num\fP}*\f3;\fP - \f3locks\fP {\f2id\fP \f3:\fP \f2num\fP}*\f3;\fP {\f3strict ;\fP} - { \f3comment\fP {\f2string\fP}\f3;\fP } - { \f3expand\fP {\f2string\fP}\f3;\fP } - { \f2newphrase\fP }* -.LP -\f2delta\fP ::= \f2num\fP - \f3date\fP \f2num\fP\f3;\fP - \f3author\fP \f2id\fP\f3;\fP - \f3state\fP {\f2id\fP}\f3;\fP - \f3branches\fP {\f2num\fP}*\f3;\fP - \f3next\fP {\f2num\fP}\f3;\fP - { \f2newphrase\fP }* -.LP -\f2desc\fP ::= \f3desc\fP \f2string\fP -.LP -\f2deltatext\fP ::= \f2num\fP - \f3log\fP \f2string\fP - { \f2newphrase\fP }* - \f3text\fP \f2string\fP -.LP -\f2num\fP ::= {\f2digit\fP | \f3.\fP}+ -.LP -\f2digit\fP ::= \f30\fP | \f31\fP | \f32\fP | \f33\fP | \f34\fP | \f35\fP | \f36\fP | \f37\fP | \f38\fP | \f39\fP -.LP -\f2id\fP ::= {\f2num\fP} \f2idchar\fP {\f2idchar\fP | \f2num\fP}* -.LP -\f2sym\fP ::= {\f2digit\fP}* \f2idchar\fP {\f2idchar\fP | \f2digit\fP}* -.LP -\f2idchar\fP ::= any visible graphic character except \f2special\fP -.LP -\f2special\fP ::= \f3$\fP | \f3,\fP | \f3.\fP | \f3:\fP | \f3;\fP | \f3@\fP -.LP -\f2string\fP ::= \f3@\fP{any character, with \f3@\fP doubled}*\f3@\fP -.LP -\f2newphrase\fP ::= \f2id\fP \f2word\fP* \f3;\fP -.LP -\f2word\fP ::= \f2id\fP | \f2num\fP | \f2string\fP | \f3:\fP -.fi -.PP -Identifiers are case sensitive. Keywords are in lower case only. -The sets of keywords and identifiers can overlap. -In most environments \*r uses the \s-1ISO\s0 8859/1 encoding: -visible graphic characters are codes 041\-176 and 240\-377, -and white space characters are codes 010\-015 and 040. -.PP -Dates, which appear after the -.B date -keyword, are of the form -\f2Y\fP\f3.\fP\f2mm\fP\f3.\fP\f2dd\fP\f3.\fP\f2hh\fP\f3.\fP\f2mm\fP\f3.\fP\f2ss\fP, -where -.I Y -is the year, -.I mm -the month (01\-12), -.I dd -the day (01\-31), -.I hh -the hour (00\-23), -.I mm -the minute (00\-59), -and -.I ss -the second (00\-60). -.I Y -contains just the last two digits of the year -for years from 1900 through 1999, -and all the digits of years thereafter. -Dates use the Gregorian calendar; times use UTC. -.PP -The -.I newphrase -productions in the grammar are reserved for future extensions -to the format of \*r files. -No -.I newphrase -will begin with any keyword already in use. -.PP -The -.I delta -nodes form a tree. All nodes whose numbers -consist of a single pair -(e.g., 2.3, 2.1, 1.3, etc.) -are on the trunk, and are linked through the -.B next -field in order of decreasing numbers. -The -.B head -field in the -.I admin -node points to the head of that sequence (i.e., contains -the highest pair). -The -.B branch -node in the admin node indicates the default -branch (or revision) for most \*r operations. -If empty, the default -branch is the highest branch on the trunk. -.PP -All -.I delta -nodes whose numbers consist of -.RI 2 n -fields -.RI ( n \(>=2) -(e.g., 3.1.1.1, 2.1.2.2, etc.) -are linked as follows. -All nodes whose first -.RI 2 n \-1 -number fields are identical are linked through the -.B next -field in order of increasing numbers. -For each such sequence, -the -.I delta -node whose number is identical to the first -.RI 2 n \-2 -number fields of the deltas on that sequence is called the branchpoint. -The -.B branches -field of a node contains a list of the -numbers of the first nodes of all sequences for which it is a branchpoint. -This list is ordered in increasing numbers. -.LP -The following diagram shows an example of an \*r file's organization. -.if !\np \{\ -.nf -.vs 12 -.ne 36 -.cs 1 20 -.eo - - Head - | - | - v / \ - --------- / \ - / \ / \ | | / \ / \ - / \ / \ | 2.1 | / \ / \ - / \ / \ | | / \ / \ -/1.2.1.3\ /1.3.1.1\ | | /1.2.2.2\ /1.2.2.1.1.1\ ---------- --------- --------- --------- ------------- - ^ ^ | ^ ^ - | | | | | - | | v | | - / \ | --------- / \ | - / \ | \ 1.3 / / \ | - / \ ---------\ / / \----------- -/1.2.1.1\ \ / /1.2.2.1\ ---------- \ / --------- - ^ | ^ - | | | - | v | - | --------- | - | \ 1.2 / | - ----------------------\ /--------- - \ / - \ / - | - | - v - --------- - \ 1.1 / - \ / - \ / - \ / - -.ec -.cs 1 -.vs -.fi -.\} -.if \np \{\ -.lf 232 -.PS 4.250i 3.812i -.\" -2.0625 -4.25 1.75 0 -.\" 0.000i 4.250i 3.812i 0.000i -.nr 00 \n(.u -.nf -.nr 0x 1 -\h'3.812i' -.sp -1 -.lf 242 -\h'2.062i-(\w'Head'u/2u)'\v'0.125i-(0v/2u)+0v+0.22m'Head -.sp -1 -\h'2.062i'\v'0.250i'\D'l0.000i 0.500i' -.sp -1 -\h'2.087i'\v'0.650i'\D'l-0.025i 0.100i' -.sp -1 -\h'2.062i'\v'0.750i'\D'l-0.025i -0.100i' -.sp -1 -\h'1.688i'\v'1.250i'\D'l0.750i 0.000i' -.sp -1 -\h'2.438i'\v'1.250i'\D'l0.000i -0.500i' -.sp -1 -\h'2.438i'\v'0.750i'\D'l-0.750i 0.000i' -.sp -1 -\h'1.688i'\v'0.750i'\D'l0.000i 0.500i' -.sp -1 -.lf 244 -\h'2.062i-(\w'2.1'u/2u)'\v'1.000i-(0v/2u)+0v+0.22m'2.1 -.sp -1 -\h'2.062i'\v'1.250i'\D'l0.000i 0.500i' -.sp -1 -\h'2.087i'\v'1.650i'\D'l-0.025i 0.100i' -.sp -1 -\h'2.062i'\v'1.750i'\D'l-0.025i -0.100i' -.sp -1 -.lf 246 -\h'2.062i-(\w'1.3'u/2u)'\v'2.000i-(1v/2u)+0v+0.22m'1.3 -.sp -1 -\h'2.062i'\v'2.250i'\D'l-0.375i -0.500i' -.sp -1 -\h'1.688i'\v'1.750i'\D'l0.750i 0.000i' -.sp -1 -\h'2.438i'\v'1.750i'\D'l-0.375i 0.500i' -.sp -1 -\h'1.875i'\v'2.000i'\D'~-0.500i 0.000i 0.000i -0.500i' -.sp -1 -\h'1.350i'\v'1.600i'\D'l0.025i -0.100i' -.sp -1 -\h'1.375i'\v'1.500i'\D'l0.025i 0.100i' -.sp -1 -.lf 249 -\h'1.375i-(\w'1.3.1.1'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.3.1.1 -.sp -1 -\h'1.375i'\v'1.000i'\D'l-0.375i 0.500i' -.sp -1 -\h'1.000i'\v'1.500i'\D'l0.750i 0.000i' -.sp -1 -\h'1.750i'\v'1.500i'\D'l-0.375i -0.500i' -.sp -1 -\h'2.062i'\v'2.250i'\D'l0.000i 0.500i' -.sp -1 -\h'2.087i'\v'2.650i'\D'l-0.025i 0.100i' -.sp -1 -\h'2.062i'\v'2.750i'\D'l-0.025i -0.100i' -.sp -1 -.lf 252 -\h'2.062i-(\w'1.2'u/2u)'\v'3.000i-(1v/2u)+0v+0.22m'1.2 -.sp -1 -\h'2.062i'\v'3.250i'\D'l-0.375i -0.500i' -.sp -1 -\h'1.688i'\v'2.750i'\D'l0.750i 0.000i' -.sp -1 -\h'2.438i'\v'2.750i'\D'l-0.375i 0.500i' -.sp -1 -\h'1.875i'\v'3.000i'\D'~-0.500i 0.000i -0.500i 0.000i -0.500i 0.000i 0.000i -0.500i' -.sp -1 -\h'0.350i'\v'2.600i'\D'l0.025i -0.100i' -.sp -1 -\h'0.375i'\v'2.500i'\D'l0.025i 0.100i' -.sp -1 -.lf 255 -\h'0.375i-(\w'1.2.1.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.1.1 -.sp -1 -\h'0.375i'\v'2.000i'\D'l-0.375i 0.500i' -.sp -1 -\h'0.000i'\v'2.500i'\D'l0.750i 0.000i' -.sp -1 -\h'0.750i'\v'2.500i'\D'l-0.375i -0.500i' -.sp -1 -\h'0.375i'\v'2.000i'\D'l0.000i -0.500i' -.sp -1 -\h'0.350i'\v'1.600i'\D'l0.025i -0.100i' -.sp -1 -\h'0.375i'\v'1.500i'\D'l0.025i 0.100i' -.sp -1 -.lf 257 -\h'0.375i-(\w'1.2.1.3'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.1.3 -.sp -1 -\h'0.375i'\v'1.000i'\D'l-0.375i 0.500i' -.sp -1 -\h'0.000i'\v'1.500i'\D'l0.750i 0.000i' -.sp -1 -\h'0.750i'\v'1.500i'\D'l-0.375i -0.500i' -.sp -1 -\h'2.250i'\v'3.000i'\D'~0.500i 0.000i 0.000i -0.500i' -.sp -1 -\h'2.725i'\v'2.600i'\D'l0.025i -0.100i' -.sp -1 -\h'2.750i'\v'2.500i'\D'l0.025i 0.100i' -.sp -1 -.lf 261 -\h'2.750i-(\w'1.2.2.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.2.1 -.sp -1 -\h'2.750i'\v'2.000i'\D'l-0.375i 0.500i' -.sp -1 -\h'2.375i'\v'2.500i'\D'l0.750i 0.000i' -.sp -1 -\h'3.125i'\v'2.500i'\D'l-0.375i -0.500i' -.sp -1 -\h'2.938i'\v'2.250i'\D'~0.500i 0.000i 0.000i -0.500i 0.000i -0.500i' -.sp -1 -\h'3.413i'\v'1.350i'\D'l0.025i -0.100i' -.sp -1 -\h'3.438i'\v'1.250i'\D'l0.025i 0.100i' -.sp -1 -.lf 264 -\h'3.438i-(\w'\s-21.2.2.1.1.1\s0'u/2u)'\v'1.000i-(1v/2u)+1v+0.22m'\s-21.2.2.1.1.1\s0 -.sp -1 -\h'3.438i'\v'0.750i'\D'l-0.375i 0.500i' -.sp -1 -\h'3.062i'\v'1.250i'\D'l0.750i 0.000i' -.sp -1 -\h'3.812i'\v'1.250i'\D'l-0.375i -0.500i' -.sp -1 -\h'2.750i'\v'2.000i'\D'l0.000i -0.500i' -.sp -1 -\h'2.725i'\v'1.600i'\D'l0.025i -0.100i' -.sp -1 -\h'2.750i'\v'1.500i'\D'l0.025i 0.100i' -.sp -1 -.lf 267 -\h'2.750i-(\w'1.2.2.2'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.2.2 -.sp -1 -\h'2.750i'\v'1.000i'\D'l-0.375i 0.500i' -.sp -1 -\h'2.375i'\v'1.500i'\D'l0.750i 0.000i' -.sp -1 -\h'3.125i'\v'1.500i'\D'l-0.375i -0.500i' -.sp -1 -\h'2.062i'\v'3.250i'\D'l0.000i 0.500i' -.sp -1 -\h'2.087i'\v'3.650i'\D'l-0.025i 0.100i' -.sp -1 -\h'2.062i'\v'3.750i'\D'l-0.025i -0.100i' -.sp -1 -.lf 270 -\h'2.062i-(\w'1.1'u/2u)'\v'4.000i-(1v/2u)+0v+0.22m'1.1 -.sp -1 -\h'2.062i'\v'4.250i'\D'l-0.375i -0.500i' -.sp -1 -\h'1.688i'\v'3.750i'\D'l0.750i 0.000i' -.sp -1 -\h'2.438i'\v'3.750i'\D'l-0.375i 0.500i' -.sp -1 -.sp 4.250i+1 -.if \n(00 .fi -.br -.nr 0x 0 -.lf 271 -.PE -.lf 272 -.\} -.SH IDENTIFICATION -.de VL -\\$2 -.. -Author: Walter F. Tichy, -Purdue University, West Lafayette, IN, 47907. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH SEE ALSO -rcsintro(1), ci(1), co(1), ident(1), rcs(1), rcsclean(1), rcsdiff(1), -rcsmerge(1), rlog(1) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. Index: gnu/usr.bin/rcs/rcs/rcsintro.1 =================================================================== --- gnu/usr.bin/rcs/rcs/rcsintro.1 (revision 255904) +++ gnu/usr.bin/rcs/rcs/rcsintro.1 (working copy) @@ -1,302 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.if n .ds - \%-- -.if t .ds - \(em -.if !\n(.g \{\ -. if !\w|\*(lq| \{\ -. ds lq `` -. if \w'\(lq' .ds lq "\(lq -. \} -. if !\w|\*(rq| \{\ -. ds rq '' -. if \w'\(rq' .ds rq "\(rq -. \} -.\} -.am SS -.LP -.. -.TH RCSINTRO 1 \*(Dt GNU -.SH NAME -rcsintro \- introduction to RCS commands -.SH DESCRIPTION -The Revision Control System (\*r) manages multiple revisions of files. -\*r automates the storing, retrieval, logging, identification, and merging -of revisions. \*r is useful for text that is revised frequently, for example -programs, documentation, graphics, papers, and form letters. -.PP -The basic user interface is extremely simple. The novice only needs -to learn two commands: -.BR ci (1) -and -.BR co (1). -.BR ci , -short for \*(lqcheck in\*(rq, deposits the contents of a -file into an archival file called an \*r file. An \*r file -contains all revisions of a particular file. -.BR co , -short for \*(lqcheck out\*(rq, retrieves revisions from an \*r file. -.SS "Functions of \*r" -.IP \(bu -Store and retrieve multiple revisions of text. \*r saves all old -revisions in a space efficient way. -Changes no longer destroy the original, because the -previous revisions remain accessible. Revisions can be retrieved according to -ranges of revision numbers, symbolic names, dates, authors, and -states. -.IP \(bu -Maintain a complete history of changes. -\*r logs all changes automatically. -Besides the text of each revision, \*r stores the author, the date and time of -check-in, and a log message summarizing the change. -The logging makes it easy to find out -what happened to a module, without having to compare -source listings or having to track down colleagues. -.IP \(bu -Resolve access conflicts. When two or more programmers wish to -modify the same revision, \*r alerts the programmers and prevents one -modification from corrupting the other. -.IP \(bu -Maintain a tree of revisions. \*r can maintain separate lines of development -for each module. It stores a tree structure that represents the -ancestral relationships among revisions. -.IP \(bu -Merge revisions and resolve conflicts. -Two separate lines of development of a module can be coalesced by merging. -If the revisions to be merged affect the same sections of code, \*r alerts the -user about the overlapping changes. -.IP \(bu -Control releases and configurations. -Revisions can be assigned symbolic names -and marked as released, stable, experimental, etc. -With these facilities, configurations of modules can be -described simply and directly. -.IP \(bu -Automatically identify each revision with name, revision number, -creation time, author, etc. -The identification is like a stamp that can be embedded at an appropriate place -in the text of a revision. -The identification makes it simple to determine which -revisions of which modules make up a given configuration. -.IP \(bu -Minimize secondary storage. \*r needs little extra space for -the revisions (only the differences). If intermediate revisions are -deleted, the corresponding deltas are compressed accordingly. -.SS "Getting Started with \*r" -Suppose you have a file -.B f.c -that you wish to put under control of \*r. -If you have not already done so, make an \*r directory with the command -.IP -.B "mkdir RCS" -.LP -Then invoke the check-in command -.IP -.B "ci f.c" -.LP -This command creates an \*r file in the -.B RCS -directory, -stores -.B f.c -into it as revision 1.1, and -deletes -.BR f.c . -It also asks you for a description. The description -should be a synopsis of the contents of the file. All later check-in -commands will ask you for a log entry, which should summarize the -changes that you made. -.PP -Files in the \*r directory are called \*r files; -the others are called working files. -To get back the working file -.B f.c -in the previous example, use the check-out -command -.IP -.B "co f.c" -.LP -This command extracts the latest revision from the \*r file -and writes -it into -.BR f.c . -If you want to edit -.BR f.c , -you must lock it as you check it out with the command -.IP -.B "co \-l f.c" -.LP -You can now edit -.BR f.c . -.PP -Suppose after some editing you want to know what changes that you have made. -The command -.IP -.B "rcsdiff f.c" -.LP -tells you the difference between the most recently checked-in version -and the working file. -You can check the file back in by invoking -.IP -.B "ci f.c" -.LP -This increments the revision number properly. -.PP -If -.B ci -complains with the message -.IP -.BI "ci error: no lock set by " "your name" -.LP -then you have tried to check in a file even though you did not -lock it when you checked it out. -Of course, it is too late now to do the check-out with locking, because -another check-out would -overwrite your modifications. Instead, invoke -.IP -.B "rcs \-l f.c" -.LP -This command will lock the latest revision for you, unless somebody -else got ahead of you already. In this case, you'll have to negotiate with -that person. -.PP -Locking assures that you, and only you, can check in the next update, and -avoids nasty problems if several people work on the same file. -Even if a revision is locked, it can still be checked out for -reading, compiling, etc. All that locking -prevents is a -.I "check-in" -by anybody but the locker. -.PP -If your \*r file is private, i.e., if you are the only person who is going -to deposit revisions into it, strict locking is not needed and you -can turn it off. -If strict locking is turned off, -the owner of the \*r file need not have a lock for check-in; all others -still do. Turning strict locking off and on is done with the commands -.IP -.BR "rcs \-U f.c" " and " "rcs \-L f.c" -.LP -If you don't want to clutter your working directory with \*r files, create -a subdirectory called -.B RCS -in your working directory, and move all your \*r -files there. \*r commands will look first into that directory to find -needed files. All the commands discussed above will still work, without any -modification. -(Actually, pairs of \*r and working files can be specified in three ways: -(a) both are given, (b) only the working file is given, (c) only the -\*r file is given. Both \*r and working files may have arbitrary path prefixes; -\*r commands pair them up intelligently.) -.PP -To avoid the deletion of the working file during check-in (in case you want to -continue editing or compiling), invoke -.IP -.BR "ci \-l f.c" " or " "ci \-u f.c" -.LP -These commands check in -.B f.c -as usual, but perform an implicit -check-out. The first form also locks the checked in revision, the second one -doesn't. Thus, these options save you one check-out operation. -The first form is useful if you want to continue editing, -the second one if you just want to read the file. -Both update the identification markers in your working file (see below). -.PP -You can give -.B ci -the number you want assigned to a checked in -revision. Assume all your revisions were numbered 1.1, 1.2, 1.3, etc., -and you would like to start release 2. -The command -.IP -.BR "ci \-r2 f.c" " or " "ci \-r2.1 f.c" -.LP -assigns the number 2.1 to the new revision. -From then on, -.B ci -will number the subsequent revisions -with 2.2, 2.3, etc. The corresponding -.B co -commands -.IP -.BR "co \-r2 f.c" " and " "co \-r2.1 f.c" -.PP -retrieve the latest revision numbered -.RI 2. x -and the revision 2.1, -respectively. -.B co -without a revision number selects -the latest revision on the -.IR trunk , -i.e. the highest -revision with a number consisting of two fields. Numbers with more than two -fields are needed for branches. -For example, to start a branch at revision 1.3, invoke -.IP -.B "ci \-r1.3.1 f.c" -.LP -This command starts a branch numbered 1 at revision 1.3, and assigns -the number 1.3.1.1 to the new revision. For more information about -branches, see -.BR rcsfile (5). -.SS "Automatic Identification" -\*r can put special strings for identification into your source and object -code. To obtain such identification, place the marker -.IP -.B "$\&Id$" -.LP -into your text, for instance inside a comment. -\*r will replace this marker with a string of the form -.IP -.BI $\&Id: " filename revision date time author state " $ -.LP -With such a marker on the first page of each module, you can -always see with which revision you are working. -\*r keeps the markers up to date automatically. -To propagate the markers into your object code, simply put -them into literal character strings. In C, this is done as follows: -.IP -.ft 3 -static char rcsid[] = \&"$\&Id$\&"; -.ft -.LP -The command -.B ident -extracts such markers from any file, even object code -and dumps. -Thus, -.B ident -lets you find out -which revisions of which modules were used in a given program. -.PP -You may also find it useful to put the marker -.B $\&Log$ -into your text, inside a comment. This marker accumulates -the log messages that are requested during check-in. -Thus, you can maintain the complete history of your file directly inside it. -There are several additional identification markers; see -.BR co (1) -for -details. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993 Paul Eggert. -.SH "SEE ALSO" -ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.br Index: gnu/usr.bin/rcs/rcsclean/Makefile =================================================================== --- gnu/usr.bin/rcs/rcsclean/Makefile (revision 255904) +++ gnu/usr.bin/rcs/rcsclean/Makefile (working copy) @@ -1,8 +0,0 @@ -PROG= rcsclean -SRCS= rcsclean.c -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/rcsclean/rcsclean.1 =================================================================== --- gnu/usr.bin/rcs/rcsclean/rcsclean.1 (revision 255904) +++ gnu/usr.bin/rcs/rcsclean/rcsclean.1 (working copy) @@ -1,203 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH RCSCLEAN 1 \*(Dt GNU -.SH NAME -rcsclean \- clean up working files -.SH SYNOPSIS -.B rcsclean -.RI [ options "] [ " file " .\|.\|. ]" -.SH DESCRIPTION -.B rcsclean -removes files that are not being worked on. -.B "rcsclean \-u" -also unlocks and removes files that are being worked on -but have not changed. -.PP -For each -.I file -given, -.B rcsclean -compares the working file and a revision in the corresponding -\*r file. If it finds a difference, it does nothing. -Otherwise, it first unlocks the revision if the -.B \-u -option is given, -and then removes the working file -unless the working file is writable and the revision is locked. -It logs its actions by outputting the corresponding -.B "rcs \-u" -and -.B "rm \-f" -commands on the standard output. -.PP -Files are paired as explained in -.BR ci (1). -If no -.I file -is given, all working files in the current directory are cleaned. -Pathnames matching an \*r suffix denote \*r files; -all others denote working files. -.PP -The number of the revision to which the working file is compared -may be attached to any of the options -.BR \-n , -.BR \-q , -.BR \-r , -or -.BR \-u . -If no revision number is specified, then if the -.B \-u -option is given and the caller has one revision locked, -.B rcsclean -uses that revision; otherwise -.B rcsclean -uses the latest revision on the default branch, normally the root. -.PP -.B rcsclean -is useful for -.B clean -targets in makefiles. -See also -.BR rcsdiff (1), -which prints out the differences, -and -.BR ci (1), -which -normally reverts to the previous revision -if a file was not changed. -.SH OPTIONS -.TP -.BI \-k subst -Use -.I subst -style keyword substitution when retrieving the revision for comparison. -See -.BR co (1) -for details. -.TP -.BR \-n [\f2rev\fP] -Do not actually remove any files or unlock any revisions. -Using this option will tell you what -.B rcsclean -would do without actually doing it. -.TP -.BR \-q [\f2rev\fP] -Do not log the actions taken on standard output. -.TP -.BR \-r [\f2rev\fP] -This option has no effect other than specifying the revision for comparison. -.TP -.B \-T -Preserve the modification time on the \*r file -even if the \*r file changes because a lock is removed. -This option can suppress extensive recompilation caused by a -.BR make (1) -dependency of some other copy of the working file on the \*r file. -Use this option with care; it can suppress recompilation even when it is needed, -i.e. when the lock removal -would mean a change to keyword strings in the other working file. -.TP -.BR \-u [\f2rev\fP] -Unlock the revision if it is locked and no difference is found. -.TP -.BI \-V -Print \*r's version number. -.TP -.BI \-V n -Emulate \*r version -.IR n . -See -.BR co (1) -for details. -.TP -.BI \-x "suffixes" -Use -.I suffixes -to characterize \*r files. -See -.BR ci (1) -for details. -.TP -.BI \-z zone -Use -.I zone -as the time zone for keyword substitution; -see -.BR co (1) -for details. -.SH EXAMPLES -.LP -.RS -.ft 3 -rcsclean *.c *.h -.ft -.RE -.LP -removes all working files ending in -.B .c -or -.B .h -that were not changed -since their checkout. -.LP -.RS -.ft 3 -rcsclean -.ft -.RE -.LP -removes all working files in the current directory -that were not changed since their checkout. -.SH FILES -.B rcsclean -accesses files much as -.BR ci (1) -does. -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -A backslash escapes spaces within an option. -The -.B \s-1RCSINIT\s0 -options are prepended to the argument lists of most \*r commands. -Useful -.B \s-1RCSINIT\s0 -options include -.BR \-q , -.BR \-V , -.BR \-x , -and -.BR \-z . -.SH DIAGNOSTICS -The exit status is zero if and only if all operations were successful. -Missing working files and \*r files are silently ignored. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993 Paul Eggert. -.SH "SEE ALSO" -ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), rlog(1), -rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.SH BUGS -At least one -.I file -must be given in older Unix versions that -do not provide the needed directory scanning operations. -.br Index: gnu/usr.bin/rcs/rcsclean/rcsclean.c =================================================================== --- gnu/usr.bin/rcs/rcsclean/rcsclean.c (revision 255904) +++ gnu/usr.bin/rcs/rcsclean/rcsclean.c (working copy) @@ -1,333 +0,0 @@ -/* Clean up working files. */ - -/* Copyright 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -#include "rcsbase.h" - -#if has_dirent - static int get_directory P((char const*,char***)); -#endif - -static int unlock P((struct hshentry *)); -static void cleanup P((void)); - -static RILE *workptr; -static int exitstatus; - -mainProg(rcscleanId, "rcsclean", "$FreeBSD$") -{ - static char const usage[] = - "\nrcsclean: usage: rcsclean -ksubst -{nqru}[rev] -T -Vn -xsuff -zzone file ..."; - - static struct buf revision; - - char *a, **newargv; - char const *rev, *p; - int dounlock, expmode, perform, unlocked, unlockflag, waslocked; - int Ttimeflag; - struct hshentries *deltas; - struct hshentry *delta; - struct stat workstat; - - setrid(); - - expmode = -1; - rev = 0; - suffixes = X_DEFAULT; - perform = true; - unlockflag = false; - Ttimeflag = false; - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - for (;;) { - if (--argc < 1) { -# if has_dirent - argc = get_directory(".", &newargv); - argv = newargv; - break; -# else - faterror("no pathnames specified"); -# endif - } - a = *++argv; - if (!*a || *a++ != '-') - break; - switch (*a++) { - case 'k': - if (0 <= expmode) - redefined('k'); - if ((expmode = str2expmode(a)) < 0) - goto unknown; - break; - - case 'n': - perform = false; - goto handle_revision; - - case 'q': - quietflag = true; - /* fall into */ - case 'r': - handle_revision: - if (*a) { - if (rev) - warn("redefinition of revision number"); - rev = a; - } - break; - - case 'T': - if (*a) - goto unknown; - Ttimeflag = true; - break; - - case 'u': - unlockflag = true; - goto handle_revision; - - case 'V': - setRCSversion(*argv); - break; - - case 'x': - suffixes = a; - break; - - case 'z': - zone_set(a); - break; - - default: - unknown: - error("unknown option: %s%s", *argv, usage); - } - } - - dounlock = perform & unlockflag; - - if (nerror) - cleanup(); - else - for (; 0 < argc; cleanup(), ++argv, --argc) { - - ffree(); - - if (!( - 0 < pairnames( - argc, argv, - dounlock ? rcswriteopen : rcsreadopen, - true, true - ) && - (workptr = Iopen(workname, FOPEN_R_WORK, &workstat)) - )) - continue; - - if (same_file(RCSstat, workstat, 0)) { - rcserror("RCS file is the same as working file %s.", - workname - ); - continue; - } - - gettree(); - - p = 0; - if (rev) { - if (!fexpandsym(rev, &revision, workptr)) - continue; - p = revision.string; - } else if (Head) - switch (unlockflag ? findlock(false,&delta) : 0) { - default: - continue; - case 0: - p = Dbranch ? Dbranch : ""; - break; - case 1: - p = delta->num; - break; - } - delta = 0; - deltas = 0; /* Keep lint happy. */ - if (p && !(delta = genrevs(p,(char*)0,(char*)0,(char*)0,&deltas))) - continue; - - waslocked = delta && delta->lockedby; - locker_expansion = unlock(delta); - unlocked = locker_expansion & unlockflag; - if (unlockednum, RCSname); - - if (perform & unlocked) { - if_advise_access(deltas->first != delta, finptr, MADV_SEQUENTIAL); - if (donerewrite(true, - Ttimeflag ? RCSstat.st_mtime : (time_t)-1 - ) != 0) - continue; - } - - if (!quietflag) - aprintf(stdout, "rm -f %s\n", workname); - Izclose(&workptr); - if (perform && un_link(workname) != 0) - eerror(workname); - - } - - tempunlink(); - if (!quietflag) - Ofclose(stdout); - exitmain(exitstatus); -} - - static void -cleanup() -{ - if (nerror) exitstatus = EXIT_FAILURE; - Izclose(&finptr); - Izclose(&workptr); - Ozclose(&fcopy); - ORCSclose(); - dirtempunlink(); -} - -#if RCS_lint -# define exiterr rcscleanExit -#endif - void -exiterr() -{ - ORCSerror(); - dirtempunlink(); - tempunlink(); - _exit(EXIT_FAILURE); -} - - static int -unlock(delta) - struct hshentry *delta; -{ - register struct rcslock **al, *l; - - if (delta && delta->lockedby && strcmp(getcaller(),delta->lockedby)==0) - for (al = &Locks; (l = *al); al = &l->nextlock) - if (l->delta == delta) { - *al = l->nextlock; - delta->lockedby = 0; - return true; - } - return false; -} - -#if has_dirent - static int -get_directory(dirname, aargv) - char const *dirname; - char ***aargv; -/* - * Put a vector of all DIRNAME's directory entries names into *AARGV. - * Ignore names of RCS files. - * Yield the number of entries found. Terminate the vector with 0. - * Allocate the storage for the vector and entry names. - * Do not sort the names. Do not include '.' and '..'. - */ -{ - int i, entries = 0, entries_max = 64; - size_t chars = 0, chars_max = 1024; - size_t *offset = tnalloc(size_t, entries_max); - char *a = tnalloc(char, chars_max), **p; - DIR *d; - struct dirent *e; - - if (!(d = opendir(dirname))) - efaterror(dirname); - while ((errno = 0, e = readdir(d))) { - char const *en = e->d_name; - size_t s = strlen(en) + 1; - if (en[0]=='.' && (!en[1] || (en[1]=='.' && !en[2]))) - continue; - if (rcssuffix(en)) - continue; - while (chars_max < s + chars) - a = trealloc(char, a, chars_max<<=1); - if (entries == entries_max) - offset = trealloc(size_t, offset, entries_max<<=1); - offset[entries++] = chars; - VOID strcpy(a+chars, en); - chars += s; - } -# if void_closedir -# define close_directory(d) (closedir(d), 0) -# else -# define close_directory(d) closedir(d) -# endif - if (errno || close_directory(d) != 0) - efaterror(dirname); - if (chars) - a = trealloc(char, a, chars); - else - tfree(a); - *aargv = p = tnalloc(char*, entries+1); - for (i=0; i Index: gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 =================================================================== --- gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 (revision 255904) +++ gnu/usr.bin/rcs/rcsdiff/rcsdiff.1 (working copy) @@ -1,158 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH RCSDIFF 1 \*(Dt GNU -.SH NAME -rcsdiff \- compare RCS revisions -.SH SYNOPSIS -.B rcsdiff -[ -.BI \-k subst -] [ -.B \-q -] [ -.BI \-r rev1 -[ -.BI \-r rev2 -] ] [ -.B \-T -] [ -.RI "\f3\-V\fP[" n ] -] [ -.BI \-x suffixes -] [ -.BI \-z zone -] [ -.I "diff options" -] -.I "file .\|.\|." -.SH DESCRIPTION -.B rcsdiff -runs -.BR diff (1) -to compare two revisions of each \*r file given. -.PP -Pathnames matching an \*r suffix denote \*r files; -all others denote working files. -Names are paired as explained in -.BR ci (1). -.PP -The option -.B \-q -suppresses diagnostic output. -Zero, one, or two revisions may be specified with -.BR \-r . -The option -.BI \-k subst -affects keyword substitution when extracting -revisions, as described in -.BR co (1); -for example, -.B "\-kk\ \-r1.1\ \-r1.2" -ignores differences in keyword values when comparing revisions -.B 1.1 -and -.BR 1.2 . -To avoid excess output from locker name substitution, -.B \-kkvl -is assumed if (1) at most one revision option is given, -(2) no -.B \-k -option is given, (3) -.B \-kkv -is the default keyword substitution, and -(4) the working file's mode would be produced by -.BR "co\ \-l". -See -.BR co (1) -for details -about -.BR \-T , -.BR \-V , -.B \-x -and -.BR \-z . -Otherwise, all options of -.BR diff (1) -that apply to regular files are accepted, with the same meaning as for -.BR diff . -.PP -If both -.I rev1 -and -.I rev2 -are omitted, -.B rcsdiff -compares the latest revision on the -default branch (by default the trunk) -with the contents of the corresponding working file. This is useful -for determining what you changed since the last checkin. -.PP -If -.I rev1 -is given, but -.I rev2 -is omitted, -.B rcsdiff -compares revision -.I rev1 -of the \*r file with -the contents of the corresponding working file. -.PP -If both -.I rev1 -and -.I rev2 -are given, -.B rcsdiff -compares revisions -.I rev1 -and -.I rev2 -of the \*r file. -.PP -Both -.I rev1 -and -.I rev2 -may be given numerically or symbolically. -.SH EXAMPLE -The command -.LP -.B " rcsdiff f.c" -.LP -compares the latest revision on the default branch of the \*r file -to the contents of the working file -.BR f.c . -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -See -.BR ci (1) -for details. -.SH DIAGNOSTICS -Exit status is 0 for no differences during any comparison, -1 for some differences, 2 for trouble. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993 Paul Eggert. -.SH "SEE ALSO" -ci(1), co(1), diff(1), ident(1), rcs(1), rcsintro(1), rcsmerge(1), rlog(1) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.br Index: gnu/usr.bin/rcs/rcsdiff/rcsdiff.c =================================================================== --- gnu/usr.bin/rcs/rcsdiff/rcsdiff.c (revision 255904) +++ gnu/usr.bin/rcs/rcsdiff/rcsdiff.c (working copy) @@ -1,480 +0,0 @@ -/* Compare RCS revisions. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.19 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.18 1995/06/01 16:23:43 eggert - * (main): Pass "--binary" if -kb and if --binary makes a difference. - * Don't treat + options specially. - * - * Revision 5.17 1994/03/17 14:05:48 eggert - * Specify subprocess input via file descriptor, not file name. Remove lint. - * - * Revision 5.16 1993/11/09 17:40:15 eggert - * -V now prints version on stdout and exits. Don't print usage twice. - * - * Revision 5.15 1993/11/03 17:42:27 eggert - * Add -z. Ignore -T. Pass -Vn to `co'. Add Name keyword. - * Put revision numbers in -c output. Improve quality of diagnostics. - * - * Revision 5.14 1992/07/28 16:12:44 eggert - * Add -V. Use co -M for better dates with traditional diff -c. - * - * Revision 5.13 1992/02/17 23:02:23 eggert - * Output more readable context diff headers. - * Suppress needless checkout and comparison of identical revisions. - * - * Revision 5.12 1992/01/24 18:44:19 eggert - * Add GNU diff 1.15.2's new options. lint -> RCS_lint - * - * Revision 5.11 1992/01/06 02:42:34 eggert - * Update usage string. - * - * Revision 5.10 1991/10/07 17:32:46 eggert - * Remove lint. - * - * Revision 5.9 1991/08/19 03:13:55 eggert - * Add RCSINIT, -r$. Tune. - * - * Revision 5.8 1991/04/21 11:58:21 eggert - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.7 1990/12/13 06:54:07 eggert - * GNU diff 1.15 has -u. - * - * Revision 5.6 1990/11/01 05:03:39 eggert - * Remove unneeded setid check. - * - * Revision 5.5 1990/10/04 06:30:19 eggert - * Accumulate exit status across files. - * - * Revision 5.4 1990/09/27 01:31:43 eggert - * Yield 1, not EXIT_FAILURE, when diffs are found. - * - * Revision 5.3 1990/09/11 02:41:11 eggert - * Simplify -kkvl test. - * - * Revision 5.2 1990/09/04 17:07:19 eggert - * Diff's argv was too small by 1. - * - * Revision 5.1 1990/08/29 07:13:55 eggert - * Add -kkvl. - * - * Revision 5.0 1990/08/22 08:12:46 eggert - * Add -k, -V. Don't use access(). Add setuid support. - * Remove compile-time limits; use malloc instead. - * Don't pass arguments with leading '+' to diff; GNU DIFF treats them as options. - * Add GNU diff's flags. Make lock and temp files faster and safer. - * Ansify and Posixate. - * - * Revision 4.6 89/05/01 15:12:27 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.5 88/08/09 19:12:41 eggert - * Use execv(), not system(); yield exit status like diff(1)s; allow cc -R. - * - * Revision 4.4 87/12/18 11:37:46 narten - * changes Jay Lepreau made in the 4.3 BSD version, to add support for - * "-i", "-w", and "-t" flags and to permit flags to be bundled together, - * merged in. - * - * Revision 4.3 87/10/18 10:31:42 narten - * Updating version numbers. Changes relative to 1.1 actually - * relative to 4.1 - * - * Revision 1.3 87/09/24 13:59:21 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:15 jenkins - * Port to suns - * - * Revision 4.1 83/05/03 22:13:19 wft - * Added default branch, option -q, exit status like diff. - * Added fterror() to replace faterror(). - * - * Revision 3.6 83/01/15 17:52:40 wft - * Expanded mainprogram to handle multiple RCS files. - * - * Revision 3.5 83/01/06 09:33:45 wft - * Fixed passing of -c (context) option to diff. - * - * Revision 3.4 82/12/24 15:28:38 wft - * Added call to catchsig(). - * - * Revision 3.3 82/12/10 16:08:17 wft - * Corrected checking of return code from diff; improved error msgs. - * - * Revision 3.2 82/12/04 13:20:09 wft - * replaced getdelta() with gettree(). Changed diagnostics. - * - * Revision 3.1 82/11/28 19:25:04 wft - * Initial revision. - * - */ -#include "rcsbase.h" - -#if DIFF_L -static char const *setup_label P((struct buf*,char const*,char const[datesize])); -#endif -static void cleanup P((void)); - -static int exitstatus; -static RILE *workptr; -static struct stat workstat; - -mainProg(rcsdiffId, "rcsdiff", "$FreeBSD$") -{ - static char const cmdusage[] = - "\nrcsdiff usage: rcsdiff -ksubst -q -rrev1 [-rrev2] -Vn -xsuff -zzone [diff options] file ..."; - - int revnums; /* counter for revision numbers given */ - char const *rev1, *rev2; /* revision numbers from command line */ - char const *xrev1, *xrev2; /* expanded revision numbers */ - char const *expandarg, *lexpandarg, *suffixarg, *versionarg, *zonearg; -#if DIFF_L - static struct buf labelbuf[2]; - int file_labels; - char const **diff_label1, **diff_label2; - char date2[datesize]; -#endif - char const *cov[10 + !DIFF_L]; - char const **diffv, **diffp, **diffpend; /* argv for subsidiary diff */ - char const **pp, *p, *diffvstr; - struct buf commarg; - struct buf numericrev; /* expanded revision number */ - struct hshentries *gendeltas; /* deltas to be generated */ - struct hshentry * target; - char *a, *dcp, **newargv; - int no_diff_means_no_output; - register c; - - exitstatus = DIFF_SUCCESS; - - bufautobegin(&commarg); - bufautobegin(&numericrev); - revnums = 0; - rev1 = rev2 = xrev2 = 0; -#if DIFF_L - file_labels = 0; -#endif - expandarg = suffixarg = versionarg = zonearg = 0; - no_diff_means_no_output = true; - suffixes = X_DEFAULT; - - /* - * Room for runv extra + args [+ --binary] [+ 2 labels] - * + 1 file + 1 trailing null. - */ - diffv = tnalloc(char const*, 1 + argc + !!OPEN_O_BINARY + 2*DIFF_L + 2); - diffp = diffv + 1; - *diffp++ = DIFF; - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - while (a = *++argv, 0<--argc && *a++=='-') { - dcp = a; - while ((c = *a++)) switch (c) { - case 'r': - switch (++revnums) { - case 1: rev1=a; break; - case 2: rev2=a; break; - default: error("too many revision numbers"); - } - goto option_handled; - case '-': case 'D': - no_diff_means_no_output = false; - /* fall into */ - case 'C': case 'F': case 'I': case 'L': case 'W': -#if DIFF_L - if (c == 'L' && file_labels++ == 2) - faterror("too many -L options"); -#endif - *dcp++ = c; - if (*a) - do *dcp++ = *a++; - while (*a); - else { - if (!--argc) - faterror("-%c needs following argument%s", - c, cmdusage - ); - *diffp++ = *argv++; - } - break; - case 'y': - no_diff_means_no_output = false; - /* fall into */ - case 'B': case 'H': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'h': case 'i': case 'n': case 'p': - case 't': case 'u': case 'w': - *dcp++ = c; - break; - case 'q': - quietflag=true; - break; - case 'x': - suffixarg = *argv; - suffixes = *argv + 2; - goto option_handled; - case 'z': - zonearg = *argv; - zone_set(*argv + 2); - goto option_handled; - case 'T': - /* Ignore -T, so that RCSINIT can contain -T. */ - if (*a) - goto unknown; - break; - case 'V': - versionarg = *argv; - setRCSversion(versionarg); - goto option_handled; - case 'k': - expandarg = *argv; - if (0 <= str2expmode(expandarg+2)) - goto option_handled; - /* fall into */ - default: - unknown: - error("unknown option: %s%s", *argv, cmdusage); - }; - option_handled: - if (dcp != *argv+1) { - *dcp = 0; - *diffp++ = *argv; - } - } /* end of option processing */ - - for (pp = diffv+2, c = 0; ppnum; - - if (!fexpandsym(rev1, &numericrev, workptr)) continue; - if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue; - xrev1=target->num; -#if DIFF_L - if (diff_label1) - *diff_label1 = setup_label(&labelbuf[0], target->num, target->date); -#endif - - lexpandarg = expandarg; - if (revnums==2) { - if (!fexpandsym( - *rev2 ? rev2 : Dbranch ? Dbranch : Head->num, - &numericrev, - workptr - )) - continue; - if (!(target=genrevs(numericrev.string,(char *)0,(char *)0,(char *)0,&gendeltas))) continue; - xrev2=target->num; - if (no_diff_means_no_output && xrev1 == xrev2) - continue; - } else if ( - target->lockedby - && !lexpandarg - && Expand == KEYVAL_EXPAND - && WORKMODE(RCSstat.st_mode,true) == workstat.st_mode - ) - lexpandarg = "-kkvl"; - Izclose(&workptr); -#if DIFF_L - if (diff_label2) - if (revnums == 2) - *diff_label2 = setup_label(&labelbuf[1], target->num, target->date); - else { - time2date(workstat.st_mtime, date2); - *diff_label2 = setup_label(&labelbuf[1], (char*)0, date2); - } -#endif - - diagnose("retrieving revision %s\n", xrev1); - bufscpy(&commarg, "-p"); - bufscat(&commarg, rev1); /* not xrev1, for $Name's sake */ - - pp = &cov[3 + !DIFF_L]; - *pp++ = commarg.string; - if (lexpandarg) *pp++ = lexpandarg; - if (suffixarg) *pp++ = suffixarg; - if (versionarg) *pp++ = versionarg; - if (zonearg) *pp++ = zonearg; - *pp++ = RCSname; - *pp = 0; - - diffp = diffpend; -# if OPEN_O_BINARY - if (Expand == BINARY_EXPAND) - *diffp++ = "--binary"; -# endif - diffp[0] = maketemp(0); - if (runv(-1, diffp[0], cov)) { - rcserror("co failed"); - continue; - } - if (!rev2) { - diffp[1] = workname; - if (*workname == '-') { - char *dp = ftnalloc(char, strlen(workname)+3); - diffp[1] = dp; - *dp++ = '.'; - *dp++ = SLASH; - VOID strcpy(dp, workname); - } - } else { - diagnose("retrieving revision %s\n",xrev2); - bufscpy(&commarg, "-p"); - bufscat(&commarg, rev2); /* not xrev2, for $Name's sake */ - cov[3 + !DIFF_L] = commarg.string; - diffp[1] = maketemp(1); - if (runv(-1, diffp[1], cov)) { - rcserror("co failed"); - continue; - } - } - if (!rev2) - diagnose("diff%s -r%s %s\n", diffvstr, xrev1, workname); - else - diagnose("diff%s -r%s -r%s\n", diffvstr, xrev1, xrev2); - - diffp[2] = 0; - switch (runv(-1, (char*)0, diffv)) { - case DIFF_SUCCESS: - break; - case DIFF_FAILURE: - if (exitstatus == DIFF_SUCCESS) - exitstatus = DIFF_FAILURE; - break; - default: - workerror("diff failed"); - } - } - - tempunlink(); - exitmain(exitstatus); -} - - static void -cleanup() -{ - if (nerror) exitstatus = DIFF_TROUBLE; - Izclose(&finptr); - Izclose(&workptr); -} - -#if RCS_lint -# define exiterr rdiffExit -#endif - void -exiterr() -{ - tempunlink(); - _exit(DIFF_TROUBLE); -} - -#if DIFF_L - static char const * -setup_label(b, num, date) - struct buf *b; - char const *num; - char const date[datesize]; -{ - char *p; - char datestr[datesize + zonelenmax]; - VOID date2str(date, datestr); - bufalloc(b, - strlen(workname) - + sizeof datestr + 4 - + (num ? strlen(num) : 0) - ); - p = b->string; - if (num) - VOID sprintf(p, "-L%s\t%s\t%s", workname, datestr, num); - else - VOID sprintf(p, "-L%s\t%s", workname, datestr); - return p; -} -#endif Index: gnu/usr.bin/rcs/rcsfreeze/Makefile =================================================================== --- gnu/usr.bin/rcs/rcsfreeze/Makefile (revision 255904) +++ gnu/usr.bin/rcs/rcsfreeze/Makefile (working copy) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -SCRIPTS= rcsfreeze.sh -MAN= rcsfreeze.1 - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 =================================================================== --- gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 (revision 255904) +++ gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1 (working copy) @@ -1,68 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \s-1RCS\s0 -.TH RCSFREEZE 1 \*(Dt GNU -.SH NAME -rcsfreeze \- freeze a configuration of sources checked in under RCS -.SH SYNOPSIS -.B rcsfreeze -.RI [ "name" ] -.SH DESCRIPTION -.B rcsfreeze -assigns a symbolic revision -number to a set of \*r files that form a valid configuration. -.PP -The idea is to run -.B rcsfreeze -each time a new version is checked -in. A unique symbolic name (\c -.BI C_ number, -where -.I number -is increased each time -.B rcsfreeze -is run) is then assigned to the most -recent revision of each \*r file of the main trunk. -.PP -An optional -.I name -argument to -.B rcsfreeze -gives a symbolic name to the configuration. -The unique identifier is still generated -and is listed in the log file but it will not appear as -part of the symbolic revision name in the actual \*r files. -.PP -A log message is requested from the user for future reference. -.PP -The shell script works only on all \*r files at one time. -All changed files must be checked in already. -Run -.IR rcsclean (1) -first and see whether any sources remain in the current directory. -.SH FILES -.TP -.B RCS/.rcsfreeze.ver -version number -.TP -.B RCS/.rcsfreeze.log -log messages, most recent first -.SH AUTHOR -Stephan v. Bechtolsheim -.SH "SEE ALSO" -co(1), rcs(1), rcsclean(1), rlog(1) -.SH BUGS -.B rcsfreeze -does not check whether any sources are checked out and modified. -.PP -Although both source file names and RCS file names are accepted, -they are not paired as usual with RCS commands. -.PP -Error checking is rudimentary. -.PP -.B rcsfreeze -is just an optional example shell script, and should not be taken too seriously. -See \s-1CVS\s0 for a more complete solution. Index: gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh =================================================================== --- gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh (revision 255904) +++ gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh (working copy) @@ -1,99 +0,0 @@ -#! /bin/sh - -# rcsfreeze - assign a symbolic revision number to a configuration of RCS files - -# $FreeBSD$ - -# The idea is to run rcsfreeze each time a new version is checked -# in. A unique symbolic revision number (C_[number], where number -# is increased each time rcsfreeze is run) is then assigned to the most -# recent revision of each RCS file of the main trunk. -# -# If the command is invoked with an argument, then this -# argument is used as the symbolic name to freeze a configuration. -# The unique identifier is still generated -# and is listed in the log file but it will not appear as -# part of the symbolic revision name in the actual RCS file. -# -# A log message is requested from the user which is saved for future -# references. -# -# The shell script works only on all RCS files at one time. -# It is important that all changed files are checked in (there are -# no precautions against any error in this respect). -# file names: -# {RCS/}.rcsfreeze.ver version number -# {RCS/}.rscfreeze.log log messages, most recent first - -PATH=/bin:/usr/bin:$PATH -export PATH - -DATE=`LC_ALL=C date` || exit -# Check whether we have an RCS subdirectory, so we can have the right -# prefix for our paths. -if test -d RCS -then RCSDIR=RCS/ EXT= -else RCSDIR= EXT=,v -fi - -# Version number stuff, log message file -VERSIONFILE=${RCSDIR}.rcsfreeze.ver -LOGFILE=${RCSDIR}.rcsfreeze.log -# Initialize, rcsfreeze never run before in the current directory -test -r $VERSIONFILE || { echo 0 >$VERSIONFILE && >>$LOGFILE; } || exit - -# Get Version number, increase it, write back to file. -VERSIONNUMBER=`cat $VERSIONFILE` && -VERSIONNUMBER=`expr $VERSIONNUMBER + 1` && -echo $VERSIONNUMBER >$VERSIONFILE || exit - -# Symbolic Revision Number -SYMREV=C_$VERSIONNUMBER -# Allow the user to give a meaningful symbolic name to the revision. -SYMREVNAME=${1-$SYMREV} -echo >&2 "rcsfreeze: symbolic revision number computed: \"${SYMREV}\" -rcsfreeze: symbolic revision number used: \"${SYMREVNAME}\" -rcsfreeze: the two differ only when rcsfreeze invoked with argument -rcsfreeze: give log message, summarizing changes (end with EOF or single '.')" \ - || exit - -# Stamp the logfile. Because we order the logfile the most recent -# first we will have to save everything right now in a temporary file. -TMPLOG=/tmp/rcsfrz$$ -trap 'rm -f $TMPLOG; exit 1' 1 2 13 15 -# Now ask for a log message, continously add to the log file -( - echo "Version: $SYMREVNAME($SYMREV), Date: $DATE ------------" || exit - while read MESS - do - case $MESS in - .) break - esac - echo " $MESS" || exit - done - echo "----------- -" && - cat $LOGFILE -) >$TMPLOG && - -# combine old and new logfiles -cp $TMPLOG $LOGFILE && -rm -f $TMPLOG && - -# Now the real work begins by assigning a symbolic revision number -# to each rcs file. Take the most recent version on the default branch. - -# If there are any .*,v files, throw them in too. -# But ignore RCS/.* files that do not end in ,v. -DOTFILES= -for DOTFILE in ${RCSDIR}.*,v -do - if test -f "$DOTFILE" - then - DOTFILES="${RCSDIR}.*,v" - break - fi -done - -exec rcs -q -n$SYMREVNAME: ${RCSDIR}*$EXT $DOTFILES Index: gnu/usr.bin/rcs/rcsmerge/Makefile =================================================================== --- gnu/usr.bin/rcs/rcsmerge/Makefile (revision 255904) +++ gnu/usr.bin/rcs/rcsmerge/Makefile (working copy) @@ -1,8 +0,0 @@ -PROG= rcsmerge -SRCS= rcsmerge.c -CFLAGS+= -I${.CURDIR}/../lib -LDADD= ${LIBRCS} -DPADD= ${LIBRCS} - -.include "../../Makefile.inc" -.include Index: gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 =================================================================== --- gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 (revision 255904) +++ gnu/usr.bin/rcs/rcsmerge/rcsmerge.1 (working copy) @@ -1,189 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds r \&\s-1RCS\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH RCSMERGE 1 \*(Dt GNU -.SH NAME -rcsmerge \- merge RCS revisions -.SH SYNOPSIS -.B rcsmerge -.RI [ options ] " file" -.SH DESCRIPTION -.B rcsmerge -incorporates the changes between two revisions -of an \*r file into the corresponding working file. -.PP -Pathnames matching an \*r suffix denote \*r files; -all others denote working files. -Names are paired as explained in -.BR ci (1). -.PP -At least one revision must be specified with one of the options -described below, usually -.BR \-r . -At most two revisions may be specified. -If only one revision is specified, the latest -revision on the default branch (normally the highest branch on the trunk) -is assumed for the second revision. -Revisions may be specified numerically or symbolically. -.PP -.B rcsmerge -prints a warning if there are overlaps, and delimits -the overlapping regions as explained in -.BR merge (1). -The command is useful for incorporating changes into a checked-out revision. -.SH OPTIONS -.TP -.B \-A -Output conflicts using the -.B \-A -style of -.BR diff3 (1), -if supported by -.BR diff3 . -This merges all changes leading from -.I file2 -to -.I file3 -into -.IR file1 , -and generates the most verbose output. -.TP -\f3\-E\fP, \f3\-e\fP -These options specify conflict styles that generate less information -than -.BR \-A . -See -.BR diff3 (1) -for details. -The default is -.BR \-E . -With -.BR \-e , -.B rcsmerge -does not warn about conflicts. -.TP -.BI \-k subst -Use -.I subst -style keyword substitution. -See -.BR co (1) -for details. -For example, -.B "\-kk\ \-r1.1\ \-r1.2" -ignores differences in keyword values when merging the changes from -.B 1.1 -to -.BR 1.2 . -It normally does not make sense to merge binary files as if they were text, so -.B rcsmerge -refuses to merge files if -.B \-kb -expansion is used. -.TP -.BR \-p [\f2rev\fP] -Send the result to standard output instead of overwriting the working file. -.TP -.BR \-q [\f2rev\fP] -Run quietly; do not print diagnostics. -.TP -.BR \-r [\f2rev\fP] -Merge with respect to revision -.IR rev . -Here an empty -.I rev -stands for the latest revision on the default branch, normally the head. -.TP -.B \-T -This option has no effect; -it is present for compatibility with other \*r commands. -.TP -.BI \-V -Print \*r's version number. -.TP -.BI \-V n -Emulate \*r version -.IR n . -See -.BR co (1) -for details. -.TP -.BI \-x "suffixes" -Use -.I suffixes -to characterize \*r files. -See -.BR ci (1) -for details. -.TP -.BI \-z zone -Use -.I zone -as the time zone for keyword substitution. -See -.BR co (1) -for details. -.SH EXAMPLES -Suppose you have released revision 2.8 of -.BR f.c . -Assume -furthermore that after you complete an unreleased revision 3.4, you receive -updates to release 2.8 from someone else. -To combine the updates to 2.8 and your changes between 2.8 and 3.4, -put the updates to 2.8 into file f.c and execute -.LP -.B " rcsmerge \-p \-r2.8 \-r3.4 f.c >f.merged.c" -.PP -Then examine -.BR f.merged.c . -Alternatively, if you want to save the updates to 2.8 in the \*r file, -check them in as revision 2.8.1.1 and execute -.BR "co \-j": -.LP -.B " ci \-r2.8.1.1 f.c" -.br -.B " co \-r3.4 \-j2.8:2.8.1.1 f.c" -.PP -As another example, the following command undoes the changes -between revision 2.4 and 2.8 in your currently checked out revision -in -.BR f.c . -.LP -.B " rcsmerge \-r2.8 \-r2.4 f.c" -.PP -Note the order of the arguments, and that -.B f.c -will be -overwritten. -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -See -.BR ci (1) -for details. -.SH DIAGNOSTICS -Exit status is 0 for no overlaps, 1 for some overlaps, 2 for trouble. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH "SEE ALSO" -ci(1), co(1), ident(1), merge(1), rcs(1), rcsdiff(1), rcsintro(1), rlog(1), -rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.br Index: gnu/usr.bin/rcs/rcsmerge/rcsmerge.c =================================================================== --- gnu/usr.bin/rcs/rcsmerge/rcsmerge.c (revision 255904) +++ gnu/usr.bin/rcs/rcsmerge/rcsmerge.c (working copy) @@ -1,286 +0,0 @@ -/* Merge RCS revisions. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.15 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.14 1995/06/01 16:23:43 eggert - * (main): Report an error if -kb, so don't worry about binary stdout. - * Punctuate messages properly. Rewrite to avoid `goto end'. - * - * Revision 5.13 1994/03/17 14:05:48 eggert - * Specify subprocess input via file descriptor, not file name. Remove lint. - * - * Revision 5.12 1993/11/09 17:40:15 eggert - * -V now prints version on stdout and exits. Don't print usage twice. - * - * Revision 5.11 1993/11/03 17:42:27 eggert - * Add -A, -E, -e, -z. Ignore -T. Allow up to three file labels. - * Pass -Vn to `co'. Pass unexpanded revision name to `co', so that Name works. - * - * Revision 5.10 1992/07/28 16:12:44 eggert - * Add -V. - * - * Revision 5.9 1992/01/24 18:44:19 eggert - * lint -> RCS_lint - * - * Revision 5.8 1992/01/06 02:42:34 eggert - * Update usage string. - * - * Revision 5.7 1991/11/20 17:58:09 eggert - * Don't Iopen(f, "r+"); it's not portable. - * - * Revision 5.6 1991/08/19 03:13:55 eggert - * Add -r$. Tune. - * - * Revision 5.5 1991/04/21 11:58:27 eggert - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.4 1991/02/25 07:12:43 eggert - * Merging a revision to itself is no longer an error. - * - * Revision 5.3 1990/11/01 05:03:50 eggert - * Remove unneeded setid check. - * - * Revision 5.2 1990/09/04 08:02:28 eggert - * Check for I/O error when reading working file. - * - * Revision 5.1 1990/08/29 07:14:04 eggert - * Add -q. Pass -L options to merge. - * - * Revision 5.0 1990/08/22 08:13:41 eggert - * Propagate merge's exit status. - * Remove compile-time limits; use malloc instead. - * Make lock and temp files faster and safer. Ansify and Posixate. Add -V. - * Don't use access(). Tune. - * - * Revision 4.5 89/05/01 15:13:16 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.4 88/08/09 19:13:13 eggert - * Beware merging into a readonly file. - * Beware merging a revision to itself (no change). - * Use execv(), not system(); yield exit status like diff(1)'s. - * - * Revision 4.3 87/10/18 10:38:02 narten - * Updating version numbers. Changes relative to version 1.1 - * actually relative to 4.1 - * - * Revision 1.3 87/09/24 14:00:31 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:36 jenkins - * Port to suns - * - * Revision 4.1 83/03/28 11:14:57 wft - * Added handling of default branch. - * - * Revision 3.3 82/12/24 15:29:00 wft - * Added call to catchsig(). - * - * Revision 3.2 82/12/10 21:32:02 wft - * Replaced getdelta() with gettree(); improved error messages. - * - * Revision 3.1 82/11/28 19:27:44 wft - * Initial revision. - * - */ -#include "rcsbase.h" - -static char const co[] = CO; - -mainProg(rcsmergeId, "rcsmerge", "$FreeBSD$") -{ - static char const cmdusage[] = - "\nrcsmerge usage: rcsmerge -rrev1 [-rrev2] -ksubst -{pq}[rev] -Vn -xsuff -zzone file"; - static char const quietarg[] = "-q"; - - register int i; - char *a, **newargv; - char const *arg[3]; - char const *rev[3], *xrev[3]; /*revision numbers*/ - char const *edarg, *expandarg, *suffixarg, *versionarg, *zonearg; - int tostdout; - int status; - RILE *workptr; - struct buf commarg; - struct buf numericrev; /* holds expanded revision number */ - struct hshentries *gendeltas; /* deltas to be generated */ - struct hshentry * target; - - bufautobegin(&commarg); - bufautobegin(&numericrev); - edarg = rev[1] = rev[2] = 0; - status = 0; /* Keep lint happy. */ - tostdout = false; - expandarg = suffixarg = versionarg = zonearg = quietarg; /* no-op */ - suffixes = X_DEFAULT; - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - while (a = *++argv, 0<--argc && *a++=='-') { - switch (*a++) { - case 'p': - tostdout=true; - goto revno; - - case 'q': - quietflag = true; - revno: - if (!*a) - break; - /* falls into -r */ - case 'r': - if (!rev[1]) - rev[1] = a; - else if (!rev[2]) - rev[2] = a; - else - error("too many revision numbers"); - break; - - case 'A': case 'E': case 'e': - if (*a) - goto unknown; - edarg = *argv; - break; - - case 'x': - suffixarg = *argv; - suffixes = a; - break; - case 'z': - zonearg = *argv; - zone_set(a); - break; - case 'T': - /* Ignore -T, so that RCSINIT can contain -T. */ - if (*a) - goto unknown; - break; - case 'V': - versionarg = *argv; - setRCSversion(versionarg); - break; - - case 'k': - expandarg = *argv; - if (0 <= str2expmode(expandarg+2)) - break; - /* fall into */ - default: - unknown: - error("unknown option: %s%s", *argv, cmdusage); - }; - } /* end of option processing */ - - if (!rev[1]) faterror("no base revision number given"); - - /* Now handle all pathnames. */ - - if (!nerror) { - if (argc < 1) - faterror("no input file%s", cmdusage); - if (0 < pairnames(argc, argv, rcsreadopen, true, false)) { - - if (argc>2 || (argc==2 && argv[1])) - warn("excess arguments ignored"); - if (Expand == BINARY_EXPAND) - workerror("merging binary files"); - diagnose("RCS file: %s\n", RCSname); - if (!(workptr = Iopen(workname, FOPEN_R_WORK, (struct stat*)0))) - efaterror(workname); - - gettree(); /* reads in the delta tree */ - - if (!Head) rcsfaterror("no revisions present"); - - if (!*rev[1]) - rev[1] = Dbranch ? Dbranch : Head->num; - if (fexpandsym(rev[1], &numericrev, workptr) - && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char*)0, &gendeltas)) - ) { - xrev[1] = target->num; - if (!rev[2] || !*rev[2]) - rev[2] = Dbranch ? Dbranch : Head->num; - if (fexpandsym(rev[2], &numericrev, workptr) - && (target=genrevs(numericrev.string, (char *)0, (char *)0, (char *)0, &gendeltas)) - ) { - xrev[2] = target->num; - - if (strcmp(xrev[1],xrev[2]) == 0) { - if (tostdout) { - fastcopy(workptr, stdout); - Ofclose(stdout); - } - } else { - Izclose(&workptr); - - for (i=1; i<=2; i++) { - diagnose("retrieving revision %s\n", xrev[i]); - bufscpy(&commarg, "-p"); - bufscat(&commarg, rev[i]); /* not xrev[i], for $Name's sake */ - if (run( - -1, - /* Do not collide with merger.c maketemp(). */ - arg[i] = maketemp(i+2), - co, quietarg, commarg.string, - expandarg, suffixarg, versionarg, zonearg, - RCSname, (char*)0 - )) - rcsfaterror("co failed"); - } - diagnose("Merging differences between %s and %s into %s%s\n", - xrev[1], xrev[2], workname, - tostdout?"; result to stdout":""); - - arg[0] = xrev[0] = workname; - status = merge(tostdout, edarg, xrev, arg); - } - } - } - - Izclose(&workptr); - } - } - tempunlink(); - exitmain(nerror ? DIFF_TROUBLE : status); -} - -#if RCS_lint -# define exiterr rmergeExit -#endif - void -exiterr() -{ - tempunlink(); - _exit(DIFF_TROUBLE); -} Index: gnu/usr.bin/rcs/rcstest =================================================================== --- gnu/usr.bin/rcs/rcstest (revision 255904) +++ gnu/usr.bin/rcs/rcstest (working copy) @@ -1,454 +0,0 @@ -#! /bin/sh - -# Test RCS's functions. -# The RCS commands are searched for in the PATH as usual; -# to test the working directory's commands, prepend . to your PATH. - -# Test RCS by creating files RCS/a.* and RCS/a.c. -# If all goes well, output nothing, and remove the temporary files. -# Otherwise, send a message to standard output. -# Exit status is 0 if OK, 1 if an RCS bug is found, and 2 if scaffolding fails. -# With the -v option, output more debugging info. - -# If diff outputs `No differences encountered' when comparing identical files, -# then rcstest may also output these noise lines; ignore them. - -# The current directory and ./RCS must be readable, writable, and searchable. - -# $FreeBSD$ - - -# Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert -# Distributed under license by the Free Software Foundation, Inc. -# -# This file is part of RCS. -# -# RCS is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# RCS is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with RCS; see the file COPYING. -# If not, write to the Free Software Foundation, -# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# Report problems and direct all questions to: -# -# rcs-bugs@cs.purdue.edu - -# The Makefile overrides the following defaults. -: ${ALL_CFLAGS=-Dhas_conf_h} -: ${CC=cc} -: ${DIFF=diff} -# : ${LDFLAGS=} ${LIBS=} tickles old shell bug - -CL="$CC $ALL_CFLAGS $LDFLAGS -o a.out" -L=$LIBS - -RCSINIT=-x -export RCSINIT - -SLASH=/ -RCSfile=RCS${SLASH}a.c -RCS_alt=RCS${SLASH}a.d -lockfile=RCS${SLASH}a._ - -case $1 in --v) q=; set -x;; -'') q=-q;; -*) echo >&2 "$0: usage: $0 [-v]"; exit 2 -esac - -if test -d RCS -then rmdir=: -else rmdir=rmdir; mkdir RCS || exit -fi - -rm -f a.* $RCSfile $RCS_alt $lockfile && -echo 1.1 >a.11 && -echo 1.1.1.1 >a.3x1 && -echo 1.2 >a.12 || { echo "#initialization failed"; exit 2; } - -case "`$DIFF -c a.11 a.3x1`" in -*!\ 1.1.1.1) - diff="$DIFF -c";; -*) - echo "#warning: $DIFF -c does not work, so diagnostics may be cryptic" - diff=$DIFF -esac - -rcs -i -L -ta.11 $q a.c && -test -r $RCSfile || { - echo "#rcs -i -L failed; perhaps RCS is not properly installed." - exit 1 -} - -rlog a.c >/dev/null || { echo "#rlog failed on empty RCS file"; exit 1; } -rm -f $RCSfile || exit 2 - -cp a.11 a.c && -ci -ta.11 -mm $q a.c && -test -r $RCSfile && -rcs -L $q a.c || { echo "#ci+rcs -L failed"; exit 1; } -test ! -f a.c || { echo "#ci did not remove working file"; exit 1; } -for l in '' '-l' -do - co $l $q a.c && - test -f a.c || { echo '#co' $l did not create working file; exit 1; } - $diff a.11 a.c || { echo '#ci' followed by co $l is not a no-op; exit 1; } -done - -cp a.12 a.c && -ci -mm $q a.c && -co $q a.c && -$diff a.12 a.c || { echo "#ci+co failed"; exit 1; } - -rm -f a.c && -co -r1.1 $q a.c && -$diff a.11 a.c || { echo "#can't retrieve first revision"; exit 1; } - -rm -f a.c && -cp a.3x1 a.c && -ci -r1.1.1 -mm $q a.c && -co -r1.1.1.1 $q a.c && -$diff a.3x1 a.c || { echo "#branches failed"; exit 1; } - -rm -f a.c && -co -l $q a.c && -ci -f -mm $q a.c && -co -r1.3 $q a.c && -$diff a.12 a.c || { echo "#(co -l; ci -f) failed"; exit 1; } - -rm -f a.c && -co -l $q a.c && -echo 1.4 >a.c && -ci -l -mm $q a.c && -echo error >a.c && -ci -mm $q a.c || { echo "#ci -l failed"; exit 1; } - -rm -f a.c && -co -l $q a.c && -echo 1.5 >a.c && -ci -u -mm $q a.c && -test -r a.c || { echo "#ci -u didn't create a working file"; exit 1; } -rm -f a.c && -echo error >a.c || exit 2 -ci -mm $q a.c 2>/dev/null && { echo "#ci -u didn't unlock the file"; exit 1; } - -rm -f a.c && -rcs -l $q a.c && -co -u $q a.c || { echo "#rcs -l + co -u failed"; exit 1; } -rm -f a.c && -echo error >a.c || exit 2 -ci -mm $q a.c 2>/dev/null && { echo "#co -u didn't unlock the file"; exit 1; } - -rm -f a.c && -cp a.11 a.c && -co -f $q a.c || { echo "#co -f failed"; exit 1; } -$diff a.11 a.c >/dev/null && { echo "#co -f had no effect"; exit 1; } - -co -p1.1 $q a.c >a.t && -$diff a.11 a.t || { echo "#co -p failed"; exit 1; } - -for n in n N -do - rm -f a.c && - co -l $q a.c && - echo $n >a.$n && - cp a.$n a.c && - ci -${n}n -mm $q a.c && - co -rn $q a.c && - $diff a.$n a.c || { echo "#ci -$n failed"; exit 1; } -done - -case $LOGNAME in -?*) me=$LOGNAME;; -*) - case $USER in - ?*) me=$USER;; - *) - me=`who am i` || exit 2 - me=`echo "$me" | sed -e 's/ .*//' -e 's/.*!//'` - case $me in - '') echo >&2 "$0: cannot deduce user name"; exit 2 - esac - esac -esac - - -# Get the date of the previous revision in UTC. -date=`rlog -r a.c | sed -n '/^date: /{ s///; s/;.*//; p; q; }'` || exit -case $date in -[0-9][0-9][0-9]*[0-9]/[0-1][0-9]/[0-3][0-9]\ [0-2][0-9]:[0-5][0-9]:[0-6][0-9]);; -*) echo >&2 "$0: $date: bad rlog date output"; exit 1 -esac -PWD=`pwd` && export PWD && -rm -f a.c && -co -l $q a.c && -sed 's/@/$/g' >a.kv <a.k && -sed -e 's/w s [$]/w s '"$me"' $/' -e 's/[$]Locker: /&'"$me/" a.kv >a.kvl && -sed s/Oz//g a.kv >a.e && -sed s/Oz/N/g a.kv >a.N && -sed -e '/\$/!d' -e 's/\$$/: old $/' a.k >a.o && -sed -e 's/\$[^ ]*: //' -e 's/ \$//' a.kv >a.v && -cp a.o a.c && -ci -d"$date" -nOz -ss -ww -u2.1 -mm $q a.c && -$diff a.kv a.c || { echo "#keyword expansion failed"; exit 1; } -co -pOz -ko $q a.c >a.oo && -$diff a.o a.oo || { echo "#co -p -ko failed"; exit 1; } -cp a.kv a.o && cp a.o a.b || exit 2 -rcs -oOz $q a.c && -rcs -l $q a.c && -ci -k -u $q a.c && -$diff a.kv a.c || { echo "#ci -k failed"; exit 1; } -sed -n 's/^[^$]*\$/$/p' a.kv >a.i && -ident a.c >a.i1 && -sed -e 1d -e 's/^[ ]*//' a.i1 >a.i2 && -$diff a.i a.i2 || { echo "#ident failed"; exit 1; } - -rcs -i $q a.c 2>/dev/null && { echo "#rcs -i permitted existing file"; exit 1; } - -rm -f a.c && -co -l $q a.c && -echo 2.2 >a.c && -ci -mm $q a.c && -echo 1.1.1.2 >a.c && -rcs -l1.1.1 $q a.c && -ci -r1.1.1.2 -mm $q a.c && -rcs -b1.1.1 $q a.c && -test " `co -p $q a.c`" = ' 1.1.1.2' || { echo "#rcs -b1.1.1 failed"; exit 1; } -rcs -b $q a.c && -test " `co -p $q a.c`" = ' 2.2' || { echo "#rcs -b failed"; exit 1; } - -echo 2.3 >a.c || exit 2 -rcs -U $q a.c || { echo "#rcs -U failed"; exit 1; } -ci -mm $q a.c || { echo "#rcs -U didn't unset strict locking"; exit 1; } -rcs -L $q a.c || { echo "#rcs -L failed"; exit 1; } -echo error >a.c || exit 2 -ci -mm $q a.c 2>/dev/null && { echo "#ci retest failed"; exit 1; } - -rm -f a.c && -log0=`rlog -h a.c` && -co -l $q a.c && -ci -mm $q a.c && -log1=`rlog -h a.c` && -test " $log0" = " $log1" || { echo "#unchanged ci didn't revert"; exit 1; } - -rm -f a.c && -rcs -nN:1.1 $q a.c && -co -rN $q a.c && -$diff a.11 a.c || { echo "#rcs -n failed"; exit 1; } - -rm -f a.c && -rcs -NN:2.1 $q a.c && -co -rN $q a.c && -$diff a.N a.c || { echo "#rcs -N failed"; exit 1; } - -rm -f a.c && -co -l $q a.c && -echo ':::$''Log$' >a.c && -ci -u -mm $q a.c && -test " `sed '$!d' a.c`" = ' :::' || { echo "#comment leader failed"; exit 1; } - -rm -f a.c && -rcs -o2.2: $q a.c && -co $q a.c && -$diff a.e a.c || { echo "#rcs -o failed"; exit 1; } - -rcsdiff -r1.1 -rOz $q a.c >a.0 -case $? in -1) ;; -*) echo "#rcsdiff bad status"; exit 1 -esac -$DIFF a.11 a.kv >a.1 -$diff a.0 a.1 || { echo "#rcsdiff failed"; exit 1; } - -rcs -l2.1 $q a.c || { echo "#rcs -l2.1 failed"; exit 1; } -for i in b k kv kvl o v -do - rm -f a.c && - cp a.$i a.c && - rcsdiff -k$i -rOz $q a.c || { echo "#rcsdiff -k$i failed"; exit 1; } -done -co -p1.1 -ko $q a.c >a.t && -$diff a.11 a.t || { echo "#co -p1.1 -ko failed"; exit 1; } -rcs -u2.1 $q a.c || { echo "#rcs -u2.1 failed"; exit 1; } - -rm -f a.c && -rcsclean $q a.c && -rcsclean -u $q a.c || { echo "#rcsclean botched a nonexistent file"; exit 1; } - -rm -f a.c && -co $q a.c && -rcsclean -n $q a.c && -rcsclean -n -u $q a.c && -test -f a.c || { echo "#rcsclean -n removed a file"; exit 1; } - -rm -f a.c && -co $q a.c && -rcsclean $q a.c && -test ! -f a.c || { echo "#rcsclean missed an unlocked file"; exit 1; } - -rm -f a.c && -co -l $q a.c && -rcsclean $q a.c && -test -f a.c || { echo "#rcsclean removed a locked file"; exit 1; } -rcsclean -u $q a.c && -test ! -f a.c || { - echo "#rcsclean -u missed an unchanged locked file"; exit 1; -} - -rm -f a.c && -co -l $q a.c && -echo change >>a.c && -rcsclean $q a.c && -rcsclean $q -u a.c && -test -f a.c || { echo "#rcsclean removed a changed file"; exit 1; } - -rm -f a.c && -co -l $q a.c && -cat >a.c <<'EOF' -2.2 -a -b -c -d -EOF -test $? = 0 && -ci -l -mm $q a.c && -co -p2.2 $q a.c | sed -e s/2.2/2.3/ -e s/b/b1/ >a.c && -ci -l -mm $q a.c && -co -p2.2 $q a.c | sed -e s/2.2/new/ -e s/d/d1/ >a.c || exit 2 -cat >a.0 <<'EOF' -2.3 -a -b1 -c -d1 -EOF -cat >a.1 <<'EOF' -<<<<<<< a.c -new -======= -2.3 ->>>>>>> 2.3 -a -b1 -c -d1 -EOF -rcsmerge -E -r2.2 -r2.3 $q a.c -case $? in -0) - if $diff a.0 a.c >/dev/null - then echo "#warning: diff3 -E does not work, " \ - "so merge and rcsmerge ignore overlaps and suppress overlap lines." - else - $diff a.1 a.c || { echo "#rcsmerge failed (status 0)"; exit 1; } - echo "#warning: The diff3 lib program exit status ignores overlaps," \ - "so rcsmerge does not warn about overlap lines that it generates." - fi - ;; -1) - $diff a.1 a.c || { echo "#rcsmerge failed (status 1)"; exit 1; } - ;; -*) - echo "#rcsmerge bad status"; exit 1 -esac - -# Avoid `tr' if possible; it's not portable, and it can't handle null bytes. -# Our substitute exclusive-ORs with '\n'; -# this ensures null bytes on output, which is even better than `tr', -# since some diffs think a file is binary only if it contains null bytes. -cat >a.c <<'EOF' -#include -int main() { - int c; - while ((c=getchar()) != EOF) - putchar(c ^ '\n'); - return 0; -} -EOF -tr=tr -if (rm -f a.exe a.out && $CL a.c $L >&2) >/dev/null 2>&1 -then - if test -s a.out - then tr=./a.out - elif test -s a.exe - then tr=./a.exe - fi -fi -{ - co -p $q a.c | $tr '\012' '\200' >a.24 && - cp a.24 a.c && - ciOut=`(ci -l -mm $q a.c 2>&1)` && - case $ciOut in - ?*) echo >&2 "$ciOut" - esac && - co -p $q a.c | $tr '\200' '\012' >a.c && - rcsdiff -r2.3 $q a.c >/dev/null && - - echo 2.5 >a.c && - ci -l -mm $q a.c && - cp a.24 a.c && - rcsdiff -r2.4 $q a.c >/dev/null -} || echo "#warning: Traditional diff is used, so RCS is limited to text files." - -rcs -u -o2.4: $q a.c || { echo "#rcs -u -o failed"; exit 1; } - -rcs -i -Aa.c -t- $q a.d || { echo "#rcs -i -A failed"; exit 1; } - -rlog -r2.1 a.c >a.t && -grep '^checked in with -k' a.t >/dev/null && -sed '/^checked in with -k/d' a.t >a.u && -$diff - a.u < Index: gnu/usr.bin/rcs/rlog/rlog.1 =================================================================== --- gnu/usr.bin/rcs/rlog/rlog.1 (revision 255904) +++ gnu/usr.bin/rcs/rlog/rlog.1 (working copy) @@ -1,318 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $FreeBSD$ -.ds i \&\s-1ISO\s0 -.ds r \&\s-1RCS\s0 -.ds u \&\s-1UTC\s0 -.if n .ds - \%-- -.if t .ds - \(em -.TH RLOG 1 \*(Dt GNU -.SH NAME -rlog \- print log messages and other information about RCS files -.SH SYNOPSIS -.B rlog -.RI [ " options " ] " file " .\|.\|. -.SH DESCRIPTION -.B rlog -prints information about \*r files. -.PP -Pathnames matching an \*r suffix denote \*r files; -all others denote working files. -Names are paired as explained in -.BR ci (1). -.PP -.B rlog -prints the following information for each -\*r file: \*r pathname, working pathname, head (i.e., the number -of the latest revision on the trunk), default branch, access list, locks, -symbolic names, suffix, total number of revisions, -number of revisions selected for printing, and -descriptive text. This is followed by entries for the selected revisions in -reverse chronological order for each branch. For each revision, -.B rlog -prints revision number, author, date/time, state, number of -lines added/deleted (with respect to the previous revision), -locker of the revision (if any), and log message. -All times are displayed in Coordinated Universal Time (\*u) by default; -this can be overridden with -.BR \-z . -Without options, -.B rlog -prints complete information. -The options below restrict this output. -.nr n \w'\f3\-V\fP\f2n\fP'+2n-1/1n -.ds n \nn -.if \n(.g .if r an-tag-sep .ds n \w'\f3\-V\fP\f2n\fP'u+\n[an-tag-sep]u -.TP \*n -.B \-L -Ignore \*r files that have no locks set. -This is convenient in combination with -.BR \-h , -.BR \-l , -and -.BR \-R . -.TP -.B \-R -Print only the name of the \*r file. -This is convenient for translating a -working pathname into an \*r pathname. -.TP -.BI \-v "[string]" -Print only the working pathname and tip-revision. -The optional string is prepended to the outputline. -.TP -.B \-h -Print only the \*r pathname, working pathname, head, -default branch, access list, locks, -symbolic names, and suffix. -.TP -.B \-t -Print the same as -.BR \-h , -plus the descriptive text. -.TP -.B \-N -Do not print the symbolic names. -.TP -.B \-b -Print information about the revisions on the default branch, normally -the highest branch on the trunk. -.TP -.BI \-d "dates" -Print information about revisions with a checkin date/time in the ranges given by -the semicolon-separated list of -.IR dates . -A range of the form -.IB d1 < d2 -or -.IB d2 > d1 -selects the revisions that were deposited between -.I d1 -and -.I d2 -exclusive. -A range of the form -.BI < d -or -.IB d > -selects -all revisions earlier than -.IR d . -A range of the form -.IB d < -or -.BI > d -selects -all revisions dated later than -.IR d . -If -.B < -or -.B > -is followed by -.B = -then the ranges are inclusive, not exclusive. -A range of the form -.I d -selects the single, latest revision dated -.I d -or earlier. -The date/time strings -.IR d , -.IR d1 , -and -.I d2 -are in the free format explained in -.BR co (1). -Quoting is normally necessary, especially for -.B < -and -.BR > . -Note that the separator is -a semicolon. -.TP -.BR \-l [\f2lockers\fP] -Print information about locked revisions only. -In addition, if the comma-separated list -.I lockers -of login names is given, -ignore all locks other than those held by the -.IR lockers . -For example, -.B "rlog\ \-L\ \-R\ \-lwft\ RCS/*" -prints the name of \*r files locked by the user -.BR wft . -.TP -.BR \-r [\f2revisions\fP] -prints information about revisions given in the comma-separated list -.I revisions -of revisions and ranges. -A range -.IB rev1 : rev2 -means revisions -.I rev1 -to -.I rev2 -on the same branch, -.BI : rev -means revisions from the beginning of the branch up to and including -.IR rev , -and -.IB rev : -means revisions starting with -.I rev -to the end of the branch containing -.IR rev . -An argument that is a branch means all -revisions on that branch. -A range of branches means all revisions -on the branches in that range. -A branch followed by a -.B .\& -means the latest revision in that branch. -A bare -.B \-r -with no -.I revisions -means the latest revision on the default branch, normally the trunk. -.TP -.BI \-s states -prints information about revisions whose state attributes match one of the -states given in the comma-separated list -.IR states . -.TP -.BR \-w [\f2logins\fP] -prints information about revisions checked in by users with -login names appearing in the comma-separated list -.IR logins . -If -.I logins -is omitted, the user's login is assumed. -.TP -.B \-T -This option has no effect; -it is present for compatibility with other \*r commands. -.TP -.BI \-V -Print \*r's version number. -.TP -.BI \-V n -Emulate \*r version -.I n -when generating logs. -See -.BR co (1) -for more. -.TP -.BI \-x "suffixes" -Use -.I suffixes -to characterize \*r files. -See -.BR ci (1) -for details. -.PP -.B rlog -prints the intersection of the revisions selected with -the options -.BR \-d , -.BR \-l , -.BR \-s , -and -.BR \-w , -intersected -with the union of the revisions selected by -.B \-b -and -.BR \-r . -.TP -.BI \-z zone -specifies the date output format, -and specifies the default time zone for -.I date -in the -.BI \-d dates -option. -The -.I zone -should be empty, a numeric \*u offset, or the special string -.B LT -for local time. -The default is an empty -.IR zone , -which uses the traditional \*r format of \*u without any time zone indication -and with slashes separating the parts of the date; -otherwise, times are output in \*i 8601 format with time zone indication. -For example, if local time is January 11, 1990, 8pm Pacific Standard Time, -eight hours west of \*u, -then the time is output as follows: -.RS -.LP -.RS -.nf -.ta \w'\f3\-z+05:30\fP 'u +\w'\f31990-01-11 09:30:00+05:30\fP 'u -.ne 4 -\f2option\fP \f2time output\fP -\f3\-z\fP \f31990/01/12 04:00:00\fP \f2(default)\fP -\f3\-zLT\fP \f31990-01-11 20:00:00\-08\fP -\f3\-z+05:30\fP \f31990-01-12 09:30:00+05:30\fP -.ta 4n +4n +4n +4n -.fi -.RE -.SH EXAMPLES -.LP -.nf -.B " rlog \-L \-R RCS/*" -.B " rlog \-L \-h RCS/*" -.B " rlog \-L \-l RCS/*" -.B " rlog RCS/*" -.fi -.LP -The first command prints the names of all \*r files in the subdirectory -.B RCS -that have locks. The second command prints the headers of those files, -and the third prints the headers plus the log messages of the locked revisions. -The last command prints complete information. -.SH ENVIRONMENT -.TP -.B \s-1RCSINIT\s0 -options prepended to the argument list, separated by spaces. -See -.BR ci (1) -for details. -.SH DIAGNOSTICS -The exit status is zero if and only if all operations were successful. -.SH IDENTIFICATION -Author: Walter F. Tichy. -.br -Manual Page Revision: \*(Rv; Release Date: \*(Dt. -.br -Copyright \(co 1982, 1988, 1989 Walter F. Tichy. -.br -Copyright \(co 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert. -.SH "SEE ALSO" -ci(1), co(1), ident(1), rcs(1), rcsdiff(1), rcsintro(1), rcsmerge(1), -rcsfile(5) -.br -Walter F. Tichy, -\*r\*-A System for Version Control, -.I "Software\*-Practice & Experience" -.BR 15 , -7 (July 1985), 637-654. -.SH BUGS -The separator for revision ranges in the -.B \-r -option used to be -.B \- -instead of -.BR : , -but this leads to confusion when symbolic names contain -.BR \- . -For backwards compatibility -.B "rlog \-r" -still supports the old -.B \- -separator, but it warns about this obsolete use. -.br Index: gnu/usr.bin/rcs/rlog/rlog.c =================================================================== --- gnu/usr.bin/rcs/rlog/rlog.c (revision 255904) +++ gnu/usr.bin/rcs/rlog/rlog.c (working copy) @@ -1,1290 +0,0 @@ -/* Print log messages and other information about RCS files. */ - -/* Copyright 1982, 1988, 1989 Walter Tichy - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert - Distributed under license by the Free Software Foundation, Inc. - -This file is part of RCS. - -RCS is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -RCS is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RCS; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Report problems and direct all questions to: - - rcs-bugs@cs.purdue.edu - -*/ - -/* - * Revision 5.18 1995/06/16 06:19:24 eggert - * Update FSF address. - * - * Revision 5.17 1995/06/01 16:23:43 eggert - * (struct rcslockers): Renamed from `struct lockers'. - * (getnumericrev): Return error indication instead of ignoring errors. - * (main): Check it. Don't use dateform. - * (recentdate, extdate): cmpnum -> cmpdate - * - * Revision 5.16 1994/04/13 16:30:34 eggert - * Fix bug; `rlog -lxxx' inverted the sense of -l. - * - * Revision 5.15 1994/03/17 14:05:48 eggert - * -d' RCS_lint - * - * Revision 5.10 1992/01/06 02:42:34 eggert - * Update usage string. - * while (E) ; -> while (E) continue; - * - * Revision 5.9 1991/09/17 19:07:40 eggert - * Getscript() didn't uncache partial lines. - * - * Revision 5.8 1991/08/19 03:13:55 eggert - * Revision separator is `:', not `-'. - * Check for missing and duplicate logs. Tune. - * Permit log messages that do not end in newline (including empty logs). - * - * Revision 5.7 1991/04/21 11:58:31 eggert - * Add -x, RCSINIT, MS-DOS support. - * - * Revision 5.6 1991/02/26 17:07:17 eggert - * Survive RCS files with missing logs. - * strsave -> str_save (DG/UX name clash) - * - * Revision 5.5 1990/11/01 05:03:55 eggert - * Permit arbitrary data in logs and comment leaders. - * - * Revision 5.4 1990/10/04 06:30:22 eggert - * Accumulate exit status across files. - * - * Revision 5.3 1990/09/11 02:41:16 eggert - * Plug memory leak. - * - * Revision 5.2 1990/09/04 08:02:33 eggert - * Count RCS lines better. - * - * Revision 5.0 1990/08/22 08:13:48 eggert - * Remove compile-time limits; use malloc instead. Add setuid support. - * Switch to GMT. - * Report dates in long form, to warn about dates past 1999/12/31. - * Change "added/del" message to make room for the longer dates. - * Don't generate trailing white space. Add -V. Ansify and Posixate. - * - * Revision 4.7 89/05/01 15:13:48 narten - * changed copyright header to reflect current distribution rules - * - * Revision 4.6 88/08/09 19:13:28 eggert - * Check for memory exhaustion; don't access freed storage. - * Shrink stdio code size; remove lint. - * - * Revision 4.5 87/12/18 11:46:38 narten - * more lint cleanups (Guy Harris) - * - * Revision 4.4 87/10/18 10:41:12 narten - * Updating version numbers - * Changes relative to 1.1 actually relative to 4.2 - * - * Revision 1.3 87/09/24 14:01:10 narten - * Sources now pass through lint (if you ignore printf/sprintf/fprintf - * warnings) - * - * Revision 1.2 87/03/27 14:22:45 jenkins - * Port to suns - * - * Revision 4.2 83/12/05 09:18:09 wft - * changed rewriteflag to external. - * - * Revision 4.1 83/05/11 16:16:55 wft - * Added -b, updated getnumericrev() accordingly. - * Replaced getpwuid() with getcaller(). - * - * Revision 3.7 83/05/11 14:24:13 wft - * Added options -L and -R; - * Fixed selection bug with -l on multiple files. - * Fixed error on dates of the form -d'>date' (rewrote getdatepair()). - * - * Revision 3.6 82/12/24 15:57:53 wft - * shortened output format. - * - * Revision 3.5 82/12/08 21:45:26 wft - * removed call to checkaccesslist(); used DATEFORM to format all dates; - * removed unused variables. - * - * Revision 3.4 82/12/04 13:26:25 wft - * Replaced getdelta() with gettree(); removed updating of field lockedby. - * - * Revision 3.3 82/12/03 14:08:20 wft - * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE. - * Fixed printing of nil, removed printing of Suffix, - * added shortcut if no revisions are printed, disambiguated struct members. - * - * Revision 3.2 82/10/18 21:09:06 wft - * call to curdir replaced with getfullRCSname(), - * fixed call to getlogin(), cosmetic changes on output, - * changed conflicting long identifiers. - * - * Revision 3.1 82/10/13 16:07:56 wft - * fixed type of variables receiving from getc() (char -> int). - */ - - - -#include "rcsbase.h" - -struct rcslockers { /* lockers in locker option; stored */ - char const * login; /* lockerlist */ - struct rcslockers * lockerlink; - } ; - -struct stateattri { /* states in state option; stored in */ - char const * status; /* statelist */ - struct stateattri * nextstate; - } ; - -struct authors { /* login names in author option; */ - char const * login; /* stored in authorlist */ - struct authors * nextauthor; - } ; - -struct Revpairs{ /* revision or branch range in -r */ - int numfld; /* option; stored in revlist */ - char const * strtrev; - char const * endrev; - struct Revpairs * rnext; - } ; - -struct Datepairs{ /* date range in -d option; stored in */ - struct Datepairs *dnext; - char strtdate[datesize]; /* duelst and datelist */ - char enddate[datesize]; - char ne_date; /* datelist only; distinguishes < from <= */ - }; - -static char extractdelta P((struct hshentry const*)); -static int checkrevpair P((char const*,char const*)); -static int extdate P((struct hshentry*)); -static int getnumericrev P((void)); -static struct hshentry const *readdeltalog P((void)); -static void cleanup P((void)); -static void exttree P((struct hshentry*)); -static void getauthor P((char*)); -static void getdatepair P((char*)); -static void getlocker P((char*)); -static void getrevpairs P((char*)); -static void getscript P((struct hshentry*)); -static void getstate P((char*)); -static void putabranch P((struct hshentry const*)); -static void putadelta P((struct hshentry const*,struct hshentry const*,int)); -static void putforest P((struct branchhead const*)); -static void putree P((struct hshentry const*)); -static void putrunk P((void)); -static void recentdate P((struct hshentry const*,struct Datepairs*)); -static void trunclocks P((void)); - -static char const *insDelFormat; -static int branchflag; /*set on -b */ -static int exitstatus; -static int lockflag; -static struct Datepairs *datelist, *duelst; -static struct Revpairs *revlist, *Revlst; -static struct authors *authorlist; -static struct rcslockers *lockerlist; -static struct stateattri *statelist; - - -mainProg(rlogId, "rlog", "$FreeBSD$") -{ - static char const cmdusage[] = - "\nrlog usage: rlog -{bhLNRt} -v[string] -ddates -l[lockers] -r[revs] -sstates -Vn -w[logins] -xsuff -zzone file ..."; - - register FILE *out; - char *a, **newargv; - struct Datepairs *currdate; - char const *accessListString, *accessFormat; - char const *headFormat, *symbolFormat; - struct access const *curaccess; - struct assoc const *curassoc; - struct hshentry const *delta; - struct rcslock const *currlock; - int descflag, selectflag; - int onlylockflag; /* print only files with locks */ - int onlyRCSflag; /* print only RCS pathname */ - int pre5; - int shownames; - int revno; - int versionlist; - char *vstring; - - descflag = selectflag = shownames = true; - versionlist = onlylockflag = onlyRCSflag = false; - vstring=0; - out = stdout; - suffixes = X_DEFAULT; - - argc = getRCSINIT(argc, argv, &newargv); - argv = newargv; - while (a = *++argv, 0<--argc && *a++=='-') { - switch (*a++) { - - case 'L': - onlylockflag = true; - break; - - case 'N': - shownames = false; - break; - - case 'R': - onlyRCSflag =true; - break; - - case 'l': - lockflag = true; - getlocker(a); - break; - - case 'b': - branchflag = true; - break; - - case 'r': - getrevpairs(a); - break; - - case 'd': - getdatepair(a); - break; - - case 's': - getstate(a); - break; - - case 'w': - getauthor(a); - break; - - case 'h': - descflag = false; - break; - - case 't': - selectflag = false; - break; - - case 'q': - /* This has no effect; it's here for consistency. */ - quietflag = true; - break; - - case 'x': - suffixes = a; - break; - - case 'z': - zone_set(a); - break; - - case 'T': - /* Ignore -T, so that RCSINIT can contain -T. */ - if (*a) - goto unknown; - break; - - case 'V': - setRCSversion(*argv); - break; - - case 'v': - versionlist = true; - vstring = a; - break; - - default: - unknown: - error("unknown option: %s%s", *argv, cmdusage); - - }; - } /* end of option processing */ - - if (! (descflag|selectflag)) { - warn("-t overrides -h."); - descflag = true; - } - - pre5 = RCSversion < VERSION(5); - if (pre5) { - accessListString = "\naccess list: "; - accessFormat = " %s"; - headFormat = "RCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: "; - insDelFormat = " lines added/del: %ld/%ld"; - symbolFormat = " %s: %s;"; - } else { - accessListString = "\naccess list:"; - accessFormat = "\n\t%s"; - headFormat = "RCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s"; - insDelFormat = " lines: +%ld -%ld"; - symbolFormat = "\n\t%s: %s"; - } - - /* Now handle all pathnames. */ - if (nerror) - cleanup(); - else if (argc < 1) - faterror("no input file%s", cmdusage); - else - for (; 0 < argc; cleanup(), ++argv, --argc) { - ffree(); - - if (pairnames(argc, argv, rcsreadopen, true, false) <= 0) - continue; - - /* - * RCSname contains the name of the RCS file, - * and finptr the file descriptor; - * workname contains the name of the working file. - */ - - /* Keep only those locks given by -l. */ - if (lockflag) - trunclocks(); - - /* do nothing if -L is given and there are no locks*/ - if (onlylockflag && !Locks) - continue; - - if ( versionlist ) { - gettree(); - aprintf(out, "%s%s %s\n", vstring, workname, tiprev()); - continue; - } - - if ( onlyRCSflag ) { - aprintf(out, "%s\n", RCSname); - continue; - } - - gettree(); - - if (!getnumericrev()) - continue; - - /* - * Output the first character with putc, not printf. - * Otherwise, an SVR4 stdio bug buffers output inefficiently. - */ - aputc_('\n', out) - - /* print RCS pathname, working pathname and optional - administrative information */ - /* could use getfullRCSname() here, but that is very slow */ - aprintf(out, headFormat, RCSname, workname, - Head ? " " : "", Head ? Head->num : "", - Dbranch ? " " : "", Dbranch ? Dbranch : "", - StrictLocks ? " strict" : "" - ); - currlock = Locks; - while( currlock ) { - aprintf(out, symbolFormat, currlock->login, - currlock->delta->num); - currlock = currlock->nextlock; - } - if (StrictLocks && pre5) - aputs(" ; strict" + (Locks?3:0), out); - - aputs(accessListString, out); /* print access list */ - curaccess = AccessList; - while(curaccess) { - aprintf(out, accessFormat, curaccess->login); - curaccess = curaccess->nextaccess; - } - - if (shownames) { - aputs("\nsymbolic names:", out); /* print symbolic names */ - for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc) - aprintf(out, symbolFormat, curassoc->symbol, curassoc->num); - } - if (pre5) { - aputs("\ncomment leader: \"", out); - awrite(Comment.string, Comment.size, out); - afputc('\"', out); - } - if (!pre5 || Expand != KEYVAL_EXPAND) - aprintf(out, "\nkeyword substitution: %s", - expand_names[Expand] - ); - - aprintf(out, "\ntotal revisions: %d", TotalDeltas); - - revno = 0; - - if (Head && selectflag & descflag) { - - exttree(Head); - - /* get most recently date of the dates pointed by duelst */ - currdate = duelst; - while( currdate) { - VOID strcpy(currdate->strtdate, "0.0.0.0.0.0"); - recentdate(Head, currdate); - currdate = currdate->dnext; - } - - revno = extdate(Head); - - aprintf(out, ";\tselected revisions: %d", revno); - } - - afputc('\n',out); - if (descflag) { - aputs("description:\n", out); - getdesc(true); - } - if (revno) { - while (! (delta = readdeltalog())->selector || --revno) - continue; - if (delta->next && countnumflds(delta->num)==2) - /* Read through delta->next to get its insertlns. */ - while (readdeltalog() != delta->next) - continue; - putrunk(); - putree(Head); - } - aputs("----------------------------\n", out); - aputs("=============================================================================\n",out); - } - Ofclose(out); - exitmain(exitstatus); -} - - static void -cleanup() -{ - if (nerror) exitstatus = EXIT_FAILURE; - Izclose(&finptr); -} - -#if RCS_lint -# define exiterr rlogExit -#endif - void -exiterr() -{ - _exit(EXIT_FAILURE); -} - - - - static void -putrunk() -/* function: print revisions chosen, which are in trunk */ - -{ - register struct hshentry const *ptr; - - for (ptr = Head; ptr; ptr = ptr->next) - putadelta(ptr, ptr->next, true); -} - - - - static void -putree(root) - struct hshentry const *root; -/* function: print delta tree (not including trunk) in reverse - order on each branch */ - -{ - if (!root) return; - - putree(root->next); - - putforest(root->branches); -} - - - - - static void -putforest(branchroot) - struct branchhead const *branchroot; -/* function: print branches that has the same direct ancestor */ -{ - if (!branchroot) return; - - putforest(branchroot->nextbranch); - - putabranch(branchroot->hsh); - putree(branchroot->hsh); -} - - - - - static void -putabranch(root) - struct hshentry const *root; -/* function : print one branch */ - -{ - if (!root) return; - - putabranch(root->next); - - putadelta(root, root, false); -} - - - - - - static void -putadelta(node,editscript,trunk) - register struct hshentry const *node, *editscript; - int trunk; -/* function: Print delta node if node->selector is set. */ -/* editscript indicates where the editscript is stored */ -/* trunk indicated whether this node is in trunk */ -{ - static char emptych[] = EMPTYLOG; - - register FILE *out; - char const *s; - size_t n; - struct branchhead const *newbranch; - struct buf branchnum; - char datebuf[datesize + zonelenmax]; - int pre5 = RCSversion < VERSION(5); - - if (!node->selector) - return; - - out = stdout; - aprintf(out, - "----------------------------\nrevision %s%s", - node->num, pre5 ? " " : "" - ); - if ( node->lockedby ) - aprintf(out, pre5+"\tlocked by: %s;", node->lockedby); - - aprintf(out, "\ndate: %s; author: %s; state: %s;", - date2str(node->date, datebuf), - node->author, node->state - ); - - if ( editscript ) - if(trunk) - aprintf(out, insDelFormat, - editscript->deletelns, editscript->insertlns); - else - aprintf(out, insDelFormat, - editscript->insertlns, editscript->deletelns); - - newbranch = node->branches; - if ( newbranch ) { - bufautobegin(&branchnum); - aputs("\nbranches:", out); - while( newbranch ) { - getbranchno(newbranch->hsh->num, &branchnum); - aprintf(out, " %s;", branchnum.string); - newbranch = newbranch->nextbranch; - } - bufautoend(&branchnum); - } - - afputc('\n', out); - s = node->log.string; - if (!(n = node->log.size)) { - s = emptych; - n = sizeof(emptych)-1; - } - awrite(s, n, out); - if (s[n-1] != '\n') - afputc('\n', out); -} - - - static struct hshentry const * -readdeltalog() -/* Function : get the log message and skip the text of a deltatext node. - * Return the delta found. - * Assumes the current lexeme is not yet in nexttok; does not - * advance nexttok. - */ -{ - register struct hshentry * Delta; - struct buf logbuf; - struct cbuf cb; - - if (eoflex()) - fatserror("missing delta log"); - nextlex(); - if (!(Delta = getnum())) - fatserror("delta number corrupted"); - getkeystring(Klog); - if (Delta->log.string) - fatserror("duplicate delta log"); - bufautobegin(&logbuf); - cb = savestring(&logbuf); - Delta->log = bufremember(&logbuf, cb.size); - - ignorephrases(Ktext); - getkeystring(Ktext); - Delta->insertlns = Delta->deletelns = 0; - if ( Delta != Head) - getscript(Delta); - else - readstring(); - return Delta; -} - - - static void -getscript(Delta) -struct hshentry * Delta; -/* function: read edit script of Delta and count how many lines added */ -/* and deleted in the script */ - -{ - int ed; /* editor command */ - declarecache; - register RILE *fin; - register int c; - register long i; - struct diffcmd dc; - - fin = finptr; - setupcache(fin); - initdiffcmd(&dc); - while (0 <= (ed = getdiffcmd(fin,true,(FILE *)0,&dc))) - if (!ed) - Delta->deletelns += dc.nlines; - else { - /* skip scripted lines */ - i = dc.nlines; - Delta->insertlns += i; - cache(fin); - do { - for (;;) { - cacheget_(c) - switch (c) { - default: - continue; - case SDELIM: - cacheget_(c) - if (c == SDELIM) - continue; - if (--i) - unexpected_EOF(); - nextc = c; - uncache(fin); - return; - case '\n': - break; - } - break; - } - ++rcsline; - } while (--i); - uncache(fin); - } -} - - - - - - - - static void -exttree(root) -struct hshentry *root; -/* function: select revisions , starting with root */ - -{ - struct branchhead const *newbranch; - - if (!root) return; - - root->selector = extractdelta(root); - root->log.string = 0; - exttree(root->next); - - newbranch = root->branches; - while( newbranch ) { - exttree(newbranch->hsh); - newbranch = newbranch->nextbranch; - } -} - - - - - static void -getlocker(argv) -char * argv; -/* function : get the login names of lockers from command line */ -/* and store in lockerlist. */ - -{ - register char c; - struct rcslockers *newlocker; - argv--; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - if ( c == '\0') { - lockerlist = 0; - return; - } - - while( c != '\0' ) { - newlocker = talloc(struct rcslockers); - newlocker->lockerlink = lockerlist; - newlocker->login = argv; - lockerlist = newlocker; - while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';') - continue; - *argv = '\0'; - if ( c == '\0' ) return; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - } -} - - - - static void -getauthor(argv) -char *argv; -/* function: get the author's name from command line */ -/* and store in authorlist */ - -{ - register c; - struct authors * newauthor; - - argv--; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - if ( c == '\0' ) { - authorlist = talloc(struct authors); - authorlist->login = getusername(false); - authorlist->nextauthor = 0; - return; - } - - while( c != '\0' ) { - newauthor = talloc(struct authors); - newauthor->nextauthor = authorlist; - newauthor->login = argv; - authorlist = newauthor; - while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';') - continue; - * argv = '\0'; - if ( c == '\0') return; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - } -} - - - - - static void -getstate(argv) -char * argv; -/* function : get the states of revisions from command line */ -/* and store in statelist */ - -{ - register char c; - struct stateattri *newstate; - - argv--; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - if ( c == '\0'){ - error("missing state attributes after -s options"); - return; - } - - while( c != '\0' ) { - newstate = talloc(struct stateattri); - newstate->nextstate = statelist; - newstate->status = argv; - statelist = newstate; - while ((c = *++argv) && c!=',' && c!=' ' && c!='\t' && c!='\n' && c!=';') - continue; - *argv = '\0'; - if ( c == '\0' ) return; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - } -} - - - - static void -trunclocks() -/* Function: Truncate the list of locks to those that are held by the */ -/* id's on lockerlist. Do not truncate if lockerlist empty. */ - -{ - struct rcslockers const *plocker; - struct rcslock *p, **pp; - - if (!lockerlist) return; - - /* shorten Locks to those contained in lockerlist */ - for (pp = &Locks; (p = *pp); ) - for (plocker = lockerlist; ; ) - if (strcmp(plocker->login, p->login) == 0) { - pp = &p->nextlock; - break; - } else if (!(plocker = plocker->lockerlink)) { - *pp = p->nextlock; - break; - } -} - - - - static void -recentdate(root, pd) - struct hshentry const *root; - struct Datepairs *pd; -/* function: Finds the delta that is closest to the cutoff date given by */ -/* pd among the revisions selected by exttree. */ -/* Successively narrows down the interval given by pd, */ -/* and sets the strtdate of pd to the date of the selected delta */ -{ - struct branchhead const *newbranch; - - if (!root) return; - if (root->selector) { - if ( cmpdate(root->date, pd->strtdate) >= 0 && - cmpdate(root->date, pd->enddate) <= 0) - VOID strcpy(pd->strtdate, root->date); - } - - recentdate(root->next, pd); - newbranch = root->branches; - while( newbranch) { - recentdate(newbranch->hsh, pd); - newbranch = newbranch->nextbranch; - } -} - - - - - - - static int -extdate(root) -struct hshentry * root; -/* function: select revisions which are in the date range specified */ -/* in duelst and datelist, start at root */ -/* Yield number of revisions selected, including those already selected. */ -{ - struct branchhead const *newbranch; - struct Datepairs const *pdate; - int revno, ne; - - if (!root) - return 0; - - if ( datelist || duelst) { - pdate = datelist; - while( pdate ) { - ne = pdate->ne_date; - if ( - (!pdate->strtdate[0] - || ne <= cmpdate(root->date, pdate->strtdate)) - && - (!pdate->enddate[0] - || ne <= cmpdate(pdate->enddate, root->date)) - ) - break; - pdate = pdate->dnext; - } - if (!pdate) { - pdate = duelst; - for (;;) { - if (!pdate) { - root->selector = false; - break; - } - if (cmpdate(root->date, pdate->strtdate) == 0) - break; - pdate = pdate->dnext; - } - } - } - revno = root->selector + extdate(root->next); - - newbranch = root->branches; - while( newbranch ) { - revno += extdate(newbranch->hsh); - newbranch = newbranch->nextbranch; - } - return revno; -} - - - - static char -extractdelta(pdelta) - struct hshentry const *pdelta; -/* function: compare information of pdelta to the authorlist, lockerlist,*/ -/* statelist, revlist and yield true if pdelta is selected. */ - -{ - struct rcslock const *plock; - struct stateattri const *pstate; - struct authors const *pauthor; - struct Revpairs const *prevision; - int length; - - if ((pauthor = authorlist)) /* only certain authors wanted */ - while (strcmp(pauthor->login, pdelta->author) != 0) - if (!(pauthor = pauthor->nextauthor)) - return false; - if ((pstate = statelist)) /* only certain states wanted */ - while (strcmp(pstate->status, pdelta->state) != 0) - if (!(pstate = pstate->nextstate)) - return false; - if (lockflag) /* only locked revisions wanted */ - for (plock = Locks; ; plock = plock->nextlock) - if (!plock) - return false; - else if (plock->delta == pdelta) - break; - if ((prevision = Revlst)) /* only certain revs or branches wanted */ - for (;;) { - length = prevision->numfld; - if ( - countnumflds(pdelta->num) == length+(length&1) && - 0 <= compartial(pdelta->num, prevision->strtrev, length) && - 0 <= compartial(prevision->endrev, pdelta->num, length) - ) - break; - if (!(prevision = prevision->rnext)) - return false; - } - return true; -} - - - - static void -getdatepair(argv) - char * argv; -/* function: get time range from command line and store in datelist if */ -/* a time range specified or in duelst if a time spot specified */ - -{ - register char c; - struct Datepairs * nextdate; - char const * rawdate; - int switchflag; - - argv--; - while ((c = *++argv)==',' || c==' ' || c=='\t' || c=='\n' || c==';') - continue; - if ( c == '\0' ) { - error("missing date/time after -d"); - return; - } - - while( c != '\0' ) { - switchflag = false; - nextdate = talloc(struct Datepairs); - if ( c == '<' ) { /* case: -d ne_date = c!='=')) - c = *++argv; - (nextdate->strtdate)[0] = '\0'; - } else if (c == '>') { /* case: -d'>date' */ - c = *++argv; - if (!(nextdate->ne_date = c!='=')) - c = *++argv; - (nextdate->enddate)[0] = '\0'; - switchflag = true; - } else { - rawdate = argv; - while( c != '<' && c != '>' && c != ';' && c != '\0') - c = *++argv; - *argv = '\0'; - if ( c == '>' ) switchflag=true; - str2date(rawdate, - switchflag ? nextdate->enddate : nextdate->strtdate); - if ( c == ';' || c == '\0') { /* case: -d date */ - VOID strcpy(nextdate->enddate,nextdate->strtdate); - nextdate->dnext = duelst; - duelst = nextdate; - goto end; - } else { - /* case: -d date< or -d date>; see switchflag */ - int eq = argv[1]=='='; - nextdate->ne_date = !eq; - argv += eq; - while ((c = *++argv) == ' ' || c=='\t' || c=='\n') - continue; - if ( c == ';' || c == '\0') { - /* second date missing */ - if (switchflag) - *nextdate->strtdate= '\0'; - else - *nextdate->enddate= '\0'; - nextdate->dnext = datelist; - datelist = nextdate; - goto end; - } - } - } - rawdate = argv; - while( c != '>' && c != '<' && c != ';' && c != '\0') - c = *++argv; - *argv = '\0'; - str2date(rawdate, - switchflag ? nextdate->strtdate : nextdate->enddate); - nextdate->dnext = datelist; - datelist = nextdate; - end: - if (RCSversion < VERSION(5)) - nextdate->ne_date = 0; - if ( c == '\0') return; - while ((c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n') - continue; - } -} - - - - static int -getnumericrev() -/* function: get the numeric name of revisions which stored in revlist */ -/* and then stored the numeric names in Revlst */ -/* if branchflag, also add default branch */ - -{ - struct Revpairs * ptr, *pt; - int n; - struct buf s, e; - char const *lrev; - struct buf const *rstart, *rend; - - Revlst = 0; - ptr = revlist; - bufautobegin(&s); - bufautobegin(&e); - while( ptr ) { - n = 0; - rstart = &s; - rend = &e; - - switch (ptr->numfld) { - - case 1: /* -rREV */ - if (!expandsym(ptr->strtrev, &s)) - goto freebufs; - rend = &s; - n = countnumflds(s.string); - if (!n && (lrev = tiprev())) { - bufscpy(&s, lrev); - n = countnumflds(lrev); - } - break; - - case 2: /* -rREV: */ - if (!expandsym(ptr->strtrev, &s)) - goto freebufs; - bufscpy(&e, s.string); - n = countnumflds(s.string); - (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0; - break; - - case 3: /* -r:REV */ - if (!expandsym(ptr->endrev, &e)) - goto freebufs; - if ((n = countnumflds(e.string)) < 2) - bufscpy(&s, ".0"); - else { - bufscpy(&s, e.string); - VOID strcpy(strrchr(s.string,'.'), ".0"); - } - break; - - default: /* -rREV1:REV2 */ - if (!( - expandsym(ptr->strtrev, &s) - && expandsym(ptr->endrev, &e) - && checkrevpair(s.string, e.string) - )) - goto freebufs; - n = countnumflds(s.string); - /* Swap if out of order. */ - if (compartial(s.string,e.string,n) > 0) { - rstart = &e; - rend = &s; - } - break; - } - - if (n) { - pt = ftalloc(struct Revpairs); - pt->numfld = n; - pt->strtrev = fstr_save(rstart->string); - pt->endrev = fstr_save(rend->string); - pt->rnext = Revlst; - Revlst = pt; - } - ptr = ptr->rnext; - } - /* Now take care of branchflag */ - if (branchflag && (Dbranch||Head)) { - pt = ftalloc(struct Revpairs); - pt->strtrev = pt->endrev = - Dbranch ? Dbranch : fstr_save(partialno(&s,Head->num,1)); - pt->rnext=Revlst; Revlst=pt; - pt->numfld = countnumflds(pt->strtrev); - } - - freebufs: - bufautoend(&s); - bufautoend(&e); - return !ptr; -} - - - - static int -checkrevpair(num1,num2) - char const *num1, *num2; -/* function: check whether num1, num2 are legal pair,i.e. - only the last field are different and have same number of - fields( if length <= 2, may be different if first field) */ - -{ - int length = countnumflds(num1); - - if ( - countnumflds(num2) != length - || (2 < length && compartial(num1, num2, length-1) != 0) - ) { - rcserror("invalid branch or revision pair %s : %s", num1, num2); - return false; - } - - return true; -} - - - - static void -getrevpairs(argv) -register char * argv; -/* function: get revision or branch range from command line, and */ -/* store in revlist */ - -{ - register char c; - struct Revpairs * nextrevpair; - int separator; - - c = *argv; - - /* Support old ambiguous '-' syntax; this will go away. */ - if (strchr(argv,':')) - separator = ':'; - else { - if (strchr(argv,'-') && VERSION(5) <= RCSversion) - warn("`-' is obsolete in `-r%s'; use `:' instead", argv); - separator = '-'; - } - - for (;;) { - while (c==' ' || c=='\t' || c=='\n') - c = *++argv; - nextrevpair = talloc(struct Revpairs); - nextrevpair->rnext = revlist; - revlist = nextrevpair; - nextrevpair->numfld = 1; - nextrevpair->strtrev = argv; - for (;; c = *++argv) { - switch (c) { - default: - continue; - case '\0': case ' ': case '\t': case '\n': - case ',': case ';': - break; - case ':': case '-': - if (c == separator) - break; - continue; - } - break; - } - *argv = '\0'; - while (c==' ' || c=='\t' || c=='\n') - c = *++argv; - if (c == separator) { - while ((c = *++argv) == ' ' || c == '\t' || c =='\n') - continue; - nextrevpair->endrev = argv; - for (;; c = *++argv) { - switch (c) { - default: - continue; - case '\0': case ' ': case '\t': case '\n': - case ',': case ';': - break; - case ':': case '-': - if (c == separator) - break; - continue; - } - break; - } - *argv = '\0'; - while (c==' ' || c=='\t' || c =='\n') - c = *++argv; - nextrevpair->numfld = - !nextrevpair->endrev[0] ? 2 /* -rREV: */ : - !nextrevpair->strtrev[0] ? 3 /* -r:REV */ : - 4 /* -rREV1:REV2 */; - } - if (!c) - break; - else if (c==',' || c==';') - c = *++argv; - else - error("missing `,' near `%c%s'", c, argv+1); - } -} Index: tools/build/mk/OptionalObsoleteFiles.inc =================================================================== --- tools/build/mk/OptionalObsoleteFiles.inc (revision 255904) +++ tools/build/mk/OptionalObsoleteFiles.inc (working copy) @@ -4088,31 +4088,6 @@ OLD_FILES+=usr/share/man/man8/rshd.8.gz OLD_FILES+=usr/share/man/man8/rwhod.8.gz .endif -.if ${MK_RCS} == no -OLD_FILES+=usr/bin/ci -OLD_FILES+=usr/bin/co -OLD_FILES+=usr/bin/ident -OLD_FILES+=usr/bin/merge -OLD_FILES+=usr/bin/rcs -OLD_FILES+=usr/bin/rcsclean -OLD_FILES+=usr/bin/rcsdiff -OLD_FILES+=usr/bin/rcsfreeze -OLD_FILES+=usr/bin/rcsmerge -OLD_FILES+=usr/bin/rlog -OLD_FILES+=usr/share/man/man1/ci.1.gz -OLD_FILES+=usr/share/man/man1/co.1.gz -OLD_FILES+=usr/share/man/man1/ident.1.gz -OLD_FILES+=usr/share/man/man1/merge.1.gz -OLD_FILES+=usr/share/man/man1/rcs.1.gz -OLD_FILES+=usr/share/man/man1/rcsclean.1.gz -OLD_FILES+=usr/share/man/man1/rcsdiff.1.gz -OLD_FILES+=usr/share/man/man1/rcsfreeze.1.gz -OLD_FILES+=usr/share/man/man1/rcsintro.1.gz -OLD_FILES+=usr/share/man/man1/rcsmerge.1.gz -OLD_FILES+=usr/share/man/man1/rlog.1.gz -OLD_FILES+=usr/share/man/man5/rcsfile.5.gz -.endif - #.if ${MK_RESCUE} == no # to be filled in or replaced with a special target #.endif Index: tools/build/options/WITHOUT_RCS =================================================================== --- tools/build/options/WITHOUT_RCS (revision 255904) +++ tools/build/options/WITHOUT_RCS (working copy) @@ -1,4 +0,0 @@ -.\" $FreeBSD$ -Set to not build -.Xr rcs 1 -and related utilities.