summaryrefslogtreecommitdiff
path: root/contrib/cvs/src/rcscmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/rcscmds.c')
-rw-r--r--contrib/cvs/src/rcscmds.c170
1 files changed, 102 insertions, 68 deletions
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
index 66aea57447a5b..1f93fcfb94eed 100644
--- a/contrib/cvs/src/rcscmds.c
+++ b/contrib/cvs/src/rcscmds.c
@@ -12,28 +12,73 @@
#include "cvs.h"
#include <assert.h>
+/* This file, rcs.h, and rcs.c, are intended to define our interface
+ to RCS files. As of July, 1996, there are still a few places that
+ still exec RCS commands directly. The intended long-term direction
+ is to have CVS access RCS files via an RCS library (rcs.c can be
+ considered a start at one), for performance, cleanliness (CVS has
+ some awful hacks to work around RCS behaviors which don't make
+ sense for CVS), installation hassles, ease of implementing the CVS
+ server (I don't think that the output-out-of-order bug can be
+ completely fixed as long as CVS calls RCS), and perhaps other
+ reasons.
+
+ Whether there will also be a version of RCS which uses this
+ library, or whether the library will be packaged for uses beyond
+ CVS or RCS (many people would like such a thing) is an open
+ question. Some considerations:
+
+ 1. An RCS library for CVS must have the capabilities of the
+ existing CVS code which accesses RCS files. In particular, simple
+ approaches will often be slow.
+
+ 2. An RCS library should not use the code from the current RCS
+ (5.7 and its ancestors). The code has many problems. Too few
+ comments, too many layers of abstraction, too many global variables
+ (the correct number for a library is zero), too much intricately
+ interwoven functionality, and too many clever hacks. Paul Eggert,
+ the current RCS maintainer, agrees.
+
+ 3. More work needs to be done in terms of separating out the RCS
+ library from the rest of CVS (for example, cvs_output should be
+ replaced by a callback, and the declarations should be centralized
+ into rcs.h, and probably other such cleanups).
+
+ 4. To be useful for RCS and perhaps for other uses, the library
+ may need features beyond those needed by CVS.
+
+ 5. Any changes to the RCS file format *must* be compatible. Many,
+ many tools (not just CVS and RCS) can at least import this format.
+ RCS and CVS must preserve the current ability to import/export it
+ (preferably improved--magic branches are currently a roadblock).
+ See doc/RCSFILES in the CVS distribution for documentation of this
+ file format.
+
+ On somewhat related notes:
+
+ 1. A library for diff is an obvious idea. The one thing which I'm
+ not so sure about is that I think CVS probably wants the ability to
+ allow arbitrarily-bizarre (and possibly customized for particular
+ file formats) external diff programs.
+
+ 2. A library for patch is another such idea. CVS's needs are
+ smaller than the functionality of the standalone patch program (it
+ only calls patch in the client, and only needs to be able to patch
+ unmodified versions, which is something that RCS_deltas already
+ does in a different context). But it is silly for CVS to be making
+ people install patch as well as CVS for such a simple purpose. */
+
/* For RCS file PATH, make symbolic tag TAG point to revision REV.
This validates that TAG is OK for a user to use. Return value is
-1 for error (and errno is set to indicate the error), positive for
error (and an error message has been printed), or zero for success. */
int
-RCS_settag(path, tag, rev)
+RCS_exec_settag(path, tag, rev)
const char *path;
const char *tag;
const char *rev;
{
- if (strcmp (tag, TAG_BASE) == 0
- || strcmp (tag, TAG_HEAD) == 0)
- {
- /* Print the name of the tag might be considered redundant
- with the caller, which also prints it. Perhaps this helps
- clarify why the tag name is considered reserved, I don't
- know. */
- error (0, 0, "Attempt to add reserved tag name %s", tag);
- return 1;
- }
-
run_setup ("%s%s -x,v/ -q -N%s:%s", Rcsbin, RCS, tag, rev);
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
@@ -42,7 +87,7 @@ RCS_settag(path, tag, rev)
/* NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
-RCS_deltag(path, tag, noerr)
+RCS_exec_deltag(path, tag, noerr)
const char *path;
const char *tag;
int noerr;
@@ -54,7 +99,7 @@ RCS_deltag(path, tag, noerr)
/* set RCS branch to REV */
int
-RCS_setbranch(path, rev)
+RCS_exec_setbranch(path, rev)
const char *path;
const char *rev;
{
@@ -66,7 +111,7 @@ RCS_setbranch(path, rev)
/* Lock revision REV. NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
-RCS_lock(path, rev, noerr)
+RCS_exec_lock(path, rev, noerr)
const char *path;
const char *rev;
int noerr;
@@ -79,7 +124,7 @@ RCS_lock(path, rev, noerr)
/* Unlock revision REV. NOERR is 1 to suppress errors--FIXME it would
be better to avoid the errors or some cleaner solution. */
int
-RCS_unlock(path, rev, noerr)
+RCS_exec_unlock(path, rev, noerr)
const char *path;
const char *rev;
int noerr;
@@ -107,71 +152,53 @@ RCS_merge(path, options, rev1, rev2)
#ifndef HAVE_RCS5
if (status == 0)
{
- /* Run GREP to see if there appear to be conflicts in the file */
- run_setup ("%s", GREP);
- run_arg (RCS_MERGE_PAT);
- run_arg (path);
- status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0);
-
+ error (1, 0, "CVS no longer supports RCS versions older than RCS5");
+ /* This case needs to call file_has_markers to see if the file
+ contains conflict indicators. But is anyone using the !HAVE_RCS5
+ code any more? */
}
#endif
return status;
}
-/* Check out a revision from RCSFILE into WORKFILE, or to standard output
- if WORKFILE is NULL. If WORKFILE is "", let RCS pick the working file
- name. TAG is the tag to check out, or NULL if one should check out
- the head of the default branch. OPTIONS is a string such as
- -kb or -kkv, for keyword expansion options, or NULL if there are none.
- If WORKFILE is NULL, run regardless of noexec; if non-NULL, noexec
- inhibits execution. SOUT is what to do with standard output
- (typically RUN_TTY). If FLAGS & RCS_FLAGS_LOCK, lock it. If
- FLAGS & RCS_FLAGS_FORCE, check out even on top of an existing file.
- If NOERR is nonzero, suppress errors. */
-int
-RCS_checkout (rcsfile, workfile, tag, options, sout, flags, noerr)
- char *rcsfile;
- char *workfile;
- char *tag;
- char *options;
- char *sout;
- int flags;
- int noerr;
-{
- run_setup ("%s%s -x,v/ -q %s%s", Rcsbin, RCS_CO,
- tag ? "-r" : "", tag ? tag : "");
- if (options != NULL && options[0] != '\0')
- run_arg (options);
- if (workfile == NULL)
- run_arg ("-p");
- if (flags & RCS_FLAGS_LOCK)
- run_arg ("-l");
- if (flags & RCS_FLAGS_FORCE)
- run_arg ("-f");
- run_arg (rcsfile);
- if (workfile != NULL && workfile[0] != '\0')
- run_arg (workfile);
- return run_exec (RUN_TTY, sout, noerr ? DEVNULL : RUN_TTY,
- workfile == NULL ? (RUN_NORMAL | RUN_REALLY) : RUN_NORMAL);
-}
-
/* Check in to RCSFILE with revision REV (which must be greater than the
largest revision) and message MESSAGE (which is checked for legality).
- If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. If NOERR, do not
- report errors. If FLAGS & RCS_FLAGS_QUIET suppress errors somewhat more
- selectively. If FLAGS & RCS_FLAGS_MODTIME, use the working file's
- modification time for the checkin time. WORKFILE is the working file
- to check in from, or NULL to use the usual RCS rules for deriving it
- from the RCSFILE. */
+ If FLAGS & RCS_FLAGS_DEAD, check in a dead revision. If FLAGS &
+ RCS_FLAGS_QUIET, tell ci to be quiet. If FLAGS & RCS_FLAGS_MODTIME,
+ use the working file's modification time for the checkin time.
+ WORKFILE is the working file to check in from, or NULL to use the usual
+ RCS rules for deriving it from the RCSFILE.
+
+ Return value is -1 for error (and errno is set to indicate the
+ error), positive for error (and an error message has been printed),
+ or zero for success. */
int
-RCS_checkin (rcsfile, workfile, message, rev, flags, noerr)
+RCS_checkin (rcsfile, workfile, message, rev, flags)
char *rcsfile;
char *workfile;
char *message;
char *rev;
int flags;
- int noerr;
{
+ /* The desired behavior regarding permissions is to preserve the
+ permissions on RCSFILE if it already exists. Based on looking
+ at the RCS 5.7 source, it would appear that RCS_CI does this
+ except when it is creating RCSFILE (reasonable), or when
+ RCSFILE was created with rcs -i (this is strange, and quite
+ possibly unintentional). In those two cases it copies the
+ permissions from the workfile.
+
+ Anyway, the fix is simple enough: we preserve the mode ourself. */
+ struct stat sb;
+ int fix_mode = 1;
+ int retval;
+
+ if (CVS_STAT (rcsfile, &sb) < 0)
+ {
+ fix_mode = 0;
+ if (!existence_error (errno))
+ error (0, errno, "warning: cannot stat %s", rcsfile);
+ }
run_setup ("%s%s -x,v/ -f %s%s", Rcsbin, RCS_CI,
rev ? "-r" : "", rev ? rev : "");
if (flags & RCS_FLAGS_DEAD)
@@ -184,5 +211,12 @@ RCS_checkin (rcsfile, workfile, message, rev, flags, noerr)
if (workfile != NULL)
run_arg (workfile);
run_arg (rcsfile);
- return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL);
+ retval = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ if (retval == 0 && fix_mode)
+ {
+ if (chmod (rcsfile, sb.st_mode) < 0)
+ error (0, errno, "warning: cannot change permissions on %s",
+ rcsfile);
+ }
+ return retval;
}