summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/cvs/src
diff options
context:
space:
mode:
authortholo <tholo@openbsd.org>1996-05-06 22:18:10 +0000
committertholo <tholo@openbsd.org>1996-05-06 22:18:10 +0000
commitc2c6168287231ca1f2357af7564f6bed5739dfd2 (patch)
tree2e18723d254f3d19c64aea673815a2f2d1cc691e /gnu/usr.bin/cvs/src
parentUse MSR 0x10, not 10 to clear the Pentium instruction counter; from David (diff)
downloadwireguard-openbsd-c2c6168287231ca1f2357af7564f6bed5739dfd2.tar.xz
wireguard-openbsd-c2c6168287231ca1f2357af7564f6bed5739dfd2.zip
New CVS release from Cyclic Software
Diffstat (limited to 'gnu/usr.bin/cvs/src')
-rw-r--r--gnu/usr.bin/cvs/src/ChangeLog559
-rw-r--r--gnu/usr.bin/cvs/src/ChangeLog-93952
-rw-r--r--gnu/usr.bin/cvs/src/add.c6
-rw-r--r--gnu/usr.bin/cvs/src/admin.c4
-rw-r--r--gnu/usr.bin/cvs/src/checkin.c2
-rw-r--r--gnu/usr.bin/cvs/src/checkout.c4
-rw-r--r--gnu/usr.bin/cvs/src/classify.c6
-rw-r--r--gnu/usr.bin/cvs/src/client.c451
-rw-r--r--gnu/usr.bin/cvs/src/client.h10
-rw-r--r--gnu/usr.bin/cvs/src/create_adm.c13
-rw-r--r--gnu/usr.bin/cvs/src/cvsrc.c14
-rw-r--r--gnu/usr.bin/cvs/src/diff.c36
-rw-r--r--gnu/usr.bin/cvs/src/edit.c23
-rw-r--r--gnu/usr.bin/cvs/src/entries.c4
-rw-r--r--gnu/usr.bin/cvs/src/error.c8
-rw-r--r--gnu/usr.bin/cvs/src/expand_path.c2
-rw-r--r--gnu/usr.bin/cvs/src/fileattr.c5
-rw-r--r--gnu/usr.bin/cvs/src/filesubr.c74
-rw-r--r--gnu/usr.bin/cvs/src/find_names.c2
-rw-r--r--gnu/usr.bin/cvs/src/hash.c14
-rw-r--r--gnu/usr.bin/cvs/src/history.c2
-rw-r--r--gnu/usr.bin/cvs/src/import.c110
-rw-r--r--gnu/usr.bin/cvs/src/log.c5
-rw-r--r--gnu/usr.bin/cvs/src/logmsg.c58
-rw-r--r--gnu/usr.bin/cvs/src/mkmodules.c417
-rw-r--r--gnu/usr.bin/cvs/src/modules.c17
-rw-r--r--gnu/usr.bin/cvs/src/options.h.in22
-rw-r--r--gnu/usr.bin/cvs/src/rcs.c843
-rw-r--r--gnu/usr.bin/cvs/src/rcs.h10
-rw-r--r--gnu/usr.bin/cvs/src/rcscmds.c16
-rw-r--r--gnu/usr.bin/cvs/src/recurse.c54
-rw-r--r--gnu/usr.bin/cvs/src/remove.c22
-rw-r--r--gnu/usr.bin/cvs/src/repos.c13
-rw-r--r--gnu/usr.bin/cvs/src/rtag.c93
-rw-r--r--gnu/usr.bin/cvs/src/run.c5
-rw-r--r--gnu/usr.bin/cvs/src/sanity.sh497
-rw-r--r--gnu/usr.bin/cvs/src/scramble.c2
-rw-r--r--gnu/usr.bin/cvs/src/server.h4
-rw-r--r--gnu/usr.bin/cvs/src/status.c18
-rw-r--r--gnu/usr.bin/cvs/src/subr.c4
-rw-r--r--gnu/usr.bin/cvs/src/tag.c91
-rw-r--r--gnu/usr.bin/cvs/src/vers_ts.c79
-rw-r--r--gnu/usr.bin/cvs/src/version.c2
-rw-r--r--gnu/usr.bin/cvs/src/watch.c9
44 files changed, 2900 insertions, 732 deletions
diff --git a/gnu/usr.bin/cvs/src/ChangeLog b/gnu/usr.bin/cvs/src/ChangeLog
index 060f4cad503..99161b09557 100644
--- a/gnu/usr.bin/cvs/src/ChangeLog
+++ b/gnu/usr.bin/cvs/src/ChangeLog
@@ -1,5 +1,564 @@
+Sun May 5 21:39:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): If sdtp is NULL, go ahead and check
+ RCS_getexpand for options. Fixes binaries and non-unix clients.
+ * sanity.sh: Fix binfiles-5.5 to test for the correct behavior
+ rather than the buggy behavior which existed when the binfiles-5.5
+ test was written.
+ (binfiles-14c,binfiles-14f): Likewise.
+
+Sun May 5 17:38:21 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ Integrated changes submitted by Ian Taylor <ian@cygnus.com>
+
+ * update.c (update_dirent_proc): cvs co -p doesn't print
+ anything when run from an empty directory.
+
+ * import.c (import_descend_dir): Check for a file in the
+ repository which will be checked out to the same name as the
+ directory.
+
+Thu May 2 13:34:37 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.7.88
+
+Thu May 2 01:40:55 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * server.c (HAVE_INITGROUPS): Use initgroups() only if
+ located by configure, in the event a system has crypt(), but
+ no initgroups()
+
+Wed May 1 18:05:02 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basica): When testing rejection of reserved tag name,
+ use BASE instead of RESERVED.
+
+Wed May 1 15:15:11 1996 Tom Jarmolowski <tjj@booklink.com>
+
+ * rcs.c (linevector_delete): Only copy up to vec->nlines - nlines,
+ not to vec->nlines.
+
+Wed May 1 15:43:21 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcscmds.c (RCS_settag): Instead of reserving all tag names
+ containing only uppercase letters, reserve only BASE and HEAD.
+ * sanity.sh (mflag): Revert 26 Mar change; use all-uppercase tag
+ name again.
+
+Wed May 1 15:15:11 1996 Tom Jarmolowski <tjj@booklink.com>
+
+ * rcs.c (linevector_add): Move increment of i out of larger
+ statement, to avoid assumptions about evaluation order.
+
+Tue Apr 30 15:46:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * Version 1.7.87.
+
+ * server.c (check_password): Don't use ANSI string concatenation.
+ Reindent function.
+
+Wed Apr 24 17:27:53 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * vers_ts.c (Version_TS): xmalloc enough space (1 more
+ byte). Thanks to purify!
+
+Fri Apr 19 11:22:35 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * Version 1.7.86
+
+Thu Apr 18 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * client.c (try_read_from_server): Compare return value from fwrite
+ with a size_t not an int (Visual C++ lint).
+
+Wed Apr 17 11:56:32 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (try_read_from_server): New function.
+ (read_from_server): Use it.
+ (read_counted_file): New function.
+ * client.c, server.c: Add Template response.
+ * cvs.h (CVSADM_TEMPLATE): Added.
+ * logmsg.c (do_editor): If repository is NULL, use CVSADM_TEMPLATE
+ file in place of rcsinfo.
+ * server.c, server.h (server_template): New function.
+ * create_adm.c (Create_Admin): Call it.
+
+Tue Apr 16 13:56:06 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * repos.c (Name_Repository): Fix comments.
+ * create_adm.c (Create_Admin): Fix indentation.
+
+Wed Apr 10 16:46:54 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * options.h.in: Include relevant information here rather than
+ citing (former) FAQ.
+
+ * ChangeLog-9395: Fix typo in introductory paragraph.
+
+Wed Apr 10 14:55:10 1996 code by Mike Spengler mks@msc.edu
+ comments by Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * filesubr.c (unlink_file_dir,deep_remove_dir): Don't call unlink
+ on something which might be a directory; check using isdir instead.
+
+Wed Apr 10 14:55:10 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * checkout.c (build_dirs_and_chdir): Pass path, not cp, to
+ Create_Admin. The former is the correct update dir.
+ * sanity.sh (modules): New tests modules-155* test, for above fix.
+
+Mon Apr 8 13:53:27 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * rcs.c (annotate_fileproc): If the file is not under CVS control,
+ return instead of dumping a core. Don't bug on files with an empty
+ first revision.
+
+Fri Mar 29 16:08:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * rcs.c (annotate_fileproc): If last line of add-chunk is not
+ newline terminated, end the loop when we find that out.
+
+Fri Mar 29 16:59:34 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * rcs.c (annotate_fileproc): allow last line of add-chunk not to
+ be newline terminated
+
+Thu Mar 28 10:56:36 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ Add more diff tests:
+ * sanity.sh (basic2): Use dotest for test 61.
+ (basica): Add test basica-6.2.
+ (branches): Add tests branches-14.4 and branches-14.5.
+ (basic1): Remove tests 19, 20, 25, and 26. The only thing this
+ might miss out on is diff's interaction with added and removed
+ files, but those tests didn't test that very well anyway.
+
+ * rcs.c (RCS_getrevtime): Add comment regarding years after 1999.
+
+ * rcs.c: Add "cvs annotate" command and related code.
+ (getrcskey): Move special handling of RCSDESC from here to
+ callers. Handle those keys (desc, log, text) which do not
+ end in a semicolon.
+ * rcs.h (RCSVers): Add author field.
+ * rcs.c (RCS_reparsercsfile): Set it.
+ * cvs.h (annotate), main.c (cmd_usage, cmds), client.h client.c
+ (client_annotate), server.c (serve_annotate, requests): Usual
+ machinery to add a new command.
+ * sanity.sh (basica): Test cvs annotate.
+
+ * sanity.sh (branches): More tests, of things like adding files on
+ the trunk after a branch has been made.
+
+Tue Mar 26 09:48:49 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * expand_path.c: Don't declare free and xmalloc; cvs.h already
+ takes care of that.
+
+ * sanity.sh (mflag): Don't use tag name reserved to CVS.
+
+ NT local changes plus miscellaneous things noticed in the process:
+ * import.c (add_rcs_file): Use binary mode to write RCS file. Use
+ \012 where linefeed is intended. Copy data a small block at a
+ time, until we hit EOF, rather than trying to read the whole file
+ into memory at once.
+ * client.c (send_modified): Add comments regarding st_size.
+ * commit.c (commit): Add comments regarding binary mode and read().
+ * logmsg.c (do_editor): Add comments regarding st_size.
+ * server.c (server_updated): Use binary mode to read file we are
+ sending.
+
+ * rcscmds.c (RCS_settag): Complain if user tries to add a tag name
+ reserved to CVS.
+ * sanity.sh (basica): Test for this behavior.
+
+ * sanity.sh (binfiles): New tests test ability to change keyword
+ expansion.
+
+Mon Mar 25 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * cvs.h, filesubr.c (expand_wild): New function.
+ * recurse.c (start_recursion): Call expand_wild at beginning and
+ free its results at the end.
+ * cvs.h, subr.c (xrealloc): Make argument and return value void *.
+ * client.h, client.c (send_file_names): Add flags argument. If
+ SEND_EXPAND_WILD flag is passed, call expand_wild at beginning and
+ free its results at the end.
+ * admin.c, add.c, log.c, tag.c, status.c, edit.c, watch.c,
+ update.c, commit.c, remove.c, client.c, diff.c: Update callers.
+
+Fri Mar 22 10:09:55 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * error.c (error, fperror): Exit with status EXIT_FAILURE rather
+ than STATUS. We had been neglecting to check for 256, and the
+ value of providing a count of errors is probably minimal anyway.
+ * add.c, modules.c, mkmodules.c, tag.c, server.c, main.c,
+ import.c, client.c, scramble.c, recurse.c: Exit with status
+ EXIT_FAILURE rather than 1. On VMS, 1 is success, not failure.
+ * main.c (main): Return EXIT_FAILURE or 0. The value of providing
+ a count of errors is minimal.
+
+ * client.c (init_sockaddr): Exit with status 1 rather than
+ EXIT_FAILURE. The latter apparently doesn't exist on SunOS4.
+ Reindent function.
+
+Mon Mar 18 14:28:00 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * cvs.h, ignore.c: New variable ign_case.
+ * ignore.c (ign_name): If it is set, match in a case-insensitive
+ fashion.
+ * server.c (serve_case): New function.
+ (requests): Add Case request.
+ * client.c (start_server): If FILENAMES_CASE_INSENSITIVE is
+ defined, send Case request.
+
+Sat Mar 16 08:20:01 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ For reference, this change takes cvs's text segment from 315392
+ bytes to 311296 bytes (one 4096 byte page).
+ * cvs.h (struct file_info): Add fullname field.
+ * recurse.c (do_file_proc): Set it.
+ * commit.c (find_fileproc), client.c (send_fileproc), commit.c
+ (check_fileproc), diff.c (diff_fileproc), edit.c
+ (unedit_fileproc), patch.c (patch_fileproc), remove.c
+ (remove_fileproc), rtag.c (rtag_fileproc), tag.c (tag_fileproc),
+ update.c (update_fileproc), watch.c (watchers_fileproc): Use it
+ instead of computing it each time.
+ * diff.c (diff_fileproc), remove.c (remove_fileproc): Use fullname
+ where we had been (bogusly) omitting the directory from user
+ messages.
+ * edit.c (unedit_fileproc, edit_fileproc): If we cannot close
+ CVSADM_NOTIFY, mention CVSADM_NOTIFY rather than finfo->file in
+ error message.
+ * rtag.c (rtag_fileproc), tag.c (tag_fileproc): Reindent.
+
+Fri Mar 15 15:12:11 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * server.h: fix prototype of server_pause_check (was
+ server_check_pause)
+
+Thu Mar 14 1996 Jim Kingdon <kingdon@cyclic.com>
+
+ * vers_ts.c (Version_TS), entries.c (Scratch_Entry, AddEntryNode):
+ Change findnode to findnode_fn.
+
+ * main.c: Depending on HAVE_WINSOCK_H, include winsock.h or
+ declare gethostname.
+ * cvs.h: Don't declare it here.
+
+Thu Mar 14 07:06:59 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * commit.c (find_fileproc): If vn_user is NULL and ts_user is not,
+ print an error rather than silently succeeding.
+ * sanity.sh (basica-notadded): New test, for above fix.
+ (dotest_internal): New function.
+ (dotest,dotest_fail): Call it instead of duplicating code between
+ these two functions.
+
+ * sanity.sh: Skip tests binfiles-9 through binfiles-13 for remote.
+
+ * options.h.in: Adjust comment to reflect kfogel change.
+
+Thu Mar 14 01:38:30 1996 Karl Fogel <kfogel@floss.red-bean.com>
+
+ * options.h.in (AUTH_CLIENT_SUPPORT): turn on by default.
+
+Wed Mar 13 09:25:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (Version_TS): Don't try to override options from rcs
+ file if there isn't an rcs file (e.g. called from send_fileproc).
+ This fixes a bug detected by test 59 in "make remotecheck".
+
+ * rcs.c (RCS_reparsercsfile, RCS_getexpand): Assert that argument
+ is not NULL.
+
+ Fix a gcc -Wall warning:
+ * rcs.c, rcs.h (RCS_getexpand): New function.
+ * vers_ts.c (Version_TS): Call it.
+ * rcs.c (RCS_reparsercsfile): Make static.
+
+ Add a "cvs init" command. This is needed because cvsinit.sh
+ invoked mkmodules which doesn't exist any more.
+ * mkmodules.c: Break filelist out of mkmodules function, rename
+ struct _checkout_file to struct admin_file (for namespace
+ correctness), and add contents field.
+ (init,mkdir_if_needed): New functions.
+ * cvs.h (init): Declare.
+ * main.c (cmds): Add init.
+ (main): If command is init, don't require cvsroot to exist.
+ * client.c, client.h (client_init, send_init_command): New functions.
+ * client.c (start_server): Don't send Root request if command is init.
+ * server.c (serve_init): New function.
+ (requests): Add "init".
+
+Wed Mar 13 09:51:03 MET 1996 Norbert Kiesel <nk@col.sw-ley.de>
+
+ * vers_ts.c (Version_TS): set options to default option if the
+ file if no -k option but -A was given. This avoids the (wrong)
+ update message for binary files which are up-to-date when
+ running 'cvs -A'.
+
+ * update.c (checkout_file): remove test of -k option stored in the
+ file itself because it was moved to vers_ts.c
+
+ * sanity.sh: added tests for the above fix.
+
+Tue Mar 12 13:47:09 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c (findnode): Adjust comment regarding errors.
+
+ * hash.c (findnode, findnode_fn): Assert that key != NULL. This
+ way the check still happens even if the function is later
+ rewritten to not start out by calling hashp.
+
+Mon Mar 11 10:21:05 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh: If expr accepts multi-line patterns but is too
+ liberal in matching them, print a warning but keep going.
+
+ * sanity.sh: Add QUESTION variable, analogous to PLUS. Use it
+ instead of \? to match a question mark.
+
+ * cvs.h (CVSMODULE_OPTS, CVSMODULE_SPEC): Move from here...
+ * modules.c: ...to here. They are only used here and the code to
+ handle the syntax of modules files should not be scattered all over.
+ * modules.c (CVSMODULE_OPTS): Add "+" as first character.
+ * sanity.sh (modules): New tests 148a0 and 148a1 test for
+ above-fixed bug.
+
+Mon Mar 11 13:11:04 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * modules.c (cat_module): set optind to 0 to force getopt() to
+ reinitialize its internal nextchar
+
+Mon Mar 11 00:09:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * hash.c (findnode, findnode_fn): Revert changes of 7-8 Mar 1996.
+ The correct style is to assert() that key != NULL (see HACKING),
+ which is already done in the hashp function.
+ * fileattr.c (fileattr_delproc): Likewise, assert() that
+ node->data != NULL rather than trying to deal with it being NULL.
+
+Fri Mar 8 01:31:04 1996 Greg A. Woods <woods@most.weird.com>
+
+ * hash.c (findnode_fn): one more place to avoid calling hashp()
+ with a NULL key
+
+Thu Mar 7 17:30:01 1996 Greg A. Woods <woods@most.weird.com>
+
+ * hash.c (findnode): also return NULL if key is not set
+ [[ reported by Chris_Eich@optilink.optilink.dsccc.com, and
+ supposedly in a PR that should be marked "fixed"..... ]]
+
+ * fileattr.c (fileattr_set): set node->data to NULL after freeing
+ it to prevent subsequent accesses
+ (fileattr_delproc): don't free node->data if it's NULL, and set it
+ to NULL after freeing
+ [[ reported by Chris_Eich@optilink.optilink.dsccc.com, and
+ supposedly in a PR that should be marked "fixed"..... ]]
+
+Fri Mar 1 14:56:08 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * sanity.sh (basica): New test basica-4a tests for bug fixed by
+ sam@inf.enst.fr on 1 Mar 96.
+
+Fri Mar 1 18:10:49 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * tag.c (check_fileproc): Check for file existence before trying
+ to tag it.
+
+Fri Mar 1 07:51:29 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (update_entries): If command is export, set options to
+ NULL.
+
+Thu Feb 29 16:54:14 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * lock.c (write_lock, Reader_Lock): Remove
+ BOGUS_UNLESS_PROVEN_OTHERWISE code. It was pretty bogus, and has
+ been ifdeffed out for a long time.
+ * cvs.h (CVSTFL): Removed; no longer used.
+
+ * cvsrc.c, cvs.h (read_cvsrc): Pass in command name rather than
+ using global variable command_name.
+ * main.c (command_name): Initialize to "", not "cvs" so that error
+ messages don't say "cvs cvs". Update calls to read_cvsrc to pass
+ in command_name or "cvs" as appropriate.
+ * sanity.sh (basica): New test basica-9 tests for above-fixed bug.
+
+ * lock.c: Rename unlock to lock_simple_remove to avoid conflict
+ with builtin function on QNX.
+
+Thu Feb 29 17:02:22 1996 Samuel Tardieu <sam@inf.enst.fr>
+
+ * fileattr.c (fileattr_get): Removed NULL pointer dereference
+ which occurred in the absence of default attribute.
+
+Thu Feb 29 07:36:57 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ * rcs.c (RCS_isbranch, RCS_whatbranch): Remove no longer used file
+ argument, swap order of remaining two arguments to be like other
+ RCS_* functions.
+ (RCS_nodeisbranch): swap order of arguments to be like other RCS_*
+ functions.
+ * rcs.h (RCS_isbranch, RCS_whatbranch, RCS_nodeisbranch): Update
+ prototypes for above changes.
+ * commit.c, rtag.c, status.c, tag.c: Update for above calling
+ convention changes.
+
+Thu Feb 29 08:39:03 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * client.c (start_server): Revert changes which claimed to fall
+ back to a different way of connecting. Add comments explaining
+ why. (I don't think the changes did what they claimed, anyway).
+ Use indentation rather than comments to line up #if, #else, and
+ #endif.
+
+ * patch.c (patch, patch_fileproc): Revert change to add optional
+ arguments to -c and -u. Optional arguments are evil and in
+ violation of the POSIX argument syntax guidelines. The correct
+ way to do this is -C and -U. Also change DIFF back to "diff" in
+ output (see comments).
+
+ gcc -Wall lint:
+ * client.c (copy_a_file): Declare p inside the #ifdef in which is
+ it used.
+ * commit.c (remove_file): Remove unused variable p.
+ * commit.c (checkaddfile): Remove unused variables p.
+ * rcs.c (RCS_isbranch): Remove unused variable p.
+ * rcs.c: Remove unused declarations and definitions of
+ parse_rcs_proc, rcsnode_delproc, rcslist, and repository.
+ * rtag.c (rtag_fileproc): Remove unused variable p.
+ * patch.c (patch_fileproc): Remove unused variable p.
+ * tag.c (val_fileproc): Remove unused variable node.
+ * client.c, import.c, lock.c, server.c: Cast pid_t to long before
+ passing it to %ld.
+
+ * cvs.h: Don't prototype gethostname; merely declare it (on linux,
+ second argument is size_t not int).
+
+Thu Feb 29 10:29:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de>
+
+ * sanity.sh: added "cat > /dev/null" to loginfo entry to avoid the
+ SIGPIPE signal
+
+Thu Feb 29 10:28:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de>
+
+ * patch.c: added new variable diff_opt
+ (patch): allow optional parameter to -c and -u option, send it to
+ server
+ (patch_fileproc): cleaned up the code which prints the current
+ filename. For "-s" option, print the pathname relative to CVSROOT
+ instead of just the filename.
+
+ * filesubr.c (xchmod): added cast to shut up gcc
+
+ * cvs.h: added prototype for gethostname
+
+Thu Feb 29 10:27:25 MET 1996 Norbert Kiesel (nk) <nk@col.sw-ley.de>
+
+ * lock.c (write_lock), (Reader_Lock), import.c (update_rcs_file),
+ client.c (update_entries), (send_modified), server.c (server),
+ (receive_file), (server_updated): use %ld for printing pid_t
+ variables
+
+Thu Feb 29 02:22:12 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * run.c (run_exec): Added VMS return status support.
+
+Thu Feb 29 01:07:43 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * client.c (send_to_server): wrtn wasn't being declared under
+ VMS for some reason.
+
+Wed Feb 28 23:27:04 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * client.c: Changed #ifdef VMS && NO_SOCKET_TO_FD to
+ #if defined(VMS) && defined(NO_SOCKET_TO_FD)
+
+Wed Feb 28 22:28:43 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * build_src.com: Added DCL command procedure to build
+ and link CVS client for VMS.
+
+Wed Feb 28 22:07:20 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * client.c: VMS CVS client specific changes.
+
+ Added USE_DIRECT_TCP to allow CVS_PORT to be used to specify
+ a TCP connection port (no Kerberos). Changed
+ start_kerberos_server() to start_tcp_server().
+
+ In copy_a_file(): transform a backup file to have a
+ VMS-friendly name.
+
+ Added HAVE_CONFIG_H to include "config.h".
+
+ start_server() will starts the first successful of any
+ mutually exclusive methods of starting the CVS server
+ which might be enabled.
+
+ Initialized use_socket_style and server_sock for VMS in
+ start_server().
+
+Wed Feb 28 21:49:48 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * find_names.c, recurse.c, cvs.h: Changed Find_Dirs() to
+ Find_Directories().
+ * cvs.h: Added VMS filenames enabled through USE_VMS_FILENAMES
+ VMS POSIX will require to use the regular CVS filenames
+ while VMS is #define'd.
+
+Wed Feb 28 21:26:22 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * ignore.c: Added the patterns *.olb *.exe _$* *$ to default
+ ignore list for VMS.
+
+Wed Feb 28 13:32:28 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * logmsg.c (do_editor): Fix indentation.
+
+Wed Feb 28 12:56:49 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * logmsg.c (do_editor): If no editor is defined, exit and print
+ a message.
+
+Wed Feb 28 10:40:25 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+
+ * vers_ts.c (time_stamp, time_stamp_server): Reindent and revise
+ comments.
+
+Tue Feb 27 23:57:55 1996 Benjamin J. Lee <benjamin@cyclic.com>
+
+ * vers_ts.c: gmtime() returns NULL on some systems (VMS)
+ revert to local time via ctime() if GMT is not avaiable.
+
+Tue Feb 27 13:07:45 1996 J.T. Conklin <jtc@rtl.cygnus.com>
+
+ The changes listed below cause cvs to parse each rcs file (and
+ free the associated rcsnode after the file has been processed)
+ sequentially. cvs used to parse all files in a directory, an
+ approach that does not scale to huge repositories with lots
+ of revisions/branches/tags/etc.
+
+ * cvs.h (struct file_info): Removed srcfiles field. Added rcs
+ (node) field.
+ * recurse.c (do_recursion): Removed code that pre-parsed all
+ rcs files in the directory.
+ (do_file_proc): Parse current rcs file.
+ * rcs.c (RCS_parsefiles, parse_rcs_proc, RCS_addnode): Removed.
+ (RCS_isbranch, RCS_whatbranch): Changed srcfiles argument to
+ rcs (node).
+ * rcs.h (RCS_parsefiles, RCS_addnode): Removed prototypes.
+ (RCS_isbranch, RCS_whatbranch): Updated prototypes.
+ * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c,
+ commit.c, diff.c, history.c, import.c, log.c, patch.c, remove.c,
+ rtag.c, status.c, tag.c, update.c, vers_ts: Updated for above
+ calling convention / data structure changes.
+
Mon Feb 26 16:07:56 1996 Jim Kingdon <kingdon@harvey.cyclic.com>
+ * Version 1.7.3.
+
* Version 1.7.2.
Mon Feb 26 1996 Jim Kingdon <kingdon@cyclic.com>
diff --git a/gnu/usr.bin/cvs/src/ChangeLog-9395 b/gnu/usr.bin/cvs/src/ChangeLog-9395
index 9895149d650..c2d211198a1 100644
--- a/gnu/usr.bin/cvs/src/ChangeLog-9395
+++ b/gnu/usr.bin/cvs/src/ChangeLog-9395
@@ -3,7 +3,7 @@ during which changes which had been merged into the official CVS
(which produced releases such as 1.4A1 and 1.4A2) went into what has
become ChangeLog-9194, and changes which existed only at Cygnus went
into this file (ChangeLog-9395). Eventually the Cygnus release became
-Cyclic CVS (it is was then called), which became CVS 1.5, so probably
+Cyclic CVS (as it was then called), which became CVS 1.5, so probably
all the changes in both (what are now) ChangeLog-9194 and
ChangeLog-9395 made it into 1.5.
diff --git a/gnu/usr.bin/cvs/src/add.c b/gnu/usr.bin/cvs/src/add.c
index e481f2937ea..82efefe71ca 100644
--- a/gnu/usr.bin/cvs/src/add.c
+++ b/gnu/usr.bin/cvs/src/add.c
@@ -123,7 +123,7 @@ add (argc, argv)
free (date);
free (rcsdir);
}
- send_file_names (argc, argv);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, 0, 0);
send_to_server ("add\012", 0);
return get_responses_and_close ();
@@ -149,7 +149,7 @@ add (argc, argv)
}
vers = Version_TS (repository, options, (char *) NULL, (char *) NULL,
- user, 0, 0, entries, (List *) NULL);
+ user, 0, 0, entries, (RCSNode *) NULL);
if (vers->vn_user == NULL)
{
/* No entry available, ts_rcs is invalid */
@@ -466,7 +466,7 @@ add_directory (repository, dir)
(void) printf ("%s", message);
out:
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
return (0);
}
diff --git a/gnu/usr.bin/cvs/src/admin.c b/gnu/usr.bin/cvs/src/admin.c
index c7aa719e18b..214318af9c1 100644
--- a/gnu/usr.bin/cvs/src/admin.c
+++ b/gnu/usr.bin/cvs/src/admin.c
@@ -91,7 +91,7 @@ admin (argc, argv)
for (i = 0; i <= ac; ++i) /* XXX send -ko too with i = 0 */
send_arg (av[i]);
- send_file_names (argc, argv);
+ 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. */
@@ -124,7 +124,7 @@ admin_fileproc (finfo)
int status = 0;
vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL, (char *) NULL,
- finfo->file, 0, 0, finfo->entries, finfo->srcfiles);
+ finfo->file, 0, 0, finfo->entries, finfo->rcs);
version = vers->vn_user;
if (version == NULL)
diff --git a/gnu/usr.bin/cvs/src/checkin.c b/gnu/usr.bin/cvs/src/checkin.c
index 2e5b284892a..e1ce9cbcbde 100644
--- a/gnu/usr.bin/cvs/src/checkin.c
+++ b/gnu/usr.bin/cvs/src/checkin.c
@@ -118,7 +118,7 @@ Checkin (type, file, update_dir, repository,
/* re-register with the new data */
vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL,
- file, 1, set_time, entries, (List *) NULL);
+ file, 1, set_time, entries, (RCSNode *) NULL);
if (strcmp (vers->options, "-V4") == 0)
vers->options[0] = '\0';
Register (entries, file, vers->vn_rcs, vers->ts_user,
diff --git a/gnu/usr.bin/cvs/src/checkout.c b/gnu/usr.bin/cvs/src/checkout.c
index 005a73f91dd..64aa10e247e 100644
--- a/gnu/usr.bin/cvs/src/checkout.c
+++ b/gnu/usr.bin/cvs/src/checkout.c
@@ -779,7 +779,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten,
user = argv[i];
vers = Version_TS (repository, options, tag, date, user,
- force_tag_match, 0, entries, (List *) NULL);
+ force_tag_match, 0, entries, (RCSNode *) NULL);
if (vers->ts_user == NULL)
{
line = xmalloc (strlen (user) + 15);
@@ -863,7 +863,7 @@ build_dirs_and_chdir (dir, prepath, realdir, sticky)
/* I'm not sure whether this check is redundant. */
if (!isdir (repository))
error (1, 0, "there is no repository %s", repository);
- Create_Admin (".", cp, repository, sticky ? (char *) NULL : tag,
+ Create_Admin (".", path, repository, sticky ? (char *) NULL : tag,
sticky ? (char *) NULL : date);
if (!noexec)
{
diff --git a/gnu/usr.bin/cvs/src/classify.c b/gnu/usr.bin/cvs/src/classify.c
index 9e18309332f..924314b2099 100644
--- a/gnu/usr.bin/cvs/src/classify.c
+++ b/gnu/usr.bin/cvs/src/classify.c
@@ -22,7 +22,7 @@ static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entri
*/
Ctype
Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
- entries, srcfiles, versp, update_dir, pipeout)
+ entries, rcsnode, versp, update_dir, pipeout)
char *file;
char *tag;
char *date;
@@ -31,7 +31,7 @@ Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
int aflag;
char *repository;
List *entries;
- List *srcfiles;
+ RCSNode *rcsnode;
Vers_TS **versp;
char *update_dir;
int pipeout;
@@ -48,7 +48,7 @@ Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
/* get all kinds of good data about the file */
vers = Version_TS (repository, options, tag, date, file,
- force_tag_match, 0, entries, srcfiles);
+ force_tag_match, 0, entries, rcsnode);
if (vers->vn_user == NULL)
{
diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c
index d49a239f6b5..c0557ce6fee 100644
--- a/gnu/usr.bin/cvs/src/client.c
+++ b/gnu/usr.bin/cvs/src/client.c
@@ -1,5 +1,9 @@
/* CVS client-related stuff. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include "cvs.h"
#include "getline.h"
#include "edit.h"
@@ -8,23 +12,24 @@
#include "md5.h"
-#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS
-#ifdef HAVE_WINSOCK_H
-#include <winsock.h>
-#else /* No winsock.h */
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#endif /* No winsock.h */
-#endif /* defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS */
+#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# else /* No winsock.h */
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netdb.h>
+# endif /* No winsock.h */
+#endif /* defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS || USE_DIRECT_TCP */
#ifdef AUTH_CLIENT_SUPPORT
char *get_cvs_password PROTO((char *user, char *host, char *cvsrooot));
#endif /* AUTH_CLIENT_SUPPORT */
-#if HAVE_KERBEROS
+#if HAVE_KERBEROS || USE_DIRECT_TCP
#define CVS_PORT 1999
+#if HAVE_KERBEROS
#include <krb.h>
extern char *krb_realmofhost ();
@@ -33,6 +38,7 @@ extern char *krb_realmofhost ();
#endif /* HAVE_KRB_GET_ERR_TEXT */
#endif /* HAVE_KERBEROS */
+#endif /* HAVE_KERBEROS || USE_DIRECT_TCP */
static void add_prune_candidate PROTO((char *));
@@ -77,6 +83,7 @@ static void handle_m PROTO((char *, int));
static void handle_e PROTO((char *, int));
static void handle_notified PROTO((char *, int));
+static size_t try_read_from_server PROTO ((char *, size_t));
#endif /* CLIENT_SUPPORT */
#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT)
@@ -890,8 +897,18 @@ copy_a_file (data, ent_list, short_pathname, filename)
char *filename;
{
char *newname;
+#ifdef USE_VMS_FILENAMES
+ char *p;
+#endif
read_line (&newname, 0);
+
+#ifdef USE_VMS_FILENAMES
+ /* Mogrify the filename so VMS is happy with it. */
+ for(p = newname; *p; p++)
+ if(*p == '.' || *p == '#') *p = '_';
+#endif
+
copy_file (filename, newname);
free (newname);
}
@@ -904,6 +921,86 @@ handle_copy_file (args, len)
call_in_directory (args, copy_a_file, (char *)NULL);
}
+
+static void read_counted_file PROTO ((char *, char *));
+
+/* Read from the server the count for the length of a file, then read
+ the contents of that file and write them to FILENAME. FULLNAME is
+ the name of the file for use in error messages. FIXME-someday:
+ extend this to deal with compressed files and make update_entries
+ use it. On error, gives a fatal error. */
+static void
+read_counted_file (filename, fullname)
+ char *filename;
+ char *fullname;
+{
+ char *size_string;
+ size_t size;
+ char *buf;
+
+ /* Pointers in buf to the place to put data which will be read,
+ and the data which needs to be written, respectively. */
+ char *pread;
+ char *pwrite;
+ /* Number of bytes left to read and number of bytes in buf waiting to
+ be written, respectively. */
+ size_t nread;
+ size_t nwrite;
+
+ FILE *fp;
+
+ read_line (&size_string, 0);
+ if (size_string[0] == 'z')
+ error (1, 0, "\
+protocol error: compressed files not supported for that operation");
+ /* FIXME: should be doing more error checking, probably. Like using
+ strtoul and making sure we used up the whole line. */
+ size = atoi (size_string);
+ free (size_string);
+
+ /* A more sophisticated implementation would use only a limited amount
+ of buffer space (8K perhaps), and read that much at a time. We allocate
+ a buffer for the whole file only to make it easy to keep track what
+ needs to be read and written. */
+ buf = xmalloc (size);
+
+ /* FIXME-someday: caller should pass in a flag saying whether it
+ is binary or not. I haven't carefully looked into whether
+ CVS/Template files should use local text file conventions or
+ not. */
+ fp = fopen (filename, "wb");
+ if (fp == NULL)
+ error (1, errno, "cannot write %s", fullname);
+ nread = size;
+ nwrite = 0;
+ pread = buf;
+ pwrite = buf;
+ while (nread > 0 || nwrite > 0)
+ {
+ size_t n;
+
+ if (nread > 0)
+ {
+ n = try_read_from_server (pread, nread);
+ nread -= n;
+ pread += n;
+ nwrite += n;
+ }
+
+ if (nwrite > 0)
+ {
+ n = fwrite (pwrite, 1, nwrite, fp);
+ if (ferror (fp))
+ error (1, errno, "cannot write %s", fullname);
+ nwrite -= n;
+ pwrite += n;
+ }
+ }
+ free (buf);
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", fullname);
+}
+
/*
* The Checksum response gives the checksum for the file transferred
* over by the next Updated, Merged or Patch response. We just store
@@ -1059,6 +1156,15 @@ update_entries (data_arg, ent_list, short_pathname, filename)
else if (*tag_or_date == 'D')
date = tag_or_date + 1;
}
+ else
+ /* For cvs export, assume it is a text file. FIXME: This is
+ broken behavior--we should be having the server tell us
+ whether it is text or binary and dealing accordingly. I
+ think maybe we can parse the entries line, get the options,
+ and then ignore the entries line otherwise, but I haven't
+ checked to see whether the server sends the entries line
+ correctly in this case. */
+ options = NULL;
if (data->contents == UPDATE_ENTRIES_UPDATE
|| data->contents == UPDATE_ENTRIES_PATCH)
@@ -1088,11 +1194,17 @@ update_entries (data_arg, ent_list, short_pathname, filename)
free (size_string);
temp_filename = xmalloc (strlen (filename) + 80);
+#ifdef USE_VMS_FILENAMES
+ /* A VMS rename of "blah.dat" to "foo" to implies a
+ destination of "foo.dat" which is unfortinate for CVS */
+ sprintf (temp_filename, "%s_new_", filename);
+#else
#ifdef _POSIX_NO_TRUNC
sprintf (temp_filename, ".new.%.9s", filename);
#else /* _POSIX_NO_TRUNC */
sprintf (temp_filename, ".new.%s", filename);
#endif /* _POSIX_NO_TRUNC */
+#endif /* USE_VMS_FILENAMES */
buf = xmalloc (size);
/* Some systems, like OS/2 and Windows NT, end lines with CRLF
@@ -1102,12 +1214,10 @@ update_entries (data_arg, ent_list, short_pathname, filename)
flag, then we don't want to convert, else we do (because
CVS assumes text files by default). */
- /* Actually, I don't believe options can be NULL here, but I'm
- not dead certain of that. */
- if (options)
- bin = !(strcmp (options, "-kb"));
- else
- bin = 0;
+ if (options)
+ bin = !(strcmp (options, "-kb"));
+ else
+ bin = 0;
fd = open (temp_filename,
O_WRONLY | O_CREAT | O_TRUNC | (bin ? OPEN_BINARY : 0),
@@ -1132,7 +1242,8 @@ update_entries (data_arg, ent_list, short_pathname, filename)
if (gzip_pid > 0)
{
if (waitpid (gzip_pid, &gzip_status, 0) == -1)
- error (1, errno, "waiting for gzip process %d", gzip_pid);
+ error (1, errno, "waiting for gzip process %ld",
+ (long) gzip_pid);
else if (gzip_status != 0)
error (1, 0, "gzip process exited %d", gzip_status);
}
@@ -1608,6 +1719,32 @@ handle_clear_sticky (pathname, len)
call_in_directory (pathname, clear_sticky, (char *)NULL);
}
+
+static void template PROTO ((char *, List *, char *, char *));
+
+static void
+template (data, ent_list, short_pathname, filename)
+ char *data;
+ List *ent_list;
+ char *short_pathname;
+ char *filename;
+{
+ /* FIXME: should be computing second argument from CVSADM_TEMPLATE
+ and short_pathname. */
+ read_counted_file (CVSADM_TEMPLATE, "<CVS/Template file>");
+}
+
+static void handle_template PROTO ((char *, int));
+
+static void
+handle_template (pathname, len)
+ char *pathname;
+ int len;
+{
+ call_in_directory (pathname, template, NULL);
+}
+
+
struct save_prog {
char *name;
char *dir;
@@ -1618,7 +1755,7 @@ static struct save_prog *checkin_progs;
static struct save_prog *update_progs;
/*
- * Unlike some requests this doesn't include the repository. So we can't
+ * Unlike some responses this doesn't include the repository. So we can't
* just call call_in_directory and have the right thing happen; we save up
* the requests and do them at the end.
*/
@@ -2134,7 +2271,7 @@ client_send_expansions (local)
cleaner if we genuinely expanded module names, all the way to a
local directory and repository, but that isn't the way it works
now. */
- send_file_names (module_argc, module_argv);
+ send_file_names (module_argc, module_argv, 0);
for (i = 0; i < modules_count; ++i)
{
@@ -2207,6 +2344,8 @@ struct response responses[] =
rs_optional),
RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal,
rs_optional),
+ RSP_LINE("Template", handle_template, response_type_normal,
+ rs_optional),
RSP_LINE("Set-checkin-prog", handle_set_checkin_prog, response_type_normal,
rs_optional),
RSP_LINE("Set-update-prog", handle_set_update_prog, response_type_normal,
@@ -2245,17 +2384,23 @@ send_to_server (str, len)
int just_wrtn = 0;
size_t wrtn = 0;
+#ifdef VMS
+ /* send() blocks under VMS */
+ if (send (server_sock, str + wrtn, len - wrtn, 0) < 0)
+ error (1, errno, "writing to server socket");
+#else /* VMS */
while (wrtn < len)
{
just_wrtn = send (server_sock, str + wrtn, len - wrtn, 0);
if (just_wrtn == -1)
- error (1, errno, "reading from server socket");
+ error (1, errno, "writing to server socket");
wrtn += just_wrtn;
if (wrtn == len)
break;
}
+#endif /* VMS */
}
else
#endif /* NO_SOCKET_TO_FD */
@@ -2281,58 +2426,61 @@ send_to_server (str, len)
error (0, errno, "writing to to-server logfile");
}
-/*
- * Read LEN bytes from the server or die trying.
- */
-void
-read_from_server (buf, len)
- char *buf;
- size_t len;
+/* Read up to LEN bytes from the server. Returns actual number of bytes
+ read. Gives a fatal error on EOF or error. */
+static size_t
+try_read_from_server (buf, len)
+ char *buf;
+ size_t len;
{
+ int nread;
+
#ifdef NO_SOCKET_TO_FD
- if (use_socket_style)
+ if (use_socket_style)
{
- int just_red = 0;
- size_t red = 0;
+ nread = recv (server_sock, buf, len, 0);
+ if (nread == -1)
+ error (1, errno, "reading from server");
+ }
+ else
+#endif
+ {
+ nread = fread (buf, 1, len, from_server);
+ if (ferror (from_server))
+ error (1, errno, "reading from server");
+ if (feof (from_server))
+ error (1, 0,
+ "end of file from server (consult above messages if any)");
+ }
- while (red < len)
- {
- just_red = recv (server_sock, buf + red, len - red, 0);
+ /* Log, if that's what we're doing. */
+ if (from_server_logfile != NULL && nread > 0)
+ {
+ size_t towrite = nread;
+ if (fwrite (buf, 1, towrite, from_server_logfile) < towrite)
+ error (0, errno, "writing to from-server logfile");
+ }
- if (just_red == -1)
- error (1, errno, "reading from server");
+ return nread;
+}
- red += just_red;
- if (red == len)
- break;
- }
- }
- else
-#endif /* NO_SOCKET_TO_FD */
+/*
+ * Read LEN bytes from the server or die trying.
+ */
+void
+read_from_server (buf, len)
+ char *buf;
+ size_t len;
+{
+ size_t red = 0;
+ while (red < len)
{
- size_t red = 0;
-
- while (red < len)
- {
- red += fread (buf + red, 1, len - red, from_server);
-
- if (red == len)
- break;
-
- if (ferror (from_server))
- error (1, errno, "reading from server");
- if (feof (from_server))
- error (1, 0, "end of file from server (consult above messages if any)");
- }
+ red += try_read_from_server (buf + red, len - red);
+ if (red == len)
+ break;
}
-
- /* Log, if that's what we're doing. */
- if (from_server_logfile)
- if (fwrite (buf, 1, len, from_server_logfile) < len)
- error (0, errno, "writing to from-server logfile");
}
-
/*
* Get some server responses and process them. Returns nonzero for
* error, 0 for success. */
@@ -2406,7 +2554,7 @@ get_responses_and_close ()
else
#endif /* NO_SOCKET_TO_FD */
{
-#if defined(HAVE_KERBEROS) || defined(AUTH_CLIENT_SUPPORT)
+#if defined(HAVE_KERBEROS) || defined(USE_DIRECT_TCP) || defined(AUTH_CLIENT_SUPPORT)
if (server_fd != -1)
{
if (shutdown (server_fd, 1) < 0)
@@ -2423,7 +2571,7 @@ get_responses_and_close ()
}
}
else
-#endif /* HAVE_KERBEROS || AUTH_CLIENT_SUPPORT */
+#endif /* HAVE_KERBEROS || USE_DIRECT_TCP || AUTH_CLIENT_SUPPORT */
#ifdef SHUTDOWN_SERVER
SHUTDOWN_SERVER (fileno (to_server));
@@ -2482,22 +2630,22 @@ supported_request (name)
#ifdef AUTH_CLIENT_SUPPORT
void
init_sockaddr (name, hostname, port)
- struct sockaddr_in *name;
- const char *hostname;
- unsigned short int port;
+ struct sockaddr_in *name;
+ const char *hostname;
+ unsigned short int port;
{
- struct hostent *hostinfo;
-
- memset (name, 0, sizeof (*name));
- name->sin_family = AF_INET;
- name->sin_port = htons (port);
- hostinfo = gethostbyname (hostname);
- if (hostinfo == NULL)
+ struct hostent *hostinfo;
+
+ memset (name, 0, sizeof (*name));
+ name->sin_family = AF_INET;
+ name->sin_port = htons (port);
+ hostinfo = gethostbyname (hostname);
+ if (hostinfo == NULL)
{
- fprintf (stderr, "Unknown host %s.\n", hostname);
- exit (EXIT_FAILURE);
+ fprintf (stderr, "Unknown host %s.\n", hostname);
+ exit (EXIT_FAILURE);
}
- name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
+ name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
}
@@ -2538,7 +2686,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only)
if (sock == -1)
{
fprintf (stderr, "socket() failed\n");
- exit (1);
+ exit (EXIT_FAILURE);
}
port_number = auth_server_port_number ();
init_sockaddr (&client_sai, server_host, port_number);
@@ -2672,7 +2820,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only)
#endif /* AUTH_CLIENT_SUPPORT */
-#if HAVE_KERBEROS
+#if HAVE_KERBEROS || USE_DIRECT_TCP
/*
* FIXME: this function has not been changed to deal with
@@ -2682,19 +2830,24 @@ connect_to_pserver (tofdp, fromfdp, verify_only)
* have to make take care of this.
*/
void
-start_kerberos_server (tofdp, fromfdp)
+start_tcp_server (tofdp, fromfdp)
int *tofdp, *fromfdp;
{
int tofd, fromfd;
struct hostent *hp;
char *hname;
- const char *realm;
const char *portenv;
int port;
struct sockaddr_in sin;
int s;
+
+
+#if HAVE_KERBEROS
KTEXT_ST ticket;
+ const char *realm;
+#endif /* HAVE_KERBEROS */
+
int status;
/*
@@ -2711,14 +2864,19 @@ start_kerberos_server (tofdp, fromfdp)
hname = xmalloc (strlen (hp->h_name) + 1);
strcpy (hname, hp->h_name);
+#if HAVE_KERBEROS
realm = krb_realmofhost (hname);
+#endif /* HAVE_KERBEROS */
+ /* Get CVS_CLIENT_PORT or look up cvs/tcp with CVS_PORT as default */
portenv = getenv ("CVS_CLIENT_PORT");
if (portenv != NULL)
{
port = atoi (portenv);
if (port <= 0)
goto try_rsh_no_message;
+ if (trace)
+ fprintf(stderr, "Using TCP port %d to contact server.\n", port);
port = htons (port);
}
else
@@ -2750,11 +2908,12 @@ start_kerberos_server (tofdp, fromfdp)
tofd = -1;
if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
{
- error (0, errno, "kerberos connect");
+ error (0, errno, "connect");
close (s);
}
else
{
+#ifdef HAVE_KERBEROS
struct sockaddr_in laddr;
int laddrlen;
MSG_DAT msg_data;
@@ -2776,14 +2935,23 @@ start_kerberos_server (tofdp, fromfdp)
}
else
{
+#endif /* HAVE_KERBEROS */
+
server_fd = s;
close_on_exec (server_fd);
tofd = fromfd = s;
+
+#ifdef HAVE_KERBEROS
}
+#endif /* HAVE_KERBEROS */
}
if (tofd == -1)
{
+ /* FIXME: Falling back like this is slow and we should probably
+ just make it a fatal error (so that people use the right
+ environment variables or, when we get around to implementing
+ the right ones, access methods). */
error (0, 0, "trying to start server using rsh");
try_rsh_no_message:
server_fd = -1;
@@ -2803,7 +2971,7 @@ start_kerberos_server (tofdp, fromfdp)
*fromfdp = fromfd;
}
-#endif /* HAVE_KERBEROS */
+#endif /* HAVE_KERBEROS || USE_DIRECT_TCP */
static int send_variable_proc PROTO ((Node *, void *));
@@ -2827,6 +2995,11 @@ start_server ()
int tofd, fromfd;
char *log = getenv ("CVS_CLIENT_LOG");
+ /* Note that generally speaking we do *not* fall back to a different
+ way of connecting if the first one does not work. This is slow
+ (*really* slow on a 14.4kbps link); the clean way to have a CVS
+ which supports several ways of connecting is with access methods. */
+
/* Init these to NULL. They will be set later if logging is on. */
from_server_logfile = (FILE *) NULL;
to_server_logfile = (FILE *) NULL;
@@ -2841,23 +3014,28 @@ start_server ()
else
#endif /* AUTH_CLIENT_SUPPORT */
{
-#if HAVE_KERBEROS
- start_kerberos_server (&tofd, &fromfd);
-#else /* ! HAVE_KERBEROS */
+#if HAVE_KERBEROS || USE_DIRECT_TCP
+ start_tcp_server (&tofd, &fromfd);
+#else
-#if ! RSH_NOT_TRANSPARENT
+# if ! RSH_NOT_TRANSPARENT
start_rsh_server (&tofd, &fromfd);
-#else /* RSH_NOT_TRANSPARENT */
+# else
-#if defined(START_SERVER)
+# if defined(START_SERVER)
START_SERVER (&tofd, &fromfd, getcaller (),
server_user, server_host, server_cvsroot);
-#endif /* defined(START_SERVER) */
-
-#endif /* ! RSH_NOT_TRANSPARENT */
-#endif /* HAVE_KERBEROS */
+# endif
+# endif
+#endif
}
+#if defined(VMS) && defined(NO_SOCKET_TO_FD)
+ /* Avoid mixing sockets with stdio */
+ use_socket_style = 1;
+ server_sock = tofd;
+#endif /* VMS && NO_SOCKET_TO_FD */
+
/* "Hi, I'm Darlene and I'll be your server tonight..." */
server_started = 1;
@@ -2927,9 +3105,12 @@ start_server ()
stored_checksum_valid = 0;
stored_mode_valid = 0;
- send_to_server ("Root ", 0);
- send_to_server (server_cvsroot, 0);
- send_to_server ("\012", 1);
+ if (strcmp (command_name, "init") != 0)
+ {
+ send_to_server ("Root ", 0);
+ send_to_server (server_cvsroot, 0);
+ send_to_server ("\012", 1);
+ }
{
struct response *rs;
@@ -2946,7 +3127,7 @@ start_server ()
send_to_server ("valid-requests\012", 0);
if (get_server_responses ())
- exit (1);
+ exit (EXIT_FAILURE);
/*
* Now handle global options.
@@ -3043,10 +3224,16 @@ start_server ()
gzip_level = 0;
}
}
+
+#ifdef FILENAMES_CASE_INSENSITIVE
+ if (supported_request ("Case"))
+ send_to_server ("Case\012", 0);
+#endif
+
/* If "Set" is not supported, just silently fail to send the variables.
Users with an old server should get a useful error message when it
fails to recognize the ${=foo} syntax. This way if someone uses
- several server, some of which are new and some old, they can still
+ several servers, some of which are new and some old, they can still
set user variables in their .cvsrc without trouble. */
if (supported_request ("Set"))
walklist (variable_list, send_variable_proc, NULL);
@@ -3333,6 +3520,10 @@ send_modified (file, short_pathname, vers)
#endif /* LINES_CRLF_TERMINATED */
fd = filter_through_gzip (fd, 1, gzip_level, &gzip_pid);
+
+ /* FIXME: is there any reason to go through all this realloc'ing
+ when we could just be writing the data to the network as we read
+ it from gzip? */
while (1)
{
if ((bufp - buf) + readsize >= bufsize)
@@ -3360,7 +3551,7 @@ send_modified (file, short_pathname, vers)
error (0, errno, "warning: can't close %s", short_pathname);
if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid)
- error (1, errno, "waiting for gzip proc %d", gzip_pid);
+ error (1, errno, "waiting for gzip proc %ld", (long) gzip_pid);
else if (gzip_status != 0)
error (1, errno, "gzip exited %d", gzip_status);
@@ -3395,6 +3586,11 @@ send_modified (file, short_pathname, vers)
char *bufp = buf;
int len;
+ /* FIXME: This is gross. It assumes that we might read
+ less than st_size bytes (true on NT), but not more.
+ Instead of this we should just be reading a block of
+ data (e.g. 8192 bytes), writing it to the network, and
+ so on until EOF. */
while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0)
bufp += len;
@@ -3437,18 +3633,12 @@ send_fileproc (finfo)
struct file_info *finfo;
{
Vers_TS *vers;
- int update_dir_len = strlen (finfo->update_dir);
- char *short_pathname = xmalloc (update_dir_len + strlen (finfo->file) + 40);
- strcpy (short_pathname, finfo->update_dir);
- if (finfo->update_dir[0] != '\0')
- strcat (short_pathname, "/");
- strcat (short_pathname, finfo->file);
send_a_repository ("", finfo->repository, finfo->update_dir);
vers = Version_TS ((char *)NULL, (char *)NULL, (char *)NULL,
(char *)NULL,
- finfo->file, 0, 0, finfo->entries, (List *)NULL);
+ finfo->file, 0, 0, finfo->entries, (RCSNode *)NULL);
if (vers->vn_user != NULL)
{
@@ -3505,7 +3695,7 @@ send_fileproc (finfo)
else if (vers->ts_rcs == NULL
|| strcmp (vers->ts_user, vers->ts_rcs) != 0)
{
- send_modified (finfo->file, short_pathname, vers);
+ send_modified (finfo->file, finfo->fullname, vers);
}
else
{
@@ -3530,7 +3720,6 @@ send_fileproc (finfo)
}
freevers_ts (&vers);
- free (short_pathname);
return 0;
}
@@ -3664,9 +3853,10 @@ send_option_string (string)
/* Send the names of all the argument files to the server. */
void
-send_file_names (argc, argv)
+send_file_names (argc, argv, flags)
int argc;
char **argv;
+ unsigned int flags;
{
int i;
char *p;
@@ -3674,6 +3864,11 @@ send_file_names (argc, argv)
int level;
int max_level;
+ /* The fact that we do this here as well as start_recursion is a bit
+ of a performance hit. Perhaps worth cleaning up someday. */
+ if (flags & SEND_EXPAND_WILD)
+ expand_wild (argc, argv, &argc, &argv);
+
/* Send Max-dotdot if needed. */
max_level = 0;
for (i = 0; i < argc; ++i)
@@ -3746,6 +3941,14 @@ send_file_names (argc, argv)
}
send_to_server ("\012", 1);
}
+
+ if (flags & SEND_EXPAND_WILD)
+ {
+ int i;
+ for (i = 0; i < argc; ++i)
+ free (argv[i]);
+ free (argv);
+ }
}
@@ -3775,7 +3978,7 @@ send_files (argc, argv, local, aflag)
send_dirent_proc, (DIRLEAVEPROC)NULL,
argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0, 0);
if (err)
- exit (1);
+ exit (EXIT_FAILURE);
if (toplevel_repos == NULL)
/*
* This happens if we are not processing any files,
@@ -4256,4 +4459,32 @@ client_unedit (argc, argv)
return unedit (argc, argv); /* Call real code */
}
+void
+send_init_command ()
+{
+ /* This is here because we need the server_cvsroot variable. */
+ send_to_server ("init ", 0);
+ send_to_server (server_cvsroot, 0);
+ send_to_server ("\012", 0);
+}
+
+int
+client_init (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+
+ return init (argc, argv); /* Call real code */
+}
+
+int
+client_annotate (argc, argv)
+ int argc;
+ char **argv;
+{
+ parse_cvsroot ();
+
+ return annotate (argc, argv); /* Call real code */
+}
#endif /* CLIENT_SUPPORT */
diff --git a/gnu/usr.bin/cvs/src/client.h b/gnu/usr.bin/cvs/src/client.h
index a8011ac3a99..b238c322b09 100644
--- a/gnu/usr.bin/cvs/src/client.h
+++ b/gnu/usr.bin/cvs/src/client.h
@@ -35,6 +35,8 @@ extern int client_watchers PROTO((int argc, char **argv));
extern int client_editors PROTO((int argc, char **argv));
extern int client_edit PROTO((int argc, char **argv));
extern int client_unedit PROTO((int argc, char **argv));
+extern int client_init PROTO ((int argc, char **argv));
+extern int client_annotate PROTO ((int argc, char **argv));
/*
* Flag variable for seeing whether common code is running as a client
@@ -82,7 +84,11 @@ start_server PROTO((void));
/* Send the names of all the argument files to the server. */
void
-send_file_names PROTO((int argc, char **argv));
+send_file_names PROTO((int argc, char **argv, unsigned int flags));
+
+/* Flags for send_file_names. */
+/* Expand wild cards? */
+#define SEND_EXPAND_WILD 1
/*
* Send Repository, Modified and Entry. argc and argv contain only
@@ -170,6 +176,8 @@ extern void client_senddate PROTO((const char *date));
extern void client_expand_modules PROTO((int argc, char **argv, int local));
extern void client_send_expansions PROTO((int local));
extern void client_nonexpanded_setup PROTO((void));
+
+extern void send_init_command PROTO ((void));
extern char **failed_patches;
extern int failed_patches_count;
diff --git a/gnu/usr.bin/cvs/src/create_adm.c b/gnu/usr.bin/cvs/src/create_adm.c
index d7ee2dc6f6c..fd7fd4d7c0b 100644
--- a/gnu/usr.bin/cvs/src/create_adm.c
+++ b/gnu/usr.bin/cvs/src/create_adm.c
@@ -29,14 +29,14 @@ Create_Admin (dir, update_dir, repository, tag, date)
#ifdef SERVER_SUPPORT
if (trace)
- {
+ {
char wd[PATH_MAX];
getwd (wd);
fprintf (stderr, "%c-> Create_Admin (%s, %s, %s, %s, %s) in %s\n",
(server_active) ? 'S' : ' ',
dir, update_dir, repository, tag ? tag : "",
date ? date : "", wd);
- }
+ }
#endif
if (noexec)
@@ -125,13 +125,16 @@ Create_Admin (dir, update_dir, repository, tag, date)
#ifdef SERVER_SUPPORT
if (server_active)
- server_set_sticky (update_dir, repository, tag, date);
+ {
+ server_set_sticky (update_dir, repository, tag, date);
+ server_template (update_dir, repository);
+ }
if (trace)
- {
+ {
fprintf (stderr, "%c<- Create_Admin\n",
(server_active) ? 'S' : ' ');
- }
+ }
#endif
}
diff --git a/gnu/usr.bin/cvs/src/cvsrc.c b/gnu/usr.bin/cvs/src/cvsrc.c
index 1d2946912b5..140ce1c1f11 100644
--- a/gnu/usr.bin/cvs/src/cvsrc.c
+++ b/gnu/usr.bin/cvs/src/cvsrc.c
@@ -23,10 +23,14 @@ char cvsrc[] = CVSRC_FILENAME;
extern char *strtok ();
+/* Read cvsrc, processing options matching CMDNAME ("cvs" for global
+ options, and update *ARGC and *ARGV accordingly. */
+
void
-read_cvsrc (argc, argv)
- int *argc;
- char ***argv;
+read_cvsrc (argc, argv, cmdname)
+ int *argc;
+ char ***argv;
+ char *cmdname;
{
char *homedir;
char *homeinit;
@@ -81,7 +85,7 @@ read_cvsrc (argc, argv)
line = NULL;
line_chars_allocated = 0;
- command_len = strlen (command_name);
+ command_len = strlen (cmdname);
cvsrcfile = open_file (homeinit, "r");
while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile))
>= 0)
@@ -91,7 +95,7 @@ read_cvsrc (argc, argv)
continue;
/* stop if we match the current command */
- if (!strncmp (line, command_name, command_len)
+ if (!strncmp (line, cmdname, command_len)
&& isspace (*(line + command_len)))
{
found = 1;
diff --git a/gnu/usr.bin/cvs/src/diff.c b/gnu/usr.bin/cvs/src/diff.c
index ffe2a3d5c57..7520cec4a92 100644
--- a/gnu/usr.bin/cvs/src/diff.c
+++ b/gnu/usr.bin/cvs/src/diff.c
@@ -20,7 +20,7 @@ static Dtype diff_dirproc PROTO((char *dir, char *pos_repos, char *update_dir));
static int diff_filesdoneproc PROTO((int err, char *repos, char *update_dir));
static int diff_dirleaveproc PROTO((char *dir, int err, char *update_dir));
static int diff_file_nodiff PROTO((char *file, char *repository, List *entries,
- List *srcfiles, Vers_TS *vers));
+ RCSNode *rcs, Vers_TS *vers));
static int diff_fileproc PROTO((struct file_info *finfo));
static void diff_mark_errors PROTO((int err));
@@ -177,7 +177,7 @@ diff (argc, argv)
if (diff_date2)
client_senddate (diff_date2);
- send_file_names (argc, argv);
+ 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.
@@ -240,7 +240,7 @@ diff_fileproc (finfo)
user_file_rev = 0;
#endif
vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL, (char *) NULL,
- finfo->file, 1, 0, finfo->entries, finfo->srcfiles);
+ finfo->file, 1, 0, finfo->entries, finfo->rcs);
if (diff_rev2 != NULL || diff_date2 != NULL)
{
@@ -249,7 +249,7 @@ diff_fileproc (finfo)
}
else if (vers->vn_user == NULL)
{
- error (0, 0, "I know nothing about %s", finfo->file);
+ error (0, 0, "I know nothing about %s", finfo->fullname);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
@@ -260,7 +260,8 @@ diff_fileproc (finfo)
empty_file = DIFF_ADDED;
else
{
- error (0, 0, "%s is a new entry, no comparison available", finfo->file);
+ error (0, 0, "%s is a new entry, no comparison available",
+ finfo->fullname);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
@@ -272,7 +273,8 @@ diff_fileproc (finfo)
empty_file = DIFF_REMOVED;
else
{
- error (0, 0, "%s was removed, no comparison available", finfo->file);
+ error (0, 0, "%s was removed, no comparison available",
+ finfo->fullname);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
@@ -282,7 +284,8 @@ diff_fileproc (finfo)
{
if (vers->vn_rcs == NULL && vers->srcfile == NULL)
{
- error (0, 0, "cannot find revision control file for %s", finfo->file);
+ error (0, 0, "cannot find revision control file for %s",
+ finfo->fullname);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
@@ -291,7 +294,7 @@ diff_fileproc (finfo)
{
if (vers->ts_user == NULL)
{
- error (0, 0, "cannot find %s", finfo->file);
+ error (0, 0, "cannot find %s", finfo->fullname);
freevers_ts (&vers);
diff_mark_errors (err);
return (err);
@@ -308,7 +311,7 @@ diff_fileproc (finfo)
}
}
- if (empty_file == DIFF_NEITHER && diff_file_nodiff (finfo->file, finfo->repository, finfo->entries, finfo->srcfiles, vers))
+ if (empty_file == DIFF_NEITHER && diff_file_nodiff (finfo->file, finfo->repository, finfo->entries, finfo->rcs, vers))
{
freevers_ts (&vers);
return (0);
@@ -319,10 +322,7 @@ diff_fileproc (finfo)
/* Output an "Index:" line for patch to use */
(void) fflush (stdout);
- if (finfo->update_dir[0])
- (void) printf ("Index: %s/%s\n", finfo->update_dir, finfo->file);
- else
- (void) printf ("Index: %s\n", finfo->file);
+ (void) printf ("Index: %s\n", finfo->fullname);
(void) fflush (stdout);
tocvsPath = wrap_tocvs_process_file(finfo->file);
@@ -340,6 +340,8 @@ diff_fileproc (finfo)
if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
{
+ /* This is file, not fullname, because it is the "Index:" line which
+ is supposed to contain the directory. */
(void) printf ("===================================================================\nRCS file: %s\n",
finfo->file);
(void) printf ("diff -N %s\n", finfo->file);
@@ -485,11 +487,11 @@ diff_dirleaveproc (dir, err, update_dir)
* verify that a file is different 0=same 1=different
*/
static int
-diff_file_nodiff (file, repository, entries, srcfiles, vers)
+diff_file_nodiff (file, repository, entries, rcs, vers)
char *file;
char *repository;
List *entries;
- List *srcfiles;
+ RCSNode *rcs;
Vers_TS *vers;
{
Vers_TS *xvers;
@@ -511,7 +513,7 @@ diff_file_nodiff (file, repository, entries, srcfiles, vers)
else
{
xvers = Version_TS (repository, (char *) NULL, diff_rev1,
- diff_date1, file, 1, 0, entries, srcfiles);
+ diff_date1, file, 1, 0, entries, rcs);
if (xvers->vn_rcs == NULL)
{
/* Don't gripe if it doesn't exist, just ignore! */
@@ -538,7 +540,7 @@ diff_file_nodiff (file, repository, entries, srcfiles, vers)
else
{
xvers = Version_TS (repository, (char *) NULL, diff_rev2,
- diff_date2, file, 1, 0, entries, srcfiles);
+ diff_date2, file, 1, 0, entries, rcs);
if (xvers->vn_rcs == NULL)
{
/* Don't gripe if it doesn't exist, just ignore! */
diff --git a/gnu/usr.bin/cvs/src/edit.c b/gnu/usr.bin/cvs/src/edit.c
index a337e0d4ee3..0473a03cf7d 100644
--- a/gnu/usr.bin/cvs/src/edit.c
+++ b/gnu/usr.bin/cvs/src/edit.c
@@ -87,7 +87,7 @@ watch_onoff (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv);
+ 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. */
@@ -300,9 +300,10 @@ edit_fileproc (finfo)
if (fclose (fp) < 0)
{
if (finfo->update_dir[0] == '\0')
- error (0, errno, "cannot close %s", finfo->file);
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
else
- error (0, errno, "cannot close %s/%s", finfo->update_dir, finfo->file);
+ error (0, errno, "cannot close %s/%s", finfo->update_dir,
+ CVSADM_NOTIFY);
}
xchmod (finfo->file, 1);
@@ -448,9 +449,7 @@ unedit_fileproc (finfo)
if (xcmp (finfo->file, basefilename) != 0)
{
- if (finfo->update_dir[0] != '\0')
- printf ("%s/", finfo->update_dir);
- printf ("%s has been modified; revert changes? ", finfo->file);
+ printf ("%s has been modified; revert changes? ", finfo->fullname);
if (!yesno ())
{
/* "no". */
@@ -472,9 +471,10 @@ unedit_fileproc (finfo)
if (fclose (fp) < 0)
{
if (finfo->update_dir[0] == '\0')
- error (0, errno, "cannot close %s", finfo->file);
+ error (0, errno, "cannot close %s", CVSADM_NOTIFY);
else
- error (0, errno, "cannot close %s/%s", finfo->update_dir, finfo->file);
+ error (0, errno, "cannot close %s/%s", finfo->update_dir,
+ CVSADM_NOTIFY);
}
xchmod (finfo->file, 0);
@@ -928,10 +928,7 @@ editors_fileproc (finfo)
if (them == NULL)
return 0;
- if (finfo->update_dir[0] == '\0')
- printf ("%s", finfo->file);
- else
- printf ("%s/%s", finfo->update_dir, finfo->file);
+ fputs (finfo->fullname, stdout);
p = them;
while (1)
@@ -1006,7 +1003,7 @@ editors (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv);
+ 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. */
diff --git a/gnu/usr.bin/cvs/src/entries.c b/gnu/usr.bin/cvs/src/entries.c
index df860214e70..350f7f8fcf8 100644
--- a/gnu/usr.bin/cvs/src/entries.c
+++ b/gnu/usr.bin/cvs/src/entries.c
@@ -126,7 +126,7 @@ Scratch_Entry (list, fname)
#endif
/* hashlookup to see if it is there */
- if ((node = findnode (list, fname)) != NULL)
+ if ((node = findnode_fn (list, fname)) != NULL)
{
delnode (node); /* delete the node */
#ifdef SERVER_SUPPORT
@@ -444,7 +444,7 @@ AddEntryNode (list, entdata)
Node *p;
/* was it already there? */
- if ((p = findnode (list, entdata->user)) != NULL)
+ if ((p = findnode_fn (list, entdata->user)) != NULL)
{
/* take it out */
delnode (p);
diff --git a/gnu/usr.bin/cvs/src/error.c b/gnu/usr.bin/cvs/src/error.c
index e5e2916cfa5..8a10cc7c0db 100644
--- a/gnu/usr.bin/cvs/src/error.c
+++ b/gnu/usr.bin/cvs/src/error.c
@@ -82,7 +82,7 @@ error_set_cleanup (arg)
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args.
If ERRNUM is nonzero, print its corresponding system error message.
- Exit with status STATUS if it is nonzero. */
+ Exit with status EXIT_FAILURE if STATUS is nonzero. */
/* VARARGS */
void
#if defined (HAVE_VPRINTF) && __STDC__
@@ -206,14 +206,14 @@ error (status, errnum, message, va_alist)
{
if (cleanup_fn)
(*cleanup_fn) ();
- exit (status);
+ exit (EXIT_FAILURE);
}
}
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args to the file specified by FP.
If ERRNUM is nonzero, print its corresponding system error message.
- Exit with status STATUS if it is nonzero. */
+ Exit with status EXIT_FAILURE if STATUS is nonzero. */
/* VARARGS */
void
#if defined (HAVE_VPRINTF) && __STDC__
@@ -251,6 +251,6 @@ fperror (fp, status, errnum, message, va_alist)
{
if (cleanup_fn)
(*cleanup_fn) ();
- exit (status);
+ exit (EXIT_FAILURE);
}
}
diff --git a/gnu/usr.bin/cvs/src/expand_path.c b/gnu/usr.bin/cvs/src/expand_path.c
index 5cb8d7203c6..98980510e44 100644
--- a/gnu/usr.bin/cvs/src/expand_path.c
+++ b/gnu/usr.bin/cvs/src/expand_path.c
@@ -16,8 +16,6 @@
#include <sys/types.h>
static char *expand_variable PROTO((char *env, char *file, int line));
-extern char *xmalloc ();
-extern void free ();
/* User variables. */
diff --git a/gnu/usr.bin/cvs/src/fileattr.c b/gnu/usr.bin/cvs/src/fileattr.c
index be52cbf39c5..827c69ca990 100644
--- a/gnu/usr.bin/cvs/src/fileattr.c
+++ b/gnu/usr.bin/cvs/src/fileattr.c
@@ -51,7 +51,9 @@ static void
fileattr_delproc (node)
Node *node;
{
+ assert (node->data != NULL);
free (node->data);
+ node->data = NULL;
}
/* Read all the attributes for the current directory into memory. */
@@ -159,7 +161,7 @@ fileattr_get (filename, attrname)
return NULL;
p = node->data;
}
- while (1)
+ while (p)
{
if (strncmp (attrname, p, attrname_len) == 0
&& p[attrname_len] == '=')
@@ -345,6 +347,7 @@ fileattr_set (filename, attrname, attrval)
p = fileattr_modify (node->data, attrname, attrval, '=', ';');
free (node->data);
+ node->data = NULL;
if (p == NULL)
delnode (node);
else
diff --git a/gnu/usr.bin/cvs/src/filesubr.c b/gnu/usr.bin/cvs/src/filesubr.c
index ebc30538a9b..086da8391ae 100644
--- a/gnu/usr.bin/cvs/src/filesubr.c
+++ b/gnu/usr.bin/cvs/src/filesubr.c
@@ -325,9 +325,11 @@ xchmod (fname, writable)
if (trace)
#ifdef SERVER_SUPPORT
(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
- (server_active) ? 'S' : ' ', fname, mode);
+ (server_active) ? 'S' : ' ', fname,
+ (unsigned int) mode);
#else
- (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
+ (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
+ (unsigned int) mode);
#endif
if (noexec)
return;
@@ -420,22 +422,20 @@ unlink_file_dir (f)
if (noexec)
return (0);
- if (unlink (f) != 0)
+ /* For at least some unices, if root tries to unlink() a directory,
+ instead of doing something rational like returning EISDIR,
+ the system will gleefully go ahead and corrupt the filesystem.
+ So we first call isdir() to see if it is OK to call unlink(). This
+ doesn't quite work--if someone creates a directory between the
+ call to isdir() and the call to unlink(), we'll still corrupt
+ the filesystem. Where is the Unix Haters Handbook when you need
+ it? */
+ if (isdir(f))
+ return deep_remove_dir(f);
+ else
{
- /* under NEXTSTEP errno is set to return EPERM if
- * the file is a directory,or if the user is not
- * allowed to read or write to the file.
- * [This is probably a bug in the O/S]
- * other systems will return EISDIR to indicate
- * that the path is a directory.
- */
- if (errno == EISDIR || errno == EPERM)
- return deep_remove_dir (f);
- else
- /* The file wasn't a directory and some other
- * error occured
- */
- return -1;
+ if (unlink (f) != 0)
+ return -1;
}
/* We were able to remove the file from the disk */
return 0;
@@ -469,22 +469,22 @@ deep_remove_dir (path)
sprintf (buf, "%s/%s", path, dp->d_name);
- if (unlink (buf) != 0 )
+ /* See comment in unlink_file_dir explanation of why we use
+ isdir instead of just calling unlink and checking the
+ status. */
+ if (isdir(buf))
{
- if (errno == EISDIR || errno == EPERM)
+ if (deep_remove_dir(buf))
{
- if (deep_remove_dir (buf))
- {
- closedir (dirp);
- return -1;
- }
+ closedir(dirp);
+ return -1;
}
- else
+ }
+ else
+ {
+ if (unlink (buf) != 0)
{
- /* buf isn't a directory, or there are
- * some sort of permision problems
- */
- closedir (dirp);
+ closedir(dirp);
return -1;
}
}
@@ -644,3 +644,19 @@ get_homedir ()
{
return getenv ("HOME");
}
+
+/* See cvs.h for description. On unix this does nothing, because the
+ shell expands the wildcards. */
+void
+expand_wild (argc, argv, pargc, pargv)
+ int argc;
+ char **argv;
+ int *pargc;
+ char ***pargv;
+{
+ int i;
+ *pargc = argc;
+ *pargv = (char **) xmalloc (argc * sizeof (char *));
+ for (i = 0; i < argc; ++i)
+ (*pargv)[i] = xstrdup (argv[i]);
+}
diff --git a/gnu/usr.bin/cvs/src/find_names.c b/gnu/usr.bin/cvs/src/find_names.c
index a5658813dde..48854377a75 100644
--- a/gnu/usr.bin/cvs/src/find_names.c
+++ b/gnu/usr.bin/cvs/src/find_names.c
@@ -109,7 +109,7 @@ Find_Names (repository, which, aflag, optentries)
* create a list of directories to traverse from the current directory
*/
List *
-Find_Dirs (repository, which)
+Find_Directories (repository, which)
char *repository;
int which;
{
diff --git a/gnu/usr.bin/cvs/src/hash.c b/gnu/usr.bin/cvs/src/hash.c
index a94f46f020a..2197db07f8a 100644
--- a/gnu/usr.bin/cvs/src/hash.c
+++ b/gnu/usr.bin/cvs/src/hash.c
@@ -247,10 +247,9 @@ addnode (list, p)
return (0);
}
-/*
- * look up an entry in hash list table and return a pointer to the
- * node. Return NULL on error or not found.
- */
+/* Look up an entry in hash list table and return a pointer to the
+ node. Return NULL if not found. Abort with a fatal error for
+ errors. */
Node *
findnode (list, key)
List *list;
@@ -264,6 +263,8 @@ findnode (list, key)
if ((list == (List *) NULL))
return ((Node *) NULL);
+ assert (key != NULL);
+
head = list->hasharray[hashp (key)];
if (head == (Node *) NULL)
/* Not found. */
@@ -285,9 +286,14 @@ findnode_fn (list, key)
{
Node *head, *p;
+ /* This probably should be "assert (list != NULL)" (or if not we
+ should document the current behavior), but only if we check all
+ the callers to see if any are relying on this behavior. */
if (list == (List *) NULL)
return ((Node *) NULL);
+ assert (key != NULL);
+
head = list->hasharray[hashp (key)];
if (head == (Node *) NULL)
return ((Node *) NULL);
diff --git a/gnu/usr.bin/cvs/src/history.c b/gnu/usr.bin/cvs/src/history.c
index 3bc42395587..81c71ffbea5 100644
--- a/gnu/usr.bin/cvs/src/history.c
+++ b/gnu/usr.bin/cvs/src/history.c
@@ -1136,7 +1136,7 @@ select_hrec (hr)
time_t t;
vers = Version_TS (hr->repos, (char *) NULL, since_rev, (char *) NULL,
- hr->file, 1, 0, (List *) NULL, (List *) NULL);
+ hr->file, 1, 0, (List *) NULL, (RCSNode *) NULL);
if (vers->vn_rcs)
{
if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, (char *) 0, 0))
diff --git a/gnu/usr.bin/cvs/src/import.c b/gnu/usr.bin/cvs/src/import.c
index af8091aab6f..98c163555a6 100644
--- a/gnu/usr.bin/cvs/src/import.c
+++ b/gnu/usr.bin/cvs/src/import.c
@@ -475,7 +475,7 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
char *tocvsPath;
vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile,
- 1, 0, (List *) NULL, (List *) NULL);
+ 1, 0, (List *) NULL, (RCSNode *) NULL);
if (vers->vn_rcs != NULL
&& !RCS_isdead(vers->srcfile, vers->vn_rcs))
{
@@ -487,7 +487,7 @@ update_rcs_file (message, vfile, vtag, targc, targv, inattic)
if (tmpdir == NULL || tmpdir[0] == '\0')
tmpdir = "/tmp";
- (void) sprintf (xtmpfile, "%s/cvs-imp%d", tmpdir, getpid());
+ (void) sprintf (xtmpfile, "%s/cvs-imp%ld", tmpdir, (long) getpid());
/*
* The rcs file does have a revision on the vendor branch. Compare
@@ -679,7 +679,7 @@ add_tags (rcs, vfile, vtag, targc, targv)
return (1);
}
vers = Version_TS (repository, (char *) NULL, vtag, (char *) NULL, vfile,
- 1, 0, (List *) NULL, (List *) NULL);
+ 1, 0, (List *) NULL, (RCSNode *) NULL);
for (i = 0; i < targc; i++)
{
if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) != 0)
@@ -852,7 +852,7 @@ add_rcs_file (message, rcs, user, vtag, targc, targv)
#ifndef HAVE_RCS5
char altdate2[50];
#endif
- char *author, *buf;
+ char *author;
int i, ierrno, err = 0;
mode_t mode;
char *tocvsPath;
@@ -861,23 +861,23 @@ add_rcs_file (message, rcs, user, vtag, targc, targv)
if (noexec)
return (0);
-#ifdef LINES_CRLF_TERMINATED
- /* There exits a port of RCS to such a system that stores files with
- straight newlines. If we ever reach this point on such a system,
- we'll need to decide what to do with the open_file call below. */
- abort ();
-#endif
+ /* FIXME? We always import files as text files (note that means
+ that files get stored with straight linefeeds). There isn't an
+ obvious, clean, way to let people specify which files are binary.
+ Maybe based on the file name.... */
tocvsPath = wrap_tocvs_process_file (user);
userfile = (tocvsPath == NULL ? user : tocvsPath);
fpuser = fopen (userfile, "r");
- if (fpuser == NULL) {
+ if (fpuser == NULL)
+ {
/* not fatal, continue import */
fperror (logfp, 0, errno, "ERROR: cannot read file %s", userfile);
error (0, errno, "ERROR: cannot read file %s", userfile);
goto read_error;
}
- fprcs = fopen (rcs, "w+");
- if (fprcs == NULL) {
+ fprcs = fopen (rcs, "w+b");
+ if (fprcs == NULL)
+ {
ierrno = errno;
goto write_error_noclose;
}
@@ -885,9 +885,9 @@ add_rcs_file (message, rcs, user, vtag, targc, targv)
/*
* putadmin()
*/
- if (fprintf (fprcs, "head %s;\n", vhead) < 0 ||
- fprintf (fprcs, "branch %s;\n", vbranch) < 0 ||
- fprintf (fprcs, "access ;\n") < 0 ||
+ if (fprintf (fprcs, "head %s;\012", vhead) < 0 ||
+ fprintf (fprcs, "branch %s;\012", vbranch) < 0 ||
+ fprintf (fprcs, "access ;\012") < 0 ||
fprintf (fprcs, "symbols ") < 0)
{
goto write_error;
@@ -897,21 +897,21 @@ add_rcs_file (message, rcs, user, vtag, targc, targv)
if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) < 0)
goto write_error;
- if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) < 0 ||
- fprintf (fprcs, "locks ; strict;\n") < 0 ||
+ if (fprintf (fprcs, "%s:%s;\012", vtag, vbranch) < 0 ||
+ fprintf (fprcs, "locks ; strict;\012") < 0 ||
/* XXX - make sure @@ processing works in the RCS file */
- fprintf (fprcs, "comment @%s@;\n", get_comment (user)) < 0)
+ fprintf (fprcs, "comment @%s@;\012", get_comment (user)) < 0)
{
goto write_error;
}
if (keyword_opt != NULL)
- if (fprintf (fprcs, "expand @%s@;\n", keyword_opt) < 0)
+ if (fprintf (fprcs, "expand @%s@;\012", keyword_opt) < 0)
{
goto write_error;
}
- if (fprintf (fprcs, "\n") < 0)
+ if (fprintf (fprcs, "\012") < 0)
goto write_error;
/*
@@ -948,53 +948,56 @@ add_rcs_file (message, rcs, user, vtag, targc, targv)
#endif
author = getcaller ();
- if (fprintf (fprcs, "\n%s\n", vhead) < 0 ||
- fprintf (fprcs, "date %s; author %s; state Exp;\n",
+ if (fprintf (fprcs, "\012%s\012", vhead) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\012",
altdate1, author) < 0 ||
- fprintf (fprcs, "branches %s.1;\n", vbranch) < 0 ||
- fprintf (fprcs, "next ;\n") < 0 ||
- fprintf (fprcs, "\n%s.1\n", vbranch) < 0 ||
- fprintf (fprcs, "date %s; author %s; state Exp;\n",
+ fprintf (fprcs, "branches %s.1;\012", vbranch) < 0 ||
+ fprintf (fprcs, "next ;\012") < 0 ||
+ fprintf (fprcs, "\012%s.1\012", vbranch) < 0 ||
+ fprintf (fprcs, "date %s; author %s; state Exp;\012",
altdate2, author) < 0 ||
- fprintf (fprcs, "branches ;\n") < 0 ||
- fprintf (fprcs, "next ;\n\n") < 0 ||
+ fprintf (fprcs, "branches ;\012") < 0 ||
+ fprintf (fprcs, "next ;\012\012") < 0 ||
/*
* putdesc()
*/
- fprintf (fprcs, "\ndesc\n") < 0 ||
- fprintf (fprcs, "@@\n\n\n") < 0 ||
+ fprintf (fprcs, "\012desc\012") < 0 ||
+ fprintf (fprcs, "@@\012\012\012") < 0 ||
/*
* putdelta()
*/
- fprintf (fprcs, "\n%s\n", vhead) < 0 ||
- fprintf (fprcs, "log\n") < 0 ||
- fprintf (fprcs, "@Initial revision\n@\n") < 0 ||
- fprintf (fprcs, "text\n@") < 0)
+ fprintf (fprcs, "\012%s\012", vhead) < 0 ||
+ fprintf (fprcs, "log\012") < 0 ||
+ fprintf (fprcs, "@Initial revision\012@\012") < 0 ||
+ fprintf (fprcs, "text\012@") < 0)
{
goto write_error;
}
- if (sb.st_size > 0)
+ /* Now copy over the contents of the file, expanding at signs. */
{
- off_t size;
+ unsigned char buf[8192];
+ unsigned int len;
- size = sb.st_size;
- buf = xmalloc ((int) size);
- if (fread (buf, (int) size, 1, fpuser) != 1)
- error (1, errno, "cannot read file %s for copying", user);
- if (expand_at_signs (buf, size, fprcs) < 0)
+ while (1)
{
- free (buf);
- goto write_error;
+ len = fread (buf, 1, sizeof buf, fpuser);
+ if (len == 0)
+ {
+ if (ferror (fpuser))
+ error (1, errno, "cannot read file %s for copying", user);
+ break;
+ }
+ if (expand_at_signs (buf, len, fprcs) < 0)
+ goto write_error;
}
- free (buf);
}
- if (fprintf (fprcs, "@\n\n") < 0 ||
- fprintf (fprcs, "\n%s.1\n", vbranch) < 0 ||
- fprintf (fprcs, "log\n@") < 0 ||
+ if (fprintf (fprcs, "@\012\012") < 0 ||
+ fprintf (fprcs, "\012%s.1\012", vbranch) < 0 ||
+ fprintf (fprcs, "log\012@") < 0 ||
expand_at_signs (message, (off_t) strlen (message), fprcs) < 0 ||
- fprintf (fprcs, "@\ntext\n") < 0 ||
- fprintf (fprcs, "@@\n") < 0)
+ fprintf (fprcs, "@\012text\012") < 0 ||
+ fprintf (fprcs, "@@\012") < 0)
{
goto write_error;
}
@@ -1168,7 +1171,10 @@ import_descend_dir (message, dir, vtag, targc, targv)
if (!isdir (repository))
#endif
{
- if (isfile (repository))
+ char rcs[PATH_MAX];
+
+ (void) sprintf (rcs, "%s%s", repository, RCSEXT);
+ if (isfile (repository) || isfile(rcs))
{
fperror (logfp, 0, 0, "ERROR: %s is a file, should be a directory!",
repository);
@@ -1195,7 +1201,7 @@ import_descend_dir (message, dir, vtag, targc, targv)
else
repository[0] = '\0';
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
return (err);
}
diff --git a/gnu/usr.bin/cvs/src/log.c b/gnu/usr.bin/cvs/src/log.c
index 3be79281d21..f167d92d987 100644
--- a/gnu/usr.bin/cvs/src/log.c
+++ b/gnu/usr.bin/cvs/src/log.c
@@ -61,7 +61,7 @@ cvslog (argc, argv)
for (i = 1; i < argc && argv[i][0] == '-'; i++)
send_arg (argv[i]);
- send_file_names (argc - i, 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 */
@@ -96,8 +96,7 @@ log_fileproc (finfo)
RCSNode *rcsfile;
int retcode = 0;
- p = findnode (finfo->srcfiles, finfo->file);
- if (p == NULL || (rcsfile = (RCSNode *) p->data) == NULL)
+ if ((rcsfile = finfo->rcs) == NULL)
{
/* no rcs file. What *do* we know about this file? */
p = findnode (finfo->entries, finfo->file);
diff --git a/gnu/usr.bin/cvs/src/logmsg.c b/gnu/usr.bin/cvs/src/logmsg.c
index 55ac32d0caf..370ceab186e 100644
--- a/gnu/usr.bin/cvs/src/logmsg.c
+++ b/gnu/usr.bin/cvs/src/logmsg.c
@@ -112,10 +112,8 @@ fmt_proc (p, closure)
* editor on the file. The header garbage in the resultant file is then
* stripped and the log message is stored in the "message" argument.
*
- * rcsinfo - is the name of a file containing lines tacked onto the end of the
- * RCS info offered to the user for editing. If specified, the '-m' flag to
- * "commit" is disabled -- users are forced to run the editor.
- *
+ * If REPOSITORY is non-NULL, process rcsinfo for that repository; if it
+ * is NULL, use the CVSADM_TEMPLATE file instead.
*/
void
do_editor (dir, messagep, repository, changes)
@@ -136,6 +134,10 @@ do_editor (dir, messagep, repository, changes)
if (noexec || reuse_log_message)
return;
+ /* Abort creation of temp file if no editor is defined */
+ if (strcmp (Editor, "") == 0 && !editinfo_editor)
+ error(1, 0, "no editor defined, must use -e or -m");
+
/* Create a temporary file */
(void) tmpnam (fname);
again:
@@ -155,6 +157,41 @@ do_editor (dir, messagep, repository, changes)
if (repository != NULL)
/* tack templates on if necessary */
(void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, 1);
+ else
+ {
+ FILE *tfp;
+ char buf[1024];
+ char *p;
+ size_t n;
+ size_t nwrite;
+
+ /* Why "b"? */
+ tfp = fopen (CVSADM_TEMPLATE, "rb");
+ if (tfp == NULL)
+ {
+ if (!existence_error (errno))
+ error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
+ }
+ else
+ {
+ while (!feof (tfp))
+ {
+ n = fread (buf, 1, sizeof buf, tfp);
+ nwrite = n;
+ p = buf;
+ while (nwrite > 0)
+ {
+ n = fwrite (p, 1, nwrite, fp);
+ nwrite -= n;
+ p += n;
+ }
+ if (ferror (tfp))
+ error (1, errno, "cannot read %s", CVSADM_TEMPLATE);
+ }
+ if (fclose (tfp) < 0)
+ error (0, errno, "cannot close %s", CVSADM_TEMPLATE);
+ }
+ }
(void) fprintf (fp,
"%s----------------------------------------------------------------------\n",
@@ -206,6 +243,8 @@ do_editor (dir, messagep, repository, changes)
*messagep = NULL;
else
{
+ /* On NT, we might read less than st_size bytes, but we won't
+ read more. So this works. */
*messagep = (char *) xmalloc (post_stbuf.st_size + 1);
*messagep[0] = '\0';
}
@@ -421,16 +460,16 @@ logfile_write (repository, filter, title, message, revision, logfp, changes)
List *changes;
{
char cwd[PATH_MAX];
- FILE *pipefp, *run_popen ();
+ FILE *pipefp;
char *prog = xmalloc (MAXPROGLEN);
char *cp;
int c;
+ int pipestatus;
- /* XXX <woods@web.net> -- this is gross, ugly, and a hack! FIXME! */
/*
- * A maximum of 6 %s arguments are supported in the filter
+ * Only 1 %s argument is supported in the filter
*/
- (void) sprintf (prog, filter, title, title, title, title, title, title);
+ (void) sprintf (prog, filter, title);
if ((pipefp = run_popen (prog, "w")) == NULL)
{
if (!noexec)
@@ -453,7 +492,8 @@ logfile_write (repository, filter, title, message, revision, logfp, changes)
(void) putc ((char) c, pipefp);
}
free (prog);
- return (pclose (pipefp));
+ pipestatus = pclose (pipefp);
+ return ((pipestatus == -1) || (pipestatus == 127)) ? 1 : 0;
}
/*
diff --git a/gnu/usr.bin/cvs/src/mkmodules.c b/gnu/usr.bin/cvs/src/mkmodules.c
index 5929880b8aa..bdd27eb623d 100644
--- a/gnu/usr.bin/cvs/src/mkmodules.c
+++ b/gnu/usr.bin/cvs/src/mkmodules.c
@@ -21,6 +21,253 @@ static void rename_dbmfile PROTO((char *temp));
static void write_dbmfile PROTO((char *temp));
#endif /* !MY_NDBM */
+/* Structure which describes an administrative file. */
+struct admin_file {
+ /* Name of the file, within the CVSROOT directory. */
+ char *filename;
+
+ /* This is a one line description of what the file is for. It is not
+ currently used, although one wonders whether it should be, somehow.
+ If NULL, then don't process this file in mkmodules (FIXME: a bit of
+ a kludge; probably should replace this with a flags field). */
+ char *errormsg;
+
+ /* Contents which the file should have in a new repository. To avoid
+ problems with brain-dead compilers which choke on long string constants,
+ this is a pointer to an array of char * terminated by NULL--each of
+ the strings is concatenated. */
+ const char * const *contents;
+};
+
+static const char *const loginfo_contents[] = {
+ "# The \"loginfo\" file is used to control where \"cvs commit\" log information\n",
+ "# is sent. The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being made to, relative to the\n",
+ "# $CVSROOT. For the first match that is found, then the remainder of the\n",
+ "# line is a filter program that should expect log information on its standard\n",
+ "# input.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in the\n",
+ "# first field of this file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ "#\n",
+ "# The filter program may use one and only one \"%s\" modifier (ala printf). If\n",
+ "# such a \"%s\" is specified in the filter program, a brief title is included\n",
+ "# (as one argument, enclosed in single quotes) showing the relative directory\n",
+ "# name and listing the modified file names.\n",
+ "#\n",
+ "# For example:\n",
+ "#DEFAULT (echo \"\"; who am i; date; cat) >> $CVSROOT/CVSROOT/commitlog\n",
+ NULL
+};
+
+static const char *const rcsinfo_contents[] = {
+ "# The \"rcsinfo\" file is used to control templates with which the editor\n",
+ "# is invoked on commit and import.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being made to, relative to the\n",
+ "# $CVSROOT. For the first match that is found, then the remainder of the\n",
+ "# line is the name of the file that contains the template.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const editinfo_contents[] = {
+ "# The \"editinfo\" file is used to allow verification of logging\n",
+ "# information. It works best when a template (as specified in the\n",
+ "# rcsinfo file) is provided for the logging procedure. Given a\n",
+ "# template with locations for, a bug-id number, a list of people who\n",
+ "# reviewed the code before it can be checked in, and an external\n",
+ "# process to catalog the differences that were code reviewed, the\n",
+ "# following test can be applied to the code:\n",
+ "#\n",
+ "# Making sure that the entered bug-id number is correct.\n",
+ "# Validating that the code that was reviewed is indeed the code being\n",
+ "# checked in (using the bug-id number or a seperate review\n",
+ "# number to identify this particular code set.).\n",
+ "#\n",
+ "# If any of the above test failed, then the commit would be aborted.\n",
+ "#\n",
+ "# Actions such as mailing a copy of the report to each reviewer are\n",
+ "# better handled by an entry in the loginfo file.\n",
+ "#\n",
+ "# One thing that should be noted is the the ALL keyword is not\n",
+ "# supported. There can be only one entry that matches a given\n",
+ "# repository.\n",
+ NULL
+};
+
+static const char *const commitinfo_contents[] = {
+ "# The \"commitinfo\" file is used to control pre-commit checks.\n",
+ "# The filter on the right is invoked with the repository and a list \n",
+ "# of files to check. A non-zero exit of the filter program will \n",
+ "# cause the commit to be aborted.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const taginfo_contents[] = {
+ "# The \"taginfo\" file is used to control pre-tag checks.\n",
+ "# The filter on the right is invoked with the following arguments:\n",
+ "#\n",
+ "# $1 -- tagname\n",
+ "# $2 -- operation \"add\" for tag, \"mov\" for tag -F, and \"del\" for tag -d\n",
+ "# $3 -- repository\n",
+ "# $4-> file revision [file revision ...]\n",
+ "#\n",
+ "# A non-zero exit of the filter program will cause the tag to be aborted.\n",
+ "#\n",
+ "# The first entry on a line is a regular expression which is tested\n",
+ "# against the directory that the change is being committed to, relative\n",
+ "# to the $CVSROOT. For the first match that is found, then the remainder\n",
+ "# of the line is the name of the filter to run.\n",
+ "#\n",
+ "# If the repository name does not match any of the regular expressions in this\n",
+ "# file, the \"DEFAULT\" line is used, if it is specified.\n",
+ "#\n",
+ "# If the name \"ALL\" appears as a regular expression it is always used\n",
+ "# in addition to the first matching regex or \"DEFAULT\".\n",
+ NULL
+};
+
+static const char *const checkoutlist_contents[] = {
+ "# The \"checkoutlist\" file is used to support additional version controlled\n",
+ "# administrative files in $CVSROOT/CVSROOT, such as template files.\n",
+ "#\n",
+ "# The first entry on a line is a filename which will be checked out from\n",
+ "# the corresponding RCS file in the $CVSROOT/CVSROOT directory.\n",
+ "# The remainder of the line is an error message to use if the file cannot\n",
+ "# be checked out.\n",
+ "#\n",
+ "# File format:\n",
+ "#\n",
+ "# [<whitespace>]<filename><whitespace><error message><end-of-line>\n",
+ "#\n",
+ "# comment lines begin with '#'\n",
+ NULL
+};
+
+static const char *const cvswrappers_contents[] = {
+ "# This file describes wrappers and other binary files to CVS.\n",
+ "#\n",
+ "# Wrappers are the concept where directories of files are to be\n",
+ "# treated as a single file. The intended use is to wrap up a wrapper\n",
+ "# into a single tar such that the tar archive can be treated as a\n",
+ "# single binary file in CVS.\n",
+ "#\n",
+ "# To solve the problem effectively, it was also necessary to be able to\n",
+ "# prevent rcsmerge from merging these files.\n",
+ "#\n",
+ "# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)\n",
+ "#\n",
+ "# wildcard [option value][option value]...\n",
+ "#\n",
+ "# where option is one of\n",
+ "# -f from cvs filter value: path to filter\n",
+ "# -t to cvs filter value: path to filter\n",
+ "# -m update methodology value: MERGE or COPY\n",
+ "#\n",
+ "# and value is a single-quote delimited value.\n",
+ "#\n",
+ "# For example:\n",
+ NULL
+};
+
+static const char *const notify_contents[] = {
+ "# The \"notify\" file controls where notifications from watches set by\n",
+ "# \"cvs watch add\" or \"cvs edit\" are sent. The first entry on a line is\n",
+ "# a regular expression which is tested against the directory that the\n",
+ "# change is being made to, relative to the $CVSROOT. If it matches,\n",
+ "# then the remainder of the line is a filter program that should contain\n",
+ "# one occurrence of %s for the user to notify, and information on its\n",
+ "# standard input.\n",
+ "#\n",
+ "# \"ALL\" or \"DEFAULT\" can be used in place of the regular expression.\n",
+ "#\n",
+ "# For example:\n",
+ "#ALL mail %s -s \"CVS notification\"\n",
+ NULL
+};
+
+static const char *const modules_contents[] = {
+ "# Three different line formats are valid:\n",
+ "# key -a aliases...\n",
+ "# key [options] directory\n",
+ "# key [options] directory files...\n",
+ "#\n",
+ "# Where \"options\" are composed of:\n",
+ "# -i prog Run \"prog\" on \"cvs commit\" from top-level of module.\n",
+ "# -o prog Run \"prog\" on \"cvs checkout\" of module.\n",
+ "# -e prog Run \"prog\" on \"cvs export\" of module.\n",
+ "# -t prog Run \"prog\" on \"cvs rtag\" of module.\n",
+ "# -u prog Run \"prog\" on \"cvs update\" of module.\n",
+ "# -d dir Place module in directory \"dir\" instead of module name.\n",
+ "# -l Top-level directory only -- do not recurse.\n",
+ "#\n",
+ "# And \"directory\" is a path to a directory relative to $CVSROOT.\n",
+ "#\n",
+ "# The \"-a\" option specifies an alias. An alias is interpreted as if\n",
+ "# everything on the right of the \"-a\" had been typed on the command line.\n",
+ "#\n",
+ "# You can encode a module within a module by using the special '&'\n",
+ "# character to interpose another module into the current module. This\n",
+ "# can be useful for creating a module that consists of many directories\n",
+ "# spread out over the entire source repository.\n",
+ NULL
+};
+
+static const struct admin_file filelist[] = {
+ {CVSROOTADM_LOGINFO,
+ "no logging of 'cvs commit' messages is done without a %s file",
+ &loginfo_contents[0]},
+ {CVSROOTADM_RCSINFO,
+ "a %s file can be used to configure 'cvs commit' templates",
+ rcsinfo_contents},
+ {CVSROOTADM_EDITINFO,
+ "a %s file can be used to validate log messages",
+ editinfo_contents},
+ {CVSROOTADM_COMMITINFO,
+ "a %s file can be used to configure 'cvs commit' checking",
+ commitinfo_contents},
+ {CVSROOTADM_TAGINFO,
+ "a %s file can be used to configure 'cvs tag' checking",
+ taginfo_contents},
+ {CVSROOTADM_IGNORE,
+ "a %s file can be used to specify files to ignore",
+ NULL},
+ {CVSROOTADM_CHECKOUTLIST,
+ "a %s file can specify extra CVSROOT files to auto-checkout",
+ checkoutlist_contents},
+ {CVSROOTADM_WRAPPER,
+ "a %s file can be used to specify files to treat as wrappers",
+ cvswrappers_contents},
+ {CVSROOTADM_NOTIFY,
+ "a %s file can be used to specify where notifications go",
+ notify_contents},
+ {CVSROOTADM_MODULES,
+ /* modules is special-cased in mkmodules. */
+ NULL,
+ modules_contents},
+ {NULL, NULL}
+};
/* Rebuild the checked out administrative files in directory DIR. */
int
@@ -37,32 +284,10 @@ mkmodules (dir)
FILE *fp;
/* FIXME: arbitrary limit */
char line[512];
- static struct _checkout_file {
- char *filename;
- char *errormsg;
- } *fileptr, filelist[] = {
- {CVSROOTADM_LOGINFO,
- "no logging of 'cvs commit' messages is done without a %s file"},
- {CVSROOTADM_RCSINFO,
- "a %s file can be used to configure 'cvs commit' templates"},
- {CVSROOTADM_EDITINFO,
- "a %s file can be used to validate log messages"},
- {CVSROOTADM_COMMITINFO,
- "a %s file can be used to configure 'cvs commit' checking"},
- {CVSROOTADM_TAGINFO,
- "a %s file can be used to configure 'cvs tag' checking"},
- {CVSROOTADM_IGNORE,
- "a %s file can be used to specify files to ignore"},
- {CVSROOTADM_CHECKOUTLIST,
- "a %s file can specify extra CVSROOT files to auto-checkout"},
- {CVSROOTADM_WRAPPER,
- "a %s file can be used to specify files to treat as wrappers"},
- {CVSROOTADM_NOTIFY,
- "a %s file can be used to specify where notifications go"},
- {NULL, NULL}};
+ const struct admin_file *fileptr;
if (save_cwd (&cwd))
- exit (1);
+ exit (EXIT_FAILURE);
if (chdir (dir) < 0)
error (1, errno, "cannot chdir to %s", dir);
@@ -88,7 +313,7 @@ mkmodules (dir)
case -1: /* fork failed */
(void) unlink_file (temp);
- exit (1);
+ exit (EXIT_FAILURE);
/* NOTREACHED */
default:
@@ -102,6 +327,8 @@ mkmodules (dir)
/* Checkout the files that need it in CVSROOT dir */
for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) {
+ if (fileptr->errormsg == NULL)
+ continue;
make_tempfile (temp);
if (checkout_file (fileptr->filename, temp) == 0)
rename_rcsfile (temp, fileptr->filename);
@@ -164,7 +391,7 @@ mkmodules (dir)
}
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
return (0);
@@ -375,3 +602,141 @@ rename_rcsfile (temp, real)
(void) rename (real, bak); /* mv loginfo .#loginfo */
(void) rename (temp, real); /* mv "temp" loginfo */
}
+
+const char *const init_usage[] = {
+ "Usage: %s %s\n",
+ NULL
+};
+
+/* Create directory NAME if it does not already exist; fatal error for
+ other errors. FIXME: This should be in filesubr.c or thereabouts,
+ probably. Perhaps it should be further abstracted, though (for example
+ to handle CVSUMASK where appropriate?). */
+static void
+mkdir_if_needed (name)
+ char *name;
+{
+ if (CVS_MKDIR (name, 0777) < 0)
+ {
+ if (errno != EEXIST
+#ifdef EACCESS
+ /* OS/2; see longer comment in client.c. */
+ && errno != EACCESS
+#endif
+ )
+ error (1, errno, "cannot mkdir %s", name);
+ }
+}
+
+int
+init (argc, argv)
+ int argc;
+ char **argv;
+{
+ /* Name of CVSROOT directory. */
+ char *adm;
+ /* Name of this administrative file. */
+ char *info;
+ /* Name of ,v file for this administrative file. */
+ char *info_v;
+
+ const struct admin_file *fileptr;
+
+ umask (cvsumask);
+
+ if (argc > 1)
+ usage (init_usage);
+
+ if (client_active)
+ {
+ start_server ();
+
+ ign_setup ();
+ send_init_command ();
+ return get_responses_and_close ();
+ }
+
+ /* Note: we do *not* create parent directories as needed like the
+ old cvsinit.sh script did. Few utilities do that, and a
+ non-existent parent directory is as likely to be a typo as something
+ which needs to be created. */
+ mkdir_if_needed (CVSroot);
+
+ adm = xmalloc (strlen (CVSroot) + sizeof (CVSROOTADM) + 10);
+ strcpy (adm, CVSroot);
+ strcat (adm, "/");
+ strcat (adm, CVSROOTADM);
+ mkdir_if_needed (adm);
+
+ /* This is needed by the call to "ci" below. */
+ if (chdir (adm) < 0)
+ error (1, errno, "cannot change to directory %s", adm);
+
+ /* 80 is long enough for all the administrative file names, plus
+ "/" and so on. */
+ info = xmalloc (strlen (adm) + 80);
+ info_v = xmalloc (strlen (adm) + 80);
+ for (fileptr = filelist; fileptr && fileptr->filename; ++fileptr)
+ {
+ if (fileptr->contents == NULL)
+ continue;
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, fileptr->filename);
+ strcpy (info_v, info);
+ strcat (info_v, RCSEXT);
+ if (isfile (info_v))
+ /* We will check out this file in the mkmodules step.
+ Nothing else is required. */
+ ;
+ else
+ {
+ int retcode;
+
+ if (!isfile (info))
+ {
+ FILE *fp;
+ const char * const *p;
+
+ fp = open_file (info, "w");
+ for (p = fileptr->contents; *p != NULL; ++p)
+ if (fputs (*p, fp) < 0)
+ error (1, errno, "cannot write %s", info);
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+ }
+ /* Now check the file in. FIXME: we could be using
+ add_rcs_file from import.c which is faster (if it were
+ tweaked slightly). */
+ run_setup ("%s%s -x,v/ -q -u -t-", Rcsbin, RCS_CI);
+ run_args ("-minitial checkin of %s", fileptr->filename);
+ run_arg (fileptr->filename);
+ retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
+ if (retcode != 0)
+ error (1, retcode == -1 ? errno : 0,
+ "failed to check in %s", info);
+ }
+ }
+
+ /* Turn on history logging by default. The user can remove the file
+ to disable it. */
+ strcpy (info, adm);
+ strcat (info, "/");
+ strcat (info, CVSROOTADM_HISTORY);
+ if (!isfile (info))
+ {
+ FILE *fp;
+
+ fp = open_file (info, "w");
+ if (fclose (fp) < 0)
+ error (1, errno, "cannot close %s", info);
+ }
+
+ free (info);
+ free (info_v);
+
+ mkmodules (adm);
+
+ free (adm);
+ return 0;
+}
diff --git a/gnu/usr.bin/cvs/src/modules.c b/gnu/usr.bin/cvs/src/modules.c
index 3f3911c40cd..0e07c0bf2c8 100644
--- a/gnu/usr.bin/cvs/src/modules.c
+++ b/gnu/usr.bin/cvs/src/modules.c
@@ -23,6 +23,17 @@
#include "cvs.h"
#include "savecwd.h"
+
+/* Defines related to the syntax of the modules file. */
+
+/* Options in modules file. Note that it is OK to use GNU getopt features;
+ we already are arranging to make sure we are using the getopt distributed
+ with CVS. */
+#define CVSMODULE_OPTS "+ad:i:lo:e:s:t:u:"
+
+/* Special delimiter. */
+#define CVSMODULE_SPEC '&'
+
struct sortrec
{
char *modname;
@@ -295,7 +306,7 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* remember where we start */
if (save_cwd (&cwd))
- exit (1);
+ exit (EXIT_FAILURE);
/* copy value to our own string since if we go recursive we'll be
really screwed if we do another dbm lookup */
@@ -561,7 +572,7 @@ do_module (db, mname, m_type, msg, callback_proc, where,
/* cd back to where we started */
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
/* run checkout or tag prog if appropriate */
@@ -823,7 +834,7 @@ cat_module (status)
argc = moduleargc;
argv = moduleargv;
- optind = 1;
+ optind = 0;
wid = 0;
while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
{
diff --git a/gnu/usr.bin/cvs/src/options.h.in b/gnu/usr.bin/cvs/src/options.h.in
index d6c46d1b5df..7cb58dcd944 100644
--- a/gnu/usr.bin/cvs/src/options.h.in
+++ b/gnu/usr.bin/cvs/src/options.h.in
@@ -221,18 +221,24 @@
#define CVS_DIFFDATE
#endif
-/*
- * define this to enable the SETXID support (see FAQ 4D.13)
- */
+/* Define this to enable the SETXID support. The way to use this is
+ to create a group with no users in it (except perhaps cvs
+ administrators), set the cvs executable to setgid that group, chown
+ all the repository files to that group, and change all directory
+ permissions in the repository to 770. The last person to modify a
+ file will own it, but as long as directory permissions are set
+ right that won't matter. You'll need a system which inherits file
+ groups from the parent directory. I don't know how carefully this
+ has been inspected for security holes. */
+
#ifndef SETXID_SUPPORT
/* #define SETXID_SUPPORT */
#endif
-/* The client will not perform password-authentication unless you
- * explicitly ask for it. Whether to include the authenticating
- * server is set in config.h.
- */
-/* #define AUTH_CLIENT_SUPPORT 1 */
+/* Should we build the password-authenticating client? Whether to
+ include the password-authenticating _server_, on the other hand, is
+ set in config.h. */
+#define AUTH_CLIENT_SUPPORT 1
/*
* If you are working with a large remote repository and a 'cvs checkout' is
diff --git a/gnu/usr.bin/cvs/src/rcs.c b/gnu/usr.bin/cvs/src/rcs.c
index 8ec3267e587..c68c25524a7 100644
--- a/gnu/usr.bin/cvs/src/rcs.c
+++ b/gnu/usr.bin/cvs/src/rcs.c
@@ -14,16 +14,11 @@
static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch));
static int getrcskey PROTO((FILE * fp, char **keyp, char **valp));
-static int parse_rcs_proc PROTO((Node * file, void *closure));
static int checkmagic_proc PROTO((Node *p, void *closure));
static void do_branches PROTO((List * list, char *val));
static void do_symbols PROTO((List * list, char *val));
-static void rcsnode_delproc PROTO((Node * p));
static void rcsvers_delproc PROTO((Node * p));
-static List *rcslist;
-static char *repository;
-
/*
* We don't want to use isspace() from the C library because:
*
@@ -53,70 +48,6 @@ static const char spacetab[] = {
#define whitespace(c) (spacetab[(unsigned char)c] != 0)
-/*
- * Parse all the rcs files specified and return a list
- */
-List *
-RCS_parsefiles (files, xrepos)
- List *files;
- char *xrepos;
-{
- /* initialize */
- repository = xrepos;
- rcslist = getlist ();
-
- /* walk the list parsing files */
- if (walklist (files, parse_rcs_proc, NULL) != 0)
- {
- /* free the list and return NULL on error */
- dellist (&rcslist);
- return ((List *) NULL);
- }
- else
- /* return the list we built */
- return (rcslist);
-}
-
-/*
- * Parse an rcs file into a node on the rcs list
- */
-static int
-parse_rcs_proc (file, closure)
- Node *file;
- void *closure;
-{
- RCSNode *rdata;
-
- /* parse the rcs file into rdata */
- rdata = RCS_parse (file->key, repository);
-
- /* if we got a valid RCSNode back, put it on the list */
- if (rdata != (RCSNode *) NULL)
- RCS_addnode (file->key, rdata, rcslist);
-
- return (0);
-}
-
-/*
- * Add an RCSNode to a list of them.
- */
-
-void
-RCS_addnode (file, rcs, list)
- const char *file;
- RCSNode *rcs;
- List *list;
-{
- Node *p;
-
- p = getnode ();
- p->key = xstrdup (file);
- p->delproc = rcsnode_delproc;
- p->type = RCSNODE;
- p->data = (char *) rcs;
- (void) addnode (list, p);
-}
-
/*
* Parse an rcsfile given a user file name and a repository
@@ -216,12 +147,16 @@ RCS_parsercsfile_i (fp, rcsfile)
if (getrcskey (fp, &key, &value) == -1 || key == NULL)
goto l_error;
+ if (strcmp (key, RCSDESC) == 0)
+ goto l_error;
if (strcmp (RCSHEAD, key) == 0 && value != NULL)
rdata->head = xstrdup (value);
if (getrcskey (fp, &key, &value) == -1 || key == NULL)
goto l_error;
+ if (strcmp (key, RCSDESC) == 0)
+ goto l_error;
if (strcmp (RCSBRANCH, key) == 0 && value != NULL)
{
@@ -257,14 +192,16 @@ l_error:
}
-/*
- * Do the real work of parsing an RCS file
- *
- * There are no allowances for error here.
- */
-void
-RCS_reparsercsfile (rdata)
+/* Do the real work of parsing an RCS file.
+
+ On error, die with a fatal error; if it returns at all it was successful.
+
+ If PFP is NULL, close the file when done. Otherwise, leave it open
+ and store the FILE * in *PFP. */
+static void
+RCS_reparsercsfile (rdata, pfp)
RCSNode *rdata;
+ FILE **pfp;
{
FILE *fp;
char *rcsfile;
@@ -275,6 +212,7 @@ RCS_reparsercsfile (rdata)
char *cp;
char *key, *value;
+ assert (rdata != NULL);
rcsfile = rdata->path;
fp = fopen(rcsfile, FOPEN_BINARY_READ);
@@ -294,7 +232,8 @@ RCS_reparsercsfile (rdata)
/* if key is NULL here, then the file is missing some headers
or we had trouble reading the file. */
- if (getrcskey (fp, &key, &value) == -1 || key == NULL)
+ if (getrcskey (fp, &key, &value) == -1 || key == NULL
+ || strcmp (key, RCSDESC) == 0)
{
if (ferror(fp))
{
@@ -357,12 +296,18 @@ RCS_reparsercsfile (rdata)
vnode->date = xstrdup (valp);
- /* throw away the author field */
+ /* Get author field. */
(void) getrcskey (fp, &key, &value);
+ /* FIXME: should be using errno in case of ferror. */
+ if (key == NULL || strcmp (key, "author") != 0)
+ error (1, 0, "\
+unable to parse rcs file; `author' not in the expected place");
+ vnode->author = xstrdup (value);
- /* throw away the state field */
+ /* Get state field. */
(void) getrcskey (fp, &key, &value);
- if (strcmp (key, "state") != 0)
+ /* FIXME: should be using errno in case of ferror. */
+ if (key == NULL || strcmp (key, "state") != 0)
error (1, 0, "\
unable to parse rcs file; `state' not in the expected place");
if (strcmp (value, "dead") == 0)
@@ -372,6 +317,9 @@ unable to parse rcs file; `state' not in the expected place");
/* fill in the branch list (if any branches exist) */
(void) getrcskey (fp, &key, &value);
+ /* FIXME: should be handling various error conditions better. */
+ if (key != NULL && strcmp (key, RCSDESC) == 0)
+ value = NULL;
if (value != (char *) NULL)
{
vnode->branches = getlist ();
@@ -380,6 +328,9 @@ unable to parse rcs file; `state' not in the expected place");
/* fill in the next field if there is a next revision */
(void) getrcskey (fp, &key, &value);
+ /* FIXME: should be handling various error conditions better. */
+ if (key != NULL && strcmp (key, RCSDESC) == 0)
+ value = NULL;
if (value != (char *) NULL)
vnode->next = xstrdup (value);
@@ -387,8 +338,17 @@ unable to parse rcs file; `state' not in the expected place");
* at this point, we skip any user defined fields XXX - this is where
* we put the symbolic link stuff???
*/
+ /* FIXME: Does not correctly handle errors, e.g. from stdio. */
while ((n = getrcskey (fp, &key, &value)) >= 0)
{
+ assert (key != NULL);
+
+ if (strcmp (key, RCSDESC) == 0)
+ {
+ n = -1;
+ break;
+ }
+
/* Enable use of repositories created by certain obsolete
versions of CVS. This code should remain indefinately;
there is no procedure for converting old repositories, and
@@ -430,21 +390,19 @@ unable to parse rcs file; `state' not in the expected place");
break;
}
- fclose (fp);
+ if (pfp == NULL)
+ {
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", rcsfile);
+ }
+ else
+ {
+ *pfp = fp;
+ }
rdata->flags &= ~PARTIAL;
}
/*
- * rcsnode_delproc - free up an RCS type node
- */
-static void
-rcsnode_delproc (p)
- Node *p;
-{
- freercsnode ((RCSNode **) & p->data);
-}
-
-/*
* freercsnode - free up the info for an RCSNode
*/
void
@@ -509,6 +467,10 @@ rcsvers_delproc (p)
* o if a word starts with @, do funky rcs processing
* o strip whitespace off end of value or set value to NULL if it empty
* o return 0 since we found something besides "desc"
+ *
+ * Sets *KEYP and *VALUEP to point to storage managed by the getrcskey
+ * function; the contents are only valid until the next call to getrcskey
+ * or getrcsrev.
*/
static char *key = NULL;
@@ -570,14 +532,6 @@ getrcskey (fp, keyp, valp)
}
*cur = '\0';
- /* if we got "desc", we are done with the file */
- if (strcmp (RCSDESC, key) == 0)
- {
- *keyp = (char *) NULL;
- *valp = (char *) NULL;
- return (-1);
- }
-
/* skip whitespace between key and val */
while (whitespace (c))
{
@@ -643,6 +597,13 @@ getrcskey (fp, keyp, valp)
}
}
+ /* The syntax for some key-value pairs is different; they
+ don't end with a semicolon. */
+ if (strcmp (key, RCSDESC) == 0
+ || strcmp (key, "text") == 0
+ || strcmp (key, "log") == 0)
+ break;
+
/* compress whitespace down to a single space */
if (whitespace (c))
{
@@ -707,6 +668,63 @@ getrcskey (fp, keyp, valp)
return (0);
}
+static void getrcsrev PROTO ((FILE *fp, char **revp));
+
+/* Read an RCS revision number from FP. Put a pointer to it in *REVP;
+ it points to space managed by getrcsrev which is only good until
+ the next call to getrcskey or getrcsrev. */
+static void
+getrcsrev (fp, revp)
+ FILE *fp;
+ char **revp;
+{
+ char *cur;
+ char *max;
+ int c;
+
+ do {
+ c = getc (fp);
+ if (c == EOF)
+ /* FIXME: should be including filename in error message. */
+ error (1, errno, "cannot read rcs file");
+ } while (whitespace (c));
+
+ if (!(isdigit (c) || c == '.'))
+ /* FIXME: should be including filename in error message. */
+ error (1, 0, "error reading rcs file; revision number expected");
+
+ cur = key;
+ max = key + keysize;
+ while (isdigit (c) || c == '.')
+ {
+ if (cur >= max)
+ {
+ key = xrealloc (key, keysize + ALLOCINCR);
+ cur = key + keysize;
+ keysize += ALLOCINCR;
+ max = key + keysize;
+ }
+ *cur++ = c;
+
+ c = getc (fp);
+ if (c == EOF)
+ {
+ /* FIXME: should be including filename in error message. */
+ error (1, errno, "cannot read rcs file");
+ }
+ }
+
+ if (cur >= max)
+ {
+ key = xrealloc (key, keysize + ALLOCINCR);
+ cur = key + keysize;
+ keysize += ALLOCINCR;
+ max = key + keysize;
+ }
+ *cur = '\0';
+ *revp = key;
+}
+
/*
* process the symbols list of the rcs file
*/
@@ -852,7 +870,7 @@ RCS_gettag (rcs, symtag, force_tag_match, return_both)
/* XXX this is probably not necessary, --jtc */
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
/* If tag is "HEAD", special case to get head RCS revision */
if (tag && (strcmp (tag, TAG_HEAD) == 0 || *tag == '\0'))
@@ -1052,31 +1070,27 @@ checkmagic_proc (p, closure)
}
/*
- * Given a list of RCSNodes, returns non-zero if the specified
- * revision number or symbolic tag resolves to a "branch" within the
- * rcs file.
+ * Given an RCSNode, returns non-zero if the specified revision number
+ * or symbolic tag resolves to a "branch" within the rcs file.
+ *
+ * FIXME: this is the same as RCS_nodeisbranch except for the special
+ * case for handling a null rcsnode.
*/
int
-RCS_isbranch (file, rev, srcfiles)
- char *file;
- char *rev;
- List *srcfiles;
-{
- Node *p;
+RCS_isbranch (rcs, rev)
RCSNode *rcs;
-
+ const char *rev;
+{
/* numeric revisions are easy -- even number of dots is a branch */
if (isdigit (*rev))
return ((numdots (rev) & 1) == 0);
/* assume a revision if you can't find the RCS info */
- p = findnode (srcfiles, file);
- if (p == NULL)
+ if (rcs == NULL)
return (0);
/* now, look for a match in the symbols list */
- rcs = (RCSNode *) p->data;
- return (RCS_nodeisbranch (rev, rcs));
+ return (RCS_nodeisbranch (rcs, rev));
}
/*
@@ -1085,9 +1099,9 @@ RCS_isbranch (file, rev, srcfiles)
* take into account any magic branches as well.
*/
int
-RCS_nodeisbranch (rev, rcs)
- char *rev;
+RCS_nodeisbranch (rcs, rev)
RCSNode *rcs;
+ const char *rev;
{
int dots;
Node *p;
@@ -1130,22 +1144,18 @@ RCS_nodeisbranch (rev, rcs)
* for the specified *symbolic* tag. Magic branches are handled correctly.
*/
char *
-RCS_whatbranch (file, rev, srcfiles)
- char *file;
- char *rev;
- List *srcfiles;
+RCS_whatbranch (rcs, rev)
+ RCSNode *rcs;
+ const char *rev;
{
- int dots;
Node *p;
- RCSNode *rcs;
+ int dots;
/* assume no branch if you can't find the RCS info */
- p = findnode (srcfiles, file);
- if (p == NULL)
+ if (rcs == NULL)
return ((char *) NULL);
/* now, look for a match in the symbols list */
- rcs = (RCSNode *) p->data;
p = findnode (RCS_symbols(rcs), rev);
if (p == NULL)
return ((char *) NULL);
@@ -1198,7 +1208,7 @@ RCS_getbranch (rcs, tag, force_tag_match)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
/* find out if the tag contains a dot, or is on the trunk */
cp = strrchr (tag, '.');
@@ -1337,7 +1347,7 @@ RCS_getdate (rcs, date, force_tag_match)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
/* if the head is on a branch, try the branch first */
if (rcs->branch != NULL)
@@ -1424,7 +1434,7 @@ RCS_getdatebranch (rcs, date, branch)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
p = findnode (rcs->versions, xrev);
free (xrev);
@@ -1509,7 +1519,7 @@ RCS_getrevtime (rcs, rev, date, fudge)
assert (rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
/* look up the revision */
p = findnode (rcs->versions, rev);
@@ -1522,6 +1532,12 @@ RCS_getrevtime (rcs, rev, date, fudge)
(void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon,
&ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
&ftm->tm_sec);
+
+ /* If the year is from 1900 to 1999, RCS files contain only two
+ digits, and sscanf gives us a year from 0-99. If the year is
+ 2000+, RCS files contain all four digits and we subtract 1900,
+ because the tm_year field should contain years since 1900. */
+
if (ftm->tm_year > 1900)
ftm->tm_year -= 1900;
@@ -1565,7 +1581,7 @@ RCS_symbols(rcs)
assert(rcs != NULL);
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
if (rcs->symbols_data) {
rcs->symbols = getlist ();
@@ -1670,7 +1686,7 @@ RCS_isdead (rcs, tag)
RCSVers *version;
if (rcs->flags & PARTIAL)
- RCS_reparsercsfile (rcs);
+ RCS_reparsercsfile (rcs, NULL);
p = findnode (rcs->versions, tag);
if (p == NULL)
@@ -1679,3 +1695,568 @@ RCS_isdead (rcs, tag)
version = (RCSVers *) p->data;
return (version->dead);
}
+
+/* Return the RCS keyword expansion mode. For example "b" for binary.
+ Returns a pointer into storage which is allocated and freed along with
+ the rest of the RCS information; the caller should not modify this
+ storage. Returns NULL if the RCS file does not specify a keyword
+ expansion mode; for all other errors, die with a fatal error. */
+char *
+RCS_getexpand (rcs)
+ RCSNode *rcs;
+{
+ assert (rcs != NULL);
+ if (rcs->flags & PARTIAL)
+ RCS_reparsercsfile (rcs, NULL);
+ return rcs->expand;
+}
+
+/* Stuff related to annotate command. This should perhaps be split
+ into the stuff which knows about the guts of RCS files, and the
+ command parsing type stuff. */
+
+/* Linked list of allocated blocks. Seems kind of silly to
+ reinvent the obstack wheel, and this isn't as nice as obstacks
+ in some ways, but obstacks are pretty baroque. */
+struct allocblock
+{
+ char *text;
+ struct allocblock *next;
+};
+struct allocblock *blocks;
+
+static void *block_alloc PROTO ((size_t));
+
+static void *
+block_alloc (n)
+ size_t n;
+{
+ struct allocblock *blk;
+ blk = (struct allocblock *) xmalloc (sizeof (struct allocblock));
+ blk->text = xmalloc (n);
+ blk->next = blocks;
+ blocks = blk;
+ return blk->text;
+}
+
+static void block_free PROTO ((void));
+
+static void
+block_free ()
+{
+ struct allocblock *p;
+ struct allocblock *q;
+
+ p = blocks;
+ while (p != NULL)
+ {
+ free (p->text);
+ q = p->next;
+ free (p);
+ p = q;
+ }
+ blocks = NULL;
+}
+
+struct line
+{
+ /* Text of this line, terminated by \n or \0. */
+ char *text;
+ /* Version in which it was introduced. */
+ RCSVers *vers;
+ /* Nonzero if this line ends with \n. This will always be true
+ except possibly for the last line. */
+ int has_newline;
+};
+
+struct linevector
+{
+ /* How many lines in use for this linevector? */
+ unsigned int nlines;
+ /* How many lines allocated for this linevector? */
+ unsigned int lines_alloced;
+ /* Pointer to array containing a pointer to each line. */
+ struct line **vector;
+};
+
+static void linevector_init PROTO ((struct linevector *));
+
+/* Initialize *VEC to be a linevector with no lines. */
+static void
+linevector_init (vec)
+ struct linevector *vec;
+{
+ vec->lines_alloced = 10;
+ vec->nlines = 0;
+ vec->vector = (struct line **)
+ xmalloc (vec->lines_alloced * sizeof (*vec->vector));
+}
+
+static void linevector_add PROTO ((struct linevector *vec, char *text,
+ RCSVers *vers, unsigned int pos));
+
+/* Given some text TEXT, add each of its lines to VEC before line POS
+ (where line 0 is the first line). The last line in TEXT may or may
+ not be \n terminated. All \n in TEXT are changed to \0. Set the
+ version for each of the new lines to VERS. */
+static void
+linevector_add (vec, text, vers, pos)
+ struct linevector *vec;
+ char *text;
+ RCSVers *vers;
+ unsigned int pos;
+{
+ unsigned int i;
+ unsigned int nnew;
+ char *p;
+ struct line *lines;
+
+ assert (vec->lines_alloced > 0);
+
+ /* Count the number of lines we will need to add. */
+ nnew = 1;
+ for (p = text; *p != '\0'; ++p)
+ if (*p == '\n' && p[1] != '\0')
+ ++nnew;
+ /* Allocate the struct line's. */
+ lines = block_alloc (nnew * sizeof (struct line));
+
+ /* Expand VEC->VECTOR if needed. */
+ if (vec->nlines + nnew >= vec->lines_alloced)
+ {
+ while (vec->nlines + nnew >= vec->lines_alloced)
+ vec->lines_alloced *= 2;
+ vec->vector = xrealloc (vec->vector,
+ vec->lines_alloced * sizeof (*vec->vector));
+ }
+
+ /* Make room for the new lines in VEC->VECTOR. */
+ for (i = vec->nlines + nnew - 1; i >= pos + nnew; --i)
+ vec->vector[i] = vec->vector[i - nnew];
+
+ if (pos > vec->nlines)
+ error (1, 0, "invalid rcs file: line to add out of range");
+
+ /* Actually add the lines, to LINES and VEC->VECTOR. */
+ i = pos;
+ lines[0].text = text;
+ lines[0].vers = vers;
+ lines[0].has_newline = 0;
+ vec->vector[i++] = &lines[0];
+ for (p = text; *p != '\0'; ++p)
+ if (*p == '\n')
+ {
+ *p = '\0';
+ lines[i - pos - 1].has_newline = 1;
+ if (p[1] == '\0')
+ /* If there are no characters beyond the last newline, we
+ don't consider it another line. */
+ break;
+ lines[i - pos].text = p + 1;
+ lines[i - pos].vers = vers;
+ lines[i - pos].has_newline = 0;
+ vec->vector[i] = &lines[i - pos];
+ ++i;
+ }
+ vec->nlines += nnew;
+}
+
+static void linevector_delete PROTO ((struct linevector *, unsigned int,
+ unsigned int));
+
+/* Remove NLINES lines from VEC at position POS (where line 0 is the
+ first line). */
+static void
+linevector_delete (vec, pos, nlines)
+ struct linevector *vec;
+ unsigned int pos;
+ unsigned int nlines;
+{
+ unsigned int i;
+ unsigned int last;
+
+ last = vec->nlines - nlines;
+ for (i = pos; i < last; ++i)
+ vec->vector[i] = vec->vector[i + nlines];
+ vec->nlines -= nlines;
+}
+
+static void linevector_copy PROTO ((struct linevector *, struct linevector *));
+
+/* Copy FROM to TO, copying the vectors but not the lines pointed to. */
+static void
+linevector_copy (to, from)
+ struct linevector *to;
+ struct linevector *from;
+{
+ if (from->nlines > to->lines_alloced)
+ {
+ while (from->nlines > to->lines_alloced)
+ to->lines_alloced *= 2;
+ to->vector = (struct line **)
+ xrealloc (to->vector, to->lines_alloced * sizeof (*to->vector));
+ }
+ memcpy (to->vector, from->vector,
+ from->nlines * sizeof (*to->vector));
+ to->nlines = from->nlines;
+}
+
+static void linevector_free PROTO ((struct linevector *));
+
+/* Free storage associated with linevector (that is, the vector but
+ not the lines pointed to). */
+static void
+linevector_free (vec)
+ struct linevector *vec;
+{
+ free (vec->vector);
+}
+
+static char *month_printname PROTO ((char *));
+
+/* Given a textual string giving the month (1-12), terminated with any
+ character not recognized by atoi, return the 3 character name to
+ print it with. I do not think it is a good idea to change these
+ strings based on the locale; they are standard abbreviations (for
+ example in rfc822 mail messages) which should be widely understood.
+ Returns a pointer into static readonly storage. */
+static char *
+month_printname (month)
+ char *month;
+{
+ static const char *const months[] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ int mnum;
+
+ mnum = atoi (month);
+ if (mnum < 1 || mnum > 12)
+ return "???";
+ return (char *)months[mnum - 1];
+}
+
+static int annotate_fileproc PROTO ((struct file_info *));
+
+static int
+annotate_fileproc (finfo)
+ struct file_info *finfo;
+{
+ FILE *fp;
+ char *key;
+ char *value;
+ RCSVers *vers;
+ RCSVers *prev_vers;
+ int n;
+ int ishead;
+ Node *node;
+ struct linevector headlines;
+ struct linevector curlines;
+
+ if (finfo->rcs == NULL)
+ return (1);
+
+ /* Distinguish output for various files if we are processing
+ several files. */
+ cvs_outerr ("Annotations for ", 0);
+ cvs_outerr (finfo->fullname, 0);
+ cvs_outerr ("\n***************\n", 0);
+
+ if (!(finfo->rcs->flags & PARTIAL))
+ /* We are leaking memory by calling RCS_reparsefile again. */
+ error (0, 0, "internal warning: non-partial rcs in annotate_fileproc");
+ RCS_reparsercsfile (finfo->rcs, &fp);
+
+ ishead = 1;
+ vers = NULL;
+
+ do {
+ getrcsrev (fp, &key);
+
+ /* Stash the previous version. */
+ prev_vers = vers;
+
+ /* look up the revision */
+ node = findnode (finfo->rcs->versions, key);
+ if (node == NULL)
+ error (1, 0, "mismatch in rcs file %s between deltas and deltatexts",
+ finfo->rcs->path);
+ vers = (RCSVers *) node->data;
+
+ while ((n = getrcskey (fp, &key, &value)) >= 0)
+ {
+ if (strcmp (key, "text") == 0)
+ {
+ if (ishead)
+ {
+ char *p;
+
+ p = block_alloc (strlen (value) + 1);
+ strcpy (p, value);
+
+ linevector_init (&headlines);
+ linevector_init (&curlines);
+ linevector_add (&headlines, p, NULL, 0);
+ linevector_copy (&curlines, &headlines);
+ ishead = 0;
+ }
+ else
+ {
+ char *p;
+ char *q;
+ int op;
+ /* The RCS format throws us for a loop in that the
+ deltafrags (if we define a deltafrag as an
+ add or a delete) need to be applied in reverse
+ order. So we stick them into a linked list. */
+ struct deltafrag {
+ enum {ADD, DELETE} type;
+ unsigned long pos;
+ unsigned long nlines;
+ char *new_lines;
+ struct deltafrag *next;
+ };
+ struct deltafrag *dfhead;
+ struct deltafrag *df;
+
+ dfhead = NULL;
+ for (p = value; p != NULL && *p != '\0'; )
+ {
+ op = *p++;
+ if (op != 'a' && op != 'd')
+ /* Can't just skip over the deltafrag, because
+ the value of op determines the syntax. */
+ error (1, 0, "unrecognized operation '%c' in %s",
+ op, finfo->rcs->path);
+ df = (struct deltafrag *)
+ xmalloc (sizeof (struct deltafrag));
+ df->next = dfhead;
+ dfhead = df;
+ df->pos = strtoul (p, &q, 10);
+
+ if (p == q)
+ error (1, 0, "number expected in %s",
+ finfo->rcs->path);
+ p = q;
+ if (*p++ != ' ')
+ error (1, 0, "space expected in %s",
+ finfo->rcs->path);
+ df->nlines = strtoul (p, &q, 10);
+ if (p == q)
+ error (1, 0, "number expected in %s",
+ finfo->rcs->path);
+ p = q;
+ if (*p++ != '\012')
+ error (1, 0, "linefeed expected in %s",
+ finfo->rcs->path);
+
+ if (op == 'a')
+ {
+ unsigned int i;
+
+ df->type = ADD;
+ i = df->nlines;
+ /* The text we want is the number of lines
+ specified, or until the end of the value,
+ whichever comes first (it will be the former
+ except in the case where we are adding a line
+ which does not end in newline). */
+ for (q = p; i != 0; ++q)
+ if (*q == '\n')
+ --i;
+ else if (*q == '\0')
+ {
+ if (i != 1)
+ error (1, 0, "\
+invalid rcs file %s: premature end of value",
+ finfo->rcs->path);
+ else
+ break;
+ }
+
+ /* Copy the text we are adding into allocated
+ space. */
+ df->new_lines = block_alloc (q - p + 1);
+ strncpy (df->new_lines, p, q - p);
+ df->new_lines[q - p] = '\0';
+
+ p = q;
+ }
+ else
+ {
+ /* Correct for the fact that line numbers in RCS
+ files start with 1. */
+ --df->pos;
+
+ assert (op == 'd');
+ df->type = DELETE;
+ }
+ }
+ for (df = dfhead; df != NULL;)
+ {
+ unsigned int ln;
+
+ switch (df->type)
+ {
+ case ADD:
+ linevector_add (&curlines, df->new_lines,
+ NULL, df->pos);
+ break;
+ case DELETE:
+ if (df->pos > curlines.nlines
+ || df->pos + df->nlines > curlines.nlines)
+ error (1, 0, "\
+invalid rcs file %s (`d' operand out of range)",
+ finfo->rcs->path);
+ for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
+ curlines.vector[ln]->vers = prev_vers;
+ linevector_delete (&curlines, df->pos, df->nlines);
+ break;
+ }
+ df = df->next;
+ free (dfhead);
+ dfhead = df;
+ }
+ }
+ break;
+ }
+ }
+ if (n < 0)
+ goto l_error;
+ } while (vers->next != NULL);
+
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", finfo->rcs->path);
+
+ /* Now print out the data we have just computed. */
+ {
+ unsigned int ln;
+
+ for (ln = 0; ln < headlines.nlines; ++ln)
+ {
+ char buf[80];
+ /* Period which separates year from month in date. */
+ char *ym;
+ /* Period which separates month from day in date. */
+ char *md;
+ RCSVers *prvers;
+
+ prvers = headlines.vector[ln]->vers;
+ if (prvers == NULL)
+ prvers = vers;
+
+ sprintf (buf, "%-12s (%-8.8s ",
+ prvers->version,
+ prvers->author);
+ cvs_output (buf, 0);
+
+ /* Now output the date. */
+ ym = strchr (prvers->date, '.');
+ if (ym == NULL)
+ cvs_output ("??-???-??", 0);
+ else
+ {
+ md = strchr (ym + 1, '.');
+ if (md == NULL)
+ cvs_output ("??", 0);
+ else
+ cvs_output (md + 1, 2);
+
+ cvs_output ("-", 1);
+ cvs_output (month_printname (ym + 1), 0);
+ cvs_output ("-", 1);
+ /* Only output the last two digits of the year. Our output
+ lines are long enough as it is without printing the
+ century. */
+ cvs_output (ym - 2, 2);
+ }
+ cvs_output ("): ", 0);
+ cvs_output (headlines.vector[ln]->text, 0);
+ cvs_output ("\n", 1);
+ }
+ }
+
+ if (!ishead)
+ {
+ linevector_free (&curlines);
+ linevector_free (&headlines);
+ }
+ block_free ();
+ return 0;
+
+ l_error:
+ if (ferror (fp))
+ error (1, errno, "cannot read %s", finfo->rcs->path);
+ else
+ error (1, 0, "%s does not appear to be a valid rcs file",
+ finfo->rcs->path);
+ /* Shut up gcc -Wall. */
+ return 0;
+}
+
+static const char *const annotate_usage[] =
+{
+ "Usage: %s %s [-l] [files...]\n",
+ "\t-l\tLocal directory only, no recursion.\n",
+ NULL
+};
+
+/* Command to show the revision, date, and author where each line of a
+ file was modified. Currently it will only show the trunk, all the
+ way to the head, but it would be useful to enhance it to (a) allow
+ one to specify a revision, and display only as far as that (easy;
+ just have annotate_fileproc set all the ->vers fields to NULL when
+ you hit that revision), and (b) handle branches (not as easy, but
+ doable). The user interface for both (a) and (b) could be a -r
+ option. */
+
+int
+annotate (argc, argv)
+ int argc;
+ char **argv;
+{
+ int local = 0;
+ int c;
+
+ if (argc == -1)
+ usage (annotate_usage);
+
+ optind = 0;
+ while ((c = getopt (argc, argv, "+l")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ local = 1;
+ break;
+ case '?':
+ default:
+ usage (annotate_usage);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef CLIENT_SUPPORT
+ if (client_active)
+ {
+ start_server ();
+ ign_setup ();
+
+ 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);
+ send_to_server ("annotate\012", 0);
+ return get_responses_and_close ();
+ }
+#endif /* CLIENT_SUPPORT */
+
+ return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL,
+ (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
+ argc, argv, local, W_LOCAL, 0, 1, (char *)NULL,
+ 1, 0);
+}
diff --git a/gnu/usr.bin/cvs/src/rcs.h b/gnu/usr.bin/cvs/src/rcs.h
index 899a74de42c..698a3b17c04 100644
--- a/gnu/usr.bin/cvs/src/rcs.h
+++ b/gnu/usr.bin/cvs/src/rcs.h
@@ -61,6 +61,7 @@ struct rcsversnode
{
char *version;
char *date;
+ char *author;
char *next;
int dead;
List *branches;
@@ -79,7 +80,6 @@ typedef struct rcsversnode RCSVers;
/*
* exported interfaces
*/
-List *RCS_parsefiles PROTO((List * files, char *xrepos));
RCSNode *RCS_parse PROTO((const char *file, const char *repos));
RCSNode *RCS_parsercsfile PROTO((char *rcsfile));
char *RCS_check_kflag PROTO((const char *arg));
@@ -89,16 +89,16 @@ char *RCS_gettag PROTO((RCSNode * rcs, char *symtag, int force_tag_match,
char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date,
int force_tag_match, int return_both));
char *RCS_magicrev PROTO((RCSNode *rcs, char *rev));
-int RCS_isbranch PROTO((char *file, char *rev, List *srcfiles));
-int RCS_nodeisbranch PROTO((char *rev, RCSNode *rcs));
-char *RCS_whatbranch PROTO((char *file, char *tag, List *srcfiles));
+int RCS_isbranch PROTO((RCSNode *rcs, const char *rev));
+int RCS_nodeisbranch PROTO((RCSNode *rcs, const char *tag));
+char *RCS_whatbranch PROTO((RCSNode *rcs, const char *tag));
char *RCS_head PROTO((RCSNode * rcs));
int RCS_datecmp PROTO((char *date1, char *date2));
time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge));
List *RCS_symbols PROTO((RCSNode *rcs));
void RCS_check_tag PROTO((const char *tag));
void freercsnode PROTO((RCSNode ** rnodep));
-void RCS_addnode PROTO((const char *file, RCSNode *rcs, List *list));
char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match));
int RCS_isdead PROTO((RCSNode *, const char *));
+char *RCS_getexpand PROTO ((RCSNode *));
diff --git a/gnu/usr.bin/cvs/src/rcscmds.c b/gnu/usr.bin/cvs/src/rcscmds.c
index c8785857ca2..66aea57447a 100644
--- a/gnu/usr.bin/cvs/src/rcscmds.c
+++ b/gnu/usr.bin/cvs/src/rcscmds.c
@@ -12,12 +12,28 @@
#include "cvs.h"
#include <assert.h>
+/* For RCS file PATH, make symbolic tag TAG point to revision REV.
+ This validates that TAG is OK for a user to use. Return value is
+ -1 for error (and errno is set to indicate the error), positive for
+ error (and an error message has been printed), or zero for success. */
+
int
RCS_settag(path, tag, rev)
const char *path;
const char *tag;
const char *rev;
{
+ if (strcmp (tag, TAG_BASE) == 0
+ || strcmp (tag, TAG_HEAD) == 0)
+ {
+ /* Print the name of the tag might be considered redundant
+ with the caller, which also prints it. Perhaps this helps
+ clarify why the tag name is considered reserved, I don't
+ know. */
+ error (0, 0, "Attempt to add reserved tag name %s", tag);
+ return 1;
+ }
+
run_setup ("%s%s -x,v/ -q -N%s:%s", Rcsbin, RCS, tag, rev);
run_arg (path);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
diff --git a/gnu/usr.bin/cvs/src/recurse.c b/gnu/usr.bin/cvs/src/recurse.c
index 400856d75ac..ec51a9802a8 100644
--- a/gnu/usr.bin/cvs/src/recurse.c
+++ b/gnu/usr.bin/cvs/src/recurse.c
@@ -81,6 +81,8 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
List *files_by_dir = NULL;
struct recursion_frame frame;
+ expand_wild (argc, argv, &argc, &argv);
+
if (update_preload == NULL)
update_dir[0] = '\0';
else
@@ -114,7 +116,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
* called with the list of sub-dirs of the current dir as args
*/
if ((which & W_LOCAL) && !isdir (CVSADM))
- dirlist = Find_Dirs ((char *) NULL, W_LOCAL);
+ dirlist = Find_Directories ((char *) NULL, W_LOCAL);
else
addlist (&dirlist, ".");
@@ -245,6 +247,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc,
frame.flags, frame.which, frame.aflag,
frame.readlock, frame.dosrcs);
+ /* Free the data which expand_wild allocated. */
+ for (i = 0; i < argc; ++i)
+ free (argv[i]);
+ free (argv);
return (err);
}
@@ -382,7 +388,7 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
/* find sub-directories if we will recurse */
if (flags != R_SKIP_DIRS)
- dirlist = Find_Dirs (repository, which);
+ dirlist = Find_Directories (repository, which);
}
else
{
@@ -396,7 +402,7 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
}
/* process the files (if any) */
- if (filelist != NULL)
+ if (filelist != NULL && fileproc)
{
struct file_info finfo_struct;
@@ -413,12 +419,6 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
notify_check (repository, update_dir);
#endif /* CLIENT_SUPPORT */
- /* pre-parse the source files */
- if (dosrcs && repository)
- finfo_struct.srcfiles = RCS_parsefiles (filelist, repository);
- else
- finfo_struct.srcfiles = (List *) NULL;
-
finfo_struct.repository = repository;
finfo_struct.update_dir = update_dir;
finfo_struct.entries = entries;
@@ -433,7 +433,6 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc,
/* clean up */
dellist (&filelist);
- dellist (&finfo_struct.srcfiles);
}
if (entries)
@@ -477,11 +476,30 @@ do_file_proc (p, closure)
void *closure;
{
struct file_info *finfo = (struct file_info *)closure;
+ int ret;
+
finfo->file = p->key;
- if (fileproc != NULL)
- return fileproc (finfo);
- else
- return (0);
+ finfo->fullname = xmalloc (strlen (finfo->file)
+ + strlen (finfo->update_dir)
+ + 2);
+ finfo->fullname[0] = '\0';
+ if (finfo->update_dir[0] != '\0')
+ {
+ strcat (finfo->fullname, finfo->update_dir);
+ strcat (finfo->fullname, "/");
+ }
+ strcat (finfo->fullname, finfo->file);
+
+ if (dosrcs && repository)
+ finfo->rcs = RCS_parse (finfo->file, repository);
+ else
+ finfo->rcs = (RCSNode *) NULL;
+ ret = fileproc (finfo);
+
+ freercsnode(&finfo->rcs);
+ free (finfo->fullname);
+
+ return (ret);
}
/*
@@ -545,7 +563,7 @@ do_dir_proc (p, closure)
{
/* save our current directory and static vars */
if (save_cwd (&cwd))
- exit (1);
+ exit (EXIT_FAILURE);
sdirlist = dirlist;
srepository = repository;
dirlist = NULL;
@@ -579,7 +597,7 @@ do_dir_proc (p, closure)
/* get back to where we started and restore state vars */
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
dirlist = sdirlist;
repository = srepository;
@@ -663,7 +681,7 @@ unroll_files_proc (p, closure)
if (strcmp(p->key, ".") != 0)
{
if (save_cwd (&cwd))
- exit (1);
+ exit (EXIT_FAILURE);
if (chdir (p->key) < 0)
error (1, errno, "could not chdir to %s", p->key);
@@ -686,7 +704,7 @@ unroll_files_proc (p, closure)
free (save_update_dir);
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
}
diff --git a/gnu/usr.bin/cvs/src/remove.c b/gnu/usr.bin/cvs/src/remove.c
index e130657a4c3..2911bf41ff7 100644
--- a/gnu/usr.bin/cvs/src/remove.c
+++ b/gnu/usr.bin/cvs/src/remove.c
@@ -75,7 +75,7 @@ cvsremove (argc, argv)
ign_setup ();
if (local)
send_arg("-l");
- send_file_names (argc, argv);
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
send_files (argc, argv, local, 0);
send_to_server ("remove\012", 0);
return get_responses_and_close ();
@@ -118,11 +118,7 @@ remove_fileproc (finfo)
{
if (unlink (finfo->file) < 0 && ! existence_error (errno))
{
- if (finfo->update_dir[0] == '\0')
- error (0, errno, "unable to remove %s", finfo->file);
- else
- error (0, errno, "unable to remove %s/%s", finfo->update_dir,
- finfo->file);
+ error (0, errno, "unable to remove %s", finfo->fullname);
}
}
/* else FIXME should probably act as if the file doesn't exist
@@ -130,18 +126,19 @@ remove_fileproc (finfo)
}
vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL, (char *) NULL,
- finfo->file, 0, 0, finfo->entries, finfo->srcfiles);
+ finfo->file, 0, 0, finfo->entries, finfo->rcs);
if (vers->ts_user != NULL)
{
existing_files++;
if (!quiet)
- error (0, 0, "file `%s' still in working directory", finfo->file);
+ error (0, 0, "file `%s' still in working directory",
+ finfo->fullname);
}
else if (vers->vn_user == NULL)
{
if (!quiet)
- error (0, 0, "nothing known about `%s'", finfo->file);
+ error (0, 0, "nothing known about `%s'", finfo->fullname);
}
else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
{
@@ -153,7 +150,7 @@ remove_fileproc (finfo)
(void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
(void) unlink_file (fname);
if (!quiet)
- error (0, 0, "removed `%s'", finfo->file);
+ error (0, 0, "removed `%s'", finfo->fullname);
#ifdef SERVER_SUPPORT
if (server_active)
@@ -163,7 +160,8 @@ remove_fileproc (finfo)
else if (vers->vn_user[0] == '-')
{
if (!quiet)
- error (0, 0, "file `%s' already scheduled for removal", finfo->file);
+ error (0, 0, "file `%s' already scheduled for removal",
+ finfo->fullname);
}
else
{
@@ -173,7 +171,7 @@ remove_fileproc (finfo)
Register (finfo->entries, finfo->file, fname, vers->ts_rcs, vers->options,
vers->tag, vers->date, vers->ts_conflict);
if (!quiet)
- error (0, 0, "scheduling `%s' for removal", finfo->file);
+ error (0, 0, "scheduling `%s' for removal", finfo->fullname);
removed_files++;
#ifdef SERVER_SUPPORT
diff --git a/gnu/usr.bin/cvs/src/repos.c b/gnu/usr.bin/cvs/src/repos.c
index a61b5c7a1d4..7beaabacf80 100644
--- a/gnu/usr.bin/cvs/src/repos.c
+++ b/gnu/usr.bin/cvs/src/repos.c
@@ -4,14 +4,19 @@
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.4 kit.
- *
- * Name of Repository
- *
- * Determine the name of the RCS repository and sets "Repository" accordingly.
*/
#include "cvs.h"
+/* Determine the name of the RCS repository for directory DIR in the
+ current working directory, or for the current working directory
+ itself if DIR is NULL. Returns the name in a newly-malloc'd
+ string. On error, gives a fatal error and does not return.
+ UPDATE_DIR is the path from where cvs was invoked (for use in error
+ messages), and should contain DIR as its last component.
+ UPDATE_DIR can be NULL to signify the directory in which cvs was
+ invoked. */
+
char *
Name_Repository (dir, update_dir)
char *dir;
diff --git a/gnu/usr.bin/cvs/src/rtag.c b/gnu/usr.bin/cvs/src/rtag.c
index b175f7bfbc4..8609647a9e8 100644
--- a/gnu/usr.bin/cvs/src/rtag.c
+++ b/gnu/usr.bin/cvs/src/rtag.c
@@ -350,7 +350,7 @@ check_fileproc (finfo)
p->type = UPDATE;
p->delproc = tag_delproc;
vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL,
- (char *) NULL, finfo->file, 0, 0, finfo->entries, finfo->srcfiles);
+ (char *) NULL, finfo->file, 0, 0, finfo->entries, finfo->rcs);
p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0);
if (p->data != NULL)
{
@@ -499,16 +499,13 @@ static int
rtag_fileproc (finfo)
struct file_info *finfo;
{
- Node *p;
RCSNode *rcsfile;
char *version, *rev;
int retcode = 0;
/* find the parsed RCS data */
- p = findnode (finfo->srcfiles, finfo->file);
- if (p == NULL)
+ if ((rcsfile = finfo->rcs) == NULL)
return (1);
- rcsfile = (RCSNode *) p->data;
/*
* For tagging an RCS file which is a symbolic link, you'd best be
@@ -561,51 +558,51 @@ rtag_fileproc (finfo)
}
else
{
- char *oversion;
+ char *oversion;
- /*
- * As an enhancement for the case where a tag is being re-applied to
- * a large body of a module, make one extra call to RCS_getversion to
- * see if the tag is already set in the RCS file. If so, check to
- * see if it needs to be moved. If not, do nothing. This will
- * likely save a lot of time when simply moving the tag to the
- * "current" head revisions of a module -- which I have found to be a
- * typical tagging operation.
- */
- rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
- oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0);
- if (oversion != NULL)
- {
- int isbranch = RCS_isbranch (finfo->file, symtag, finfo->srcfiles);
-
- /*
- * if versions the same and neither old or new are branches don't
- * have to do anything
- */
- if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
- {
- free (oversion);
- free (version);
- return (0);
- }
+ /*
+ * As an enhancement for the case where a tag is being re-applied to
+ * a large body of a module, make one extra call to RCS_getversion to
+ * see if the tag is already set in the RCS file. If so, check to
+ * see if it needs to be moved. If not, do nothing. This will
+ * likely save a lot of time when simply moving the tag to the
+ * "current" head revisions of a module -- which I have found to be a
+ * typical tagging operation.
+ */
+ rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
+ oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0);
+ if (oversion != NULL)
+ {
+ int isbranch = RCS_isbranch (finfo->rcs, symtag);
+
+ /*
+ * if versions the same and neither old or new are branches don't
+ * have to do anything
+ */
+ if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
+ {
+ free (oversion);
+ free (version);
+ return (0);
+ }
- if (!force_tag_move) { /* we're NOT going to move the tag */
- if (finfo->update_dir[0])
- (void) printf ("W %s/%s", finfo->update_dir, finfo->file);
- else
- (void) printf ("W %s", finfo->file);
-
- (void) printf (" : %s already exists on %s %s",
- symtag, isbranch ? "branch" : "version", oversion);
- (void) printf (" : NOT MOVING tag to %s %s\n",
- branch_mode ? "branch" : "version", rev);
- free (oversion);
- free (version);
- return (0);
- }
- free (oversion);
- }
- retcode = RCS_settag(rcsfile->path, symtag, rev);
+ if (!force_tag_move)
+ {
+ /* we're NOT going to move the tag */
+ (void) printf ("W %s", finfo->fullname);
+
+ (void) printf (" : %s already exists on %s %s",
+ symtag, isbranch ? "branch" : "version",
+ oversion);
+ (void) printf (" : NOT MOVING tag to %s %s\n",
+ branch_mode ? "branch" : "version", rev);
+ free (oversion);
+ free (version);
+ return (0);
+ }
+ free (oversion);
+ }
+ retcode = RCS_settag(rcsfile->path, symtag, rev);
}
if (retcode != 0)
diff --git a/gnu/usr.bin/cvs/src/run.c b/gnu/usr.bin/cvs/src/run.c
index 42eeb27a430..036821e08c6 100644
--- a/gnu/usr.bin/cvs/src/run.c
+++ b/gnu/usr.bin/cvs/src/run.c
@@ -326,11 +326,13 @@ run_exec (stin, stout, sterr, flags)
break;
}
#endif
+
if (w == -1)
{
rc = -1;
rerrno = errno;
}
+#ifndef VMS /* status is return status */
else if (WIFEXITED (status))
rc = WEXITSTATUS (status);
else if (WIFSIGNALED (status))
@@ -341,6 +343,9 @@ run_exec (stin, stout, sterr, flags)
}
else
rc = 1;
+#else /* VMS */
+ rc = WEXITSTATUS (status);
+#endif /* VMS */
/* restore the signals */
#ifdef POSIX_SIGNALS
diff --git a/gnu/usr.bin/cvs/src/sanity.sh b/gnu/usr.bin/cvs/src/sanity.sh
index c47233d17a1..4f80f906abf 100644
--- a/gnu/usr.bin/cvs/src/sanity.sh
+++ b/gnu/usr.bin/cvs/src/sanity.sh
@@ -30,6 +30,18 @@ else
remote=no
fi
+# The --keep option will eventually cause all the tests to leave around the
+# contents of the /tmp directory; right now only some implement it. Not
+# useful if you are running more than one test.
+# FIXME: need some real option parsing so this doesn't depend on the order
+# in which they are specified.
+if test x"$1" = x"--keep"; then
+ shift
+ keep=yes
+else
+ keep=no
+fi
+
# Use full path for CVS executable, so that CVS_SERVER gets set properly
# for remote.
case $1 in
@@ -109,6 +121,14 @@ else
PLUS='\+'
fi
+# Likewise, for ?
+QUESTION='?'
+if expr 'a?b' : "a${QUESTION}b" >/dev/null; then
+ : good, it works
+else
+ QUESTION='\?'
+fi
+
# Cause NextStep 3.3 users to lose in a more graceful fashion.
if expr 'abc
def' : 'abc
@@ -121,6 +141,17 @@ else
exit 1
fi
+# Warn SunOS, SysVr3.2, etc., users that they may be partially losing
+if expr 'a
+b' : 'a
+c' >/dev/null; then
+ echo 'Warning: you are using a version of expr which does not correctly'
+ echo 'match multi-line patterns. Some tests may spuriously pass.'
+ echo 'You may wish to make sure GNU expr is in your path.'
+else
+ : good, it works
+fi
+
pass ()
{
echo "PASS: $1" >>${LOGFILE}
@@ -133,29 +164,10 @@ fail ()
exit 1
}
-# Usage:
-# dotest TESTNAME COMMAND OUTPUT [OUTPUT2]
-# TESTNAME is the name used in the log to identify the test.
-# COMMAND is the command to run; for the test to pass, it exits with
-# exitstatus zero.
-# OUTPUT is a regexp which is compared against the output (stdout and
-# stderr combined) from the test. It is anchored to the start and end
-# of the output, so should start or end with ".*" if that is what is desired.
-# Trailing newlines are stripped from the command's actual output before
-# matching against OUTPUT.
-# If OUTPUT2 is specified and the output matches it, then it is also
-# a pass (partial workaround for the fact that some versions of expr
-# lack \|).
-dotest ()
+# See dotest and dotest_fail for explanation (this is the parts
+# of the implementation common to the two).
+dotest_internal ()
{
- if $2 >${TESTDIR}/dotest.tmp 2>&1; then
- : so far so good
- else
- status=$?
- cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
- echo "exit status was $status" >>${LOGFILE}
- fail "$1"
- fi
# expr can't distinguish between "zero characters matched" and "no match",
# so special-case it.
if test -z "$3"; then
@@ -200,9 +212,33 @@ dotest ()
fi
}
-# Like dotest except exitstatus should be nonzero. Probably their
-# implementations could be unified (if I were a good enough sh script
-# writer to get the quoting right).
+# Usage:
+# dotest TESTNAME COMMAND OUTPUT [OUTPUT2]
+# TESTNAME is the name used in the log to identify the test.
+# COMMAND is the command to run; for the test to pass, it exits with
+# exitstatus zero.
+# OUTPUT is a regexp which is compared against the output (stdout and
+# stderr combined) from the test. It is anchored to the start and end
+# of the output, so should start or end with ".*" if that is what is desired.
+# Trailing newlines are stripped from the command's actual output before
+# matching against OUTPUT.
+# If OUTPUT2 is specified and the output matches it, then it is also
+# a pass (partial workaround for the fact that some versions of expr
+# lack \|).
+dotest ()
+{
+ if $2 >${TESTDIR}/dotest.tmp 2>&1; then
+ : so far so good
+ else
+ status=$?
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ echo "exit status was $status" >>${LOGFILE}
+ fail "$1"
+ fi
+ dotest_internal "$@"
+}
+
+# Like dotest except exitstatus should be nonzero.
dotest_fail ()
{
if $2 >${TESTDIR}/dotest.tmp 2>&1; then
@@ -213,32 +249,22 @@ dotest_fail ()
else
: so far so good
fi
- # expr can't distinguish between "zero characters matched" and "no match",
- # so special-case it.
- if test -z "$3"; then
- if test -s ${TESTDIR}/dotest.tmp; then
- echo "** expected: " >>${LOGFILE}
- echo "$3" >>${LOGFILE}
- echo "** got: " >>${LOGFILE}
- cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
- fail "$1"
- else
- cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
- pass "$1"
- fi
+ dotest_internal "$@"
+}
+
+# Like dotest except second argument is the required exitstatus.
+dotest_status ()
+{
+ $3 >${TESTDIR}/dotest.tmp 2>&1
+ status=$?
+ if test "$status" = "$2"; then
+ : so far so good
else
- if expr "`cat ${TESTDIR}/dotest.tmp`" : \
- ${STARTANCHOR}"$3"${ENDANCHOR} >/dev/null; then
- cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
- pass "$1"
- else
- echo "** expected: " >>${LOGFILE}
- echo "$3" >>${LOGFILE}
- echo "** got: " >>${LOGFILE}
- cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
- fail "$1"
- fi
+ cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
+ echo "exit status was $status; expected $2" >>${LOGFILE}
+ fail "$1"
fi
+ dotest_internal "$1" "$3" "$4" "$5"
}
# clean any old remnants
@@ -416,9 +442,23 @@ for what in $tests; do
'Directory /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir added to the repository'
cd ssdir
echo ssfile >ssfile
+
+ # Trying to commit it without a "cvs add" should be an error.
+ # The "use `cvs add' to create an entry" message is the one
+ # that I consider to be more correct, but local cvs prints the
+ # "nothing known" message and noone has gotten around to fixing it.
+ dotest_fail basica-notadded "${testcvs} -q ci ssfile" \
+"${PROG} [a-z]*: use "'`cvs add'\'' to create an entry for ssfile
+'"${PROG}"' \[[a-z]* aborted\]: correct above errors first!' \
+"${PROG}"' [a-z]*: nothing known about `ssfile'\''
+'"${PROG}"' \[[a-z]* aborted\]: correct above errors first!'
+
dotest basica-4 "${testcvs} add ssfile" \
"${PROG}"' [a-z]*: scheduling file `ssfile'\'' for addition
'"${PROG}"' [a-z]*: use '\''cvs commit'\'' to add this file permanently'
+ dotest_fail basica-4a "${testcvs} tag tag0 ssfile" \
+"${PROG} [a-z]*: nothing known about ssfile
+${PROG} "'\[[a-z]* aborted\]: correct the above errors first!'
cd ../..
dotest basica-5 "${testcvs} -q ci -m add-it" \
'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v
@@ -427,8 +467,28 @@ Checking in sdir/ssdir/ssfile;
/tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile
initial revision: 1.1
done'
+ dotest_fail basica-5a \
+ "${testcvs} -q tag BASE sdir/ssdir/ssfile" \
+"${PROG} [a-z]*: Attempt to add reserved tag name BASE
+${PROG} \[[a-z]* aborted\]: failed to set tag BASE to revision 1.1 in /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v"
+ dotest basica-5b "${testcvs} -q tag NOT_RESERVED" \
+'T sdir/ssdir/ssfile'
+
dotest basica-6 "${testcvs} -q update" ''
echo "ssfile line 2" >>sdir/ssdir/ssfile
+ dotest_status basica-6.2 1 "${testcvs} -q diff -c" \
+'Index: sdir/ssdir/ssfile
+===================================================================
+RCS file: /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v
+retrieving revision 1\.1
+diff -c -r1\.1 ssfile
+\*\*\* ssfile [0-9/]* [0-9:]* 1\.1
+--- ssfile [0-9/]* [0-9:]*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+--- 1,2 ----
+ ssfile
+'"${PLUS} ssfile line 2"
dotest basica-7 "${testcvs} -q ci -m modify-it" \
'Checking in sdir/ssdir/ssfile;
/tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile
@@ -438,6 +498,17 @@ done'
"${PROG}"' [a-z]*: nothing known about `nonexist'\''
'"${PROG}"' \[[a-z]* aborted\]: correct above errors first!'
dotest basica-8 "${testcvs} -q update" ''
+ dotest_fail basica-9 \
+ "${testcvs} -q -d /tmp/cvs-sanity/nonexist update" \
+"${PROG}: .*/tmp/cvs-sanity/cvsroot value for CVS Root found in CVS/Root
+${PROG}"': does not match command line -d /tmp/cvs-sanity/nonexist setting
+'"${PROG}"': you may wish to try the cvs command again without the -d option '
+
+ dotest basica-10 "${testcvs} annotate" \
+'Annotations for sdir/ssdir/ssfile
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+1.1 .[a-z@][a-z@ ]* [0-9a-zA-Z-]*.: ssfile
+1.2 .[a-z@][a-z@ ]* [0-9a-zA-Z-]*.: ssfile line 2'
cd ..
rm -rf ${CVSROOT_DIRNAME}/first-dir
@@ -498,24 +569,6 @@ done'
echo "FAIL: test 18-${do}-$j" | tee -a ${LOGFILE}
fi
- if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then
- true
- else
- # diff -c all
- if ${CVS} diff -c >> ${LOGFILE} || [ $? = 1 ] ; then
- echo "PASS: test 19-${do}-$j" >>${LOGFILE}
- else
- echo "FAIL: test 19-${do}-$j" | tee -a ${LOGFILE}
- fi
-
- # diff -u all
- if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then
- echo "PASS: test 20-${do}-$j" >>${LOGFILE}
- else
- echo "FAIL: test 20-${do}-$j" | tee -a ${LOGFILE}
- fi
- fi
-
cd ..
# update all.
if ${CVS} update ; then
@@ -546,26 +599,6 @@ done'
echo "FAIL: test 24-${do}-$j" | tee -a ${LOGFILE} ; exit 1
fi
- if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then
- echo "PASS: test 25-${do}-$j" >>${LOGFILE}
- else
- # diff all
- if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then
- echo "PASS: test 25-${do}-$j" >>${LOGFILE}
- else
- echo "FAIL: test 25-${do}-$j" | tee -a ${LOGFILE}
- # FIXME; exit 1
- fi
-
- # diff all
- if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then
- echo "PASS: test 26-${do}-$j" >>${LOGFILE}
- else
- echo "FAIL: test 26-${do}-$j" | tee -a ${LOGFILE}
- # FIXME; exit 1
- fi
- fi
-
# update all.
if ${CVS} co first-dir ; then
echo "PASS: test 27-${do}-$j" >>${LOGFILE}
@@ -954,11 +987,7 @@ No conflicts created by this import'
mv first-dir.cpy first-dir
cd first-dir
- if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then
- echo "PASS: test 61" >>${LOGFILE}
- else
- echo "FAIL: test 61" | tee -a ${LOGFILE} ; exit 1
- fi
+ dotest 61 "${testcvs} -q diff -u" ''
if ${CVS} update ; then
echo "PASS: test 62" >>${LOGFILE}
@@ -1365,10 +1394,12 @@ done'
echo 1:ancest >file1
echo 2:ancest >file2
echo 3:ancest >file3
- dotest branches-2 "${testcvs} add file1 file2 file3" \
+ echo 4:trunk-1 >file4
+ dotest branches-2 "${testcvs} add file1 file2 file3 file4" \
"${PROG}"' [a-z]*: scheduling file `file1'\'' for addition
'"${PROG}"' [a-z]*: scheduling file `file2'\'' for addition
'"${PROG}"' [a-z]*: scheduling file `file3'\'' for addition
+'"${PROG}"' [a-z]*: scheduling file `file4'\'' for addition
'"${PROG}"' [a-z]*: use '\''cvs commit'\'' to add these files permanently'
dotest branches-3 "${testcvs} -q ci -m add-it" \
'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/file1,v
@@ -1388,15 +1419,29 @@ done
Checking in file3;
/tmp/cvs-sanity/cvsroot/first-dir/file3,v <-- file3
initial revision: 1.1
+done
+RCS file: /tmp/cvs-sanity/cvsroot/first-dir/file4,v
+done
+Checking in file4;
+/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4
+initial revision: 1.1
+done'
+ echo 4:trunk-2 >file4
+ dotest branches-3.2 "${testcvs} -q ci -m trunk-before-branch" \
+'Checking in file4;
+/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4
+new revision: 1.2; previous revision: 1.1
done'
dotest branches-4 "${testcvs} tag -b br1" "${PROG}"' [a-z]*: Tagging \.
T file1
T file2
-T file3'
+T file3
+T file4'
dotest branches-5 "${testcvs} update -r br1" \
"${PROG}"' [a-z]*: Updating \.'
echo 1:br1 >file1
echo 2:br1 >file2
+ echo 4:br1 >file4
dotest branches-6 "${testcvs} -q ci -m modify" \
'Checking in file1;
/tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
@@ -1405,29 +1450,129 @@ done
Checking in file2;
/tmp/cvs-sanity/cvsroot/first-dir/file2,v <-- file2
new revision: 1.1.2.1; previous revision: 1.1
+done
+Checking in file4;
+/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4
+new revision: 1.2.2.1; previous revision: 1.2
done'
dotest branches-7 "${testcvs} -q tag -b brbr" 'T file1
T file2
-T file3'
+T file3
+T file4'
dotest branches-8 "${testcvs} -q update -r brbr" ''
echo 1:brbr >file1
+ echo 4:brbr >file4
dotest branches-9 "${testcvs} -q ci -m modify" \
'Checking in file1;
/tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1
new revision: 1.1.2.1.2.1; previous revision: 1.1.2.1
+done
+Checking in file4;
+/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4
+new revision: 1.2.2.1.2.1; previous revision: 1.2.2.1
done'
- dotest branches-10 "cat file1 file2 file3" '1:brbr
+ dotest branches-10 "cat file1 file2 file3 file4" '1:brbr
2:br1
-3:ancest'
- dotest branches-11 "${testcvs} -q update -r br1" 'U file1' 'P file1'
- dotest branches-12 "cat file1 file2 file3" '1:br1
+3:ancest
+4:brbr'
+ dotest branches-11 "${testcvs} -q update -r br1" \
+'[UP] file1
+[UP] file4'
+ dotest branches-12 "cat file1 file2 file3 file4" '1:br1
2:br1
-3:ancest'
- dotest branches-13 "${testcvs} -q update -A" '. file1
-. file2'
- dotest branches-14 "cat file1 file2 file3" '1:ancest
+3:ancest
+4:br1'
+ echo 4:br1-2 >file4
+ dotest branches-12.2 "${testcvs} -q ci -m change-on-br1" \
+'Checking in file4;
+/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4
+new revision: 1.2.2.2; previous revision: 1.2.2.1
+done'
+ dotest branches-13 "${testcvs} -q update -A" '[UP] file1
+[UP] file2
+[UP] file4'
+ dotest branches-14 "cat file1 file2 file3 file4" '1:ancest
2:ancest
-3:ancest'
+3:ancest
+4:trunk-2'
+ echo 4:trunk-3 >file4
+ dotest branches-14.2 \
+ "${testcvs} -q ci -m trunk-change-after-branch" \
+'Checking in file4;
+/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4
+new revision: 1.3; previous revision: 1.2
+done'
+ dotest branches-14.3 "${testcvs} log file4" \
+'
+RCS file: /tmp/cvs-sanity/cvsroot/first-dir/file4,v
+Working file: file4
+head: 1\.3
+branch:
+locks: strict
+access list:
+symbolic names:
+ brbr: 1\.2\.2\.1\.0\.2
+ br1: 1\.2\.0\.2
+keyword substitution: kv
+total revisions: 6; selected revisions: 6
+description:
+----------------------------
+revision 1\.3
+date: [0-9/: ]*; author: [a-z@][a-z@]*; state: Exp; lines: '"${PLUS}"'1 -1
+trunk-change-after-branch
+----------------------------
+revision 1\.2
+date: [0-9/: ]*; author: [a-z@][a-z@]*; state: Exp; lines: '"${PLUS}"'1 -1
+branches: 1\.2\.2;
+trunk-before-branch
+----------------------------
+revision 1\.1
+date: [0-9/: ]*; author: [a-z@][a-z@]*; state: Exp;
+add-it
+----------------------------
+revision 1\.2\.2\.2
+date: [0-9/: ]*; author: [a-z@][a-z@]*; state: Exp; lines: '"${PLUS}"'1 -1
+change-on-br1
+----------------------------
+revision 1\.2\.2\.1
+date: [0-9/: ]*; author: [a-z@][a-z@]*; state: Exp; lines: '"${PLUS}"'1 -1
+branches: 1\.2\.2\.1\.2;
+modify
+----------------------------
+revision 1\.2\.2\.1\.2\.1
+date: [0-9/: ]*; author: [a-z@][a-z@]*; state: Exp; lines: '"${PLUS}"'1 -1
+modify
+============================================================================='
+ dotest_status branches-14.4 1 \
+ "${testcvs} diff -c -r 1.1 -r 1.3 file4" \
+'Index: file4
+===================================================================
+RCS file: /tmp/cvs-sanity/cvsroot/first-dir/file4,v
+retrieving revision 1\.1
+retrieving revision 1\.3
+diff -c -r1\.1 -r1\.3
+\*\*\* file4 [0-9/]* [0-9:]* 1\.1
+--- file4 [0-9/]* [0-9:]* 1\.3
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! 4:trunk-1
+--- 1 ----
+! 4:trunk-3'
+ dotest_status branches-14.5 1 \
+ "${testcvs} diff -c -r 1.1 -r 1.2.2.1 file4" \
+'Index: file4
+===================================================================
+RCS file: /tmp/cvs-sanity/cvsroot/first-dir/file4,v
+retrieving revision 1\.1
+retrieving revision 1\.2\.2\.1
+diff -c -r1\.1 -r1\.2\.2\.1
+\*\*\* file4 [0-9/]* [0-9:]* 1\.1
+--- file4 [0-9/]* [0-9:]* 1\.2\.2\.1
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\* 1 \*\*\*\*
+! 4:trunk-1
+--- 1 ----
+! 4:br1'
dotest branches-15 \
"${testcvs} update -j 1.1.2.1 -j 1.1.2.1.2.1 file1" \
'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/file1,v
@@ -1442,6 +1587,11 @@ rcsmerge: warning: conflicts during merge'
>>>>>>> 1.1.2.1.2.1'
cd ..
+ if test "$keep" = yes; then
+ echo Keeping /tmp/cvs-sanity and exiting due to --keep
+ exit 0
+ fi
+
rm -rf ${CVSROOT_DIRNAME}/first-dir
rm -r first-dir
;;
@@ -1771,10 +1921,10 @@ Merging differences between 1.1 and 1.2 into a
rcsmerge: warning: conflicts during merge
'"${PROG}"' [a-z]*: conflicts found in a
C a
-\? dir1
-\? sdir' \
-'\? dir1
-\? sdir
+'"${QUESTION}"' dir1
+'"${QUESTION}"' sdir' \
+''"${QUESTION}"' dir1
+'"${QUESTION}"' sdir
RCS file: /tmp/cvs-sanity/cvsroot/first-dir/a,v
retrieving revision 1.1
retrieving revision 1.2
@@ -1824,10 +1974,10 @@ C a'
cd ../../2
dotest conflicts-136 "${testcvs} -q update" \
'[UP] first-dir/abc
-\? first-dir/dir1
-\? first-dir/sdir' \
-'\? first-dir/dir1
-\? first-dir/sdir
+'"${QUESTION}"' first-dir/dir1
+'"${QUESTION}"' first-dir/sdir' \
+''"${QUESTION}"' first-dir/dir1
+'"${QUESTION}"' first-dir/sdir
[UP] first-dir/abc'
dotest conflicts-137 'test -f first-dir/abc' ''
rmdir first-dir/dir1 first-dir/sdir
@@ -1897,6 +2047,9 @@ C a'
${testcvs} add subdir >>${LOGFILE}
cd subdir
+ mkdir ssdir
+ ${testcvs} add ssdir >>${LOGFILE}
+
touch a b
if ${testcvs} add a b 2>>${LOGFILE} ; then
@@ -1936,6 +2089,12 @@ C a'
echo dirmodule first-dir/subdir >>CVSROOT/modules
echo namedmodule -d nameddir first-dir/subdir >>CVSROOT/modules
echo aliasmodule -a first-dir/subdir/a >>CVSROOT/modules
+ echo aliasnested -a first-dir/subdir/ssdir >>CVSROOT/modules
+
+ # Options must come before arguments. It is possible this should
+ # be relaxed at some point (though the result would be bizarre for
+ # -a); for now test the current behavior.
+ echo bogusalias first-dir/subdir/a -a >>CVSROOT/modules
if ${testcvs} ci -m 'add modules' CVSROOT/modules \
>>${LOGFILE} 2>&1; then
echo 'PASS: test 148' >>${LOGFILE}
@@ -1944,6 +2103,21 @@ C a'
exit 1
fi
cd ..
+ dotest 148a0 "${testcvs} co -c" 'CVSROOT CVSROOT
+aliasmodule -a first-dir/subdir/a
+aliasnested -a first-dir/subdir/ssdir
+bogusalias first-dir/subdir/a -a
+dirmodule first-dir/subdir
+namedmodule -d nameddir first-dir/subdir
+realmodule first-dir/subdir a'
+ # I don't know why aliasmodule isn't printed (I would have thought
+ # that it gets printed without the -a; although I'm not sure that
+ # printing expansions without options is useful).
+ dotest 148a1 "${testcvs} co -s" 'CVSROOT NONE CVSROOT
+bogusalias NONE first-dir/subdir/a -a
+dirmodule NONE first-dir/subdir
+namedmodule NONE first-dir/subdir
+realmodule NONE first-dir/subdir a'
# Test that real modules check out to realmodule/a, not subdir/a.
if ${testcvs} co realmodule >>${LOGFILE}; then
@@ -2072,8 +2246,23 @@ U nameddir/b'
echo 'FAIL: test 154' | tee -a ${LOGFILE}
exit 1
fi
+
cd ..
- rm -rf 1 ; rm -rf ${CVSROOT_DIRNAME}/first-dir
+ rm -rf 1
+
+ mkdir 2
+ cd 2
+ dotest modules-155a0 "${testcvs} co aliasnested" \
+"${PROG} [a-z]*: Updating first-dir/subdir/ssdir"
+ dotest modules-155a1 "test -d first-dir" ''
+ dotest modules-155a2 "test -d first-dir/subdir" ''
+ dotest modules-155a3 "test -d first-dir/subdir/ssdir" ''
+ # Test that nothing extraneous got created.
+ dotest modules-155a4 "ls -1" "first-dir"
+ cd ..
+ rm -rf 2
+
+ rm -rf ${CVSROOT_DIRNAME}/first-dir
;;
mflag)
for message in '' ' ' '
@@ -2454,14 +2643,14 @@ U second-dir/rootig.c'
U first-dir/foobar.c'
cd first-dir
touch rootig.c defig.o envig.c optig.c notig.c
- dotest 189c "${testcvs} -q update -I optig.c" '\? notig.c'
+ dotest 189c "${testcvs} -q update -I optig.c" "${QUESTION} notig.c"
# The fact that CVS requires us to specify -I CVS here strikes me
# as a bug.
- dotest 189d "${testcvs} -q update -I ! -I CVS" '\? rootig.c
-\? defig.o
-\? envig.c
-\? optig.c
-\? notig.c'
+ dotest 189d "${testcvs} -q update -I ! -I CVS" "${QUESTION} rootig.c
+${QUESTION} defig.o
+${QUESTION} envig.c
+${QUESTION} optig.c
+${QUESTION} notig.c"
cd ..
rm -rf first-dir
@@ -2493,6 +2682,18 @@ done'
dotest binfiles-4 "${testcvs} -q co first-dir" 'U first-dir/binfile'
cd first-dir
dotest binfiles-5 "cmp ../../1/binfile.dat binfile" ''
+ # Testing that sticky options is -kb is the closest thing we have
+ # to testing that binary files work right on non-unix machines
+ # (until there is automated testing for such machines, of course).
+ dotest binfiles-5.5 "${testcvs} status binfile" \
+'===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.1.*
+ Repository revision: 1\.1 /tmp/cvs-sanity/cvsroot/first-dir/binfile,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb'
cp ../../1/binfile2.dat binfile
dotest binfiles-6 "${testcvs} -q ci -m modify-it" \
'Checking in binfile;
@@ -2503,6 +2704,62 @@ done'
dotest binfiles-7 "${testcvs} -q update" '[UP] binfile'
dotest binfiles-8 "cmp ../binfile2.dat binfile" ''
+ # The bugs which these test for are apparently not fixed for remote.
+ if test "$remote" = no; then
+ dotest binfiles-9 "${testcvs} -q update -A" ''
+ dotest binfiles-10 "${testcvs} -q update -kk" '[UP] binfile'
+ dotest binfiles-11 "${testcvs} -q update" ''
+ dotest binfiles-12 "${testcvs} -q update -A" '[UP] binfile'
+ dotest binfiles-13 "${testcvs} -q update -A" ''
+ fi
+
+ cd ../../2/first-dir
+ echo 'this file is $''RCSfile$' >binfile
+ dotest binfiles-14a "${testcvs} -q ci -m modify-it" \
+'Checking in binfile;
+/tmp/cvs-sanity/cvsroot/first-dir/binfile,v <-- binfile
+new revision: 1.3; previous revision: 1.2
+done'
+ dotest binfiles-14b "cat binfile" 'this file is $''RCSfile$'
+ # See binfiles-5.5 for discussion of -kb.
+ dotest binfiles-14c "${testcvs} status binfile" \
+'===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.3.*
+ Repository revision: 1\.3 /tmp/cvs-sanity/cvsroot/first-dir/binfile,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb'
+ dotest binfiles-14d "${testcvs} admin -kv binfile" \
+'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/binfile,v
+done'
+ # cvs admin doesn't change the checked-out file or its sticky
+ # kopts. There probably should be a way which does (but
+ # what if the file is modified? And do we try to version
+ # control the kopt setting?)
+ dotest binfiles-14e "cat binfile" 'this file is $''RCSfile$'
+ dotest binfiles-14f "${testcvs} status binfile" \
+'===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.3.*
+ Repository revision: 1\.3 /tmp/cvs-sanity/cvsroot/first-dir/binfile,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kb'
+ dotest binfiles-14g "${testcvs} -q update -A" '[UP] binfile'
+ dotest binfiles-14h "cat binfile" 'this file is binfile,v'
+ dotest binfiles-14i "${testcvs} status binfile" \
+'===================================================================
+File: binfile Status: Up-to-date
+
+ Working revision: 1\.3.*
+ Repository revision: 1\.3 /tmp/cvs-sanity/cvsroot/first-dir/binfile,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: -kv'
+
cd ../..
rm -rf ${CVSROOT_DIRNAME}/first-dir
rm -r 1 2
@@ -2511,7 +2768,7 @@ done'
# Test CVS's ability to handle *info files.
dotest info-1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}"
cd CVSROOT
- echo "ALL echo x\${=MYENV}\${=OTHER}y\${=ZEE}=\$USER=\$CVSROOT= >>$TESTDIR/testlog" > loginfo
+ echo "ALL sh -c \"echo x\${=MYENV}\${=OTHER}y\${=ZEE}=\$USER=\$CVSROOT= >>$TESTDIR/testlog; cat >/dev/null\"" > loginfo
dotest info-2 "${testcvs} add loginfo" \
"${PROG}"' [a-z]*: scheduling file `loginfo'"'"' for addition
'"${PROG}"' [a-z]*: use '"'"'cvs commit'"'"' to add this file permanently'
diff --git a/gnu/usr.bin/cvs/src/scramble.c b/gnu/usr.bin/cvs/src/scramble.c
index b1a17a5f97f..07094a6cb2e 100644
--- a/gnu/usr.bin/cvs/src/scramble.c
+++ b/gnu/usr.bin/cvs/src/scramble.c
@@ -123,7 +123,7 @@ descramble (str)
{
fprintf (stderr, "descramble: unknown scrambling method\n", str);
fflush (stderr);
- exit (1);
+ exit (EXIT_FAILURE);
}
#endif /* DIAGNOSTIC */
diff --git a/gnu/usr.bin/cvs/src/server.h b/gnu/usr.bin/cvs/src/server.h
index cb49267e991..30ddb8c4ae6 100644
--- a/gnu/usr.bin/cvs/src/server.h
+++ b/gnu/usr.bin/cvs/src/server.h
@@ -72,6 +72,8 @@ extern void server_clear_entstat PROTO((char *update_dir, char *repository));
extern void server_set_sticky PROTO((char *update_dir, char *repository,
char *tag,
char *date));
+/* Send Template response. */
+extern void server_template PROTO ((char *, char *));
extern void server_update_entries
PROTO((char *file, char *update_dir, char *repository,
@@ -83,7 +85,7 @@ extern void server_cleanup PROTO((int sig));
#ifdef SERVER_FLOWCONTROL
/* Pause if it's convenient to avoid memory blowout */
-extern void server_check_pause PROTO((void));
+extern void server_pause_check PROTO((void));
#endif /* SERVER_FLOWCONTROL */
#endif /* SERVER_SUPPORT */
diff --git a/gnu/usr.bin/cvs/src/status.c b/gnu/usr.bin/cvs/src/status.c
index 6c8ec95d8ae..277da0c2944 100644
--- a/gnu/usr.bin/cvs/src/status.c
+++ b/gnu/usr.bin/cvs/src/status.c
@@ -16,8 +16,7 @@ static int tag_list_proc PROTO((Node * p, void *closure));
static int local = 0;
static int long_format = 0;
-static char *xfile;
-static List *xsrcfiles;
+static RCSNode *xrcsnode;
static const char *const status_usage[] =
{
@@ -75,7 +74,7 @@ status (argc, argv)
if (local)
send_arg("-l");
- send_file_names (argc, argv);
+ 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);
@@ -108,7 +107,7 @@ status_fileproc (finfo)
Vers_TS *vers;
status = Classify_File (finfo->file, (char *) NULL, (char *) NULL, (char *) NULL,
- 1, 0, finfo->repository, finfo->entries, finfo->srcfiles, &vers,
+ 1, 0, finfo->repository, finfo->entries, finfo->rcs, &vers,
finfo->update_dir, 0);
switch (status)
{
@@ -195,8 +194,8 @@ status_fileproc (finfo)
{
char *branch = NULL;
- if (RCS_isbranch (finfo->file, edata->tag, finfo->srcfiles))
- branch = RCS_whatbranch(finfo->file, edata->tag, finfo->srcfiles);
+ if (RCS_isbranch (finfo->rcs, edata->tag))
+ branch = RCS_whatbranch(finfo->rcs, edata->tag);
(void) printf (" Sticky Tag:\t\t%s (%s: %s)\n",
edata->tag,
@@ -228,8 +227,7 @@ status_fileproc (finfo)
(void) printf ("\n Existing Tags:\n");
if (symbols)
{
- xfile = finfo->file;
- xsrcfiles = finfo->srcfiles;
+ xrcsnode = finfo->rcs;
(void) walklist (symbols, tag_list_proc, NULL);
}
else
@@ -267,8 +265,8 @@ tag_list_proc (p, closure)
{
char *branch = NULL;
- if (RCS_isbranch (xfile, p->key, xsrcfiles))
- branch = RCS_whatbranch(xfile, p->key, xsrcfiles) ;
+ if (RCS_isbranch (xrcsnode, p->key))
+ branch = RCS_whatbranch(xrcsnode, p->key) ;
(void) printf ("\t%-25.25s\t(%s: %s)\n", p->key,
branch ? "branch" : "revision",
diff --git a/gnu/usr.bin/cvs/src/subr.c b/gnu/usr.bin/cvs/src/subr.c
index 77e0a926bba..8ed9177b2d2 100644
--- a/gnu/usr.bin/cvs/src/subr.c
+++ b/gnu/usr.bin/cvs/src/subr.c
@@ -38,9 +38,9 @@ xmalloc (bytes)
* a "malloc" if the argument is NULL, but you can't depend on it. Here, I
* can *force* it.
*/
-char *
+void *
xrealloc (ptr, bytes)
- char *ptr;
+ void *ptr;
size_t bytes;
{
char *cp;
diff --git a/gnu/usr.bin/cvs/src/tag.c b/gnu/usr.bin/cvs/src/tag.c
index 69e78423287..2e3000945de 100644
--- a/gnu/usr.bin/cvs/src/tag.c
+++ b/gnu/usr.bin/cvs/src/tag.c
@@ -160,7 +160,7 @@ tag (argc, argv)
send_arg (symtag);
- send_file_names (argc, argv);
+ 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. */
@@ -234,8 +234,15 @@ check_fileproc (finfo)
p->key = xstrdup (finfo->file);
p->type = UPDATE;
p->delproc = tag_delproc;
- vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL, (char *) NULL,
- finfo->file, 0, 0, finfo->entries, finfo->srcfiles);
+ vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL,
+ (char *) NULL, finfo->file, 0, 0,
+ finfo->entries, finfo->rcs);
+ if (vers->srcfile == NULL)
+ {
+ if (!really_quiet)
+ error (0, 0, "nothing known about %s", finfo->file);
+ return (1);
+ }
p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0);
if (p->data != NULL)
{
@@ -392,7 +399,7 @@ tag_fileproc (finfo)
int retcode = 0;
vers = Version_TS (finfo->repository, (char *) NULL, (char *) NULL, (char *) NULL,
- finfo->file, 0, 0, finfo->entries, finfo->srcfiles);
+ finfo->file, 0, 0, finfo->entries, finfo->rcs);
if ((numtag != NULL) || (date != NULL))
{
@@ -439,10 +446,7 @@ tag_fileproc (finfo)
/* warm fuzzies */
if (!really_quiet)
{
- if (finfo->update_dir[0])
- (void) printf ("D %s/%s\n", finfo->update_dir, finfo->file);
- else
- (void) printf ("D %s\n", finfo->file);
+ (void) printf ("D %s\n", finfo->fullname);
}
freevers_ts (&vers);
@@ -500,34 +504,33 @@ tag_fileproc (finfo)
oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0);
if (oversion != NULL)
{
- int isbranch = RCS_isbranch (finfo->file, symtag, finfo->srcfiles);
-
- /*
- * if versions the same and neither old or new are branches don't have
- * to do anything
- */
- if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
- {
- free (oversion);
- freevers_ts (&vers);
- return (0);
- }
-
- if (!force_tag_move) { /* we're NOT going to move the tag */
- if (finfo->update_dir[0])
- (void) printf ("W %s/%s", finfo->update_dir, finfo->file);
- else
- (void) printf ("W %s", finfo->file);
-
- (void) printf (" : %s already exists on %s %s",
- symtag, isbranch ? "branch" : "version", oversion);
- (void) printf (" : NOT MOVING tag to %s %s\n",
- branch_mode ? "branch" : "version", rev);
- free (oversion);
- freevers_ts (&vers);
- return (0);
- }
- free (oversion);
+ int isbranch = RCS_isbranch (finfo->rcs, symtag);
+
+ /*
+ * if versions the same and neither old or new are branches don't have
+ * to do anything
+ */
+ if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch)
+ {
+ free (oversion);
+ freevers_ts (&vers);
+ return (0);
+ }
+
+ if (!force_tag_move)
+ {
+ /* we're NOT going to move the tag */
+ (void) printf ("W %s", finfo->fullname);
+
+ (void) printf (" : %s already exists on %s %s",
+ symtag, isbranch ? "branch" : "version", oversion);
+ (void) printf (" : NOT MOVING tag to %s %s\n",
+ branch_mode ? "branch" : "version", rev);
+ free (oversion);
+ freevers_ts (&vers);
+ return (0);
+ }
+ free (oversion);
}
if ((retcode = RCS_settag(vers->srcfile->path, symtag, rev)) != 0)
@@ -542,15 +545,12 @@ tag_fileproc (finfo)
/* more warm fuzzies */
if (!really_quiet)
{
- if (finfo->update_dir[0])
- (void) printf ("T %s/%s\n", finfo->update_dir, finfo->file);
- else
- (void) printf ("T %s\n", finfo->file);
+ (void) printf ("T %s\n", finfo->fullname);
}
if (nversion != NULL)
{
- free(nversion);
+ free (nversion);
}
freevers_ts (&vers);
return (0);
@@ -595,16 +595,13 @@ val_fileproc (finfo)
struct file_info *finfo;
{
RCSNode *rcsdata;
- Node *node;
struct val_args *args = val_args_static;
char *tag;
- node = findnode (finfo->srcfiles, finfo->file);
- if (node == NULL)
+ if ((rcsdata = finfo->rcs) == NULL)
/* Not sure this can happen, after all we passed only
W_REPOS | W_ATTIC. */
return 0;
- rcsdata = (RCSNode *) node->data;
tag = RCS_gettag (rcsdata, args->name, 1, 0);
if (tag != NULL)
@@ -727,7 +724,7 @@ Numeric tag %s contains characters other than digits and '.'", name);
else
{
if (save_cwd (&cwd))
- exit (1);
+ exit (EXIT_FAILURE);
if (chdir (repository) < 0)
error (1, errno, "cannot change to %s directory", repository);
}
@@ -740,7 +737,7 @@ Numeric tag %s contains characters other than digits and '.'", name);
if (repository != NULL && repository[0] != '\0')
{
if (restore_cwd (&cwd, NULL))
- exit (1);
+ exit (EXIT_FAILURE);
free_cwd (&cwd);
}
diff --git a/gnu/usr.bin/cvs/src/vers_ts.c b/gnu/usr.bin/cvs/src/vers_ts.c
index 650a4e63677..34983a125d8 100644
--- a/gnu/usr.bin/cvs/src/vers_ts.c
+++ b/gnu/usr.bin/cvs/src/vers_ts.c
@@ -14,12 +14,12 @@ static void time_stamp_server PROTO((char *, Vers_TS *));
/*
* Fill in and return a Vers_TS structure "user" is the name of the local
- * file; entries is the entries file - preparsed for our pleasure. xfiles is
- * all source code control files, preparsed for our pleasure
+ * file; entries is the entries file - preparsed for our pleasure. rcs is
+ * the current source control file - preparsed for our pleasure.
*/
Vers_TS *
Version_TS (repository, options, tag, date, user, force_tag_match,
- set_time, entries, xfiles)
+ set_time, entries, rcs)
char *repository;
char *options;
char *tag;
@@ -28,7 +28,7 @@ Version_TS (repository, options, tag, date, user, force_tag_match,
int force_tag_match;
int set_time;
List *entries;
- List *xfiles;
+ RCSNode *rcs;
{
Node *p;
RCSNode *rcsdata;
@@ -51,7 +51,7 @@ Version_TS (repository, options, tag, date, user, force_tag_match,
}
else
{
- p = findnode (entries, user);
+ p = findnode_fn (entries, user);
sdtp = (struct stickydirtag *) entries->list->data; /* list-private */
}
@@ -86,10 +86,24 @@ Version_TS (repository, options, tag, date, user, force_tag_match,
*/
if (options)
vers_ts->options = xstrdup (options);
- else if (sdtp && sdtp->aflag == 0)
+ else if (!vers_ts->options)
{
- if (!vers_ts->options)
+ if (sdtp && sdtp->aflag == 0)
vers_ts->options = xstrdup (sdtp->options);
+ else if (rcs != NULL)
+ {
+ /* If no keyword expansion was specified on command line,
+ use whatever was in the rcs file (if there is one). This
+ is how we, if we are the server, tell the client whether
+ a file is binary. */
+ char *rcsexpand = RCS_getexpand (rcs);
+ if (rcsexpand != NULL)
+ {
+ vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
+ strcpy (vers_ts->options, "-k");
+ strcat (vers_ts->options, rcsexpand);
+ }
+ }
}
if (!vers_ts->options)
vers_ts->options = xstrdup ("");
@@ -112,16 +126,10 @@ Version_TS (repository, options, tag, date, user, force_tag_match,
}
/* Now look up the info on the source controlled file */
- if (xfiles != (List *) NULL)
+ if (rcs != NULL)
{
- p = findnode (xfiles, user);
- if (p != NULL)
- {
- rcsdata = (RCSNode *) p->data;
- rcsdata->refcount++;
- }
- else
- rcsdata = NULL;
+ rcsdata = rcs;
+ rcsdata->refcount++;
}
else if (repository != NULL)
rcsdata = RCS_parse (user, repository);
@@ -244,8 +252,26 @@ time_stamp_server (file, vers_ts)
}
else
{
+ struct tm *tm_p;
+ struct tm local_tm;
+
vers_ts->ts_user = xmalloc (25);
- cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */
+ /* We want to use the same timestamp format as is stored in the
+ st_mtime. For unix (and NT I think) this *must* be universal
+ time (UT), so that files don't appear to be modified merely
+ because the timezone has changed. For VMS, or hopefully other
+ systems where gmtime returns NULL, the modification time is
+ stored in local time, and therefore it is not possible to cause
+ st_mtime to be out of sync by changing the timezone. */
+ tm_p = gmtime (&sb.st_mtime);
+ if (tm_p)
+ {
+ memcpy (&local_tm, tm_p, sizeof (local_tm));
+ cp = asctime (&local_tm); /* copy in the modify time */
+ }
+ else
+ cp = ctime (&sb.st_mtime);
+
cp[24] = 0;
(void) strcpy (vers_ts->ts_user, cp);
}
@@ -270,8 +296,25 @@ time_stamp (file)
}
else
{
+ struct tm *tm_p;
+ struct tm local_tm;
ts = xmalloc (25);
- cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */
+ /* We want to use the same timestamp format as is stored in the
+ st_mtime. For unix (and NT I think) this *must* be universal
+ time (UT), so that files don't appear to be modified merely
+ because the timezone has changed. For VMS, or hopefully other
+ systems where gmtime returns NULL, the modification time is
+ stored in local time, and therefore it is not possible to cause
+ st_mtime to be out of sync by changing the timezone. */
+ tm_p = gmtime (&sb.st_mtime);
+ if (tm_p)
+ {
+ memcpy (&local_tm, tm_p, sizeof (local_tm));
+ cp = asctime (&local_tm); /* copy in the modify time */
+ }
+ else
+ cp = ctime(&sb.st_mtime);
+
cp[24] = 0;
(void) strcpy (ts, cp);
}
diff --git a/gnu/usr.bin/cvs/src/version.c b/gnu/usr.bin/cvs/src/version.c
index 89b7dd53225..4848e82b1f1 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.7.2";
+char *version_string = "\nConcurrent Versions System (CVS) 1.8.1";
#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 b5e3ed87d94..08734895d28 100644
--- a/gnu/usr.bin/cvs/src/watch.c
+++ b/gnu/usr.bin/cvs/src/watch.c
@@ -331,7 +331,7 @@ watch_addremove (argc, argv)
send_arg ("-a");
send_arg ("none");
}
- send_file_names (argc, argv);
+ 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. */
@@ -429,10 +429,7 @@ watchers_fileproc (finfo)
if (them == NULL)
return 0;
- if (finfo->update_dir[0] == '\0')
- printf ("%s", finfo->file);
- else
- printf ("%s/%s", finfo->update_dir, finfo->file);
+ fputs (finfo->fullname, stdout);
p = them;
while (1)
@@ -507,7 +504,7 @@ watchers (argc, argv)
if (local)
send_arg ("-l");
- send_file_names (argc, argv);
+ 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. */