diff options
Diffstat (limited to 'contrib/cvs/src/rcscmds.c')
-rw-r--r-- | contrib/cvs/src/rcscmds.c | 170 |
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; } |