diff options
author | 1996-05-06 22:18:10 +0000 | |
---|---|---|
committer | 1996-05-06 22:18:10 +0000 | |
commit | c2c6168287231ca1f2357af7564f6bed5739dfd2 (patch) | |
tree | 2e18723d254f3d19c64aea673815a2f2d1cc691e /gnu/usr.bin/cvs/src | |
parent | Use MSR 0x10, not 10 to clear the Pentium instruction counter; from David (diff) | |
download | wireguard-openbsd-c2c6168287231ca1f2357af7564f6bed5739dfd2.tar.xz wireguard-openbsd-c2c6168287231ca1f2357af7564f6bed5739dfd2.zip |
New CVS release from Cyclic Software
Diffstat (limited to 'gnu/usr.bin/cvs/src')
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. */ |