diff options
author | 1997-04-21 04:24:52 +0000 | |
---|---|---|
committer | 1997-04-21 04:24:52 +0000 | |
commit | b6c0222275d7627ee4b3daf0c986f90dee05daa5 (patch) | |
tree | a5ac20eaee1455538e53df69eb0b8cd0a762562f /gnu/usr.bin/cvs/src | |
parent | defined(YP) -> ${YP} == "yes" (diff) | |
download | wireguard-openbsd-b6c0222275d7627ee4b3daf0c986f90dee05daa5.tar.xz wireguard-openbsd-b6c0222275d7627ee4b3daf0c986f90dee05daa5.zip |
Latest release from Cyclic Software
Diffstat (limited to 'gnu/usr.bin/cvs/src')
33 files changed, 2069 insertions, 493 deletions
diff --git a/gnu/usr.bin/cvs/src/ChangeLog b/gnu/usr.bin/cvs/src/ChangeLog index 42a631ef2be..6fe1e91c768 100644 --- a/gnu/usr.bin/cvs/src/ChangeLog +++ b/gnu/usr.bin/cvs/src/ChangeLog @@ -1,5 +1,276 @@ +Fri Apr 18 11:24:26 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * version.c: Version 1.9.8. + + * commit.c (struct find_data): Add field force. + (find_fileproc, commit): Use it instead of force_ci to decide + whether to send files to server. + (commit): Set it if either -f or -r is specified. + * sanity.sh (basica): Add tests basica-8a0, basica-8a1, and + basica-8a2; tests for above fix. + +Wed Apr 16 11:50:59 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * zlib.c: Remove paragraph with Free Software Foundation address. + See 2 Jan 1997 entry in ../ChangeLog for rationale. + +Tue Apr 15 00:36:23 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * update.c (patch_file_write): Always assign to final_nl, so that + it ends up reflecting whether the data from the last call had a + newline, not whether the data from any of the calls ended in a + newline. Doesn't matter with the current RCS_checkout + implementation, but it will if RCS_checkout is changed to pass + less than the entire file. + + * rcs.c (RCS_cmp_file): Change NULL to RUN_TTY in passing sout to + RCS_checkout, for clarity. + + * import.c (update_rcs_file): Remove unused variable ierrno. + + * add.c, checkout.c, commit.c, diff.c, edit.c, import.c, + history.c, log.c, main.c, patch.c, release.c, remove.c, rtag.c, + status.c, tag.c, update.c, watch.c: Pass "+" to all calls to + getopt. This ensures that we maintain existing behavior even with + glibc2. + + * filesubr.c (fopen_case): Don't set *PATHP if we return an + error. Since the 9 Apr 1997 change, the behavior has been to + sometimes set it and sometimes not. + * rcs.c (RCS_parse): Adjust callers to not free it. Without this + change, they could call free() on an uninitialized variable. + + * checkout.c (checkout): Add comment about export -k. + + * root.c (check_root_consistent): Add comment about wording of + message. + +Mon Apr 14 11:51:49 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * client.c (call_in_directory): If rdirp reaches the end of + reposdirname, then just set it to NULL. If server does not create + directories one at a time, give a warning. + * sanity.sh (modules3): Enable tests modules3-8 through + modules3-11 for remote; tests for above fix. + + * client.c (call_in_directory): Don't set short_pathname to + pathname for a while; just use pathname itself (cleans up a relic + of the old "Repository" (not "Directory") code). Add comment + explaining short_pathname. + +Sun Apr 13 18:07:50 1997 Ian Lance Taylor <ian@cygnus.com> + + * rcs.c (RCS_checkout): Add pfn and callerdat parameters. Change + all callers. Move setting of expand after retrieval of file + data. + (struct cmp_file_data): Define. + (RCS_cmp_file): New function. + (cmp_file_buffer): New static function. + * rcs.h (RCSCHECKOUTPROC): Define type. + (RCS_checkout): Update declaration. + (RCS_cmp_file): Define. + * diff.c (diff_file_nodiff): Call RCS_cmp_file rather than + RCS_checkout and xcmp. + * import.c (update_rcs_file): Likewise. + * no_diff.c (No_Difference): Likewise. + * update.c (struct patch_file_data): Define. + (patch_file): Just return if noexec, or if binary file. Pass + patch_file_write to RCS_checkout. Don't check for newlines or + compute checksums here. Stat RCS file to set modes. + (patch_file_write): New static function. + + * update.c (patch_file): Checkout directly to file2, rather than + to finfo->file followed by rename. Remove check for whether + result of checkout is readable; that was for an old, obsolete, + form of death support. + +Sun Apr 13 13:16:40 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * checkout.c (build_one_dir): New function. + (struct dir_to_build): New structure. + (build_dirs_and_chir): Rewritten to accept a linked list of struct + dir_to_build rather than the silly string processing we had been + doing before. + (checkout_proc): Rewrite code that calls build_dirs_and_chdir + accordingly. + * sanity.sh: Enable tests modules3-10 and modules3-11 for local CVS; + tests for above fix. + + * rcs.h (RCS_CO): Removed; no longer used. + +Sun Apr 13 00:04:34 1997 Ian Lance Taylor <ian@cygnus.com> + + Expand RCS keywords internally; never call co: + * rcs.h (struct rcsversnode): Add state field. + * rcs.c (kflags): Move out of RCS_check_kflag, and make file + static. + (enum kflag): Define. + (RCS_reparsercsfile): Always save lock information. Save state in + new state field, rather than other field. + (struct rcs_keyword): Define. + (keywords): New static variable. + (enum keyword): Define. + (printable_date, escape_keyword_value): New static functions. + (expand_keywords): New static function. + (RCS_checkout): Call expand_keywords. Don't call + RCS_exec_checkout. + (RCS_deltas): Add log and loglen parameters. Change all callers. + * log.c (log_version_requested): Use new state field. + (log_version): Likewise. + * cvs.h (RCS_exec_checkout): Don't declare. + * rcscmds.c (RCS_exec_checkout): Remove. + +Sat Apr 12 17:32:59 1997 Ian Lance Taylor <ian@cygnus.com> + + * sanity.sh (modules3): Remove second-dir at end of tests. + (sticky): Correct removal of directories at end of tests. + + * sanity.sh (keyword): New tests for RCS keyword expansion. + +Sat Apr 12 16:47:13 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (basicb): New tests basicb-1b, basicb-1c, basicb-9b, + basic-9c test current build_dirs_and_chdir behavior. + +Fri Apr 11 23:54:56 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (modules3): New tests modules3-7* test for ability to + supply a path in -d in modules. Similar to modules3-8 through + modules3-11 except because the nesting is different, these ones + work. + +Thu Apr 10 00:14:47 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (modules3): New tests modules3-12 through modules3-15 + test use of a module name which contains a slash. + + * sanity.sh (basicb): New tests basicb-14 to basicb-20 test use of + co -d with two or more arguments. + + * rcscmds.c: Refer to doc/RCSFILES in comment. + +Wed Apr 9 09:49:17 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (basicb): New tests basicb-11 through basicb-13 test + ability to specify several directory levels in co -d (commented + out). + + * filesubr.c (fopen_case): If CVS_OPENDIR gives an + existence_error, return it to the caller instead of giving a fatal + error. + + * client.c (update_entries): Fix typo in call to error (1 -> errno). + +Tue Apr 8 23:02:22 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * error.h, error.c: Test for #ifdef __STDC__, not #if __STDC__. + This is consistent with other parts of CVS; it means that the + declaration for fperror will match the definition even if __STDC__ + is defined to 0 as the SunPro 4.0 compiler does. Reported by + Richard Smith <rjsmith@cisco.com>. + +2 Apr 1997 Jim Kingdon + + * entries.c (ParseTag): Add "break;" after "default:" to avoid + error from Visual C++. + +Wed Apr 2 12:06:44 1997 Vince Del Vecchio <vdelvecc@spd.analog.com> + and Jim Kingdon + + * client.c: In reporting errors from socket calls, use + SOCK_STRERROR and SOCK_ERRNO since strerror(errno) doesn't work + for Win32. + +Tue Apr 8 10:45:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (modules3): Add tests modules3-8 to modules3-11, to + test for ability to supply a path to -d in modules. Mostly + commented out as CVS is buggy in this area. + +Mon Apr 7 12:41:44 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * add.c (add): Add comment about SEND_NO_CONTENTS. + +Sun Apr 6 21:46:32 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * update.c (update): Add comment about noexec and SEND_NO_CONTENTS. + +Sun Apr 6 17:34:08 1997 Robert Bihlmeyer <robbe@orcus.priv.at> + + * Pass +f not f to getopt_long to prevent options from being + permuted with glibc 2.0.1. + +Sun Mar 30 00:07:05 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * cvs.h (struct vers_ts): Adjust comment regarding ts_user. + * server.c (serve_is_modified): New function. Set entries to show + that the file is modified but we don't know the contents. + * server.c (requests): Add "Is-modified" request. + * vers_ts.c (time_stamp_server): If the timestamp in entdata is + "M" or "D", just copy that over into ts_user. + * vers_ts.c (Version_TS): If timestamp is "D", use the entries + line for the sole purpose of passing it to time_stamp_server. + * no_diff.c (No_Difference): If ts_user is "M", conclude the files + are different. + * client.h, client.c (send_files): Replace arguments build_dirs + and force with argument flags. Add flag SEND_NO_CONTENTS and add + to struct send_data. + (send_fileproc): If no_contents, then send Is-modified instead of + Modified. + * add.c, admin.c, client.c, commit.c, diff.c, edit.c, log.c, + rcs.c, remove.c, status.c, tag.c, update.c, watch.c: Change all + send_files callers. + +Fri Mar 28 22:32:25 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * server.c (requests): Change "Repository" to rq_optional. I'm + not sure whether I overlooked this when I removed support for + Repository, or whether I was thinking that servers would need to + support it anyway, for CVS 1.5 to 1.9 clients, but making it + optional doesn't prevent the server from supporting it and it + seems silly for the client to complain about absence of a request + that it never will use. + +Fri Mar 28 10:06:59 1997 Steven Miller <Miller@wingra.com> + + * entries.c (Subdirs_Known): Don't create Entries.Log if noexec. + +Thu Mar 27 18:14:12 1997 Ian Lance Taylor <ian@cygnus.com> + + * sanity.sh (death2): Remove commented out test death2-21. It + would now pass, but it duplicates the new test sticky-11. + +Thu Mar 27 10:21:19 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (dotest_internal): Write test output to logfile even + if test succeeds. This was the behavior prior to 30 Sep 1996. + See the comment for rationale. + Tue Mar 25 13:26:52 1997 Jim Kingdon <kingdon@harvey.cyclic.com> + * cvs.h, entries.c (WriteTag): Add arguments nonbranch, + update_dir, and repository. Move the server_set_sticky call from + callers to here. + * cvs.h, create_adm.c (Create_Admin): New argument nonbranch. + * cvs.h, entries.c (ParseTag): Add argument nonbranchp. + * cvs.h (struct stickydirtag): Add field nonbranch. + * entries.c (Entries_Open): Set it. + * cvs.h (Vers_TS): Add field nonbranch. + * vers_ts.c (Version_TS): Copy it from struct stickydirtag. + * server.c, server.h (server_set_sticky): Add argument nonbranch. + * add.c, client.c, checkout.c, modules.c, update.c, create_adm.c, + commit.c: Update callers. + * add.c (add): If nonbranch, don't add the file on that "branch". + * commit.c (write_dirnonbranch): New variable. + (commit_fileproc, commit): Set it. + (commit_dirleaveproc): Pass it to WriteTag. + * update.c (rewrite_tag, nonbranch): New variables. + (update, update_dirent_proc, update_fileproc): Set them. + (update_filesdoneproc): If rewrite_tag, call WriteTag. + * sanity.sh (sticky): New tests, test for above fix. + + * version.c: Change version number to 1.9.7. + * version.c: Version 1.9.6. Mon Mar 24 13:02:04 1997 Jim Kingdon <kingdon@harvey.cyclic.com> diff --git a/gnu/usr.bin/cvs/src/add.c b/gnu/usr.bin/cvs/src/add.c index 28faecc7839..8bba5bb62a1 100644 --- a/gnu/usr.bin/cvs/src/add.c +++ b/gnu/usr.bin/cvs/src/add.c @@ -103,7 +103,7 @@ add (argc, argv) /* parse args */ optind = 1; - while ((c = getopt (argc, argv, "k:m:")) != -1) + while ((c = getopt (argc, argv, "+k:m:")) != -1) { switch (c) { @@ -147,17 +147,18 @@ add (argc, argv) { char *tag; char *date; + int nonbranch; char *rcsdir; /* before we do anything else, see if we have any per-directory tags */ - ParseTag (&tag, &date); + ParseTag (&tag, &date, &nonbranch); rcsdir = combine_dir (repository, argv[i]); strip_trailing_slashes (argv[i]); - Create_Admin (argv[i], argv[i], rcsdir, tag, date); + Create_Admin (argv[i], argv[i], rcsdir, tag, date, nonbranch); if (tag) free (tag); @@ -179,7 +180,8 @@ add (argc, argv) } } send_file_names (argc, argv, SEND_EXPAND_WILD); - send_files (argc, argv, 0, 0, 1, 0); + /* FIXME: should be able to pass SEND_NO_CONTENTS, I think. */ + send_files (argc, argv, 0, 0, SEND_BUILD_DIRS); send_to_server ("add\012", 0); return get_responses_and_close (); } @@ -265,28 +267,39 @@ add (argc, argv) } } - /* There is a user file, so build the entry for it */ - if (build_entry (repository, user, vers->options, - message, entries, vers->tag) != 0) - err++; + if (vers->nonbranch) + { + error (0, 0, + "cannot add file on non-branch tag %s", + vers->tag); + ++err; + } else { - added_files++; - if (!quiet) + /* There is a user file, so build the entry for it */ + if (build_entry (repository, user, vers->options, + message, entries, vers->tag) != 0) + err++; + else { - if (vers->tag) - error (0, 0, "\ + added_files++; + if (!quiet) + { + if (vers->tag) + error (0, 0, "\ scheduling %s `%s' for addition on branch `%s'", - (wrap_name_has (user, WRAP_TOCVS) - ? "wrapper" - : "file"), - user, vers->tag); - else - error (0, 0, "scheduling %s `%s' for addition", - (wrap_name_has (user, WRAP_TOCVS) - ? "wrapper" - : "file"), - user); + (wrap_name_has (user, WRAP_TOCVS) + ? "wrapper" + : "file"), + user, vers->tag); + else + error (0, 0, + "scheduling %s `%s' for addition", + (wrap_name_has (user, WRAP_TOCVS) + ? "wrapper" + : "file"), + user); + } } } } @@ -302,20 +315,31 @@ same name already exists in the repository."); } else { - if (vers->tag) - error (0, 0, "\ -file `%s' will be added on branch `%s' from version %s", - user, vers->tag, vers->vn_rcs); + if (vers->nonbranch) + { + error (0, 0, + "cannot add file on non-branch tag %s", + vers->tag); + ++err; + } else - /* I'm not sure that mentioning vers->vn_rcs makes - any sense here; I can't think of a way to word the - message which is not confusing. */ - error (0, 0, "\ + { + if (vers->tag) + error (0, 0, "\ +file `%s' will be added on branch `%s' from version %s", + user, vers->tag, vers->vn_rcs); + else + /* I'm not sure that mentioning + vers->vn_rcs makes any sense here; I + can't think of a way to word the + message which is not confusing. */ + error (0, 0, "\ re-adding file %s (in place of dead revision %s)", - user, vers->vn_rcs); - Register (entries, user, "0", vers->ts_user, NULL, - vers->tag, NULL, NULL); - ++added_files; + user, vers->vn_rcs); + Register (entries, user, "0", vers->ts_user, NULL, + vers->tag, NULL, NULL); + ++added_files; + } } } else @@ -446,6 +470,7 @@ add_directory (repository, entries, dir) struct saved_cwd cwd; char *message = NULL; char *tag, *date; + int nonbranch; if (strchr (dir, '/') != NULL) { @@ -460,7 +485,7 @@ add_directory (repository, entries, dir) } /* before we do anything else, see if we have any per-directory tags */ - ParseTag (&tag, &date); + ParseTag (&tag, &date, &nonbranch); /* now, remember where we were, so we can get back */ if (save_cwd (&cwd)) @@ -550,9 +575,9 @@ add_directory (repository, entries, dir) #ifdef SERVER_SUPPORT if (!server_active) - Create_Admin (".", dir, rcsdir, tag, date); + Create_Admin (".", dir, rcsdir, tag, date, nonbranch); #else - Create_Admin (".", dir, rcsdir, tag, date); + Create_Admin (".", dir, rcsdir, tag, date, nonbranch); #endif if (tag) free (tag); diff --git a/gnu/usr.bin/cvs/src/admin.c b/gnu/usr.bin/cvs/src/admin.c index 763eb981d29..dd187801dfa 100644 --- a/gnu/usr.bin/cvs/src/admin.c +++ b/gnu/usr.bin/cvs/src/admin.c @@ -93,10 +93,7 @@ admin (argc, argv) send_arg (av[i]); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, 0, 0, 0, 0); + send_files (argc, argv, 0, 0, SEND_NO_CONTENTS); send_to_server ("admin\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/checkin.c b/gnu/usr.bin/cvs/src/checkin.c index c5b5d073f16..3c6a3b2cd98 100644 --- a/gnu/usr.bin/cvs/src/checkin.c +++ b/gnu/usr.bin/cvs/src/checkin.c @@ -93,7 +93,8 @@ Checkin (type, finfo, rcs, rev, tag, options, message) /* FIXME: should be checking for errors. */ (void) RCS_checkout (finfo->rcs, finfo->file, rev, - (char *) NULL, options, RUN_TTY); + (char *) NULL, options, RUN_TTY, + (RCSCHECKOUTPROC) NULL, (void *) NULL); xchmod (finfo->file, 1); if (xcmp (finfo->file, fname) == 0) diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c index 03b0cae7134..2f6b8c673bb 100644 --- a/gnu/usr.bin/cvs/src/client.c +++ b/gnu/usr.bin/cvs/src/client.c @@ -14,7 +14,7 @@ #include "md5.h" -#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP +#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP || defined(SOCK_ERRNO) || defined(SOCK_STRERROR) # ifdef HAVE_WINSOCK_H # include <winsock.h> # else /* No winsock.h */ @@ -22,7 +22,31 @@ # include <netinet/in.h> # include <netdb.h> # endif /* No winsock.h */ -#endif /* defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP */ +#endif /* defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP + || defined(SOCK_ERRNO) || defined(SOCK_STRERROR) */ + +/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls + do not set errno, but that this macro should be used to obtain an + error code. This probably doesn't make sense unless + NO_SOCKET_TO_FD is also defined. */ +#ifndef SOCK_ERRNO +#define SOCK_ERRNO errno +#endif + +/* If SOCK_STRERROR is defined, then the error codes returned by + socket operations are not known to strerror, and this macro must be + used instead to convert those error codes to strings. */ +#ifndef SOCK_STRERROR +# define SOCK_STRERROR strerror + +# if STDC_HEADERS +# include <string.h> +# endif + +# ifndef strerror +extern char *strerror (); +# endif +#endif /* ! SOCK_STRERROR */ #if HAVE_KERBEROS || USE_DIRECT_TCP #define CVS_PORT 1999 @@ -426,7 +450,11 @@ log_buffer_shutdown (closure) via a socket using send() and recv(). This is because under some operating systems (OS/2 and Windows 95 come to mind), a socket cannot be converted to a file descriptor -- it must be treated as a - socket and nothing else. */ + socket and nothing else. + + We may also need to deal with socket routine error codes differently + in these cases. This is handled through the SOCK_ERRNO and + SOCK_STRERROR macros. */ static int use_socket_style = 0; static int server_sock; @@ -435,6 +463,12 @@ static int server_sock; recv. The buffer is always in blocking mode so we don't implement the block routine. */ +/* Note that it is important that these routines always handle errors + internally and never return a positive errno code, since it would in + general be impossible for the caller to know in general whether any + error code came from a socket routine (to decide whether to use + SOCK_STRERROR or simply strerror to print an error message). */ + /* We use an instance of this structure as the closure field. */ struct socket_buffer @@ -496,7 +530,7 @@ socket_buffer_input (closure, data, need, size, got) { nbytes = recv (sb->socket, data, size, 0); if (nbytes < 0) - error (1, errno, "reading from server"); + error (1, 0, "reading from server: %s", SOCK_STRERROR (SOCK_ERRNO)); if (nbytes == 0) { /* End of file (for example, the server has closed @@ -536,7 +570,7 @@ socket_buffer_output (closure, data, have, wrote) is needed for systems where its return value is something other than the number of bytes written. */ if (send (sb->socket, data, have, 0) < 0) - error (1, errno, "writing to server socket"); + error (1, 0, "writing to server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); #else while (have > 0) { @@ -544,7 +578,7 @@ socket_buffer_output (closure, data, have, wrote) nbytes = send (sb->socket, data, have, 0); if (nbytes < 0) - error (1, errno, "writing to server socket"); + error (1, 0, "writing to server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); have -= nbytes; data += nbytes; @@ -768,8 +802,13 @@ call_in_directory (pathname, func, data) { char *dir_name; char *filename; - /* Just the part of pathname relative to toplevel_repos. */ - char *short_pathname = pathname; + /* This is what we get when we hook up the directory (working directory + name) from PATHNAME with the filename from REPOSNAME. For example: + pathname: ccvs/src/ + reposname: /u/src/master/ccvs/foo/ChangeLog + short_pathname: ccvs/src/ChangeLog + */ + char *short_pathname; char *p; /* @@ -820,7 +859,7 @@ call_in_directory (pathname, func, data) else *p = '\0'; - dir_name = xstrdup (short_pathname); + dir_name = xstrdup (pathname); p = strrchr (dir_name, '/'); if (p == NULL) { @@ -892,7 +931,7 @@ call_in_directory (pathname, func, data) strcpy (r, "/."); Create_Admin (".", ".", repo, (char *) NULL, - (char *) NULL); + (char *) NULL, 0); free (repo); } @@ -907,6 +946,12 @@ call_in_directory (pathname, func, data) /* Directory does not exist, we need to create it. */ newdir = 1; + + /* Provided we are willing to assume that directories get + created one at a time, we could simplify this a lot. + Do note that one aspect still would need to walk the + dir_name path: the checking for "fncmp (dir, CVSADM)". */ + dir = xmalloc (strlen (dir_name) + 1); dirp = dir_name; rdirp = reposdirname; @@ -941,8 +986,10 @@ call_in_directory (pathname, func, data) /* Skip the slash. */ ++dirp; if (rdirp == NULL) - error (0, 0, - "internal error: repository string too short."); + /* This just means that the repository string has + fewer components than the dir_name string. But + that is OK (e.g. see modules3-8 in testsuite). */ + ; else rdirp = strchr (rdirp, '/'); } @@ -1007,6 +1054,13 @@ call_in_directory (pathname, func, data) if (rdirp) { + /* See comment near start of function; the only + way that the server can put the right thing + in each CVS/Repository file is to create the + directories one at a time. I think that the + CVS server has been doing this all along. */ + error (0, 0, "\ +warning: server is not creating directories one at a time"); strncpy (r, reposdirname, rdirp - reposdirname); r[rdirp - reposdirname] = '\0'; } @@ -1014,7 +1068,7 @@ call_in_directory (pathname, func, data) strcpy (r, reposdirname); Create_Admin (dir, dir, repo, - (char *)NULL, (char *)NULL); + (char *)NULL, (char *)NULL, 0); free (repo); b = strrchr (dir, '/'); @@ -1588,7 +1642,7 @@ update_entries (data_arg, ent_list, short_pathname, filename) error (1, 0, "patch original file %s does not exist", short_pathname); if ( CVS_STAT (temp_filename, &s) < 0) - error (1, 1, "can't stat patch file %s", temp_filename); + error (1, errno, "can't stat patch file %s", temp_filename); if (s.st_size == 0) retcode = 0; else @@ -2595,7 +2649,7 @@ client_send_expansions (local, where, build_dirs) { argv[0] = where ? where : modules_vector[i]; if (isfile (argv[0])) - send_files (1, argv, local, 0, build_dirs, 0); + send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0); } send_a_repository ("", CVSroot_directory, ""); } @@ -2869,7 +2923,7 @@ get_responses_and_close () if (use_socket_style) { if (shutdown (server_sock, 2) < 0) - error (1, errno, "shutting down server socket"); + error (1, 0, "shutting down server socket: %s", SOCK_STRERROR (SOCK_ERRNO)); } else #endif /* NO_SOCKET_TO_FD */ @@ -2878,8 +2932,8 @@ get_responses_and_close () if (server_fd != -1) { if (shutdown (server_fd, 1) < 0) - error (1, errno, "shutting down connection to %s", - CVSroot_hostname); + error (1, 0, "shutting down connection to %s: %s", + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); /* * This test will always be true because we dup the descriptor */ @@ -3029,8 +3083,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only) init_sockaddr (&client_sai, CVSroot_hostname, port_number); if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)) < 0) - error (1, errno, "connect to %s:%d failed", CVSroot_hostname, - port_number); + error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname, + port_number, SOCK_STRERROR (SOCK_ERRNO)); /* Run the authorization mini-protocol before anything else. */ { @@ -3096,7 +3150,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only) for (i = 0; (i < (LARGEST_RESPONSE - 1)) && (ch != '\n'); i++) { if (recv (sock, &ch, 1, 0) < 0) - error (1, errno, "recv() from server %s", CVSroot_hostname); + error (1, 0, "recv() from server %s: %s", CVSroot_hostname, + SOCK_STRERROR (SOCK_ERRNO)); read_buf[i] = ch; } @@ -3109,8 +3164,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only) error (0, 0, "authorization failed: server %s rejected access", CVSroot_hostname); - error (1, errno, - "shutdown() failed (server %s)", CVSroot_hostname); + error (1, 0, + "shutdown() failed (server %s): %s", CVSroot_hostname, + SOCK_STRERROR (SOCK_ERRNO)); } if (verify_only) @@ -3128,7 +3184,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only) error (0, 0, "unrecognized auth response from %s: %s", CVSroot_hostname, read_buf); - error (1, errno, "shutdown() failed, server %s", CVSroot_hostname); + error (1, 0, + "shutdown() failed, server %s: %s", CVSroot_hostname, + SOCK_STRERROR (SOCK_ERRNO)); } error (1, 0, "unrecognized auth response from %s: %s", @@ -3139,7 +3197,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only) if (verify_only) { if (shutdown (sock, 2) < 0) - error (0, errno, "shutdown() failed, server %s", CVSroot_hostname); + error (0, 0, "shutdown() failed, server %s: %s", CVSroot_hostname, + SOCK_STRERROR (SOCK_ERRNO)); return 1; } else @@ -3170,9 +3229,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only) /* * FIXME: this function has not been changed to deal with * NO_SOCKET_TO_FD (i.e., systems on which sockets cannot be converted - * to file descriptors. The first person to try building a kerberos - * client on such a system (OS/2, Windows 95, and maybe others) will - * have to make take care of this. + * to file descriptors) or with SOCK_ERRNO/SOCK_STRERROR. The first + * person to try building a kerberos client on such a system (OS/2, + * Windows 95, and maybe others) will have to make take care of this. */ void start_tcp_server (tofdp, fromfdp) @@ -4098,7 +4157,7 @@ send_modified (file, short_pathname, vers) * one. */ if (newsize > 0) - send_to_server (buf, newsize); + send_to_server (buf, newsize); } free (buf); free (mode_string); @@ -4110,8 +4169,10 @@ send_modified (file, short_pathname, vers) struct send_data { + /* Each of the following flags are zero for clear or nonzero for set. */ int build_dirs; int force; + int no_contents; }; static int send_fileproc PROTO ((void *callerdat, struct file_info *finfo)); @@ -4143,19 +4204,19 @@ send_fileproc (callerdat, finfo) if (vers->vn_user != NULL) { - char *tmp; - - tmp = xmalloc (strlen (filename) + strlen (vers->vn_user) - + strlen (vers->options) + 200); - sprintf (tmp, "Entry /%s/%s/%s%s/%s/", - filename, vers->vn_user, - vers->ts_conflict == NULL ? "" : "+", - (vers->ts_conflict == NULL ? "" - : (vers->ts_user != NULL && - strcmp (vers->ts_conflict, vers->ts_user) == 0 - ? "=" - : "modified")), - vers->options); + char *tmp; + + tmp = xmalloc (strlen (filename) + strlen (vers->vn_user) + + strlen (vers->options) + 200); + sprintf (tmp, "Entry /%s/%s/%s%s/%s/", + filename, vers->vn_user, + vers->ts_conflict == NULL ? "" : "+", + (vers->ts_conflict == NULL ? "" + : (vers->ts_user != NULL && + strcmp (vers->ts_conflict, vers->ts_user) == 0 + ? "=" + : "modified")), + vers->options); /* The Entries request. */ /* Not sure about whether this deals with -k and stuff right. */ @@ -4187,7 +4248,15 @@ send_fileproc (callerdat, finfo) || args->force || strcmp (vers->ts_user, vers->ts_rcs) != 0) { - send_modified (filename, finfo->fullname, vers); + if (args->no_contents + && supported_request ("Is-modified")) + { + send_to_server ("Is-modified ", 0); + send_to_server (filename, 0); + send_to_server ("\012", 1); + } + else + send_modified (filename, finfo->fullname, vers); } else { @@ -4510,23 +4579,22 @@ send_file_names (argc, argv, flags) } -/* - * Send Repository, Modified and Entry. argc and argv contain only - * the files to operate on (or empty for everything), not options. - * local is nonzero if we should not recurse (-l option). build_dirs - * is nonzero if nonexistent directories should be sent. force is - * nonzero if we should send unmodified files to the server as though - * they were modified. Also sends Argument lines for argc and argv, - * so should be called after options are sent. - */ +/* Send Repository, Modified and Entry. argc and argv contain only + the files to operate on (or empty for everything), not options. + local is nonzero if we should not recurse (-l option). flags & + SEND_BUILD_DIRS is nonzero if nonexistent directories should be + sent. flags & SEND_FORCE is nonzero if we should send unmodified + files to the server as though they were modified. flags & + SEND_NO_CONTENTS means that this command only needs to know + _whether_ a file is modified, not the contents. Also sends Argument + lines for argc and argv, so should be called after options are sent. */ void -send_files (argc, argv, local, aflag, build_dirs, force) +send_files (argc, argv, local, aflag, flags) int argc; char **argv; int local; int aflag; - int build_dirs; - int force; + unsigned int flags; { struct send_data args; int err; @@ -4536,8 +4604,9 @@ send_files (argc, argv, local, aflag, build_dirs, force) * But we don't actually use it, so I don't think it matters what we pass * for aflag here. */ - args.build_dirs = build_dirs; - args.force = force; + args.build_dirs = flags & SEND_BUILD_DIRS; + args.force = flags & SEND_FORCE; + args.no_contents = flags & SEND_NO_CONTENTS; err = start_recursion (send_fileproc, send_filesdoneproc, send_dirent_proc, (DIRLEAVEPROC)NULL, (void *) &args, diff --git a/gnu/usr.bin/cvs/src/client.h b/gnu/usr.bin/cvs/src/client.h index d313c965e6e..6d92da51149 100644 --- a/gnu/usr.bin/cvs/src/client.h +++ b/gnu/usr.bin/cvs/src/client.h @@ -83,7 +83,12 @@ send_file_names PROTO((int argc, char **argv, unsigned int flags)); */ void send_files PROTO((int argc, char **argv, int local, int aflag, - int build_dirs, int force)); + unsigned int flags)); + +/* Flags for send_files. */ +#define SEND_BUILD_DIRS 1 +#define SEND_FORCE 2 +#define SEND_NO_CONTENTS 4 /* Send an argument to the remote server. */ void diff --git a/gnu/usr.bin/cvs/src/create_adm.c b/gnu/usr.bin/cvs/src/create_adm.c index e1f7773d3b8..0ef6e57fc5e 100644 --- a/gnu/usr.bin/cvs/src/create_adm.c +++ b/gnu/usr.bin/cvs/src/create_adm.c @@ -16,12 +16,13 @@ /* update_dir includes dir as its last component. */ void -Create_Admin (dir, update_dir, repository, tag, date) +Create_Admin (dir, update_dir, repository, tag, date, nonbranch) char *dir; char *update_dir; char *repository; char *tag; char *date; + int nonbranch; { FILE *fout; char *cp; @@ -123,12 +124,11 @@ Create_Admin (dir, update_dir, repository, tag, date) } /* Create a new CVS/Tag file */ - WriteTag (dir, tag, date); + WriteTag (dir, tag, date, nonbranch, update_dir, repository); #ifdef SERVER_SUPPORT if (server_active) { - server_set_sticky (update_dir, repository, tag, date); server_template (update_dir, repository); } diff --git a/gnu/usr.bin/cvs/src/diff.c b/gnu/usr.bin/cvs/src/diff.c index 24bc7b60d9c..ba618ec6eb0 100644 --- a/gnu/usr.bin/cvs/src/diff.c +++ b/gnu/usr.bin/cvs/src/diff.c @@ -202,7 +202,7 @@ diff (argc, argv) optind = 1; while ((c = getopt_long (argc, argv, - "abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:", + "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:V:W:k:r:", longopts, &option_index)) != -1) { switch (c) @@ -309,15 +309,12 @@ diff (argc, argv) client_senddate (diff_date2); send_file_names (argc, argv, SEND_EXPAND_WILD); -#if 0 - /* FIXME: We shouldn't have to send current files to diff two - revs, but it doesn't work yet and I haven't debugged it. - So send the files -- it's slower but it works. - gnu@cygnus.com Apr94 */ + /* Send the current files unless diffing two revs from the archive */ if (diff_rev2 == NULL && diff_date2 == NULL) -#endif - send_files (argc, argv, local, 0, 0, 0); + send_files (argc, argv, local, 0, 0); + else + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("diff\012", 0); err = get_responses_and_close (); @@ -576,7 +573,8 @@ diff_fileproc (callerdat, finfo) (*options ? options : vers->options), - tmp); + tmp, (RCSCHECKOUTPROC) NULL, + (void *) NULL); if (retcode == -1) { (void) CVS_UNLINK (tmp); @@ -596,7 +594,8 @@ diff_fileproc (callerdat, finfo) retcode = RCS_checkout (vers->srcfile, (char *) NULL, use_rev1, (char *) NULL, *options ? options : vers->options, - tmp); + tmp, (RCSCHECKOUTPROC) NULL, + (void *) NULL); if (retcode == -1) { (void) CVS_UNLINK (tmp); @@ -739,7 +738,6 @@ diff_file_nodiff (finfo, vers, empty_file) enum diff_file empty_file; { Vers_TS *xvers; - char *tmp; int retcode; /* free up any old use_rev* variables and reset 'em */ @@ -900,29 +898,10 @@ diff_file_nodiff (finfo, vers, empty_file) * with 0 or 1 -r option specified, run a quick diff to see if we * should bother with it at all. */ - tmp = cvs_temp_name (); - retcode = RCS_checkout (vers->srcfile, (char *) NULL, use_rev1, - (char *) NULL, + + retcode = RCS_cmp_file (vers->srcfile, use_rev1, *options ? options : vers->options, - tmp); - switch (retcode) - { - case 0: /* everything ok */ - if (xcmp (finfo->file, tmp) == 0) - { - (void) CVS_UNLINK (tmp); - free (tmp); - return DIFF_SAME; - } - break; - case -1: /* fork failed */ - (void) CVS_UNLINK (tmp); - error (1, errno, "fork failed during checkout of %s", - vers->srcfile->path); - default: - break; - } - (void) CVS_UNLINK (tmp); - free (tmp); - return DIFF_DIFFERENT; + finfo->file); + + return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT; } diff --git a/gnu/usr.bin/cvs/src/edit.c b/gnu/usr.bin/cvs/src/edit.c index 7593da43d20..f884c9d12a1 100644 --- a/gnu/usr.bin/cvs/src/edit.c +++ b/gnu/usr.bin/cvs/src/edit.c @@ -61,7 +61,7 @@ watch_onoff (argc, argv) int err; optind = 1; - while ((c = getopt (argc, argv, "l")) != -1) + while ((c = getopt (argc, argv, "+l")) != -1) { switch (c) { @@ -87,10 +87,7 @@ watch_onoff (argc, argv) if (local) send_arg ("-l"); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, local, 0, 0, 0); + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server (turning_on ? "watch-on\012" : "watch-off\012", 0); return get_responses_and_close (); } @@ -356,7 +353,7 @@ edit (argc, argv) setting_tunedit = 0; setting_tcommit = 0; optind = 1; - while ((c = getopt (argc, argv, "la:")) != -1) + while ((c = getopt (argc, argv, "+la:")) != -1) { switch (c) { @@ -488,7 +485,7 @@ unedit (argc, argv) usage (edit_usage); optind = 1; - while ((c = getopt (argc, argv, "l")) != -1) + while ((c = getopt (argc, argv, "+l")) != -1) { switch (c) { @@ -974,7 +971,7 @@ editors (argc, argv) usage (editors_usage); optind = 1; - while ((c = getopt (argc, argv, "l")) != -1) + while ((c = getopt (argc, argv, "+l")) != -1) { switch (c) { @@ -999,10 +996,7 @@ editors (argc, argv) if (local) send_arg ("-l"); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, local, 0, 0, 0); + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("editors\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/entries.c b/gnu/usr.bin/cvs/src/entries.c index 8fb22d0e5c9..1e9dd58cd1e 100644 --- a/gnu/usr.bin/cvs/src/entries.c +++ b/gnu/usr.bin/cvs/src/entries.c @@ -435,6 +435,7 @@ Entries_Open (aflag) struct stickydirtag *sdtp = NULL; Entnode *ent; char *dirtag, *dirdate; + int dirnonbranch; int do_rewrite = 0; FILE *fpin; int sawdir; @@ -446,7 +447,7 @@ Entries_Open (aflag) * Parse the CVS/Tag file, to get any default tag/date settings. Use * list-private storage to tuck them away for Version_TS(). */ - ParseTag (&dirtag, &dirdate); + ParseTag (&dirtag, &dirdate, &dirnonbranch); if (aflag || dirtag || dirdate) { sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp)); @@ -454,6 +455,7 @@ Entries_Open (aflag) sdtp->aflag = aflag; sdtp->tag = xstrdup (dirtag); sdtp->date = xstrdup (dirdate); + sdtp->nonbranch = dirnonbranch; /* feed it into the list-private area */ entries->list->data = (char *) sdtp; @@ -597,10 +599,13 @@ AddEntryNode (list, entdata) * Write out/Clear the CVS/Tag file. */ void -WriteTag (dir, tag, date) +WriteTag (dir, tag, date, nonbranch, update_dir, repository) char *dir; char *tag; char *date; + int nonbranch; + char *update_dir; + char *repository; { FILE *fout; char *tmp; @@ -621,8 +626,16 @@ WriteTag (dir, tag, date) fout = open_file (tmp, "w+"); if (tag) { - if (fprintf (fout, "T%s\n", tag) < 0) - error (1, errno, "write to %s failed", tmp); + if (nonbranch) + { + if (fprintf (fout, "N%s\n", tag) < 0) + error (1, errno, "write to %s failed", tmp); + } + else + { + if (fprintf (fout, "T%s\n", tag) < 0) + error (1, errno, "write to %s failed", tmp); + } } else { @@ -636,15 +649,20 @@ WriteTag (dir, tag, date) if (unlink_file (tmp) < 0 && ! existence_error (errno)) error (1, errno, "cannot remove %s", tmp); free (tmp); +#ifdef SERVER_SUPPORT + if (server_active) + server_set_sticky (update_dir, repository, tag, date, nonbranch); +#endif } /* * Parse the CVS/Tag file for the current directory. */ void -ParseTag (tagp, datep) +ParseTag (tagp, datep, nonbranchp) char **tagp; char **datep; + int *nonbranchp; { FILE *fp; @@ -667,13 +685,30 @@ ParseTag (tagp, datep) /* Remove any trailing newline. */ if (line[line_length - 1] == '\n') line[--line_length] = '\0'; - if (*line == 'T' && tagp) - *tagp = xstrdup (line + 1); - else if (*line == 'D' && datep) - *datep = xstrdup (line + 1); - /* if not 'T' or 'D' silently ignore it; it may have been - written by a future version of CVS which extends the - syntax. */ + switch (*line) + { + case 'T': + if (tagp != NULL) + *tagp = xstrdup (line + 1); + if (nonbranchp != NULL) + *nonbranchp = 0; + break; + case 'D': + if (datep != NULL) + *datep = xstrdup (line + 1); + break; + case 'N': + if (tagp != NULL) + *tagp = xstrdup (line + 1); + if (nonbranchp != NULL) + *nonbranchp = 1; + break; + default: + /* Silently ignore it; it may have been + written by a future version of CVS which extends the + syntax. */ + break; + } } (void) fclose (fp); free (line); @@ -700,10 +735,13 @@ Subdirs_Known (entries) FILE *fp; sdtp->subdirs = 1; - /* Create Entries.Log so that Entries_Close will do something. */ - fp = open_file (CVSADM_ENTLOG, "a"); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_ENTLOG); + if (!noexec) + { + /* Create Entries.Log so that Entries_Close will do something. */ + fp = open_file (CVSADM_ENTLOG, "a"); + if (fclose (fp) == EOF) + error (1, errno, "cannot close %s", CVSADM_ENTLOG); + } } } diff --git a/gnu/usr.bin/cvs/src/error.c b/gnu/usr.bin/cvs/src/error.c index 0ed7eb24d37..5c7eef500ae 100644 --- a/gnu/usr.bin/cvs/src/error.c +++ b/gnu/usr.bin/cvs/src/error.c @@ -26,7 +26,7 @@ int error_use_protocol; #ifdef HAVE_VPRINTF -#if __STDC__ +#ifdef __STDC__ #include <stdarg.h> #define VA_START(args, lastarg) va_start(args, lastarg) #else /* ! __STDC__ */ @@ -50,7 +50,7 @@ int error_use_protocol; #include <stdlib.h> #include <string.h> #else /* ! STDC_HEADERS */ -#if __STDC__ +#ifdef __STDC__ void exit(int status); #else /* ! __STDC__ */ void exit (); @@ -86,7 +86,7 @@ error_exit PROTO ((void)) no need to print a message. */ /* VARARGS */ void -#if defined (HAVE_VPRINTF) && __STDC__ +#if defined (HAVE_VPRINTF) && defined (__STDC__) error (int status, int errnum, const char *message, ...) #else error (status, errnum, message, va_alist) @@ -213,7 +213,7 @@ error (status, errnum, message, va_alist) Exit with status EXIT_FAILURE if STATUS is nonzero. */ /* VARARGS */ void -#if defined (HAVE_VPRINTF) && ((__STDC__ - 0) > 0) +#if defined (HAVE_VPRINTF) && defined (__STDC__) fperror (FILE *fp, int status, int errnum, char *message, ...) #else fperror (fp, status, errnum, message, va_alist) diff --git a/gnu/usr.bin/cvs/src/error.h b/gnu/usr.bin/cvs/src/error.h index 5d37bb44d75..e0fde4a5bec 100644 --- a/gnu/usr.bin/cvs/src/error.h +++ b/gnu/usr.bin/cvs/src/error.h @@ -37,7 +37,7 @@ # endif #endif -#if __STDC__ +#ifdef __STDC__ void error (int, int, const char *, ...) \ __attribute__ ((__format__ (__printf__, 3, 4))); #else diff --git a/gnu/usr.bin/cvs/src/filesubr.c b/gnu/usr.bin/cvs/src/filesubr.c index f105b454950..70048ae148b 100644 --- a/gnu/usr.bin/cvs/src/filesubr.c +++ b/gnu/usr.bin/cvs/src/filesubr.c @@ -755,9 +755,7 @@ cvs_casecmp (str1, str2) case-insensitivity. Returns errno code or 0 for success. Puts the new file in *FP. NAME and MODE are as for fopen. If PATHP is not NULL, then put a malloc'd string containing the pathname as found - into *PATHP. Note that a malloc'd string is put into *PATHP - even if we return an error. It doesn't mean anything, but it still - must be freed. + into *PATHP. *PATHP is only set if the return value is 0. Might be cleaner to separate the file finding (which just gives *PATHP) from the file opening (which the caller can do). For one @@ -788,7 +786,22 @@ fopen_case (name, mode, fp, pathp) found_name = NULL; dirp = CVS_OPENDIR (dir); if (dirp == NULL) - error (1, errno, "cannot read directory %s", dir); + { + if (existence_error (errno)) + { + /* This can happen if we are looking in the Attic and the Attic + directory does not exist. Return the error to the caller; + they know what to do with it. */ + retval = errno; + goto out; + } + else + { + /* Give a fatal error; that way the error message can be + more specific than if we returned the error to the caller. */ + error (1, errno, "cannot read directory %s", dir); + } + } errno = 0; while ((dp = readdir (dirp)) != NULL) { @@ -829,9 +842,12 @@ fopen_case (name, mode, fp, pathp) if (pathp == NULL) free (dir); + else if (retval != 0) + free (dir); else *pathp = dir; free (found_name); + out: return retval; } #endif /* SERVER_SUPPORT */ diff --git a/gnu/usr.bin/cvs/src/history.c b/gnu/usr.bin/cvs/src/history.c index 1d19418bc8a..bce237f5275 100644 --- a/gnu/usr.bin/cvs/src/history.c +++ b/gnu/usr.bin/cvs/src/history.c @@ -390,7 +390,7 @@ history (argc, argv) backto = xstrdup (""); rec_types = xstrdup (""); optind = 1; - while ((c = getopt (argc, argv, "Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1) + while ((c = getopt (argc, argv, "+Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1) { switch (c) { diff --git a/gnu/usr.bin/cvs/src/import.c b/gnu/usr.bin/cvs/src/import.c index 38cb55b3e65..4e01e65c616 100644 --- a/gnu/usr.bin/cvs/src/import.c +++ b/gnu/usr.bin/cvs/src/import.c @@ -81,7 +81,7 @@ import (argc, argv) vbranch = xstrdup (CVSBRANCH); optind = 1; - while ((c = getopt (argc, argv, "Qqdb:m:I:k:W:")) != -1) + while ((c = getopt (argc, argv, "+Qqdb:m:I:k:W:")) != -1) { switch (c) { @@ -503,7 +503,6 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic) { Vers_TS *vers; int letter; - int ierrno; char *tocvsPath; struct file_info finfo; @@ -520,12 +519,7 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic) if (vers->vn_rcs != NULL && !RCS_isdead(vers->srcfile, vers->vn_rcs)) { - char *xtmpfile; int different; - int retcode = 0; - - xtmpfile = xmalloc (strlen (Tmpdir) + 40); - (void) sprintf (xtmpfile, "%s/cvs-imp%ld", Tmpdir, (long) getpid()); /* * The rcs file does have a revision on the vendor branch. Compare @@ -536,36 +530,14 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic) * This is to try to cut down the number of "C" conflict messages for * locally modified import source files. */ - retcode = RCS_checkout (vers->srcfile, (char *) NULL, vers->vn_rcs, - (char *) NULL, -#ifdef HAVE_RCS5 - "-ko", -#else - NULL, -#endif - xtmpfile); - if (retcode != 0) - { - ierrno = errno; - fperror (logfp, 0, retcode == -1 ? ierrno : 0, - "ERROR: cannot co revision %s of file %s", vers->vn_rcs, - vers->srcfile->path); - error (0, retcode == -1 ? ierrno : 0, - "ERROR: cannot co revision %s of file %s", vers->vn_rcs, - vers->srcfile->path); - (void) unlink_file (xtmpfile); - free (xtmpfile); - return (1); - } - tocvsPath = wrap_tocvs_process_file (vfile); - different = xcmp (xtmpfile, vfile); + /* FIXME: Why don't we pass tocvsPath to RCS_cmp_file if it is + not NULL? */ + different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, "-ko", vfile); if (tocvsPath) if (unlink_file_dir (tocvsPath) < 0) error (0, errno, "cannot remove %s", tocvsPath); - (void) unlink_file (xtmpfile); - free (xtmpfile); if (!different) { int retval = 0; diff --git a/gnu/usr.bin/cvs/src/log.c b/gnu/usr.bin/cvs/src/log.c index 8c6634ba66c..8fb6910a2f7 100644 --- a/gnu/usr.bin/cvs/src/log.c +++ b/gnu/usr.bin/cvs/src/log.c @@ -168,7 +168,7 @@ cvslog (argc, argv) memset (&log_data, 0, sizeof log_data); optind = 1; - while ((c = getopt (argc, argv, "bd:hlNRr::s:tw::")) != -1) + while ((c = getopt (argc, argv, "+bd:hlNRr::s:tw::")) != -1) { switch (c) { @@ -233,10 +233,7 @@ cvslog (argc, argv) send_arg (argv[i]); send_file_names (argc - i, argv + i, SEND_EXPAND_WILD); -/* FIXME: We shouldn't have to send current files to get log entries, but it - doesn't work yet and I haven't debugged it. So send the files -- - it's slower but it works. gnu@cygnus.com Apr94 */ - send_files (argc - i, argv + i, local, 0, 0, 0); + send_files (argc - i, argv + i, local, 0, SEND_NO_CONTENTS); send_to_server ("log\012", 0); err = get_responses_and_close (); @@ -1000,16 +997,10 @@ log_version_requested (log_data, revlist, rcs, vnode) RCSVers *vnode; { /* Handle the list of states from the -s option. */ - if (log_data->statelist != NULL) + if (log_data->statelist != NULL + && findnode (log_data->statelist, vnode->state) == NULL) { - Node *p; - - p = findnode (vnode->other, "state"); - if (p != NULL - && findnode (log_data->statelist, p->data) == NULL) - { - return 0; - } + return 0; } /* Handle the list of authors from the -w option. */ @@ -1306,8 +1297,7 @@ log_version (log_data, revlist, rcs, ver, trunk) cvs_output (ver->author, 0); cvs_output ("; state: ", 0); - p = findnode (ver->other, "state"); - cvs_output (p->data, 0); + cvs_output (ver->state, 0); cvs_output (";", 1); if (! trunk) diff --git a/gnu/usr.bin/cvs/src/mkmodules.c b/gnu/usr.bin/cvs/src/mkmodules.c index add69b8c5a8..a5be35808ee 100644 --- a/gnu/usr.bin/cvs/src/mkmodules.c +++ b/gnu/usr.bin/cvs/src/mkmodules.c @@ -512,7 +512,8 @@ checkout_file (file, temp) return (1); } rcsnode = RCS_parsercsfile (rcs); - retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp); + retcode = RCS_checkout (rcsnode, NULL, NULL, NULL, NULL, temp, + (RCSCHECKOUTPROC) NULL, (void *) NULL); if (retcode != 0) { error (0, retcode == -1 ? errno : 0, "failed to check out %s file", diff --git a/gnu/usr.bin/cvs/src/modules.c b/gnu/usr.bin/cvs/src/modules.c index 8ec1b7a38f5..814f0cdeb29 100644 --- a/gnu/usr.bin/cvs/src/modules.c +++ b/gnu/usr.bin/cvs/src/modules.c @@ -401,7 +401,7 @@ do_module (db, mname, m_type, msg, callback_proc, where, error (1, 0, "there is no repository %s", nullrepos); Create_Admin (".", dir, - nullrepos, (char *) NULL, (char *) NULL); + nullrepos, (char *) NULL, (char *) NULL, 0); if (!noexec) { FILE *fp; diff --git a/gnu/usr.bin/cvs/src/no_diff.c b/gnu/usr.bin/cvs/src/no_diff.c index 31ef057417f..384800fda6b 100644 --- a/gnu/usr.bin/cvs/src/no_diff.c +++ b/gnu/usr.bin/cvs/src/no_diff.c @@ -22,12 +22,17 @@ No_Difference (finfo, vers) Vers_TS *vers; { Node *p; - char *tmp; int ret; char *ts, *options; int retcode = 0; char *tocvsPath; + /* If ts_user is "Is-modified", we can only conclude the files are + different (since we don't have the file's contents). */ + if (vers->ts_user != NULL + && strcmp (vers->ts_user, "Is-modified") == 0) + return -1; + if (!vers->srcfile || !vers->srcfile->path) return (-1); /* different since we couldn't tell */ @@ -36,88 +41,51 @@ No_Difference (finfo, vers) else options = xstrdup (""); - tmp = cvs_temp_name (); - retcode = RCS_checkout (vers->srcfile, (char *) NULL, vers->vn_user, - (char *) NULL, options, tmp); + tocvsPath = wrap_tocvs_process_file (finfo->file); + retcode = RCS_cmp_file (vers->srcfile, vers->vn_user, options, + tocvsPath == NULL ? finfo->file : tocvsPath); if (retcode == 0) { -#if 0 - /* Why would we want to munge the modes? And only if the timestamps - are different? And even for commands like "cvs status"???? */ - if (!iswritable (finfo->file)) /* fix the modes as a side effect */ - xchmod (finfo->file, 1); -#endif - - tocvsPath = wrap_tocvs_process_file (finfo->file); - - /* do the byte by byte compare */ - if (xcmp (tocvsPath == NULL ? finfo->file : tocvsPath, tmp) == 0) - { -#if 0 - /* Why would we want to munge the modes? And only if the - timestamps are different? And even for commands like - "cvs status"???? */ - if (cvswrite == FALSE) /* fix the modes as a side effect */ - xchmod (finfo->file, 0); -#endif - - /* no difference was found, so fix the entries file */ - ts = time_stamp (finfo->file); - Register (finfo->entries, finfo->file, - vers->vn_user ? vers->vn_user : vers->vn_rcs, ts, - options, vers->tag, vers->date, (char *) 0); + /* no difference was found, so fix the entries file */ + ts = time_stamp (finfo->file); + Register (finfo->entries, finfo->file, + vers->vn_user ? vers->vn_user : vers->vn_rcs, ts, + options, vers->tag, vers->date, (char *) 0); #ifdef SERVER_SUPPORT - if (server_active) - { - /* We need to update the entries line on the client side. */ - server_update_entries - (finfo->file, finfo->update_dir, finfo->repository, SERVER_UPDATED); - } + if (server_active) + { + /* We need to update the entries line on the client side. */ + server_update_entries + (finfo->file, finfo->update_dir, finfo->repository, SERVER_UPDATED); + } #endif - free (ts); + free (ts); - /* update the entdata pointer in the vers_ts structure */ - p = findnode (finfo->entries, finfo->file); - vers->entdata = (Entnode *) p->data; + /* update the entdata pointer in the vers_ts structure */ + p = findnode (finfo->entries, finfo->file); + vers->entdata = (Entnode *) p->data; - ret = 0; - } - else - ret = 1; /* files were really different */ - if (tocvsPath) - { - /* Need to call unlink myself because the noexec variable - * has been set to 1. */ - if (trace) - (void) fprintf (stderr, "%c-> unlink (%s)\n", -#ifdef SERVER_SUPPORT - (server_active) ? 'S' : ' ', -#else - ' ', -#endif - tocvsPath); - if ( CVS_UNLINK (tocvsPath) < 0) - error (0, errno, "could not remove %s", tocvsPath); - } + ret = 0; } else - { - error (0, retcode == -1 ? errno : 0, - "could not check out revision %s of %s", - vers->vn_user, finfo->fullname); - ret = -1; /* different since we couldn't tell */ - } + ret = 1; /* files were really different */ - if (trace) + if (tocvsPath) + { + /* Need to call unlink myself because the noexec variable + * has been set to 1. */ + if (trace) + (void) fprintf (stderr, "%c-> unlink (%s)\n", #ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> unlink2 (%s)\n", - (server_active) ? 'S' : ' ', tmp); + (server_active) ? 'S' : ' ', #else - (void) fprintf (stderr, "-> unlink (%s)\n", tmp); + ' ', #endif - if (CVS_UNLINK (tmp) < 0) - error (0, errno, "could not remove %s", tmp); - free (tmp); + tocvsPath); + if ( CVS_UNLINK (tocvsPath) < 0) + error (0, errno, "could not remove %s", tocvsPath); + } + free (options); return (ret); } diff --git a/gnu/usr.bin/cvs/src/rcs.c b/gnu/usr.bin/cvs/src/rcs.c index 01ac779d0b2..1d0d38a4b89 100644 --- a/gnu/usr.bin/cvs/src/rcs.c +++ b/gnu/usr.bin/cvs/src/rcs.c @@ -11,6 +11,13 @@ #include <assert.h> #include "cvs.h" +/* The RCS -k options, and a set of enums that must match the array. + These come first so that we can use enum kflag in function + prototypes. */ +static const char *const kflags[] = + {"kv", "kvl", "k", "v", "o", "b", (char *) NULL}; +enum kflag { KFLAG_KV = 0, KFLAG_KVL, KFLAG_K, KFLAG_V, KFLAG_O, KFLAG_B }; + static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile)); static void RCS_reparsercsfile PROTO((RCSNode *, int, FILE **)); static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch)); @@ -23,10 +30,16 @@ static void do_symbols PROTO((List * list, char *val)); static void free_rcsnode_contents PROTO((RCSNode *)); static void rcsvers_delproc PROTO((Node * p)); static char *translate_symtag PROTO((RCSNode *, const char *)); +static char *printable_date PROTO((const char *)); +static char *escape_keyword_value PROTO ((const char *, int *)); +static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *, + const char *, size_t, enum kflag, char *, + size_t, char **, size_t *)); +static void cmp_file_buffer PROTO((void *, const char *, size_t)); enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH}; static void RCS_deltas PROTO ((RCSNode *, FILE *, char *, enum rcs_delta_op, - char **, size_t *)); + char **, size_t *, char **, size_t *)); /* * We don't want to use isspace() from the C library because: @@ -141,11 +154,9 @@ RCS_parse (file, repos) else if (! existence_error (status)) { error (0, status, "cannot open %s", rcsfile); - free (found_path); retval = NULL; goto out; } - free (found_path); (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT); status = fopen_case (rcsfile, "rb", &fp, &found_path); @@ -167,11 +178,9 @@ RCS_parse (file, repos) else if (! existence_error (status)) { error (0, status, "cannot open %s", rcsfile); - free (found_path); retval = NULL; goto out; } - free (found_path); } #endif retval = NULL; @@ -356,7 +365,11 @@ RCS_reparsercsfile (rdata, all, pfp) if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) break; - if (all) + /* We always save lock information, so that we can handle + -kkvl correctly when checking out a file. We don't use a + special field for this information, since it will normally + not be set for a CVS file. */ + if (all || strcmp (key, "locks") == 0) { Node *kv; @@ -385,7 +398,6 @@ RCS_reparsercsfile (rdata, all, pfp) for (;;) { char *valp; - Node *kvstate; vnode = (RCSVers *) xmalloc (sizeof (RCSVers)); memset (vnode, 0, sizeof (RCSVers)); @@ -414,30 +426,11 @@ unable to parse rcs file; `author' not in the expected place"); if (key == NULL || strcmp (key, "state") != 0) error (1, 0, "\ unable to parse rcs file; `state' not in the expected place"); + vnode->state = xstrdup (value); if (strcmp (value, "dead") == 0) { vnode->dead = 1; } - if (! all) - kvstate = NULL; - else - { - if (vnode->other == NULL) - vnode->other = getlist (); - kvstate = getnode (); - kvstate->type = RCSFIELD; - kvstate->key = xstrdup (key); - kvstate->data = xstrdup (value); - if (addnode (vnode->other, kvstate) != 0) - { - error (0, 0, - "\ -warning: duplicate key `%s' in version `%s' of RCS file `%s'", - key, vnode->version, rcsfile); - freenode (kvstate); - kvstate = NULL; - } - } /* fill in the branch list (if any branches exist) */ (void) getrcskey (fp, &key, &value, NULL); @@ -480,11 +473,9 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'", if (strcmp(key, RCSDEAD) == 0) { vnode->dead = 1; - if (kvstate != NULL) - { - free (kvstate->data); - kvstate->data = xstrdup ("dead"); - } + if (vnode->state != NULL) + free (vnode->state); + vnode->state = xstrdup ("dead"); continue; } /* if we have a revision, break and do it */ @@ -2056,8 +2047,6 @@ char * RCS_check_kflag (arg) const char *arg; { - static const char *const kflags[] = - {"kv", "kvl", "k", "v", "o", "b", (char *) NULL}; static const char *const keyword_usage[] = { "%s %s: invalid RCS keyword expansion mode\n", @@ -2166,36 +2155,648 @@ RCS_getexpand (rcs) return rcs->expand; } -/* Check out a revision from RCS. This function optimizes by reading - the head version directly if it is easy. Check out the revision - into WORKFILE, or to standard output if WORKFILE is NULL. REV is - the numeric revision to check out; it may be NULL, which means to - check out the head of the default branch. If NAMETAG is not NULL, - it is the tag that should be used when expanding the RCS Name - keyword. 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). */ +/* RCS keywords, and a matching enum. */ +struct rcs_keyword +{ + const char *string; + size_t len; +}; +#define KEYWORD_INIT(s) (s), sizeof (s) - 1 +static const struct rcs_keyword keywords[] = +{ + { KEYWORD_INIT ("Author") }, + { KEYWORD_INIT ("Date") }, + { KEYWORD_INIT ("Header") }, + { KEYWORD_INIT ("Id") }, + { KEYWORD_INIT ("Locker") }, + { KEYWORD_INIT ("Log") }, + { KEYWORD_INIT ("Name") }, + { KEYWORD_INIT ("RCSfile") }, + { KEYWORD_INIT ("Revision") }, + { KEYWORD_INIT ("Source") }, + { KEYWORD_INIT ("State") }, + { NULL, 0 } +}; +enum keyword +{ + KEYWORD_AUTHOR = 0, + KEYWORD_DATE, + KEYWORD_HEADER, + KEYWORD_ID, + KEYWORD_LOCKER, + KEYWORD_LOG, + KEYWORD_NAME, + KEYWORD_RCSFILE, + KEYWORD_REVISION, + KEYWORD_SOURCE, + KEYWORD_STATE +}; + +/* Convert an RCS date string into a readable string. This is like + the RCS date2str function. */ + +static char * +printable_date (rcs_date) + const char *rcs_date; +{ + int year, mon, mday, hour, min, sec; + char buf[100]; + + (void) sscanf (rcs_date, SDATEFORM, &year, &mon, &mday, &hour, &min, + &sec); + if (year < 1900) + year += 1900; + sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday, + hour, min, sec); + return xstrdup (buf); +} + +/* Escape the characters in a string so that it can be included in an + RCS value. */ + +static char * +escape_keyword_value (value, free_value) + const char *value; + int *free_value; +{ + char *ret, *t; + const char *s; + + for (s = value; *s != '\0'; s++) + { + char c; + + c = *s; + if (c == '\t' + || c == '\n' + || c == '\\' + || c == ' ' + || c == '$') + { + break; + } + } + + if (*s == '\0') + { + *free_value = 0; + return (char *) value; + } + + ret = xmalloc (strlen (value) * 4 + 1); + *free_value = 1; + + for (s = value, t = ret; *s != '\0'; s++, t++) + { + switch (*s) + { + default: + *t = *s; + break; + case '\t': + *t++ = '\\'; + *t = 't'; + break; + case '\n': + *t++ = '\\'; + *t = 'n'; + break; + case '\\': + *t++ = '\\'; + *t = '\\'; + break; + case ' ': + *t++ = '\\'; + *t++ = '0'; + *t++ = '4'; + *t = '0'; + break; + case '$': + *t++ = '\\'; + *t++ = '0'; + *t++ = '4'; + *t = '4'; + break; + } + } + + *t = '\0'; + + return ret; +} + +/* Expand RCS keywords in the memory buffer BUF of length LEN. This + applies to file RCS and version VERS. If NAME is not NULL, and is + not a numeric revision, then it is the symbolic tag used for the + checkout. EXPAND indicates how to expand the keywords. This + function sets *RETBUF and *RETLEN to the new buffer and length. + This function may modify the buffer BUF. If BUF != *RETBUF, then + RETBUF is a newly allocated buffer. */ + +static void +expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) + RCSNode *rcs; + RCSVers *ver; + const char *name; + const char *log; + size_t loglen; + enum kflag expand; + char *buf; + size_t len; + char **retbuf; + size_t *retlen; +{ + struct expand_buffer + { + struct expand_buffer *next; + char *data; + size_t len; + int free_data; + } *ebufs = NULL; + struct expand_buffer *ebuf_last = NULL; + size_t ebuf_len = 0; + char *locker; + char *srch, *srch_next; + size_t srch_len; + + if (expand == KFLAG_O || expand == KFLAG_B) + { + *retbuf = buf; + *retlen = len; + return; + } + + /* If we are using -kkvl, dig out the locker information if any. */ + locker = NULL; + if (expand == KFLAG_KVL && rcs->other != NULL) + { + Node *p; + + p = findnode (rcs->other, "locks"); + if (p != NULL) + { + char *cp; + size_t verlen; + + /* The format of the locking information is + USER:VERSION USER:VERSION ... + If we find our version on the list, we set LOCKER to + the corresponding user name. */ + + verlen = strlen (ver->version); + cp = p->data; + while ((cp = strstr (cp, ver->version)) != NULL) + { + if (cp > p->data + && cp[-1] == ':' + && (cp[verlen] == '\0' + || whitespace (cp[verlen]))) + { + char *cpend; + + --cp; + cpend = cp; + while (cp > p->data && ! whitespace (*cp)) + --cp; + locker = xmalloc (cpend - cp + 1); + memcpy (locker, cp, cpend - cp); + locker[cpend - cp] = '\0'; + break; + } + + ++cp; + } + } + } + + /* RCS keywords look like $STRING$ or $STRING: VALUE$. */ + srch = buf; + srch_len = len; + while ((srch_next = memchr (srch, '$', srch_len)) != NULL) + { + char *s, *send; + size_t slen; + const struct rcs_keyword *keyword; + enum keyword kw; + char *value; + int free_value; + char *sub; + size_t sublen; + + srch_len -= (srch_next + 1) - srch; + srch = srch_next + 1; + + /* Look for the first non alphabetic character after the '$'. */ + send = srch + srch_len; + for (s = srch; s < send; s++) + if (! isalpha (*s)) + break; + + /* If the first non alphabetic character is not '$' or ':', + then this is not an RCS keyword. */ + if (s == send || (*s != '$' && *s != ':')) + continue; + + /* See if this is one of the keywords. */ + slen = s - srch; + for (keyword = keywords; keyword->string != NULL; keyword++) + { + if (keyword->len == slen + && strncmp (keyword->string, srch, slen) == 0) + { + break; + } + } + if (keyword->string == NULL) + continue; + + kw = (enum keyword) (keyword - keywords); + + /* If the keyword ends with a ':', then the old value consists + of the characters up to the next '$'. If there is no '$' + before the end of the line, though, then this wasn't an RCS + keyword after all. */ + if (*s == ':') + { + for (; s < send; s++) + if (*s == '$' || *s == '\n') + break; + if (s == send || *s != '$') + continue; + } + + /* At this point we must replace the string from SRCH to S + with the expansion of the keyword KW. */ + + /* Get the value to use. */ + free_value = 0; + if (expand == KFLAG_K) + value = NULL; + else + { + switch (kw) + { + default: + abort (); + + case KEYWORD_AUTHOR: + value = ver->author; + break; + + case KEYWORD_DATE: + value = printable_date (ver->date); + free_value = 1; + break; + + case KEYWORD_HEADER: + case KEYWORD_ID: + { + char *path; + int free_path; + char *date; + + if (kw == KEYWORD_HEADER) + path = rcs->path; + else + path = last_component (rcs->path); + path = escape_keyword_value (path, &free_path); + date = printable_date (ver->date); + value = xmalloc (strlen (path) + + strlen (ver->version) + + strlen (date) + + strlen (ver->author) + + strlen (ver->state) + + (locker == NULL ? 0 : strlen (locker)) + + 20); + + sprintf (value, "%s %s %s %s %s%s%s", + path, ver->version, date, ver->author, + ver->state, + locker != NULL ? " " : "", + locker != NULL ? locker : ""); + if (free_path) + free (path); + free (date); + free_value = 1; + } + break; + + case KEYWORD_LOCKER: + value = locker; + break; + + case KEYWORD_LOG: + case KEYWORD_RCSFILE: + value = escape_keyword_value (last_component (rcs->path), + &free_value); + break; + + case KEYWORD_NAME: + if (name != NULL && ! isdigit (*name)) + value = (char *) name; + else + value = NULL; + break; + + case KEYWORD_REVISION: + value = ver->version; + break; + + case KEYWORD_SOURCE: + value = escape_keyword_value (rcs->path, &free_value); + break; + + case KEYWORD_STATE: + value = ver->state; + break; + } + } + + sub = xmalloc (keyword->len + + (value == NULL ? 0 : strlen (value)) + + 10); + if (expand == KFLAG_V) + { + /* Decrement SRCH and increment S to remove the $ + characters. */ + --srch; + ++srch_len; + ++s; + sublen = 0; + } + else + { + strcpy (sub, keyword->string); + sublen = strlen (keyword->string); + if (expand != KFLAG_K) + { + sub[sublen] = ':'; + sub[sublen + 1] = ' '; + sublen += 2; + } + } + if (value != NULL) + { + strcpy (sub + sublen, value); + sublen += strlen (value); + } + if (expand != KFLAG_V && expand != KFLAG_K) + { + sub[sublen] = ' '; + ++sublen; + sub[sublen] = '\0'; + } + + if (free_value) + free (value); + + /* The Log keyword requires special handling. This behaviour + is taken from RCS 5.7. The special log message is what RCS + uses for ci -k. */ + if (kw == KEYWORD_LOG + && (sizeof "checked in with -k by " <= loglen + || strncmp (log, "checked in with -k by ", + sizeof "checked in with -k by " - 1) != 0)) + { + char *start; + char *leader; + size_t leader_len, leader_sp_len; + const char *logend; + const char *snl; + int cnl; + char *date; + const char *sl; + + /* We are going to insert the trailing $ ourselves, before + the log message, so we must remove it from S, if we + haven't done so already. */ + if (expand != KFLAG_V) + ++s; + + /* Find the start of the line. */ + start = srch; + while (start > buf && start[-1] != '\n') + --start; + + /* Copy the start of the line to use as a comment leader. */ + leader_len = srch - start; + if (expand != KFLAG_V) + --leader_len; + leader = xmalloc (leader_len); + memcpy (leader, start, leader_len); + leader_sp_len = leader_len; + while (leader_sp_len > 0 && leader[leader_sp_len - 1] == ' ') + --leader_sp_len; + + /* RCS does some checking for an old style of Log here, + but we don't bother. RCS issues a warning if it + changes anything. */ + + /* Count the number of newlines in the log message so that + we know how many copies of the leader we will need. */ + cnl = 0; + logend = log + loglen; + for (snl = log; snl < logend; snl++) + if (*snl == '\n') + ++cnl; + + date = printable_date (ver->date); + sub = xrealloc (sub, + (sublen + + sizeof "Revision" + + strlen (ver->version) + + strlen (date) + + strlen (ver->author) + + loglen + + (cnl + 2) * leader_len + + 20)); + if (expand != KFLAG_V) + { + sub[sublen] = '$'; + ++sublen; + } + sub[sublen] = '\n'; + ++sublen; + memcpy (sub + sublen, leader, leader_len); + sublen += leader_len; + sprintf (sub + sublen, "Revision %s %s %s\n", + ver->version, date, ver->author); + sublen += strlen (sub + sublen); + free (date); + + sl = log; + while (sl < logend) + { + if (*sl == '\n') + { + memcpy (sub + sublen, leader, leader_sp_len); + sublen += leader_sp_len; + sub[sublen] = '\n'; + ++sublen; + ++sl; + } + else + { + const char *slnl; + + memcpy (sub + sublen, leader, leader_len); + sublen += leader_len; + for (slnl = sl; slnl < logend && *slnl != '\n'; ++slnl) + ; + if (slnl < logend) + ++slnl; + memcpy (sub + sublen, sl, slnl - sl); + sublen += slnl - sl; + sl = slnl; + } + } + + memcpy (sub + sublen, leader, leader_sp_len); + sublen += leader_sp_len; + + free (leader); + } + + /* Now SUB contains a string which is to replace the string + from SRCH to S. SUBLEN is the length of SUB. */ + + if (sublen == s - srch) + { + memcpy (srch, sub, sublen); + free (sub); + } + else + { + struct expand_buffer *ebuf; + + /* We need to change the size of the buffer. We build a + list of expand_buffer structures. Each expand_buffer + structure represents a portion of the final output. We + concatenate them back into a single buffer when we are + done. This minimizes the number of potentially large + buffer copies we must do. */ + + if (ebufs == NULL) + { + ebufs = (struct expand_buffer *) xmalloc (sizeof *ebuf); + ebufs->next = NULL; + ebufs->data = buf; + ebufs->free_data = 0; + ebuf_len = srch - buf; + ebufs->len = ebuf_len; + ebuf_last = ebufs; + } + else + { + assert (srch >= ebuf_last->data); + assert (srch - ebuf_last->data <= ebuf_last->len); + ebuf_len -= ebuf_last->len - (srch - ebuf_last->data); + ebuf_last->len = srch - ebuf_last->data; + } + + ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); + ebuf->data = sub; + ebuf->len = sublen; + ebuf->free_data = 1; + ebuf->next = NULL; + ebuf_last->next = ebuf; + ebuf_last = ebuf; + ebuf_len += sublen; + + ebuf = (struct expand_buffer *) xmalloc (sizeof *ebuf); + ebuf->data = s; + ebuf->len = srch_len - (s - srch); + ebuf->free_data = 0; + ebuf->next = NULL; + ebuf_last->next = ebuf; + ebuf_last = ebuf; + ebuf_len += srch_len - (s - srch); + } + + srch_len -= (s - srch); + srch = s; + } + + if (locker != NULL) + free (locker); + + if (ebufs == NULL) + { + *retbuf = buf; + *retlen = len; + } + else + { + char *ret; + + ret = xmalloc (ebuf_len); + *retbuf = ret; + *retlen = ebuf_len; + while (ebufs != NULL) + { + struct expand_buffer *next; + + memcpy (ret, ebufs->data, ebufs->len); + ret += ebufs->len; + if (ebufs->free_data) + free (ebufs->data); + next = ebufs->next; + free (ebufs); + ebufs = next; + } + } +} + +/* Check out a revision from an RCS file. + + If PFN is not NULL, then ignore WORKFILE and SOUT. Call PFN zero + or more times with the contents of the file. CALLERDAT is passed, + uninterpreted, to PFN. (The current code will always call PFN + exactly once for a non empty file; however, the current code + assumes that it can hold the entire file contents in memory, which + is not a good assumption, and might change in the future). + + Otherwise, if WORKFILE is not NULL, check out the revision to + WORKFILE. However, if WORKFILE is not NULL, and noexec is set, + then don't do anything. + + Otherwise, if WORKFILE is NULL, check out the revision to SOUT. If + SOUT is RUN_TTY, then write the contents of the revision to + standard output. When using SOUT, the output is generally a + temporary file; don't bother to get the file modes correct. + + REV is the numeric revision to check out. It may be NULL, which + means to check out the head of the default branch. + + If NAMETAG is not NULL, and is not a numeric revision, then it is + the tag that should be used when expanding the RCS Name keyword. + + OPTIONS is a string such as "-kb" or "-kv" for keyword expansion + options. It may be NULL to use the default expansion mode of the + file, typically "-kkv". */ int -RCS_checkout (rcs, workfile, rev, nametag, options, sout) +RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) RCSNode *rcs; char *workfile; char *rev; char *nametag; char *options; char *sout; + RCSCHECKOUTPROC pfn; + void *callerdat; { int free_rev = 0; + enum kflag expand; FILE *fp; struct stat sb; char *key; char *value; size_t len; int free_value = 0; - char *ouroptions; - int keywords; - int ret; + char *log = NULL; + size_t loglen; + FILE *ofp; if (trace) { @@ -2208,9 +2809,10 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout) rcs->path, rev != NULL ? rev : "", options != NULL ? options : "", - (workfile != NULL - ? workfile - : (sout != RUN_TTY ? sout : "(stdout)"))); + (pfn != NULL ? "(function)" + : (workfile != NULL + ? workfile + : (sout != RUN_TTY ? sout : "(stdout)")))); } assert (rev == NULL || isdigit (*rev)); @@ -2219,6 +2821,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout) return 0; assert (sout == RUN_TTY || workfile == NULL); + assert (pfn == NULL || (sout == RUN_TTY && workfile == NULL)); /* Some callers, such as Checkin or remove_file, will pass us a branch. */ @@ -2257,6 +2860,12 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout) getrcsrev (fp, &key); while (getrcskey (fp, &key, &value, &len) >= 0) { + if (strcmp (key, "log") == 0) + { + log = xmalloc (len); + memcpy (log, value, len); + loglen = len; + } if (strcmp (key, "text") == 0) { gothead = 1; @@ -2300,85 +2909,94 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout) error (1, errno, "cannot fstat %s", rcs->path); } - RCS_deltas (rcs, fp, rev, RCS_FETCH, &value, &len); + RCS_deltas (rcs, fp, rev, RCS_FETCH, &value, &len, &log, &loglen); free_value = 1; } /* If OPTIONS is NULL or the empty string, then the old code would invoke the RCS co program with no -k option, which means that co would use the string we have stored in rcs->expand. */ - if (options != NULL && options[0] != '\0') - { - assert (options[0] == '-' && options[1] == 'k'); - ouroptions = options + 2; - } - else if (rcs->expand != NULL) - ouroptions = rcs->expand; + if ((options == NULL || options[0] == '\0') && rcs->expand == NULL) + expand = KFLAG_KV; else - ouroptions = "kv"; - - keywords = 0; - - if (strcmp (ouroptions, "o") != 0 - && strcmp (ouroptions, "b") != 0) { - register int inkeyword; - register char *s, *send; + const char *ouroptions; + const char * const *cpp; - /* Keyword expansion is being done. Make sure the text does - not contain any keywords. If it does have any, do the - regular checkout. */ - inkeyword = 0; - send = value + len; - for (s = value; s < send; s++) + if (options != NULL && options[0] != '\0') { - register char c; + assert (options[0] == '-' && options[1] == 'k'); + ouroptions = options + 2; + } + else + ouroptions = rcs->expand; - c = *s; - if (c == '$') - { - if (inkeyword) - { - keywords = 1; - break; - } - inkeyword = 1; - } - else if (c == ':') - { - if (inkeyword) - { - keywords = 1; - break; - } - } - else if (inkeyword && ! isalpha ((unsigned char) c)) - inkeyword = 0; + for (cpp = kflags; *cpp != NULL; cpp++) + if (strcmp (*cpp, ouroptions) == 0) + break; + + if (*cpp != NULL) + expand = (enum kflag) (cpp - kflags); + else + { + error (0, 0, + "internal error: unsupported substitution string -k%s", + ouroptions); + expand = KFLAG_KV; } } - if (! keywords) + if (expand != KFLAG_O && expand != KFLAG_B) { - FILE *ofp; + Node *p; + char *newvalue; - /* We have the text we want. */ + p = findnode (rcs->versions, rev == NULL ? rcs->head : rev); + if (p == NULL) + error (1, 0, "internal error: no revision information for %s", + rev == NULL ? rcs->head : rev); + + expand_keywords (rcs, (RCSVers *) p->data, nametag, log, loglen, + expand, value, len, &newvalue, &len); + if (newvalue != value) + { + if (free_value) + free (value); + value = newvalue; + free_value = 1; + } + } + + if (log != NULL) + { + free (log); + log = NULL; + } + + if (pfn != NULL) + { + /* The PFN interface is very simple to implement right now, as + we always have the entire file in memory. */ + if (len != 0) + pfn (callerdat, value, len); + } + else + { if (workfile == NULL) { if (sout == RUN_TTY) ofp = stdout; else { - ofp = CVS_FOPEN (sout, - strcmp (ouroptions, "b") == 0 ? "wb" : "w"); + ofp = CVS_FOPEN (sout, expand == KFLAG_B ? "wb" : "w"); if (ofp == NULL) error (1, errno, "cannot open %s", sout); } } else { - ofp = CVS_FOPEN (workfile, - strcmp (ouroptions, "b") == 0 ? "wb" : "w"); + ofp = CVS_FOPEN (workfile, expand == KFLAG_B ? "wb" : "w"); if (ofp == NULL) error (1, errno, "cannot open %s", workfile); } @@ -2411,41 +3029,129 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout) if (fclose (ofp) < 0) error (1, errno, "cannot close %s", sout); } + } - if (free_value) - free (value); - if (free_rev) - free (rev); + if (free_value) + free (value); + if (free_rev) + free (rev); - return 0; - } + return 0; +} - /* We were not able to optimize retrieving this revision. */ +/* This structure is passed between RCS_cmp_file and cmp_file_buffer. */ -#if 0 - /* A bit of debugging code to make sure that NAMETAG corresponds - to REV. */ - if (nametag != NULL && strcmp (nametag, rev) != 0) +struct cmp_file_data +{ + const char *filename; + FILE *fp; + int different; +}; + +/* Compare the contents of revision REV of RCS file RCS with the + contents of the file FILENAME. OPTIONS is a string for the keyword + expansion options. Return 0 if the contents of the revision are + the same as the contents of the file, 1 if they are different. */ + +int +RCS_cmp_file (rcs, rev, options, filename) + RCSNode *rcs; + char *rev; + char *options; + const char *filename; +{ + int binary; + FILE *fp; + struct cmp_file_data data; + int retcode; + + if (options != NULL && options[0] != '\0') + binary = (strcmp (options, "-kb") == 0); + else { - char *numtag; + char *expand; - numtag = translate_symtag (rcs, nametag); - assert (rev != NULL && numtag != NULL && strcmp (numtag, rev) == 0); - free (numtag); + expand = RCS_getexpand (rcs); + if (expand != NULL && strcmp (expand, "b") == 0) + binary = 1; + else + binary = 0; } -#endif - if (free_value) - free (value); + fp = CVS_FOPEN (filename, binary ? FOPEN_BINARY_READ : "r"); - ret = RCS_exec_checkout (rcs->path, workfile, - nametag != NULL ? nametag : rev, - options, sout); + data.filename = filename; + data.fp = fp; + data.different = 0; - if (free_rev) - free (rev); + retcode = RCS_checkout (rcs, (char *) NULL, rev, (char *) NULL, + options, RUN_TTY, cmp_file_buffer, + (void *) &data); - return ret; + /* If we have not yet found a difference, make sure that we are at + the end of the file. */ + if (! data.different) + { + if (getc (fp) != EOF) + data.different = 1; + } + + fclose (fp); + + if (retcode != 0) + return 1; + + return data.different; +} + +/* This is a subroutine of RCS_cmp_file. It is passed to + RCS_checkout. */ + +#define CMP_BUF_SIZE (8 * 1024) + +static void +cmp_file_buffer (callerdat, buffer, len) + void *callerdat; + const char *buffer; + size_t len; +{ + struct cmp_file_data *data = (struct cmp_file_data *) callerdat; + char *filebuf; + + /* If we've already found a difference, we don't need to check + further. */ + if (data->different) + return; + + filebuf = xmalloc (len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len); + + while (len > 0) + { + size_t checklen; + + checklen = len > CMP_BUF_SIZE ? CMP_BUF_SIZE : len; + if (fread (filebuf, 1, checklen, data->fp) != checklen) + { + if (ferror (data->fp)) + error (1, errno, "cannot read file %s for comparing", + data->filename); + data->different = 1; + free (filebuf); + return; + } + + if (memcmp (filebuf, buffer, checklen) != 0) + { + data->different = 1; + free (filebuf); + return; + } + + buffer += checklen; + len -= checklen; + } + + free (filebuf); } /* For RCS file RCS, make symbolic tag TAG point to revision REV. @@ -2888,16 +3594,21 @@ month_printname (month) RCS with file position pointing to the deltas. We close the file when we are done. + If LOG is non-NULL, then *LOG is set to the log message of VERSION, + and *LOGLEN is set to the length of the log message. + On error, give a fatal error. */ static void -RCS_deltas (rcs, fp, version, op, text, len) +RCS_deltas (rcs, fp, version, op, text, len, log, loglen) RCSNode *rcs; FILE *fp; char *version; enum rcs_delta_op op; char **text; size_t *len; + char **log; + size_t *loglen; { char *branchversion; char *cpversion; @@ -2993,6 +3704,16 @@ RCS_deltas (rcs, fp, version, op, text, len) while ((n = getrcskey (fp, &key, &value, &vallen)) >= 0) { + if (log != NULL + && isversion + && strcmp (key, "log") == 0 + && strcmp (branchversion, version) == 0) + { + *log = xmalloc (vallen); + memcpy (*log, value, vallen); + *loglen = vallen; + } + if (strcmp (key, "text") == 0) { if (ishead) @@ -3358,7 +4079,8 @@ annotate_fileproc (callerdat, finfo) cvs_outerr (finfo->fullname, 0); cvs_outerr ("\n***************\n", 0); - RCS_deltas (finfo->rcs, fp, version, RCS_ANNOTATE, NULL, NULL); + RCS_deltas (finfo->rcs, fp, version, RCS_ANNOTATE, (char **) NULL, + (size_t) NULL, (char **) NULL, (size_t *) NULL); free (version); return 0; } @@ -3427,10 +4149,7 @@ annotate (argc, argv) if (date) client_senddate (date); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, local, 0, 0, 0); + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("annotate\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/rcs.h b/gnu/usr.bin/cvs/src/rcs.h index 1305b8c754c..699280a79ad 100644 --- a/gnu/usr.bin/cvs/src/rcs.h +++ b/gnu/usr.bin/cvs/src/rcs.h @@ -10,7 +10,6 @@ #define RCS "rcs" #define RCS_CI "ci" -#define RCS_CO "co" #define RCS_DIFF "rcsdiff" #define RCS_RCSMERGE "rcsmerge" @@ -71,6 +70,7 @@ struct rcsversnode char *version; char *date; char *author; + char *state; char *next; int dead; List *branches; @@ -87,6 +87,9 @@ typedef struct rcsversnode RCSVers; */ #define RCS_MAGIC_BRANCH 0 +/* The type of a function passed to RCS_checkout. */ +typedef void (*RCSCHECKOUTPROC) PROTO ((void *, const char *, size_t)); + /* * exported interfaces */ @@ -113,7 +116,9 @@ char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match)); int RCS_isdead PROTO((RCSNode *, const char *)); char *RCS_getexpand PROTO ((RCSNode *)); -int RCS_checkout PROTO ((RCSNode *, char *, char *, char *, char *, char *)); +int RCS_checkout PROTO ((RCSNode *, char *, char *, char *, char *, char *, + RCSCHECKOUTPROC, void *)); +int RCS_cmp_file PROTO ((RCSNode *, char *, char *, const char *)); int RCS_settag PROTO ((RCSNode *, const char *, const char *)); int RCS_deltag PROTO ((RCSNode *, const char *, int)); int RCS_setbranch PROTO((RCSNode *, const char *)); diff --git a/gnu/usr.bin/cvs/src/release.c b/gnu/usr.bin/cvs/src/release.c index d387e6e5b7b..f2f1edf5b0e 100644 --- a/gnu/usr.bin/cvs/src/release.c +++ b/gnu/usr.bin/cvs/src/release.c @@ -82,7 +82,7 @@ release (argc, argv) if (argc == -1) usage (release_usage); optind = 1; - while ((c = getopt (argc, argv, "Qdq")) != -1) + while ((c = getopt (argc, argv, "+Qdq")) != -1) { switch (c) { diff --git a/gnu/usr.bin/cvs/src/remove.c b/gnu/usr.bin/cvs/src/remove.c index 6f31e0acb55..157125068fe 100644 --- a/gnu/usr.bin/cvs/src/remove.c +++ b/gnu/usr.bin/cvs/src/remove.c @@ -51,7 +51,7 @@ cvsremove (argc, argv) usage (remove_usage); optind = 1; - while ((c = getopt (argc, argv, "flR")) != -1) + while ((c = getopt (argc, argv, "+flR")) != -1) { switch (c) { @@ -100,7 +100,8 @@ cvsremove (argc, argv) if (local) send_arg("-l"); send_file_names (argc, argv, 0); - send_files (argc, argv, local, 0, 0, 0); + /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */ + send_files (argc, argv, local, 0, 0); send_to_server ("remove\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/root.c b/gnu/usr.bin/cvs/src/root.c index 1e38c31478a..26910328fe9 100644 --- a/gnu/usr.bin/cvs/src/root.c +++ b/gnu/usr.bin/cvs/src/root.c @@ -227,7 +227,11 @@ check_root_consistent () cause deadlock, as noted in server_cleanup. Best solution would presumably be to write some code so that error() automatically defers the error in those cases where that is needed. */ - + /* FIXME? Possible that the wording should be more clear (e.g. + Root says "%s" but pserver protocol says "%s" + or something which would aid people who are writing implementations + of the client side of the CVS protocol. I don't see any security + problem with revealing that information. */ if ((Pserver_Repos != NULL) && (CVSroot_directory != NULL)) if (strcmp (Pserver_Repos, CVSroot_directory) != 0) error (1, 0, "repository mismatch: \"%s\" vs \"%s\"", diff --git a/gnu/usr.bin/cvs/src/rtag.c b/gnu/usr.bin/cvs/src/rtag.c index d499e0b3fe5..1e2017b9b0d 100644 --- a/gnu/usr.bin/cvs/src/rtag.c +++ b/gnu/usr.bin/cvs/src/rtag.c @@ -92,7 +92,7 @@ rtag (argc, argv) usage (rtag_usage); optind = 1; - while ((c = getopt (argc, argv, "FanfQqlRdbr:D:")) != -1) + while ((c = getopt (argc, argv, "+FanfQqlRdbr:D:")) != -1) { switch (c) { diff --git a/gnu/usr.bin/cvs/src/sanity.sh b/gnu/usr.bin/cvs/src/sanity.sh index 7906ec804c4..9f556209329 100644 --- a/gnu/usr.bin/cvs/src/sanity.sh +++ b/gnu/usr.bin/cvs/src/sanity.sh @@ -251,11 +251,24 @@ dotest_internal () else if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : \ "$3"${ENDANCHOR} >/dev/null; then + # See below about writing this to the logfile. + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} pass "$1" else if test x"$4" != x; then if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : \ "$4"${ENDANCHOR} >/dev/null; then + # Why, I hear you ask, do we write this to the logfile + # even when the test passes? The reason is that the test + # may give us the regexp which we were supposed to match, + # but sometimes it may be useful to look at the exact + # text which was output. For example, suppose one wants + # to grep for a particular warning, and make _sure_ that + # CVS never hits it (even in cases where the tests might + # match it with .*). Or suppose one wants to see the exact + # date format output in a certain case (where the test will + # surely use a somewhat non-specific pattern). + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} pass "$1" else echo "** expected: " >>${LOGFILE} @@ -466,6 +479,7 @@ RCSINIT=; export RCSINIT if test x"$*" = x; then tests="basica basicb basic1 deep basic2 rdiff death death2 branches multibranch import join new newb conflicts conflicts2 modules modules2 modules3 mflag errmsg1 devcom devcom2 devcom3 ignore binfiles binwrap info serverpatch log log2 crerepos rcs big modes" + tests="${tests} sticky keyword" else tests="$*" fi @@ -642,11 +656,24 @@ done' # Test the -f option to ci cd sdir/ssdir + dotest basica-8a0 "${testcvs} -q ci -m not-modified ssfile" '' dotest basica-8a "${testcvs} -q ci -f -m force-it" \ 'Checking in ssfile; /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile new revision: 1\.3; previous revision: 1\.2 done' + dotest basica-8a1 "${testcvs} -q ci -m bump-it -r 2.0" \ +'Checking in ssfile; +/tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile +new revision: 2\.0; previous revision: 1\.3 +done' + # -f should not be necessary, but it should be harmless. + # Also test the "-r 3" (rather than "-r 3.0") usage. + dotest basica-8a2 "${testcvs} -q ci -m bump-it -f -r 3" \ +'Checking in ssfile; +/tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile +new revision: 3\.1; previous revision: 2\.0 +done' cd ../.. dotest basica-8b "${testcvs} -q diff -r1.2 -r1.3" \ 'Index: sdir/ssdir/ssfile @@ -704,6 +731,12 @@ done' : mkdir ${CVSROOT_DIRNAME}/first-dir dotest basicb-1 "${testcvs} -q co first-dir" '' dotest basicb-1a "test -d CVS" '' + # See comment at modules3-7f for more on this behavior. + dotest basicb-1b "cat CVS/Repository" \ +"${TESTDIR}/cvsroot/first-dir" "${TESTDIR}/cvsroot/\." + dotest basicb-1c "cat first-dir/CVS/Repository" \ +"${TESTDIR}/cvsroot/first-dir" + cd first-dir mkdir sdir1 sdir2 dotest basicb-2 "${testcvs} add sdir1 sdir2" \ @@ -790,13 +823,84 @@ U first-dir1/sdir2/sfile2' 'U newdir/sdir1/sfile1 U newdir/sdir2/sfile2' dotest basicb-9a "test -d CVS" '' + # See comment at modules3-7f for more on this behavior. + dotest basicb-9b "cat CVS/Repository" \ +"${TESTDIR}/cvsroot/first-dir" "${TESTDIR}/cvsroot/\." + dotest basicb-9c "cat newdir/CVS/Repository" \ +"${TESTDIR}/cvsroot/CVSROOT/Emptydir" dotest basicb-10 "cat newdir/sdir1/sfile1 newdir/sdir2/sfile2" \ "sfile1 develops sfile2 starts" rm -rf newdir + # Hmm, this might be a case for CVSNULLREPOS, but CVS doesn't + # seem to deal with it... + if false; then + dotest basicb-11 "${testcvs} -q co -d sub1/sub2 first-dir" \ +"U sub1/sub2/sdir1/sfile1 +U sub1/sub2/sdir2/sfile2" + cd sub1 + dotest basicb-12 "${testcvs} -q update" '' + touch xx + dotest basicb-13 "${testcvs} add xx" fixme + cd .. + rm -r sub1 + # to test: sub1/sub2/sub3 + fi # end of tests commented out. + + # Create a second directory. + mkdir 1 + cd 1 + dotest basicb-14 "${testcvs} -q co -l ." 'U topfile' + mkdir second-dir + dotest basicb-15 "${testcvs} add second-dir" \ +"Directory ${TESTDIR}/cvsroot/second-dir added to the repository" + cd second-dir + touch aa + dotest basicb-16 "${testcvs} add aa" \ +"${PROG} [a-z]*: scheduling file .aa. for addition +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + dotest basicb-17 "${testcvs} -q ci -m add" \ +'RCS file: /tmp/cvs-sanity/cvsroot/second-dir/aa,v +done +Checking in aa; +/tmp/cvs-sanity/cvsroot/second-dir/aa,v <-- aa +initial revision: 1\.1 +done' + cd ../.. + rm -rf 1 + # Now here is the kicker: note that the semantics of -d + # are fundamentally different if we specify two or more directories + # rather than one! I consider this to be seriously bogus, + # but for the moment I am just trying to figure out what + # CVS's current behaviors are. + dotest basicb-18 "${testcvs} -q co -d test2 first-dir second-dir" \ +"U test2/first-dir/sdir1/sfile1 +U test2/first-dir/sdir2/sfile2 +U test2/second-dir/aa" + cd test2 + touch emptyfile + # The fact that CVS lets us add a file here is a CVS bug, right? + # I can just make this an error message (on the add and/or the + # commit) without getting flamed, right? + # Right? + # Right? + dotest basicb-19 "${testcvs} add emptyfile" \ +"${PROG} [a-z]*: scheduling file .emptyfile. for addition +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + dotest basicb-20 "${testcvs} -q ci -m add" \ +'RCS file: /tmp/cvs-sanity/cvsroot/CVSROOT/Emptydir/emptyfile,v +done +Checking in emptyfile; +/tmp/cvs-sanity/cvsroot/CVSROOT/Emptydir/emptyfile,v <-- emptyfile +initial revision: 1\.1 +done' + cd .. + rm -rf test2 + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -rf ${CVSROOT_DIRNAME}/second-dir rm -f ${CVSROOT_DIRNAME}/topfile,v ;; @@ -2176,12 +2280,6 @@ ${PROG} [a-z]*: file3 is no longer in the repository" dotest_fail death2-20 "test -f file2" - # Make sure we can't add a file on this nonbranch tag. - # FIXME: Right now CVS will let you add a file on a - # nonbranch tag, so this test is commented out. - # echo "bad revision" > file2 - # dotest death2-21 "${testcvs} add file2" "some error message" - # Make sure diff only reports appropriate files. dotest_fail death2-diff-13 "${testcvs} -q diff -r rdiff-tag" \ "${PROG} [a-z]*: file1 is a new entry, no comparison available" @@ -3931,6 +4029,10 @@ done' cat >modules <<EOF mod1 -a first-dir/file1 bigmod -a mod1 first-dir/file1 +namednest -d src/sub/dir first-dir +nestdeeper -d src/sub1/sub2/sub3/dir first-dir +nestshallow -d src/dir second-dir/suba/subb +path/in/modules &mod1 EOF dotest modules3-5 "${testcvs} -q ci -m add-modules" \ "Checking in modules; @@ -3944,9 +4046,128 @@ ${PROG} [a-z]*: Rebuilding administrative file database" rm -rf first-dir dotest modules3-7 "${testcvs} -q co bigmod" 'U first-dir/file1' cd .. + rm -r 1 + + mkdir 1; cd 1 + mkdir suba + mkdir suba/subb + # This fails to work remote (it doesn't notice the directories, + # I suppose because they contain no files). Bummer, especially + # considering this is a documented technique and everything. + dotest modules3-7a \ +"${testcvs} import -m add-dirs second-dir tag1 tag2" \ +"${PROG} [a-z]*: Importing /tmp/cvs-sanity/cvsroot/second-dir/suba +${PROG} [a-z]*: Importing /tmp/cvs-sanity/cvsroot/second-dir/suba/subb + +No conflicts created by this import" " +No conflicts created by this import" + cd ..; rm -r 1 + mkdir 1; cd 1 + dotest modules3-7b "${testcvs} co second-dir" \ +"${PROG} [a-z]*: Updating second-dir +${PROG} [a-z]*: Updating second-dir/suba +${PROG} [a-z]*: Updating second-dir/suba/subb" \ +"${PROG} server: Updating second-dir" + + if test "x$remote" = xyes; then + cd second-dir + mkdir suba + dotest modules3-7-workaround1 "${testcvs} add suba" \ +"Directory ${TESTDIR}/cvsroot/second-dir/suba added to the repository" + cd suba + mkdir subb + dotest modules3-7-workaround2 "${testcvs} add subb" \ +"Directory ${TESTDIR}/cvsroot/second-dir/suba/subb added to the repository" + cd ../.. + fi + + cd second-dir/suba/subb + touch fileb + dotest modules3-7c "${testcvs} add fileb" \ +"${PROG} [a-z]*: scheduling file .fileb. for addition +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + dotest modules3-7d "${testcvs} -q ci -m add-it" \ +'RCS file: /tmp/cvs-sanity/cvsroot/second-dir/suba/subb/fileb,v +done +Checking in fileb; +/tmp/cvs-sanity/cvsroot/second-dir/suba/subb/fileb,v <-- fileb +initial revision: 1\.1 +done' + cd ../../.. + cd ..; rm -r 1 + + mkdir 1; cd 1 + dotest modules3-7e "${testcvs} -q co nestshallow" \ +"U src/dir/fileb" + + # Using ${TESTDIR}/cvsroot/second-dir/suba instead of + # ${TESTDIR}/cvsroot/second-dir seems wrong, it seems like the + # 30 Dec 1996 change to build_dirs_and_chdir simply failed + # to consider what to put in CVS/Repository. + # Remote does "${TESTDIR}/cvsroot/\." which seems equally wrong, + # if in a different way, but variety is the spice of life, + # eh? + dotest modules3-7f "cat CVS/Repository" \ +"${TESTDIR}/cvsroot/second-dir/suba" "${TESTDIR}/cvsroot/\." + + dotest modules3-7g "cat src/CVS/Repository" \ +"${TESTDIR}/cvsroot/second-dir/suba" + dotest modules3-7h "cat src/dir/CVS/Repository" \ +"${TESTDIR}/cvsroot/second-dir/suba/subb" + cd ..; rm -r 1 + mkdir 1 + cd 1 + dotest modules3-8 "${testcvs} -q co namednest" \ +'U src/sub/dir/file1' + dotest modules3-9 "test -f src/sub/dir/file1" '' + cd .. + rm -r 1 + + # Try the same thing, but with the directories nested even + # deeper (deeply enough so they are nested more deeply than + # the number of directories from / to ${TESTDIR}). + mkdir 1 + cd 1 + dotest modules3-10 "${testcvs} -q co nestdeeper" \ +'U src/sub1/sub2/sub3/dir/file1' + dotest modules3-11 "test -f src/sub1/sub2/sub3/dir/file1" '' + cd .. rm -r 1 + + # This one is almost too twisted for words. The pathname output + # in the message from "co" doesn't include the "path/in/modules", + # but those directories do get created (with no CVSADM except + # in "modules" which has a CVSNULLREPOS). + # I'm not sure anyone is relying on this nonsense or whether we + # need to keep doing it, but it is what CVS currently does... + # Skip it for remote; the remote code has the good sense to + # not deal with it (on the minus side it gives + # "internal error: repository string too short." instead of a + # real error). + # I kind of suspect that it would be OK to just make it a fatal + # error to have '/' in a module name. + if test "x$remote" = xno; then + mkdir 1; cd 1 + dotest modules3-12 "${testcvs} -q co path/in/modules" \ +"U first-dir/file1" + dotest modules3-13 "test -f path/in/modules/first-dir/file1" '' + cd ..; rm -r 1 + + # Now here is where it gets seriously bogus. + mkdir 1; cd 1 + dotest modules3-14 \ +"${testcvs} -q rtag tag1 path/in/modules" '' + # CVS creates this even though rtag should *never* affect + # the directory current when it is called! + dotest modules3-15 "test -d path/in/modules" '' + # Just for trivia's sake, rdiff is not similarly vulnerable + # because it passes 0 for run_module_prog to do_module. + cd ..; rm -r 1 + fi # end of tests skipped for remote + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -rf ${CVSROOT_DIRNAME}/second-dir ;; mflag) @@ -5715,11 +5936,293 @@ done' fi cd ../.. - rm -rf 1 ${TESTDIR}/first-dir + rm -rf 1 ${CVSROOT_DIRNAME}/first-dir # Perhaps should restore the umask and CVSUMASK. But the other # tests "should" not care about them... ;; + sticky) + # More tests of sticky tags, particularly non-branch sticky tags. + mkdir 1; cd 1 + dotest sticky-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest sticky-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + + touch file1 + dotest sticky-3 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + dotest sticky-4 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +initial revision: 1\.1 +done" + dotest sticky-5 "${testcvs} -q tag tag1" "T file1" + echo add a line >>file1 + dotest sticky-6 "${testcvs} -q ci -m modify" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.2; previous revision: 1\.1 +done" + dotest sticky-7 "${testcvs} -q update -r tag1" "[UP] file1" + dotest sticky-8 "cat file1" '' + dotest sticky-9 "${testcvs} -q update" '' + dotest sticky-10 "cat file1" '' + touch file2 + dotest_fail sticky-11 "${testcvs} add file2" \ +"${PROG} [a-z]*: cannot add file on non-branch tag tag1" + dotest sticky-12 "${testcvs} -q update -A" "[UP] file1 +${QUESTION} file2" "${QUESTION} file2 +[UP] file1" + dotest sticky-13 "${testcvs} add file2" \ +"${PROG} [a-z]*: scheduling file .file2. for addition +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + + cd ../.. + rm -rf 1 ${CVSROOT_DIRNAME}/first-dir + ;; + + keyword) + # Test keyword expansion. + mkdir 1; cd 1 + dotest keyword-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest keyword-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + + echo '$''Author$' > file1 + echo '$''Date$' >> file1 + echo '$''Header$' >> file1 + echo '$''Id$' >> file1 + echo '$''Locker$' >> file1 + echo '$''Name$' >> file1 + echo '$''RCSfile$' >> file1 + echo '$''Revision$' >> file1 + echo '$''Source$' >> file1 + echo '$''State$' >> file1 + echo '$''Nonkey$' >> file1 + # Omit the trailing dollar sign + echo '$''Date' >> file1 + # Put two keywords on one line + echo '$''State$' '$''State$' >> file1 + # Use a header for Log + echo 'xx $''Log$' >> file1 + + dotest keyword-3 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + dotest keyword-4 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +initial revision: 1\.1 +done" + dotest keyword-5 "cat file1" \ +'\$'"Author: ${username} "'\$'" +"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'" +"'\$'"Header: ${TESTDIR}/cvsroot/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" +"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" +"'\$'"Locker: "'\$'" +"'\$'"Name: "'\$'" +"'\$'"RCSfile: file1,v "'\$'" +"'\$'"Revision: 1\.1 "'\$'" +"'\$'"Source: ${TESTDIR}/cvsroot/first-dir/file1,v "'\$'" +"'\$'"State: Exp "'\$'" +"'\$'"Nonkey"'\$'" +"'\$'"Date +"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'" +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.1 [0-9/]* [0-9:]* ${username} +xx add +xx" + + # Use cvs admin to lock the RCS file in order to check -kkvl + # vs. -kkv. CVS does not normally lock RCS files, but some + # people use cvs admin to enforce reserved checkouts. + dotest keyword-6 "${testcvs} admin -l file1" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +1\.1 locked +done" + + dotest keyword-7 "${testcvs} update -kkv file1" "U file1" + dotest keyword-8 "cat file1" \ +'\$'"Author: ${username} "'\$'" +"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'" +"'\$'"Header: ${TESTDIR}/cvsroot/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" +"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp "'\$'" +"'\$'"Locker: "'\$'" +"'\$'"Name: "'\$'" +"'\$'"RCSfile: file1,v "'\$'" +"'\$'"Revision: 1\.1 "'\$'" +"'\$'"Source: ${TESTDIR}/cvsroot/first-dir/file1,v "'\$'" +"'\$'"State: Exp "'\$'" +"'\$'"Nonkey"'\$'" +"'\$'"Date +"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'" +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.1 [0-9/]* [0-9:]* ${username} +xx add +xx" + + dotest keyword-9 "${testcvs} update -kkvl file1" "U file1" + dotest keyword-10 "cat file1" \ +'\$'"Author: ${username} "'\$'" +"'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'" +"'\$'"Header: ${TESTDIR}/cvsroot/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp ${username} "'\$'" +"'\$'"Id: file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp ${username} "'\$'" +"'\$'"Locker: ${username} "'\$'" +"'\$'"Name: "'\$'" +"'\$'"RCSfile: file1,v "'\$'" +"'\$'"Revision: 1\.1 "'\$'" +"'\$'"Source: ${TESTDIR}/cvsroot/first-dir/file1,v "'\$'" +"'\$'"State: Exp "'\$'" +"'\$'"Nonkey"'\$'" +"'\$'"Date +"'\$'"State: Exp "'\$'" "'\$'"State: Exp "'\$'" +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.1 [0-9/]* [0-9:]* ${username} +xx add +xx" + + dotest keyword-11 "${testcvs} update -kk file1" "U file1" + dotest keyword-12 "cat file1" \ +'\$'"Author"'\$'" +"'\$'"Date"'\$'" +"'\$'"Header"'\$'" +"'\$'"Id"'\$'" +"'\$'"Locker"'\$'" +"'\$'"Name"'\$'" +"'\$'"RCSfile"'\$'" +"'\$'"Revision"'\$'" +"'\$'"Source"'\$'" +"'\$'"State"'\$'" +"'\$'"Nonkey"'\$'" +"'\$'"Date +"'\$'"State"'\$'" "'\$'"State"'\$'" +xx "'\$'"Log"'\$'" +xx Revision 1\.1 [0-9/]* [0-9:]* ${username} +xx add +xx" + + dotest keyword-13 "${testcvs} update -kv file1" "U file1" + dotest keyword-14 "cat file1" \ +"${username} +[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] +${TESTDIR}/cvsroot/first-dir/file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp +file1,v 1\.1 [0-9/]* [0-9:]* ${username} Exp + + +file1,v +1\.1 +${TESTDIR}/cvsroot/first-dir/file1,v +Exp +"'\$'"Nonkey"'\$'" +"'\$'"Date +Exp Exp +xx file1,v +xx Revision 1\.1 [0-9/]* [0-9:]* ${username} +xx add +xx" + + dotest keyword-15 "${testcvs} update -ko file1" "U file1" + dotest keyword-16 "cat file1" \ +'\$'"Author"'\$'" +"'\$'"Date"'\$'" +"'\$'"Header"'\$'" +"'\$'"Id"'\$'" +"'\$'"Locker"'\$'" +"'\$'"Name"'\$'" +"'\$'"RCSfile"'\$'" +"'\$'"Revision"'\$'" +"'\$'"Source"'\$'" +"'\$'"State"'\$'" +"'\$'"Nonkey"'\$'" +"'\$'"Date +"'\$'"State"'\$'" "'\$'"State"'\$'" +xx "'\$'"Log"'\$' + + # Test the Name keyword. First go back to normal expansion. + + # FIXME: When using remote, update -A does not revert the + # keyword expansion mode. We work around that bug here. + # This workaround should be removed when the bug is fixed. + if test "x$remote" = "xyes"; then + cd .. + rm -rf first-dir + dotest keyword-17 "${testcvs} -q co first-dir" "U first-dir/file1" + cd first-dir + else + dotest keyword-17 "${testcvs} update -A file1" "U file1" + fi + + echo '$''Name$' > file1 + dotest keyword-18 "${testcvs} ci -m modify file1" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.2; previous revision: 1\.1 +done" + dotest keyword-19 "${testcvs} -q tag tag1" "T file1" + echo "change" >> file1 + dotest keyword-20 "${testcvs} -q ci -m mod2 file1" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.3; previous revision: 1\.2 +done" + dotest keyword-21 "${testcvs} -q update -r tag1" "[UP] file1" + + # FIXME: This test fails when remote. The second expect + # string below should be removed when this is fixed. + dotest keyword-22 "cat file1" '\$'"Name: tag1 "'\$' \ +'\$'"Name: "'\$' + + dotest keyword-23 "${testcvs} update -A file1" "[UP] file1" + + # Test the Log keyword. + echo 'xx $''Log$' > file1 + cat >${TESTDIR}/comment.tmp <<EOF +First log line +Second log line +EOF + dotest keyword-24 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.4; previous revision: 1\.3 +done" + rm -f ${TESTDIR}/comment.tmp + dotest keyword-25 "cat file1" \ +"xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} +xx First log line +xx Second log line +xx" + + echo "change" >> file1 + dotest keyword-26 "${testcvs} ci -m modify file1" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.5; previous revision: 1\.4 +done" + dotest keyword-27 "cat file1" \ +"xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.5 [0-9/]* [0-9:]* ${username} +xx modify +xx +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} +xx First log line +xx Second log line +xx +change" + + cd ../.. + rm -rf 1 ${CVSROOT_DIRNAME}/first-dir + ;; + *) echo $what is not the name of a test -- ignored ;; diff --git a/gnu/usr.bin/cvs/src/server.h b/gnu/usr.bin/cvs/src/server.h index e9c5807a53c..cb332250783 100644 --- a/gnu/usr.bin/cvs/src/server.h +++ b/gnu/usr.bin/cvs/src/server.h @@ -71,8 +71,7 @@ extern void server_clear_entstat PROTO((char *update_dir, char *repository)); /* Set or clear a per-directory sticky tag or date. */ extern void server_set_sticky PROTO((char *update_dir, char *repository, - char *tag, - char *date)); + char *tag, char *date, int nonbranch)); /* Send Template response. */ extern void server_template PROTO ((char *, char *)); diff --git a/gnu/usr.bin/cvs/src/status.c b/gnu/usr.bin/cvs/src/status.c index b794a2e43ab..67b71beb565 100644 --- a/gnu/usr.bin/cvs/src/status.c +++ b/gnu/usr.bin/cvs/src/status.c @@ -41,7 +41,7 @@ status (argc, argv) usage (status_usage); optind = 1; - while ((c = getopt (argc, argv, "vlR")) != -1) + while ((c = getopt (argc, argv, "+vlR")) != -1) { switch (c) { @@ -77,9 +77,13 @@ status (argc, argv) send_arg("-l"); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* XXX This should only need to send file info; the file - contents themselves will not be examined. */ - send_files (argc, argv, local, 0, 0, 0); + /* Note that by setting SEND_NO_CONTENTS, we do prevent the + server from updating our timestamp if the timestamp is + unchanged and the file is unmodified. And I think it is a + user-visible thing in that case (shows "locally modified" + instead of "up to date" I would think). But the speed seems + to be worth it. */ + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("status\012", 0); err = get_responses_and_close (); diff --git a/gnu/usr.bin/cvs/src/tag.c b/gnu/usr.bin/cvs/src/tag.c index cee7aecbbe8..9c49da562bb 100644 --- a/gnu/usr.bin/cvs/src/tag.c +++ b/gnu/usr.bin/cvs/src/tag.c @@ -83,7 +83,7 @@ cvstag (argc, argv) usage (tag_usage); optind = 1; - while ((c = getopt (argc, argv, "FQqlRcdr:D:bf")) != -1) + while ((c = getopt (argc, argv, "+FQqlRcdr:D:bf")) != -1) { switch (c) { @@ -177,10 +177,14 @@ cvstag (argc, argv) send_arg (symtag); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, local, 0, 0, 0); + + /* SEND_NO_CONTENTS has a mildly bizarre interaction with + check_uptodate; if the timestamp is modified but the file + is unmodified, the check will fail, only to have "cvs diff" + show no differences (and one must do "update" or something to + reset the client's notion of the timestamp). */ + + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("tag\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/vers_ts.c b/gnu/usr.bin/cvs/src/vers_ts.c index d7420e7160d..03a0036202c 100644 --- a/gnu/usr.bin/cvs/src/vers_ts.c +++ b/gnu/usr.bin/cvs/src/vers_ts.c @@ -9,7 +9,7 @@ #include "cvs.h" #ifdef SERVER_SUPPORT -static void time_stamp_server PROTO((char *, Vers_TS *)); +static void time_stamp_server PROTO((char *, Vers_TS *, Entnode *)); #endif /* @@ -30,6 +30,7 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) RCSNode *rcsdata; Vers_TS *vers_ts; struct stickydirtag *sdtp; + Entnode *entdata; /* get a new Vers_TS struct */ vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS)); @@ -51,29 +52,40 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) sdtp = (struct stickydirtag *) finfo->entries->list->data; /* list-private */ } + entdata = NULL; if (p != NULL) { - Entnode *entdata = (Entnode *) p->data; + entdata = (Entnode *) p->data; - vers_ts->vn_user = xstrdup (entdata->version); - vers_ts->ts_rcs = xstrdup (entdata->timestamp); - vers_ts->ts_conflict = xstrdup (entdata->conflict); - if (!tag) - { - if (!(sdtp && sdtp->aflag)) - vers_ts->tag = xstrdup (entdata->tag); - } - if (!date) - { - if (!(sdtp && sdtp->aflag)) - vers_ts->date = xstrdup (entdata->date); - } - if (!options || (options && *options == '\0')) +#ifdef SERVER_SUPPORT + /* An entries line with "D" in the timestamp indicates that the + client sent Is-modified without sending Entry. So we want to + use the entries line for the sole purpose of telling + time_stamp_server what is up; we don't want the rest of CVS + to think there is an entries line. */ + if (strcmp (entdata->timestamp, "D") != 0) +#endif { - if (!(sdtp && sdtp->aflag)) - vers_ts->options = xstrdup (entdata->options); + vers_ts->vn_user = xstrdup (entdata->version); + vers_ts->ts_rcs = xstrdup (entdata->timestamp); + vers_ts->ts_conflict = xstrdup (entdata->conflict); + if (!tag) + { + if (!(sdtp && sdtp->aflag)) + vers_ts->tag = xstrdup (entdata->tag); + } + if (!date) + { + if (!(sdtp && sdtp->aflag)) + vers_ts->date = xstrdup (entdata->date); + } + if (!options || (options && *options == '\0')) + { + if (!(sdtp && sdtp->aflag)) + vers_ts->options = xstrdup (entdata->options); + } + vers_ts->entdata = entdata; } - vers_ts->entdata = entdata; } /* @@ -114,7 +126,10 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0)) { if (!vers_ts->tag) + { vers_ts->tag = xstrdup (sdtp->tag); + vers_ts->nonbranch = sdtp->nonbranch; + } if (!vers_ts->date) vers_ts->date = xstrdup (sdtp->date); } @@ -177,7 +192,7 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) { #ifdef SERVER_SUPPORT if (server_active) - time_stamp_server (finfo->file, vers_ts); + time_stamp_server (finfo->file, vers_ts, entdata); else #endif vers_ts->ts_user = time_stamp (finfo->file); @@ -195,9 +210,10 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) #define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs)) static void -time_stamp_server (file, vers_ts) +time_stamp_server (file, vers_ts, entdata) char *file; Vers_TS *vers_ts; + Entnode *entdata; { struct stat sb; char *cp; @@ -215,11 +231,16 @@ time_stamp_server (file, vers_ts) lost. I don't know that that's right, but it's not clear to me that either choice is. Besides, would we have an RCS string in that case anyways? */ - if (vers_ts->entdata == NULL) + if (entdata == NULL) mark_lost (vers_ts); - else if (vers_ts->entdata->timestamp - && vers_ts->entdata->timestamp[0] == '=') + else if (entdata->timestamp + && entdata->timestamp[0] == '=') mark_unchanged (vers_ts); + else if (entdata->timestamp != NULL + && (entdata->timestamp[0] == 'M' + || entdata->timestamp[0] == 'D') + && entdata->timestamp[1] == '\0') + vers_ts->ts_user = xstrdup ("Is-modified"); else mark_lost (vers_ts); } diff --git a/gnu/usr.bin/cvs/src/version.c b/gnu/usr.bin/cvs/src/version.c index 8921e787a76..8e19b26bf35 100644 --- a/gnu/usr.bin/cvs/src/version.c +++ b/gnu/usr.bin/cvs/src/version.c @@ -12,7 +12,7 @@ #include "cvs.h" -char *version_string = "\nConcurrent Versions System (CVS) 1.9.6"; +char *version_string = "\nConcurrent Versions System (CVS) 1.9.8"; #ifdef CLIENT_SUPPORT #ifdef SERVER_SUPPORT diff --git a/gnu/usr.bin/cvs/src/watch.c b/gnu/usr.bin/cvs/src/watch.c index 51b50fcd10e..70deb7c3477 100644 --- a/gnu/usr.bin/cvs/src/watch.c +++ b/gnu/usr.bin/cvs/src/watch.c @@ -256,7 +256,7 @@ watch_addremove (argc, argv) the_args.edit = 0; the_args.unedit = 0; optind = 1; - while ((c = getopt (argc, argv, "la:")) != -1) + while ((c = getopt (argc, argv, "+la:")) != -1) { switch (c) { @@ -333,10 +333,7 @@ watch_addremove (argc, argv) send_arg ("none"); } send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, local, 0, 0, 0); + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server (the_args.adding ? "watch-add\012" : "watch-remove\012", 0); @@ -483,7 +480,7 @@ watchers (argc, argv) usage (watchers_usage); optind = 1; - while ((c = getopt (argc, argv, "l")) != -1) + while ((c = getopt (argc, argv, "+l")) != -1) { switch (c) { @@ -508,10 +505,7 @@ watchers (argc, argv) if (local) send_arg ("-l"); send_file_names (argc, argv, SEND_EXPAND_WILD); - /* FIXME: We shouldn't have to send current files, but I'm not sure - whether it works. So send the files -- - it's slower but it works. */ - send_files (argc, argv, local, 0, 0, 0); + send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("watchers\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/zlib.c b/gnu/usr.bin/cvs/src/zlib.c index 776e1bfb5e4..02ad70c2f53 100644 --- a/gnu/usr.bin/cvs/src/zlib.c +++ b/gnu/usr.bin/cvs/src/zlib.c @@ -11,11 +11,7 @@ This program 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 this program; if not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + GNU General Public License for more details. */ /* The routines in this file are the interface between the CVS client/server support and the zlib compression library. */ |