Revert r256095, r256120 (partial), r256121:
r256095: - Add gnu/usr.bin/rcs back to the base system. r256120: - Add WITHOUT_RCS back to src.conf.5. r256121: - Remove UPDATING entry regarding gnu/usr.bin/rcs removal. Requested by: many Approved by: re (marius) Discussed with: core
This commit is contained in:
parent
02147e9cd0
commit
c9fc60beee
@ -38,29 +38,6 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20131015: removal of RCS from base
|
||||
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
|
||||
# 20131001: ar and ranlib from binutils not used
|
||||
OLD_FILES+=usr/bin/gnu-ar
|
||||
OLD_FILES+=usr/bin/gnu-ranlib
|
||||
|
4
UPDATING
4
UPDATING
@ -31,10 +31,6 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
|
||||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20131006:
|
||||
RCS has been removed from the base system. If you need RCS
|
||||
install either devel/rcs or devel/rcs57.
|
||||
|
||||
20130930:
|
||||
BIND has been removed from the base system. If all you need
|
||||
is a local resolver, simply enable and start the local_unbound
|
||||
|
@ -12,6 +12,7 @@ SUBDIR= ${_binutils} \
|
||||
${_gperf} \
|
||||
grep \
|
||||
${_groff} \
|
||||
${_rcs} \
|
||||
sdiff \
|
||||
send-pr \
|
||||
${_texinfo}
|
||||
@ -31,6 +32,10 @@ _dtc= dtc
|
||||
_texinfo= texinfo
|
||||
.endif
|
||||
|
||||
.if ${MK_RCS} != "no"
|
||||
_rcs= rcs
|
||||
.endif
|
||||
|
||||
.if ${MK_BINUTILS} != "no"
|
||||
_binutils= binutils
|
||||
.endif
|
||||
|
24
gnu/usr.bin/rcs/CREDITS
Normal file
24
gnu/usr.bin/rcs/CREDITS
Normal file
@ -0,0 +1,24 @@
|
||||
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$
|
3
gnu/usr.bin/rcs/Makefile
Normal file
3
gnu/usr.bin/rcs/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
SUBDIR= lib ci co ident merge rcs rcsclean rcsdiff rcsmerge rlog rcsfreeze
|
||||
|
||||
.include <bsd.subdir.mk>
|
3
gnu/usr.bin/rcs/Makefile.inc
Normal file
3
gnu/usr.bin/rcs/Makefile.inc
Normal file
@ -0,0 +1,3 @@
|
||||
# $FreeBSD$
|
||||
|
||||
LIBRCS= ${.OBJDIR}/../lib/librcs.a
|
548
gnu/usr.bin/rcs/NEWS
Normal file
548
gnu/usr.bin/rcs/NEWS
Normal file
@ -0,0 +1,548 @@
|
||||
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"<T"' now excludes revisions whose times equal T exactly.
|
||||
Use `rlog -d"<=T"' to get the old behavior.
|
||||
|
||||
merge now takes up to three -L options, one for each input file.
|
||||
Formerly, it took at most two -L options, for the 1st and 3rd input files.
|
||||
|
||||
`rcs' now requires at least one option; this is for future expansion.
|
||||
|
||||
Other features new to RCS version 5.7 include:
|
||||
|
||||
merge and rcsmerge now pass -A, -E, and -e options to the subsidiary diff3.
|
||||
|
||||
rcs -kb acts like rcs -ko, except it uses binary I/O on working files.
|
||||
This makes no difference under Posix or Unix, but it does matter elsewhere.
|
||||
With -kb in effect, rcsmerge refuses to merge;
|
||||
this avoids common problems with CVS merging.
|
||||
|
||||
The following is for future use by GNU Emacs 19's version control package:
|
||||
|
||||
rcs's new -M option causes it to not send mail when you break somebody
|
||||
else's lock. This is not meant for casual use; see rcs(1).
|
||||
|
||||
ci's new -i option causes an error if the RCS file already exists.
|
||||
Similarly, -j causes an error if the RCS file does not already exist.
|
||||
|
||||
The new keyword `Name' is supported; its value is the name, if any,
|
||||
used to check out the revision. E.g. `co -rN foo' causes foo's
|
||||
$Name...$ keyword strings to end in `: N $'.
|
||||
|
||||
The new -zZONE option causes RCS to output dates and times using ISO 8601
|
||||
format with ZONE as the time zone, and to use ZONE as the default time
|
||||
zone for input. Its most common use is the -zLT option, which causes RCS
|
||||
to use local time externally. You can also specify foreign time zones;
|
||||
e.g. -z+05:30 causes RCS to use India time (5 hours 30 minutes east of UTC).
|
||||
This option does not affect RCS files themselves, which always use UTC;
|
||||
it affects only output (e.g. rlog output, keyword expansion, diff -c times)
|
||||
and interpretation of options (e.g. the -d option of ci, co, and rlog).
|
||||
Bare -z restores the default behavior of UTC with no time zone indication,
|
||||
and the traditional RCS date separator `/' instead of the ISO 8601 `-'.
|
||||
RCSINIT may contain a -z option. ci -k parses UTC offsets.
|
||||
|
||||
The new -T option of ci, co, rcs, and rcsclean preserves the modification
|
||||
time of the RCS file unless a revision is added or removed.
|
||||
ci -T sets the RCS file's modification time to the new revision's time
|
||||
if the former precedes the latter and there is a new revision;
|
||||
otherwise, it preserves the RCS file's modification time.
|
||||
Use this option with care, as it can confuse `make'; see ci(1).
|
||||
|
||||
The new -N option of rlog omits symbolic names from the output.
|
||||
|
||||
A revision number that starts with `.' is considered to be relative to
|
||||
the default branch (normally the trunk). A branch number followed by `.'
|
||||
stands for the last revision on that branch.
|
||||
|
||||
If someone else already holds the lock, rcs -l now asks whether you want
|
||||
to break it, instead of immediately reporting an error.
|
||||
|
||||
ci now always unlocks a revision like 3.5 if you check in a revision
|
||||
like 3.5.2.1 that is the first of a new branch of that revision.
|
||||
Formerly it was inconsistent.
|
||||
|
||||
File names may now contain tab, newline, space, and '$'.
|
||||
They are represented in keyword strings with \t, \n, \040, and \044.
|
||||
\ in a file name is now represented by \\ in a keyword string.
|
||||
|
||||
Identifiers may now start with a digit and (unless they are symbolic names)
|
||||
may contain `.'. This permits author names like `john.doe' and `4tran'.
|
||||
|
||||
A bare -V option now prints the current version number.
|
||||
|
||||
rcsdiff outputs more readable context diff headers if diff -L works.
|
||||
|
||||
rcsdiff -rN -rN now suppresses needless checkout and comparison
|
||||
of identical revisions.
|
||||
|
||||
Error messages now contain the names of files to which they apply.
|
||||
|
||||
Mach style memory mapping is now supported.
|
||||
|
||||
The installation procedure now conforms to the GNU coding standards.
|
||||
|
||||
When properly configured, RCS now strictly conforms to Posix 1003.1b-1993.
|
||||
|
||||
|
||||
Features new to RCS version 5.6 include:
|
||||
|
||||
Security holes have been plugged; setgid use is no longer supported.
|
||||
|
||||
co can retrieve old revisions much more efficiently.
|
||||
To generate the Nth youngest revision on the trunk,
|
||||
the old method used up to N passes through copies of the working file;
|
||||
the new method uses a piece table to generate the working file in one pass.
|
||||
|
||||
When ci finds no changes in the working file,
|
||||
it automatically reverts to the previous revision unless -f is given.
|
||||
|
||||
RCS follows symbolic links to RCS files instead of breaking them,
|
||||
and warns when it breaks hard links to RCS files.
|
||||
|
||||
`$' stands for the revision number taken from working file keyword strings.
|
||||
E.g. if F contains an Id keyword string,
|
||||
`rcsdiff -r$ F' compares F to its checked-in revision, and
|
||||
`rcs -nL:$ F' gives the symbolic name L to F's revision.
|
||||
|
||||
co and ci's new -M option sets the modification time
|
||||
of the working file to be that of the revision.
|
||||
Without -M, ci now tries to avoid changing the working file's
|
||||
modification time if its contents are unchanged.
|
||||
|
||||
rcs's new -m option changes the log message of an old revision.
|
||||
|
||||
RCS is portable to hosts that do not permit `,' in filenames.
|
||||
(`,' is not part of the Posix portable filename character set.)
|
||||
A new -x option specifies extensions other than `,v' for RCS files.
|
||||
The Unix default is `-x,v/', so that the working file `w' corresponds
|
||||
to the first file in the list `RCS/w,v', `w,v', `RCS/w' that works.
|
||||
The non-Unix default is `-x', so that only `RCS/w' is tried.
|
||||
Eventually, the Unix default should change to `-x/,v'
|
||||
to encourage interoperability among all Posix hosts.
|
||||
|
||||
A new RCSINIT environment variable specifies defaults for options like -x.
|
||||
|
||||
The separator for revision ranges has been changed from `-' to `:', because
|
||||
the range `A-B' is ambiguous if `A', `B' and `A-B' are all symbolic names.
|
||||
E.g. the old `rlog -r1.5-1.7' is now `rlog -r1.5:1.7'; ditto for `rcs -o'.
|
||||
For a while RCS will still support (but warn about) the old `-' separator.
|
||||
|
||||
RCS manipulates its lock files using a method that is more reliable under NFS.
|
||||
|
||||
|
||||
Features new to RCS version 5 include:
|
||||
|
||||
RCS can check in arbitrary files, not just text files, if diff -a works.
|
||||
RCS can merge lines containing just a single `.' if diff3 -m works.
|
||||
GNU diff supports the -a and -m options.
|
||||
|
||||
RCS can now be used as a setuid program.
|
||||
See ci(1) for how users can employ setuid copies of ci, co, and rcsclean.
|
||||
Setuid privileges yield extra security if the effective user owns RCS files
|
||||
and directories, and if only the effective user can write RCS directories.
|
||||
RCS uses the real user for all accesses other than writing RCS directories.
|
||||
As described in ci(1), there are three levels of setuid support.
|
||||
|
||||
1. Setuid works fully if the seteuid() system call lets any
|
||||
process switch back and forth between real and effective users,
|
||||
as specified in Posix 1003.1a Draft 5.
|
||||
|
||||
2. On hosts with saved setuids (a Posix 1003.1-1990 option) and without
|
||||
a modern seteuid(), setuid works unless the real or effective user is root.
|
||||
|
||||
3. On hosts that lack both modern seteuid() and saved setuids,
|
||||
setuid does not work, and RCS uses the effective user for all accesses;
|
||||
formerly it was inconsistent.
|
||||
|
||||
New options to co, rcsdiff, and rcsmerge give more flexibility to keyword
|
||||
substitution.
|
||||
|
||||
-kkv substitutes the default `$Keyword: value $' for keyword strings.
|
||||
However, a locker's name is inserted only as a file is being locked,
|
||||
i.e. by `ci -l' and `co -l'. This is normally the default.
|
||||
|
||||
-kkvl acts like -kkv, except that a locker's name is always inserted
|
||||
if the given revision is currently locked. This was the default in
|
||||
version 4. It is now the default only with when using rcsdiff to
|
||||
compare a revision to a working file whose mode is that of a file
|
||||
checked out for changes.
|
||||
|
||||
-kk substitutes just `$Keyword$', which helps to ignore keyword values
|
||||
when comparing revisions.
|
||||
|
||||
-ko retrieves the old revision's keyword string, thus bypassing keyword
|
||||
substitution.
|
||||
|
||||
-kv retrieves just `value'. This can ease the use of keyword values, but
|
||||
it is dangerous because it causes RCS to lose track of where the keywords
|
||||
are, so for safety the owner write permission of the working file is
|
||||
turned off when -kv is used; to edit the file later, check it out again
|
||||
without -kv.
|
||||
|
||||
rcs -ko sets the default keyword substitution to be in the style of co -ko,
|
||||
and similarly for the other -k options. This can be useful with file
|
||||
formats that cannot tolerate changing the lengths of keyword strings.
|
||||
However it also renders a RCS file readable only by RCS version 5 or later.
|
||||
Use rcs -kkv to restore the usual default substitution.
|
||||
|
||||
RCS can now be used by development groups that span time zone boundaries.
|
||||
All times are now displayed in UTC, and UTC is the default time zone.
|
||||
To use local time with co -d, append ` LT' to the time.
|
||||
When interchanging RCS files with sites running older versions of RCS,
|
||||
time stamp discrepancies may prevent checkins; to work around this,
|
||||
use `ci -d' with a time slightly in the future.
|
||||
|
||||
Dates are now displayed using four-digit years, not two-digit years.
|
||||
Years given in -d options must now have four digits.
|
||||
This change is required for RCS to continue to work after 1999/12/31.
|
||||
The form of dates in version 5 RCS files will not change until 2000/01/01,
|
||||
so in the meantime RCS files can still be interchanged with sites
|
||||
running older versions of RCS. To make room for the longer dates,
|
||||
rlog now outputs `lines: +A -D' instead of `lines added/del: A/D'.
|
||||
|
||||
To help prevent diff programs that are broken or have run out of memory
|
||||
from trashing an RCS file, ci now checks diff output more carefully.
|
||||
|
||||
ci -k now handles the Log keyword, so that checking in a file
|
||||
with -k does not normally alter the file's contents.
|
||||
|
||||
RCS no longer outputs white space at the ends of lines
|
||||
unless the original working file had it.
|
||||
For consistency with other keywords,
|
||||
a space, not a tab, is now output after `$Log:'.
|
||||
Rlog now puts lockers and symbolic names on separate lines in the output
|
||||
to avoid generating lines that are too long.
|
||||
A similar fix has been made to lists in the RCS files themselves.
|
||||
|
||||
RCS no longer outputs the string `Locker: ' when expanding Header or Id
|
||||
keywords. This saves space and reverts back to version 3 behavior.
|
||||
|
||||
The default branch is not put into the RCS file unless it is nonempty.
|
||||
Therefore, files generated by RCS version 5 can be read by RCS version 3
|
||||
unless they use the default branch feature introduced in version 4.
|
||||
This fixes a compatibility problem introduced by version 4.
|
||||
|
||||
RCS can now emulate older versions of RCS; see `co -V'.
|
||||
This may be useful to overcome compatibility problems
|
||||
due to the above changes.
|
||||
|
||||
Programs like Emacs can now interact with RCS commands via a pipe:
|
||||
the new -I option causes ci, co, and rcs to run interactively,
|
||||
even if standard input is not a terminal.
|
||||
These commands now accept multiple inputs from stdin separated by `.' lines.
|
||||
|
||||
ci now silently ignores the -t option if the RCS file already exists.
|
||||
This simplifies some shell scripts and improves security in setuid sites.
|
||||
|
||||
Descriptive text may be given directly in an argument of the form -t-string.
|
||||
|
||||
The character set for symbolic names has been upgraded
|
||||
from Ascii to ISO 8859.
|
||||
|
||||
rcsdiff now passes through all options used by GNU diff;
|
||||
this is a longer list than 4.3BSD diff.
|
||||
|
||||
merge's new -L option gives tags for merge's overlap report lines.
|
||||
This ability used to be present in a different, undocumented form;
|
||||
the new form is chosen for compatibility with GNU diff3's -L option.
|
||||
|
||||
rcsmerge and merge now have a -q option, just like their siblings do.
|
||||
|
||||
rcsclean's new -n option outputs what rcsclean would do,
|
||||
without actually doing it.
|
||||
|
||||
RCS now attempts to ignore parts of an RCS file that look like they come
|
||||
from a future version of RCS.
|
||||
|
||||
When properly configured, RCS now strictly conforms with Posix 1003.1-1990.
|
||||
RCS can still be compiled in non-Posix traditional Unix environments,
|
||||
and can use common BSD and USG extensions to Posix.
|
||||
RCS is a conforming Standard C program, and also compiles under traditional C.
|
||||
|
||||
Arbitrary limits on internal table sizes have been removed.
|
||||
The only limit now is the amount of memory available via malloc().
|
||||
|
||||
File temporaries, lock files, signals, and system call return codes
|
||||
are now handled more cleanly, portably, and quickly.
|
||||
Some race conditions have been removed.
|
||||
|
||||
A new compile-time option RCSPREFIX lets administrators avoid absolute path
|
||||
names for subsidiary programs, trading speed for flexibility.
|
||||
|
||||
The configuration procedure is now more automatic.
|
||||
|
||||
Snooping has been removed.
|
||||
|
||||
|
||||
Version 4 was the first version distributed by FSF.
|
||||
Beside bug fixes, features new to RCS version 4 include:
|
||||
|
||||
The notion of default branch has been added; see rcs -b.
|
||||
|
||||
|
||||
Version 3 was included in the 4.3BSD distribution.
|
||||
|
||||
|
||||
Here are some possible future changes for RCS:
|
||||
|
||||
Bring back sccstorcs.
|
||||
|
||||
Add an option to `rcsmerge' so that it can use an arbitrary program
|
||||
to do the 3-way merge, instead of the default `merge'.
|
||||
Likewise for `rcsdiff' and `diff'. It should be possible to pass
|
||||
arbitrary options to these programs, and to the subsidiary `co's.
|
||||
|
||||
Add format options for finer control over the output of ident and rlog.
|
||||
E.g. there should be an easy way for rlog to output lines like
|
||||
`src/main.c 2.4 wft', one for each locked revision.
|
||||
rlog options should have three orthogonal types: selecting files,
|
||||
selecting revisions, and selecting rlog format.
|
||||
|
||||
Add format options for finer control over the output of keyword strings.
|
||||
E.g. there should be some way to prepend @(#), and there should be some
|
||||
way to change $ to some other character to disable further substitution.
|
||||
These options should make the resulting files uneditable, like -kv.
|
||||
|
||||
Add long options, e.g. `--version'. Unfortunately RCS's option syntax
|
||||
is incompatible with getopt. Perhaps the best way is to overload `rcs', e.g.
|
||||
`rcs diff --keyword-substitution=old file' instead of `rcsdiff -ko file'.
|
||||
|
||||
Add a way to put only the interesting part of the path into the $Header
|
||||
keyword expansion.
|
||||
|
||||
rlog -rM:N should work even if M and N have different numbers of fields,
|
||||
so long as M is an ancestor of N or vice versa.
|
||||
|
||||
rcs should evaluate options in order; this allows rcs -oS -nS.
|
||||
|
||||
rcs should be able to fix minor mistakes in checkin dates and authors.
|
||||
|
||||
Be able to redo your most recent checkin with minor changes.
|
||||
|
||||
co -u shouldn't complain about a writable working file if it won't change
|
||||
its contents.
|
||||
|
||||
Configure the Makefile automatically, as well as conf.h.
|
||||
|
||||
Add a new option to rcs that behaves like -o, but that doesn't lose the
|
||||
nonempty log messages, but instead merges them with the next revision
|
||||
if it exists, perhaps with a 1-line header containing author, date, etc.
|
||||
|
||||
Add a `-' option to take the list of pathnames from standard input.
|
||||
Perhaps the pathnames should be null-terminated, not newline-terminated,
|
||||
so that pathnames that contain newlines are handled properly.
|
||||
|
||||
Permit multiple option-pathname pairs, e.g. co -r1.4 a -r1.5 b.
|
||||
|
||||
Add options to allow arbitrary combinations of working file names
|
||||
with RCS file names -- they shouldn't have to match.
|
||||
|
||||
Add an option to break a symbolic link to an RCS file,
|
||||
instead of breaking the hard link that it points to.
|
||||
|
||||
Add ways to specify the earliest revision, the most recent revision,
|
||||
the earliest or latest revision on a particular branch, and
|
||||
the parent or child of some other revision.
|
||||
|
||||
If a user has multiple locks, perhaps ci should fall back on ci -k's
|
||||
method to figure out which revision to use.
|
||||
|
||||
Symbolic names need not refer to existing branches and revisions.
|
||||
rcs(1)'s BUGS section says this is a bug. Is it? If so, it should be fixed.
|
||||
|
||||
Add an option to rcs -o so that old log messages are not deleted if
|
||||
the next undeleted revision exists, but are merely appended to the log
|
||||
message of that revision.
|
||||
|
||||
ci -k should be able to get keyword values from the first `$Log' entry.
|
||||
|
||||
Add an option to rcsclean to clean directories recursively.
|
||||
|
||||
Write an rcsck program that repairs corrupted RCS files,
|
||||
much as fsck repairs corrupted file systems.
|
||||
For example, it should remove stale lock files.
|
||||
|
||||
Clean up the source code with a consistent indenting style.
|
||||
|
||||
Update the date parser to use the more modern getdate.y by Bellovin,
|
||||
Salz, and Berets, or the even more modern getdate by Moraes. None of
|
||||
these getdate implementations are as robust as RCS's old warhorse in
|
||||
avoiding problems like arithmetic overflow, so they'll have to be
|
||||
fixed first.
|
||||
|
||||
Break up the code into a library so that it's easier to write new programs
|
||||
that manipulate RCS files, and so that useless code is removed from the
|
||||
existing programs. For example, the rcs command contains unnecessary
|
||||
keyword substitution baggage, and the merge command can be greatly pruned.
|
||||
|
||||
Make it easier to use your favorite text editor to edit log messages,
|
||||
etc. instead of having to type them in irretrievably at the terminal.
|
||||
|
||||
Let the user specify a search path for default branches,
|
||||
e.g. to use L as the default branch if it works, and M otherwise.
|
||||
Let the user require that at least one entry in the default branch path works.
|
||||
Let the user say that later entries in the default branch path are read only,
|
||||
i.e. one cannot check in changes to them.
|
||||
This should be an option settable by RCSINIT.
|
||||
|
||||
Add a way for a user to see which revisions affected which lines.
|
||||
|
||||
Have `rlog -nN F' print just the revision number that N translates to.
|
||||
E.g. `rlog -nB. F' would print the highest revision on the branch B.
|
||||
Use this to add an option -bB to rcsbranch, to freeze the named branch.
|
||||
This should interact well with default branches.
|
||||
|
||||
Add a co option that prints the revision number before each line,
|
||||
as SCCS's `get -m' does.
|
||||
|
||||
The following projects require a change to RCS file format.
|
||||
|
||||
Allow keyword expansion to be changed on a per-revision basis,
|
||||
not on a per-file basis as now. This would allow -ko to be used
|
||||
on imported revisions, with the default -kkv otherwise.
|
||||
|
||||
When two or more branches are merged, record all the ancestors
|
||||
of the new revision. The hard part of this is keeping track of all
|
||||
the ancestors of a working file while it's checked out.
|
||||
|
||||
Add loose locking, which is like non-strict but applies to all users,
|
||||
not just the owner of the RCS file.
|
||||
|
||||
Be able to store RCS files in compressed format.
|
||||
Don't bother to use a .Z extension that would exceed file name length limits;
|
||||
just look at the magic number.
|
||||
|
||||
Add locker commentary, e.g. `co -l -m"checkout to fix merge bug" foo'
|
||||
to tell others why you checked out `foo'.
|
||||
Also record the time when the revision was locked,
|
||||
and perhaps the working pathname (if applicable).
|
||||
|
||||
Let the user mark an RCS revision as deleted; checking out such a revision
|
||||
would result in no working file. Similarly, using `co -d' with a date either
|
||||
before the initial revision or after the file was marked deleted should
|
||||
remove the working file. For extra credit, extend the notion of `deleted' to
|
||||
include `renamed'. RCS should support arbitrary combinations of renaming and
|
||||
deletion, e.g. renaming A to B and B to A, checking in new revisions to both
|
||||
files, and then renaming them back.
|
||||
|
||||
Be able to check in an entire directory structure into a single RCS file.
|
||||
|
||||
Use a better scheme for locking revisions; the current scheme requires
|
||||
changing the RCS file just to lock or unlock a revision.
|
||||
The new scheme should coexist as well as possible with older versions of RCS,
|
||||
and should avoid the rare NFS bugs mentioned in rcsedit.c.
|
||||
E.g. if there's a reliable lockd running, RCS should use it
|
||||
instead of relying on NFS.
|
||||
|
||||
Add rcs options for changing keyword names, e.g. XConsortium instead of Id.
|
||||
|
||||
Add a `$Description' keyword; but this may be tricky, since descriptions can
|
||||
contain newlines and $s.
|
||||
|
||||
Add a `$Copyright' keyword that expands to a copyright notice.
|
||||
|
||||
Add frozen branches a la SCCS. In general, be able to emulate all of
|
||||
SCCS, so that an SCCS-to-RCS program can be practical. For example,
|
||||
there should be an equivalent to the SCCS prt command.
|
||||
|
||||
Add support for distributed RCS, where widely separated
|
||||
users cannot easily access each others' RCS files,
|
||||
and must periodically distribute and reconcile new revisions.
|
||||
|
||||
Be able to create empty branches.
|
||||
|
||||
Be able to store just deltas from a read-only principal copy,
|
||||
e.g. from source on CD-ROM.
|
||||
|
||||
Improve RCS's method for storing binary files.
|
||||
Although it is more efficient than SCCS's,
|
||||
the diff algorithm is still line oriented,
|
||||
and often generates long output for minor changes to an executable file.
|
||||
|
||||
From the user's point of view, it would be best if
|
||||
RCS detected and handled binary files without human intervention,
|
||||
switching expansion methods as needed from revision to revision.
|
||||
|
||||
Allow RCS to determine automagically whether -ko or -kb should be the default
|
||||
by inspecting the file's contents or name. The magic should be optional
|
||||
and user-programmable.
|
||||
|
||||
Extend the grammar of RCS files so that keywords need not be in a fixed order.
|
||||
|
||||
Internationalize messages; unfortunately, there's no common standard yet.
|
||||
This requires a change in RCS file format because of the
|
||||
`empty log message' and `checked in with -k' hacks inside RCS files.
|
||||
|
||||
Add documentation in texinfo format.
|
90
gnu/usr.bin/rcs/REFS
Normal file
90
gnu/usr.bin/rcs/REFS
Normal file
@ -0,0 +1,90 @@
|
||||
Here are references to RCS and related free software and documentation.
|
||||
Some of this information changes often; see the Frequently Asked Questions
|
||||
for more up-to-date references.
|
||||
|
||||
$FreeBSD$
|
||||
|
||||
|
||||
Frequently Asked Questions (FAQs)
|
||||
|
||||
<http://www.qucis.queensu.ca/Software-Engineering/>
|
||||
<ftp://rtfm.mit.edu//pub/usenet-by-hierarchy/comp/software-eng/>
|
||||
for software engineering; e.g. see
|
||||
<http://www.qucis.queensu.ca/Software-Engineering/blurb/rcs>.
|
||||
|
||||
<http://www.iac.honeywell.com/Pub/Tech/CM/CMFAQ.html>
|
||||
<ftp://rtfm.mit.edu//pub/usenet-by-hierarchy/comp/software/config-mgmt/>
|
||||
for configuration management
|
||||
|
||||
<http://www.winternet.com/~zoo/cvs/FAQ.txt>
|
||||
<ftp://ftp.odi.com/pub/users/dgg/FAQ.gz>
|
||||
for CVS (see below)
|
||||
|
||||
|
||||
RCS and related GNU project software
|
||||
|
||||
<ftp://ftp.cs.purdue.edu/pub/RCS/>
|
||||
The RCS project distribution directory also contains beta versions,
|
||||
ports, and prebuilt documentation.
|
||||
|
||||
<ftp://prep.ai.mit.edu/pub/gnu/>
|
||||
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)
|
||||
|
||||
<ftp://ftp.leo.org/pub/comp/os/os2/gnu/devtools/> DOS, OS/2 ports
|
||||
<ftp://ftp.cc.utexas.edu/microlib/nt/gnu/> 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.
|
||||
|
||||
<http://www.winternet.com/~zoo/cvs/>
|
||||
<http://www.loria.fr/~molli/cvs-index.html>
|
||||
These pages have useful information about CVS.
|
||||
|
||||
<ftp://prep.ai.mit.edu/pub/gnu/cvs-1.3.tar.gz>
|
||||
CVS 1.3 is the latest released version.
|
||||
|
||||
<ftp://ftp.delos.com/pub/cvs/alpha/cvs-1.4A2.tar.gz>
|
||||
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.
|
||||
|
||||
<ftp://ftp-os2.cdrom.com/pub/os2/unix/> DOS, OS/2 ports
|
||||
<ftp://ftp.cc.utexas.edu/microlib/nt/gnu/> NT port
|
||||
|
||||
<ftp://ftp.cyclic.com/pub/cvs/>
|
||||
Cyclic CVS adds network transparency to CVS; it supports efficient,
|
||||
reliable, and authenticated repository access via TCP/IP.
|
||||
|
||||
|
||||
Other software that uses RCS
|
||||
|
||||
<ftp://ftp.nau.edu/pub/Aegis/>
|
||||
Aegis manages revisions, baselines, mandatory reviews, and mandatory testing.
|
||||
|
||||
<ftp://ftp.vix.com/pub/patches/csu/>
|
||||
BCS, the Baseline Configuration System,
|
||||
manages revisions, baselines, and staging areas.
|
||||
|
||||
<ftp://riftp.osf.org/pub/ode/>
|
||||
ODE, the Open Software Foundation Development Environment,
|
||||
manages revisions, builds, and sandboxes.
|
||||
OSF uses it for their own development.
|
||||
|
||||
<ftp://bellcore.com/pub/Odin/>
|
||||
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.
|
8
gnu/usr.bin/rcs/ci/Makefile
Normal file
8
gnu/usr.bin/rcs/ci/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= ci
|
||||
SRCS= ci.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
898
gnu/usr.bin/rcs/ci/ci.1
Normal file
898
gnu/usr.bin/rcs/ci/ci.1
Normal file
@ -0,0 +1,898 @@
|
||||
.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
|
1318
gnu/usr.bin/rcs/ci/ci.c
Normal file
1318
gnu/usr.bin/rcs/ci/ci.c
Normal file
File diff suppressed because it is too large
Load Diff
8
gnu/usr.bin/rcs/co/Makefile
Normal file
8
gnu/usr.bin/rcs/co/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= co
|
||||
SRCS= co.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
736
gnu/usr.bin/rcs/co/co.1
Normal file
736
gnu/usr.bin/rcs/co/co.1
Normal file
@ -0,0 +1,736 @@
|
||||
.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
|
826
gnu/usr.bin/rcs/co/co.c
Normal file
826
gnu/usr.bin/rcs/co/co.c
Normal file
@ -0,0 +1,826 @@
|
||||
/* 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,
|
||||
0<lockflag ? " (locked)" :
|
||||
lockflag<0 ? " (unlocked)" : "");
|
||||
|
||||
/* Prepare to remove old working file if necessary. */
|
||||
if (workstatstat == 0)
|
||||
if (!rmworkfile()) continue;
|
||||
|
||||
/* skip description */
|
||||
getdesc(false); /* don't echo*/
|
||||
|
||||
locker_expansion = 0 < lockflag;
|
||||
targetdelta->name = 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 ((2<l1 || 2<l2) && cmpnum(r1,r2)!=0) {
|
||||
/* not on main trunk or identical */
|
||||
l3 = 0;
|
||||
while (cmpnumfld(r1, r2, l3+1)==0 && cmpnumfld(r1, r2, l3+2)==0)
|
||||
l3 += 2;
|
||||
/* This will terminate since r1 and r2 are not the same; see above. */
|
||||
if (l3==0) {
|
||||
/* no common prefix; common ancestor on main trunk */
|
||||
VOID partialno(&t1, r1, l1>2 ? 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 (i<lastjoin) {
|
||||
/*prepare marker for merge*/
|
||||
if (i==0)
|
||||
bufscpy(&subs, targetdelta->num);
|
||||
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;
|
||||
}
|
1518
gnu/usr.bin/rcs/doc/rcs.ms
Normal file
1518
gnu/usr.bin/rcs/doc/rcs.ms
Normal file
File diff suppressed because it is too large
Load Diff
95
gnu/usr.bin/rcs/doc/rcs_func.ms
Normal file
95
gnu/usr.bin/rcs/doc/rcs_func.ms
Normal file
@ -0,0 +1,95 @@
|
||||
.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.
|
8
gnu/usr.bin/rcs/ident/Makefile
Normal file
8
gnu/usr.bin/rcs/ident/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= ident
|
||||
SRCS= ident.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
182
gnu/usr.bin/rcs/ident/ident.1
Normal file
182
gnu/usr.bin/rcs/ident/ident.1
Normal file
@ -0,0 +1,182 @@
|
||||
.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 <stdio.h>
|
||||
.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.
|
270
gnu/usr.bin/rcs/ident/ident.c
Normal file
270
gnu/usr.bin/rcs/ident/ident.c
Normal file
@ -0,0 +1,270 @@
|
||||
/* 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;
|
||||
}
|
14
gnu/usr.bin/rcs/lib/Makefile
Normal file
14
gnu/usr.bin/rcs/lib/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# $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 <bsd.lib.mk>
|
400
gnu/usr.bin/rcs/lib/conf.h
Normal file
400
gnu/usr.bin/rcs/lib/conf.h
Normal file
@ -0,0 +1,400 @@
|
||||
/* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Comment out #include lines below that do not work. */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
/* #include <mach/mach.h> */
|
||||
/* #include <net/errno.h> */
|
||||
#include <pwd.h>
|
||||
/* #include <siginfo.h> */
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
/* #include <ucontext.h> */
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
/* #include <vfork.h> */
|
||||
|
||||
/* Define boolean symbols to be 0 (false, the default), or 1 (true). */
|
||||
#define has_sys_param_h 1 /* Does #include <sys/param.h> work? */
|
||||
/* extern int errno; */ /* Uncomment if <errno.h> 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 <sys/param.h>
|
||||
# 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 <stdarg.h> work? */
|
||||
/* #define has_varargs ? */ /* Does <varargs.h> 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 <stdarg.h>
|
||||
#else
|
||||
# if has_varargs
|
||||
# include <varargs.h>
|
||||
# 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) */
|
||||
|
||||
/* <fcntl.h> */
|
||||
#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
|
||||
|
||||
/* <sys/stat.h> */
|
||||
#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
|
||||
|
||||
/* <sys/wait.h> */
|
||||
#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
|
||||
|
||||
/* <unistd.h> */
|
||||
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 */
|
||||
|
||||
/* <stdio.h> */
|
||||
#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
|
||||
|
||||
/* <stdlib.h> */
|
||||
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
|
||||
|
||||
/* <string.h> */
|
||||
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.h> */
|
||||
time_t time P((time_t*));
|
344
gnu/usr.bin/rcs/lib/maketime.c
Normal file
344
gnu/usr.bin/rcs/lib/maketime.c
Normal file
@ -0,0 +1,344 @@
|
||||
/* 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 <stdlib.h>
|
||||
# include <time.h>
|
||||
#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 <stdio.h>
|
||||
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
|
39
gnu/usr.bin/rcs/lib/maketime.h
Normal file
39
gnu/usr.bin/rcs/lib/maketime.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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));
|
148
gnu/usr.bin/rcs/lib/merger.c
Normal file
148
gnu/usr.bin/rcs/lib/merger.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* 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;
|
||||
}
|
701
gnu/usr.bin/rcs/lib/partime.c
Normal file
701
gnu/usr.bin/rcs/lib/partime.c
Normal file
@ -0,0 +1,701 @@
|
||||
/* 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 <limits.h>
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#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;
|
||||
}
|
71
gnu/usr.bin/rcs/lib/partime.h
Normal file
71
gnu/usr.bin/rcs/lib/partime.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* 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 *));
|
762
gnu/usr.bin/rcs/lib/rcsbase.h
Normal file
762
gnu/usr.bin/rcs/lib/rcsbase.h
Normal file
@ -0,0 +1,762 @@
|
||||
/* 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 <strings.h> -> 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[];
|
1958
gnu/usr.bin/rcs/lib/rcsedit.c
Normal file
1958
gnu/usr.bin/rcs/lib/rcsedit.c
Normal file
File diff suppressed because it is too large
Load Diff
354
gnu/usr.bin/rcs/lib/rcsfcmp.c
Normal file
354
gnu/usr.bin/rcs/lib/rcsfcmp.c
Normal file
@ -0,0 +1,354 @@
|
||||
/* 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 (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) {
|
||||
/*
|
||||
* This log message was inserted. Skip its header.
|
||||
* The number of newlines to skip is
|
||||
* 1 + (C+1)*(1+L+1), where C is the number of newlines
|
||||
* in the comment leader, and L is the number of
|
||||
* newlines in the log string.
|
||||
*/
|
||||
int c1 = 1;
|
||||
for (ccnt=Comment.size; ccnt--; )
|
||||
c1 += Comment.string[ccnt] == '\n';
|
||||
lncnt = 2*c1 + 1;
|
||||
while (ls--) if (*sp++=='\n') lncnt += c1;
|
||||
for (;;) {
|
||||
if (xc=='\n')
|
||||
if(--lncnt==0) break;
|
||||
Igeteof_(xfp, xc, goto returnresult;)
|
||||
}
|
||||
/* skip last comment leader */
|
||||
/* Can't just skip another line here, because there may be */
|
||||
/* additional characters on the line (after the Log....$) */
|
||||
ccnt = RCSversion<VERSION(5) ? Comment.size : leaderlen;
|
||||
do {
|
||||
Igeteof_(xfp, xc, goto returnresult;)
|
||||
/*
|
||||
* Read to the end of the comment leader or '\n',
|
||||
* whatever comes first, because the leader's
|
||||
* trailing white space was probably stripped.
|
||||
*/
|
||||
} while (ccnt-- && (xc!='\n' || --c1));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* both end in the same character, but not a KDELIM */
|
||||
/* must compare string values.*/
|
||||
#ifdef FCMPTEST
|
||||
VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword);
|
||||
#endif
|
||||
if (!eqkeyvals)
|
||||
goto return1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xc != uc)
|
||||
goto return1;
|
||||
if (xc == '\n')
|
||||
leaderlen = 0;
|
||||
else
|
||||
leaderlen++;
|
||||
}
|
||||
}
|
||||
|
||||
eof:
|
||||
if (xeof==ueof)
|
||||
goto returnresult;
|
||||
return1:
|
||||
result = 1;
|
||||
returnresult:
|
||||
Ifclose(ufp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef FCMPTEST
|
||||
|
||||
char const cmdid[] = "rcsfcmp";
|
||||
|
||||
main(argc, argv)
|
||||
int argc; char *argv[];
|
||||
/* first argument: comment leader; 2nd: log message, 3rd: expanded file,
|
||||
* 4th: unexpanded file
|
||||
*/
|
||||
{ struct hshentry delta;
|
||||
|
||||
Comment.string = argv[1];
|
||||
Comment.size = strlen(argv[1]);
|
||||
delta.log.string = argv[2];
|
||||
delta.log.size = strlen(argv[2]);
|
||||
if (rcsfcmp(Iopen(argv[3], FOPEN_R_WORK, (struct stat*)0), argv[4], &delta))
|
||||
VOID printf("files are the same\n");
|
||||
else VOID printf("files are different\n");
|
||||
}
|
||||
#endif
|
1132
gnu/usr.bin/rcs/lib/rcsfnms.c
Normal file
1132
gnu/usr.bin/rcs/lib/rcsfnms.c
Normal file
File diff suppressed because it is too large
Load Diff
681
gnu/usr.bin/rcs/lib/rcsgen.c
Normal file
681
gnu/usr.bin/rcs/lib/rcsgen.c
Normal file
@ -0,0 +1,681 @@
|
||||
/* 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);
|
||||
}
|
452
gnu/usr.bin/rcs/lib/rcskeep.c
Normal file
452
gnu/usr.bin/rcs/lib/rcskeep.c
Normal file
@ -0,0 +1,452 @@
|
||||
/* 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
|
186
gnu/usr.bin/rcs/lib/rcskeys.c
Normal file
186
gnu/usr.bin/rcs/lib/rcskeys.c
Normal file
@ -0,0 +1,186 @@
|
||||
/* 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);
|
||||
}
|
1568
gnu/usr.bin/rcs/lib/rcslex.c
Normal file
1568
gnu/usr.bin/rcs/lib/rcslex.c
Normal file
File diff suppressed because it is too large
Load Diff
69
gnu/usr.bin/rcs/lib/rcsmap.c
Normal file
69
gnu/usr.bin/rcs/lib/rcsmap.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* 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
|
||||
};
|
911
gnu/usr.bin/rcs/lib/rcsrev.c
Normal file
911
gnu/usr.bin/rcs/lib/rcsrev.c
Normal file
@ -0,0 +1,911 @@
|
||||
/* 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 `<now>' 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 num1<num2, num1==num2, and num1>num2, 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 d1<d2 ? -1 : 1;
|
||||
if ((r = memcmp(s1, s2, d1)))
|
||||
return r;
|
||||
s1 += d1;
|
||||
s2 += d1;
|
||||
|
||||
/* skip '.' */
|
||||
if (*s1) s1++;
|
||||
if (*s2) s2++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int cmpnumfld(num1, num2, fld)
|
||||
char const *num1, *num2;
|
||||
int fld;
|
||||
/* Compare the two dotted numbers at field fld.
|
||||
* num1 and num2 must have at least fld fields.
|
||||
* fld must be positive.
|
||||
*/
|
||||
{
|
||||
register char const *s1, *s2;
|
||||
register size_t d1, d2;
|
||||
|
||||
s1 = num1;
|
||||
s2 = num2;
|
||||
/* skip fld-1 fields */
|
||||
while (--fld) {
|
||||
while (*s1++ != '.')
|
||||
continue;
|
||||
while (*s2++ != '.')
|
||||
continue;
|
||||
}
|
||||
/* Now s1 and s2 point to the beginning of the respective fields */
|
||||
while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
|
||||
while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
|
||||
|
||||
return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cmpdate(d1, d2)
|
||||
char const *d1, *d2;
|
||||
/*
|
||||
* Compare the two dates. This is just like cmpnum,
|
||||
* except that for compatibility with old versions of RCS,
|
||||
* 1900 is added to dates with two-digit years.
|
||||
*/
|
||||
{
|
||||
char year1[5], year2[5];
|
||||
int r = cmpnumfld(normalizeyear(d1,year1), normalizeyear(d2,year2), 1);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
else {
|
||||
while (isdigit(*d1)) d1++; d1 += *d1=='.';
|
||||
while (isdigit(*d2)) d2++; d2 += *d2=='.';
|
||||
return cmpnum(d1, d2);
|
||||
}
|
||||
}
|
||||
|
||||
static char const *
|
||||
normalizeyear(date, year)
|
||||
char const *date;
|
||||
char year[5];
|
||||
{
|
||||
if (isdigit(date[0]) && isdigit(date[1]) && !isdigit(date[2])) {
|
||||
year[0] = '1';
|
||||
year[1] = '9';
|
||||
year[2] = date[0];
|
||||
year[3] = date[1];
|
||||
year[4] = 0;
|
||||
return year;
|
||||
} else
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cantfindbranch(revno, date, author, state)
|
||||
char const *revno, date[datesize], *author, *state;
|
||||
{
|
||||
char datebuf[datesize + zonelenmax];
|
||||
|
||||
rcserror("No revision on branch %s has%s%s%s%s%s%s.",
|
||||
revno,
|
||||
date ? " a date before " : "",
|
||||
date ? date2str(date,datebuf) : "",
|
||||
author ? " and author "+(date?0:4) : "",
|
||||
author ? author : "",
|
||||
state ? " and state "+(date||author?0:4) : "",
|
||||
state ? state : ""
|
||||
);
|
||||
}
|
||||
|
||||
static void
|
||||
absent(revno, field)
|
||||
char const *revno;
|
||||
int field;
|
||||
{
|
||||
struct buf t;
|
||||
bufautobegin(&t);
|
||||
rcserror("%s %s absent", field&1?"revision":"branch",
|
||||
partialno(&t,revno,field)
|
||||
);
|
||||
bufautoend(&t);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
compartial(num1, num2, length)
|
||||
char const *num1, *num2;
|
||||
int length;
|
||||
|
||||
/* compare the first "length" fields of two dot numbers;
|
||||
the omitted field is considered to be larger than any number */
|
||||
/* restriction: at least one number has length or more fields */
|
||||
|
||||
{
|
||||
register char const *s1, *s2;
|
||||
register size_t d1, d2;
|
||||
register int r;
|
||||
|
||||
s1 = num1; s2 = num2;
|
||||
if (!s1) return 1;
|
||||
if (!s2) return -1;
|
||||
|
||||
for (;;) {
|
||||
if (!*s1) return 1;
|
||||
if (!*s2) return -1;
|
||||
|
||||
while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
|
||||
while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
|
||||
|
||||
if (d1 != d2)
|
||||
return d1<d2 ? -1 : 1;
|
||||
if ((r = memcmp(s1, s2, d1)))
|
||||
return r;
|
||||
if (!--length)
|
||||
return 0;
|
||||
|
||||
s1 += d1;
|
||||
s2 += d1;
|
||||
|
||||
if (*s1 == '.') s1++;
|
||||
if (*s2 == '.') s2++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char * partialno(rev1,rev2,length)
|
||||
struct buf *rev1;
|
||||
char const *rev2;
|
||||
register int length;
|
||||
/* Function: Copies length fields of revision number rev2 into rev1.
|
||||
* Return rev1's string.
|
||||
*/
|
||||
{
|
||||
register char *r1;
|
||||
|
||||
bufscpy(rev1, rev2);
|
||||
r1 = rev1->string;
|
||||
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 : "<empty>"
|
||||
);
|
||||
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 : "<empty>"
|
||||
);
|
||||
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 <return> 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
|
681
gnu/usr.bin/rcs/lib/rcssyn.c
Normal file
681
gnu/usr.bin/rcs/lib/rcssyn.c
Normal file
@ -0,0 +1,681 @@
|
||||
/* 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 <admin> 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
|
||||
* <keyword> <token> ;
|
||||
* where token is one of <id> or <num>. optional indicates whether
|
||||
* <token> is optional. A pointer to
|
||||
* the actual character string of <id> or <num> 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
|
191
gnu/usr.bin/rcs/lib/rcstime.c
Normal file
191
gnu/usr.bin/rcs/lib/rcstime.c
Normal file
@ -0,0 +1,191 @@
|
||||
/* 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, RCSversion<VERSION(5));
|
||||
VOID sprintf(date,
|
||||
# if has_printf_dot
|
||||
"%.2d.%.2d.%.2d.%.2d.%.2d.%.2d",
|
||||
# else
|
||||
"%02d.%02d.%02d.%02d.%02d.%02d",
|
||||
# endif
|
||||
tm->tm_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
|
||||
: RCSversion<VERSION(5) ? TM_LOCAL_ZONE
|
||||
: 0
|
||||
),
|
||||
target
|
||||
);
|
||||
}
|
||||
|
||||
/* Convert an RCS internal format date to time_t. */
|
||||
time_t
|
||||
date2time(source)
|
||||
char const source[datesize];
|
||||
{
|
||||
char s[datesize + zonelenmax];
|
||||
return str2time_checked(date2str(source, s), (time_t)0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Set the time zone for date2str output. */
|
||||
void
|
||||
zone_set(s)
|
||||
char const *s;
|
||||
{
|
||||
if ((use_zone_offset = *s)) {
|
||||
long zone;
|
||||
char const *zonetail = parzone(s, &zone);
|
||||
if (!zonetail || *zonetail)
|
||||
error("%s: not a known time zone", s);
|
||||
else
|
||||
zone_offset = zone;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Format a user-readable form of the RCS format DATE into the buffer DATEBUF.
|
||||
* Yield DATEBUF.
|
||||
*/
|
||||
char const *
|
||||
date2str(date, datebuf)
|
||||
char const date[datesize];
|
||||
char datebuf[datesize + zonelenmax];
|
||||
{
|
||||
register char const *p = date;
|
||||
|
||||
while (*p++ != '.')
|
||||
continue;
|
||||
if (!use_zone_offset)
|
||||
VOID sprintf(datebuf,
|
||||
"19%.*s/%.2s/%.2s %.2s:%.2s:%s"
|
||||
+ (date[2]=='.' && VERSION(5)<=RCSversion ? 0 : 2),
|
||||
(int)(p-date-1), date,
|
||||
p, p+3, p+6, p+9, p+12
|
||||
);
|
||||
else {
|
||||
struct tm t;
|
||||
struct tm const *z;
|
||||
int non_hour;
|
||||
long zone;
|
||||
char c;
|
||||
|
||||
t.tm_year = atoi(date) - (date[2]=='.' ? 0 : 1900);
|
||||
t.tm_mon = atoi(p) - 1;
|
||||
t.tm_mday = atoi(p+3);
|
||||
t.tm_hour = atoi(p+6);
|
||||
t.tm_min = atoi(p+9);
|
||||
t.tm_sec = atoi(p+12);
|
||||
t.tm_wday = -1;
|
||||
zone = zone_offset;
|
||||
if (zone == TM_LOCAL_ZONE) {
|
||||
time_t u = tm2time(&t, 0), d;
|
||||
z = localtime(&u);
|
||||
d = difftm(z, &t);
|
||||
zone = (time_t)-1 < 0 || d < -d ? d : -(long)-d;
|
||||
} else {
|
||||
adjzone(&t, zone);
|
||||
z = &t;
|
||||
}
|
||||
c = '+';
|
||||
if (zone < 0) {
|
||||
zone = -zone;
|
||||
c = '-';
|
||||
}
|
||||
VOID sprintf(datebuf,
|
||||
# if has_printf_dot
|
||||
"%.2d-%.2d-%.2d %.2d:%.2d:%.2d%c%.2d",
|
||||
# else
|
||||
"%02d-%02d-%02d %02d:%02d:%02d%c%02d",
|
||||
# endif
|
||||
z->tm_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;
|
||||
}
|
1398
gnu/usr.bin/rcs/lib/rcsutil.c
Normal file
1398
gnu/usr.bin/rcs/lib/rcsutil.c
Normal file
File diff suppressed because it is too large
Load Diff
2
gnu/usr.bin/rcs/lib/version.c
Normal file
2
gnu/usr.bin/rcs/lib/version.c
Normal file
@ -0,0 +1,2 @@
|
||||
#include "rcsbase.h"
|
||||
char const RCS_version_string[] = "5.7";
|
8
gnu/usr.bin/rcs/merge/Makefile
Normal file
8
gnu/usr.bin/rcs/merge/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= merge
|
||||
SRCS= merge.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
137
gnu/usr.bin/rcs/merge/merge.1
Normal file
137
gnu/usr.bin/rcs/merge/merge.1
Normal file
@ -0,0 +1,137 @@
|
||||
.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
|
113
gnu/usr.bin/rcs/merge/merge.c
Normal file
113
gnu/usr.bin/rcs/merge/merge.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* 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);
|
||||
}
|
10
gnu/usr.bin/rcs/rcs/Makefile
Normal file
10
gnu/usr.bin/rcs/rcs/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= rcs
|
||||
MAN= rcs.1 rcsintro.1 rcsfile.5
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
454
gnu/usr.bin/rcs/rcs/rcs.1
Normal file
454
gnu/usr.bin/rcs/rcs/rcs.1
Normal file
@ -0,0 +1,454 @@
|
||||
.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
|
1629
gnu/usr.bin/rcs/rcs/rcs.c
Normal file
1629
gnu/usr.bin/rcs/rcs/rcs.c
Normal file
File diff suppressed because it is too large
Load Diff
425
gnu/usr.bin/rcs/rcs/rcsfile.5
Normal file
425
gnu/usr.bin/rcs/rcs/rcsfile.5
Normal file
@ -0,0 +1,425 @@
|
||||
.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.
|
302
gnu/usr.bin/rcs/rcs/rcsintro.1
Normal file
302
gnu/usr.bin/rcs/rcs/rcsintro.1
Normal file
@ -0,0 +1,302 @@
|
||||
.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
|
8
gnu/usr.bin/rcs/rcsclean/Makefile
Normal file
8
gnu/usr.bin/rcs/rcsclean/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= rcsclean
|
||||
SRCS= rcsclean.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
203
gnu/usr.bin/rcs/rcsclean/rcsclean.1
Normal file
203
gnu/usr.bin/rcs/rcsclean/rcsclean.1
Normal file
@ -0,0 +1,203 @@
|
||||
.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
|
333
gnu/usr.bin/rcs/rcsclean/rcsclean.c
Normal file
333
gnu/usr.bin/rcs/rcsclean/rcsclean.c
Normal file
@ -0,0 +1,333 @@
|
||||
/* 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 (unlocked<waslocked && workstat.st_mode&(S_IWUSR|S_IWGRP|S_IWOTH))
|
||||
continue;
|
||||
|
||||
if (unlocked && !checkaccesslist())
|
||||
continue;
|
||||
|
||||
if (dorewrite(dounlock, unlocked) != 0)
|
||||
continue;
|
||||
|
||||
if (0 <= expmode)
|
||||
Expand = expmode;
|
||||
else if (
|
||||
waslocked &&
|
||||
Expand == KEYVAL_EXPAND &&
|
||||
WORKMODE(RCSstat.st_mode,true) == workstat.st_mode
|
||||
)
|
||||
Expand = KEYVALLOCK_EXPAND;
|
||||
|
||||
getdesc(false);
|
||||
|
||||
if (
|
||||
!delta ? workstat.st_size!=0 :
|
||||
0 < rcsfcmp(
|
||||
workptr, &workstat,
|
||||
buildrevision(deltas, delta, (FILE*)0, false),
|
||||
delta
|
||||
)
|
||||
)
|
||||
continue;
|
||||
|
||||
if (quietflag < unlocked)
|
||||
aprintf(stdout, "rcs -u%s %s\n", delta->num, 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<entries; i++)
|
||||
*p++ = a + offset[i];
|
||||
*p = 0;
|
||||
tfree(offset);
|
||||
return entries;
|
||||
}
|
||||
#endif
|
8
gnu/usr.bin/rcs/rcsdiff/Makefile
Normal file
8
gnu/usr.bin/rcs/rcsdiff/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= rcsdiff
|
||||
SRCS= rcsdiff.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
158
gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
Normal file
158
gnu/usr.bin/rcs/rcsdiff/rcsdiff.1
Normal file
@ -0,0 +1,158 @@
|
||||
.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
|
480
gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
Normal file
480
gnu/usr.bin/rcs/rcsdiff/rcsdiff.c
Normal file
@ -0,0 +1,480 @@
|
||||
/* 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; pp<diffp; )
|
||||
c += strlen(*pp++) + 1;
|
||||
diffvstr = a = tnalloc(char, c + 1);
|
||||
for (pp = diffv+2; pp<diffp; ) {
|
||||
p = *pp++;
|
||||
*a++ = ' ';
|
||||
while ((*a = *p++))
|
||||
a++;
|
||||
}
|
||||
*a = 0;
|
||||
|
||||
#if DIFF_L
|
||||
diff_label1 = diff_label2 = 0;
|
||||
if (file_labels < 2) {
|
||||
if (!file_labels)
|
||||
diff_label1 = diffp++;
|
||||
diff_label2 = diffp++;
|
||||
}
|
||||
#endif
|
||||
diffpend = diffp;
|
||||
|
||||
cov[1] = CO;
|
||||
cov[2] = "-q";
|
||||
# if !DIFF_L
|
||||
cov[3] = "-M";
|
||||
# endif
|
||||
|
||||
/* 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;
|
||||
diagnose("===================================================================\nRCS file: %s\n",RCSname);
|
||||
if (!rev2) {
|
||||
/* Make sure work file is readable, and get its status. */
|
||||
if (!(workptr = Iopen(workname, FOPEN_R_WORK, &workstat))) {
|
||||
eerror(workname);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gettree(); /* reads in the delta tree */
|
||||
|
||||
if (!Head) {
|
||||
rcserror("no revisions present");
|
||||
continue;
|
||||
}
|
||||
if (revnums==0 || !*rev1)
|
||||
rev1 = Dbranch ? Dbranch : Head->num;
|
||||
|
||||
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
|
7
gnu/usr.bin/rcs/rcsfreeze/Makefile
Normal file
7
gnu/usr.bin/rcs/rcsfreeze/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SCRIPTS= rcsfreeze.sh
|
||||
MAN= rcsfreeze.1
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
68
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1
Normal file
68
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.1
Normal file
@ -0,0 +1,68 @@
|
||||
.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.
|
99
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
Normal file
99
gnu/usr.bin/rcs/rcsfreeze/rcsfreeze.sh
Normal file
@ -0,0 +1,99 @@
|
||||
#! /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
|
8
gnu/usr.bin/rcs/rcsmerge/Makefile
Normal file
8
gnu/usr.bin/rcs/rcsmerge/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= rcsmerge
|
||||
SRCS= rcsmerge.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
189
gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
Normal file
189
gnu/usr.bin/rcs/rcsmerge/rcsmerge.1
Normal file
@ -0,0 +1,189 @@
|
||||
.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
|
286
gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
Normal file
286
gnu/usr.bin/rcs/rcsmerge/rcsmerge.c
Normal file
@ -0,0 +1,286 @@
|
||||
/* 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);
|
||||
}
|
454
gnu/usr.bin/rcs/rcstest
Executable file
454
gnu/usr.bin/rcs/rcstest
Executable file
@ -0,0 +1,454 @@
|
||||
#! /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 <<EOF
|
||||
@Author: w @
|
||||
@Date: $date @
|
||||
@Header: $PWD$SLASH$RCSfile 2.1 $date w s @
|
||||
@Id: a.c 2.1 $date w s @
|
||||
@Locker: @
|
||||
* @Log: a.c @
|
||||
* Revision 2.1 $date w
|
||||
* m
|
||||
*
|
||||
@Name: Oz @
|
||||
@RCSfile: a.c @
|
||||
@Revision: 2.1 @
|
||||
@Source: $PWD$SLASH$RCSfile @
|
||||
@State: s @
|
||||
EOF
|
||||
test $? = 0 &&
|
||||
sed 's/:.*\$/$/' 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 <stdio.h>
|
||||
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 <<EOF
|
||||
|
||||
RCS file: $RCSfile
|
||||
Working file: a.c
|
||||
head: 2.3
|
||||
branch:
|
||||
locks: strict
|
||||
access list:
|
||||
symbolic names:
|
||||
N: 2.1
|
||||
Oz: 2.1
|
||||
n: 1.8
|
||||
keyword substitution: kv
|
||||
total revisions: 13; selected revisions: 1
|
||||
description:
|
||||
1.1
|
||||
----------------------------
|
||||
revision 2.1
|
||||
date: $date; author: w; state: s; lines: +14 -1
|
||||
=============================================================================
|
||||
EOF
|
||||
test $? = 0 || { echo "#rlog failed"; exit 1; }
|
||||
|
||||
|
||||
test ! -f $lockfile || { echo "#lock file not removed"; exit 1; }
|
||||
|
||||
rm -f a.* $RCSfile $RCS_alt
|
||||
$rmdir RCS
|
8
gnu/usr.bin/rcs/rlog/Makefile
Normal file
8
gnu/usr.bin/rcs/rlog/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
PROG= rlog
|
||||
SRCS= rlog.c
|
||||
CFLAGS+= -I${.CURDIR}/../lib
|
||||
LDADD= ${LIBRCS}
|
||||
DPADD= ${LIBRCS}
|
||||
|
||||
.include "../../Makefile.inc"
|
||||
.include <bsd.prog.mk>
|
318
gnu/usr.bin/rcs/rlog/rlog.1
Normal file
318
gnu/usr.bin/rcs/rlog/rlog.1
Normal file
@ -0,0 +1,318 @@
|
||||
.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
|
1290
gnu/usr.bin/rcs/rlog/rlog.c
Normal file
1290
gnu/usr.bin/rcs/rlog/rlog.c
Normal file
File diff suppressed because it is too large
Load Diff
6
share/doc/psd/13.rcs/Makefile
Normal file
6
share/doc/psd/13.rcs/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SUBDIR= rcs rcs_func
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
5
share/doc/psd/13.rcs/Makefile.inc
Normal file
5
share/doc/psd/13.rcs/Makefile.inc
Normal file
@ -0,0 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
VOLUME= psd/13.rcs
|
||||
MACROS= -ms
|
||||
SRCDIR= ${.CURDIR}/../../../../../gnu/usr.bin/rcs/doc
|
7
share/doc/psd/13.rcs/rcs/Makefile
Normal file
7
share/doc/psd/13.rcs/rcs/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SRCS= rcs.ms
|
||||
USE_PIC=
|
||||
USE_TBL=
|
||||
|
||||
.include <bsd.doc.mk>
|
6
share/doc/psd/13.rcs/rcs_func/Makefile
Normal file
6
share/doc/psd/13.rcs/rcs_func/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
DOC= rcs_func
|
||||
SRCS= rcs_func.ms
|
||||
|
||||
.include <bsd.doc.mk>
|
@ -20,6 +20,7 @@ SUBDIR= title \
|
||||
05.sysman \
|
||||
06.Clang \
|
||||
12.make \
|
||||
13.rcs \
|
||||
15.yacc \
|
||||
16.lex \
|
||||
17.m4 \
|
||||
|
@ -909,6 +909,11 @@ This includes
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
etc.
|
||||
.It Va WITHOUT_RCS
|
||||
.\" from FreeBSD: head/tools/build/options/WITHOUT_RCS 156932 2006-03-21 07:50:50Z ru
|
||||
Set to not build
|
||||
.Xr rcs 1
|
||||
and related utilities.
|
||||
.It Va WITHOUT_RESCUE
|
||||
.\" from FreeBSD: head/tools/build/options/WITHOUT_RESCUE 156932 2006-03-21 07:50:50Z ru
|
||||
Set to not build
|
||||
|
@ -334,6 +334,7 @@ __DEFAULT_YES_OPTIONS = \
|
||||
PROFILE \
|
||||
QUOTAS \
|
||||
RCMDS \
|
||||
RCS \
|
||||
RESCUE \
|
||||
ROUTED \
|
||||
SENDMAIL \
|
||||
|
@ -3859,6 +3859,31 @@ 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
|
||||
|
4
tools/build/options/WITHOUT_RCS
Normal file
4
tools/build/options/WITHOUT_RCS
Normal file
@ -0,0 +1,4 @@
|
||||
.\" $FreeBSD$
|
||||
Set to not build
|
||||
.Xr rcs 1
|
||||
and related utilities.
|
Loading…
Reference in New Issue
Block a user