From: tholo Date: Tue, 30 Jan 1996 00:16:59 +0000 (+0000) Subject: Upgrade to 1.7.1 snapshot X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=13571821e83933f3c1d7fd1ab5ff9cd54f0eea7f;p=openbsd Upgrade to 1.7.1 snapshot --- diff --git a/gnu/usr.bin/cvs/.cvsignore b/gnu/usr.bin/cvs/.cvsignore new file mode 100644 index 00000000000..0d0323b3eea --- /dev/null +++ b/gnu/usr.bin/cvs/.cvsignore @@ -0,0 +1,11 @@ +Makefile +config.status +config.log +config.cache +config.h +stamp-h +cvsinit +cvs-*.tar.gz +WinDebug +WinRel +cvsnt.vcp diff --git a/gnu/usr.bin/cvs/BUGS b/gnu/usr.bin/cvs/BUGS index 3ad13a82828..fc6af32f227 100644 --- a/gnu/usr.bin/cvs/BUGS +++ b/gnu/usr.bin/cvs/BUGS @@ -1,3 +1,17 @@ +To report bugs send mail to bug-cvs@prep.ai.mit.edu, or run the "cvsbug" +program and fill out the template: + + $ cvsbug + +The "cvsbug" program is installed in the same location as the "cvs" +program. If your installation failed, you may need to run "cvsbug" +directly out of the "src" directory as "src/cvsbug.sh". This is also +the procedure for submitting suggested changes to CVS--note that all +submitted changes may be distributed under the terms of the GNU Public +License, so if you don't like this, don't submit them. + + + * `cvs checkout -d nested/dir/path ' just doesn't work. The simpler version -- `cvs checkout -d single-dir ' works, however. @@ -14,7 +28,7 @@ * From: Roland McGrath - To: Cyclic CVS Hackers + To: Cyclic CVS Hackers Subject: weird bug Date: Sat, 25 Mar 1995 16:41:41 -0500 X-Windows: Even your dog won't like it. @@ -170,7 +184,7 @@ From: "Charles M. Hannum" - To: remote-cvs@cyclic.com + To: info-cvs@prep.ai.mit.edu Cc: jimb@totoro.bio.indiana.edu Subject: Re: forwarded message from Charles M. Hannum Date: Wed, 22 Feb 1995 22:07:07 -0500 @@ -183,7 +197,7 @@ * From: "Charles M. Hannum" - To: remote-cvs@cyclic.com + To: info-cvs@prep.ai.mit.edu Subject: Regarding that relative path problem Date: Thu, 23 Feb 1995 02:41:51 -0500 @@ -205,7 +219,7 @@ * From: "Charles M. Hannum" - To: remote-cvs@cyclic.com + To: info-cvs@prep.ai.mit.edu Subject: Still one more bug Date: Sat, 25 Feb 1995 17:01:15 -0500 @@ -225,7 +239,7 @@ * From: Roland McGrath - To: Cyclic CVS Hackers + To: Cyclic CVS Hackers Subject: bizarre failure mode Date: Tue, 7 Mar 95 14:17:28 -0500 diff --git a/gnu/usr.bin/cvs/ChangeLog b/gnu/usr.bin/cvs/ChangeLog index 2b9fc93a27c..856c931bda0 100644 --- a/gnu/usr.bin/cvs/ChangeLog +++ b/gnu/usr.bin/cvs/ChangeLog @@ -1,3 +1,308 @@ +Wed Jan 24 20:26:55 1996 Jim Kingdon + + * configure.in: Remove diff stuff. Also remove AC_CANONICAL_HOST + and bindir crud as that was the only place they were used. + * config.h.in, configure: Regenerated. + * config.sub, config.guess: Removed. + * src/options.h.in (DIFF): Change to "diff" and change comment to tell + people not to use -a. + * src/sanity.sh: New test binfiles tests for above-fixed bug (see + comments in patch_file in update.c--passing -a to diff generates a + patch which patch cannot apply). + + * NEWS: Adjust to reflect existence of 1.7. + +Tue Jan 23 14:20:39 1996 Jim Blandy + + * devel-cvs: New file, not to be included in the distribution. + +Thu Jan 18 21:46:56 1996 Jim Blandy + + * BUGS: Remove all mention of the outdated cyclic-cvs@cyclic.com + and remote-cvs@cyclic.com addresses. It turns out that people see + these addresses and use them. Mention the proper way to report + bugs. + +Wed Jan 17 16:40:01 1996 Jim Kingdon + + * README: Fix typo (info-cvs-requests -> info-cvs-request). + +Fri Jan 12 13:38:12 1996 Jim Kingdon + + * configure.in, configure: Revert "Checking user's gender" change. + Sure, you only live once, but I want mine to be a *long* life, not + one interrupted by a CVS user who is not amused coming after me + with an axe. + +Fri Jan 12 12:46:23 1996 Karl Fogel + + * configure: regenerated. + + * configure.in: print "Checking user's gender... ok". I mean, + what the heck, you only live once. + +Thu Jan 11 14:00:00 1996 Jim Kingdon + + * cvsnt.mak: Update dependencies. + +Thu Jan 11 12:03:10 1996 Norbert Kiesel + + * NEWS: document loss of CVS_NOADMIN. Also, mention the + possibility to use "cvs" in .cvsrc. + +Wed Jan 10 20:40:23 1996 Karl Fogel + + * configure: regenerated. + + * configure.in (AC_OUTPUT): added `macintosh/Makefile'. + + * Makefile.in (SUBDIRS): added `macintosh'. + +Wed Jan 10 01:17:18 1996 Jim Kingdon + + * README: Remove URL of obsolete David Zuhn web page. + + * FAQ: Replace entire file with short paragraph explaining the FAQ + is dead. + + * configure.in: Don't set exec_prefix. Set bindir from prefix if + exec_prefix isn't set. + * configure: Regenerated. + + * INSTALL: Update list of machines for 1.6.85 (further changes to + the list of machines will not receive ChangeLog entries). + +Tue Jan 9 09:02:05 1996 Jim Kingdon + + * NEWS: Mention changes in default ignore list. + + * INSTALL: check.log is not in /tmp/cvs-sanity. Mention + submitting bug reports as a possibility, not a request from us. + Separate out "make check" a bit to make clear it is optional. + +Mon Jan 8 11:42:40 1996 Jim Kingdon + + * INSTALL: Remove grep stuff; no longer necessary. + Don't say that patch must understand unidiffs; no longer true. + Suggest configuring with -Wall (here until we have a "how to hack + CVS document"). + +Wed Jan 3 19:00:00 1996 Jim Kingdon + + * .cvsignore: Add cvsnt.vcp. + +Mon Jan 1 22:45:50 1996 Jim Kingdon + + * os2/Makefile.in (Makefile), windows-NT/Makefile.in (Makefile): + New rules. + +Sun Dec 31 16:52:49 1995 Karl Fogel + + * NEWS: add a blurb about password authentication. + +Sun Dec 31 16:16:38 1995 Jim Kingdon + + * README: Add "submissions will be distributed under the GPL" + language (like the newspapers have for letters to the editor). + +Thu Dec 21 16:00:00 1995 Jim Kingdon + + * cvsnt.mak: Revert to an old version, then add in recent changes + to lists of files (using Visual C++; not by hand editing--this way + it can be used as an internal project not just an external one). + +Tue Dec 19 17:13:14 1995 Jim Kingdon + + * NEWS: Mention -kb (strictly speaking a bugfix, not a new + feature, I guess, but it seems worth mentioning anyway). + +Tue Dec 19 17:00:00 1995 Jim Kingdon + + * TODO: Remove "regular TODO list:" line which accidentally got + checked in. + +Mon Dec 18 18:59:30 1995 Jim Kingdon + + * Makefile.in (TAR_VERBOSE): Default to empty, not "v". I don't + want that whole long list of files any more than jimb's daily + update script does. + +Sun Dec 17 23:59:11 1995 Jim Kingdon + + * configure.in (AC_REPLACE_FUNCS): Remove vasprintf. + * configure: Regenerated. + +Sat Dec 16 17:19:45 1995 Jim Kingdon + + * configure.in (AC_REPLACE_FUNCS): Add vasprintf. + * configure: Regenerated. + +Mon Nov 20 14:19:47 1995 Jim Kingdon + + * TODO: Remove items about developer communications; they are done. + * NEWS: Mention developer communication features. + * cvsinit.sh: Also add notify file. + +Mon Dec 11 22:44:58 1995 Karl Fogel + + * New subdir "macintosh", for Mike Ladwig's + port-in-progress. + +Thu Dec 7 14:32:49 1995 Jim Meyering (meyering@comco.com) + + * Makefile.in (check): Make sure library is built before running + make in src. + (remotecheck): Likewise. + (installcheck): Likewise. + +Wed Dec 6 11:40:37 1995 J.T. Conklin + + * configure.in: Remove leading -l from first argument of + AC_CHECK_LIB for -lkrb and -ldes checks. + +Mon Dec 4 08:06:31 1995 Jim Kingdon + + * config.h.in: Regenerated. + +Sun Dec 3 20:05:10 1995 Jim Kingdon + + * configure.in: Remove grep stuff. + * configure: Regenerated. + +Fri Dec 1 11:16:18 1995 Norbert Kiesel + + * configure, config.h.in: re-ran autoconf + + * configure.in (AC_CHECK_HEADERS): add sys/resource.h to list of + tested headers + + * Makefile.in (DISTFILES): add config.sub and config.guess + +Thu Nov 23 09:01:53 1995 Jim Kingdon + + * TODO: Remove item about doc describing undoing a change; it + already does. + +Sun Nov 19 18:12:36 1995 Jim Blandy + + * Makefile.in (dist): Pull out the 'v' in the tar command to a + variable, so I can disable it in my daily update script. + +Tue Nov 14 18:31:36 1995 Greg A. Woods + + * cvsinit.sh: + - new rcs id + - new opening comment + - read only one "word" for CVSROOT + - add checkoutlist, cvswrappers, taginfo, wrap, & unwrap to + examples install loop, special handling for latter.... + - don't do any special stuff for loginfo -- always comment out + everything in the newly installed examples + - add a wee message to suggest editing newly installed examples + - tweak some more comments, esp. regarding install of contrib + scripts.... + - make $CVSROOT/CVROOT/history group writable if it didn't exist + as it's not very useful otherwise + +Tue Nov 14 15:22:25 1995 Greg A. Woods + + * cvsinit.sh: woops! wasn't installing contrib/log! + +Tue Nov 14 12:09:11 1995 Greg A. Woods + + * INSTALL: oops, missed a couple of things about "configure" + + * configure: re-ran autoconf + +Tue Nov 14 11:06:25 1995 Greg A. Woods + + * config.guess, config.sub: first time in (from autoconf-2.4) + + * configure.in: + - updated to work with autoconf-2.4 + - call AC_CANONICAL_HOST to get host OS type right (needs + config.sub and config.guess) + - added full support for --with-diffutils and --with-gnugrep + - fixed the diff search to work almost like the one for RCS-5.7 + - fixed some quoting problems + + * README: mention optional 'make check' step + + * INSTALL: + - updated notes about working SunOS versions + - re-wrote notes about RCS, diffutils, etc. + - added notes about configuring with GNU diffutils and GNU grep + - added notes about using 'make check' + - changed bug reporiting instructions to mention cvsbug + - re-wrote notes about setting CVSROOT in shell startups + +Fri Nov 3 11:11:16 1995 Jim Kingdon + + * README: Fix typo in URL of molli's web site. + +Tue Oct 31 19:28:16 1995 Karl Fogel + + * testing something, please ignore. + +Mon Oct 23 18:37:27 1995 Karl Fogel + + * configure: re-ran autoconf. + + * configure.in (AC_OUTPUT): os2/Makefile. + + * Makefile.in (SUBDIRS): added os2 subdir. + +Mon Oct 23 12:02:51 1995 Norbert Kiesel + + * cvsnt.mak: added lib/getline.c + +Fri Oct 20 17:04:55 1995 Norbert Kiesel + + * cvsnt.mak: added src/expand_path.c, error.[ch] now in src + +Thu Oct 19 16:26:32 1995 Jim Kingdon + + * INSTALL: Remove note about RCS 5.7 and log messages + consisting only of whitespace; fixed in CVS on 11 Jul 95. + +Tue Oct 17 17:57:23 1995 Warren Jones + + * man/cvs.5, examples/modules: Document -e. + +Tue Oct 10 16:34:25 1995 Thorsten Lockert + + * configure.in: More crud looking for kerberos, this time for 4.4BSD. + * configure: Regenerated. + +Sun Oct 8 12:22:19 1995 Peter Wemm + + * configure.in: check for POSIX and BSD style reliable signals + * configure: regenerated by autoconf + * config.h.in: regenerated by autoheader + +Fri Oct 6 21:50:48 1995 Jim Kingdon + + There is little point in trying to share a file as trivial as + lib/error.c between programs. So just admit it is CVS specific: + * lib/error.c: Move from here... + * src/error.c: ...to here, and remove CVS_SUPPORT ifdefs. + * lib/error.h: Move from here... + * src/error.h: ...to here. Remove CVS_SUPPORT + ifdefs; remove unused variable error_message_count. + * src/Makefile.in (OBJECTS): Add error.o. + (SOURCES): Add error.c. + (HEADERS): Add error.h. + * lib/Makefile.in (OBJECTS): Remove error.o. + (SOURCES): Remove error.c. + (HEADERS): Remove error.h. + * acconfig.h, configure.in: Remove CVS_SUPPORT. + * configure, config.h.in: Rebuilt using autoconf and autoheader. + * windows-NT/config.h: Remove CVS_SUPPORT. + +Thu Oct 5 17:26:38 1995 Jim Kingdon + + * INSTALL: Mention Siemens-Nixdorf RM600. + Tue Oct 3 09:32:19 1995 Jim Kingdon * NEWS: Remove item about -f global option; it is old news already @@ -17,11 +322,11 @@ Mon Oct 2 18:10:35 1995 Larry Jones we need it for the FD_SET stuff for select().) Moved check for gethostname() after check for connect() since if connect() is not found, we may add librariesd and gethostname() - may well be in one of those libraries. + may well be in one of those libraries. If connect() isn't found, look in -linet (ISC) in addition to -lsocket and -lnsl. Also, ignore the cache since we need to update LIBS reguardless of whether it was found before or not and - the answer may well be different afterwards. + the answer may well be different afterwards. Define CLIENT_SUPPORT and SERVER_SUPPORT only if connect() is found. @@ -238,7 +543,7 @@ Tue Jul 18 21:18:00 1995 Jim Blandy * configure.in (AC_CHECK_HEADERS): Check for sys/time.h. If you're using AC_HEADER_TIME, it's best to check for this too. - + * cvsnt.mak: New file --- makefile equivalent for Microsoft Visual C++. Choose this as your project when working with CVS under MSVC++. * cvsnt.vcp: New file --- configuration info for Microsoft Visual C++. @@ -300,7 +605,7 @@ Sun Jul 9 19:03:00 1995 Greg A. Woods * Makefile.in: add another reminder to run 'cvsinit' to update repository(ies) (from previous local changes) - + Thu Jul 6 17:53:55 1995 Paul Eggert * Makefile.in (mostlyclean-local): Remove $(PROGS). @@ -418,8 +723,8 @@ Tue May 30 00:07:15 1995 Jim Meyering (meyering@comco.com) Mon May 29 22:24:28 1995 J.T. Conklin * configure.in: Use AC_HEADER_DIRENT instead of AC_DIR_HEADER. - Use AC_HEADER_STAT to determine if S_FOO() macros work. - Use AC_HEADER_TIME to determine if both and + Use AC_HEADER_STAT to determine if S_FOO() macros work. + Use AC_HEADER_TIME to determine if both and can be included as recommend by autoconf manual. Remove AC_STRUCT_TM test, as above test is better. @@ -453,7 +758,7 @@ Fri Apr 28 22:31:26 1995 Jim Blandy Sat Apr 8 19:02:21 1995 Roland McGrath - * configure.in: Check for fchdir. + * configure.in: Check for fchdir. (connect check): Use AC_CHECK_LIB instead of (obsolete) AC_HAVE_LIBRARY. diff --git a/gnu/usr.bin/cvs/FAQ b/gnu/usr.bin/cvs/FAQ index acfbb5d75c3..450fa32f57d 100644 --- a/gnu/usr.bin/cvs/FAQ +++ b/gnu/usr.bin/cvs/FAQ @@ -1,10006 +1,14 @@ - -Archive-name: cvs-faq -Hand Revision: 3.5 <<== Include this in your comments -Last Updated: 1995/03/09 -$Revision: 1.1.1.1 $ -$Date: 1995/12/19 09:21:26 $ - -=========================================================================== -== Frequently Asked Questions about CVS (The Concurrent Versions System) == -=========================================================================== - - This document attempts to answer questions posed by users of CVS. - - CVS installers, administrators and maintainers looking for info on - system setup should read the section entitled "Installing CVS". - - - Disclaimer: - - Although an attempt has been made to ensure the veracity of the - following material, no responsibility is assumed for any use, or - for any consequences resulting from any use, of the information - contained herein. No guarantee of suitability for any purpose - is offered or implied. Nothing in this document may be assumed - to represent the employers of its contributors. - - I also might have slipped in a whopper or two to see if you are - paying attention. ;-) In other words, don't bet the house on - anything you read here unless you have checked it out yourself. - - - - Send questions and answers (along with additions to, subtractions - from, and divisions of existing questions -- no multiplications, - square roots, or transcendental functions, my cabinet is full of them) - to the author, who wrote all unattributed text: (Does it always - feel strange to refer to oneself in the third person?) - - David G. Grubbs - - - Major revisions contain enough alterations to render change markers - meaningless. (Major revisions are those with a final digit of '0', - such as 2.0 or 3.0.) To help readers of previous versions of this - document, minor revisions will be annotated: - - Change markers: Column 1 will contain a: - - '-' for a Question that has changed. - '=' for an Answer that has changed. - '#' for an entry with changes to both Question and Answer. - '+' for a newly added Question and Answer. - - - Trivial changes, such as question reordering or spelling and grammar - corrections are not marked. Deleted questions will simply disappear, - as will any question that can be answered by "get the latest release". - - Editorial comments are delimited by pairs of "[[" & "]]". They - contain either references to the (usually unfinished) nature of the - FAQ entry itself, version-specific comments to be removed (or - altered) when new revisions of CVS are released or snide remarks from - the editor. - - If you plan to do anything with this document other than: - - - Read it. - - Redistribute the whole document along with the date and revision. - - Post sections as answers to CVS questions (as long as you - identify it as coming from the FAQ.) - - talk to the author first. - - - -============================================ -== Section 0 ==== Introduction ==== -============================================ - -The questions in this document come from many sources in many forms. Some -are simple, some verbose. A few are difficult, but all of them have been -asked of the author at one time or another. Some questions are really -three or more different problems rolled into one plaintive cry for help. -Others reveal one of the bugs or weaknesses of CVS. - -CVS addresses some difficult problems to which there are no perfect -solutions. CVS also changes over time as new features are required. - -Therefore, the questions are about a complicated moving target. - -Though in most cases I've tried to provide the simplest answer I can -think of, some of the *questions* are difficult to follow. If you -aren't using CVS regularly, don't expect to understand everything. - -A Frequently Asked Questions document is not a substitute for the man page -or any other documentation. It is an attempt to answer questions. - -You should also keep in mind that FAQs are not really intended to be -read in their entirety like a text book. You should use "grep" or -your editor's search capability to hunt for keywords and read the -sections you need. - - -Questions are divided into five numbered Sections. Sections are divided -into lettered sub-sections. The questions are numbered sequentially -within each sub-section, though they are in no particular order. - - - 1. What is CVS? - A. What is CVS? What's it for? Why CVS? - B. Where do I find it? Where can I find Help? - C. How does CVS differ from other similar software? - D. What do you mean by . . .? (Definitions) - - 2. User Tasks - A. Getting Started - B. Common User Tasks - C. Less Common User Tasks - D. General Questions - - 3. Commands - A. through P. One section for each CVS command. - - 4. Advanced Topics - A. Installing CVS - B. Setting up and Managing the Repository - C. Branching and Merging - D. Tricks of the Trade - E. Internal errors - F. Related Software - G. Engineering - H. Other Systems - - 5. Past & Future - A. Contributors. - B. Bugs and Patches - C. Development - D. Professional Support - - 6. Table of Contents - - -Final note: - - Except for the "Past & Future" section, all answers in this - document refer to CVS version 1.4. The latest released version is - 1.5. - - -============================================ -== Section 1 ==== What is CVS? ==== -============================================ - ----------------- --- Section 1A -- What is CVS? What's it for? Why CVS? ----------------- - - **** Questions: - - 1A.1 What does CVS stand for? Can you describe it in one sentence? - 1A.2 What is CVS for? What does it do for me? - 1A.3 How does CVS work? - 1A.4 What is CVS useful for? - 1A.5 What is CVS *not* useful for? - - - **** Answers: - - 1A.1 What does CVS stand for? Can you describe it in one sentence? - - "CVS" is an acronym for the "Concurrent Versions System". - - CVS is a "Source Control" or "Revision Control" tool - designed to keep track of source changes made by groups of - developers working on the same files, allowing them to - stay in sync with each other as each individual chooses. - - - 1A.2 What is CVS for? What does it do for me? - - CVS is used to keep track of collections of files in a shared - directory called "The Repository". Each collection of files - can be given a "module" name, which is used to "checkout" - that collection. - - After checkout, files can be modified (using your favorite - editor), "committed" back into the Repository and compared - against earlier revisions. Collections of files can be - "tagged" with a symbolic name for later retrieval. - - You can add new files, remove files you no longer want, ask for - information about sets of files in three different ways, - produce patch "diffs" from a base revision and merge the - committed changes of other developers into your working files. - - - 1A.3 How does CVS work? - - CVS saves its version-control information in RCS files stored in a - directory hierarchy, called the Repository, which is separate from - the user's working directory. - - Files in the Repository are stored in a format dictated by the - RCS commands CVS uses to do much of its real work. RCS files - are standard byte-stream files with an internal format described - by keywords stored in the files themselves. - - To begin work, you execute a "checkout" command, handing it a - module name or directory path (relative to the $CVSROOT variable) - you want to work on. CVS copies the latest revision of each file - in the specified module or directory out of the Repository and - into a directory tree created in your current directory. You may - specify a particular branch to work on by symbolic name if you - don't want to work on the default (main or trunk) branch. - - You may then modify files in the new directory tree, build them - into output files and test the results. When you want to make - your changes available to other developers, you "commit" them back - into the Repository. - - Other developers can check out the same files at the same time. - To merge the committed work of others into your working files - you use the "update" command. When your merged files build - and test correctly, you may commit the merged result. This - method is referred to as "copy-modify-merge", which does not - require locks on the source files. - - At any time, usually at some milestone, you can "tag" the - committed files, producing a symbolic name that can be handed to a - future "checkout" command. A special form of "tag" produces a - branch in development, as usually happens at "release" time. - - When you no longer plan to modify or refer to your local copy - of the files, they can be removed. - - - 1A.4 What is CVS useful for? - - CVS is intended to handle source control for files in three major - situations: - - 1. Multiple developers working on the same files. - - The major advantage of using CVS over the simpler tools like - RCS or SCCS is that it allows multiple developers to work on - the same sources at the same time. - - The shared Repository provides a rendezvous for committed - sources that allows developers a fair amount of flexibility in - how often to publish (via the "commit" command) changes or - include work committed by others (via the "update" command). - - - 2. Tracking a stream of releases from a source vendor. - - If you are making changes to sources distributed by someone - else, the CVS feature, called the Vendor Branch, allows you to - combine local modifications with repeated vendor releases. - - I have found this most useful when dealing with sources from - three major classes of source vendor: - - a. Large companies who send you tapes full of the latest - release (e.g. Unix OS vendors, database companies). - - b. Public Domain software which *always* requires work. - - c. Pseudo-Public sources which may require work. - (e.g. GNU programs, X, CVS itself, etc.) - - - 3. Branching development. - - Aside from the "Vendor Branch", there are three kinds of - "branches in development" that CVS can support: - - a. Your working directory can be treated as a private branch. - - b. A Development branch can be shared by one or more developers. - - c. At release time, a branch is usually created for bug fixes. - - (See 1D.9 and Section 4C for more info on branches.) - - CVS's branch support is a bit primitive, but it was designed to - allow you to create branches, work on them for while and merge - them back into the main line of development. You should also - be able to merge work performed on the main branch into the - branch you are working on. Arbitrary sharing and merging - between branches is not currently supported. - - - 1A.5 What is CVS *not* useful for? - - CVS is not a build system. - - Though the structure of your Repository and modules file - interact with your build system (e.g. a tree of Makefiles), - they are essentially independent. - - CVS does not dictate how you build anything. It merely stores - files for retrieval in a tree structure you devise. - - CVS does not dictate how to use disk space in the checked out - working directories. If you require your Makefiles or build - procedures to know the relative positions of everything else, - you wind up requiring the entire Repository to be checked out. - That's simply bad planning. - - If you modularize your work, and construct a build system - that will share files (via links, mounts, VPATH in Makefiles, - etc.), you can arrange your disk usage however you like. - - But you have to remember that *any* such system is a lot of - work to construct and maintain. CVS does not address the - issues involved. You must use your brain and a collection - of other tools to provide a build scheme to match your plans. - - Of course, you should use CVS to maintain the tools created to - support such a build system (scripts, Makefiles, etc). - - - CVS is not a substitute for management. - - You and your project leaders are expected to plan what you are - doing. Everyone involved must be aware of schedules, merge - points, branch names, release dates and the range of - procedures needed to build products. (If you produce it and - someone else uses it, it is a product.) CVS can't cover for a - failure to manage your project. - - CVS is an instrument for making sources dance to your tune. - But you are the piper and the composer. No instrument plays - itself or writes its own music. - - - CVS is not a substitute for developer communication. - - When faced with conflicts within a single file, most - developers manage to resolve them without too much effort. - But a more general definition of "conflict" includes problems - too difficult to solve without communication between - developers. - - CVS cannot determine when simultaneous changes within a single - file, or across a whole collection of files, will logically - conflict with one another. Its concept of a "conflict" is - purely textual, arising when two changes to the same base file - are near enough to spook the merge command into dropping - conflict markers into the merged file. - - CVS is not capable of figuring out distributed conflicts in - program logic. For example, if you change the arguments to - function X defined in file A and, at the same time, edit file - B, adding new calls to function X using the old arguments. - You are outside the realm of CVS's competence. - - Acquire the habit of reading specs and talking to your peers. - - - CVS is not a configuration management system. - - CVS is a source control system. The phrase "configuration - management" is a marketing term, not an industry-recognized - set of functions. - - A true "configuration management system" would contain - elements of the following: - - * Source control. - * Dependency tracking. - * Build systems (i.e. What to build and how to find - things during a build. What is shared? What is local?) - * Bug tracking. - * Automated Testing procedures. - * Release Engineering documentation and procedures. - * Tape Construction. - * Customer Installation. - * A way for users to run different versions of the same - software on the same host at the same time. - - CVS provides only the first. - - - ----------------- --- Section 1B -- Where do I find CVS? Where can I find Help? ----------------- - - **** Questions: - - 1B.1 How do I get more information about CVS? - 1B.2 Is there an archive of CVS material? - 1B.3 How do I get files out of the archive if I don't have FTP? - 1B.4 How do I get a copy of the latest version of CVS? - 1B.5 Is there a mailing list devoted to CVS? How do I find it? - 1B.6 What happened to the CVS Usenet newsgroup I heard about? - - - **** Answers: - - 1B.1 How do I get more information about CVS? - - 1. The first thing I would do is to read the Info file that comes - with the CVS sources under "doc". You can format and read the - cvs.texinfo file in two ways: 1. Use TeX to format it and a - "dvips" command to print it and 2. Install the cvs.info files - that are created by the Makefile and read them online using the - Emacs "info-mode" or a stand-alone "info" reader. - - 2. Then I'd run "cvsinit" to set up a Repository and read the man - page while trying out the commands. - - Type "cvs -H" for general help or "cvs -H command" for - command-specific help. - - 3. For background, you can read the original CVS paper (in the - source tree, under "doc"). It describes the purpose of CVS and - some of how it was designed. Note that the emphasis of the - document (especially on multiple vendors providing the same - sources) is somewhat out of date. - - 4. For more detailed information about "internals", read the man - pages for RCS. If you are a programmer, you can also read the - source code to CVS. - - 5. Other information and tutorials may be available in the "doc" - directory of the FTP archive described below. - - 6. For current information, and a fair amount of detail, join the - info-cvs mailing list described below. - - - 1B.2 Is there an archive of CVS material? - - An anonymous FTP area has been set up. It contains many of the - CVS files you might want, including extra documentation, patches - and a copy of the latest release. - - ftp ftp.delos.com - >>> User: anonymous - >>> Passwd: - cd /pub/cvs - get README - get Index - - The README has more (and more up-to-date) information. The Index - contains a terse list of what is in the archive. - - A WWW home page is also available at http://www.delos.com/cvs. - - - 1B.3 How do I get files out of the archive if I don't have FTP? - - Use one of the FTP<->Email servers. These are the ones - I've been told about: - - - 1. FTPMAIL service is available from the same host as the FTP - server described above. Send mail to "ftpmail@delos.com" - containing "help" in the body of the message. For example, - on most Unix systems, you can type: - - echo help | Mail ftpmail@delos.com - - The FTPMAIL server will respond with a document describing how - to use the server. If the "Mail" command doesn't exist on your - system, try "mailx", "/usr/ucb/mail" or "/bin/mail". - - - 2. If you are on BITNET, use Princeton's BITFTP server. Type - - echo 'send help' | Mail bitftp@pucc.princeton.edu - - (It is likely that only BITNET addresses can use this one.) - - - 3. Other possibilities I've heard of from the net: - (Try the one closest to you.) - - ftpmail@decwrl.dec.com - ftpmail@sunsite.unc.edu - ftpmail@cs.arizona.edu - ftpmail@cs.uow.edu.au - ftpmail@doc.ic.ac.uk - - - 1B.4 How do I get a copy of the latest version of CVS? - - The latest released version of CVS and all the programs it - depends on should be available through anonymous FTP on any FSF - archive. The main FSF archive is at "prep.ai.mit.edu". There are - mirrors of the FSF archive on UUNET and other large Internet sites. - - Program(s) Suggested revision - ----------- ----------------------- - CVS 1.5 - RCS 5.7 (latest version available today) - GNU diff 2.7 (or later) [contained in diffutils-2.7] - GDBM 1.5 (or later) [optional] - - The GNU version of diff is suggested by both the RCS and CVS - configuration instructions because it works better than the - standard version. - - It is a good idea not to accept the versions of CVS, RCS or diff - you find lying on your system unless you have checked out their - provenance. Using inconsistent collections of tools can cause you - more trouble than you can probably afford. - - The FTP archive mentioned above should contain the latest official - release of CVS, some official and unofficial patches and possibly - complete patched versions of CVS in use somewhere. - - - 1B.5 Is there a mailing list devoted to CVS? How do I find it? - - An Internet mailing list named "info-cvs" grew out of the private - mailing list used by the CVS 1.3 alpha testers in early 1992. - Throughout 1994, the list received an average of 100 messages per - month. - - You can add yourself to the mailing list by sending an Email - message to: - - info-cvs-request@prep.ai.mit.edu - - (Don't forget the "-request" or you'll send a message to the - whole list, some of whom are capable of remote execution.) - - Mail to the whole list should be sent to: - - info-cvs@prep.ai.mit.edu - - An archive of the mailing list is maintained in the FTP archive - mentioned above. - - - 1B.6 What happened to the CVS Usenet newsgroup I heard about? - - - A Usenet newsgroup named "gnu.cvs.info" was announced in April - 1993, with an expected creation date of August, 1993. - - As of this writing (October, 1994) it hasn't appeared. - - If the newsgroup is ever created, it and the mailing list should - be bidirectionally gatewayed, meaning that you only need access to - one of them. Anything sent to the mailing list would be - automatically posted to "gnu.cvs.info" and anything posted to the - newsgroup would be automatically mailed to "info-cvs". - - A newsgroup would be easier to use than a mailing list. If the - CVS newsgroup ever shows up, ask your system administrator whether - you get the "gnu" hierarchy. If so, select a news reader and dive - in. - - ----------------- --- Section 1C -- How does CVS differ from other, similar software? ----------------- - -This section attempts to list programs purporting to cover some of the -same territory as CVS. [[These are very sparsely documented here. If you -know something about one of these tools, how about trying to flesh out an -entry or two?]] - - - **** Questions: - - 1C.1 How does CVS differ from RCS? - 1C.2 How does CVS differ from SCCS? - 1C.3 How does CVS differ from ClearCase? -#1C.4 How does CVS differ from TeamWare/SparcWorks? - 1C.5 How does CVS differ from Aegis? - 1C.6 How does CVS differ from Shapetools? - 1C.7 How does CVS differ from TeamNet? - 1C.8 How does CVS differ from ProFrame? - 1C.9 How does CVS differ from CaseWare/CM? - 1C.10 How does CVS differ from Sublime? - 1C.11 How does CVS differ from PVCS? - 1C.12 How does CVS differ from CMVC? - - - **** Answers: - - - 1C.1 How does CVS differ from RCS? - - CVS uses RCS to do much of its work and absolutely all the work - of changing the underlying RCS files in the Repository. - - RCS comprises a set of programs designed to keep track of changes - to individual files. Of course, it also allows you to refer to - multiple files on the command line, but they are handled by - iterating over individual files. There is no pretense of - coordinated interaction among groups of files. - - CVS's main intent is to provide a set of grouping functions that - allow you to treat a collection of RCS files as a single object. - Of course, CVS also has to do a lot of iteration, but it tries - its best to hide that it is doing so. In addition, CVS has some - truly group-oriented facets, such as the modules file and the CVS - administrative files that refer to a whole directory or module. - - One group aspect that can be a bit confusing is that a CVS branch - is not the same as an RCS branch. To support a CVS branch, CVS - uses "tags" (what RCS calls "symbols") and some local state, - in addition to RCS branches. - - Other features offered by CVS that are not supported directly by - RCS are - - 1. Automatic determination of the state of a file, (e.g. - modified, up-to-date with the Repository, already tagged - with the same string, etc.) which helps in limiting the - amount of displayed text you have to wade through to - figure out what changed and what to do next. - - 2. A copy-modify-merge scheme that avoids locking the files - and allows simultaneous development on a single file. - - 3. Serialization of commits. CVS requires you to merge all - changes committed (via "update") since you checked out - your working copy of the file. Although it is still - possible to commit a file filled with old data, it is less - likely than when using raw RCS. - - 4. Relatively easy merging of releases from external Vendors. - - - 1C.2 How does CVS differ from SCCS? - - SCCS is much closer to RCS than to CVS, so some of the previous - entry applies. - - You might want to take a look at Walter Tichy's papers on RCS, - which are referred to in the RCS man pages. - - [[More info here?]] - - - 1C.3 How does CVS differ from ClearCase? - - ClearCase is a distributed client-server version control system. - ClearCase is a variant DSEE tools, formerly available on Apollo - platforms. The ClearCase tool set includes a few X-based - interface tools, a command-line interface, and C programmer API. - It is currently available on Sun, HP, SGI and OSF/1 platforms. - - ClearCase uses a special Unix filesystem type, called "mvfs" - for "multi-version file system". Conceptually, mvfs adds - another dimension to a regular Unix filesystem. The new - axis is used to store the different versions of files and to - provide a tree-hierarchical view of a collection of objects that - might be scattered across any number of separate hosts on your - local network. - - Each user acquires a "view" into the file database by creating a - special mvfs mount point on their machine. Each view has a - "configuration spec" containing a set of selection rules that - specify the particular version of each file to make visible in - that view. You can think of a "view" as a work area in CVS, except - that the files don't really exist on your local disk until you - modify them. This technique conserves disk space because it - doesn't keep private copies of read-only files. - - Another advantage is that a view is "transparent" in the sense that - all of the files in a "view" appear to be regular Unix files to - other tools and Unix system calls. An extended naming convention - allows access to particular versions of a file directly: - "test.cc@@/main/bugfix/3" identifies the third version of test.c - on the bugfix branch. - - ClearCase supports both the copy-modify-merge model of CVS (by - using what are called "unreserved checkouts" and the - checkin/checkout development model with file locking. Directories - are version-controlled objects as well as files. A graphical merge - tool is provided. Like RCS, ClearCase supports branches, symbolic - tags, and delta compression. ASCII as well as binary files are - supported, and converters from RCS, SCCS, DSEE formats are also - included. - - A make-compatible build facility is provided that can identify - common object code and share it among developers. A build - auditing feature automatically records file dependencies by - tracking every file that is opened when producing a derived - object, thus making explicit dependency lists unnecessary. Pre- - and post-event triggers are available for most ClearCase - operations to invoke user programs or shell scripts. User-defined - attributes can be assigned to any version or object. Hyper-links - between version controlled objects can record their relationship. - - For more information, contact: - - Atria Software, Inc. - 24 Prime Park Way - Natick, MA 01760 - info@atria.com - - (508) 650-1193 (phone) - (508) 650-1196 (fax) - - Originally contributed by Steve Turner - Edited by the author of this FAQ. - - -#1C.4 How does CVS differ from TeamWare/SparcWorks? - - TeamWare is a configuration management tool from Sun Microsystems, - a part of SparcWorks. It uses the same copy and merge model as - CVS. The central abstraction is a workspace, which corresponds to - either a CVS branch or a checked out module. TeamWare allows you - to manipulate workspaces directly, including moving and merging - code between workspaces. You can put your workspace on tape and - continue to work with it at home, just like you can with CVS. - TeamWare is built upon and compatible with SCCS. - - TeamWare provides both a command line interface and a graphical - interface. The CodeManager tool will display the project as a - tree of workspaces, and allows you to manipulate them with drag - and drop. The other tools are VersionTool that displays and - manipulates a dag with a version history of a single file, - CheckPoint that will create symbolic tags, MakeTool, a make - compatible tool with a GUI, and FileMerge which will interactively - merge files when needed (like emerge for emacs). If you have a - sun, you can try /usr/old/mergetool for an old SunView version of - FileMerge. - - Email: sunprosig@sun.com - - Originally extracted from TeamWare - Marketing literature by Per Abrahamsen. - Edited by the author of this FAQ. - - - For more information, contact: - - SunExpress, Inc. - P.O. Box 4426 - Bridgeton, MO 63044-9863 - (800)873-7869 - - - 1C.5 How does CVS differ from Aegis? - - Aegis appears to be a policy-setting tool that allows you to use - other sub-programs (make, RCS, etc.) to implement pieces of the - imposed policy. - - The initial document seems to say that most Unix tools are - inadequate for use under Aegis. - - It is not really similar to CVS and requires a different mindset. - - [[Need more info here.]] - - - 1C.6 How does CVS differ from Shapetools? - - Shapetools includes a build mechanism (called Shape, not - surprisingly) that is aware of the version mechanism, and some - dependency tracking. It is based on a file system extension - called Attributed File System, which allows arbitrary-sized - "attributes" to be associated with a file. Files are version - controlled in a manner similar to RCS. Configurations are managed - through the Shapefile, an extension of the Makefile syntax and - functionality. Shape includes version selection rules to allow - sophisticated selection of component versions in a build. - - Shapetools' concurrency control is pessimistic, in contrast to - that of CVS. Also, there's very limited support for branching and - merging. It has a built-in policy for transitioning a system from - initial development to production. - - Contributed by Don Dwiggins - - - 1C.7 How does CVS differ from TeamNet? - - TeamNet is a configuration management tool from TeamOne. - - For more information, contact: - - TeamOne - 710 Lakeway Drive, Ste 100 - Sunnyvale, CA 94086 - (800) 442-6650 - - Contributed by Steve Turner - - - 1C.8 How does CVS differ from ProFrame? - - ProFrame is a new system integration framework from IBM. - ProFrame is compliant with the CFI (CAD Framework Initiative) - industry standards, including the Scheme extension language. - - ProFrame consists of three major components: (1) the Process - Manager that automates your local design methodology (2) the - Design Data Manager handles configuration management, and (3) - Inter-tool Communication to provide a communication path among - tools running on heterogeneous servers. - - The Design Data Manager(2) is probably the appropriate - component to compare to CVS. The Design Data Manager provides - version control with checkin/checkout capability, - configuration management, and data dependency tracking. A - graphical data selection interface is provided. Using this - interface, you may create and manipulate objects and hierarchy - structures, view the revision history for an object, and view - and assign attributes to a design object. - - The ProFrame server currently runs only on RS6000, but clients - may be a wide variety of Unix platforms. Contact IBM for the - latest platform information. - - For more information, contact: - - IBM - EDA Marketing and Sales - P.O. Box 950, M/S P121 - Poughkeepsie, NY 12602 - (800) 332-0066 - - - Contributed by Steve Turner - [extracted from the ProFrame 1.1.0 datasheet] - - - 1C.9 How does CVS differ from CaseWare/CM? - - CaseWare/CM is a software configuration management product - from CaseWare, Inc. CaseWare/CM may be customized to support - a wide variety of methodologies, including various phases of - the software lifecycle, and different access rights for users. - - A GUI is provided to view version histories and - configurations. A merge tools is also included. CaseWare - supports type-specific lifecycles, which allows different types - of files to move through different lifecycles. Also provided - is a build facility to support automatic dependency analysis, - parallel, distributed, and remote builds, and variant - releases. - - CaseWare/CM has been integrated with other CASE tools, - including FrameMaker, ALSYS Ada, CodeCenter/Object Center, HP - SoftBench, and Software Through Pictures. CaseWare also - offers CaseWare/PT, a problem tracking system to integrate - change requests with configuration management. - - Multiple vendors and operating systems are supported. - - For more information, contact: - - CaseWare, Inc. - 108 Pacifica, 2nd Floor - Irvine, CA 92718-3332 - (714) 453-2200 (phone) - (714) 453-2276 (fax) - - Contributed by Steve Turner - [extracted from the CaseWare/CM data sheet] - - - 1C.10 How does CVS differ from Sublime? - - Produced by AT&T. - - [[Need more info here.]] - - - 1C.11 How does CVS differ from PVCS? - - PVCS works on single files like RCS and SCCS, CVS works on - complete subsystems. PVCS has a make utility (called a - configuration builder), CVS does not. PVCS has a GUI interface - for Unix, DOS, OS/2, and MS Windows. - - Intersolv, Inc. - 1700 NW 167th Place - OR 97006 - - Contributed by Per Abrahamsen - [Extracted from Intersolv Marketing literature.] - - - 1C.12 How does CVS differ from CMVC? - - CMVC is an IBM Configuration Management and Version Control - system. (Though I'm not certain that's the right acronym - expansion.) It runs on Suns, HPs, RS6000s, OS/2 and Windows. - - Other than revision control, it apparently has features to manage - releases, bug tracking and the connection between alterations and - reported bugs and feature requests. It is a client/server system, - based on a choice of commercial Relational Database systems, and - it provides a Motif or command line interface. - - Unlike CVS, it uses a strict locking protocol to serialize source - code alterations. - - ----------------- --- Section 1D -- What do you mean by . . .? (Definitions) ----------------- - - **** Questions: - - 1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"? - 1D.2 What is an RCS file? - 1D.3 What is a working file? - 1D.4 What is a working directory (or working area)? - 1D.5 What is "checking out"? - 1D.6 What is a revision? - 1D.7 What is a "Tag"? - 1D.8 What are "HEAD" and "BASE"? - 1D.9 What is a Branch? - 1D.10 What is "the trunk"? - 1D.11 What is a module? - 1D.12 What does "merge" mean? - - - **** Answers: - - - 1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"? - - The Repository is a directory tree containing the CVS - administrative files and all the RCS files that constitute - "imported" or "committed" work. The Repository is kept in a - shared area, separate from the working areas of all developers. - - Users of CVS must set their "CVSROOT" environment variable to the - absolute pathname of the head of the Repository. Most command - line interpreters replace an instance of "$CVSROOT" with the value - of the "CVSROOT" environment variable. By analogy, in this - document "$CVSROOT" is used as shorthand for "the absolute - pathname of the directory at the head of the Repository". - - One of the things found in $CVSROOT is a directory named CVSROOT. - It contains all the "state", the administrative files, that CVS - needs during execution. The "modules", "history", "commitinfo", - "loginfo" and other files can be found there. See 4B.2 for more - information about CVSROOT files. - - - 1D.2 What is an RCS file? - - An RCS file is a text file containing the source text and the - revision history for all committed revisions of a source file. It - is stored separately from the working files, in a directory - hierarchy, called the Repository. - - RCS is the "Revision Control System" that CVS uses to manage - individual files. RCS file names normally end in ",v", but - that can be altered (via the RCS -x option) to conform to file - naming standards on platforms with unusual filename limitations. - - - 1D.3 What is a working file? - - A working file is a disk file containing a checked-out copy of a - source file that earlier had been placed under CVS. If the - working file has been edited, the changes since the last committed - revision are invisible to other users of CVS. - - - 1D.4 What is a working directory (or working area)? - - A working directory is the place where you work and the place - from which you "commit" files. - - The "checkout" command creates a tree of working directories, - filling them with working files. Each working directory contains - a sub-directory named ./CVS containing three administrative files, - which are created by "checkout" and are always present: - - ./CVS/Entries - contains information about working files. - - ./CVS/Repository - contains the location of the directory within the - Repository that was used to create the working directory. - - ./CVS/Root - contains the value of $CVSROOT at the time you created - the working directory. - - Other files may also appear in ./CVS depending on the state of - your working directory: - - ./CVS/Tag - contains the "sticky tag" associated with the whole - directory. See 3A.2 for its main purpose. - [Created by "checkout" or "update" when using "-r ".] - [Deleted by "checkout" or "update" when using '-A'.] - - ./CVS/Entries.Static - contains a fixed list of working files. If this file - exists, an "update" doesn't automatically bring newly - added files out of the Repository. - [Created and maintained by hand.] - - ./CVS/Checkin.prog - contains a program to run whenever anything in the - working directory is committed. - [Created by checkout if "-i " appears in the - modules file for the checked-out module.] - - ./CVS/Update.prog - contains a program to run whenever anything in the - working directory is updated. - [Created by checkout if "-u " appears in the - modules file for the checked-out module.] - - ./CVS/,p - ./CVS/,t - contain (possibly zero-length) state information about an - "add" that has not been committed. - [Created by "add".] - [Deleted by "commit" or "remove".] - - - 1D.5 What is "checking out"? - - "Checking out" is the act of using the "checkout" command to - copy a particular revision from a set of RCS files into your - working area. You normally execute "checkout" only once per - working directory (or tree of working directories), maintaining - them thereafter with the "update" command. - - See section 3C on the "checkout" command. - - - 1D.6 What is a revision? - - A "revision" is a version of a file that was "committed" - ("checked in", in RCS terms) some time in the past. CVS (and - RCS) can retrieve any file that was committed by specifying its - revision number or its "tag" ("symbolic name", in RCS terms). - - In CVS, a "tag" is more useful than a revision number. It usually - marks a milestone in development represented by different revision - numbers in different files, all available as one "tagged" - collection. - - Sometimes the word "revision" is used as shorthand for "the file - you get if you retrieve (via "checkout" or "update") the given - revision from the Repository." - - - 1D.7 What is a "Tag"? - - A "Tag" is a symbolic name, a synonym or alias for a - particular revision number in a file. The CVS "tag" command - places the same "Tag" on all files in a working directory, - allowing you to retrieve those files by name in the future. - - The CVS "Tag" is implemented by applying RCS "symbols" to each - individual file. The Tags on a file (or collection of files) may - be displayed using the "log" command. - - - 1D.8 What are "HEAD" and "BASE"? - - HEAD and BASE are built-in tags that don't show up in the "log" - or "status" listings. They are interpreted directly by CVS. - - "HEAD" refers to the latest revision on the current branch in the - Repository. The current branch is either the main line of - development, or a branch in development created by placing a - branch tag on a set of files and checking out that branch. - - "BASE" refers to the revision on the current branch you last - checked out, updated, or committed. If you have not modified - your working file, "BASE" is the committed revision matching it. - - Most of the time BASE and HEAD refer to the same revision. They - can become different in two ways: - - 1. Someone else changed HEAD by committing a new revision of your - file to the Repository. You can pull BASE up to equal HEAD by - executing "update". - - 2. You moved BASE backward by executing "checkout" or "update" - with the option "-r " or "-D ". CVS records a - sticky tag and moves your files to the specified earlier - revision. You can clear the sticky tag and pull BASE up to - equal HEAD again by executing "update -A". - - - 1D.9 What is a Branch? - - In general, a branch is any mechanism that allows one or more - developers to modify a file without affecting anyone other than - those working on the same branch. - - There are four kinds of "branch" CVS can manage: - - 1. The Vendor Branch. - - A single vendor branch is supported. The "import" command - takes a sequence of releases from a source code vendor (called - a "vendor" even if no money is involved), placing them on a - special "Vendor" branch. The Vendor branch is considered part - of the "Main line" of development, though it must be merged - into locally modified files on the RCS Main branch before the - "import" is complete. - - See Section 3H ("import"). - - 2. Your Working directory. - - A checked-out working directory, can be treated like a private - branch. No one but you can touch your files. You have - complete control over when you include work committed by - others. However, you can't commit or tag intermediate versions - of your work. - - 3. A Development branch. - - A group of developers can share changes among the group, - without affecting the Main line of development, by creating a - branch. Only those who have checked-out the branch see the - changes committed to that branch. This kind of branch is - usually temporary, collapsing (i.e. merge and forget) into the - Main line when the project requiring the branch is completed. - - You can also create a private branch of this type, allowing an - individual to commit (and tag) intermediate revisions without - changing the Main line. It should be managed exactly like a - Development Branch -- collapsed into the Main line (or its - parent branch, if that is not the Main Branch) and forgotten - when the work is done. - - 4. A Release branch. - - At release time, a branch should be created marking what was - released. Later, small changes (sometimes called "patches") - can be made to the release without including everything else on - the Main line of development. You avoid forcing the customer - to accept new, possibly untested, features added since the - release. This is also the way to correct bugs found during - testing in an environment where other developers have continued - to commit to the Main line while you are testing and packaging - the release. - - Although the internal format of this type of branch (branch tag - and RCS branches) is the same as in a development branch, its - purpose and the way it is managed are different. The major - difference is that a Release branch is normally Permanent. - Once you let a release out the door to customers, or to the - next stage of whatever process you are using, you should retain - forever the branch marking that release. - - Since the branch is permanent, you cannot incorporate the - branch fixes into the Main line by "collapsing" (merging and - forgetting) the release branch. For large changes to many - files on the release branch, you will have to perform a branch - merge using "update -j -j ". (See 4C.7) - - The most common way to merge small changes back into Main line - development is to make the change in both places - simultaneously. This is faster than trying to perform a - selective merge. - - See 1D.12 (merges) and Section 4C, on Branching for more info. - - - 1D.10 What is "the trunk"? - - Another name for the RCS Main Branch. The RCS Main Branch is - related, but not equivalent, to both the CVS Main branch and what - developers consider to be the Main line of development. - See 3H.3 and Section 4C on Branching. - - - 1D.11 What is a module? - - In essence, a module is a name you hand to the "checkout" command - to retrieve one or more files to work on. It was originally - intended to be a simple, unique name in the "modules" file - attached to a directory or a subset of files within a directory. - - The module idea is now a somewhat slippery concept that can be - defined in two different ways: - - A. A module is an argument to "checkout". There are three types: - - 1. An entry in the modules file. A "module" name as described - in 'B.' below. - - 2. A relative path to a directory or file in the Repository. - - 3. A mixed-mode string of "modulename/relative-path". - Everything up to the first slash ('/') is looked up as a - module. The relative path is appended to the directory - associated with the module name and the resulting path is - checked out as in #2 above. - - - B. A module is a unique (within the file) character string in the - first column of the modules file. There are five types: - - 1. A name for a directory within the Repository that - allows you to ignore the parent directories above it. - - Example: - - emacs gnu/emacs - - - 2. A name for a subset of the files within such a directory. - - Example: - - ls unix/bin Makefile ls.c - - The 2nd through Nth strings in the above can be files, - directories or module substitutions. No relative paths. - - A module substitution occurs when you use a '&module-name' - reference. The module-name referred to is logically - substituted for the '&module-name' string. - - - 3. A relative pathname to a directory within the Repository - which, when checked out, creates an image of part of the - Repository structure in your current directory. - - Example: - - gnu/emacs -o /bin/emacs.helper gnu/emacs - - The files checked out are exactly the same as the files - "checkout" would retrieve if the path weren't even in the - modules file. The only reason to put this kind of relative - pathname into the modules file is to hook one of the helper - functions onto it. - - - 4. A relative pathname to a single file within the Repository - which, when checked out, creates something you probably - don't want: It creates a directory by the name of the file - and puts the file in it. - - Example: - - gnu/emacs/Makefile -o /bin/emacs.helper gnu/emacs Makefile - - The file checked out is the same as what you would get if - you handed the relative pathname to the "checkout" command. - But it puts it in a strange place. The only reason to do - this is to hook a helper function onto a specific file name. - - - 5. An alias consisting of a list of any of the above, including - other aliases, plus exceptions. - - Example: - - my_work -a emacs !emacs/tests gnu/bison unix/bin/ls.c - - - The exception "!emacs/test" above is functionally equivalent - to specifying "!emacs/tests" on the "checkout" command line. - - - Another way to look at it is that the modules file is simply - another way to "name" files. The hierarchical directory - structure provides another. You should use whatever turns out to - be simplest for your development group. - - See 4G.2 for some specific ideas about how to use the modules file. - - - 1D.12 What does "merge" mean? - - A merge is a way of combining changes made in two independent - copies of a common starting file. Checking out an RCS revision - produces a file, so for the purposes of a merge "file" and - "revision" are equivalent. So, we can say there are always three - "files" involved in a merge: - - 1. The original, starting, "base" or "branch point" file. - 2. A copy of the base file modified in one way. - 3. Another copy of the base file modified in a different way. - - Humans aren't very good at handling three things at once, so the - terminology dealing with merges can become strained. One way to - think about it is that all merges are performed by inserting the - difference between a base revision and a later revision (committed - by someone else) into your working file. Both the "later" - revision and your working file are presumed to have started life - as a copy of the "base" revision. - - In CVS, there are three main types of "merge": - - 1. The "update" command automatically merges revisions committed - by others into your working file. In this case, the three - files involved in the merge are: - - Base: The revision you originally checked out. - Later: A revision committed onto the current branch - after you checked out the Base revision. - Working: Your working file. The one lying in the working - directory containing changes you have made. - - 2. The "update -j {optional files}" command merges - changes made on the given branch into your working files, which - is presumed to be on the Main line of development. - - See 4C.6 - - 3. The "update -j -j {optional files}" command merges - the difference between two specified revisions into files in - your working directory. The two revisions are usually on - the same branch and, when updating multiple files, they are - most useful when they are Tag names rather than numeric - revisions. - - See 4C.7 - - - - -========================================== -== Section 2 ==== User Tasks ==== -========================================== - ----------------- --- Section 2A -- Getting Started ----------------- - - **** Questions: - - 2A.1 What is the first thing I have to know? - 2A.2 Where do I work? - 2A.3 What does CVS use from my environment? - 2A.4 OK, I've been told that CVS is set up, my module is named - "ralph" and I have to start editing. What do I type? - 2A.5 I have been using RCS for a while. Can I convert to CVS without - losing my revision history? How about converting from SCCS? - - - **** Answers: - - 2A.1 What is the first thing I have to know? - - Your organization has most likely assigned one or more persons to - understand, baby-sit and administer the CVS programs and the data - Repository. I call these persons Repository Administrators. They - should have set up a Repository and "imported" files into it. - - If you don't believe anyone has this responsibility, or you are - just testing CVS, then *you* are the Repository Administrator. - - If you are a normal user of CVS ask your Repository Administrator - what module you should check out. - - Then you can work. - - If you *are* the Repository Administrator, you will want to read - everything you can get your hands on, including this FAQ. Source - control issues can be difficult, especially when you get to - branches and release planning. Expect to feel stupid for a few - days/weeks. - - No tool in the universe avoids the need for intelligent - organization. In other words, there are all sorts of related - issues you will probably have to learn. Don't expect to dive in - without any preparation, stuff your 300 Megabytes of sources into - CVS and expect to start working. If you don't prepare first, you - will probably spend a few sleepless nights. - - - 2A.2 Where do I work? - - Wherever you have disk space. That's one of the advantages of - CVS: you use the "checkout" command to copy files from the - Repository to your working directory, which can be anywhere you - have the space. - - Your local group might have conventions for where to work. - Ask your peers. - - - 2A.3 What does CVS use from my environment? - - You must set two environment variables. Some shells share these - variables with local shell variables using a different syntax. - You'll have to learn how your shell handles them. - - Variable Value (or action) - --------- --------------------- - CVSROOT Absolute pathname of the head of your Repository. - - PATH Normally set to a list of ':'-separated directory - pathnames searched to find executables. You must - make sure "cvs" is in one of the directories. - - If your CVS was built with the RCSBIN directory set - to null (""), and you don't set the RCSBIN - variable mentioned below, then the RCS commands - also must be somewhere in your PATH. - - - Optional variables: (Used if set, but ignored otherwise.) - - Variable Value (or action) - --------- --------------------- - CVSEDITOR The name of your favorite fast-start editor - program. You'll be kicked into your editor to - supply revision comments if you don't specify them - via -m "Log message" on the command line. - - EDITOR Used if CVSEDITOR doesn't exist. If EDITOR - doesn't exist, CVS uses a configured constant, - usually, "vi". - - CVSREAD Sets files to read-only on "checkout". - - RCSBIN Changes where CVS finds the RCS commands. - - CVSIGNORE Adds to the ignore list. See Section 2D. - - - Other variables used by CVS that are normally set upon login: - - Variable Value (or action) - --------- --------------------- - LOGNAME Used to find the real user name. - - USER Used to find the real user name if no LOGNAME. - - HOME Used to determine your home directory, if set. - Otherwise LOGNAME/USER/getuid() are used to find - your home directory from the passwd file. - - TMPDIR Used during import. It might also be used if your - platform's version of mktemp(3) is unusual, or - you have changed the source to use tmpnam(3). - - - - 2A.4 OK, I've been told that CVS is set up, my module is named - "ralph" and I have to start editing. What do I type? - - cd - cvs checkout ralph - cd ralph - - And hack away. - - - 2A.5 I have been using RCS for a while. Can I convert to CVS without - losing my revision history? How about converting from SCCS? - - If you are asking such questions, you are not a mere user of CVS, - but one of its Administrators! You should take a look at Section - 4A, "Installing CVS" and Section 4B, "Setting up and Managing - the Repository". - - ----------------- --- Section 2B -- Common User Tasks ----------------- - -What I consider a "common user task" generally involves combinations -of the following commands: - - checkout, update, commit, diff, log, status, tag, add - - -Conventions in this section: - - 1. Before each CVS command, you are assumed to have typed a "cd" - command to move into a writable working directory. - - 2. All further "cd" commands specified in the examples are assumed - to start in the above working directory. - - 3. Unless a point is being made about multiple instances, all modules - are named , all tags are named (branch tags are - named ) and all files are named . - - The checkout command will take a relative path name in place - of a module name. If you use a relative pathname in place of - , you should use the same relative path every place - you see in that example. - - - **** Questions: - - 2B.1 What is the absolute minimum I have to do to edit a file? - 2B.2 If I edit multiple files, must I type "commit" for each one? - 2B.3 How do I get rid of the directory that "checkout" created? - 2B.4 How do I find out what has changed since my last update? - 2B.5 I just created a new file. How do I add it to the Repository? - 2B.6 How do I merge changes made by others into my working directory? - 2B.7 How do I label a set of revisions so I can retrieve them later? - 2B.8 How do I checkout an old release of a module, directory or file? - 2B.9 What do I have to remember to do periodically? - - - **** Answers: - - - 2B.1 What is the absolute minimum I have to do to edit a file? - - Tell your Repository Administrator to create a module covering the - directory or files you care about. You will be told that your - module name is . Then type: - - cvs checkout - cd - emacs # Isn't Emacs a synonym for edit? - cvs commit - - If you don't use modules (in my opinion, a mistake), you can check - out a directory by substituting its relative path within the - Repository for in the example above. - - To work on a single file, you'll have to change "cd " to - "cd `dirname `". - - - 2B.2 If I edit multiple files, must I type "commit" for each one? - - No. You can commit a list of files and directories, including - relative paths into multiple directories. You can also commit - every modified file in the current directory or in all directories - and subdirectories from your current directory downward. See 3D.2. - - - 2B.3 How do I get rid of the directory that "checkout" created? - - Change your directory to be the same as when you executed the - "checkout" command that created . - - If you want to get rid of the CVS control information, but leave - the files and directories, type: - - cvs release - - If you want to obliterate the entire directory, type: - - cvs release -d - - ("release -d" searches through the output of "cvs -n update" and - refuses to continue if the "update" command finds any modified - files or non-ignored foreign files. Foreign directories too.) - - If you don't care about keeping "history", or checking for - modified and foreign files, you can just remove the whole - directory. That's "rm -rf " under Unix. - - - 2B.4 How do I find out what has changed since my last update? - - There are many ways to answer this. - - To find out what you've changed in your current working directory - since your last checkout, update or commit, type: - - cvs diff - - To find out what other people have added (to your branch) since - you last checked out or updated, type: - - cvs diff -r BASE -r HEAD - - To look at a revision history containing the comments for all - changes, you can use the "log" command. - - You can also use "history" to trace a wide variety of events. - - - 2B.5 I just created a new file. How do I add it to the Repository? - - The "update" command will mark files CVS doesn't know about in - your working directory with a '?' indicator. - - ? - - To add to the Repository, type: - - cvs add - cvs commit - - See 3A.[2-5] and 4C.8 for branch and merge considerations. - - - 2B.6 How do I merge changes made by others into my working directory? - - If you are asking about other branches, see Section 4C on - "Branching". You will have to use the "update -j" command. - - Retrieving changes made to the Repository on the *same* branch you - are working on is the main purpose of the "update" command. The - "update" command tries to merge work committed to the Repository - by others since you last executed "checkout", "update" or "commit" - into your working files. - - For a single file, there are six possible results when you type - the "update" command: - - 1. If the file is lying in your working directory, but is not - under CVS, it will do nothing but print: - - ? - - 2. If neither you nor anyone else has committed changes to , - since your last "checkout", "update" or "commit", "update" - will print nothing and do nothing. - - 3. If you have made no changes to a working file, but you or - others have committed changes to the Repository since your last - "checkout", "update" or "commit" of this working file, CVS will - remove your working file and replace it with a copy of the - latest revision of that file in the Repository. It will print: - - U - - You might want to examine the changes (using the CVS "diff" - command) to see if they mesh with your own in related files. - - 4. If you have made changes to a working file, but no one has - changed your BASE revision (the revision you retrieved from the - Repository in your last "checkout", "update" or "commit"), - "update" will print: - - M - - Nothing changes. You were told that you have a modified - file in your directory. - - 5. If you have made changes to your working file and you or others - have committed changes to the Repository, but in different - sections of the file, CVS will merge the changes stored in the - Repository since your last "checkout", "update" or "commit" - into your working file. "update" will print: - - RCS file: /Repository/module/ - retrieving revision 1.X - retrieving revision 1.Y - Merging differences between 1.X and 1.Y into - M - - If you execute "diff" before and after this step, you should - see the same output, since both the base file and your working - file changed in parallel. This is one of the few times the - otherwise nonsensical phrase "same difference" means something. - - 6. If both you and those who committed files (since your last - checkout, update or commit) have made changes to the same - section of a file, CVS will merge the changes into your file as - in #5 above, but it will leave conflict indicators in the file. - "update" will print: - - RCS file: /Repository/module/ - retrieving revision 1.X - retrieving revision 1.Y - Merging differences between 1.X and 1.Y into - rcsmerge warning: overlaps during merge - cvs update: conflicts found in - C - - This is a "conflict". The file will contain markers - surrounding the overlapping text. The 'C' conflict indicator - is sticky -- subsequent "update" commands will continue to show - a 'C' until you edit the file. - - You must examine the overlaps with care and resolve the problem - by analyzing how to retain the features of both changes. See - 2D.7 and 3P.6 for more details on conflict resolution. - - - 2B.7 How do I label a set of revisions so I can retrieve them later? - - To "tag" the BASE revisions (the ones you last checked out, - updated, or committed) you should "cd" to the head of the working - directory you want to tag and type: - - cvs tag - - It recursively walks through your working directory tagging the - BASE revisions of all files. - - To "tag" the latest revision on the Main branch in the - Repository, you can use the following from anywhere: - (No "cd" is required -- it works directly on the Repository.) - - cvs rtag - - - 2B.8 How do I checkout an old release of a module, directory or file? - - Module names and directories are simply ways to name sets of - files. Once the names are determined, there are 6 ways to specify - which revision of a particular file to check out: - - 1. By tag or symbolic name, via the "-r " option. - - 2. By date, via the "-D " option. - - 3. By branch tag (a type of tag with a magic format), via the - "-r " option. - - 4. By date within a branch, via the "-r :" - option. - - 5. By an explicit branch revision number ("-r "), which - refers to the latest revision on the branch. This isn't really - an "old" revision, from the branch's perspective, but from the - user's perspective the whole branch might have been abandoned - in the past. - - 6. An explicit revision number: "-r " Though this works, it - is almost useless for more than one file. - - - You type: - - cvs checkout - cd - - - 2B.9 What do I have to remember to do periodically? - - You should execute "cvs -n update" fairly often to keep track of - what you and others have changed. It won't change anything -- it - will just give you a report. - - Unless you are purposely delaying the inclusion of others' work, - you should execute "update" once in a while and resolve the - conflicts. It is not good to get too far out of sync with the - rest of the developers working on your branch. - - It is assumed that your system administrators have arranged for - editor backup and Unix temp files (#* and .#*) to be deleted after - a few weeks. But you might want to look around for anything else - that is ignored or hidden. Try "cvs -n update -I !" to see all - the ignored files. - - If you are the Repository Administrator, see 4B.16 on - Administrator responsibilities. - - ----------------- --- Section 2C -- Less Common User Tasks ----------------- - -What I consider a "less common user task" generally involves one or -more of the following commands: - - history, import, export, rdiff, release, remove, rtag - - - **** Questions: - - 2C.1 Can I create non-CVS sub-directories in my working directory? - 2C.2 How do I add new sub-directories to the Repository? - 2C.3 How do I remove a file I don't need? - 2C.4 How do I rename a file? - 2C.5 How do I make sure that all the files and directories in my - working directory are really in the Repository? - 2C.6 How do I create a branch? - 2C.7 How do I modify the modules file? How about the other files in - the CVSROOT administrative area? - 2C.8 How do I split a file into pieces, retaining revision histories? - - - **** Answers: - - - 2C.1 Can I create non-CVS sub-directories in my working directory? - - Yes. Unless the directory exists in the Repository, "update" will - skip over them and print a '?' the way it does for files you - forgot to add. You can avoid seeing the '?' by adding the name - of the foreign directory to the ./.cvsignore file, just ask you - can do with files. - - If you explicitly mention a foreign directory on the "update" - command line, it will traverse the directory and waste a bit of - time, but if any directory or sub-directory lacks the ./CVS - administrative directory, CVS will print an error and abort. - - - 2C.2 How do I add new sub-directories to the Repository? - - The "add" command will work on directories. You type: - - mkdir - cvs add - - It will respond: - - Directory /Repos/ added to the repository - - and will create both a matching directory in the Repository and a - ./CVS administrative directory within the local directory. - - - 2C.3 How do I remove a file I don't need? - - (See the questions in Section 4B on removing files from the - Repository.) - - You type: - - rm - cvs remove - - CVS registers the file for removal. To complete the removal, you - must type: - - cvs commit - - CVS moves the file to the Attic associated with your working - directory. Each directory in the Repository stores its deleted - files in an Attic sub-directory. A normal "checkout" doesn't - look in the Attic, but if you specify a tag, a date or a - revision, the "checkout" (or "update") command will retrieve - files from the Attic with that tag, date or revision. - - - 2C.4 How do I rename a file? - - CVS does not offer a way to rename a file in a way that CVS can - track later. See Section 4B for more information. - - Here is the best (to some, the only acceptable) way to get the - effect of renaming, while preserving the change log: - - 1. Copy the RCS (",v") file directly in the Repository. - - cp $CVSROOT//,v $CVSROOT//,v - - By duplicating the file, you will preserve the change - history and the ability to retrieve earlier revisions of the - old file via the "-r " or "-D " options to - "checkout" and "update". - - 2. Remove the old file using CVS. - - cd / - rm - cvs remove - cvs commit - - This will move the to the Attic associated with - . - - 3. Retrieve and remove all the Tags from it. - - By stripping off all the old Tags, "checkout -r" and - "update -r" won't retrieve revisions Tagged before - the renaming. - - cd / - cvs update - cvs log # Save the list of Tags - cvs tag -d - cvs tag -d - . . . - - - This technique can be used to rename files within one directory or - across different directories. You can apply this idea to - directories too, as long as you apply the above to each file and - don't delete the old directory. - - Of course, you have to change your build system (e.g. Makefile) in - your to know about the name change. - - Warning: Stripping the old tags from the copied file will allow - "-r " to do the right thing, but you will still have problems - with "-D " because there is no place to store the "deletion - time". See 5B.3 for more details. - - - 2C.5 How do I make sure that all the files and directories in my - working directory are really in the Repository? - - A "cvs update", or "cvs -n update" (which won't modify your - working directory) will display foreign elements, which have no - counterpart in the Repository, preceded by a '?'. To register - foreign directories, you can use "cvs add". To register foreign - files, you can use "cvs add" followed by "cvs commit". - - You could also checkout your module, or the Repository directory - associated with your working directory, a second time into another - work area and compare it to your working directory using the - (non-CVS) "diff -r" command. - - By default many patterns of files are ignored. If you create a - file named "core" or a file ending in ".o", it is usually - ignored. If you really want to see all the files that aren't in - the Repository, you can use a special "ignore" pattern to say - "ignore no files". Try executing: (You may have to quote or - backwhack (i.e. precede by '\') the '!' in your shell.) - - cvs -n update -I ! - - The above command will display not only the normal modified, - update and conflict indicators ('M', 'U', and 'C' respectively) on - files within the Repository, but it will also display each file - not in the Repository preceded by a '?' character. - - The '-n' option will not allow "update" to alter your working - directory. - - - 2C.6 How do I create a branch? - - Type this in your working directory: - - cvs tag -b - - and you will create a branch. No files have real branches in them - yet, but if you move onto the branch by typing: - - cvs update -r - - and commit a file in the normal way: - - cvs commit - - then a branch will be created in the underlying ,v file and - the new revision of will appear only on that branch. - - See Section 4C, on Branching. - - - 2C.7 How do I modify the modules file? How about the other files in - the CVSROOT administrative area? - - A module named "modules" has been provided in the default modules - file, so you can type: - - cvs checkout modules - cd modules - - Another module named CVSROOT has been provided in the default - modules file, covering all the administrative files. Type: - - cvs checkout CVSROOT - cd CVSROOT - - Then you can edit your files, followed by: - - cvs commit - - If you start with the provided template for the "modules" file, - the CVSROOT and the "modules" module will have the "mkmodules" - program as a "commit helper". After a file is committed to such a - module, "mkmodules" will convert a number of standard files (See - 4B.2) in the CVSROOT directory inside the Repository into a form - that is usable by CVS. - - - 2C.8 How do I split a file into pieces, retaining revision histories? - - If you and a coworker find yourselves repeatedly committing the - same file, but never for changes in the same area of the file, you - might want to split the file into two or more pieces. If you are - both changing the same section of code, splitting the file is of - no use. You should talk to each other instead. - - If you decide to split the file, here's a suggestion. In many - ways, it is similar to multiple "renamings" as described in - 2C.4 above. - - Say you want to split , which already in the Repository, - into three pieces, , and . - - 1. Copy the RCS (",v") files directly in the Repository, - creating the new files, then bring readable copies of the - new files into the working directory via "update". - - cp $CVSROOT//,v $CVSROOT//,v - cp $CVSROOT//,v $CVSROOT//,v - cvs update - - 2. Then remove all the from the new files by using: - - cvs log # Save the list of - cvs tag -d - cvs tag -d - . . . - - 3. Edit each file until it has the data you want in it. - This is a hand-editing job, not something CVS can handle. - Then commit all the files. - - [From experience, I'd suggest making sure that only one copy - of each line of code exists among the three files, except - for "include" statements, which must be duplicated. And - make sure the code compiles.] - - emacs - cvs commit - - - As in the "rename" case, by duplicating the files, you'll preserve - the change history and the ability to retrieve earlier revisions. - - Of course, you have to alter your build system (e.g. Makefiles) to - take the new names and the change in contents into account. - - - ----------------- --- Section 2D -- General Questions ----------------- - - **** Questions: - - 2D.1 How do I see what CVS is trying to do? - 2D.2 If I work with multiple modules, should I check them all out and - commit them occasionally? Is it OK to leave modules checked out? - 2D.3 What is a "sticky" tag? What makes it sticky? How do I loosen it? - 2D.4 How do I get an old revision without updating the "sticky tag"? - 2D.5 What operations disregard sticky tags? - 2D.6 Is there a way to avoid reverting my Emacs buffer after - committing a file? Is there a "cvs-mode" for Emacs? - 2D.7 How does conflict resolution work? What *really* happens if two - of us change the same file? - 2D.8 How can I tell who has a module checked out? - 2D.9 Where did the .#.1.3 file in my working directory come from? - 2D.10 What is this "ignore" business? What is it ignoring? - 2D.11 Is there a way to set user-specific configuration options? - 2D.12 Is it safe to interrupt CVS using Control-C? - 2D.13 How do I turn off the "admin" command? - 2D.14 How do I turn off the ability to disable history via "cvs -l"? - 2D.15 How do I keep certain people from accessing certain directories? - - - **** Answers: - - - 2D.1 How do I see what CVS is trying to do? - - The '-t' option on the main "cvs" command will display every - external command (mostly RCS commands and file deletions) it - executes. When combined with the '-n' option, which prevents the - execution of any command that might modify a file, you can see - what it will do before you let it fly. The '-t' option will *not* - display every internal action, only calls to external programs. - - To see a harmless example, try typing: - - cvs -nt update - - Some systems offer a "trace" or "truss" command that will display - all system calls as they happen. This is a *very* low-level - interface that does not normally follow the execution of external - commands, but it can be useful. - - The most complete answer is to read the source, compile it - with the '-g' option and step through it under a debugger. - - - 2D.2 If I work with multiple modules, should I check them all out and - commit them occasionally? Is it OK to leave modules checked out? - - The simple answers are "Yes." - - There is no reason to remove working directories, other than to - save disk space. As long as you have committed the files you - choose to make public, your working directory is just like any - other directory. - - CVS doesn't care whether you leave modules checked out or not. - The advantage of leaving them checked out is that you can quickly - visit them to make and commit changes. - - - 2D.3 What is a "sticky" tag? What makes it sticky? How do I loosen it? - - When you execute "update -r ", CVS remembers the . It - has become "sticky" in the sense that until you change it or - remove it, the tag is remembered and used in references to the - file as if you had typed "-r " on the command line. - - It is most useful for a , which is a sticky tag - indicating what branch you are working on. - - A revision number ("-r ") or date ("-D ") can - also become sticky when they are specified on the command line. - - A sticky tag, revision or date remains until you specify another - tag, revision or date the same way. The "update -A" command - moves back to the Main branch, which has the side-effect of - clearing all sticky items on the updated files. - - The "checkout" command creates sticky tags, revisions and dates - the same way "update" does. - - Also, the '-k' option records a "sticky" keyword option that - is used in further "updates until "update -A" is specified. - - - 2D.4 How do I get an old revision without updating the "sticky tag"? - - Use the '-p' option to "pipe" data to standard output. The - command "update -p -r " sends the selected revision to - your standard output (usually the terminal, unless redirected). - The '-p' affects no disk files, leaving a "sticky tag" unaltered - and avoiding all other side-effects of a normal "update". - - If you want to save the result, you can redirect "stdout" to a - file using your shell's redirection capability. In most shells - the following command works: - - cvs update -p -r filename > diskfile - - - 2D.5 What operations disregard sticky tags? - - The functions that routinely disregard sticky tags are: - - 1. Those that work directly on the Repository or its - administrative files: - - admin rtag log status remove history - - 2. Those that take Tags or revisions as arguments and ignore - everything else: (They also never *set* a sticky tag.) - - rdiff import export - - 3. The "release" command itself ignores sticky tags, but it - calls "cvs -n update" (which *does* pay attention to a - sticky tag) to figure out what inconsistencies exist in - the working directory. If no discrepancies exist between - the files you originally checked out (possibly marked by a - sticky tag) and what is there now, "release -d" will - delete them all. - - 4. The "tag" command works on the revision lying in the - working directory however it got there. That the revision - lying there might happen to have a sticky tag attached to - it is not the "tag" command's concern. - - - The main function that *does* read and write sticky tags is the - "update" command. You can avoid referring to or changing the - sticky tag by using the '-p' option, which sends files to your - terminal, touching nothing else. - - The "checkout" command sets sticky tags when checking out a new - module and it acts like "update" when checking out a module into - an existing directory. - - The "diff" and "commit" commands use the sticky tags, unless - overridden on the command line. They do not set sticky tags. - Note that you can only "commit" to a file checked out with a - sticky tag, if the tag identifies a branch. - - There are really two types of sticky tags, one attached to - individual files (in the ./CVS/Entries file) and one attached to - each directory (in the ./CVS/Tag file). They can differ. - - The "add" command registers the desire to add a new file. If the - "directory tag" (./CVS/Tag) file exists at the time of the "add", - the value stored in ./CVS/Tag becomes the "sticky tag" on the new - file. The file doesn't exist in the Repository until you "commit" - it, but the ./CVS/Entries file holds the sticky tag name from the - time of the "add" forward. - - - 2D.6 Is there a way to avoid reverting my Emacs buffer after - committing a file? Is there a "cvs-mode" for Emacs? - - See Section 4F.1 - - - 2D.7 How does conflict resolution work? What *really* happens if two - of us change the same file? - - While editing files, there is no conflict. You are working on - separate copies of the file stored in the virtual "branch" - represented by your working directories. After one of you commits - a file, the other may not commit the same file until "update" has - merged the earlier committed changes into the later working file. - - For example, say you both check out rev 1.2 of and make - change to your working files. Your coworker commits revision 1.3. - When you try to commit your file, CVS says: - - cvs commit: Up-to-date check failed for `' - - You must merge your coworker's changes into your working file by - typing: - - cvs update - - which will produce the output described in 2B.6. - - If a conflict occurs, the filename will be shown with a status of - 'C'. After you resolve any overlaps caused by the merging - process, you may then commit the file. See 3P.6 for info on - "sticky conflicts". - - Even if you get a simple 'M', you should examine the differences - before committing the file. A smooth, error-free text merge is - still no indication that the file is in proper shape. Compile and - test it at least. - - The answer to two obvious questions is "Yes". - - Yes, the first one who commits avoids the merge. Later developers - have to merge the earlier changes into their working files before - committing the merged result. Depending on how difficult the merge - is and how important the contending projects are, the order of - commits and updates might have to be carefully staged. - - And yes, between the time you execute "update" and "commit" (while - you are fixing conflicts and testing the results) someone else may - commit another revision of . You will have to execute - "update" again to merge the new work before committing. Most - organizations don't have this problem. If you do, you might - consider splitting the file. Or hiring a manager. - - - 2D.8 How can I tell who has a module checked out? - - If you "checkout" module names (not relative pathnames) and you - use the release command, the "history" command will display active - checkouts, who has them and where they were checked out. It is - advisory only; it can be circumvented by using the '-l' option on - the main "cvs" command. - - - 2D.9 Where did the .#.1.3 file in my working directory come from? - - It was created during an "update" when CVS merged changes from the - Repository into your modified working file. - - It serves the same purpose as any "backup" file: saving your bacon - often enough to be worth retaining. It is invaluable in - recovering when things go wrong. - - Say Developers A (you) and B check out rev 1.3 of file . - You both make changes -- different changes. B commits first, so - ,v in the Repository contains revisions up through 1.4. - - At this point, there are 5 (yes, five) versions of the file of - interest to you: - - 1. Revision 1.3 (What you originally checked out.) - 2. Revision 1.4 (What you need from developer B.) - 3. Your old working file. (Before the update.) - 4. Your new working file. (After the merge caused by "update".) - 5. Revision 1.5 (Which you will commit shortly.) - - In the case where your working file was not modified, #1 and #3 - will be the same, as will #2 and #4. In this degenerate case, - there is no need to create #5. The following assumes that your - working file was modified. - - If the merge executed by the "update" caused no overlaps, and you - commit the file immediately, #4 and #5 will be the same. But you - can make arbitrary changes before committing, so the difference - between #4 and #5 might be more than just the correction of - overlaps. In general, though, you don't need #4 after a commit. - - But #3 (which is the one saved as ".#.1.3") holds all of - your work, independent of B's work. It could represent a major - effort that you couldn't afford to lose. If you don't save it - somewhere, the merge makes #3 *disappear* under a potential - blizzard of conflicts caused by overlapping changes. - - I have been saved a few times, and others I support have been - saved hundreds of times, by the ability to "diff - ", which can be done in the - example above by the Unix shell command: - - cvs update -p -r 1.3 | diff - .#.1.3 - - The assumption is that the ".#" files will be useful far beyond - the "commit" point, but not forever. You are expected to run - the "normal" Unix cleanup script from "cron", which removes "#*" - and ".#*" files older than a some period chosen by your - sysadmin, usually ranging from 7 to 30 days. - - A question was raised about the need for #3 after #5 has been - committed, under the assumption that you won't commit files until - everything is exactly as you like them. - - This assumes perfect humans, which violates one of the Cardinal - rules of Software Engineering: Never assume any form of discipline - on the part of the users of software. If restrictions are not - bound into the software, then you, the toolsmith, have to arrange - a recovery path. - - In other words, I've seen every possible variety of screwup you - can imagine in #5. There is no way to make assumptions about - what "should" happen. I've seen #5 filled with zeros because of - NFS failures, I've seen emacs core dumps that leave #5 in an - unreasonable state, I've seen a foolish developer uppercase the - whole file (with his "undo" size set low so he couldn't undo it) - and decide that it would be less work to play with the - uppercased file than to blow it away and start over. I've even - seen committed files with conflict markers still in them, a sure - sign of carelessness. - - There are all sorts of scenarios where having #3 is incredibly - useful. You can move it back into place and try again. - - - 2D.10 What is this "ignore" business? What is it ignoring? - - The "update" and "import" commands use collections of Unix - wildcards to skip over files and directories matching any of those - patterns. - - You may add to the built-in ignore list by adding lines of - whitespace-separated wildcards to the following places: (They are - read in this order.) - - 1. In a file named "cvsignore" in $CVSROOT/CVSROOT. - - A Repository Administrator uses this to add site-specific - files and patterns to the built-in ignore list. - - 2. In a file named ".cvsignore" in your home directory. - - For user-specific files. For example, if you use "__" as - your default junk file prefix, you can put "__*" in your - .cvsignore file. - - People who play around exclusively in directory trees where the - Makefiles are generated by "imake" or "configure" might want to - put "Makefile" in their ignore list, since they are all - generated and usually don't end up in the Repository. - - 3. In the CVSIGNORE environment variable. - - For session-specific files. - - 4. Via the '-I' option on "import" or "update" commands. - - For this-command-only files. - - 5. In a file named ".cvsignore" within each directory. - - The contents of a ".cvsignore" file in each directory is - temporarily added to the ignore list. This way you can ignore - files that are peculiar to that directory, such as executables - and other generated files without known wildcard patterns. - - In any of the places listed above, a single '!' character nulls - out the ignore list. A Repository administrator can use this to - override, rather than enhance, the built-in ignore list. A user - can choose to override the system-wide ignore list. For example, - if you place "! *.o *.a" in your .cvsignore file, only *.o *.a - files, plus any files a local-directory .cvsignore file, are - ignored. - - A variant of the ignore-file scheme is used internally during - checkout. "Module names" found in the modules file (or on the - "checkout" command line) that begin with a '!' are ignored during - checkout. This is useful to permanently ignore (if the '!' path - is in the modules file) or temporarily ignore (if the '!' path is - on the command line) a sub-directory within a Repository - hierarchy. For example: - - cvs checkout !gnu/emacs/tests gnu/emacs - - would checkout the module (or relative path within $CVSROOT) named - "gnu/emacs", but ignore the "tests" directory within it. - - - 2D.11 Is there a way to set user-specific configuration options? - - User-specific configuration is available through use of a ".cvsrc" - file in your home directory. - - CVS searches the first column of your ~/.cvsrc file for the cvs - command name you invoked. If the command is found, the rest of - the line is treated like a set of command line options, stuffed - into the command line before the arguments you actually typed. - - For example, if you always want to see context diffs and you never - want to have to delete a file before you run "cvs remove", then - you should create a .cvsrc file containing the following: - - diff -c - remove -f - - which will add the given options to every invocation of the given - commands. - - [[The rest of this will be removed someday, when CVS changes.]] - - I would like to stop here with a comment that the command name to - use is the full, canonical one. But the command that the cvsrc - support uses is the string you typed on the command line, not the - proper command. So to get the full effect of the above example, - you should also add all the alternate command names: - - di -c - dif -c - rm -f - delete -f - - There are two other limitations that will probably be fixed when - CVS sprouts long option names: - - 1. It only affects options made available on the command line. - - There is a limited number of short options. With long option - names, there is no problem. You can have as many long options - as you like, affecting anything that looks malleable. - - 2. The existing command line options do not come in on/off pairs, - so there is no easy way to override your ~/.cvsrc configuration - for a single invocation of a command. - - Choosing a good set of long option pairs would fix this. - - - 2D.12 Is it safe to interrupt CVS using Control-C? - - It depends on what you mean by "safe". ("Ah," said Arthur, - "this is obviously some strange usage of the word *safe* that I - wasn't previously aware of." -- Hitchhiker's Guide to the Galaxy) - - You won't hurt the underlying RCS files and if you are executing a - command that only *reads* data, you will have no cleanup to do. - - But you may have to hit Control-C repeatedly to stop it. CVS uses - the Unix "system" routine which blocks signals in the CVS parent - process. A single Control-C during "system" will only halt the - child process, usually some form of RCS command. - - If you don't hit another Control-C while the CVS process has - control, it is likely to continue onto the next task assuming that - the earlier one did its job. It is not enough to hit two - Control-C's. You might simply kill two child processes and not - interrupt CVS at all. Depending on the speed of your processor, - your terminal and your fingers, you might have to hit dozens of - Control-C's to stop the damn thing. - - - Executing a CVS command, such as "commit" or "tag" that writes - to the files is a different matter. - - Since CVS is not a full-fledged database, with what database - people call "commit points", merely stopping the process will not - back out the "transaction" and place you back in the starting - blocks. CVS has no concept of an "atomic" transaction or of - "backtracking", which means that a command can be half-executed. - - Hitting Control-C will usually leave lock files that you have to - go clean up in the Repository. - - Example1: - - If you interrupt a multi-file "commit" in the middle of - an RCS checkin, RCS will leave the file either fully - checked-in or in its original state. But CVS might have - been half-way through the list of files to commit. The - directory or module will be inconsistent. - - To recover, you must remove the lock files, then decide - whether you want to back out or finish the job. - - To back out, you'll have to apply the "admin -o" - command, very carefully, to remove the newly committed - revisions. This is usually a bad idea, but is - occasionally necessary. - - To finish, you can simply retype the same commit command. - CVS will figure out what files are still modified and - commit them. It helps that RCS doesn't leave a file in an - intermediate state. - - - Example2: - - If you interrupt a multi-file "tag" command, you have a - problem similar, but not equivalent, to interrupting a - "commit". The RCS file will still be consistent, but - unlike "commit", which only *adds* to the RCS file, "tag" - can *move* a tag and it doesn't keep a history of what - revision a tag used to be attached to. - - Normally, you have little choice but to re-execute the - command and allow it to tag everything consistently. - - You might be able to recover by carefully re-applying the - tags via the "cvs admin -N" command, but you'll still have - to dig up from outside sources the information you use to - determine what tag was on what revision in what file. - the Repository, or by using the equivalent: "cvs admin". - - - Halting a new "checkout" should cause no harm. If you don't want - it, "release" (or rm -rf) it. If you do want it, re-execute the - command. A repeated "checkout" from above a directory acts like a - repeated "update -d" within it. - - Halting "update" half-way will give you an unpredictable - collection of files and revisions. To continue, you can rerun the - update and it should move you forward into in a known state. To - back out, you'll have to examine the output from the first - "update" command, take a look at each file that was modified and - reconstruct the previous state by editing the ./CVS/Entries file - and by using "cvs admin". Good Luck. - - - 2D.13 How do I turn off the "admin" command? - - In the current revision, you'd have to edit the source code. - - - 2D.14 How do I turn off the ability to disable history via "cvs -l"? - - In the current revision, you'd have to edit the source code. - - - 2D.15 How do I keep certain people from accessing certain directories? - - If you don't try to run CVS set[ug]id, you can use Unix groups and - permissions to limit access to the Repository. - - If you only want to limit "commit" commands, you can write a - program to put in the "commitinfo" file. In the "contrib" - directory, there are a few scripts that might help you out. - - - -======================================== -== Section 3 ==== Commands ==== -======================================== - -This section contains questions that are easily recognized to be about a -single command, usually of the form: "Why does the 'xyz' command do this?" - -Questions about "missing" features and side-effects not attributable to a -particular command are in Section 2D, "General Questions". - -I won't provide patches here that are longer than a few lines. Patches -referred to in this section are available in the FTP archive described -toward the beginning of this document. - - ----------------- --- Section 3A -- "add", "ad", "new" ----------------- - - **** Questions: - - 3A.1 What is "add" for? - 3A.2 How do I add a new file to the branch I'm working on? - 3A.3 Why did my new file end up in the Attic? - 3A.4 Now that it's in the Attic, how do I connect it to the Main branch? - 3A.5 How do I avoid the hassle of reconnecting an Attic-only file to - the Main Branch? - 3A.6 How do I cancel an "add"? - 3A.7 What are the ./CVS/file,p and ./CVS/file,t files for? - 3A.8 How do I "add" a binary file? - - - **** Answers: - - 3A.1 What is "add" for? - - To add a new directory to the Repository or to register the - desire to add a new file to the Repository. - - The directory is created immediately, while the desire to add the - file is recorded in the local ./CVS administrative directory. To - really add the file to the Repository, you must then "commit" it. - - - 3A.2 How do I add a new file to the branch I'm working on? - - The user actions for adding a file to any branch, including the - Main Branch, are exactly the same. - - You are in a directory checked out (or updated) with the '-A' - option (to place you on the Main Branch) or the "-r " - option (to place you on a branch tagged with ). To - add to the branch you are on, you type: - - cvs add - cvs commit - - If no ./CVS/Tag file exists (the '-A' option deletes it), the - file will be added to the Main Branch. If a ./CVS/Tag file exists - (the "-r " option creates it), the file will be added - to the branch named (i.e. tagged with) . - - Unless you took steps to first add the file to the Main Branch, - your new file ends up in the Attic. - - - 3A.3 Why did my new file end up in the Attic? - - The file is thrown into the Attic to keep it from being visible - when you check out the Main Branch, since it was never committed - to the Main Branch. - - - 3A.4 Now that it's in the Attic, how do I connect it to the Main branch? - - That can be considered a kind of "merge". See 4C.8 - - - 3A.5 How do I avoid the hassle of reconnecting an Attic-only file to - the Main Branch? - - You create it on the Main Branch first, then branch it. - - If you haven't yet added the file or if you decided to delete the - new Attic file and start over, then do the following: - (If you added the file (or worse, the 157 files) to the Attic and - don't want to start over, try the procedure in 4C.8.) - - - 1. Temporarily remove the sticky branch information. Either: - - A. Move the whole directory back to the Main Branch. - [This might not be a good idea if you have modified files, - since it will require a merge in each direction.] - - cvs update -A - - *or* - - B. Move the ./CVS/Tag file out of the way. - - mv ./CVS/Tag HOLD_Tag - - 2. Add and branch the file "normally": - - cvs add - cvs commit - cvs tag -b - - [ is the same Branch Tag as you used on all - the other files. Look at ./CVS/Entries or the output - from "cvs stat" for sticky tags.] - - 3. Clean up the temporary step. - - A. If you moved the ./CVS/Tag file, put it back. Then - move the new file onto the branch where you are working. - - mv HOLD_Tag ./CVS/Tag - cvs update -r - - B. If you ran "update -A" rather than moving the ./CVS/Tag - file, move the whole directory (including the new file) back - onto the branch where you were working: - - cvs update -r - - - 3A.6 How do I cancel an "add"? - - If you want to remove the file entirely and cancel the "add" at - the same time, type: - - cvs remove -f - - If you want to cancel the "add", but leave the file as it was - before you typed "cvs add", then you have to fake it: - - mv .hold - cvs remove - mv .hold - - - 3A.7 What are the ./CVS/file,p and ./CVS/file,t files for? - - The ./CVS/file,p and ./CVS/file,t files are created by the "add" - command to hold command line options and message text between the - time of the "add" command and the expected "commit". - - The ./CVS/file,p file is always null, since its function was - absorbed by the "options" field in the ./CVS/Entries file. If you - put something in this file it will be used as arguments to the RCS - "ci" command that commit uses to check the file in, but CVS itself - doesn't put anything there. - - The ./CVS/file,t file is null unless you specify an initial - message in an "add -m 'message'" command. The text is handed to - "rcs -i -t./CVS/file,t" to create the initial RCS file container. - - Both files must exist to commit a newly added file. If the - ./CVS/file,p file doesn't exist, CVS prints an error and aborts - the commit. If the ./CVS/file,t file doesn't exist, RCS prints an - error and CVS gets confused, but does no harm. - - To recover from missing ,p and ,t files, just create two - zero-length files and rerun the "commit". - - - 3A.8 How do I "add" a binary file? - - If you configured CVS to use the GNU version of "diff" and - "diff3", you only need to turn off RCS keyword expansion. - - First you turn off RCS keyword expansion for the initial checkin - by using "add -ko". It works like "update -ko" in creating a - "sticky" option only for the copy of the file in the current - working directory. - - cvs add -ko - - Commit the file normally. The sticky -ko option will be used. - - cvs commit - - Then mark the RCS file in the Repository so that keyword - expansion is turned off for all checked out versions of the file. - - cvs admin -ko - - Since "admin -ko" records the keyword substitution value in the - Repository's RCS file, you no longer need the sticky option. You - can turn it off with the "update -A" command, but if you were on a - branch, you'll have to follow it "update -r " to put - yourself back on the branch. - - - Managing that binary file is another problem. See 4D.1. - - - ----------------- --- Section 3B -- "admin", "adm", "rcs" ----------------- - - **** Questions: - - 3B.1 What is "admin" for? - 3B.2 Wow! Isn't that dangerous? - 3B.3 What would I normally use "admin" for? - 3B.4 What should I avoid when using "admin"? - 3B.5 How do I restrict the "admin" command? The -i flag in the modules - file can restrict commits. What's the equivalent for "admin"? - 3B.6 I backed out a revision with "admin -o" and committed a - replacement. Why doesn't "update" retrieve the new revision? - - - **** Answers: - - - 3B.1 What is "admin" for? - - To provide direct access to the underlying "rcs" command (which - is not documented in this FAQ) bypassing all safeguards and CVS - assumptions. - - - 3B.2 Wow! Isn't that dangerous? - - Yes. - - Though you can't hurt the internal structure of an RCS file using - its own "rcs" command, you *can* change the underlying RCS - files using "admin" in ways that CVS can't handle. - - If you feel the need to use "admin", create some test files - with the RCS "ci" command and experiment on them with "rcs" - before blasting any CVS files. - - - 3B.3 What would I normally use "admin" for? - - Normally, you wouldn't use admin at all. In unusual - circumstances, experts can use it to set up or restore the - internal RCS state that CVS requires. - - You can use "admin -o" (for "outdate") to remove revisions - you don't care about. This has its own problems, such as leaving - dangling Tags and confusing the "update" command. - - There is some feeling among manipulators of binary files that - "admin -l" should be used to serialize access. See 3C.8. - - An interesting use for "admin" came up while maintaining CVS - itself. I import versions of CVS onto the Vendor branch of my - copy of CVS, make changes to some files and ship the diffs - (created by "cvs diff -c -r TO_BRIAN") off to Brian Berliner. - After creating the diff, I retag ("cvs tag -F TO_BRIAN") the - working directory, which is then ready to produce the next patch. - - I'll use "add.c" as an example (only because the name is short). - - When the next release came out, I discovered that the released - "add.c" (version 1.1.1.3 on the Vendor branch) was exactly the - same as my modified file (version 1.3). I didn't care about the - changelog on versions 1.2 and 1.3 (or the evidence of having done - the work), so I decided to revert the file to the state where it - looked like I had not touched the file -- where I was just using - the latest on the vendor branch after a sequence of imports. - - To do that, I removed all the revisions on the main branch, except - for the original 1.1 from which the Vendor branch sprouts: - - cvs admin -o1.2: add.c - - Then I set the RCS "default branch" back to the Vendor branch, the - way import would have created it: - - cvs admin -b1.1.1 add.c - - And I moved the "TO_BRIAN" Tag to the latest revision on the - Vendor branch, since that is the base from which further patches - would be created (if I made any): - - cvs admin -NTO_BRIAN:1.1.1.3 add.c - - Instead of 1.1.1.3, I could have used one of the "Release Tags" - last applied by "import" (3rd through Nth arguments). - - Suggestion: Practice on non-essential files. - - - - 3B.4 What should I avoid when using "admin"? - - If you know exactly what you are doing, hack away. But under - normal circumstances: - - Never use "admin" to alter branches (using the '-b' option), which - CVS takes very seriously. If you change the default branch, CVS - will not work as expected. If you create new branches without - using the "tag -b" command, you may not be able to treat them as - CVS branches. - - See 3C.8 for a short discussion of how to use "admin -l" for - serializing access to binary files. - - The "admin -o " allows you to delete revisions, usually a - bad idea. You should commit a correction rather than back out a - revision. Outdating a revision is prone to all sorts of problems: - - 1. Discarding data is always a bad idea. Unless something in the - revision you just committed is a threat to your job or your - life, (like naming a function "_is_a_dweeb", or - including the combination to the local Mafioso's safe in a C - comment), just leave it there. No one cares about simple - mistakes -- just commit a corrected revision. - - 2. The time travel paradoxes you can cause by changing history - are not worth the trouble. Even if CVS can't interfere with - your parents' introduction, it *can* log commits in at least - two ways (history and loginfo). The reports now lie -- the - revision referred to in the logs no longer exists. - - 3. If you used "import" to place into CVS, outdating all - the revisions on the Main branch back to and including revision - 1.2 (or worse, 1.1), will produce an invalid CVS file. - - If the ,v file only contains revision 1.1 (and the - connected branch revision 1.1.1.1), then the default branch - must be set to the Vendor branch as it was when you first - imported the file. Outdating back through 1.2 doesn't restore - the branch setting. Despite the above admonition against it, - "admin -b" is the only way to recover: - - cvs admin -b1.1.1 - - 4. Although you can't outdate a physical (RCS) branch point - without removing the whole branch, you *can* outdate a revision - referred to by a magic branch tag. If you do so, you will - invalidate the branch. - - 5. If you "outdate" a tagged revision, you will invalidate all - uses of the , not just the one on . A tag is - supposed to be attached to a consistent set of files, usually a - set built as a unit. By discarding one of the files in the - set, you have destroyed the utility of the . And it - leaves a dangling tag, which points to nothing. - - 6. And even worse, if you commit a revision already tagged, you - will alter what the pointed to without using the "tag" - command. For example, if revision 1.3 has attached to it - and you "outdate" the 1.3 revision, will point to a - nonexistent revision. Although this is annoying, it is nowhere - near as much trouble as the problem that will occur when you - commit to this file again, recreating revision 1.3. The old - tag will point to the new revision, a file that was not in - existence when the was applied. And the discrepancy is - nearly undetectable. - - - If you don't understand the above, you should not use the admin - command at all. - - - 3B.5 How do I restrict the "admin" command? The -i flag in the modules - file can restrict commits. What's the equivalent for "admin"? - - At this writing, to disable the "admin" command, you will have - to change the program source code, recompile and reinstall. - - - 3B.6 I backed out a revision with "admin -o" and committed a - replacement. Why doesn't "update" retrieve the new revision? - - CVS is confused because the revision in the ./CVS/Entries file - matches the latest revision in the Repository *and* the timestamp - in the ./CVS/Entries file matches your working file. CVS believes - that your file is "up-to-date" and doesn't need to be updated. - - You can cause CVS to notice the change by "touch"ing the file. - Unfortunately what CVS will tell you is that you have a "Modified" - file. If you then "commit" the file, you will bypass the - normal CVS check for "up-to-date" and will probably commit the - revision that was originally removed by "admin -o". - - Changing a file without changing the revision number confuses CVS - no matter whether you did it by replacing the revision (using - "admin -o" and "commit" or raw RCS commands) or by applying an - editor directly to a Repository (",v") file. Don't do it unless - you are absolutely certain no one has the latest revision of the - file checked out. - - The best solution to this is to institute a program of deterrent - flogging of abusers of "admin -o". - - The "admin" command has other problems." See 3B.4 above. - - ----------------- --- Section 3C -- "checkout", "co", "get" ----------------- - - **** Questions: - - 3C.1 What is "checkout" for? - 3C.2 What is the "module" that "checkout" takes on the command line? - 3C.3 Isn't a CVS "checkout" just a bunch of RCS checkouts? - 3C.4 What's the difference between "update" and "checkout"? - 3C.5 Why can't I check out a file from within my working directory? - 3C.6 How do I avoid dealing with those long relative pathnames? - 3C.7 Can I move a checked-out directory? Does CVS remember where it - was checked out? - 3C.8 How can I lock files while I'm working on them the way RCS does? - 3C.9 What is "checkout -s"? How is it different from "checkout -c"? - - - **** Answers: - - 3C.1 What is "checkout" for? - - To acquire a copy of a module (or set of files) to work on. - - All work on files controlled by CVS starts with a "checkout". - - - 3C.2 What is the "module" that "checkout" takes on the command line? - - It is a name for a directory or a collection of files in the - Repository. It provides a compact name space and the ability to - execute before and after helper functions based on definitions in - the modules file. - - See 1D.11. - - - 3C.3 Isn't a CVS "checkout" just a bunch of RCS checkouts? - - Like much of CVS, a similar RCS concept is used to support a CVS - function. But a CVS checkout is *not* the same as an RCS - checkout. - - Differences include: - - 1. CVS does not lock the files. Others may access them at the - same time. - - 2. CVS works best when you provide a name for a collection of - files (a module or a directory) rather than an explicit list of - files to work on. - - 3. CVS remembers what revisions you checked out and what branch - you are on, simplifying later commands. - - - 3C.4 What's the difference between "update" and "checkout"? - - The "checkout" and "update" commands are nearly equivalent in how - they treat individual files. They differ in the following ways: - - 1. The "checkout" command always creates a directory, moves into - it, then becomes equivalent to "update -d". - - 2. The "update" command does not create directories unless you add - the '-d' option. - - 3. "Update" is intended to be executed within a working directory - created by "checkout". It doesn't take a module or directory - argument, but figures out what Repository files to look at by - reading the files in the ./CVS administrative directory. - - 4. The two commands generate completely different types of records - in the "history" file. - - - 3C.5 Why can't I check out a file from within my working directory? - - Though you *can* check out a file, you normally check out a module - or directory. And you normally do it only once at the beginning - of a project. - - After the initial "checkout", you can use the "update" command - to retrieve any file you want within the checked-out directory. - There is no need for further "checkout" commands. - - If you want to retrieve another module or directory to work on, - you must provide two pathnames: where to find it in the Repository - and where to put it on disk. The "modules" file and your current - directory supply two pieces of naming information. While inside a - checked-out working directory, the CVS administrative information - provides most of the rest. - - You should be careful not to confuse CVS with RCS and use - "checkout" in the RCS sense. An RCS "checkout" (which is - performed by the RCS "co" command) is closer to a "cvs update" - than to a "cvs checkout". - - - 3C.6 How do I avoid dealing with those long relative pathnames? - - This question has also been phrased: - - How do I avoid all those layers of directories on checkout? - or - Why do I have to go to the top of my working directory and - checkout some long pathname to get a file or two? - - - This type of question occurs only among groups of people who - decide not to use "modules". The answer is to use "modules". - - When you hand the "checkout" command a relative pathname rather - than a module name, all directories in the path are created, - maintaining the same directory hierarchy as in the Repository. - The same kind of environment results if you specify a "module" - that is really an alias expanding into a list of relative - pathnames rather than a list of module names. - - If you use "module" names, "checkout" creates a single - directory by the name of the module in your current directory. - This "module" directory becomes your working directory. - - The "module" concept combines the ability to "name" a collection - of files with the ability to structure the Repository so that - consistent sets of files are checked out together. It is the - responsibility of the Repository Administrators to set up a - modules file that describes the software within the Repository. - - - 3C.7 Can I move a checked-out directory? Does CVS remember where it - was checked out? - - Yes and Yes. - - The ./CVS/Repository file in each working directory contains a - pathname pointing to the matching directory within the - Repository. The pathname is either absolute or relative to - $CVSROOT, depending on how you configured CVS. - - When you move a checked-out directory, the CVS administrative - files will move along with it. As long as you don't move the - Repository itself, or alter your $CVSROOT variable, the moved - directory will continue to be usable. - - CVS remembers where you checked out the directory in the - "history" file, which can be edited, or even ignored if you - don't use the "working directory" information displayed by the - "history" command. - - - 3C.8 How can I lock files while I'm working on them the way RCS does? - - Until the day arrives of the all-powerful merge tool, there are - still files that must be accessed serially. For those instances, - here's a potential solution: - - 1. Install a pre-commit program in the "commitinfo" file to check - for RCS locks. The program "rcslock.pl" performs this - function. It can be found in the contrib directory of the CVS - source distribution. - - 2. When you want to make a change to a file you know can't be - merged, first use "cvs admin -l" to lock the file. If you - can't acquire the lock, use the standard "locked out" protocol: - go talk to the person holding the lock. - - 3. Make sure the pre-commit program prints a message and exits - with a non-zero status if someone besides the user running - "commit" has the file locked. This non-zero exist status will - cause the "commit" to fail cleanly. - - 4. Make sure the pre-commit program exits with a zero status if - the file is either unlocked or locked by the user running - "commit". The "cvs commit" command that kicked off the - pre-commit program will take a zero exist status as an OK and - checkin the file, which has the side-effect of unlocking it. - - - ===> The following is opinion and context. Don't read it if you - are looking for a quick fix. - - The topic of locking CVS files resurfaces on the network every so - often, producing the same results each time: - - The Big Endians: - - CVS was designed to avoid locks, using a copy-modify-merge - model. Locking is not necessary and you should take the time - to learn the CVS model which many people find workable. So why - not get with the program and learn how to think the CVS way? - - The Little Endians: - - The users determine how a tool is to be used, not the - designers. We, the users, have always used locking, our bosses - demand locking, locking is good, locking is God. I don't want - to hear any more lectures on the CVS model. Make locking work. - - Any organization making active changes to a source base will - eventually face the need to do parallel development. Parallel - development implies merges. (If you plan to keep separate copies - of everything and never merge, good luck. Tell me who you work - for so I can buy stock in your disk suppliers this year and sell - your stock short next year.) - - Merges will never go away. CVS chose to make "merges" stand - front and center as an important, common occurrence in - development. It is one way of looking at things. - - For free-format text, the merge paradigm gives you a considerable - amount of freedom. It does take a bit of management, but any - project should be ready to deal with it. - - On the other hand, there are many files that can't be merged using - text merge techniques. Straight text merge programs like "diff3" - are guaranteed to fail on executables (with relative branch - statements), files with self-referential counts stored in the file - (such as TAGS files), or files with relative motion statements in - them (such as Frame MIF files, many postscript files). They - aren't all binary files. - - For these types of files, and many others, there are only two - solutions: - - 1. Complex merge tools that are intimately aware of the contents - of the files to be merged. (ClearCase, and probably others, - allow you to define your own "files types" with associated - "merge tools".) - - 2. Serialization of access to the file. The only technical - solution to the problem of serialization is "locking". - - - Since you can call a program that offers: - - "Which one do you want? A/B?" - - a "merge tool", more and more merge tools will appear which can be - hooked into a merge-intensive program like CVS. Think of a bitmap - "merge" tool that displays the bitmaps on the screen and offers a - "paint" interface to allow you to cut and paste, overlay, invert - or fuse the two images such that the result is a "merged" file. - - My conclusion is that the need for locking is temporary, awaiting - better technology. For large development groups, locking is not - an alternative to merging for text files. - - - 3C.9 What is "checkout -s"? How is it different from "checkout -c"? - - The '-c' and '-s' options to "checkout" both cause the modules - file to appear on standard output, but formatted differently. - - "checkout -c" lists the modules file alphabetized by the module - name. It also prints all data (including options like '-a' and - "-o ") specified in the modules file. - - "checkout -s" lists the modules file sorted by "status" field, - then by module name. The status field was intended to allow you - to mark modules with strings of your choice to get a quick sorted - report based on the data you chose to put in the status fields. I - have used it for priority ("Showstopper", etc as tied into a bug - database), for porting status ("Ported", "Compiled", etc. when - porting a large collection of modules), for "assignee" (the person - responsible for maintenance), and for "test suite" (which - automatic test procedure to run for a particular module). - - ----------------- --- Section 3D -- "commit", "ci", "com" ----------------- - - **** Questions: - - 3D.1 What is "commit" for? - 3D.2 If I edit ten files, do I have to type "commit" ten times? - 3D.3 Explain: cvs commit: Up-to-date check failed for `' - 3D.4 What happens if two people try to "commit" conflicting changes? - 3D.5 I committed something and I don't like it. How do I remove it? - 3D.6 Explain: cvs commit: sticky tag `V3' for file `X' is not a branch - 3D.7 Why does "commit -r " put newly added files in the Attic? - 3D.8 Why would a "commit" of a newly added file not produce rev 1.1? - - - **** Answers: - - 3D.1 What is "commit" for? - - To store new revisions in the Repository, making them visible - to other users. - - - 3D.2 If I edit ten files, do I have to type "commit" ten times? - - No. The "commit" command will take multiple filenames, directory - names and relative pathnames on the command line and commit them - all with the same log message. If a file is unchanged, even if it - is explicitly listed on the command line, CVS will skip it. - - Like all CVS commands, "commit" will work on the whole directory - by default. Just type "cvs commit" to tell CVS to commit all - modified files (i.e. the files that "update" would display - preceded by 'M') in the current directory and in all - sub-directories. - - - 3D.3 Explain: cvs commit: Up-to-date check failed for `' - - You may not "commit" a file if your BASE revision (i.e. the - revision you last checked out, committed or retrieved via - "update") doesn't match the HEAD revision (i.e the latest revision - on your branch, usually the Main Branch). - - In other words, someone committed a revision since you last - executed "checkout", "update" or "commit". You must now execute - "update" to merge the other person's changes into your working - file before "commit" will work. You are thus protected (somewhat) - from a common form of race condition in source control systems, - where a checkin of a minor alteration of a second copy of the same - base file obliterates the changes made in the first. - - Normally, the "update" command's auto-merge should be followed - by another round of building and testing before the "commit". - - - 3D.4 What happens if two people try to "commit" conflicting changes? - - Conflicts can occur only when two developers check out the same - revision of the same file and make changes. The first developer - to commit the file has no chance of seeing the conflict. Only the - second developer runs into it, usually when faced with the - "Up-to-date" error explained in the previous question. - - There are two types of conflicts: - - 1. When two developers make changes to the same section of code, - the auto-merge caused by "update" will print a 'C' on your - terminal and leave "overlap" markers in the file. - - You are expected to examine and clean them up before committing - the file. (That may be obvious to *some* of you, but . . .) - - 2. A more difficult problem arises when two developers change - different sections of code, but make calls to, or somehow - depend on, the old version of each other's code. - - The auto-merge does the "right" thing, if you view the file - as a series of text lines. But as a program, the two - developers have created a problem for themselves. - - This is no different from making cross-referential changes in - *separate* files. CVS can't help you. In a perfect world, you - would each refer to the specification and resolve it - independently. In the real world you have to talk/argue, read - code, test and debug until the combined changes work again. - - Welcome to the world of parallel development. - - - 3D.5 I committed something and I don't like it. How do I remove it? - - Though you *can* use the "admin -o" (synonym: "rcs -o") command to - delete revisions, unless the file you committed is so embarrassing - that the need to eradicate it overrides the need to be careful, - you should just grab an old version of the file ("update -p -r - " might help here) and commit it on top of the - offending revision. - - See Section 3B on "admin". - - - 3D.6 Explain: cvs commit: sticky tag `V3' for file `X' is not a branch - - The message implies two things: - - 1. You created your working directory by using "checkout -r - V3", or you recently executed "update -r V3". - - 2. The tag named V3 is not a branch tag. - - - CVS records (i.e. makes "sticky") any "-r " argument - handed to the "checkout" or "update" commands. The is - recorded as the CVS working branch, which is the branch to which - "commit" will add a new revision. - - Branch tags are created when you use the -b switch on the "tag" or - "rtag" commands. Branch tags are magic tags that don't create a - physical branch, but merely mark the revision to branch from when - the branch is needed. The first commit to a magic branch creates - a physical branch in the RCS files. - - You can commit onto the end of the Main Trunk, if you have no - sticky tag at all, or onto the end of a branch, if you have a - sticky branch tag. But you can't commit a file that has a sticky - tag not pointing to a branch. CVS assumes a sticky Tag or - Revision that does not refer to a branch is attached to the middle - of a series of revisions. You can't squeeze a new revision - between two others. Sticky dates also block commits since they - never refer to a branch. - - - Scenario1: - - If you don't want a branch and were just looking at an old - revision, then you can move back to the Main Branch by typing: - - cvs update -A {files or dirs, default is '.'} - - or you can move to the branch named by: - - cvs update -r {files or dirs, default is '.'} - - - Scenario2: - - If you really wanted to be on a branch and made an earlier - mistake by tagging your branch point with a non-branch tag, - you can recover by adding a new branch tag to the old - non-branch tag: - - cvs rtag -b -r - - (It was not a big mistake. Branch-point tags can be useful. - But the must have a different name.) - - If you don't know the name or don't use "modules", - you can also use "tag" this way: - - cvs update -r - cvs tag -b . - - Then, to put your working directory onto the branch, you type: - - cvs update -r - - - You can't delete before adding , and I would - not advise deleting the at all, because it is useful - in referring to the branch point. If you must, you can delete - the non-branch tag by: - - cvs rtag -d - or - cvs tag -d . - - - Scenario3: - - If you made the same mistake as in Scenario2 (of placing a - non-branch tag where you wanted a branch tag), but really want - to be the name of your branch, you can execute a - slightly different series of commands to rename it and move - your working directory onto the branch. - - Warning: This is not a way to rename a branch tag. It is a way - to turn a non-branch tag into a branch tag with the - same name. - - cvs rtag -r - cvs rtag -d - cvs rtag -b -r - - Then, if you really must, delete the : - - cvs rtag -d - - - - Note: The unwieldy mixture of "tag" and "rtag" is mostly - because you can't specify a revision (-r ) to the - "tag" command. - - See 4C.3 for more info on creating a branch. - - - 3D.7 Why does "commit -r " put newly added files in the Attic? - - If you specify "-r " (where is a dotted numeric number - like 2.4), it correctly sets the initial revision to , but it - also attaches the numeric as a sticky tag and throws the - file into the Attic. This is a bug. The obvious solution is to - move the file out of the Attic into the associated Repository - directory and "update -A" the file. There are no Tags to clean up. - - If you specify "-r " to commit a newly added file, the - is treated like a , which becomes a symbolic RCS label - pointing to the string '1', which can be considered to be the - "Main branch number" when the main branch is still at revision - 1.N. The file is also thrown into the Attic. See 4C.8 for a way - to recover from this. - - In fact, a plain "commit" without the "-r" will throw a newly - added file into the Attic if you added it to a directory checked - out on a branch. See 3A.[2-5]. - - See Section 4C, on Branching, for many more details. - - - 3D.8 Why would a "commit" of a newly added file not produce rev 1.1? - - When committing a newly added file CVS looks for the highest main - branch major number in all files in the ./CVS/Entries file. - Normally it is '1', but if you have a file of revision 3.27 in - your directory, CVS will find the '3' and create revision 3.1 for - the first rev of . Normally, the first revision is 1.1. - - ----------------- --- Section 3E -- "diff", "di", "dif" ----------------- - - **** Questions: - - 3E.1 What is "diff" for? - 3E.2 Why did "diff" display nothing when I know there are later - committed revisions in the Repository? - 3E.3 How do I display what changed in the Repository since I last - executed "checkout", "update" or "commit"? - 3E.4 How do I display the difference between my working file and what - I checked in last Thursday? - 3E.5 Why can't I pass long options, like --unified, to "diff"? - - - **** Answers: - - 3E.1 What is "diff" for? - - 1. To display the difference between a working file and its BASE - revision (the revision last checked out, updated or committed): - - cvs diff - - 2. To display the difference between a working file and a - committed revision of the same file: - - cvs diff -r - - 3. To display the difference between two committed revisions of - the same file: - - cvs diff -r -r - - You can specify any number of arguments. Without any - arguments, it compares the whole directory. - - In the examples above, "-D " may be substituted wherever - "-r " appears. The revision a refers to is the - revision that existed on that date. - - - 3E.2 Why did "diff" display nothing when I know there are later - committed revisions in the Repository? - - By default, "diff" displays the difference between your working - file and the BASE revision. If you haven't made any changes to - the file since your last "checkout", "update" or "commit" there is - no difference to display. - - To display the difference between your working file and the latest - revision committed to your current branch, type: - - cvs diff -r HEAD - - - 3E.3 How do I display what changed in the Repository since I last - executed "checkout", "update" or "commit"? - - A special tag (interpreted by CVS -- it does not appear in the Tag - list) named "BASE" always refers to the revision you last checked - out, updated or committed. Another special tag named "HEAD" - always refers to the latest revision on your working branch. - - To compare BASE and HEAD, you type: - - cvs diff -r BASE -r HEAD - - - 3E.4 How do I display the difference between my working file and what - I checked in last Thursday? - - cvs diff -D "last Thursday" - - where "last Thursday" is a date string. To be more precise, the - argument to the '-D' option is a timestamp. Many formats are - accepted. See the man page under "-D date_spec" for details. - - - 3E.5 Why can't I pass long options, like --unified, to "diff"? - - CVS only handles single character '-X' arguments, not the FSF long - options. CVS also passes through only arguments it knows about, - because a few arguments are captured and interpreted by CVS. - - If you didn't configure RCS and CVS to use the GNU version of - diff, long options wouldn't work even if future versions of CVS - acquire the ability to pass them through. - - Most of the long options have equivalent single-character options, - which do work. The "--unified" option is equivalent to '-u' in - revisions of GNU diff since 1.15. - - - ----------------- --- Section 3F -- "export", "exp", "ex" ----------------- - - **** Questions: - - 3F.1 What is "export" for? - 3F.2 Why does it remove the RCS keywords so I can't use the "ident" - command on the source files? - 3F.3 Can I override the '-kv' flag CVS passes to RCS? - 3F.4 Why doesn't "export" have a '-k' flag like "import" does? - 3F.5 Why does "export -D" check out every file in the Attic? - - - **** Answers: - - 3F.1 What is "export" for? - - "export" checks out a copy of a module in a form intended for - export outside the CVS environment. The "export" command produces - the same directory and file structure as the "checkout" command, - but it doesn't create "CVS" sub-directories and it removes all the - RCS keywords from the files. - - - 3F.2 Why does it remove the RCS keywords so I can't use the "ident" - command on the source files? - - It removes the RCS keywords, so that if the recipient of the - exported sources checks them into another set of RCS files (with - or without CVS), and then makes modifications through RCS or CVS - commands, the revision numbers that they had when you exported - them will be preserved. (That ident no longer works is just an - unfortunate side effect.) - - The theory is that you are exporting the sources to someone else - who will make independent changes, and at some point you or they - will want to know what revisions from your Repository they started - with (probably to merge changes, or to try to decide whether to - merge changes). - - A better way to handle this situation would be to give them their - own branch of your Repository. They would need to remember to - checkin the exported sources with RCS IDs intact (ci -k) so that - their changes would get revision numbers from the branch, rather - than starting at 1.1 again. Perhaps a future version of CVS will - provide a way to export sources this way. - - Contributed by Dan Franklin - - - 3F.3 Can I override the '-kv' flag CVS passes to RCS? - - Not as of CVS version 1.4. - - - 3F.4 Why doesn't "export" have a '-k' flag like "import" does? - - Export is intended for a specific purpose -- to remove all trace - of revision control on the way *out* of CVS. - - - 3F.5 Why does "export -D" check out every file in the Attic? - - See 5B.3 for an explanation of the same problem with "update". - - - ----------------- --- Section 3G -- "history", "hi", "his" ----------------- - - **** Questions: - - 3G.1 What is "history" for? - 3G.2 Of what use is it? - 3G.3 What is this, Big Brother? - 3G.4 I deleted my working directory and "history" still says I have - it checked out. How do I fix it? - 3G.5 So I *can* edit the History file? - 3G.6 Why does the history file grow so quickly? - 3G.7 What is the difference between "cvs history -r " and - "cvs history -t "? - 3G.8 Why does "cvs history -c -t " fail to print anything? - 3G.9 "cvs history -a -o" only printed one line for each checked-out - module. Shouldn't it print all the directories where the - modules are checked out? - 3G.10 I can't figure out "history", can you give me concrete examples? - 3G.11 Can we merge history files when we merge Repositories? - - - **** Answers: - - 3G.1 What is "history" for? - - To provide information difficult or impossible to extract out of - the RCS files, such as a "tag" history or a summary of module - activities. - - - 3G.2 Of what use is it? - - I have found it useful in a number of ways, including: - - 1. Providing a list of files changed since - - - A tagged release. - - Yesterday, last Thursday, or a specific date. - - Someone changed a specific file. - - 2. Providing a list of special events: - - - Files added or removed since one of the above events. - - Merge failures since one of the above events. (Where did the - conflicts occur?) - - Has anyone (and who) grabbed the revision of this file I - committed last week, or are they still working blind? - - 3. Telling me how often a file/directory/module has been changed. - - 4. Dumping a summary of work done on a particular module, - including who last worked on it and what changed. - - 5. Displaying the checked-out modules and where they are being - worked on. - - 6. To tell me what users "joe" and "malcolm" have done this week. - - - 3G.3 What is this, Big Brother? - - War is Peace. - Freedom is Slavery. - Ignorance is Strength. - - Normally manager types and those with the power to play Big - Brother don't care about this information. The Software Engineer - responsible for integration usually wants to know who is working - on what and what changed. Use your imagination. - - - 3G.4 I deleted my working directory and "history" still says I have - it checked out. How do I fix it? - - You can use "release -f" to forcibly add a "release" record to the - history file for a working directory associated with a "module". - If your version of "release" doesn't have the '-f' option, or you - checked out the directory using a relative path, you have to edit - the $CVSROOT/CVSROOT/history file. - - You can remove the last 'O' line in the history file referring - to the module in question or add an 'F' record. - - - 3G.5 So I *can* edit the History file? - - Yes, but if you are using history at all, you should take a little - care not to lose information. I normally use Emacs on the file, - since it can detect that a file has changed out from under it. - You could also copy and zero out the history file, edit the copy - and append any new records to the edited copy before replacing it. - - - 3G.6 Why does the history file grow so quickly? - - It stores 'U' records, which come in handy sometimes when you - are tracking whether people have updated each other's code - before testing. There should (and probably will sometime) be a - way to choose what kinds of events go into the history file. - - The contributed "cln_hist.pl" script will remove all the 'U' - records, plus matching pairs of 'O' and 'F' records during - your normal clean up of the history file. - - - 3G.7 What is the difference between "cvs history -r " and - "cvs history -t "? - - The '-t' option looks for a Tag record stored by "rtag" in the - history file and limits the search to dates after the last - of the given name was added. - - The '-r' option was intended to search all files looking for the - in the RCS files. It takes forever and needs to be - rewritten. - - - 3G.8 Why does "cvs history -c -t " fail to print anything? - - You have been using "tag" instead of "rtag". The "tag" command - currently doesn't store a history record. This is another remnant - of CVS's earlier firm belief in "modules". But it also has a - basis in how "rtag" and "tag" were originally used. - - "rtag" was intended for large-scale tagging of large chunks of the - Repository, an event work recording. "tag" was intended for - adding and updating tags on a few files or directories, though it - could also be used to tag the entire checked-out working tree when - there is no module defined to match the tree or when the working - tree is the only place where the right collection of revisions to - tag can be found. - - - 3G.9 "cvs history -a -o" only printed one line for each checked-out - module. Shouldn't it print all the directories where the - modules are checked out? - - Not as designed. - - Command Question it is supposed to answer. - ---------------- ------------------------------------------ - cvs history -o What modules do I have checked out? - cvs history -a -o - - cvs history -o -w What working directories have I created - and what modules are in them? - cvs history -a -o -w - - The -o option chooses the "checked out modules" report, which is - the default history report. - - - 3G.10 I can't figure out "history", can you give me concrete examples? - - Default output selects records only for the user who executes the - "history" command. To see records for other users, add one or - more "-u user" options or the '-a' option to select *all* users. - - To list (for the selected users): Type "cvs history" and: - - * Checked out modules: -o (the default) - * Files added since creation: -x A - * Modified files since creation: -c - * Modified files since last Friday: -c -D 'last Friday' - * Modified files since TAG was added: -c -t - * Modified files since TAG on files: -c -r - * Last modifier of file/Repository X? -c -l -[fp] X - * Modified files since string "str": -c -b str - * Tag history: (Actually "rtag".) -T - * History of file/Repository/module X: -[fpn] X - * Module report on "module": -m module - - - 3G.11 Can we merge history files when we merge Repositories? - - Assuming that the two Repositories have different sets of - pathnames, it should be possible to merge two history files by - sorting them together by the timestamp fields. - - You should be able to run: - - sort +0.1 ${dir1}/history ${dir2}/history > history - - - If you "diff" a standard history file before and after such a - sort, you might see other differences caused by garbage (split - lines, nulls, etc) in the file. If your Repository is mounted - through NFS onto multiple machines you will also see a few - differences caused by different clocks on different machines. - (Especially if you don't use NTP to keep the clocks in sync.) - - - ----------------- --- Section 3H -- "import", "im", "imp" ----------------- - - **** Questions: - - 3H.1 What is "import" for? - 3H.2 How am I supposed to use "import"? - 3H.3 Why does import put files on a branch? Why can't I work on the - main trunk instead of a Vendor branch? - 3H.4 Is there any way to import binary files? - 3H.5 Why does "import" corrupt some binary files? - 3H.6 How do I retain the original $\Revision$ strings in the sources? -=3H.7 I imported some files for the Yarg compiler that compiles files - with a suffix of ".yarg" and whose comment prefix is "YARG> ". - When I check them out, they will no longer compile because they - have this junk in them. Why? - 3H.8 How do I make "import" save the timestamps on the original files? - 3H.9 Why can't I "import" 3 releases on different branches? - 3H.10 What do I do if the Vendor adds or deletes files between releases? - 3H.11 What about if the Vendor changes the names of files or - directories, or rearranges the whole structure between releases? - 3H.12 I thought "import" was for Vendor releases, why would I use it - for code of my own? Do I have to use import? - 3H.13 How do I import a large Vendor release? - 3H.14 Explain: ERROR: cannot create link to : Permission denied - 3H.15 Where does the -m go when the file doesn't change? - 3H.16 How do I "import" just the files ignored by a previous "import"? - 3H.17 Why did "import" ignore all the symlinks? - - - **** Answers: - - 3H.1 What is "import" for? - - The "import" command is a fast way to insert a whole tree of files - into CVS. - - The first "import" to a particular file within the Repository - creates an RCS file with a single revision on the "Vendor branch." - Subsequent "import"s of the same file within the Repository append - a new revision onto the Vendor branch. It does not, as some seem - to believe, create a new branch for each "import". All "imports" - are appended to the single Vendor branch. - - If the file hasn't changed, no new revision is created -- the new - "Release-Tag" is added to the previous revision. - - After the import is finished, files you have not changed locally - are considered to have changed in the "Main line of development". - Files you *have* changed locally must have the new Vendor code - merged into them before they are visible on the "Main line". - - See 4C.6 and 4C.15 - - - 3H.2 How am I supposed to use "import"? - - Create a source directory containing only the files you want to - import. Make sure you clean up any cruft left over from previous - builds or editing. You want to make sure that the directory - contains only what you want to call "source" from which everything - else is built. - - If this is not the first import from this "Vendor", you should - also compare the output of "find . ! -name CVS -print | sort" - executed both at the head of a checked out working directory and - at the head of the sources to be imported. If you find any - deleted or renamed files, you have to deal with them by hand. - (See 4B.8 on renaming.) - - "cd" into your source directory and type: - - cvs import -m "Message" - - where is the relative directory pathname within the - Repository that corresponds to the sources you are importing. - - You might also consider using the "-I !" option to avoid ignoring - anything. It is easier to remove bogus files from the Repository - than to create a sparse tree of the ignored files and rerun - "import". - - For example, if the FSF, CVS, Make and I are still active in the - year 2015, I'll import version 89.53 of GNU make this way: - - cvs import -m "GNUmake V89.53" gnu/make GNU GNUMAKE_89_53 - - See 3H.13 for more details. - - - 3H.3 Why does import put files on a branch? Why can't I work on the - main trunk instead of a Vendor branch? - - This was a Design choice. The Vendor branch is the way "import" - deals with a Vendor release. It is a solution to the Engineering - problem of how to merge multiple external releases of - Vendor-supplied sources into your ongoing work. The Vendor - releases are kept on a separate, special, "Vendor" branch and your - work is kept on the RCS trunk. New Vendor releases are imported - onto the Vendor branch and then merged into your work, if there is - any, on the trunk. - - This way, you can use CVS to find out not only about your work, - but you can also find out what the Vendor changed by diffing - between two of the Release Tags you handed to "import". - - CVS was designed to work this way. If you use CVS in some other - way, you should think carefully about what you are doing. - - Note that the CVS "Main Branch" and the RCS Main Trunk are not the - same. Placing files on the Vendor Branch doesn't keep you from - creating a development branch to work on. - - See Section 4C, on Branching. - - - If you are not working with 3rd party (i.e. Vendor) sources, you - can skip the "import" and avoid the Vendor branch entirely. It - works just as well to move pre-existing RCS files into Repository - directories. - - You can create a whole Repository tree by copying a directory - hierarchy of normal source files directly into the Repository and - applying CVS to it. Here's an idea you should *test* before using: - - cd - set source = `pwd` - set module = xyzzy <<== Your choice of directory name - mkdir $CVSROOT/$module - cd $CVSROOT/$module - (cd $source; tar cf - .) | tar xvpBf - - find . -type f -exec ci -t-Original. {} \; - - The RCS "ci" command, without -u or -l options, will turn your - source file into an RCS (",v") and delete the original source. - - - 3H.4 Is there any way to import binary files? - - If you configured CVS to use the GNU version of "diff" and - "diff3", then you can import any kind of file. - - Binary files with RCS keywords in them are a problem, since you - don't want them to expand. - - If the tree you are about to "import" is entirely filled with - binary files, you can use the '-ko' option on "import". - Otherwise, I would run the import normally, then fix the binary - files as described below in 3H.5. - - See 4D.1 on Binary files. - - - 3H.5 Why does "import" corrupt some binary files? - - The RCS "co" command, when it is invoked by a CVS "checkout" or - "update" (or after a "commit") command, searches for and expands a - list of keywords within the file. They are documented in the RCS - "co" man page. Strings such as "$\Id$" (or "$\Id:"), or - "$\Revision$" (or "$\Revision:") are altered to the include the - indicated information. - - [[Note: The keywords should appear in the text without the '\' - character I have inserted to *avoid* expansion here. The only - real RCS keywords in this document are at the top of the file, - where I store the Revision and Date.]] - - If RCS keyword strings show up in a binary file, they will be - altered unless you set the '-ko' option on the RCS files to tell - RCS to keep the original keyword values and not to expand new - ones. After "import", you can set the '-ko' option this way: - - cvs admin -ko - rm - cvs update - - After an import that didn't use '-ko' (because the whole tree - wasn't of binary files) you should fix up the binary files as - described above before checking out any new copies of the files - and before updating any working directories you checked out - earlier. - - See 4D.1 on Binary files. - - - 3H.6 How do I retain the original $\Revision$ strings in the sources? - - If you want to leave old RCS keywords as they are, you can use the - '-ko' tricks described above. - - -=3H.7 I imported some files for the Yarg compiler that compiles files - with a suffix of ".yarg" and whose comment prefix is "YARG> ". - When I check them out, they will no longer compile because they - have this junk in them. Why? - - YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG> - YARG> $\Log: - # Revision 1.3 1998/03/03 00:16:16 bubba - # What is 2+2 anyway? - # - # Revision 1.2 1998/03/03 00:15:15 bubba - # Added scorekeeping. - YARG> - YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG>YARG> - - - Well bubba, "Yarg" hasn't hit the big time yet. Neither RCS nor - CVS know about your suffix or your comment prefix. So you have - two choices: - - 1. Check out the Yarg-less module, and tell all the files about - your comment prefix. Visit each directory and type: - - cvs admin -c"YARG> " *.yarg - - If *all* files in the whole directory tree are Yarg files, - you can use this instead: - - cvs admin -c"YARG> " . - - Then save any changes you made, remove all the "*.yarg" files - and grab new copies from the Repository: - - rm *.yarg - (or: find . -name '*.yarg' -exec rm {} ';') - (or: find . -name '*.yarg' -print | xargs rm) - (or: find . -name '*.yarg' -print0 | xargs -0 rm - if you have spaces in filenames and the GNU find/xargs.) - cvs update - - It might be faster to remove the whole directory and check it - out again. - - 2. Change the import.c file in the CVS sources and add the .yarg - suffix, along with the "YARG> " comment prefix to the - "comtable" array. - - If you ever plan to add new files with $\Log in them, you - should also go into the RCS sources and make the same change in - the table contained in the "rcsfnms.c" file. - - Then delete the imported files from the Repository and - re-"import" the sources. - - - 3H.8 How do I make "import" save the timestamps on the original files? - - Use "import -d" to save the current timestamps on the files as the - RCS revision times. - - See 4D.8 for another aspect of file timestamps. - - - 3H.9 Why can't I "import" 3 releases on different branches? - - I'll bet you typed something like this: - - cd /src/blasto.v2 - cvs import -b 1.1.2 VENDOR2 Version2 - cd /src/blasto.v3 - cvs import -b 1.1.3 VENDOR3 Version3 - cd /src/blasto.v4 - cvs import -b 1.1.4 VENDOR4 Version4 - - This is wrong, or at least it won't help you much. You have - created three separate Vendor branches, which is probably not - what you wanted. - - Earlier versions of CVS, as described in Brian Berliner's Usenix - paper, tried to support multiple Vendor branches on the theory - that you might receive source for the *same* program from multiple - vendors. It turns out that this is very rare, whereas the need to - branch in *your* development, for releases and for project - branches, is much greater. - - So the model now is to use a single vendor branch to contain a - series of releases from the same vendor. Your work moves along - on the Main Trunk, or on a CVS branch to support a real - "branch in development". - - To set this up, you should type this instead of the above: - - cd /src/blasto.v2 - cvs import VENDOR Version2 - cd /src/blasto.v3 - cvs import VENDOR Version3 - cd /src/blasto.v4 - cvs import VENDOR Version4 - - - 3H.10 What do I do if the Vendor adds or deletes files between releases? - - Added files show up with no extra effort. To handle "removed" - files, you should always compare the tree structure of the new - release against the one you have in your Repository. If the - Vendor has removed files since the previous release, go into a - working directory containing your current version of the sources - and "cvs remove" (followed by "cvs commit" to make it really take - effect) each file that is no longer in the latest release. - - Using this scheme will allow you to "checkout" any version of - the vendor's code, with the correct revisions and files, by - using "checkout -r Version[234]". - - Renames are harder to find, since you have to compare file - contents to determine that one has occurred. If you notice one, - see 4B.8 on renaming files. - - - 3H.11 What about if the Vendor changes the names of files or - directories, or rearranges the whole structure between releases? - - Currently CVS can't handle this cleanly. It requires - "renaming" a bunch of files or directories. - - See 4B.8 on "renaming" for more details. - - What I generally do is to close the Repository for a while and - make changes in both the Repository and in a copy of the vendor - release until the structure matches, then execute the import. - - If you ever have to check out and build an old version, you may - have to use the new, or completely different Makefiles. - - - 3H.12 I thought "import" was for Vendor releases, why would I use it - for code of my own? Do I have to use import? - - For code you produce yourself, "import" is a convenience for fast - insertion of whole trees. It is not necessary. You can just as - easily create ",v" files using the RCS "ci" command and move - them directly into the Repository. - - Other than the CVSROOT directory, the Repository consists entirely - of directories of ",v" files. The Repository contains no other - state information. - - See Section 4B, on Setting up and Managing the Repository. - - - 3H.13 How do I import a large Vendor release? - - When the sum of the changes made by the Vendor and the changes - made by local developers is small, "import" is not a big - problem. But when you are managing a large Repository, any care - taken up front will save you time later. - - First read the following, then, before executing "import", see the - questions in Section 4C dealing with branch merges and Vendor - branch merges. - - 0. If this is not the first import of this code, before starting, - rtag the whole directory you will be changing. - - 1. The first step is to make sure the structure of the new files - matches the structure of the current Repository. - - Run "find . -print | sort" on both trees and "diff" the output. - - 2. Alter the "source" tree until the "diff" (of the list of - filenames, not of the whole trees) shows that the directory - structures are equivalent. - - The "comm" command, if you have it, can help figure out what - has been added or deleted between releases. - - 3. If they deleted any files, you can handle them cleanly with - "cvs remove". The command "comm -23 files.old files.new" will - show you a list of files that need to be removed. - - You should examine the list first to see if any have been - renamed rather than simply deleted. - - 4. If they renamed any files, see 4B.8 on renaming files. - - 5. Remember to *SAVE* the output from the import command. - - 6. When you have dealt with removed and renamed files, then you - can execute the import: - - cd - cvs import -I ! -m "Message" - - - Where - - "-I !" is an optional argument that keeps "import" from - ignoring files. The comparison of the "find" - commands above will probably avoid the need for - this, but it is easier to remove files from the - Repository than to run a subset "import" to catch - just the ignored files. - [You might have to quote or backwhack the '!'.] - - Message is the log message to be stored in the RCS files. - - is a relative path to a directory within the - Repository. The directory must be at - the same relative level within the new sources as - the you give is within the Repository. (I - realize this is not obvious. Experiment first.) - - is a Tag used to identify the Vendor who sent you - the files you are importing. All "imports" into - the same *must* use the same VendorTag. - You can find it later by using the "log" command. - - is a Tag used to identify the particular release - of the software you are importing. It must be - unique and should be mnemonic -- at least include - the revision number in it. (Note: you can't use - '.' characters in a Tag. Substitute '_' or '-'.) - - 7. There will be six categories of files to deal with. - (Actually there are eight, but you have already dealt with - "removed" and "renamed" files.) - - If this is the first "import" into a given directory, - only the first three of these ('I', 'L' and 'N') can occur. - - - a. Ignored file. - - CVS prints: I filename - - You'll need to examine it to see if it *should* have been - ignored. If you use "-I !", nothing will be ignored. - - - b. Symbolic link. - - CVS prints: L linkname - - Links are "ignored", but you'll probably want to create - a "checkout helper" function to regenerate them. - - - c. New file. - - CVS prints: N filename - - CVS creates a new file in the Repository. You don't - have to do anything to the file, but you might have to - change Makefiles to refer to it if this is really a new - file. - - - d. A file unchanged by the Vendor since its last release. - - CVS prints: U filename - - CVS will notice this and simply add the new ReleaseTag - to the latest rev on the Vendor branch. - - No work will be needed by you, whether you have changed - the file or not. No one will notice anything. - - e. A file changed by the Vendor, but not by you. - - CVS prints: U filename - - CVS should add the file onto the vendor branch and - attach the Release Tag to it. - - When you next execute "update" in any working directory - you'll get the new revision. - - - f. A file changed by both the Vendor and by you. - - CVS prints: C filename - - These are the trouble files. For each of these files - (or in groups -- I usually do one directory at a - time), you must execute: - - cvs update -j -j - or - cvs update -j -j - - It will print either 'M' (if no overlaps) or 'C', if - overlaps. If a 'C' shows up, you'll need to edit the - file by hand. - - Then, for every file, you'll need to execute "cvs commit". - - See the part of Section 4C dealing with branch merges. - - - 8. If you are truly performing a large import, you will most - likely need help. Managing those people is another problem - area. - - Since the merge of the Vendor branch is just like any other - merge, you should read section 4C for more info about - performing and cleaning up merges. - - The larger the import, and the larger the group of people - involved, the more often you should use "tag" and "rtag" to - record even trivial milestones. See 4C.14, especially the - "paranoid" section. - - Before starting the import, you should install and test a - "commitinfo" procedure to record all commits in a file or via - Email to a mail archive. Along with the tags you placed on the - Repository before the import, this archive will help to track - what was changed, if problems occur - - There are four stages to the recovery: - - A. Parcel out the work -- Effective Emacs Engineering. - - As input to the assignment process, you might want to - examine the tree and record the last person who changed the - file. You can also research, if you don't already know, who - is expert in each area of the software. - - Examine the import log (you saved the output, right?), - estimate how much work is involved in each area and assign - groups of files to individual developers. Unless some - directory is immense, it is easier to manage if you assign - whole directories to one person. - - Keep a list. Suggest a completion date/time. Tell them to - "commit" the file when they are finished with the merge. - If you tagged the Repository before starting the import, you - should have no trouble figuring out what happened. - - If you can, find out (or tell them) which working directory - to use. You should verify that the working directory they - use is on the Main Branch ("update -A") and without modified - files. - - If you trust your crew, have them notify you by Email. Have - them send you the output from "cvs update" in their working - directory. You might have to poll some people until you are - certain they have finished, or have given up. (This is not - an invention. I've heard a false, "Yeah, sure. I finished - yesterday," more times that you'd believe.) - - When all reports are in, go on to the Source Verification - stage. - - B. Source Verification -- CVS and other Tools. - - If you didn't dictate which ones to use, find all working - directories and run "cvs -n update" in all of them. The - history command and the "commitinfo" log you set up might - help to find checked out working directories. - - Sticky conflict flags will help, but they can't recover from - sloppiness or incompetence. You might want to check - everything out into a tree and grep for the parts of the - merge conflict markers CVS doesn't look for. CVS looks for - the string '^>>>>>>> '. The merge operation also puts - '^<<<<<<< ' and '^======= ' markers in the file that - careless developers might leave there. - - If you find problems simply by looking at the source files - and working directories, start the flogging now. Resolving - the textual conflicts is the easy part. Weed the turkeys - out before reaching the next part of the cleanup -- the - resolution of logical conflicts. - - Then apply a set of post-commit tags. - - C. Logical Verification -- Diff and powerful eyeballs. - - No source control system can solve the problem of resolving - distributed conflicts in program logic. If you change the - argument template for function A (defined in file A.c) and - add new calls to function A from within function B (defined - in file B.c) using the old argument format, you are outside - the realm of CVS's competence. - - Assign someone to understand what the Vendor changed by - running "cvs diff -c -r ", - where the tags were those handed to the last two invocations - of "import". - - Then have the same person compare that output (logically or - you can actually diff the diffs) to the output of the - similar "cvs diff -c -r ". - The two sets of differences should be almost identical. - They should both show only the work *you* have performed. - - D. Product Verification -- Build and Test. - - Don't let your help off the hook until you verify that the - merge actually produced something that can compile and pass - tests. Compiling should really be part of the logical - verification phase, but you should test the output of the - build system before declaring victory and releasing the - troops. - - - 9. After it is all built, apply another set of tags to mark the - end of the "import process". You can delete the intermediate - tags you added during source and logic testing, but keep the - "pre-import" and "post-import" tags forever. - - - Of course, experience can tell you when to skip a step. But I'd - start out by considering each one as necessary unless you can - prove otherwise. - - - - 3H.14 Explain: ERROR: cannot create link to : Permission denied - - This error appears when you try to execute a second (or later) - "import" into the same module from a directory to which you don't - have write access. - - The "link error" is caused by a feature purposely added to - speed up the import. - - Though the error message is somewhat strange, it indicates that - "import" is supposed to be executed only in writable directories. - - - 3H.15 Where does the -m go when the file doesn't change? - - The handed to import is used as an RCS log message, but - only if the imported file changed since the last version on the - Vendor branch. If the imported file hasn't changed, then no new - revision is created. The is still applied, but to - the previous revision. So the Tags are still correct, but the - message is lost. - - Maybe it should be appended to the previous log message. But - currently it isn't. - - - 3H.16 How do I "import" just the files ignored by a previous "import"? - - A real answer follows, but first, an editorial: - - I am now convinced that you should always use the "-I !" - option. Removing a few extraneous files from the Repository - is a lot easier than the recovery step described below. - - - Let's assume your original import procedure was: - (We assume there is enough disk space in /tmp.) - - cd - cvs import -m 'xyz 1.3' gnu/xyz GNU GNUXYZ_1_3 | tee /tmp/IMP - - To import just the files ignored by "import", I would do this: - - 1. Create a list of the ignored files to import: - - cd - awk '/^I / {print $2}' /tmp/IMP | sed 's|^gnu/xyz/||' > /tmp/IG - [Edit the IG file to contain just the files you want.] - - 2. Then create a sparse directory by handing your list to the GNU - version of "tar", installed in many places as "gtar": - - mkdir /tmp/FIXUP - gtar -T /tmp/IG -c -f - . | (cd /tmp/FIXUP; gtar xvBf -) - - 3. Then rerun the import. Use the exact same command, but execute - it in the sparse directory tree you just created. And this - time, tell it not to ignore anything. - - cd /tmp/FIXUP - cvs import -I ! -m 'xyz 1.3' gnu/xyz GNU GNUXYZ_1_3 - - - 3H.17 Why did "import" ignore all the symlinks? - - This is another design choice. - - Like the Unix "tar" command, "import" could sprout an option to - follow symbolic links, but I don't think CVS will ever follow - symbolic links by default. - - Two possible future enhancements have been seriously discussed: - - 1. Treat symbolic links as data in its parent directory (the way - ClearCase does) in some sort of per-directory control file. - - 2. Treat symbolic links as version-controlled elements themselves, - whose data is the value of readlink(2). - - For now, they are simply ignored. - - If you want to save and reconstruct symlinks, you might want to - define a "checkout" or "update" program in the modules file which - could consult a file kept under CVS in your working directory and - make sure the specified links are in place. - - - ----------------- --- Section 3I -- "log", "lo", "rlog" ----------------- - - **** Questions: - - 3I.1 What is "log" for? - 3I.2 How do I extract the log entries between two revisions? - 3I.3 How do I extract the log entries on a whole branch? - 3I.4 How do I generate ChangeLogs from RCS logs? - 3I.5 Why does "log" tell me a file was committed exactly 5 hours later - than I know it was? - - - **** Answers: - - 3I.1 What is "log" for? - - To provide an interface to the RCS "rlog" command, which displays - information about the underlying RCS files, including the revision - history and Tag (RCS calls it a "symbol") list. - - - 3I.2 How do I extract the log entries between two revisions? - - If both and are on the same branch, you can get - what you are looking for with: (If they aren't on the same branch - you'll either get an error or a display of the whole change log.) - - cvs log -r: - - If you want all the revisions on the branch from to the end - of the branch is on, you can use: - - cvs log -r: - - (If is a numeric RCS symbol attached to a branch revision - with an even number of '.'s in it, you get the whole branch.) - - If you want all the revisions on the branch from the beginning of - the branch is on up to revision , you can use: - - cvs log -r: - - - Note: Depending on whether and are: - - - numeric or symbolic - - in the file or not - - on the same branch or not - - the RCS "rlog" (and therefore the "cvs log") command will - display some combination of: - - - error messages - - (intuitively correct) partial log listings - - a display of the entire change log. - - - 3I.3 How do I extract the log entries on a whole branch? - - cvs log -r - - where must be a branch revision (one with an even number - of dots) or a *non-branch* tag on a branch revision. Non-branch - tags on a branch revision are not normally attached by CVS, to add - one you will have to explicitly tag a physical branch number - within each file. Since these branch numbers are almost never the - same in different files, this command is not all that useful. - - The intuitive command (at least from the CVS perspective): - - cvs log -r - - does not work. - - - 3I.4 How do I generate ChangeLogs from RCS logs? - - A program called rcs2log is distributed as part of GNU Emacs 19. - A (possibly older) version of this program appears in the contrib - directory of the cvs source tree. - - - 3I.5 Why does "log" tell me a file was committed exactly 5 hours later - than I know it was? - - I can tell by this question that you were working in a time zone - that is 5 hours behind GMT (e.g. the U.S. East Coast in winter). - - RCS file dates are stored in GMT to allow users in different time - zones to agree on the meaning of a timestamp. At first glance - this doesn't seem necessary, but many companies use distributed - file systems, such as NFS or AFS, across multiple timezones. - - Some standard form must be used. GMT, as the "grid origin", is an - obvious candidate. The only other reasonable choice is to put the - timezone information in all the time stamps, but that changes the - RCS file format incompatibly, a step which has been avoided in the - last few RCS releases. - - ----------------- --- Section 3J -- "patch", "pa", "rdiff" ----------------- - - **** Questions: - - 3J.1 What is "patch" for? - 3J.2 Why does "patch" include files from the Attic when I use '-D'? - 3J.3 How do I make "patch" produce a patch for one or two files? - It seems to work only with modules. - - - **** Answers: - - 3J.1 What is "patch" for? - - To produce a "diff" between tagged releases to be handed to the - "patch" command at other sites. This is the standard way that - source patches are distributed on the network. - - - 3J.2 Why does "patch" include files from the Attic when I use '-D'? - - See the explanation of the same problem with "update -D" - contained in section 5B. - - - 3J.3 How do I make "patch" produce a patch for one or two files? - It seems to work only with modules. - - Patch is intended for producing patches of whole modules between - releases to be distributed to remote sites. Instead of "patch", - you can use the "diff" command with the '-c' context option: - - cvs diff -c -r -r . . . - - The patch command will be able to merge such a "diff" into the - remote source files. - - If you configured CVS to use a version of "diff" that supports the - '-u' option, you can produce a more compact "patch" in "unidiff" - format. The latest revisions of the patch command can parse and - apply patches in "unidiff" format. - - - ----------------- --- Section 3K -- "release", "re", "rel" ----------------- - - - **** Questions: - - 3K.1 What is "release" for? - 3K.2 Why can't I reverse a "cvs checkout path/name/subdir" with a - "cvs release path/name/subdir" without an "unknown module name"? - 3K.3 Why can't I "release" portions of a checked out directory? I - should be able to "release" any file or sub-directory within - my working directory. - 3K.4 I removed the tree that I was about to start working on. How do I - tell cvs that I want to release it if I don't have it anymore? - 3K.5 Why doesn't "release -d module" reverse a "checkout module"? - 3K.6 Why can't I release a module renamed with "cvs checkout -d"? - - - **** Answers: - - 3K.1 What is "release" for? - - To register that a module is no longer in use. It is intended - to reverse the effects of a "checkout" by adding a record to - the history file to balance the checkout record and by - optionally allowing you to delete the checked-out directory - associated with the module name. - - - 3K.2 Why can't I reverse a "cvs checkout path/name/subdir" with a - "cvs release path/name/subdir" without an "unknown module name"? - - A simplistic implementation. (I can say this -- I wrote it.) - - The "release" function was written for CVS 1.2 under the - assumption that the "module name" is a first class, unavoidable - interface to the Repository, allowing no way to retrieve anything - other than by module name. Though it is easier to program that - way, many users of CVS believe the modules support to be too - primitive to allow such a limitation. - - Since "release" was written, other parts of CVS broke that - assumption. It needs to be revised. - - - 3K.3 Why can't I "release" portions of a checked out directory? I - should be able to "release" any file or sub-directory within - my working directory. - - This isn't really a limitation in "release", per se. CVS doesn't - try to keep track of which files in which directories are "checked - out" and which are just lying there. You can delete directories - and "update" will not bring them back unless you add a special - "-d" option. - - In other words, CVS doesn't keep track of how you adjust the - partition between files you consider part of your working set and - files that were checked out because they are part of the same - module or directory. And neither does "release". - - In future CVS releases, "release" might become sophisticated - enough to handle both the reversal of a "checkout" and the - deletion of random portions of the working directory, but it isn't - that way now. - - - 3K.4 I removed the tree that I was about to start working on. How do I - tell cvs that I want to release it if I don't have it anymore? - - See 3G.4. - - - 3K.5 Why doesn't "release -d module" reverse a "checkout module"? - - It does, if you are using "module" in a way that "release" - expects: a non-alias string in the left column of the "modules" - database. - - If "module" is really an alias, or if you are using a relative - path in the place of "module", or if you renamed the directory - with the -d option in the modules file or on the "checkout" - command line, then the current version of "release" won't work. - - Future versions of "release" will probably fix most of these. - - - 3K.6 Why can't I release a module renamed with "cvs checkout -d"? - - The current version of "release" doesn't know how to track the - renaming option ('-d') of the "checkout" command. It will - probably be fixed in the future. - - - ----------------- --- Section 3L -- "remove", "rm", "delete" ----------------- - - **** Questions: - - 3L.1 What is "remove" for? - 3L.2 Why doesn't "remove" work on directories when it appears to try? - 3L.3 I don't like removing files. Is there another way to ignore them? - 3L.4 I just removed a file. How do I resurrect it? - 3L.5 Why doesn't "remove" delete the file? Instead, it prints an - error message and tells me to remove the file by hand. - - - **** Answers: - - 3L.1 What is "remove" for? - - To remove a file from the working branch. It removes a file from - the main branch by placing it in an "Attic" directory. - - - 3L.2 Why doesn't "remove" work on directories when it appears to try? - - Oversight. It should be able to delete an empty directory, but - you still don't have a way to remember when it was there and when - it disappeared to allow the "-D " option to work. - - You'll have to remove the working directory and the matching - directory in the Repository. - - - 3L.3 I don't like removing files. Is there another way to ignore them? - - There's no reason to be hasty in using the "remove" command. - - If there is a way to ignore files in your build procedures, I'd - just do that. Later, when you decide that the files are really - ancient, you can execute a "remove" command to clean up. - - The CVS "ignore" concept can't ignore files already in CVS. - - - 3L.4 I just removed a file. How do I resurrect it? - - If you executed "remove", but haven't typed "commit" (you can - tell this by the 'R' notation that "update" prints next to the - file), you can execute "add" to reverse the "remove". - - If you followed the "remove" with a "commit", you'll have - to move it back out of the Attic by hand: - - I use something like this: (csh-like syntax) - - set repos = `cat ./CVS/Repository` - mv $repos/Attic/filename,v $repos/filename,v - - (If you use relative paths in your Repository files, that first - line becomes: set repos = $CVSROOT/`cat ./CVS/Repository`) - - While a file is in the Attic, you can't "add" another file by - the same name. To add such a file you either have to move it by - hand as in the above, or delete it from the Attic. - - The main reason for the Attic is to retain files with tags in - them. If you execute: "update -r ", files with - attached to some revision will be taken from the normal Repository - area and from the Attic. That's why you can't "add" a file with - the same name. "remove" only moves a file off the main branch, it - doesn't obliterate it. - - - 3L.5 Why doesn't "remove" delete the file? Instead, it prints an - error message and tells me to remove the file by hand. - - Design choice. Unix software written within last decade, usually - requires an extra verification step, such as answering a question - or adding a flag on the command line. CVS currently requires that - you delete the file first unless you specify the '-f' (force) - option, which deletes the file before performing "cvs remove". - - - ----------------- --- Section 3M -- "rtag", "rt", "rfreeze" ----------------- - -(See the "tag" section below for the general questions about Tagging, which - "tag" and "rtag" share in common.) - - - **** Questions: - - 3M.1 What is "rtag" for? - 3M.2 Why use "rtag"? It assumes no one is changing the Repository. - 3M.3 What revision does "rtag -r " actually put the tag on? - 3M.4 What happens if the tags are the same in "rtag -r "? - 3M.5 Why doesn't "rtag -b -r " rename or - duplicate a magic branch tag? - - - **** Answers: - - 3M.1 What is "rtag" for? - - To add a symbolic label (a "tag") to the last committed revisions - of a module directly in the Repository. - - - 3M.2 Why use "rtag"? It assumes no one is changing the Repository. - - Though the "tag" command is more useful in marking the - revisions you have in a particular working directory, "rtag" is - much handier for whole-Repository actions, which occur at major - release boundaries. - - - 3M.3 What revision does "rtag -r " actually put the tag on? - - In short, the '-r' option is another way to select the revision to - tag. The revision is selected the same way for all commands that - accept a "-r " option. - - Depending on whether is a , or a non-branch - and on whether you use the '-b' option to "rtag", you get - four different results: - - 1. rtag -r - - Adds the non-branch tag to the same revision that the - non-branch tag is attached to. - - Example: - --> TT1 - --> TT2 - --> Symbols: TT1:1.4 - After --> Symbols: TT1:1.4,TT2:1.4 - - - 2. rtag -r - - Adds the non-branch tag to the HEAD of (the highest - revision number on) the branch labelled with tag . - - Example: - --> BR1 - --> TT2 - --> Symbols: BR1:1.2.0.2 (1.2.2.5 is HEAD) - After --> Symbols: BR1:1.2.0.2,TT2:1.2.2.5 - - If the branch tagged by has not been created, - then the tag shows up on the branch point revision: - - Example: - --> BR1 - --> TT2 - --> Symbols: BR1:1.2.0.2 (No 1.2.X exists.) - After --> Symbols: BR1:1.2.0.2,TT2:1.2 - - - 3. rtag -b -r - - Adds the magic branch tag to the revision that - the non-branch tag is attached to, preparing it to be a - branch point. - - Example: - --> TT1 - --> BR2 - --> Symbol: TT1:1.4 - After --> Symbol: TT1:1.4, BR2:1.4.0.2 - - - 4. rtag -b -r - - Adds the magic branch tag to the revision at the - HEAD of (the highest revision number on) the branch labelled - with , preparing it to be a branch point. - - Example: - --> BR1 - --> BR2 - --> Symbol: BR1:1.2.0.2 (1.2.2.5 is HEAD) - After --> Symbol: BR1:1.2.0.2,BR2:1.2.2.5.0.2 - - If the branch tagged by has not been created, - then the tag shows up as a second branch off the same - branch point revision: - - Example: - --> BR1 - --> TT2 - --> Symbols: BR1:1.2.0.2 (No 1.2.X exists.) - After --> Symbols: BR1:1.2.0.2,TT2:1.2.0.4 - - - - In all four cases above, if already exists on the file, you - get an error unless you specify the '-F' option. - - In all four cases, if does not exist on the file, is - not added unless you specify the '-f' option. - - - 3M.4 What happens if the tags are the same in "rtag -r "? - - Again, there are four cases depending on whether is a - branch tag, or a non-branch tag and on whether you use the - '-b' option to "rtag": - - 1. rtag -r - - Is a no-op. It does nothing even with '-F' specified. - - If you add the '-f' option ("rtag -f -r "), then - is attached to the latest revision on the Main Branch if - the file does *not* already have on some revision. - - If the is already on the file, using "rtag -f" is still - a no-op. - - - 2. rtag -r - - Produces an error, since the is already on some - revision of the file. - - But, "rtag -F -r " turns the magic - branch tag into a non-branch tag. - - Symbols: BR1:1.4.0.2 - becomes - Symbols: BR1:1.4 - - - 3. rtag -b -r - - Produces an error, since the is already on the file. - - But, "rtag -F -b -r " turns the non-branch - tag into a magic branch tag. - - Symbols: BR1:1.4 - becomes - Symbols: BR1:1.4.0.2 - - - 4. rtag -b -r - - Produces an error, since the is already on the - file. - - But, "rtag -F -b -r " increments the - branch number. It essentially removes the branch and creates a - new one by the same name. - - Symbols: BR1:1.2.0.4 - becomes - Symbols: BR1:1.2.0.6 - - - - 3M.5 Why doesn't "rtag -b -r " rename or - duplicate a magic branch tag? - - None of the "tag" or "rtag" options rename anything. They only - apply (or, with the '-F' option, move) tags to specific revisions - in the file. - - See 3M.[3-4] above for details of how it works. - - To rename a non-branch tag, see 3O.9. - To rename a magic branch tag, see 4D.5 - - - ----------------- --- Section 3N -- "status", "st", "stat" ----------------- - - **** Questions: - - 3N.1 What is "status" for? - 3N.2 Why does "status" limit the File: at the top to 17 characters? - 3N.3 Why does it print "Sticky" lines when the values are "(none)"? - 3N.4 Shouldn't the status "Needs Checkout" be "Needs Update"? - - - **** Answers: - - 3N.1 What is "status" for? - - To display the status of files, including the revision and branch - you are working on and the existence of "sticky" information. - - - 3N.2 Why does "status" limit the File: at the top to 17 characters? - - Designed that way to line up with other data. You can find the - whole filename in the line beginning with "RCS version:", which is - not limited in length. - - - 3N.3 Why does it print "Sticky" lines when the values are "(none)"? - - Oversight. It should probably elide lines without information. - - - 3N.4 Shouldn't the status "Needs Checkout" be "Needs Update"? - - Probably. - - [[Did this show up in CVS 1.4?]] - - - ----------------- --- Section 3O -- "tag", "ta", "freeze" ----------------- - - **** Questions: - - 3O.1 What is "tag" for? - 3O.2 What is the difference between "tag" and "rtag"? - 3O.3 Why does "tag -b" not put a tag on the Branch Point revision? - How do I refer to the Branch Point? - 3O.4 So "{r}tag" labels a bunch of files. What do you use a Tag for? - 3O.5 How do I get "tag" and "rtag" to send mail the way "commit" does? - 3O.6 Why can't "tag" handle the '-r' option that "rtag" takes? - 3O.7 After a "tag " in my working directory, why doesn't "checkout - -r " somewhere else produce copies of my current files? - 3O.8 Why doesn't "tag" write a history record the way "rtag" does? - 3O.9 How do I rename a ? - - - **** Answers: - - 3O.1 What is "tag" for? - - To add a symbolic label (a "tag") to the RCS files last checked - out, updated or committed in a working directory. - - - 3O.2 What is the difference between "tag" and "rtag"? - - The end result of both commands is that a , or symbolic name, - is attached to a single revision in each of a collection of files. - - The differences lie in: - - 1. The collection of files they work on. - - "rtag" works on the collection of files referred to by a - "module" name as defined in the "modules" file, or a relative - path within the Repository. - - "tag" works on files and directories specified on the command - line within the user's working directory. (Default is '.') - - Both commands recursively follow directory hierarchies within - the named files and directories. - - 2. The revisions they choose to tag. - - "rtag" places a tag on the latest committed revision of - each file on the branch specified by the '-r' option. By - default it tags the Main Branch. - - "tag" places a tag on the BASE (i.e. last checked out, updated - or committed) revision of each file found in the working - directory. (The BASE revision of a file is the one stored in - the ./CVS/Entries file.) - - 3. A different set of command line options. - - For example, "rtag" takes a "-r " option to retag an - existing tag. The "tag" command does not. - - 4. How it is logged. - - Currently "rtag" records the and the module in the - "history" file, while "tag" does not. - - - 3O.3 Why does "tag -b" not put a tag on the Branch Point revision? - How do I refer to the Branch Point? - - This is probably an oversight, or a disbelief in the need for it. - If everything works perfectly, the "update -j" command will do the - merge you need and you don't need to check up on it by playing - with the branch point revision. - - The '-b' option attaches a magic branch tag to allow CVS later to - figure out the branch point. The actual revision that is - attached to does not exist. References to the branch tag are - equivalent to references to the latest revision on the branch. - - There is no way to refer to the branch point without adding a - non-branch tag. You might want to add non-branch tags as a - habit and add branch tags later, possibly immediate after adding - the non-branch tag. See 4C.3 on Creating a Branch. - - - 3O.4 So "{r}tag" labels a bunch of files. What do you use a Tag for? - - You use it to "checkout" the labeled collection of files as a - single object, referring to it by name. - - Anywhere a revision number can be used a Tag can be used. In fact - tags are more useful because they draw a line through a collection - of files, marking a development milestone. - - The way to think about a Tag is as a curve drawn through a matrix - of filename vs. revision number. Consider this: - - Say we have 5 files (in some arbitrary modules, some may be in 2 - or more modules by name, some may be in 2 or more modules because - of the Repository tree structure) with the following revisions: - - file1 file2 file3 file4 file5 - - 1.1 1.1 1.1 1.1 /--1.1* <-*- - 1.2*- 1.2 1.2 -1.2*- - 1.3 \- 1.3*- 1.3 / 1.3 - 1.4 \ 1.4 / 1.4 - \-1.5*- 1.5 - 1.6 - - At some time in the past, the '*' versions were tagged. Think - of the as a handle attached to the curve drawn through the - tagged revisions. When you pull on the handle, you get all the - tagged revisions. Another way to look at it is that you draw a - straight line through the set of revisions you care about and - shuffle the other revisions accordingly. Like this: - - file1 file2 file3 file4 file5 - - 1.1 - 1.2 - 1.1 1.3 _ - 1.1 1.2 1.4 1.1 / - 1.2*----1.3*----1.5*----1.2*----1.1 (--- <-- Look here - 1.3 1.6 1.3 \_ - 1.4 1.4 - 1.5 - - I find that using these visual aids, it is much easier to - understand what a is and what it is useful for. - - - 3O.5 How do I get "tag" and "rtag" to send mail the way "commit" does? - - The "commit" command is supported by two files ("commitinfo" - and "loginfo") not used by other commands. To do logging the - same way for "tag" and "rtag" would require another file like - loginfo, which currently doesn't exist. - - The "rtag" command requires a "module" entry, which can specify a - "tag" program using the "-t programname" option on the module - line. - - There is no equivalent support for "tag". - - - 3O.6 Why can't "tag" handle the '-r' option that "rtag" takes? - - Oversight. The answer is probably "Fixed in a Future Release." - - - 3O.7 After a "tag " in my working directory, why doesn't "checkout - -r " somewhere else produce copies of my current files? - - The only reason this would fail, other than misspelling the - string, is that you didn't "commit" your work before "tagging" it. - Only committed revisions may be tagged. Modified files are not - marked for later tagging. - - - 3O.8 Why doesn't "tag" write a history record the way "rtag" does? - - The "rtag" command was originally intended to place major - "release" tags onto modules. The "tag" functionality was - developed to *move* the more significant tag when slight changes - to individual files sneaked in after the release tag was stamped - onto the Repository. - - The significant event was the "rtag", which was recorded in the - "history" file for the "history -T" option to work. - - It turns out that "tag" is generally more useful than "rtag", so - the model has changed. Future revisions of CVS will probably - store both kinds of tags in the history file. - - - 3O.9 How do I rename a ? - - For a procedure to rename a branch tag, See section 4D.5 - The following covers only non-branch tags. - - First, pick a that is not in use. You could reuse - (i.e. move) an existing tag to the new revisions using the '-F' - option, but that will confuse matters when both tags are not - already on a file. (It will probably confuse "rtag -f" too.) - - Use "rtag" to place only on revisions attached to - in the whole Repository, then delete the old one. - - cvs rtag -r world - cvs rtag -d world. - - - You can also checkout or update your working directory to the - and "tag" rather than "rtag" the result. But that - will take longer and it has the chance of producing conflicts. - - cvs update -r - cvs tag - cvs tag -d - cvs update -A (or cvs update -r ) - - ----------------- --- Section 3P -- "update", "up", "upd" ----------------- - - **** Questions: - - 3P.1 What is "update" for? - 3P.2 What do 'U', 'M' and 'C' mean when I type "update"? Are they - different for "cvs -n update"? - 3P.3 What's the difference between "update" and "checkout"? - 3P.4 Why don't I get new files when I execute "update"? - 3P.5 Why does "update" say 'M' both for plain modified files and for - successful (i.e. conflict-free) merges? Aren't they different? - 3P.6 What's a "sticky conflict"? How does it know a conflict occurred? - 3P.7 Is there a feature to tell me what I have changed, added and - removed without changing anything? - 3P.8 Why were all my files deleted when I executed "update"? - - - **** Answers: - - 3P.1 What is "update" for? - - The "update" command is by far the most important command and is - probably also the most used command. - - It has five purposes: (And many options.) - - 1. To display the status of your working files. - - Though a plain "update" also displays the status, it does so - after possibly altering your working directory. To see the - status of your working files without changing anything, type: - - cvs -n update {optional list of files} - - - 2. To merge changes made by others to the branch you are working - on into your working files. - - Each working directory is attached to a branch, usually the - Main branch. To merge changes made on your working branch - since your last checkout, update or commit, type: - - cvs update {optional list of files} - - - 3. To merge changes made on another branch into the branch you are - working on (your "working branch"). - - If you want to grab a whole branch, from the branch point, - which is assumed to be on the Main Branch, to the end of the - branch, you type: - - cvs update -j {optional files} - - If you want to grab the changes made between two tags or - revisions, you type: - - cvs update -j -j {optional files} - - (If you are working with a single file, the Tags could also be - revisions numbers. Unless you take great care to match - revision numbers across different files (a waste of time given - the way Tags work), using revision numbers in place of the - Tags for multiple files would be meaningless.) - - - 4. To move your working directory to another branch. - - A working directory is presumed to be attached to (or working - on) a particular branch, usually the Main branch. To alter - what CVS believes to be your working branch, you "move" to that - branch. - - To move to a tagged branch, type: - - cvs update -r {optional files} - - To move to the Main Branch, type: - - cvs update -A {optional files} - - If you have modified files in your working directory, this is - not a clean move. CVS will attempt to merge the changes - necessary to make it look like you made the same changes to the - new branch as you made in the old one. But if you do this - twice without resolving the merge conflicts each time, you can - lose work. - - - 5. To retrieve old revisions of files. - - This option is similar to 4 above but you are not restricted to - using a . You may specify any revision or - with '-r' and get the specified revision or the tagged - revision: - - cvs update -r {optional files} - - Or you may specify any date with '-D': - - cvs update -D {optional files} - - The '-p' option sends the revisions to standard output - (normally your terminal) rather than setting the "sticky" tag - and changing the files. - - - 3P.2 What do 'U', 'M' and 'C' mean when I type "update"? Are they - different for "cvs -n update"? - - "cvs update" merges changes made to the Repository, since your - last "checkout", "update" or "commit", into your working files. - You can think of it as changing your BASE revision. - - "cvs update" prints lines beginning with: - - 'U' after replacing your unmodified file with a different - revision from the Repository. - - 'M' for two different reasons: - - 1. for files you have modified that have not changed in - the Repository. - - 2. after a merge, if it detected no conflicts. - - 'C' after a merge, if it detected conflicts. See 2D.7 and - 3P.6 for more info on conflict resolution and "sticky - conflicts." - - "cvs -n update" shows what it *would* do, rather than doing it. - Or, another way of looking at it, "cvs -n update" displays the - relationship between your current BASE revisions (identified in - your ./CVS/Entries file) and the HEAD revisions (the latest - revisions in the Repository). - - "cvs -n update" prints lines beginning with: - - 'U' for files you have not modified that have changed in the - Repository. - - 'M' for files you have modified that have not changed in the - Repository. - - 'C' for files you have modified that have also been changed in - the Repository. - - - See 4C.6 for what the letters mean when merging in from another - branch. The output is almost the same for a normal update if you - consider the Repository as the branch and your working directory - as the "trunk". - - - 3P.3 What's the difference between "update" and "checkout"? - - See 3C.4 above. - - - 3P.4 Why don't I get new files when I execute "update"? - - There are six reasons for nothing to happen during an "update": - - 1. Nothing on your branch changed in the Repository. - - If no one has committed anything to the branch you are working - on (normally the Main branch) since the last time you executed - "checkout", "update" or "commit", nothing will happen. - - It's like shouting "xyzzy" or "plugh" in the wrong room. - - 2. You have a "sticky" non-branch or attached to the - working files you are trying to "update". - - At some time in the past you checked out or updated your - directory with the "-r " or "-D " option. Until you - do it again with a different tag or date, or go back to the - Main Branch with "update -A", you will never again see any - updates. - - 3. The ./CVS/Entries.Static file exists and you are expecting a - new file. - - If your ./CVS administrative directory contains a file named - Entries.Static, no files will be checked out that aren't - already in the Entries or Entries.Static file. - - 4. You forgot to use the '-d' option and are looking for new - directories. - - If you execute "update" without the '-d' option, it will not - create new directories that have been added to the Repository. - - 5. You typed "update" instead of "cvs update". - - On most Unix systems, your disk caches are now furiously being - flushed by multiple update daemons, destroying performance and - proving to management that you need more CPU power. :-) - - On HP systems you might be asked what package you want to - install from the "update server". - - 6. Someone removed (using "admin -o") your BASE revision (the - revision CVS thought you had in your working directory), then - committed a "replacement". CVS is now confused because the - revision in the Repository matches your BASE revision when the - files themselves don't match. See 3B.6. - - - 3P.5 Why does "update" say 'M' both for plain modified files and for - successful (i.e. conflict-free) merges? Aren't they different? - - A design choice. Yes, they are different internally, but that - shouldn't matter. Your files are in the same condition after the - "update" as they were before -- a "diff" will display only your - modifications. And you are expected to continue onward with parts - two and three of the normal development cycle: "emacs" (a synonym - for "edit" in most of the civilized world) and "commit". - - - 3P.6 What's a "sticky conflict"? How does it know a conflict occurred? - - When a "cvs update" (or an "update -j") creates a conflict, it - prints a 'C' and stores the timestamp of the file after the merge - in a special field in the ./CVS/Entries file. - - This conflict indication implies that the merge command altered - your working file to contain conflict markers surrounding the - overlapping code segments. For example, say that - - - Two developers acquire revision 1.2 of via "checkout" or - "update". - - - Developer A changes line 1 from "9999" to "5555", then commits - the file, creating revision 1.3. - - - Developer B changes line 1 from "9999" to "7777", then tries to - commit the file, but is blocked because the file is not up to - date. Developer B then runs "update" and sees the conflict - marker 'C'. The beginning of the file would look like this: - - <<<<<<< The working in question. - 7777 Change made to the working . - ======= - 5555 Change made in the first commit (1.3) - >>>>>>> 1.3 The revision created by the first commit. - - The conflict is "sticky", which means that until the conflict is - cleared, the "update" command will continue to display the file's - status as 'C' and the "status" command will show the file's status - as "Unresolved Conflict". - - Until the conflict is cleared, "commit" is blocked for this file. - - The sticky conflict indicator can be cleared by: - - 1. Resolving the conflict by editing the file. Two things must - happen before the conflict is considered resolved: - - The timestamp of the file must change. - *and* - The file must contain no conflict markers. (The string - searched for in the file is the regexp: "^>>>>>>> ".) - - After clearing the sticky conflict indicator, you may then - commit the file normally. - - 2. Removing the file and running "update". This throws away the - local changes and accepts the latest committed file on this - branch. No commit is needed. - - 3. Forcing the commit to happen by using "commit -f". This is - probably a mistake since there are few lines of real - text that begin with ">>>>>>> ". - - - 3P.7 Is there a feature to tell me what I have changed, added and - removed without changing anything? - - The command "cvs -n update" will do exactly that. - - - 3P.8 Why were all my files deleted when I executed "update"? - - You probably executed "update -r " some time ago, then - removed from the Repository files. "update -r " will - delete a file that doesn't contain . - - A way to fix this is to "cd" into your working directory and - type: - - cvs update -A - - If you don't want the latest revisions on the Main (or Vendor) - Branch, then decide what Tag (normal or branch) you want and type: - - cvs update -r - - Another way to make a file disappear is to execute "update -D - " where is before the date stamped onto the first - revision in the RCS file. - - - -=============================================== -== Section 4 ==== Advanced Topics ==== -=============================================== - ----------------- --- Section 4A -- Installing CVS ----------------- - - **** Questions: - - 4A.1 What do I have to do before I install CVS? - 4A.2 How do I configure the CVS programs? - 4A.3 What do I have to install? - 4A.4 How do I work around the merge problems in GNU diff version 2.1 - or later? - - - **** Answers: - - 4A.1 What do I have to do before I install CVS? - - 1. You must decide where to set up a Repository. - - Though you can construct a Repository tree structure using - links and mount points, there must be a single copy of each - real file across your entire organization. You may not "rdist" - files and expect to edit both copies. - - CVS does not support a truly distributed Repository. You can - have multiple Repositories, but each one must be mounted (not - copied or "rdist"ed) from a single place onto all machines - where it will be used. - - Initially, a Repository takes about same amount of disk space - as the sources you want to put into it, plus a bit of overhead - for the RCS files. - - See Section 4B. For multiple Repositories, see 4G.3 - - 2. You need a directory in everyone's $PATH variable where you can - install all the executables. /usr/local/bin is a common place. - - 3. You need some helper tools besides CVS such as "RCS" and a - good set of "diff" and "diff3" programs. See 1B.4 for - suggestions. - - 4. Read the README, INSTALL and ChangeLog files to see what you - are getting into. - - 5. Make sure you have versions of all the programs mentioned in - the "cvs/src/options.h" and "cvs/src/rcs.h" files. - - 6. Though you can probably muddle along without it, you should - appoint one or more "Repository Administrators" who will be - responsible for maintaining the Repository structure, - administrative files and the "modules" interface. - - Someone at your site should probably be on the info-cvs mailing - list. See 1B.5. - - - 4A.2 How do I configure the CVS programs? - - 1. You should certainly start by reading the README file, the - INSTALL files and possibly the ChangeLogs in each directory, - the Makefile.in files and the "cvsinit.sh" program. - - 2. Edit the "options.h" file in the "src" directory. - - You might need to specify a few site-specific pieces of - information including the names of a number of functions. - - Hint1: You probably want to set the DIFF macro to use your - version of the GNU diff program with the '-a' option. - Ours is set to "gdiff -a". - - Hint2: You want to use RCS 5.6.0.1 or greater and set the - "HAVE_RCS5" macro. - - 3. Execute the ./configure command. - - 4. Type "make". - - 5. After running "make" you might try running the "sanity.sh" - script: - ./src/sanity.sh `pwd`/src/cvs - - It writes into /tmp/cvs-sanity by default. - - 6. Finish reading the INSTALL file and test out the system. - - - 4A.3 What do I have to install? - - 1. Install the "cvs" executable and "mkmodules" from the CVS - sources. The man page is useful too. If you plan to report - bugs, you should also install "cvsbug". - - 2. Make sure you have versions of all the programs mentioned in - the options.h file, most of which are included in a standard - Unix system. - - 3. Unless you plan to reimplement RCS [:-)], you must install RCS. - - It is a very good idea to examine the RCS installation - instructions and make sure you are using the GNU versions of - "diff" and "diff3" or merges (an important part of CVS) will - not work as well as you'd like. - - 4. Set your $CVSROOT environment variable and create the - Repository (which you planned out in 4A.1) with the "cvsinit" - command at the top of the CVS sources. - - 5. You'll need to edit the Repository control files created by - "cvsinit". - - 6. Install any helper programs mentioned in the modules file. - - - 4A.4 How do I work around the merge problems in GNU diff version 2.1 - or later? - - See 1B.4 If you use recent versions of RCS and "diff", you won't - run into the above. If you do, see 5B.8 - - ----------------- --- Section 4B -- Setting up and Managing the Repository ----------------- - - **** Questions: - - 4B.1 What do I do first? How do I create a Repository? - 4B.2 What are those files in $CVSROOT/CVSROOT? - 4B.3 Is there any other state stored in the Repository besides in the - $CVSROOT/CVSROOT directory? - 4B.4 How do I put sources into the Repository? - 4B.5 What file permissions should I use on (and in) the Repository? - 4B.6 How do I structure my Repository? - 4B.7 Why would anyone use "modules"? They are too restrictive. I - want to be able to select just the files I want to edit. - 4B.8 How do I rename a file or directory? What are the consequences? - 4B.9 What are "Attic" directories? - 4B.10 Is it OK to remove anything from the Repository? - 4B.11 Can I convert to CVS from RCS without losing my revision history? - 4B.12 Can I move RCS files with branches in them into the Repository? - 4B.13 Can I use raw RCS commands on the Repository? - 4B.14 How do I convert from SCCS to RCS? - 4B.15 How do I limit access to the Repository? - 4B.16 What are the Repository Administrator's responsibilities? - 4B.17 How do I move the whole Repository? - 4B.18 How do I change permissions on a file in the Repository by using - a CVS command? (i.e. without using "chmod 777 $CVSROOT/dir/file") - - - **** Answers: - - - 4B.1 What do I do first? How do I create a Repository? - - First, install all the programs. (See Section 4A.) - - Then create a Repository by executing "cvsinit", which works only - from within the head of the CVS source directory. (It needs files - from the distribution to work.) - - If you want a very primitive Repository and don't want to save a - history log, refer to modules, or use any of the "info" files for - logging, pre-commit checks, or editing templates, you can dispense - with "cvsinit" entirely. I would advise executing it. - - The cvsinit program will create a short modules file containing - the module named "CVSROOT". To to your work directory and type: - - cvs checkout CVSROOT - - Then read the files that are checked out. - - You will certainly want to add modules of your own. Edit the - "modules" file and add lines to describe the items you want to - "checkout" by module name. Here's a short list that could be - used for storing a small number of GNU and PD sources: - - local local - - gnu local/gnu - emacs local/gnu/emacs - cvs local/gnu/cvs - - public local/public - pdprog1 local/public/pdprog1 - pdprog2 local/public/pdprog2 - - test test - junk test/junk - - - When you are done editing, "commit" the modules file. If you - configured CVS to use "dbm", you might have to edit and commit the - modules file twice to change the pathname of the mkmodules program - in the modules file. - - Try using the "import" command to insert the "junk" module - and play around until you are comfortable. - - - - 4B.2 What are those files in $CVSROOT/CVSROOT? - - There are eight Repository control (or "database") files of - interest in the CVSROOT directory: - - 1. modules contains the "modules" database. See 1D.11, 2C.7, - 4B.6 and 4B.7 for more details. - - 2. commitinfo contains two columns: 1. a regular expression to - match against pathnames within the Repository and - 2. a to execute for matching pathnames. - - When you execute "commit", CVS passes the - Repository pathname for each directory (and the - files to commit within that directory) to - . If exits with a non-zero - status, the commit is blocked. - - A associated with a pathname of - "DEFAULT" is executed if nothing else matches. - Every associated with a pathname of - "ALL" is executed separately. - - 3. rcsinfo contains the same first column as commitinfo, but - the second column is a template file for - specifying the log entry you are required to enter - for each commit. - - "DEFAULT" and "ALL" work the same as in the - commitinfo file. - - 4. editinfo contains the same two columns as commitinfo, but - the in the second column is intended to - do some consistency checking on the commit log. - - "DEFAULT" works as in commitinfo. - - 5. loginfo contains the same two columns as commitinfo, but - the is expected to read a log message - from its standard input. The can do - anything it wants with the log information, but - normally it is appended to a log file or sent to - mailing lists. - - "DEFAULT" & "ALL" work the same as in commitinfo. - - 6. cvsignore contains "ignore" patterns that are added to the - built-in ignore list. See 2D.10. - - 7. checkoutlist contains a list of other files kept under RCS in - $CVSROOT/CVSROOT that should be checked out by - mkmodules to provide a readable copy. - - 8. history contains a stream of text records, one for each - event that the "history" command is interested - in. Though the contents of the history file can - be read, it is intended to be read and displayed - by the "history" command. This file is the only - one in the above list that is not under RCS. - - - 4B.3 Is there any other state stored in the Repository besides in the - $CVSROOT/CVSROOT directory? - - Only in the RCS files. The Repository holds exactly two things: - the tree of RCS files (each usually ending in ",v") and the - CVSROOT directory described above. - - - 4B.4 How do I put sources into the Repository? - - There are three main ways to put files in the Repository: - - 1. Use the "import" command described in Section 3H. - - This method is the fastest way to put trees of new code into - the Repository and the *only* way to handle source releases - from a 3rd party software vendor. - - 2. Use "add" followed by "commit". - - This is how to add new files and directories to the Repository, - a few at a time. Directories don't need to be committed. - - 3. You can move RCS files directly into the Repository. - - You should create a directory hierarchy to hold them, but you - can just move arbitrary ",v" files into the Repository. The - only "state" in the Repository other than within ",v" files is - in the required CVSROOT directory at the top of the Repository. - - - 4B.5 What file permissions should I use on (and in) the Repository? - - If you run a completely open environment (which usually means that - you don't have, or don't want to waste, the time to deal with it): - - - Set all directory permissions to 777. - - - Have everyone set their umasks to 0. - - (BTW, I don't suggest this. I am merely reporting it.) - - - If you are a normal Unix shop and want to use groups effectively: - - - Set all the directory permissions in the Repository to 775. - - If you are using a system that handles both System V and BSD - filesystems, you might have to set the permissions to 2775.) - - If you are using one of the many recent versions of Unix that - don't allow you to use the full octal mode, then you'll have - to type: chmod u=rwx,g=rwx,o=rx,g+s - - - Change all the groups on the directories to match the groups - you want to write to various directories. - - - Make sure every user is in the appropriate groups. - - - Have everyone set their umask to 002, including root. - - - If you don't want non-group members to even read the files, do the - above, but change: - - - Repository directory permissions to 770. (or 2770) - - - umasks to 007. - - - If you work in an environment where people can't be trusted to - set their "umask" to something reasonable, you might want to set - the umask for them: - - mv /usr/local/bin/cvs /usr/local/bin/cvs.real - cat > /usr/local/bin/cvs - #!/bin/sh - umask 2 # Or whatever your site standard is. - exec /usr/local/bin/cvs.real ${1+"$@"} - ^D - - - 4B.6 How do I structure my Repository? - - The Repository holds your software. It can be all interrelated - or it can be a bunch of separately managed directories. - - How you break a whole system down into its component parts, while - defining interfaces between them, is one aspect of "Software - Engineering", a discipline that requires the study of dozens of - strange and wonderful areas of the computer and management worlds. - - CVS provides a way to keep track of changes to individual files, - a way to "tag" collections of files, and a way to "name" - collections of files and directories. That's all. Everything - else is in the way you apply it. - - In other words, you should structure your Repository to match your - needs, usually tied in with the other tools you use to build, - install and distribute your work. Common needs include the - ability to: - - - mount (or automount) directories from many places in your - organization. - - check out just what you need and no more. - - check out multiple sections in a fixed relation to each other. - - check out large sections to match the assumptions built into - your build system. (Makefiles?) - - In my opinion, you should start small and keep everything in one - tree, placing each major sub-system into a separate directory. - Later, when you know what you are doing, you can make it more - sophisticated. - - - 4B.7 Why would anyone use "modules"? They are too restrictive. I - want to be able to select just the files I want to edit. - - Any form of structure is restrictive. If you believe that total - chaos is a viable working paradigm, or if you believe you can keep - track of the interrelations between all portions of your - Repository in your head, then you can do what you please. - - If you believe that systems of files require management and - structure, then the "modules" idea is very useful. It is a way - to impose a naming scheme on a tree of files, a naming scheme that - can be simpler than a large list of relative pathnames. - - The "modules" file represents a published interface to the - Repository set up by your Repository Administrator. If s/he did a - creditable job, the modules offered will be internally consistent - and will smoothly interact with the rest of your environment. - - - 4B.8 How do I rename a file or directory? What are the consequences? - - In CVS there is no single "rename" command. - - See 2C.4 for the suggested way to rename a file or directory. - - The rest of this section covers some of the consequences of - renaming. - - A "renaming database" has been proposed that would keep track - of name changes so that "update -r " would continue to - work across the renaming. But as it stands, you have to pick - one of the following options: - - 1. Use the technique described in 2C.4. (For each file, duplicate - the file in the Repository, "remove" the old version so it - winds up in the Attic and strip all Tags off the new version.) - - - "update -r " produces the correct files. - - - The duplicated revision history can be slightly misleading. - - - A plain (i.e. without the "-r ") "checkout" or "update - -d" will create directories "renamed" this way, but you can - delete it and a plain "update" won't bring it back. - - - 2. Move the files and directories in the Repository to the new - names. - - - You save the revision history under a different file name. - - - You save a little space. - - - "update -r " produces the wrong files or directories. - - This is not a good general solution, but if you plan never to - look back (someone may be gaining on you!), it is sometimes a - useful notion. - - If you are clever with Makefiles, you might be able to rework - them to handle either the new or old names, depending on - which ones exist at the time. Then you can move an old - onto the new, more sophisticated, revision of the Makefile. - (Yes, this changes the "released" file if indicates a - release. But it is an option.) - - - Important Note: If you rename a directory, you must rename - the corresponding directory in every checked-out working - directory. At the same time, you must edit the pathname - stored in the ./CVS/Repository file within each of the moved - directories. - - The easiest way to move a lot of directories around is to - tell everyone to remove their working directories and check - them out again from scratch. - - - The file exists in the working directory and in the - ./CVS/Entries file, but not in the Repository. For the old - file, "update" prints: - - cvs update: xyz.c is no longer in the repository - - and deletes the file. If the file was modified, "update" - prints: - - cvs update: conflict: xyz.c is modified but - no longer in the repository - C xyz.c - - and leaves the file alone. In the new directory, you see: - - U xyz.c - - as you would if someone else executed "add" and "commit". - - - 3. For each file, copy the working file to a new name in the - working directory and use the "cvs remove" to get rid of the - old old file and "cvs add" to add the new one. Since there is - no way for CVS to remove a directory, this only works for files. - - - This is what most people think of first. Without a "rename" - command, the remove/add technique seems obvious. - - - You lose the connection of your new working file to its past - revision history. - - - 4B.9 What are "Attic" directories? - - When you use the "remove" command on a file, CVS doesn't delete - the file, it only registers your desire to delete it. - - When you "commit" a removed file, CVS moves the Repository's - matching RCS file into a sub-directory named "Attic" within the - Repository. - - Attic files are examined when the '-r' or '-D' option is used - on "checkout" or "update". If the specified revision, tag or - date matches one on a file in the Attic, that file is checked out - with the others. - - You can think of the Attic as a sort of dead branch, which is only - looked at when you refer to a or . - - - 4B.10 Is it OK to remove anything from the Repository? - - In general, removing anything from the Repository is a bad idea. - The information in a deleted object is lost forever. There are - many ways to skip over files, directories and revisions without - deleting them. - - Here are some of the consequences of removing the following things - stored in the Repository: - - 1. CVSROOT files (Repository control files) - - The Repository will work without any of them, but you should - understand what you are losing by deleting them. See 4B.2. - - 2. Revisions - - The only way to remove revisions is to use the "admin -o" - command (or the equivalent RCS command "rcs -o"). - - They are lost forever. Any tags formerly attached to deleted - revisions are now pointing into the Phantom Zone. You'll need - to contact Jor-el to get them back. - - 3. Files - - You should not remove a file unless you truly never want to see - it again. If you want to be able to check out an old revision - of this file, use "cvs remove" instead. - - 4. Tags - - Tags take up little space and you can't recover from deleting - them. If you depend on tags for releases you will lose vital - information. - - 5. Directories - - There is no Attic for directories, so the only way to remove - them is to use "rm -r". They are gone forever. - - If you delete (or move) a directory, all checked-out versions - of that directory will cause CVS to halt. You'll have to visit - each checked-out directory and remove the matching working - directory by hand. - - 6. Attic files - - The "remove" command sends files to the Attic. To really - delete them, you have to go into the Attic and use "rm". - - If a file in the Attic has a Tag on it that you might ever want - to check out again, you probably don't want to delete it. - - 7. Lock files (named: "#cvs.[wr]fl.") - - These are lock files. If you are getting "lock" errors and - the dates on the lock files indicate that they are old, you can - delete them. - - Deleting lock files still in use by a CVS process might produce - unusual errors. - - - 4B.11 Can I convert to CVS from RCS without losing my revision history? - - Yes, you can simply move (or copy) your RCS files into a directory - within the Repository, check out that directory and start working. - - - 4B.12 Can I move RCS files with branches in them into the Repository? - - Yes, but they may not work if you created branches in a way that - conflicts with CVS's assumptions: - - 1. You can't use .0. branches. (They are reserved for "Magic" - branch tags.) - - 2. If you use branch 1.1.1, you can't use the Vendor branch. - - You can use other RCS branches under CVS. There is no need to - create "magic" branch tags because the physical branch already - exists. - - - 4B.13 Can I use raw RCS commands on the Repository? - - You can use raw rcs commands directly on the Repository if you - take a little care. The Repository itself contains no "CVS state" - (as opposed to RCS revision histories) outside the CVSROOT - directory. - - But using raw RCS commands to change branches, tags or other - things that CVS depends on may render the files unusable. - - See 4D.7 on RCS/CVS sharing of the Repository and Section 3B on - the "admin" command. - - - 4B.14 How do I convert from SCCS to RCS? - - You'll have to execute something like "sccs2rcs" (in the CVS - contrib directory) on every file. Then you can move the resulting - RCS files into the Repository as described above. - - - 4B.15 How do I limit access to the Repository? - - There are all sorts of ways to restrict access to Repository - files, none of which are hooked directly into CVS. - - Techniques for limiting access include: - - 1. Training, management and good backups. - - The best form of Repository control is a combination of: - - - A reliable backup scheme (verify it!) - - Enough training to ensure your developers are competent - and knowledgeable about all areas of your sources. - - Effective management of the boundaries and grey areas. - - In many cases, technical solutions to "security" problems are - inadequate. You should first try to avoid them. - - Personal Opinion: In an environment where "unknowns" are - allowed to touch important sources the "owner" of the CVS - Repository must be a large, loud, vigorous lout with a - well-balanced truncheon and the right to use it. Don't - underestimate the effectiveness of letting everyone know they - will be strapped into the stocks on the Town Common and pelted - with vegetables if they break something they don't understand - without first asking the experts. - - 2. Set Unix groups and permissions. See 4B.5. - You can set different owners, groups and permissions for each - sub-directory within the Repository if that helps. - - 3. Catch invocations of "commit" by defining pre-commit programs - in the "commitinfo" file. This is fairly powerful, since it - can block commits based on anything you can program. Take a - look at the programs in the "contrib" directory of the CVS - source tree. - - 4. Use multiple Repositories, each with its own protection scheme. - If you use NFS (or AFS) you can even use "export" restrictions - to various groups of machines to keep (for example) the - Engineering Repository off the Customer Service machines. - - 5. Try the "setgid" trick described in 4D.13. - - 6. Try to use the RCS access control lists, though I don't - think CVS will handle them cleanly. - - 7. Edit the source code to CVS to add your own access control. - - - 4B.16 What are the Repository Administrator's responsibilities? - - Generally, the Administrator should set "policy", create the - Repository and monitor its size and control files. - - Some specific responsibilities include: - - 1. Examining the Repository once in a while to clean up: - - a. Trash files left by misguided developers who mistake the - Repository for a working directory. - - b. Non-RCS files. Other than the files CVS needs in the - $CVSROOT/CVSROOT directory, every file in the Repository - should be an RCS file. - - c. Lock files (both CVS '#*' and RCS ',*' files) left around - after crashes. - - d. Wrong permissions, groups and ownerships. - - e. Locked files. (RCS locks, that is.) - - f. Attic files that should never have been under CVS at all. - Don't blindly delete files from Attic directories -- they - were mostly put there (via the "cvs remove") for a reason. - Files that should be deleted are binary files (e.g. '*.o', - 'core', executables) that were mistakenly inserted by - "import -I !". - - 2. Maintaining the modules file. - - 3. Storing site-specific ignore patterns in the - $CVSROOT/CVSROOT/cvsignore file. - - 4. Storing the names of non-standard CVSROOT files (See 4B.2) in - the $CVSROOT/CVSROOT/checkoutlist - - 5. Maintaining the other Repository control files: commitinfo, - loginfo, rcsinfo and editinfo. - - 6. Pruning the history file every once in a while. (Try the - "cln_hist.pl" script in the "contrib" directory.) - - 7. Staying aware of developments on the info-cvs mailing list and - what is available in the FTP and WWW archives. - - 8. Running "ps ax" once in a while and kill off any "update" - programs not running as "root". It is too easy to leave the - "cvs" off the front of the "cvs update" command. - - 9. Executing monitor programs to check the internal consistency of - the Repository files. Ideas: - - a. Files that have a default RCS branch that is not 1.1.1 - (From an abuse of "admin -b".) - - b. Files that have only Revisions 1.1 and 1.1.1.1, with a - default branch of "MAIN". (From an abuse of "admin -o".) - - c. Existing branch tags and various branch consistency checks. - - - 4B.17 How do I move the whole Repository? - - Copy or move the tree. (On Unix systems, a set of piped "tar" - commands works great. If the Repository does not contain any - symlinks, which it normally doesn't, you can also use "cp -r".) - - If you can avoid changing $CVSROOT (i.e. the "logical" pathname of - the Repository) by replacing the old location with a symbolic link - to the new location, you don't have to do anything else. - - (You could also mount the new location on top of the old location - if you are using NFS or some other filesystem that allows it.) - - - If you must change $CVSROOT, you must also tell everyone to change - the CVSROOT environment variable in all running shells and in any - personal configuration files ('.' files on Unix) where it is set. - - The Repository itself contains no references to its own name, - except possibly in some of the files in the CVSROOT directory. If - your modules (or loginfo, commitinfo, etc.) file mentions helper - programs directly in the Repository, you'll have to change the - pathnames to point to the new Repository location. - - The main changes you'll have to make are to all the CVS - administrative files (./CVS/Repository and ./CVS/Root) in every - working directory ever checked out from the previous location of - the Repository you just moved. - - You have three choices: - - 1. If all ./CVS/Repository files in all working directories - contain relative pathnames, you don't have to do anything else. - - 2. Have everyone "release" or delete their working directories - (after committing, or just saving, their work) and check them - all out again from the new Repository after the move. - - 3. Use "find . ( -name Repository -o -name Root )" and a - PERL or shell script to run through all the ./CVS/Repository - and ./CVS/Root files and edit the values in the files. - - - 4B.18 How do I change permissions on a file in the Repository by using - a CVS command? (i.e. without using "chmod 777 $CVSROOT/dir/file") - - When you first "import" or "add"/"commit" a file, the read and - execute bits on the Repository file are inherited from the - original source file, while the write bits on the Repository file - are are turned off. This is a standard RCS action. - - After that, there is no way to alter the permissions on a file in - the Repository using CVS (or RCS) commands. You have to change - the permissions on both your working file and on the Repository - file from which it was retrieved. - - Whenever you "checkout" the file or retrieve a new revision via - "update" (or after a "commit"), your working file is set to match - the permissions of the Repository file, minus any "umask" bits you - have set. - - - ----------------- --- Section 4C -- Branching and Merging ----------------- - - **** Questions: - - 4C.1 What is a branch? - 4C.2 Why (or when) would I want to create a branch? - 4C.3 How do I create and checkout a branch? - 4C.4 Once created, how do I manage a branch? - 4C.5 Are there any extra issues in managing multiple branches? - 4C.6 How do I merge a whole branch back into the trunk? -=4C.7 How do I merge changes from the trunk into my branch or between - branches? - 4C.8 How do I merge onto the Main Branch a file that exists only on a - branch other than the Main Branch? (i.e. it is in the Attic) - 4C.9 How do I know what branch I'm (working) on? - 4C.10 Do I really have to know the name of the branch I'm working on? - 4C.11 How do I refer to the revision where I branched so I can see - what changed since the Branch Point on another branch? - 4C.12 Why didn't the command "cvs admin -bBRANCH1 *" create a branch? - 4C.13 Is it possible to set the "default CVS branch" for everyone? - 4C.14 How do I perform a large merge? - 4C.15 Is a Vendor merge any different from a branch merge? - 4C.16 How do I go back to a previous version of the code on a branch? - 4C.17 Once I've found the files I want, how do I start changing them? - I keep getting warnings about sticky tags. - 4C.18 Why do I get the latest files on the branch when I tried to - "update -r "? - 4C.19 How can I avoid a merge? I just want to move the latest revision - on my working branch directly onto the trunk. - 4C.20 How to I avoid merge collisions in the RCS $\Log$ data? - 4C.21 Why should I trust automatic merges? - 4C.22 How does CVS decide if it can safely perform a merge? - 4C.23 After resolving merge conflicts in a file, what if I want to keep - my previous version, and not take any of the branch changes? - - - **** Answers: - - 4C.1 What is a branch? - - Unfortunately, the word "branch" is an overloaded technical term. - It is used in too many different ways in three categories. It - might help to understand some of the issues by going through - the categories: - - 1. How Humans use the word "branch": - - Most development starts with everyone working on the same - software, making changes and heading toward a single goal. - This is called something like "Main Line Development". Note - that though many people do main line development on CVS's - "Main Branch", that is a choice, not a requirement. - - After a release or when one or more developers want to go off - and work on some project for a while, the Software Engineers - assigned to deal with large software issues generate a "Branch - in Development" to support the release or project. (Keep in - mind that a programmer is no more a Software Engineer than a - carpenter is a Civil Engineer.) - - Essentially, the word "branch" implies a way to allow - simultaneous development on the same files by multiple people. - - The above terms are human-oriented. They refer to actions - that people would like to take. They do *not* imply any - particular implementation or set of procedures. Branches in - development can be supported in many different ways. - - - 2. How CVS uses the word "branch": - - CVS uses the word "branch" in a number of ways. The two most - important are: - - - The vendor branch holds releases from (normally) an - outside software vendor. It is implemented using a - specific RCS branch (i.e. 1.1.1). - - - The "Main Branch", which normally holds your "Main Line - Development", but is defined as the collection of - revisions you get when you "checkout" something fresh, or - when you use the '-A' option to "update". - - Important Note: The CVS "Main Branch" is *not* the same as - the RCS concept with the same name. If you are using Vendor - Branches, files you have never changed are on three branches at - the same time: - - - The RCS 1.1.1 branch. - - The CVS Vendor branch. - - The CVS "Main Branch". - - The concepts overlap, but they are not equivalent. - - In referring to CVS, "branch" can be used in four other ways: - - - A CVS working directory satisfies the definition of - "branch" for a single developer -- you are on a private - "virtual branch" that does not appear in any of the RCS - files or the CVS control files. - - - The CVS "default branch" is the Repository source for the - collection of files in your working directory. It is - *not* the same as the RCS "default branch". Normally the - CVS default branch is the same as the CVS Main branch. If - you use the "-r " option to the "checkout" - command, you will record a "sticky" tag that changes your - default branch to the one you checked out. - - - A "magic" branch can be a branch that hasn't happened - yet. It is implemented by a special tag you can check out - that is not attached to a real RCS branch. When you - commit a file to a magic branch, the branch becomes real - (i.e. a physical RCS branch). - - - And, of course, CVS uses "branch" to indicate a - human-oriented "branch in development". - - 3. How RCS uses the word "branch": - - - The RCS "Main Branch" (Synonym: "The Trunk") contains a - series of two-part revision numbers separated by a single '.' - (e.g. 1.2). It is treated specially and is the initial - default branch. (The default default?) - - - The RCS "Default" branch starts out attached to the RCS "Main - Branch". For RCS purposes, it can be changed to point to any - branch. Within CVS, you *must*not* alter the RCS default - branch. It is used to support the CVS idea of a "Main - Branch" and it must either point to the RCS Main Branch, or - the Vendor Branch (1.1.1) if you haven't made any changes to - the file since you executed "import". - - - 4C.2 Why (or when) would I want to create a branch? - - Remember that you can think of your working directory as a - "branch for one". You can consider yourself to be on a branch - all the time because you can work without interfering with others - until your project (big or small) is done. - - The four major situations when you should create a branch: - - 1. When you expect to take a long time or make a large set of - changes that the merging process will be difficult. Both - "long" and "large" are defined in your own environment. - - 2. When you want to be able to "commit" and "tag" your work - repeatedly without affecting others. - - If you ever think you need Source Control for your own work, - but don't want your changes to affect others, create a private - branch. (Put your username in the branch tag, to make it - obvious that it is private.) - - 3. When you need to share code among a group of developers, but - not the whole development organization working on the files. - - Rather than trying to share a working directory, you can move - onto a branch and share your work with others by "committing" - your work onto the branch. Developers not working on the - branch won't see your work unless they switch to your branch or - explicitly merge your branch into theirs. - - 4. When you need to make minor changes to a released system. - - Normally a "release" is labeled by a branch tag, allowing later - work on the released files. If the release is labeled by a - non-branch tag, it is easy to add a branch tag to a previously - tagged module with the "rtag" command. If the release is not - tagged, you made a mistake. Recovery requires identifying all - revisions involved in the release and adding a tag to them. - - - 4C.3 How do I create and checkout a branch? - - Suggested technique: - - 1. Attach a non-branch tag to all the revisions you want to - branch from. (i.e. the branch point revisions) - - 2. When you decide you really need a branch, attach a branch tag - to the same revisions marked by the non-branch tag. - - 3. "Checkout" or "update" your working directory onto the branch. - - - A. Suggested procedure when using modules: - - 1. cvs rtag module - 2. cvs rtag -b -r - 3. cvs checkout -r module - - - B. Suggested procedure when using your working directory, which - contains the revisions of your working files you want to branch - from: - - 1. cvs tag - 2. cvs rtag -b -r - 3. cvs update -r - - - In each procedure above, Step #1 applies a non-branch tag to all - the branch point revisions in the module/directory. Though this - is not strictly necessary, if you don't add a non-branch tag to - the revisions you branch from, you won't be able to refer to the - branch point in the future. - - Between steps 1 & 2 you may commit changes. The result would be - same because "rtag -r " applies to the - same revision that is attached to. You can use this - technique to avoid attaching *any* branch tags until you need - them. - - Step B.2 has two corollaries: - - 1. If you plan to create the branch tag before committing - anything in your working directory, you can use "cvs tag -b - " instead of the "rtag" command. - - 2. The can be a relative path to a directory - from which your working directory was checked out. - - If you have trouble figuring out what to use (or - pathname to use in its place), you can aim it at whatever - parent directories you believe will cover all your work. - - If you are sure the is not being used anywhere - else, you can even aim it at the whole Repository ($CVSROOT), - if you have to. It might take some extra time, but assuming - that your is a unique string and you don't use the '-f' - option to "rtag -r", "rtag" will only add a to files in - which it actually *finds* the earlier . - - In each procedure above, Step #3 may occur any time after step 2. - Unless you explicitly remove them with "tag -d", a is - permanent. - - - The is an unusual creature. It labels a branch in a - way that allows you to "checkout" the branch, to "commit" files to - the end of the branch and to refer to the end of the branch. It - does not label the base of the branch (the branch point). - - There are two obvious ways to choose the and - names. But keep in mind that the is - typed by any developer who wants to work on the branch -- you - should make it mean something to them. - - Style #1 presumes that the simple version string refers to a set - of designed, documented or promised features, not to a specific - set of files. In this case, you tag the branch with the generic - Version string and assume that whenever you refer to "Version", - you want the "latest" set of files associated with that Version, - including all patches. (You can substitute whatever you like for - "bp_", as long as your is some modification of - the .) - - Matching - - bp_V1_3 V1_3 - bp_Release2-3-5 Release2-3-5 - bp_Production4_5 Release4_5 - - - Style #2 presumes that the simple version string refers to the - specific set of files used to construct the first release of - "version". In this case, you tag the branch-point revisions with - the generic Version string and assume that whenever you refer to - this Version, you want the original set of released revisions. To - get the latest patched revisions of the release, you refer to the - branch tag "latest_". (You can substitute what - ever you like for "latest_", as long as your is some - modification of the .) - - Matching - - V1_3 latest_V1_3 - Release2-3-5 latest_Release2-3-5 - Release4_5 latest_Production4_5 - - - In both styles you can find out what you had to change since the - original release of this Version by typing: - - cvs diff -r -r - - For Style 1, this is: - - cvs diff -r bp_ -r - - For Style 2, this is: - - cvs diff -r -r latest_ - - - Notes on "being on a branch": - - - "update -r " tells CVS to attach a "sticky tag" to - working directory (in ./CVS/Tag) and the checked-out files (on - each line of ./CVS/Entries). - - - A "sticky" (including a ) causes most CVS - commands to act as if "-r " were on the command line. - - - A "sticky" indicates that the working directory - (and working files) are "on the branch". - - - 4C.4 Once created, how do I manage a branch? - - The most important thing you should know about managing a branch - is that the creation of a branch is not a lightweight act. When - you create a branch, you must also create a set of procedures to - keep track of it. - - Specifically, you must: - - - Remember that the branch exists. (This is non-trivial if you - create a lot of them.) - - - Plan when to merge it back into the main line of development. - - - Schedule the order that multiple branch merges are to be done. - - - If you ever intend to merge branches into each other, instead of - limiting merges of branch work back into the "main line", you - must keep careful track of which parts of which branches have - merged into which other branches. - - - The simplest way to deal with branches is to limit their number, - "collapse" them back into the main line as quickly as is - reasonable and forget them. If a group wants to continue working, - tell them to create another branch off the fully merged main line. - - Remember that CVS is just a tool. Over time, it will probably - handle branching better, requiring less careful attendance. - But no matter how good it becomes, the whole idea of "branching" - is a complicated management problem. Don't take it lightly. - - - 4C.5 Are there any extra issues in managing multiple branches? - - If you plan to split from the "main line" and merge back after a - time, the only problem will be scheduling the order of branch - merges. As each branch is merged, the main line must be rebuilt - and tested. Merging multiple branches (i.e. "lines of - development") before building and testing creates more problems - than you are ready for. - - If you plan to collapse some branches into others, then move the - combined branches back into the main line, you have to be careful - with the revisions and tags you hand to your "update -j" - command, but it shouldn't be much trouble. - - If you plan to allow every branch to incrementally take the work - done on other branches, you are creating an almost insurmountable - bookkeeping problem. Every developer will say "Hey, I can - handle taking just this little bit," but for the system as a - whole it is disaster. Try it once and see. If you are forced - into this situation, you will need to keep track of the beginning - and end points of every merge ever done. Good Luck. - - - 4C.6 How do I merge a whole branch back into the trunk? - - If you don't have a working directory, you can checkout and merge - in one command: - - cvs checkout -j - cd - - If you already have a working directory: - - cd - cvs update <== Optional, to bring it up to date. - cvs update -j - - CVS will print lines beginning with - - 'U' for files that you hadn't changed, but the branch did. - - 'M' for files that you changed and the branch didn't - *and* for files that you both changed that were merged - without overlaps. (This overload is unfortunate.) - - 'C' for files that you both changed in a way that conflicts - with each other. - - You need to go edit all the 'C' files and clean up the conflicts. - Then you must commit them. - - -=4C.7 How do I merge changes from the trunk into my branch or between - branches? - - The idea is similar to the above, but since CVS doesn't treat the - main branch like other branches, you'll have to be more careful. - There are 5 different ways to look at the problem. - - A. The way to merge *all* changes made on the trunk into a working - branch is to move to the branch you want via "checkout -r" or - "update -r": - - cvs update -r {optional files} - - Then merge the changes from the trunk into your working branch - using the pseudo-tag named "HEAD": - - cvs up -j HEAD {optional files} - - You will get everything from the branch point of the branch - named up to the HEAD of the main branch. This is - still kind of strange. If the file is on a branch, HEAD should - be the latest thing on the branch, not the HEAD of MAIN. But - that's not the way CVS (currently) works. - - If you run "cvs up -j HEAD" again after adding more revisions - to the trunk, you may get overlaps for the text you have - already merged. It depends on your version of your RCS "merge" - command (actually the "co -j" option, which depends on the - version of "diff3" you configured RCS to use). - - - B. You can merge the difference between any two using - two "-j" options on "update" or "checkout". - - Identify the two tags on the branch you want to merge from. - - cvs update -j -j {optional files} - - This step assumes you were careful about tagging milestones. - You can use this technique for any two on the same - branch, even the trunk. It is also possible to use tags on - different branches, but you'll have to ponder the meaning of - the difference between those two tags. - - In place of one of the , you can use a to - refer to the latest revision on that branch. See 4C.11 and - 4C.3 for info on branch points. - - Merges can also be performed by handing RCS revisions to the - '-j' options, but since revision numbers aren't the same in all - files, merging by number is normally limited to one file. Sets - of files with the exact same trees of branches and revision - numbers would work too, but that's a rare situation. - - - C. To "take" revisions from other branches instead of merging - them, see 4C.19 for an idea. - - - D. A way to gain the effect of merging the main to the branch is - to merge the branch into the main using the normal - - cvs update -A {optional files} - cvs update -j {optional files} - cvs commit - cvs tag -F -b {optional files} - - See part B of 4D.5 - - - E. Other oddities. - - This also works, but is probably not officially supported: - - cvs update -j N {optional files} - - where N is a number. This will merge all the changes from the - branch point up to the highest revision on the main branch - starting with N. For example, if your highest trunk revision - is 1.52, you can use this to grab revisions from the trunk: - - cvs update -j 1 {optional files} - - Another example: Say you have a branch point at rev 1.2 for a - branch named "BR1" and trunk revisions 1.3, 1.4, 2.1, 2.2, 2.3, - 3.1, 3.2. Then: - - cvs update -j 1 {optional files} - - will merge the changes from 1.2 to 1.4 - - cvs update -j 2 {optional files} - - will merge the changes from 1.2 to 2.3 - - cvs update -j 3 {optional files} - - will merge the changes from 1.2 to 3.2, which in this example, is - equivalent to the use of "-j HEAD" in part A above. - - The intuitive (at least to me): - - cvs up -j MAIN (or TRUNK) {optional files} - - doesn't work. If the trunk (i.e. "main branch") had an - implicit branch named "MAIN", you could use: - - cvs up -j MAIN:10/26 -j MAIN:now {optional files} - - and refer to date-stamped revisions on the trunk using the - : support that works on other branches. - - You might also think you could place an explicit tag on branch - 1 (or higher) (e.g. MAINHACK:1) and use it in place of the - implicit "MAIN", but I haven't found the right combination. - - [[If you find working techniques, I'll add them here.]] - - - 4C.8 How do I merge onto the Main Branch a file that exists only on a - branch other than the Main Branch? (i.e. it is in the Attic) - - For how such a file can exist, see 3A.2 and 3A.3. - - For how to avoid creating such a file, see 3A.5. - - Though you might think that the "update -j" command could perform - the "merge" of a file from the side branch to the Main Branch, it - isn't (yet) smart enough. Unfortunately, there is no single CVS - command to do this -- it takes three steps: - - 1. To move something onto the Main Branch from the Attic, you have - to physically move the file from the Attic to the main - Repository directory associated with your working directory. - - It is exactly like resurrecting a removed file. See 3L.4 - - I use something like this: (csh-like syntax) - - set repos = `cat ./CVS/Repository` - mv $repos/Attic/filename,v $repos/filename,v - - (If you use relative paths in your Repository files, that first - line becomes: set repos = $CVSROOT/`cat ./CVS/Repository`) - - 2. Now that the file is physically in the right place within the - Repository, "update -A" will make it appear in your working - directory on the Main Branch. Do that now. - - 3. You now have a choice. The act of physically moving the file - has fused together the branch and the Main Branch - for this file. You can continue that way, making changes along - the RCS Main Branch which CVS will (for this type of file only) - treat as both the Main Branch and the branch. - - The other choice, which I would suggest, is to re-tag the file - with , restoring a normal-looking magic branch tag - to the file: - - cvs tag -F -b - - - After you have done the above, you can run "update -A" or "update - -r " to resume whatever you were doing before you - started this procedure. - - Caveat: The final result is a file whose revision tree doesn't - look like it was ever on any branch but the Main Branch until the - above "tag -F -b" command was executed. CVS and RCS have no way - of saving the history of the actions you have just performed. - - - 4C.9 How do I know what branch I'm (working) on? - - Type: - cvs status - - and look at the "Sticky Tag" field for each file. If: - - 1. The *same* tag is on *every* file in your working tree, *and* - 2. That tag matches the contents of the ./CVS/Tag file, *and* - 3. That tag is a branch tag, - - then you know what branch you are working on. You can get sticky - Tag information directly from the ./CVS/Entries file instead of - "cvs status". - - If all the sticky Tags don't agree, then your directory is - temporarily inconsistent. This is a feature allowing you to make - changes (or perform merges) to individual files on multiple - branches without checking out the whole directory. - - The sticky Tag on each file in the ./CVS/Entries file (as - displayed by the "status" command) indicates what branch the - working file is on. New files are added to the Tag stored - in ./CVS/Tag. - - To force your entire working directory onto the same branch, type: - - cvs update -r - - - 4C.10 Do I really have to know the name of the branch I'm working on? - - If a developer can't be relied on to know what branch of - development to work on, then either the developer's manager - isn't planning branches properly or the developer has serious - problems. - - I have found that one of the hardest concepts to get across to - developers (and some managers) is that "a branch in development" - (as opposed to the use of RCS branches to support some other - scheme) is a heavyweight act. Every time you create a real branch - in development, you must spawn a set of managerial procedures and - a schedule by which you plan to merge each branch into each other - branch. Unless you plan to keep it simple and collapse (by - merging and forgetting) branches quickly, they are not to be - created lightly. - - In other words, if you don't regularly attend group meetings in - which the branch to be worked on is a major topic of discussion, - then the group is not managing branches properly. - - We created a couple major branches a few months ago and even the - customer service people refer to the "XYZ branch" as a shorthand - for "continuing development on the XYZ project". - - - 4C.11 How do I refer to the revision where I branched so I can see - what changed since the Branch Point on another branch? - - Given the current format, there is no direct way to - refer to the branch point, which is more useful in many ways - than referring to the branch, which always refers to the latest - revision on the branch. - - When CVS adds a branch tag, it attaches an RCS symbol to a - non-existent revision number containing the revision number of the - branch point as a prefix. (See Section 3O, on the "tag" command.) - RCS can't use the CVS magic branch tag and many of the CVS - commands can't refer to it. - - To be certain of your ability to refer to a branch point, you must - create a "branch point" tag at the same time as the Branch tag. - See 4C.3. - - - 4C.12 Why didn't the command "cvs admin -bBRANCH1 *" create a branch? - - Because your command creates an RCS branch, not a CVS branch. See - the above discussion on branches. RCS branches are used to - support CVS branches, but they are not the same. You can't act as - if you have direct control over the RCS files. - - The "admin" command was placed there as a convenience to allow - you to execute raw "rcs" commands on the Repository, taking - advantage of CVS's ability to find the files in the Repository. - - But you have to remember that you are using RCS commands on a - CVS Repository, which is not generally safe unless you know - exactly what CVS depends on. - - For one thing, CVS insists on control of the default branch. It - is set either to the Main branch or the Vendor branch depending - on whether you have changed the Vendor's code. If you change - the default branch, you are monkeying with the internals and - you will get unexpected results. - - To set your "default CVS branch" to BRANCH1, you must use - "checkout" or "update" with the "-r BRANCH1" option. Then you - have changed CVS's idea of your "default branch", which has - little to do with RCS's default branch. - - - 4C.13 Is it possible to set the "default CVS branch" for everyone? - - No. It doesn't work that way. - - When using CVS, all administrative information (such as what - branch you checked out) is stored in CVS sub-directories, local to - the user. There is no global state, other than the description - and logging files in the $CVSROOT/CVSROOT directory. - - You tell "checkout" or "update" what branch you want to check out - via the "-r " option. The default is CVS's "Main Branch". - - I don't see a problem in *designing* a new way to indicate what - branch you get by default, instead of the main one, but that's not - how it currently works. - - - 4C.14 How do I perform a large merge? - - Large merges require a bit more planning to be able to track - what has happened in the inevitable cases where something goes - wrong. No tool can force a "merge" to make perfect sense. - - Though you can handle the details in many different ways, the two - ends of the spectrum of merge techniques are: gonzo and paranoid. - - A. The gonzo method assumes that you know everything about your - sources so that recovery from failures is "just a matter of - typing." You created the branch this way: - - cvs checkout - cd - cvs tag -b - cvs update -r - >>> Edit away. - cvs commit <<== Onto branch - - Now you want to merge your branch back into the Main branch, - you are certain you can make it work, or at least detect all - the failures, so you dive in and hack away: (For simplicity, we - will assume you are collapsing (i.e. merging and forgetting) a - side-branch into the Main branch from your single working - directory.) - - cvs update -A - cvs update -j - >>> Edit the 'C' files and remove the overlaps. - >>> Edit some more to make it all compile and work. - cvs commit - - Looks simple. For more details on the output from the - "update -j" command, see 3P.2 and 4C.6. - - Note: You could also checkout a whole new working directory and - perform the merge at the same time by replacing the two - update commands with these two commands: - - cvs checkout -j - cd - - - B. The paranoid way is more difficult, but it can catch all sorts - of problems. You created the branch this way: - - cvs checkout - cd - cvs tag - cvs tag -b - cvs update -r - >>> Edit away. - cvs commit <<== Onto branch - - The extra tag command places a non-branch tag on the Branch - Point, an act that makes it easier to do "diffs" later. Now we - decide to perform the merge: - - cvs tag - cvs update -A - *1* cvs diff -r -r - >>> *1* shows all the changes on the branch. - *2* cvs diff -r -r HEAD - >>> *2* shows the changes on the trunk since branching. - cvs tag - cvs update -j - >>> Edit the 'C' files and remove the overlaps. - *3* cvs diff - >>> Verify that *3* matches *1*, except for line numbers. - cvs commit - cvs tag - >>> Edit some more to make it all compile and work. - cvs commit - cvs tag - - - The reason *3* and *1* match so closely is that they are the - differences between two pairs of starting points and ending points - after the same data was inserted. If they are significantly - different, you will want to figure out why. - - NOTE: You will have to tell everyone to stay the hell out of the - Repository while you do this. If they commit something while you - are in the middle of a merge, your job will be much more - difficult. If they "update" at the wrong time, their work will - be randomized until you finish. It's better to call a halt. - - See 3H.13 for some more information about dealing with merges - after import. The last part of the procedure is applicable to any - large merge. - - - 4C.15 Is a Vendor merge any different from a branch merge? - - No. In most ways, a Vendor branch is exactly the same as any - other branch. In a Vendor merge, the data is append to the branch - by the "import" command, rather than by hand-editing, but the - merge process is the same. - - See the "import" command in section 3H. - - - 4C.16 How do I go back to a previous version of the code on a branch? - - You can avoid digging into RCS revision numbers (executing "update - -r " on each file) by trying one of these: - - 1. Use non-branch tags as you normally would. Non-branch tags - attach to specific revisions, so a "tag " command would - mark the revisions you have in your working directory, which - are on your branch. If you need to retrieve them, use "update - -r " - - Doing this overrides the sticky attached to your - working directory with a non-branch tag, which means you won't - be able to commit until you again move forward to the end of - the branch with "update -r ". - - 2. Use the "update -r :" trick. - - This is almost like using the '-D' option, but it looks for - revisions extant on only along the given branch. - - As in #1, you can't commit to this kind of working area, - because it has a sticky date referring to revisions in the - middle of a branch. - - - 3. You can branch a branch. - - If you add a branch tag to file in a working directory that was - checked out on a branch, you will branch the branch. This - works just fine, though you'll have to play some games to merge - everything back together again. You'll also create 6-part - revision numbers. (They'll be 8-part revision numbers if you - branch a branch that started out with some unmodified files on - the Vendor branch. Think about it. How does revision - 1.2.4.2.4.2.2.1 grab you?) - - - 4C.17 Once I've found the files I want, how do I start changing them? - I keep getting warnings about sticky tags. - - What you probably did was type "cvs update -r " where - is a non-branch tag. "update" created a sticky tag for a specific - revision, not a branch. To start working right there, you have to - create a branch to work on. - - You have two choices. - - A. You can do it in place and keep working: - - cvs tag -b <<== To tag the current files. - cvs update -r <<== To move onto the branch. - - B. You can do it "externally" and create a new working directory: - - cvs rtag -b -r - cvs checkout -r - - can be a relative path within the Repository. - - in the above is the non-branch tag you placed earlier - that caused the error in your question. Be warned that - if is not set on all the files (or all the right - revisions) you won't get exactly what you wanted. - - - 4C.18 Why do I get the latest files on the branch when I tried to - "update -r "? - - If "update -r " always retrieves the latest files on a - branch, then is really a . A branch tag is - supposed to be used to grab a branch to work on. Since you can't - modify a file in the middle of a branch, checking out a - will give you the latest revision on the branch. - - If you want to "checkout" a specific collection of revisions, you - must use a "non-branch" tag. See the first part of 4C.16. - - - 4C.19 How can I avoid a merge? I just want to move the latest revision - on my working branch directly onto the trunk. - - There is no direct way to do this using CVS, though the technique - is not difficult using shell commands. Here's one way: - - 1. Move your working directory to the Main Branch. - - cvs update -A - - 2. Use "update -p" to grab the latest revision on the branch and - write it over your working files. Make sure you don't have an - modified files -- you will lose them. The following is in - "csh" syntax. Change the wildcard to grab the files you want - - foreach i (Makefile *.cc *.hh) - cvs update -p -r $i > $i - end - - 3. Commit all the working files onto the Main Branch. - - cvs commit -m 'Moved branch onto MAIN' - - You should experiment with the above before blasting everything. - - - 4C.20 How to I avoid merge collisions in the RCS $\Log$ data? - - In short, you can't. The RCS $\Log$ keyword is handled - differently from all other RCS keywords. - - On the info-cvs mailing list, there is a periodic discussion that - goes something like this: - - Question: How do I deal with $\Log$? - Answer1: You can't do much with it. Here's how it works. . . - Answer2: I've found a limited way to use it. . . - Answer3: Get rid of it. $\Log$ is an abomination. - - I tend to lean toward answer #3. There are only two sets of - people who would ever have access to logs stored within sources - files, developers and source customers. - - For developers: - - 1. Log entries within sources files are notoriously incomplete, - rushed, poorly phrased and in many cases incorrect, making them - useless for debugging or file maintenance. I remember a maxim - from "Software Tools" (I believe): "Read the code, not the - comments." No managerial order or plan for programmer - discipline will affect this in the real world. - - 2. Log entries are usually in an unreadable mixture of styles. - Many log entries are just plain meaningless. Some are foolish. - Some are even insulting. Examples: - - "Corrected spelling of misspelling." - "Bug fix." - "Reversed stupid change in previous revisions." - "If Joe could do his job, this would already have worked." - - 3. Log entries are not managed well by the tools. Any merge can - cause conflicts in the $\Log$ data. Branch merges produce - incomplete logs. They can be edited into chaos and they are - not regenerated. They waste space duplicating information - available to the developer with a single command. - - 4. Even if correct when originally entered, as changes are made to - the file, log entries become false over time. Humans are not - good at reading down through a list and remembering only the - last change affecting something. Over time *most* of the log - is wrong. - - 5. Even if still correct, the log data is almost useless to - developers without the code diffs. If you can get code diffs, - you can display the log. - - - For source customers the problem is even worse. The last thing - you want to show customers is a hodge-podge of tiny comments about - large changes followed by a series of emergency fixes before - delivery. If you distribute sources, then you should provide - documentation, or changelogs reviewed by people who won't let - comments like "Fixed for stupid customer." out the door. - - Conclusion: Though some people would prefer to see in this FAQ - techniques for making the $\Log$ entries the best they can be, I - believe them to be a lost cause. My suggestion is to hunt down, - root out and destroy all occurrences of $\Log$ and the unusable - data attached to it wherever you may find it. - - - 4C.21 Why should I trust automatic merges? - - Some developers have the feeling that three-way merging doesn't - work. They fear and distrust the way the "update" command - automatically merges committed changes from the Repository into - the working file. - - Experience has shown that most merges are utterly painless and - most of the rest are easily resolved. The few conflicts that - cause headaches are nearly all due to poor communication between - developers, a problem no source control system can obviate. - - Some developers were troubled in the past by flaky Unix software. - I can't say that everything is perfect, but the tools CVS depends - on (RCS and diff, mainly) are fairly solid nowadays. They work. - - Since it does seem to work for most of us, the algorithm is - unlikely to change soon. Why not test it on a couple trouble - spots and if it works for you, use it for a while? Then you can - make an informed decision. - - - 4C.22 How does CVS decide if it can safely perform a merge? - - CVS can merge any text file, possibly discovering a conflict and - leaving overlaps for you to edit. Editing the conflict markers - out of the file is a moment's work, but resolving the conflict - could take an arbitrary amount of time. CVS works to determine if - it *should* merge, not if it *can*. - - See 2B.6 for how the merge proceeds. - - - 4C.23 After resolving merge conflicts in a file, what if I want to keep - my previous version, and not take any of the branch changes? - - If you want to retain your previous version, a version on the - MAIN branch greater than 1.1 (one you committed there), just throw - the merged file away and "cvs update" the file. - - You don't need to commit something to remember it. The tags you - place before and after the merge should give all the handles you - need to find various versions. You don't have to create a new - version of the file. - - If you want to retain the previous Vendor revision, you can grab a - copy of it using "cvs update -p" and commit it or use the - technique described in 3B.3 to revert back to the Vendor branch. - - - ----------------- --- Section 4D -- Tricks of the Trade ----------------- - -This section covers topics ranging from simple ideas that occur to every -CVS user to time-saving procedures I consider difficult to understand. - -Some are therefore dangerous. Avoid anything you don't fully understand. - - - **** Questions: - - 4D.1 How can you even check in binary files, let alone allow CVS to - do its auto-merge trick on them? - 4D.2 Can I edit the RCS (",v") files in the Repository? - 4D.3 Can I edit the ./CVS/{Entries,Repository,Tag} files? - 4D.4 Someone executed "admin -o" and removed revisions to which - tags/symbols were attached. How do I fix them? - 4D.5 How do I move or rename a magic branch tag? - 4D.6 Can I use RCS locally to record my changes without making them - globally visible by committing them? - 4D.7 How can I allow access to the Repository by both CVS and RCS? - 4D.8 I "updated" a file my friend, "bubba", committed yesterday. - Why doesn't the file now have a modified date of yesterday? - 4D.9 While in the middle of a large "commit", how do I run other - commands, like "diff" or "stat" without seeing lock errors? - 4D.10 Where did the ./CVS/Entries.Static file come from? What is it for? - 4D.11 Why did I get the wrong Repository in the loginfo message? - 4D.12 How do I run CVS setuid so I can only allow access through the - CVS program itself? - 4D.13 How about using groups and setgid() then? - 4D.14 How do I use the "commitinfo" file? - 4D.15 How do I use the "loginfo" files? - 4D.16 How can I keep people with restrictive umask values from blocking - access to the Repository? - 4D.17 Why do timestamps sometimes get set to the date of the revision, - sometimes not? The inconsistency causes unnecessary recompiles. - - - **** Answers: - - 4D.1 How can you even check in binary files, let alone allow CVS to - do its auto-merge trick on them? - - If you configure RCS and CVS to use the GNU version of diff with - the '-a' option, CVS and RCS will handle binary files. See - section 4A for configuration info. - - You may also need to apply the '-ko' flag to the files to avoid - expanding RCS keywords, which can be done via: - - cvs admin -ko filename - - - The only real problem occurs when "cvs update" attempts to merge - binary revisions committed elsewhere into a modified working file. - This can be a particular problem if you are trying to use CVS on - Frame or Interleaf (document processing systems) that produce - non-text output. - - See 3C.8 for a way to serialize access to binary files. - See 3A.8 for adding binary files, 3H.4 for importing binary files - and 3B.4 for some more information about "admin". - - - 4D.2 Can I edit the RCS (",v") files in the Repository? - - Yes, but be very careful. The RCS files are not free-form files, - they have a structure that is easily broken by hand-editing. The - only time I would suggest doing this is to recover from emergency - failures that are difficult to deal with using CVS commands, - including the "admin" command, which can talk directly to RCS. - - Though no one actively encourages the editing of RCS files, many - people have succumbed to the urge to do so when pressed for time. - The reasons given, usually with evident contrition, include: - - - Editing mistakes in, or adding text to, log entries. (If you - have RCS 5.6 or later, you should use `cvs admin -m'.) - - Renaming or moving symbolic names. (You should `cvs admin -N' - instead.) - - Unlocking a file by changing the "locker" from someone else to - yourself. (It's safer to use `cvs admin -u -l'.) - - Making global changes to past history. Example: Eradicating - former employees names from old documents and Author entries. - (And someone thought the "history" command was evidence of Big - Brother! I never realized how much help a wide-open revision - control system could have provided to The Ministry of Truth.) - - - 4D.3 Can I edit the ./CVS/{Entries,Repository,Tag} files? - - Yes, but with CVS 1.3 and later, there is almost no reason to edit - any of the CVS administrative files. - - If you move pieces of your Repository around it can be faster to - edit all the ./CVS/Repository files rather than checking out a - large tree. But that is nearly the only reason to do so. - - - 4D.4 Someone executed "admin -o" and removed revisions to which - tags/symbols were attached. How do I fix them? - - It depends on what you mean by "fix". I can think of three ways - to fix your predicament: - - - 1. Remove the tags. - - Assuming you really wanted to get rid of the revision and its - associated tags, you can remove them with the "admin" command. - The "tag -d" command will only remove tags attached to existing - revisions. You can remove a tag, even if it is attached to a - non-existent revision, by typing: - - cvs admin -N - - 2. Retrieve the outdated revision. - - You should first look in your backup system for recent versions - of the file. If you can't use them, you can carefully extract - each revision that followed the earliest outdated revision - using RCS (or "cvs admin") commands and reconstruct the file - with all the right revisions, branches and tags. This is a lot - of work. - - You *can't* insert a revision into the current RCS file. - - 3. Move the Tags to another revision in each file. - - If you want to move the tags to another valid revision, you - have two choices, both of which require that you find all the - revision numbers of the files you want to "tag" and execute the - following command sequences on each . - - a. Use "update" to grab the revision you want, then - execute a normal "tag" command to Tag that revision: - - cvs update -r - cvs tag - - b. Use "admin" to set the tag to a specific revision: - - cvs admin -N: - - - 4D.5 How do I move or rename a magic branch tag? - - (To rename a non-branch see 3O.9.) - - Before reading this, read 3M.3 and 3M.4 and understand exactly - how tag and rtag use '-r' and why it won't do the right job here. - - A. First, I have to explain exactly what a magic branch tag is. - - A magic is an artificial tag attached to a - non-existent revision on a non-existent branch number zero. It - looks like this: - - TAG1:.0.Y - - is the "branch point revision", a normal revision with an - odd number of '.'s in it. (e.g. 1.5, 1.3.1.6, etc) - - Y is an even number (e.g. 2, 4, 6, etc.) All CVS branches, - other than the Vendor branch, are even numbered. - - TAG1 is considered by CVS to be attached to revision . The - first "update -r TAG1 " after applying TAG1 will produce - a copy of revision with a sticky tag of TAG1. The first - "commit" to that file will cause CVS to construct an RCS branch - named .Y and check in revision .Y.1 on the new branch. - - Note: TAG1 is *not* considered to be attached to by RCS, - which explains why you can't refer directly to the branch point - revision for some CVS commands. - - - B. Moving a magic is the act of reapplying the same - tag to different revisions in the file: - - TAG1:.0.Y - to - TAG1:.0.Z or TAG1:.0.B - - You can move a magic branch tag to the revisions of your choice - by using "update" to find the revisions you want to tag and - reapplying the tag to all the files with the '-F' option to - force it to move the existing . - - cvs update -r (or '-A' for the Main Branch) - cvs tag -F -b - - If the earlier location of TAG1 refers to a physical branch - within any RCS file, moving it will make the existing branch in - the file seem to disappear from CVS's view. This is not a good - idea unless you really want to forget the existence of those - RCS branches. - - If the "update" above retrieves the original branch point - revision (), the "tag" command above will create the tag: - - TAG1:.0.Z - - Where Z is 2 greater than the highest magic branch already on - revision . The TAG1 branch will still have the same branch - point (i.e. revision ), but the first commit to the new TAG1 - branch will create a different RCS branch number (.Z instead - of .Y). - - - C. Renaming a magic is the act of changing - - TAG1:.0.Y - to - TAG2:.0.Y - - There is no harm in changing a tag name as long as you forget - that TAG1 ever existed and you clean up any working directories - with sticky TAG1 tags on them by using "update -A", "update -r - " or by removing the working directories. - - On the other hand, actually changing the tag is not easy. - - See 3M.3 for why the seemingly obvious solution won't work: - - cvs tag -b -r - - The only direct way to rename a magic tag is to use the "admin" - command on each file: (You might want to use '-n'. Read "man - rcs" and look at the '-n' and '-N' options.) - - cvs admin -N: . - cvs tag -d - - But you have to be careful because "admin" is different from - other CVS commands: - - 1. "admin" can be used recursively, but only by specifying - directory names in its argument list (e.g. '.'), - - 2. Where "rtag -r " would interpret - as a magic CVS branch tag, "admin" is a - direct interface to RCS which sees a magic branch tag as - a simple (though non-existent) RCS revision number. - - This is good for us in this particular case, but different - from normal CVS. - - 3. "admin" also skips the Attic and produces different kinds - of errors than CVS usually does. (Because they are coming - directly from RCS.) - - - The other way to rename a magic is to edit the - Repository files with a script of some kind. I've done it in - the past, but I'll leave it as an exercise for the reader. - - - 4D.6 Can I use RCS locally to record my changes without making them - globally visible by committing them? - - You can, but it will probably confuse CVS to have ",v" files in - your working directory. And you will lose all your log entries - when you finally commit it. - - Your best bet is to create your own CVS branch and work there. - You can commit as many revisions as you want, then merge it back - into the main line (or parent branch) when you are finished. - - - 4D.7 How can I allow access to the Repository by both CVS and RCS? - - The first step is to try not to. If some people are using CVS, - there is no reason for everyone not to. It is not hard to learn - the basics and CVS makes certain operations *easier* than a series - of RCS commands. Personal preference in what software tools can - be applied to a shared Repository has to take second place to - system integration needs. If you disagree, try writing some Lisp - code for inclusion in your Unix kernel and see what kind of - reception you get. - - If you really must allow routine RCS access to the CVS Repository, - you can link an RCS sub-directory into a piece of the Repository: - - ln -s /Repository/some/directory/I/want RCS - - and RCS will work just fine. - - - Those who are using RCS will have to keep the following in mind: - - 1. If a file was originally added to the Repository by "import" - and has not been changed using CVS, the *RCS* default branch - will remain attached to the Vendor branch, causing revisions - checked-in by "ci" to wind up on the Vendor branch, instead of - the main branch. Only CVS moves the RCS default branch on - first commit. - - The way around this is to checkin (using "ci") all the files - first and move them into the Repository. That way they won't - have Vendor branches. Then RCS will work OK. - - 2. It is possible to use "rcs" and "ci" to make the files unusable - by CVS. The same is true of the CVS "admin" command. - - 3. Normal RCS practice locks a file on checkout with "co -l". In - such an environment, RCS users should plan to keep survival - gear and food for at least 30 days near their desks. When - faced with bizarre and unexpected permission errors, howling - mobs of slavering CVS users will run the RCS users out of town - with pitchforks and machetes. - - See 3C.8 for a way to avoid machetes aroused by lock collisions. - - 4. Though files checked in by RCS users will correctly cause - "up-to-date" failures during CVS "commits" and they will be - auto-merged into CVS working directories during "update", the - opposite won't happen. - - RCS users will get no warning and will not be required to merge - older work into their code. They can easily checkin an old - file on top of a new revision added by CVS, discarding work - committed earlier by CVS users. - - See the howling mob scenario described above. - - - RCS is great. I have used it for years. But I wouldn't mix it - this way. In a two-camp society, you are asking for real trouble, - both in technical hassles to clean up and in political hassles to - soothe. Branch merges will also be a major problem. - - - 4D.8 I "updated" a file my friend, "bubba", committed yesterday. - Why doesn't the file now have a modified date of yesterday? - - CVS restores dates from the RCS files only on first "checkout". - After that, it is more important to maintain a timestamp relative - to the other files in the working directory. - - Example: You committed a source file at 5PM. Bubba updated his - copy of the file, grabbing your changes, then changed and - committed a new revision of the file at 6PM. At 7PM, you compile - your file. Then you execute "update". If CVS sets the date to - the one in the RCS file, the file would be given a timestamp of - 6PM and your Makefile wouldn't rebuild anything that depended on - it. Bad news. - - Note that the same logic applies to retrieving a revision out of - the Repository to replace a deleted file. If CVS changes your - file in an existing working directory, whether it was because a - new revision was committed by someone else or because you deleted - your working file, the timestamp on the retrieved working file - *must* be set to the current time. - - When you first retrieve a file, there is no reason to expect any - particular timestamp on the file within your working area. But - later, when dependency checking is performed during a build, it is - more important for the timestamps on the local files to be - consistent with each other than than it is for working files to - match the timestamps on the files in the Repository. - See 4D.17 for some more about timestamps. - - - 4D.9 While in the middle of a large "commit", how do I run other - commands, like "diff" or "stat" without seeing lock errors? - - Type: - cvs -n - - - The '-n' option to the main cvs command turns off lock checking, a - reasonable act for read-only commands given the promise offered by - '-n' not to alter anything. The "diff", "log" and "stat" commands - provide the same information (for files that are not being - committed) when used with and without the '-n' option. - - Warning: Ignoring locks can produce inconsistent information - across a collection of files if you are looking at the revisions - affected by an active commit. Be careful when creating "patches" - from the output of "cvs -n diff". If you are looking only at your - working files, tagged revisions, and BASE revisions (revisions - whose numbers are read from your ./CVS/Entries files), you should - get consistent results. Of course, if you catch a single file in - the middle of RCS activity, you might get some strange errors. - - Note that the suggested command is "cvs -n ". The - visually similar command "cvs -n" has no relation to the - suggested usage and has an entirely different meaning for each - command. - - "cvs -n update" also works in the middle of a commit, providing - slightly different information from a plain "cvs update". But, of - course, it also avoids modifying anything. - - You could also use the RCS functions, "rlog" and "rcsdiff" to - display some of the information by referring directly to the - Repository files. - - You need RCS version 5 or later for the commands described above - to work reliably. - - - 4D.10 Where did the ./CVS/Entries.Static file come from? What is it for? - - Each CVS working directory contains a ./CVS/Entries file listing - the files managed by CVS in that working directory. Normally, if - the "update" command finds a file in the Repository that is not in - the ./CVS/Entries file, "update" copies the appropriate revision - of the "new" file out of the Repository and adds the filename to - the Entries file. This happens for files: - - 1. Added to the Repository from another working directory. - 2. Dragged out of the Attic when switching branches with - "update -A" or "update -r". - 3. Whose names were deleted from the ./CVS/Entries file. - - If the ./CVS/Entries.Static file exists, CVS will only bring out - revisions of files that are contained in either ./CVS/Entries or - ./CVS/Entries.Static. If a Repository file is found in *neither* - file, it is ignored. - - The ./CVS/Entries.Static file is created when you check out an - individual file or a module that creates working directories that - don't contain all files in the corresponding Repository directory. - In those cases, without an ./CVS/Entries.Static file, a simple - "update" would bring more files out of the Repository than the - original "checkout" wanted. - - The ./CVS/Entries.Static file can be removed by hand. It is - automatically removed if you run "update -d" to create new - directories (even if no new directories are created). - (Internally, since "checkout" turns on the '-d' flag and calls the - "update" routine, a "checkout" of a module or directory that - writes into an existing directory will also remove the - ./CVS/Entries.Static file.) - - - 4D.11 Why did I get the wrong Repository in the loginfo message? - - You probably: - - 1. Use multiple Repositories. - - 2. Configured CVS to use absolute pathnames in the - ./CVS/Repository file. - - 3. Configured CVS not to use the ./CVS/Root file. - - 4. Typed the "commit" command in one Repository with your - $CVSROOT pointing at another. - - "commit" and all other CVS commands will heed an absolute pathname - in the ./CVS/Repository file (or in the "-d CVSrootdir" override), - but the log function doesn't take arguments -- it just looks at - $CVSROOT. - - If you avoid even one of the four steps above, you won't see this - problem. If you configure ./CVS/Root, you won't be allowed to - execute the program causing the error. - - - 4D.12 How do I run CVS setuid so I can only allow access through the - CVS program itself? - - Setuid to root is not a great idea. Any program that modifies - files and is used by a widely distributed group of users is not a - good candidate for a setuid program. (The worst suggestion I've - ever heard was to make *Emacs* setuid to root.) - - Root access on Unix is too powerful. Also, it might not work in - some (secure?) environments. - - Running it setuid to some user other than root might work, if you - add this line to main.c near the beginning: - - setuid(geteuid()); - - Otherwise it uses *your* access rights, rather than the effective - uid's. - - Also, you have to invent a fake user whose name will show up in - various places. But many sites, especially those who might want a - setuid CVS for "security", want personal accountability -- no - generic accounts. I don't know whether accountability outweighs - file security. - - And finally, unless you take action to limit the "admin" - command, you are leaving yourself unprotected anyway. - - - 4D.13 How about using groups and setgid() then? - - Here is a way to run CVS setgid in some environments: - - 0. Stick this near the front of the main() in main.c: - - setgid(getegid()); - - This will allow "access" to work on systems where it - only works on the real gid. - - 1. Create a group named "cvsg". (This example uses "cvsg". You - can name it as you wish.) - - 2. Put *no* users in the "cvsg" group. You can put Repository - administrators in this group if you want to. - - 3. Set the cvs executable to setgid (not setuid): - - cd /usr/local/bin; chown root.cvsg cvs; chmod 2755 cvs - - 4. Make sure every file in the Repository is in group "cvsg": - - chown -R root.cvsg $CVSROOT - - 5. Change all directory permissions to 770. This allows all - access to the files by the "cvsg" group (which has no members!) - and no access at all to anyone else. - - find $CVSROOT -type d -exec chmod 2770 {} \; - - On some systems you might have to type: - - find $CVSROOT -type d -exec chmod u=rwx,g=rwx,o=,g+s {} \; - - This should allow only the cvs program (or other "setgid to group - cvsg") programs to write into the area, but no one else. Yes the - user winds up owning the file, but s/he can't find it again later - since s/he can't traverse the tree. (If you enable the world - execute bit (mode 2771) on directories, users can traverse the - tree and the user who last wrote the file can still write to it.) - - If you want to allow read access, check out an entire tree - somewhere. You have to do this anyway to build it. - - Note: If you are using a stupid file system that can't inherit - file groups from the parent directory (even with the "setgid" - (Octal 2000) bit set), you might have to modify CVS (or RCS) to - reset the group every time you create a new file. I have not - tested this. - - The setgid() method shares with the setuid() method the problem of - keeping "admin" from breaking things. - - - 4D.14 How do I use the "commitinfo" file? - - Go read 4B.2 first. - - The "commitinfo" file allows you to execute "sanity check" - functions before allowing a commit. If any function called from - within the commitinfo file exits with a non-zero status, the - commit is denied. - - To fill out a "commitinfo" file, ask yourself (and those sharing - your Repository) these questions: - - - Is there anything you want to check or change before someone is - allowed to commit a file? If not, forget commitinfo. - - If you want to serialize binary files, you might consider - something like the rcslock.pl program in the contrib directory - of the CVS sources. - - - Do you want to execute the same exact thing before committing to - every file in the Repository? (This is useful if you want to - program the restrictions yourself.) If so, set up a single line - in the commitinfo: - - DEFAULT /absolute/path/to/program - - CVS executes the program once for each directory that "commit" - traverses, passing as arguments the directory and the files to - be committed within that directory. - - Write your program accordingly. Some examples exist in the - contrib directory. - - - Do you want a different kind of sanity check performed for - different directories? If so, you'll have to decide what to do - for all directories and enter lines like this: - - regexp1 /absolute/path/to/program-for-regexp1 - regexp2 /absolute/path/to/program-for-regexp2 - DEFAULT /absolute/path/to/program-for-all-else - - - - Is there anything you want to happen before *all* commits, in - addition to other pattern matches? If so, include a line like - this: - - ALL /absolute/path/to/program - - It is executed independently of all the above. And it's - repeatable -- you can have as many ALL lines as you like. - - - 4D.15 How do I use the "loginfo" files? - - See 4B.2 and the "commitinfo" question above. - - The "loginfo" file has the same format as the "commitinfo" - file, but its function is different. Where the "commitinfo" - information is used before a commit, the "loginfo" file is used - after a commit. - - All the commands in the "loginfo" file should read data from - standard input, then either append it to a file or send a message - to a mailing list. If you want to make it simple, you can put - shell (the shell used by "popen(3)") command lines directly in the - "loginfo" (or "commitinfo") file. These seem to work: - - ^special /usr/ucb/Mail -s %s special-mailing-list - ^other /usr/ucb/Mail -s %s other-mailing-list - DEFAULT (echo '===='; echo %s; cat) > /path/name/to/log/file - - - 4D.16 How can I keep people with restrictive umask values from blocking - access to the Repository? - - If a user creates a new file with restricted permissions - (e.g. 0600), and commits it, the Repository will have a file in it - that is unreadable by everyone. The 0600 example would be - unreadable by *anyone* but root and the user who created it. - - There are 3 solutions to this: - - 0. Let it happen. This is a valid way to protect things. If - everyone is working alone, a umask of 077 is OK. If everyone - is working only in small groups, a umask of 007 is OK. - - 1. Train your users not to create such things if you expect to - share them. - - 2. See 4B.5 for a small script that will reset the umask. - - I personally don't like the idea of a program automatically - *loosening* security. It would be better for you all to talk - about the issue and decide how to work together. - - - 4D.17 Why do timestamps sometimes get set to the date of the revision, - sometimes not? The inconsistency causes unnecessary recompiles. - - The "checkout" command normally sets the timestamp of a working - file to match the timestamp stored on the revision in the - Repository's RCS file. - - The "commit" command retains the timestamp of the file, if the - act of checking it in didn't change it (by expanding keywords). - - The "update" command sets the time to the revision time the first - time it sees the file. After that, it sets the time of the file - to the current time. See 4D.8 for a reason why. - - Here's a two-line PERL program to set timestamps on files based on - other timestamps. I've found this program useful. When you are - certain you don't want a source file to be recompiled, you can set - its timestamp to the stamp on the object file. - - #!/usr/local/bin/perl - # - # Set timestamp of args 2nd-Last to that of the first arg. - # - ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime) - = stat(shift); - utime($atime,$mtime,@ARGV); - - - ----------------- --- Section 4E -- Internal errors ----------------- - - **** Questions: - - 4E.1 Explain: "ci error: unexpected EOF in diff output" - 4E.2 Explain: "RCS file /Repository/module/file.c,v is in use" - 4E.3 Explain: "co error, line 2: Missing access list" - 4E.4 Explain: "error: RCS file name `xyz .c' contains white space" - 4E.5 Explain: cvs checkout: warning: is not (any longer) pertinent - 4E.6 Why did a Repository file change from ,v to ,,? - - - **** Answers: - - 4E.1 Explain: "ci error: unexpected EOF in diff output" - - RCS versions earlier than 5.5 print the above error when a file - does not end in a newline character. It can be caused by: - - - Editing with Emacs and not using "require-final-newline". - - Committing a binary file. - - Filesystem failures (NFS!) that put nulls in your file. - - The solution is to upgrade to RCS 5.5 or later. (Of course, this - won't fix filesystem failures. It will merely allow RCS (and - therefore CVS) to handle the file without error.) - - - 4E.2 Explain: "RCS file /Repository/module/file.c,v is in use" - - This is an RCS error that occurs when its internal lock file has - been left around by an RCS command interrupted by some sort of - system crash, disk failure or SIGKILL signal. - - Go into the Repository and look for files with names similar to - "file.c,v", usually starting with ',', '_' or '#'. Make - sure they are really crash remnants and do not belong to - transactions in progress -- a recent last-modified timestamp - is a good indicator of a live transaction. Delete them if they - are old. - - - 4E.3 Explain: "co error, line 2: Missing access list" - - This is an error message from RCS Version 3 when it tries to read - a file created by a later version of RCS. - - HP decided to "standardize" on an ancient version of RCS some time - ago. You can't use it for CVS. See 4H.6. - - Since the error comes from having a later version of RCS than HP - supports, you probably did install the later version but must have - recently changed your $PATH or installed the HP package that has - RCS in it. - - You should either reconfigure CVS to use absolute pathnames to the - proper versions of the RCS programs that CVS uses, or change your - PATH to look there first. If you haven't installed the latest - version of RCS, you should upgrade. See 1B.4 - - - 4E.4 Explain: "error: RCS file name `xyz .c' contains white space" - - RCS 5.6 doesn't allow white space in filenames. Apparently this - restriction will be removed in RCS 5.7, but CVS may still require - that filenames have no white space in them. - - - 4E.5 Explain: cvs checkout: warning: is not (any longer) pertinent - - This message occurs in three instances: - - 1. When there is an entry in the ./CVS/Entries for file and - there is no RCS file in the Repository to back it up. - - If the working file exists, and hasn't changed (determined from - the timestamp) it is removed. - - - 2. When you try to check out a piece of the Repository with: - - cvs checkout some/place/in/repository/tree - - and at least the first element of the path (i.e. "some" in the - above) exists, but some part of the rest of it does not. - - The checkout command checks the modules file first for the - whole path, then for a prefix of the path as a module name. If - it doesn't find *any* portion of your path in the modules file, - it says: - - cvs checkout: cannot find module `' - ignored - - If it finds some set of prefix directories, it prints the - message you see. - - In practice this is usually a spelling error. - - 3. If the Repository files you are trying to check out or update - are not readable by you, the same problems can occur. - Check the permissions on the files involved. - - - - 4E.6 Why did a Repository file change from ,v to ,,? - - This is an RCS problem, since the ,, syntax for file names - is used by RCS and not CVS. - - RCS constructs a new ,v in a temporary file named ,, - (which doubles as a lock file) then renames it to ,v when it - is done. The only way this is reliable is if your system's - version of rename(2) is an atomic, as required by POSIX. - - If your system has a non-atomic (and therefore non-POSIX) - rename(2) system call, RCS runs uses an internal version of this - algorithm to approximate the atomic rename: - - rm ,v; ln ,, ,v; rm ,, - - If the system crashes, or you lose your NFS connection between the - first "rm", but before the "ln", you can be left only with the - ,, file. If the crash or network failure occurs between the - "ln" and the final "rm", you could be left with a pair of linked - names. - - Recovery: - - If only the ,, exists, rename it to ,v. - - - If both ,, and ,v exist and are linked, remove the - ,, file. - - - If both ,, and ,v exist and are separate files, look - at the dates, "diff" them and make your best guess. This sounds - like the remnants of two separate events. - - - ----------------- --- Section 4F -- Related Software ----------------- - - **** Questions: - - 4F.1 How do I use CVS under Emacs? Is there an Emacs cvs-mode? - 4F.2 What is GIC (Graphical Interface to CVS)? - 4F.3 What is CAVEMAN? - - - **** Answers: - -This section covers a small handful of subsystems that connect to CVS in -some way. Most are "front ends" in that they offer a different user -interface to CVS, but use CVS to perform the normal tasks. - - NOTE: The short summaries below combine details culled from public - announcements of the listed software with the personal opinions of - the author of the FAQ entry. - - 4F.1 How do I use CVS under Emacs? Is there an Emacs cvs-mode? - - The pcl-cvs package distributed with CVS is an emacs package that - helps with the update/commit process. When you are ready to - update, you use the 'cvs-update' command within emacs. This - executes "update" and fills a cvs-mode buffer with a line for each - file that changed. The most helpful features are: descriptive - words for what happened (i.e. Merged or Conflict rather than 'U' - or 'C'), single keys bound to diffs and commits, and the ability - to mark arbitrary groups of files, possibly from different - directories, for commit as a whole. - - All the developers in my group that use emacs find pcl-cvs a much - friendlier and more helpful way to update/commit than raw cvs. - One vi user even converted to emacs just to use pcl-cvs. - - Contributed by Jeffrey M Loomis - - 4F.2 What is GIC (Graphical Interface to CVS)? - - GIC provides a graphical user interface to the Concurrent Version - System (CVS), a powerful revision control system. GIC is - implemented in the Tcl/Tk programming language and is intended to - augment the sometimes cumbersome CVS command line interface. - Novices should find GIC to be much easier to learn than the CVS - command line. - - While GIC is easy to use, it does not contain any documentation on - CVS. Users of GIC must first learn the concepts of CVS such as - modules and merging, as well as the simple functions, such as - committing and updating. The CVS manual page and the README file - are good places to look. - - contact - David Marwood - marwood@cpsc.ucalgary.ca - - [Extracted from an announcement by David Marwood.] - - GIC can be obtained by anonymous ftp to (on the date of this FAQ) - - ftp.cpsc.ucalgary.ca:/pub/users/marwood/gic-1.1.tar.Z - ftp.cpsc.ucalgary.ca:/pub/users/marwood/gic-1.2b1.tar.Z - - - 4F.3 What is CAVEMAN? - - CAVEMAN is a front end to CVS written in PERL providing a - collection of features desired by the site where it was developed. - - - The ability to spread a "project" over multiple Repositories. - - Optional automatic tagging after each commit. - - Additional locking of files. - - Extra before and after program hooks. - - A layer of event logging. - - All sorts of error messages. - - Many changes to the semantics of commands. - - It is available via anonymous ftp on ftp.llnl.gov [128.115.54.18] - in gnu/caveman_vX.Y.Z.tar.gz (The numbers X, Y, & Z vary.) - - contact - Kathleen Dyer kdyer@llnl.gov - (510)423-6803 - (510)423-5112 FAX - - [[Does someone want to elaborate?]] - - ----------------- --- Section 4G -- Engineering ----------------- - - **** Questions: - - 4G.1 Where can I find out about Software Engineering? - 4G.2 How do I flexibly arrange the modules file to describe my sources? - 4G.3 Can I have multiple source repositories, one for each project? - 4G.4 Who should administer the Repository and manage the modules file? - 4G.5 Isn't disk space a big factor? CVS copies files out of the - Repository, duplicating everything. - - - **** Answers: - -This section is really beyond the scope of CVS, but so many people ask -questions about how to do Software Configuration and Engineering that I -thought I'd try to include some information. If you have any -improvements, references or ideas, speak up. - - - - 4G.1 Where can I find out about Software Engineering? - - A couple different people suggested this book: - - Software Configuration Management: Coordination for Team - Productivity; Wayne A. Babich; Addison Wesley; 1986; - ISBN 0-201-10161-0 - - - A number of others suggested Appendix B of the book "Decline and - Fall of the American Programmer" by Ed Yourdon, called "The - Programmer's Bookshelf". It list 87 books you are expected to - have read. Since they publish many of the books, Prentice-Hall - distributes this list as "Prentice Hall Professional Technical - reference PTR-125-AA3. - - One interesting item from the Yourdon book: The total number - of professional computer books sold is less than the number - of programmers currently in the United States. It wasn't clear - from the book whether this meant "per year" or not, but it is - still frightening. - - - 4G.2 How do I flexibly arrange the modules file to describe my sources? - - An equivalent question might be, "How do I structure my sources?" - This can be a difficult question especially in the areas that are - more political than technical. - - Generally you want to think about which pieces of your system need - to be checked out together, built as one system or tagged as a - consistent whole. You should certainly create module names that - correspond to complete, buildable collections that you would tag - and release as one "product". It is also convenient to create - module names for small sections of the Repository containing - files that will all be worked on at the same time by the same - person or group. - - Once you have defined the structure of your work, you can usually - see how to lay it out in a Repository. After that the modules - file is easy. You set up module names and aliases to match what - you need to check out by name. If you like relative directories, - it is possible, but not recommended, to work completely without a - modules file. See 1D.11 and 2C.7 for some info about the modules - file. - - Here are a few types of modules. You should experiment to see - what kind of structure each of these produces. They all have - different uses. - - 1. Connected projects in one group with two separate helper - directories. The helper directories can contain build tools, - header files, libraries, or whatever you like. - - These are all aliases that checkout relative pathnames. The - equivalent results could be produced by placing the selected - relative pathnames on the "cvs checkout" command line. - - pr1 -a P1 HELPERS - pr2 -a P2 HELPERS - pr3 -a P3 HELPERS - pr12 -a P1 P2 HELPERS - pr13 -a P1 P3 HELPERS - pr23 -a P2 P3 HELPERS - - P1 -a group1/proj1 - P2 -a group1/proj2 - P3 -a group1/proj3 - HELPERS -a group1/helper1 group1/helper2 MAKEFILE - MAKEFILE -a group1/Makefile - - Actual Repository directory structure: (from $CVSROOT down) - - group1/ - Makefile - The top level Makefile. - helper1/ - helper2/ - Helper files and dirs - proj1/ - Files and dirs - proj2/ - Files and dirs - proj3/ - Files and dirs - - "checkout group1" produces a duplicate of the above. - "checkout projX" produces all but "projY" and "projZ". - "checkout projXY" produces all but "projZ". - - - 2. Here is the exact same set of module names describing the same - Repository layout using module names (and aliases containing - module names) instead of merely aliases for relative pathnames. - - There is one difference in the result. The name of the top - level directory in the checked out working tree will match the - "module" name (e.g. pr1) instead of always being "group1" as it - was in the first example above. - - pr1 group1 proj1 &HELPERS - pr2 group1 proj2 &HELPERS - pr3 group1 proj3 &HELPERS - pr12 group1 proj1 proj2 &HELPERS - pr13 group1 proj1 proj3 &HELPERS - pr23 group1 proj2 proj3 &HELPERS - - HELPERS -a helper1 helper2 group1-Makefile - helper1 group1/helper1 - helper2 group1/helper2 - group1-Makefile -d . group1 Makefile - - The above line (with the -d in it) says that when the - module named "group1-Makefile" is checked out, the file - named Makefile file will be found in a directory named - $CVSROOT/group1 and will be checked out into a directory - named '.', which obviously already exists. - - The & references say to interpret those pathnames relative - to the directory where the whole module is stored. For - the "pr1" module, that directory is "group1", so the - &HELPERS reference winds up placing Makefile in '.' - relative to "group1". - - - 3. A short one containing the basic "module" actions: - - m1 head/path file1 dir2 file3 dir4 file5 - - When checked out, a directory named "m1" appears in your - current directory. Elements named file1, dir2, file3, - dir4, and file5 appear in it. They were originally taken - as relative paths from $CVSROOT/head/path. - - - 4. Here's another way to construct a working directory out of - pieces of the Repository: - - projX projX Makefile &projX_inc &projX_src &projX_doc - - # The first line selects a single file within projX, plus - # the contents of three other modules. Those three other - # modules rename their directories. - - projX_inc -d include projX/inc - projX_src -d source projX/src - projX_doc -d documentation projX/doc - - - 5. A Unix tree. This is similar to what CVS was developed for and - the way I have used it for years. - - # Top level - unix unix - u_bin unix/bin - u_etc unix/etc - u_man unix/man - usr-bin unix/usr.bin - - # Subdirs of top level dirs. (tiny subset) - ls unix/bin/ls - fsck unix/etc/fsck - man8 unix/man/man8 - - # Programs without subdirs. (tiny subset) - cat unix/bin Makefile cat.c - uniq unix/usr.bin Makefile uniq.c - - # /usr/local/src - localsrc localsrc - gnu localsrc/gnu - public localsrc/public - X11 localsrc/X11 - - # GNU and PD tools - cvs localsrc/gnu/cvs - emacs localsrc/gnu/emacs - rcs localsrc/gnu/rcs - btoa localsrc/public/btoa - tcsh localsrc/public/tcsh - - # X11 related items. - tvtwm localsrc/X11/contrib/tvtwm - - "unix" was checked out and built from the top down, using a set - of Makefiles that knew about the whole structure. "localsrc" - was kept checked out in /usr/local/src. - - At any time I could run "checkout ls" or "checkout cat" and get - a simple directory with only that tool in it, plus a subset - Makefile that knew how to build that tool against the installed - (or alternate, via environment variables) headers and libraries. - - I found it very handy to be able to run "ls" and see the three - tools I was porting that week. - - - 4G.3 Can I have multiple source repositories, one for each project? - - Yes, you can have as many Repositories as you like. But each - Repository must be managed separately, creating additional work. - - Question 4A.1 provides a short description of setting up a - single Repository. A few additional considerations: - - 1. It is a good idea to start by creating a single Repository and - split it up (or create additional Repositories) only if you - believe it is really necessary. I would only create a new - Repository if the data is completely disconnected from the rest - of the main Repository. - - 2. If there is a lot of overlap among the developers working on - the collections of files you want to place in different - Repositories, or if there is any connection between those - collections, I would go out of my way to create a single - Repository. It is much easier to manage. - - 3. Disk space should not be a factor since you can build up a - Repository using symbolic links and/or remote mounts. - - 4. Each Repository is completely distinct. You can't check out - modules from different Repositories at the same time. A better - way of looking at it is that if you *can* check out two modules - or directories with a single "checkout" command (without - contortions or explicit absolute pathnames), then they are in - the same Repository. - - 5. To "checkout" modules from multiple Repositories, you must use - the "cvs -d" option on all CVS commands or alter your $CVSROOT - variable when you change focus to another Repository. If you - work with multiple Repositories, it is a good idea to configure - CVS to use absolute pathnames in the ./CVS/Repository file, - since most commands (other than "checkout") will use that file - rather than $CVSROOT. - - 6. If you configure CVS to use relative pathnames in your - ./CVS/Repository files, you must always be careful to set your - $CVSROOT properly or you will get unexpected results. - - If you have two modules or directories by the same name at the - same relative path inside two different Repositories, you are - asking for disaster. You could unexpectedly update a directory - with completely unrelated files. This is not a fanciful - example -- a Repository is occasionally duplicated for release - purposes in which case *all* the paths in the two Repositories - are the same. - - - 4G.4 Who should administer the Repository and manage the modules file? - - This is a "management style" question. In large or traditional - groups, the CVS procedures are warped to conform to local - conventions. In small groups, in groups with strong personalities - or on new projects the choice of source control procedures can - help create some of the working environment. Here is a taxonomy - of environments I have worked in or helped set up: - - Situation 1. - - A small number of competent developers working on a medium - size project. We all got along and we all respected each - other (at least technically). Anyone edited anything. - - Modules and Repository admin was mostly left to me. I never - found a problem in minor changes made by anyone else. - - - Situation 2. - - A large number of experienced developers sprinkled with - wackos. Many of the developers didn't want to deal with any - kind of source control. They wanted a full-service source - control system that caused them zero thought. - - I learned "big stick" diplomacy here. There was a small - number of "designated" (by me) people who were allowed to do - *anything* other than "update" and "commit". Even "checkouts" - were controlled. This is where I found "history" and - "release" the most useful. - - Situation 3. - - A small number of developers who wanted me to "help", but who - didn't want to deal with anything other than their favorite - algorithms. - - I didn't have the time to baby-sit this group, so I designated - one of them to be my official contact and made him do it all. - He felt sullied by the requirement to pay attention to - anything other than his pet coding projects, but enjoyed the - "status" of being the only one who could touch the control - files without my kicking the chair out from under him. - - Situation 4. - - A huge number of developers of covering the whole spectrum of - competence and experience split into 20 groups, none of which - cooperated with the others, working on 57 different projects, - most of which didn't inter-operate. - - Managing it in any coherent way was not my responsibility (and - beyond my tolerance for chaos). Too many people. So I - privately designated a person in each group to be the contact - and kept watch on the Repository activity. When something - went wrong, I notified the contact for the group and told him - what was happening and *he* kept his troops in line. They - were tougher with their own group that I would have been. - - Eventually only a few people were willing to touch the control - files, since they were flamed from all directions if they - screwed up. - - Situation 5. - - In a medium group of really *serious*, and seriously - overworked, people, someone else was designated the "master". - I convinced the master I knew what I was doing and went on my - way. - - No one else in the world was allowed to touch anything. - - Situation 6. - - In a large amorphous group of beginners, experts and clowns, - over whom no one had official control, I was forced to employ - a group of relative beginners (who became experts rather - quickly) to police the world. The ultimate in locking the - barn after the horse was stolen, we kept Chaos from destroying - us only by use of superior firepower. - - - - My choice, if allowed, is to let anyone touch anything. I keep - backups of important items and let people know individually - whether I want them to touch things or not. If someone on my "no - touch" list touches and succeeds, they are allowed more slack. If - they screw up after being warned, their screwup becomes public. - After a few months, I usually have no trouble keeping the world - running smoothly, at least from my (and CVS's) perspective. - - - 4G.5 Isn't disk space a big factor? CVS copies files out of the - Repository, duplicating everything. - - Everyone knows that disk space is getting cheaper. How do we - reconcile this with the equally well-known problem that *all* disk - is *always* filled up? - - In my opinion, the main reason disk space will never be an - unlimited resource is that it is the major variable in - organizational time/space tradeoffs. It isn't a problem of waste - or an aspect of Murphy's law, as some claim it is, but rather a - direct consequence of good management. Disk space is, and will - always be, a limited resource. - - First, the cost of *deploying* that disk is not dropping as fast - as the cost of the storage medium. The cost of machines to hold - the disks and the networks to connect them are dropping more - slowly than disk media. And the cost of the human time necessary - to manage the machines, networks, disks, and the developers using - them, is not dropping at all. The cost of human time continues to - rise. - - If management decides that expensive human time can be saved by - using all that new disk space to keep the last three releases - online, then that's what it will be used for. If each release - takes up a Gigabyte and you support 30 platforms, a simple - time-saving suggestion has just grabbed 100 Gigabytes of disk - space. And we've ignored the potential disk storage needed to - support "better Customer Service", another management refrain. - - Even at 30 cents per Megabyte (next year's price), you've just - used up $30,000 of disk space. And that doesn't count the - computers, tape drives and humans necessary to maintain and deploy - all of it. Spending money to save time has its own overhead, too. - - - Binaries are getting bigger. Graphics and data collection devices - can eat up any amount of disk. There are more tools available, - more libraries, more raw data than you can ever store. My home - computer has a Gigabyte of disk on it. It could easily handle 30. - - The "economy" of disk storage media will never remove the need to - manage disk space. - - - So, here's an un-reviewed suggestion originally from Graydon Dodson - , which I've altered and edited heavily. - - - Keep a directory where the whole tree is checked out. (It might - be built and tested once in a while to make sure it is worth - linking to, but that doesn't affect the source control aspect of - this procedure). Let's call it /master/build. - - - Write a tool that creates a tree of directories (like the X11 - "lndir" command) filled with links to the checked out files in - the /master/build tree. - - This tool should also provide real copies of, not symlinks to, - all the files within the CVS administrative directories. - - - You could also provide a way for the tool to take a list of - whole directories that you will never change, for which it would - create a single symlink to the directory and not a subtree of - symlinks to files. Or you could rm -r pieces of the resulting - working directory yourself and replace it with links. - - - If you want to edit a file, you have to grab a real copy and - keep it until your revision shows up in the /master/build tree. - I'd create a script to do this: cvsgrab - - #!/bin/csh -f - set f = $1 - if (! -l $f) then - echo "file $f is not a symlink" - exit 1 - endif - rm $f - set rev = `grep "^/$f/" CVS/Entries | awk -F/ '{print $3}'` - cvs update -p -r $rev $f > $f - - You can't do a plain "cvs update" since that would grab newer - revisions from the Repository, not the revision you wanted to - start with. After the file is no longer a symlink, you can work - normally. You'll have to run "update" before "commit" anyway if - there are newer revisions. - - - Presumably there would also be a tool to traverse the link tree - and revert it to links if there are no modified files and/or if - all the real files match the revision of the /master/build tree. - - - To avoid confusing CVS when the /master/build revisions are - updated but your CVS/Entries files is not, CVS would have to - change to handle symlinks. It currently causes problems with - this scenario: - - 1. ./ is a symlink. - 2. ./CVS/Entries says you are revision 1.2. - 3. The corresponding CVS/Entries file in /master/build - says the latest revision is 1.3. - 4. cvs update shows a 'C' conflict flag. - - ----------------- --- Section 4H -- Other Systems ----------------- - - **** Questions: - - 4H.1 I use a NeXT. Is there anything I need to know? - 4H.2 I use OS/2 and/or DOS. Is there anything I need to know? - 4H.3 I use SCO Unix. Is there anything I need to know? - 4H.4 I use AIX. Is there anything I need to know? - 4H.5 I use IRIX. Is there anything I need to know? - 4H.6 I use an HP system. Is there anything I need to know? - 4H.7 I use AFS. Is there anything I need to know? - 4H.8 I use A/UX. Is there anything I need to know? - - - **** Answers: - -Out of the box, CVS works on most varieties of Unix. Some near-Unix -systems have a few problems and non-Unix systems have a *lot* of problems. - - 4H.1 I use a NeXT. Is there anything I need to know? - - NeXTSTEP 3.0's Interface Builder uses "nib" directories, rather - than the files used in previous revisions. It removes files it - doesn't recognize, making it impossible to place such a directory - under CVS -- the CVS admin directory will be removed. - - Some time ago, posted a palette named - CVSPalette that claimed to resolve this problem. It was intended - to preserve the CVS administrative directories within nib - documents (directories) that Interface Builder usually removes. - - CVSPalette is no longer in its announced place: - - ftp.cs.orst.edu:/pub/next/submissions - - though I did find two other interesting files on ftp.cs.orst.edu: - - /software/NeXT/sources/tools/cvs-next-2_1_1.tar.Z - - which is a port of CVS 1.3 (along with RCS and diff) and: - - /software/NeXT/sources/programming/cvs.postamble-2.4.gz - - which appears to be a set of wrappers for CVS commands that claim - to allow you to use CVS effectively (and without need for the - "command line") on a NeXT machine. - - - [[Anyone know the truth about CVS and NeXT?]] - - - 4H.2 I use OS/2 and/or DOS. Is there anything I need to know? - - You can share RCS files between Unix and DOS while avoiding the - MS-DOS file name limits by setting your RCSINIT environment - variable to '-x/,v'. New RCS files will be created without the - standard ",v" suffix, though files ending in ",v" will still be - found if there is no matching file in the same directory without - the ",v". - - Erik van Linstee offers an - OS/2 and a DOS port of CVS 1.3 in: - - ftp.informatik.tu-muenchen.de:/pub/comp/os/os2/gnu/devtools - or - ftp.rrzn.uni-hannover.de:/pub/os2-local - - The files are named: - - cvs13p?[bs].zip - - Where the ? stands for the patch level (currently 8) and the b is - for the binaries, the s for the sources. - - There are three binaries. An OS/2 only one (32-bit), a DOS only one - (16-bit) and an EMX one that runs on both (32-bit). - - There are many differences between the Unix and the DOS versions - of CVS. Read the material that comes with the DOS version before - using it. - - [[Updates?]]. - - - 4H.3 I use SCO Unix. Is there anything I need to know? - - On SCO/UNIX 3.2 V2.0 POSIX signals don't work. Unfortunately the - configure program detects POSIXness and configures in the use of - POSIX signals. Workaround : Edit out the check for POSIXness in - the configure script. [[You could also remove all occurrences of - "-DPOSIX=1" from the Makefiles after configure is run. -dgg-]] - - SCO/UNIX doesn't understand #!/ syntax. This breaks - the use of log.pl as it gets invoked by /bin/sh instead of - !#/usr/local/bin/perl. WorkAround : edit log.pl and change it into - a shell script which invokes perl with log.perl (renamed from - log.pl) as input. - Contributed by Joe Drumgoole - - - 4H.4 I use AIX. Is there anything I need to know? - - The only report on AIX claims to have no trouble using it in - concert with SunOS and IRIX platforms. - - - 4H.5 I use IRIX. Is there anything I need to know? - - If you see "uid" numbers where you would expect user names, try - adding -lsun to the link line. Without it CVS is unable to - retrieve "passwd" data through NIS. - - - 4H.6 I use an HP system. Is there anything I need to know? - - HP distributes RCS version 3 (a circa 1983 release!) with HP-UX. - CVS does not work with RCS version 3; it requires RCS version 4 - or later. Your best bet is to find the latest version of RCS - and install it somewhere. - - HP-UX 8.07 has a serious bug with the mmap system call and NFS - files; the bug can crash the operating system. Make sure that - you configure RCS to avoid mmap by setting has_mmap to 0 in - RCS's conf.h. This bug is fixed in HP-UX 9. - - Contributed by Paul Eggert - - If using the setgid() trick described in 4D.13, you will have to - create an entry in the /etc/privgroup file to give the group - assigned to the cvs executable setgid permission (see - setprivgrp(1m)). Additionally, if you are restricting "read" - access to the Repository by limiting access to the executable - (this requires yet another group), then you will require that - /etc/logingroup exists and is configured correctly (usually it's - just alink to /etc/group). - - Contributed by Dale Woolridge - - - 4H.7 I use AFS. Is there anything I need to know? - - There is a problem with the way CVS performs its locking when the - files are within AFS. When your current PTS id != your uid, the - locks are not deleted. The stat() system call returns the PTS id - of the owner. If that id != your uid, CVS assumes you did not lock - it, and leaves the lock files alone. The next time you try to use - it, it complains that someone has the repository locked. - - Contributed by Michael Ganzberger - - [[This was against CVS 1.3. Is it still in CVS 1.4?]] - - - 4H.8 I use A/UX. Is there anything I need to know? - - [[??]] - - - - -============================================= -== Section 5 ==== Past & Future ==== -============================================= - ----------------- --- Section 5A -- Contributors ----------------- - - **** Questions: - -=5A.1 Who wrote CVS? - 5A.2 You didn't write all of this FAQ, did you? - - - **** Answers: - - -=5A.1 Who wrote CVS? - - Brian Berliner converted a collection of - scripts written by Dick Grune into a C program, - then added all sorts of features. He continues to maintain CVS. - - Jeff Polk wrote much of the code added between - revisions 1.2 and 1.3. Many others were involved at some level. - - david d zuhn fixed a number of bugs, added - some of the new features, reworked the whole thing to be more - portable, and provided much of the energy to push CVS 1.4 out - the door. - - Jim Kingdon implemented CVS 1.5's remote repository access - features, fixed many bugs, and managed the release of version 1.5. - - Take a look at the README and the ChangeLog files in the CVS - sources for more contributors. - - - 5A.2 You didn't write all of this FAQ, did you? - - In the original hunt for questions to answer (performed in - Jan/Feb, 1993), I polled hundreds of people and I rephrased all - sorts of text found on the net. Between 2/93 and 10/93, I - released about 20 versions, with corrections and additions from - the info-cvs mailing list and private correspondence. - - Between 10/93 and 10/94 I extracted frequently asked questions - from the 1200 mail messages to the info-cvs mailing list, - turned them into focused questions and tried to answer them. - - 93/02/?? ~4000 lines - 93/06/?? ~5000 lines - 93/10/23 7839 lines 278K - 94/10/29 9856 lines 360K - 95/05/09 9981 lines 365K - - Because there are so many posers of questions, I will list only - those who contribute answers or help significantly with the - content and structure of this document. - - If I used someone else's text verbatim, I mentioned it in the - given answer. The people whose email postings have added to this - document or who have added to my understanding are: - - Brian Berliner , CVS maintainer. - Paul Eggert , RCS maintainer. - - Gray Watson - Per Cederqvist - Pete Clark - - all of whom have sent me copies of their tutorials - and local CVS documentation. - - Additional contributors, who have sent me ideas, text, corrections - and support include (in alphabetical order): - - Per Abrahamsen - Donald Amby - Mark D Baushke - Jim Blandy - Tom Cunningham - Graydon Dodson - Joe Drumgoole - Don Dwiggins - Bryant Eastham - Dan Franklin - Michael Ganzberger - Steve Harris - Erik van Linstee - Jeffrey M Loomis - Barry Margolin - Mark K. Mellis - Chris Moore - Gary Oberbrunner - Steve Turner - Dave Wolfe - Dale Woolridge - - - - Please send corrections. If I forgot you, remind me and I'll add - your name to the list. - - ----------------- --- Section 5B -- Bugs and Patches ----------------- - -This section addresses some known bugs and patches for them. -Large patches will be stored in the FTP area. -See the Development section later for stuff being worked on. - - **** Questions: - - 5B.1 Why can't CVS handle deletion of directories? - 5B.2 Why can't CVS handle the moving of sources from one place in the - directory hierarchy to another? - 5B.3 When I typed "cvs update -D ", why did it check out all - sorts of ancient files from the Attic? Shouldn't it just create - the set of files and revisions that existed at that date? - 5B.4 When I typed "cvs update -D " in my branch, why did it - screw up all my files? - 5B.5 When I executed "checkout" into an existing directory I got "No - such file or directory" errors. Why? - 5B.6 Why does "update" send all output to the terminal after 26 files - have been updated? - 5B.7 Why does the merge occasionally resurrect lines of code? - 5B.8 Why does the merge fail when my "rcsmerge" program is - configured to use GNU diff version 2.1 or later? - - - **** Answers: - - 5B.1 Why can't CVS handle deletion of directories? - - An oversight, probably. [[Fixed in a future release?]] - - - 5B.2 Why can't CVS handle the moving of sources from one place in the - directory hierarchy to another? - - A "renaming database" has been proposed to track the history of - pathname changes in the Repository. A general solution is a - difficult problem. See 4B.8. - - - 5B.3 When I typed "cvs update -D ", why did it check out all - sorts of ancient files from the Attic? Shouldn't it just create - the set of files and revisions that existed at that date? - - This seems to be a bug, but is really the lack of any obvious - place to store the date when a file is "removed". - - There are four ranges of dates that CVS has to deal with when - trying to determine what revision was available on : - - 1. Dates before the earliest revision in the file. - - 2. Dates between any two revisions in the file. - - 3. Dates between the latest revision in the file and the date - when the file was moved to the Attic by "commit". - - 4. Dates after moving the file to the Attic. - - Since the date when a file is moved to the Attic is not stored - anywhere, CVS can't tell the difference between #3 and #4. - To avoid not producing a file that should exist in case #3, it - produces extraneous files in case #4. - - - For the above reason, if you have removed files in the Attic, it - is better to use "-r , or even "-r HEAD" than to use a - date spec. - - If you must use "-D ", then you should either archive and - delete Attic files (losing some past history) or construct your - Makefiles to work with an explicit list of files and let the old - source files stay in the working directory. The contents of the - revision-controlled Makefile can then be considered to contain - deletion "information". - - - 5B.4 When I typed "cvs update -D " in my branch, why did it - screw up all my files? - - Currently, the internal routine ("version_ts") that looks up - info about a file, overrides both the tag and date if *either* - the tag or date is specified on the command line. If only the - date is specified, it should not override a branch tag, but it - does. - - In CVS 1.3, the documented "-D :" syntax only - works with the Main Branch and the Vendor Branch. - - [[Is this fixed in CVS 1.4? This is one item I didn't check.]] - - - 5B.5 When I executed "checkout" into an existing directory I got "No - such file or directory" errors. Why? - - Though the man page says that "checkout" turns into an - "update -d" in directories that already exist, it is referring - to directories that already exist *and* were created by CVS. - - When you try to run "checkout" on top of an existing directory - structure, some of which wasn't created by CVS, it will handle - directories and non-CVS files within directories already under - CVS, but it will display the above error on non-CVS files within - non-CVS directories. - - - 5B.6 Why does "update" send all output to the terminal after 26 files - have been updated? - - CVS uses the "tmpnam()" function to generate temporary file names. - The ANSI standard for the "tmpnam()" function says: - - "The tmpnam function generates a different string each time it is - called, up to TMP_MAX times. If it is called more than TMP_MAX - times, the behavior is implementation defined." - - Later it says that the value of "TMP_MAX shall be at least 25." - - On some platforms, the above specification is taken literally by - turning "at least 25" into "exactly 26" and by doing something - foolish (i.e. "implementation defined") after that. Some - systems return the same name repeatedly, which causes one form of - trouble. Others return NULL or garbage, which causes a different - form of trouble. - - The broken systems appear to be cycling a single character through - the alphabet. SunOS cycles 3 characters through the alphabet, so - it won't cause trouble until 26 cubed or 17576 calls to - "tmpnam()". - - Since CVS doesn't depend on the exact format of the tmp files, the - workaround is to provide a "tmpnam()" that doesn't have a limit - on the number of calls to it. - - - 5B.7 Why does the merge occasionally resurrect lines of code? - - The diff3 program provided by GNU diff version 1.15 has a bug - that occasionally causes text to come back from the dead. - - This is an old problem which you can avoid by upgrading to the - latest GNU "diffutils" package. If you were using GNU diff - version 1.15 and plan to upgrade to the latest GNU diff program, - see the next question. - - - 5B.8 Why does the merge fail when my "rcsmerge" program is - configured to use GNU diff version 2.1 or later? - - A change in the overlap format was introduced in GNU diff3 - between versions 2.0 and 2.1 that causes RCS versions before - 5.6.0.1 to fail during a merge. - - To get consistent rcsmerge behavior, you have four choices: - - 1. Go back to using GNU diff 1.15 or 2.0 with RCS versions 5.5 or - 5.6. If you want to use GNU diff 2.1 or later, you'll have to - pick one of the other three choices in this list. - - 2. Grab RCS version 5.6.0.1 from an FSF archive and set the - DIFF3_A macro to '1' as it tells you to in the Makefile: - - #define DIFF3_A 1 - - 3. Patch the RCS 5.6 source. Change line 84 in "merger.c" from: - - DIFF3, "-am", "-L", label[0], "-L", label[1], - to - DIFF3, "-amE", "-L", label[0], "-L", "", "-L", label[1], - - 4. Wait both for RCS version 5.7 to be released and for a new - version of CVS that can deal with it. - - ----------------- --- Section 5C -- Development ----------------- - - - **** Questions: - - 5C.1 Where do I send bug reports? - 5C.2 Where do I send fixes and patches? - 5C.3 Where do I send ideas for future development? -=5C.4 What plans are there for new features? - 5C.5 I have some time and I'd like to help. What can I do for you? - - - **** Answers: - - 5C.1 Where do I send bug reports? - - First make sure it is a bug. Talk to your friends, coworkers and - anyone you know who uses CVS. Search this FAQ for related issues. - Then test it carefully. Try out variations to narrow down the - problem. Make sure it is repeatable. Look for workarounds so you - can report them. - - If you are still sure it's a bug and you tried to fix it, skip to - the next question. Otherwise, send a message to the info-cvs - mailing list containing one of the following: - - 1. If you have a good repeatable case and you think you know what - is going on, then describe the problem in detail. Include - a workaround if you have one. - - 2. If you have no idea what is going on, go ahead and send a - question to the info-cvs mailing list. Include any information - you have describing the symptoms. - - - 5C.2 Where do I send fixes and patches? - - First make sure the "fix" does something useful. Have someone - review your fix. Spend a bit of one person's time in a detailed - analysis of your vast idea before displaying a half-vast idea to - hundreds of people. - - If you tried to fix it and the patch is small, include the patch - in your message. Make sure the patch is based on the latest - released version of CVS. - - If you tried to fix it and the patch is large, you should think - about why it is so large. Did you add a generally useful feature, - or did it grow out of hand? - - If you still believe it is solid, produce a patch file using the - CVS commands "patch" or "diff -c". [[You *are* keeping CVS under - CVS, right?]] The patch should be based on the latest released - version of CVS. Then use the "cvsbug" program (provided with the - CVS sources) to send it to the CVS maintainers. A self-contained - patch that provides a single useful feature or correction might - show up independently in the patches directory of the FTP archive. - - If careful testing reveals an RCS bug rather than a CVS bug, you - can send bug reports to: rcs-bugs@cs.purdue.edu - - - 5C.3 Where do I send ideas for future development? - - If you have a bright idea, discuss it on the info-cvs mailing - list. If you have the time to implement something you can test, - send the diffs along too as described above. - - -=5C.4 What plans are there for new features? - - A "rename" or "per-directory" database has been bandied about on - the net for years. It is needed, but it is a lot of work. - - CVS version 1.5 supports remote repository access, but Paul - F. Kunz has produced another version - (rCVS) that also runs remotely. It is available for testing. - - On the host "preprint.slac.stanford.edu", you can find: - Paper: slacpubs/5000/slac-pub-5923.ps.Z - - This was for a conference in Sept, 1993, before first beta. - - On the host "ftp.slac.stanford.edu", you can find: - Sources: pub/sources/rcvs-0.8.1.tar.Z - - With the caveat that until version 1.0 is available, rCVS should - be considered an unreliable Beta release, you are invited to - grab a copy and test it. - - - [[Others?]] - - - 5C.5 I have some time and I'd like to help. What can I do for you? - - You can review this document, correct errors and fill in any of - the incomplete sections. - - You can add to the contrib area, which contains useful ways to use - some of the programmable CVS facilities (loginfo, commitinfo) or - ways of connecting to work environments (pcl-cvs). - - You could write a regression test suite. Or at least a scaffold - into which we can drop tests. - - You can write specs for new features, fix bugs, review the man - page or . . . - - [[Brian?]] - - [[Is there some way we can register someone as working - on something or should we just stay in the "implement it and - send it to me" mode?]] - ----------------- --- Section 5D -- Professional Support ----------------- - - - **** Questions: - -+5D.1 Doesn't Cygnus support CVS? -+5D.2 What is Cyclic Software doing with CVS? - - - **** Answers: - -+5D.1 Doesn't Cygnus support CVS? - - Cygnus is a company that supports a variety of FSF software. It - uses a version of CVS and people from Cygnus are on the info-cvs - mailing list. - - [[Could someone from Cygnus state Cygnus's official and unofficial - relationship with CVS?]] - - -+5D.2 What is Cyclic Software doing with CVS? - - Cyclic Software exists to provide support for CVS. Here's a copy - of their product line sheet: - - - Cyclic Software - Standard Support - - Cyclic Software offers support contracts for CVS. This - includes: - - * Full source, binaries, and documentation for CVS, RCS, GNU - diffutils, patch, and gzip -- that is, CVS and everything it - wants to run -- via FTP or tape; - - * guaranteed responses for bugs within 5 business days; - - * guaranteed fixes for reproducible bugs within 10 business days. - - (By "reproducible bugs", we mean instances where the software - clearly does not behave as documentation or reasonable - expectations indicate it should, and that we are able to - reproduce this misbehavior reliably. Naturally, we will make - every possible effort to reproduce the bugs you report; our - experience has been that it's usually not difficult.) - - We charge a fixed fee for: - - * one year - - * one host type (hardware & operating system) - - * twenty users at your site, with two of those users designated - as "contacts" for CVS, to reduce communication problems. - - If the host type is not one we have access to for testing - purposes, you can either lend us a machine of the appropriate type - for the duration of the contract, or pay an additional fee - up-front. We have access to Solaris, Irix, HP-UX, Linux and - Ultrix. (This list is subject to change; contact us for details.) - - If the above fee structure is not well-suited to your - organization, please say so. We're interested in tailoring our - services to be as useful to you as possible. - - Training - - We offer on-site training in the use of CVS at a daily rate, - plus expenses (inc. travel, accommodations). The classes target - new and intermediate users of CVS; we feel advanced users benefit - more from a written manual and the source code. - - Custom Enhancements - - We will implement enhancements to CVS or its documentation, and - port CVS to new architectures. Our rates for this work depend on - the amount of work to be done. - - We strongly prefer to work on enhancements suitable for - incorporation into the general CVS release upon completion; we - will help you design the enhancement in a way that makes this - possible. - - Short-Term Consulting - - We will do short-term consulting at hourly rates. These rates - are calculated to include the overhead of dealing in short time - periods. Therefore, in sufficiently large projects, we recommend - arranging a long-term support contract instead of dealing on an - hourly basis. - - Anything Else - - Cyclic Software is interested in arranging contracts for work - in other areas, to be produced as free software. Everything is - negotiable. - - How To Contact Us - - (Email is preferred.) - - Email: - Phone: +1 812 335 9023 - Web: http://www.cyclic.com - SnailMail: Cyclic Software - P.O. Box 804 - Bloomington, IN 47402-0804 - USA - - Contributed by Jim Blandy - - - -================================================= -== Section 6 ==== Table of Contents ==== -================================================= - -=========================================================================== -== Frequently Asked Questions about CVS (The Concurrent Versions System) == -=========================================================================== - -============================================ -== Section 0 ==== Introduction ==== -============================================ - -Questions are divided into five numbered Sections. Sections are divided -into lettered sub-sections. The questions are numbered sequentially -within each sub-section, though they are in no particular order. - - 1. What is CVS? - A. What is CVS? What's it for? Why CVS? - B. Where do I find it? Where can I find Help? - C. How does CVS differ from other similar software? - D. What do you mean by . . .? (Definitions) - - 2. User Tasks - A. Getting Started - B. Common User Tasks - C. Less Common User Tasks - D. General Questions - - 3. Commands - A. through P. One section for each CVS command. - - 4. Advanced Topics - A. Installing CVS - B. Setting up and Managing the Repository - C. Branching and Merging - D. Tricks of the Trade - E. Internal errors - F. Related Software - G. Engineering - H. Other Systems - - 5. Past & Future - A. Contributors. - B. Bugs and Patches - C. Development - D. Professional Support - - 6. Table of Contents - - - -============================================ -== Section 1 ==== What is CVS? ==== -============================================ - ----------------- --- Section 1A -- What is CVS? What's it for? Why CVS? ----------------- - 1A.1 What does CVS stand for? Can you describe it in one sentence? - 1A.2 What is CVS for? What does it do for me? - 1A.3 How does CVS work? - 1A.4 What is CVS useful for? - 1A.5 What is CVS *not* useful for? - ----------------- --- Section 1B -- Where do I find CVS? Where can I find Help? ----------------- - 1B.1 How do I get more information about CVS? - 1B.2 Is there an archive of CVS material? - 1B.3 How do I get files out of the archive if I don't have FTP? - 1B.4 How do I get a copy of the latest version of CVS? - 1B.5 Is there a mailing list devoted to CVS? How do I find it? - 1B.6 What happened to the CVS Usenet newsgroup I heard about? - ----------------- --- Section 1C -- How does CVS differ from other, similar software? ----------------- - 1C.1 How does CVS differ from RCS? - 1C.2 How does CVS differ from SCCS? - 1C.3 How does CVS differ from ClearCase? -#1C.4 How does CVS differ from TeamWare/SparcWorks? - 1C.5 How does CVS differ from Aegis? - 1C.6 How does CVS differ from Shapetools? - 1C.7 How does CVS differ from TeamNet? - 1C.8 How does CVS differ from ProFrame? - 1C.9 How does CVS differ from CaseWare/CM? - 1C.10 How does CVS differ from Sublime? - 1C.11 How does CVS differ from PVCS? - 1C.12 How does CVS differ from CMVC? - ----------------- --- Section 1D -- What do you mean by . . .? (Definitions) ----------------- - 1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"? - 1D.2 What is an RCS file? - 1D.3 What is a working file? - 1D.4 What is a working directory (or working area)? - 1D.5 What is "checking out"? - 1D.6 What is a revision? - 1D.7 What is a "Tag"? - 1D.8 What are "HEAD" and "BASE"? - 1D.9 What is a Branch? - 1D.10 What is "the trunk"? - 1D.11 What is a module? - 1D.12 What does "merge" mean? - - -========================================== -== Section 2 ==== User Tasks ==== -========================================== - ----------------- --- Section 2A -- Getting Started ----------------- - 2A.1 What is the first thing I have to know? - 2A.2 Where do I work? - 2A.3 What does CVS use from my environment? - 2A.4 OK, I've been told that CVS is set up, my module is named - "ralph" and I have to start editing. What do I type? - 2A.5 I have been using RCS for a while. Can I convert to CVS without - losing my revision history? How about converting from SCCS? - ----------------- --- Section 2B -- Common User Tasks ----------------- - 2B.1 What is the absolute minimum I have to do to edit a file? - 2B.2 If I edit multiple files, must I type "commit" for each one? - 2B.3 How do I get rid of the directory that "checkout" created? - 2B.4 How do I find out what has changed since my last update? - 2B.5 I just created a new file. How do I add it to the Repository? - 2B.6 How do I merge changes made by others into my working directory? - 2B.7 How do I label a set of revisions so I can retrieve them later? - 2B.8 How do I checkout an old release of a module, directory or file? - 2B.9 What do I have to remember to do periodically? - ----------------- --- Section 2C -- Less Common User Tasks ----------------- - 2C.1 Can I create non-CVS sub-directories in my working directory? - 2C.2 How do I add new sub-directories to the Repository? - 2C.3 How do I remove a file I don't need? - 2C.4 How do I rename a file? - 2C.5 How do I make sure that all the files and directories in my - working directory are really in the Repository? - 2C.6 How do I create a branch? - 2C.7 How do I modify the modules file? How about the other files in - the CVSROOT administrative area? - 2C.8 How do I split a file into pieces, retaining revision histories? - ----------------- --- Section 2D -- General Questions ----------------- - 2D.1 How do I see what CVS is trying to do? - 2D.2 If I work with multiple modules, should I check them all out and - commit them occasionally? Is it OK to leave modules checked out? - 2D.3 What is a "sticky" tag? What makes it sticky? How do I loosen it? - 2D.4 How do I get an old revision without updating the "sticky tag"? - 2D.5 What operations disregard sticky tags? - 2D.6 Is there a way to avoid reverting my Emacs buffer after - committing a file? Is there a "cvs-mode" for Emacs? - 2D.7 How does conflict resolution work? What *really* happens if two - of us change the same file? - 2D.8 How can I tell who has a module checked out? - 2D.9 Where did the .#.1.3 file in my working directory come from? - 2D.10 What is this "ignore" business? What is it ignoring? - 2D.11 Is there a way to set user-specific configuration options? - 2D.12 Is it safe to interrupt CVS using Control-C? - 2D.13 How do I turn off the "admin" command? - 2D.14 How do I turn off the ability to disable history via "cvs -l"? - 2D.15 How do I keep certain people from accessing certain directories? - - -======================================== -== Section 3 ==== Commands ==== -======================================== - ----------------- --- Section 3A -- "add", "ad", "new" ----------------- - 3A.1 What is "add" for? - 3A.2 How do I add a new file to the branch I'm working on? - 3A.3 Why did my new file end up in the Attic? - 3A.4 Now that it's in the Attic, how do I connect it to the Main branch? - 3A.5 How do I avoid the hassle of reconnecting an Attic-only file to - the Main Branch? - 3A.6 How do I cancel an "add"? - 3A.7 What are the ./CVS/file,p and ./CVS/file,t files for? - 3A.8 How do I "add" a binary file? - ----------------- --- Section 3B -- "admin", "adm", "rcs" ----------------- - 3B.1 What is "admin" for? - 3B.2 Wow! Isn't that dangerous? - 3B.3 What would I normally use "admin" for? - 3B.4 What should I avoid when using "admin"? - 3B.5 How do I restrict the "admin" command? The -i flag in the modules - file can restrict commits. What's the equivalent for "admin"? - 3B.6 I backed out a revision with "admin -o" and committed a - replacement. Why doesn't "update" retrieve the new revision? - ----------------- --- Section 3C -- "checkout", "co", "get" ----------------- - 3C.1 What is "checkout" for? - 3C.2 What is the "module" that "checkout" takes on the command line? - 3C.3 Isn't a CVS "checkout" just a bunch of RCS checkouts? - 3C.4 What's the difference between "update" and "checkout"? - 3C.5 Why can't I check out a file from within my working directory? - 3C.6 How do I avoid dealing with those long relative pathnames? - 3C.7 Can I move a checked-out directory? Does CVS remember where it - was checked out? - 3C.8 How can I lock files while I'm working on them the way RCS does? - 3C.9 What is "checkout -s"? How is it different from "checkout -c"? - ----------------- --- Section 3D -- "commit", "ci", "com" ----------------- - 3D.1 What is "commit" for? - 3D.2 If I edit ten files, do I have to type "commit" ten times? - 3D.3 Explain: cvs commit: Up-to-date check failed for `' - 3D.4 What happens if two people try to "commit" conflicting changes? - 3D.5 I committed something and I don't like it. How do I remove it? - 3D.6 Explain: cvs commit: sticky tag `V3' for file `X' is not a branch - 3D.7 Why does "commit -r " put newly added files in the Attic? - 3D.8 Why would a "commit" of a newly added file not produce rev 1.1? - ----------------- --- Section 3E -- "diff", "di", "dif" ----------------- - 3E.1 What is "diff" for? - 3E.2 Why did "diff" display nothing when I know there are later - committed revisions in the Repository? - 3E.3 How do I display what changed in the Repository since I last - executed "checkout", "update" or "commit"? - 3E.4 How do I display the difference between my working file and what - I checked in last Thursday? - 3E.5 Why can't I pass long options, like --unified, to "diff"? - ----------------- --- Section 3F -- "export", "exp", "ex" ----------------- - 3F.1 What is "export" for? - 3F.2 Why does it remove the RCS keywords so I can't use the "ident" - command on the source files? - 3F.3 Can I override the '-kv' flag CVS passes to RCS? - 3F.4 Why doesn't "export" have a '-k' flag like "import" does? - 3F.5 Why does "export -D" check out every file in the Attic? - ----------------- --- Section 3G -- "history", "hi", "his" ----------------- - 3G.1 What is "history" for? - 3G.2 Of what use is it? - 3G.3 What is this, Big Brother? - 3G.4 I deleted my working directory and "history" still says I have - it checked out. How do I fix it? - 3G.5 So I *can* edit the History file? - 3G.6 Why does the history file grow so quickly? - 3G.7 What is the difference between "cvs history -r " and - "cvs history -t "? - 3G.8 Why does "cvs history -c -t " fail to print anything? - 3G.9 "cvs history -a -o" only printed one line for each checked-out - module. Shouldn't it print all the directories where the - modules are checked out? - 3G.10 I can't figure out "history", can you give me concrete examples? - 3G.11 Can we merge history files when we merge Repositories? - ----------------- --- Section 3H -- "import", "im", "imp" ----------------- - 3H.1 What is "import" for? - 3H.2 How am I supposed to use "import"? - 3H.3 Why does import put files on a branch? Why can't I work on the - main trunk instead of a Vendor branch? - 3H.4 Is there any way to import binary files? - 3H.5 Why does "import" corrupt some binary files? - 3H.6 How do I retain the original $\Revision$ strings in the sources? -=3H.7 I imported some files for the Yarg compiler that compiles files - with a suffix of ".yarg" and whose comment prefix is "YARG> ". - When I check them out, they will no longer compile because they - have this junk in them. Why? - 3H.8 How do I make "import" save the timestamps on the original files? - 3H.9 Why can't I "import" 3 releases on different branches? - 3H.10 What do I do if the Vendor adds or deletes files between releases? - 3H.11 What about if the Vendor changes the names of files or - directories, or rearranges the whole structure between releases? - 3H.12 I thought "import" was for Vendor releases, why would I use it - for code of my own? Do I have to use import? - 3H.13 How do I import a large Vendor release? - 3H.14 Explain: ERROR: cannot create link to : Permission denied - 3H.15 Where does the -m go when the file doesn't change? - 3H.16 How do I "import" just the files ignored by a previous "import"? - 3H.17 Why did "import" ignore all the symlinks? - ----------------- --- Section 3I -- "log", "lo", "rlog" ----------------- - 3I.1 What is "log" for? - 3I.2 How do I extract the log entries between two revisions? - 3I.3 How do I extract the log entries on a whole branch? - 3I.4 How do I generate ChangeLogs from RCS logs? - 3I.5 Why does "log" tell me a file was committed exactly 5 hours later - than I know it was? - ----------------- --- Section 3J -- "patch", "pa", "rdiff" ----------------- - 3J.1 What is "patch" for? - 3J.2 Why does "patch" include files from the Attic when I use '-D'? - 3J.3 How do I make "patch" produce a patch for one or two files? - It seems to work only with modules. - ----------------- --- Section 3K -- "release", "re", "rel" ----------------- - 3K.1 What is "release" for? - 3K.2 Why can't I reverse a "cvs checkout path/name/subdir" with a - "cvs release path/name/subdir" without an "unknown module name"? - 3K.3 Why can't I "release" portions of a checked out directory? I - should be able to "release" any file or sub-directory within - my working directory. - 3K.4 I removed the tree that I was about to start working on. How do I - tell cvs that I want to release it if I don't have it anymore? - 3K.5 Why doesn't "release -d module" reverse a "checkout module"? - 3K.6 Why can't I release a module renamed with "cvs checkout -d"? - ----------------- --- Section 3L -- "remove", "rm", "delete" ----------------- - 3L.1 What is "remove" for? - 3L.2 Why doesn't "remove" work on directories when it appears to try? - 3L.3 I don't like removing files. Is there another way to ignore them? - 3L.4 I just removed a file. How do I resurrect it? - 3L.5 Why doesn't "remove" delete the file? Instead, it prints an - error message and tells me to remove the file by hand. - ----------------- --- Section 3M -- "rtag", "rt", "rfreeze" ----------------- - 3M.1 What is "rtag" for? - 3M.2 Why use "rtag"? It assumes no one is changing the Repository. - 3M.3 What revision does "rtag -r " actually put the tag on? - 3M.4 What happens if the tags are the same in "rtag -r "? - 3M.5 Why doesn't "rtag -b -r " rename or - duplicate a magic branch tag? - ----------------- --- Section 3N -- "status", "st", "stat" ----------------- - 3N.1 What is "status" for? - 3N.2 Why does "status" limit the File: at the top to 17 characters? - 3N.3 Why does it print "Sticky" lines when the values are "(none)"? - 3N.4 Shouldn't the status "Needs Checkout" be "Needs Update"? - ----------------- --- Section 3O -- "tag", "ta", "freeze" ----------------- - 3O.1 What is "tag" for? - 3O.2 What is the difference between "tag" and "rtag"? - 3O.3 Why does "tag -b" not put a tag on the Branch Point revision? - How do I refer to the Branch Point? - 3O.4 So "{r}tag" labels a bunch of files. What do you use a Tag for? - 3O.5 How do I get "tag" and "rtag" to send mail the way "commit" does? - 3O.6 Why can't "tag" handle the '-r' option that "rtag" takes? - 3O.7 After a "tag " in my working directory, why doesn't "checkout - -r " somewhere else produce copies of my current files? - 3O.8 Why doesn't "tag" write a history record the way "rtag" does? - 3O.9 How do I rename a ? - ----------------- --- Section 3P -- "update", "up", "upd" ----------------- - 3P.1 What is "update" for? - 3P.2 What do 'U', 'M' and 'C' mean when I type "update"? Are they - different for "cvs -n update"? - 3P.3 What's the difference between "update" and "checkout"? - 3P.4 Why don't I get new files when I execute "update"? - 3P.5 Why does "update" say 'M' both for plain modified files and for - successful (i.e. conflict-free) merges? Aren't they different? - 3P.6 What's a "sticky conflict"? How does it know a conflict occurred? - 3P.7 Is there a feature to tell me what I have changed, added and - removed without changing anything? - 3P.8 Why were all my files deleted when I executed "update"? - - -=============================================== -== Section 4 ==== Advanced Topics ==== -=============================================== - ----------------- --- Section 4A -- Installing CVS ----------------- - 4A.1 What do I have to do before I install CVS? - 4A.2 How do I configure the CVS programs? - 4A.3 What do I have to install? - 4A.4 How do I work around the merge problems in GNU diff version 2.1 - or later? - ----------------- --- Section 4B -- Setting up and Managing the Repository ----------------- - 4B.1 What do I do first? How do I create a Repository? - 4B.2 What are those files in $CVSROOT/CVSROOT? - 4B.3 Is there any other state stored in the Repository besides in the - $CVSROOT/CVSROOT directory? - 4B.4 How do I put sources into the Repository? - 4B.5 What file permissions should I use on (and in) the Repository? - 4B.6 How do I structure my Repository? - 4B.7 Why would anyone use "modules"? They are too restrictive. I - want to be able to select just the files I want to edit. - 4B.8 How do I rename a file or directory? What are the consequences? - 4B.9 What are "Attic" directories? - 4B.10 Is it OK to remove anything from the Repository? - 4B.11 Can I convert to CVS from RCS without losing my revision history? - 4B.12 Can I move RCS files with branches in them into the Repository? - 4B.13 Can I use raw RCS commands on the Repository? - 4B.14 How do I convert from SCCS to RCS? - 4B.15 How do I limit access to the Repository? - 4B.16 What are the Repository Administrator's responsibilities? - 4B.17 How do I move the whole Repository? - 4B.18 How do I change permissions on a file in the Repository by using - a CVS command? (i.e. without using "chmod 777 $CVSROOT/dir/file") - ----------------- --- Section 4C -- Branching and Merging ----------------- - 4C.1 What is a branch? - 4C.2 Why (or when) would I want to create a branch? - 4C.3 How do I create and checkout a branch? - 4C.4 Once created, how do I manage a branch? - 4C.5 Are there any extra issues in managing multiple branches? - 4C.6 How do I merge a whole branch back into the trunk? -=4C.7 How do I merge changes from the trunk into my branch or between - branches? - 4C.8 How do I merge onto the Main Branch a file that exists only on a - branch other than the Main Branch? (i.e. it is in the Attic) - 4C.9 How do I know what branch I'm (working) on? - 4C.10 Do I really have to know the name of the branch I'm working on? - 4C.11 How do I refer to the revision where I branched so I can see - what changed since the Branch Point on another branch? - 4C.12 Why didn't the command "cvs admin -bBRANCH1 *" create a branch? - 4C.13 Is it possible to set the "default CVS branch" for everyone? - 4C.14 How do I perform a large merge? - 4C.15 Is a Vendor merge any different from a branch merge? - 4C.16 How do I go back to a previous version of the code on a branch? - 4C.17 Once I've found the files I want, how do I start changing them? - I keep getting warnings about sticky tags. - 4C.18 Why do I get the latest files on the branch when I tried to - "update -r "? - 4C.19 How can I avoid a merge? I just want to move the latest revision - on my working branch directly onto the trunk. - 4C.20 How to I avoid merge collisions in the RCS $\Log$ data? - 4C.21 Why should I trust automatic merges? - 4C.22 How does CVS decide if it can safely perform a merge? - 4C.23 After resolving merge conflicts in a file, what if I want to keep - my previous version, and not take any of the branch changes? - ----------------- --- Section 4D -- Tricks of the Trade ----------------- - 4D.1 How can you even check in binary files, let alone allow CVS to - do its auto-merge trick on them? - 4D.2 Can I edit the RCS (",v") files in the Repository? - 4D.3 Can I edit the ./CVS/{Entries,Repository,Tag} files? - 4D.4 Someone executed "admin -o" and removed revisions to which - tags/symbols were attached. How do I fix them? - 4D.5 How do I move or rename a magic branch tag? - 4D.6 Can I use RCS locally to record my changes without making them - globally visible by committing them? - 4D.7 How can I allow access to the Repository by both CVS and RCS? - 4D.8 I "updated" a file my friend, "bubba", committed yesterday. - Why doesn't the file now have a modified date of yesterday? - 4D.9 While in the middle of a large "commit", how do I run other - commands, like "diff" or "stat" without seeing lock errors? - 4D.10 Where did the ./CVS/Entries.Static file come from? What is it for? - 4D.11 Why did I get the wrong Repository in the loginfo message? - 4D.12 How do I run CVS setuid so I can only allow access through the - CVS program itself? - 4D.13 How about using groups and setgid() then? - 4D.14 How do I use the "commitinfo" file? - 4D.15 How do I use the "loginfo" files? - 4D.16 How can I keep people with restrictive umask values from blocking - access to the Repository? - 4D.17 Why do timestamps sometimes get set to the date of the revision, - sometimes not? The inconsistency causes unnecessary recompiles. - ----------------- --- Section 4E -- Internal errors ----------------- - 4E.1 Explain: "ci error: unexpected EOF in diff output" - 4E.2 Explain: "RCS file /Repository/module/file.c,v is in use" - 4E.3 Explain: "co error, line 2: Missing access list" - 4E.4 Explain: "error: RCS file name `xyz .c' contains white space" - 4E.5 Explain: cvs checkout: warning: is not (any longer) pertinent - 4E.6 Why did a Repository file change from ,v to ,,? - ----------------- --- Section 4F -- Related Software ----------------- - 4F.1 How do I use CVS under Emacs? Is there an Emacs cvs-mode? - 4F.2 What is GIC (Graphical Interface to CVS)? - 4F.3 What is CAVEMAN? - ----------------- --- Section 4G -- Engineering ----------------- - 4G.1 Where can I find out about Software Engineering? - 4G.2 How do I flexibly arrange the modules file to describe my sources? - 4G.3 Can I have multiple source repositories, one for each project? - 4G.4 Who should administer the Repository and manage the modules file? - 4G.5 Isn't disk space a big factor? CVS copies files out of the - Repository, duplicating everything. - ----------------- --- Section 4H -- Other Systems ----------------- - 4H.1 I use a NeXT. Is there anything I need to know? - 4H.2 I use OS/2 and/or DOS. Is there anything I need to know? - 4H.3 I use SCO Unix. Is there anything I need to know? - 4H.4 I use AIX. Is there anything I need to know? - 4H.5 I use IRIX. Is there anything I need to know? - 4H.6 I use an HP system. Is there anything I need to know? - 4H.7 I use AFS. Is there anything I need to know? - 4H.8 I use A/UX. Is there anything I need to know? - - -============================================= -== Section 5 ==== Past & Future ==== -============================================= - ----------------- --- Section 5A -- Contributors ----------------- -=5A.1 Who wrote CVS? - 5A.2 You didn't write all of this FAQ, did you? - ----------------- --- Section 5B -- Bugs and Patches ----------------- - 5B.1 Why can't CVS handle deletion of directories? - 5B.2 Why can't CVS handle the moving of sources from one place in the - directory hierarchy to another? - 5B.3 When I typed "cvs update -D ", why did it check out all - sorts of ancient files from the Attic? Shouldn't it just create - the set of files and revisions that existed at that date? - 5B.4 When I typed "cvs update -D " in my branch, why did it - screw up all my files? - 5B.5 When I executed "checkout" into an existing directory I got "No - such file or directory" errors. Why? - 5B.6 Why does "update" send all output to the terminal after 26 files - have been updated? - 5B.7 Why does the merge occasionally resurrect lines of code? - 5B.8 Why does the merge fail when my "rcsmerge" program is - configured to use GNU diff version 2.1 or later? - ----------------- --- Section 5C -- Development ----------------- - 5C.1 Where do I send bug reports? - 5C.2 Where do I send fixes and patches? - 5C.3 Where do I send ideas for future development? -=5C.4 What plans are there for new features? - 5C.5 I have some time and I'd like to help. What can I do for you? - ----------------- --- Section 5D -- Professional Support ----------------- -+5D.1 Doesn't Cygnus support CVS? -+5D.2 What is Cyclic Software doing with CVS? - - -================================================= -== Section 6 ==== Table of Contents ==== -================================================= - -% End of Table of Contents -% End of CVS FAQ document - -# Local Variables: -# mode: text -# fill-column: 74 -# fill-prefix: "\t" -# End: +This file formerly contained a CVS FAQ, maintained by David Grubbs. +However, it has been out of date for a long time, he officially gave up +maintaining it in the fall of 1995, and noone else has taken it over. +Most of the information which used to be in it can be found in the CVS +manual, doc/cvs.texinfo in this distribution. For information on +questions like "what is the latest version of CVS?" and "what about GUIs +for CVS?", see the CVS web site, +http://www.loria.fr/~molli/cvs-index.html. There are many web sites on +Configuration Management packages (of which CVS is an example); for +example see + +http://www.yahoo.com/Computers_and_Internet/Software/Software_Engineering/Configuration_Management/index.html + +or http://www.iac.honeywell.com/Pub/Tech/CM/index.html. diff --git a/gnu/usr.bin/cvs/INSTALL b/gnu/usr.bin/cvs/INSTALL index 8bb34777f54..54239ad9b6f 100644 --- a/gnu/usr.bin/cvs/INSTALL +++ b/gnu/usr.bin/cvs/INSTALL @@ -1,3 +1,5 @@ +#ident "$CVSid$" + First, read the README file. If you're still happy... CVS has been tested on the following platforms. The most recent @@ -12,40 +14,46 @@ Alpha: DEC Alpha running OSF/1 version 3.0 (1.5.95) (footnote 7) HPPA: HP 9000/710 running HP-UX 8.07A using gcc (about 1.4A2) - HP 9000/715 running HP-UX 9.01 using gcc (about 1.4A2) + HP 9000/715 running HP-UX 9.01 (1.6) HPPA 1.1 running HP-UX A.09.03 (1.5.95) (footnote 8) - NextSTEP 3.3 (1.4.92, a few tweaks needed) + NextSTEP 3.3 (1.6.86) i386 family: - Gateway P5-66 (pentium) running Solaris 2.4 using gcc (about 1.4A2) - PC Clone running UnixWare v1.1.1 using gcc (about 1.4A2) - PC Clone running ISC 4.0.1 (1.5.94) - PC Clone running Fintronic Linux 1.2.5 (1.5) - PC Clone running BSDI 2.0 (1.4.93) (footnote 5) - PC Clone running Windows NT 3.51 (1.5 client) + Solaris 2.4 using gcc (about 1.4A2) + UnixWare v1.1.1 using gcc (about 1.4A2) + ISC 4.0.1 (1.5.94) + Linux (kernel 1.2.x) (1.6.86) + BSDI 2.0 (1.4.93) (footnote 5) FreeBSD 2.0.5, i486, gcc (1.5.95) - NextSTEP 3.3 (1.4.92, a few tweaks needed) + NextSTEP 3.3 (1.6.86) SCO Unix 3.2.4.2 (1.4.93) (footnote 4) SCO OpenServer 5.0.0, "CC='cc -b elf' configure" + Lynx 2.3.0 080695 (1.6.86) (footnote 9) + Windows NT 3.51 (1.6.86 client-only) m68k: - NextSTEP 3.3 (1.4.92, a few tweaks needed) + Sun 3 running SunOS 4.1.1_U1 w/ bundled K&R /usr/5bin/cc (1.6) + NextSTEP 3.3 (1.6.86) + Lynx 2.3.0 062695 (1.6.86) (footnote 9) m88k: Data General AViiON running dgux 5.4R2.10 (1.5) Harris Nighthawk 5800 running CX/UX 7.1 (1.5) (footnote 6) MIPS: DECstation running Ultrix 4.2a (1.4.90) - DECstation running Ultrix 4.3 (1.5) + DECstation running Ultrix 4.3 (1.6.86) SGI running Irix 4.0.5H using gcc and cc (about 1.4A2) (footnote 2) SGI running Irix 5.3 (1.4.93) SGI running Irix-6 (about 1.4.90) (footnote 3) + Siemens-Nixdorf RM600 running SINIX-Y (1.6) PowerPC or RS/6000: - IBM RS/6000 running AIX 3.2.5 (cc=xlc, CVS 1.5) + IBM RS/6000 running AIX 3.1 using gcc and cc (1.6.86) + IBM RS/6000 running AIX 3.2.5 using xlc (1.5) IBM RS/6000 running AIX 4.1 using gcc and cc (about 1.4A2) (footnote 1) + Lynx 2.3.1 120495 (1.6.86) (footnote 9) SPARC: - Sun SPARC running SunOS 4.1.3, 4.1.2, and 4.1.1 (1.5) - Sun SPARC running SunOS 4.1.3, w/ bundled K&R cc (1.5.94) + Sun SPARC running SunOS 4.1.x (1.6.86) Sun SPARCstation 10 running Solaris 2.3 using gcc and cc (about 1.4A2) Sun SPARCstation running Solaris 2.4 using gcc and cc (about 1.5.91) - NextSTEP 3.3 (1.4.92, a few tweaks needed) + Sun SPARC running Solaris 2.5 (2.5 beta?) (1.6.4) + NextSTEP 3.3 (1.6.86) (footnote 1) AIX 4.1 systems fail to run "configure" due to bugs in their @@ -79,6 +87,17 @@ SPARC: success with this configure command: CC=cc CFLAGS='+O2 -Aa -D_HPUX_SOURCE' ./configure --verbose hppa1.1-hp-hpux +(footnote 9) + Had to configure with ./configure --host=-lynx. + + In src/cvs.h, protected the waitpid prototype with ifdef _POSIX_SOURCE. + (I might try building with gcc -mposix -D_POSIX_SOURCE.) + + LynxOS has , but you don't want to use it. + You want to use instead. + So after running configure I had to undef HAVE_DIRENT_H and + define HAVE_SYS_DIR_H. + ------------------------------------------------------------------------------- Installation under Unix: @@ -98,33 +117,50 @@ Installation under Unix: This release of CVS also requires RCS commands to be installed in the user's PATH (or a path you have configured in src/options.h). - If you don't have RCS, you will need to get it from GNU as well. - It is best to get the version 5.6.0.1 (or later) version of RCS, - available from prep.ai.mit.edu in the file - pub/gnu/rcs-5.6.0.1.tar.Z. It is best (although not essential) to - avoid RCS versions 5.6.[5-7] beta because the rcsmerge therein - defaults to -A instead of -E which affects the way CVS handles - conflicts (this is fixed in RCS 5.6.8 and RCS 5.7). Along with - RCS, you will want to run GNU diff. This will allow revision - control of files with binary data (a real nice feature). You will - need at least version 1.15 of GNU diff for this to work. Be sure - that you configure RCS to work correctly with GNU diff to avoid - other configuration problems. If you are running RCS 5.7, you - should be aware that you must supply a log message containing at - least one non-whitespace character (CVS catches some, but not all, - cases). This has always been a problem but the symptoms are - apparently more severe with RCS 5.7. This is expected to be fixed - in a future CVS release. - - If you are using the remote client, you will need a version of - patch which understands unidiffs (such as any recent version of - GNU patch). + If you don't have RCS, you will need to get it from GNU as well. It + is best to get the version 5.7 (or later) version of RCS, available + from prep.ai.mit.edu in the file pub/gnu/rcs-5.7.tar.gz. It is best + (although not essential) to avoid RCS versions 5.6.[5-7] beta + because the rcsmerge therein defaults to -A instead of -E which + affects the way CVS handles conflicts (this is fixed in RCS 5.6.8 + and RCS 5.7). + + Along with RCS, you will want to run GNU diffutils. This will allow + revision control of files with binary data (a real nice feature). + You will need at least version 1.15 of GNU diff for this to work. + The current version of GNU diffutils is 2.7, and it is also + available from prep.ai.mit.edu in the file pub/gnu/diffutils-2.7.tar.gz. + + WARNING: Be sure that you (have) configure(d) RCS to work correctly + with GNU diff to avoid other configuration problems. + + Configure will attempt to discern the location of your most capable + version of diff, and tries to find the GNU Diffutils version first. + You can explicitly tell configure to use the diffutils that's + installed in the same place you intend to install CVS: + + $ ./configure --with-diffutils + + Or, if you've installed it somewhere else, you can give configure + the full pathname: + + $ ./configure --with-diffutils=/usr/gnu/bin/diff + + If you are using the remote client, you will need patch installed. NOTE: The configure program will cache the results of the previous configure execution. If you need to re-run configure from scratch, you may need to run "make distclean" first to remove the cached configuration information. + If you are using gcc and are planning to modify CVS, you may want to + configure with -Wall, which can detect many programming errors. This + is not the default because it might cause spurious warnings, but at least + on some machines, there are no spurious warnings. For example: + $ CFLAGS="-g -Wall" ./configure + + Try './configure --help' for further information on its usage. + NOTE ON CVS's USE OF NDBM: By default, CVS uses some built-in ndbm emulation code to allow @@ -172,10 +208,35 @@ Installation under Unix: $ make - This will (hopefully) make the needed CVS binaries within the "src" - directory. Send me your "config.status" file with your host type, - operating system information, and make output if something fails for - your system. + This will (hopefully) make the needed CVS binaries within the + "src" directory. If something fails for your system, and you want + to submit a bug report, you may wish to include your + "config.status" file, your host type, operating system and + compiler information, make output, and anything else you think + will be helpful. + +3a) Run the regression tests (optional). + + You may also wish to validate the correctness of the new binary by + running the regression tests: + + $ make check + + Note that if your /bin/sh doesn't support shell functions, you'll + have to try something like this, where "/bin/sh5" is replaced by the + pathname of a shell which handles normal shell functions: + + $ make SHELL=/bin/sh5 check + + WARNING: This test can take quite a while to run, esp. if your + disks are slow or over-loaded. + + If you receive any un-expected output from the regression tests, + it may indicate a bug in CVS (or might just indicate a problem + running the tests). If you choose to submit a bug report, + relevant information to include might be your "config.status" + file, your host type, operating system and compiler information, + the contents of check.log, and any "make check" output. 4) Install the binaries/documentation: @@ -215,14 +276,16 @@ Installation under Unix: PATH. There are many ways to customize CVS for your site. Read the cvs(5) manual page when you get the chance. -7) Have all users of the CVS system set the CVSROOT environment variable - appropriately to reflect the placement of your source repository. If - the above example is used, the following commands can be placed in - user's ~/.profile, ~/.bash_profile, or ~/.login file: +7) Have all users of the CVS system set the CVSROOT environment + variable appropriately to reflect the placement of your source + repository. If the above example is used, the following commands + can be placed in user's ~/.profile, ~/.bash_profile file; or in the + site-wide /etc/profile: CVSROOT=/src/master; export CVSROOT - for sh/bash/ksh users, or + for sh/bash/ksh users, or place the following commands in the user's + ~/.cshrc, ~/.login, or /etc/chsrc file: setenv CVSROOT /src/master @@ -237,7 +300,7 @@ Installation under Unix: following commands: $ make distclean - $ cvs import -m 'CVS 1.4 distribution' cvs CVS CVS1_4 + $ cvs import -m 'CVS 1.6 distribution' cvs CVS CVS-1_6 9) Having done step 8, one should be able to checkout a fresh copy of the CVS distribution and hack away at the sources with the following command: @@ -259,12 +322,14 @@ Installation under Unix: ------------------------------------------------------------------------------- -Detailed info about your interaction with "configure": +Detailed information about your interaction with "configure": The "configure" script and its interaction with its options and the -environment is described here. +environment is described here. For more detailed documentation about +"configure", please refer to the GNU Autoconf documentation. Supported options are: + --srcdir=DIR Useful for compiling on many different machines sharing one source tree. --prefix=DIR The root of where to install the @@ -272,15 +337,17 @@ Supported options are: --exec_prefix=DIR If you want executables in a host-dependent place and shared things in a host-independent place. + --with-diffutils[=PATH] Assume use of GNU diffutils is possible. The following environment variables override configure's default behaviour: + CC If not set, tries to use gcc first, then cc. Also tries to use "-g -O" as options, backing down to -g alone if that doesn't work. INSTALL If not set, tries to use "install", then - "cp" as a final choice. + "./install-sh" as a final choice. RANLIB If not set, tries to determine if "ranlib" is available, choosing "echo" if it doesn't appear to be. diff --git a/gnu/usr.bin/cvs/NEWS b/gnu/usr.bin/cvs/NEWS index 332b72f2cbb..23f781dc4a1 100644 --- a/gnu/usr.bin/cvs/NEWS +++ b/gnu/usr.bin/cvs/NEWS @@ -1,3 +1,45 @@ +Changes since 1.7: + + + +Changes from 1.6 to 1.7: + +* The default ignore list has changed slightly: *.obj has been added +and CVS* has been changed to CVS CVS.adm. + +* CVS now supports password authentication when accessing remote +repositories; this is useful for sites that can't use rsh (because of +a firewall, for example), and also don't have kerberos. See node +"Password authenticated" (in "Remote repositories", in +doc/cvs.texinfo) for more details. Note: This feature requires both +the client and server to be upgraded. + +* Using the -kb option to specify binary files now works--most cases +did not work before. See the "Binary files" section of +doc/cvs.texinfo for details. + +* New developer communication features. See the "Watches" section of +doc/cvs.texinfo for details. + +* RCS keyword "Name" supported for "cvs update -r " and "cvs +checkout -r ". + +* If there is a group whose name matches a compiled in value which +defaults to "cvsadmin", only members of that group can use "cvs +admin". This replaces the CVS_NOADMIN option. + +* CVS now sets the modes of files in the repository based on the +CVSUMASK environment variable or a compiled in value defaulting to +002. This way other developers will be able to access the files in +the repository regardless of the umask of the developer creating them. + +* The command names in .cvsrc now match the official name of the +command, not the one (possibly an alias) by which it was invoked. If +you had previously relied on "cvs di" and "cvs diff" using different +options, instead use a shell function or alias (for example "alias +cvsdi='cvs diff -u'"). You also can specify global CVS options (like +"-z") using the command name "cvs". + Changes from 1.5 to 1.6: * Del updated the man page to include all of the new features diff --git a/gnu/usr.bin/cvs/README b/gnu/usr.bin/cvs/README index d223601df63..08827861453 100644 --- a/gnu/usr.bin/cvs/README +++ b/gnu/usr.bin/cvs/README @@ -36,7 +36,10 @@ program and fill out the template: The "cvsbug" program is installed in the same location as the "cvs" program. If your installation failed, you may need to run "cvsbug" -directly out of the "src" directory as "src/cvsbug.sh". +directly out of the "src" directory as "src/cvsbug.sh". This is also +the procedure for submitting suggested changes to CVS--note that all +submitted changes may be distributed under the terms of the GNU Public +License, so if you don't like this, don't submit them. Please consult the INSTALL file for information on tested configurations. If you have a comment about an already tested @@ -99,6 +102,7 @@ Please read the INSTALL file for installation instructions. Brief summary: $ ./configure $ make + $ make check # optional, long-running, step $ make install $ cvsinit @@ -107,12 +111,11 @@ Please read the INSTALL file for installation instructions. Brief summary: * How do I get up-to-date information and information about other versions of CVS? -On the web, http://www.winternet.com/~zoo/cvs/ or -http://www.loria.fr/~molli/cvs-index. +On the web, http://www.loria.fr/~molli/cvs-index.html. The mailing list for CVS is info-cvs@prep.ai.mit.edu. Send subscription and removal requests for that list to -info-cvs-requests@prep.ai.mit.edu. +info-cvs-request@prep.ai.mit.edu. [Historical note: info-cvs@prep.ai.mit.edu is now the union of info-cvs@prep and cyclic-cvs@cyclic.com. Please use the prep @@ -195,7 +198,7 @@ apologize. Just write to me and let me know! Raye Raskin Harlan Stenn Gunnar Tornblom - Greg A. Woods + Greg A. Woods Many contributors have added code to the "contrib" directory. See the README file there for a list of what is available. There is also a diff --git a/gnu/usr.bin/cvs/TODO b/gnu/usr.bin/cvs/TODO index 2f5eb808bef..13ec12d116a 100644 --- a/gnu/usr.bin/cvs/TODO +++ b/gnu/usr.bin/cvs/TODO @@ -6,9 +6,6 @@ $CVSid: @(#)TODO 1.26 94/09/21 $ appropriate points ]] (I'm not sure what this means -kingdon, Jun 1995). -16. List of current users of a directory needs to be maintained. - [[ sort of solved by history database ]] - 22. Catch signals for cleanup when "add"ing files. 24. Insist on a log message. @@ -42,20 +39,6 @@ $CVSid: @(#)TODO 1.26 94/09/21 $ [[ most commands now use the generic recursion processor, but not all; this note is left here to remind me to fix the others ]] -51. a way to identify what files other people are working on. Imagine "cvs - modified", which prints out a table like - - file modifiers - ===== ========= - foo.c - bar.c wsd - baz.c nrt jda - - I think this would be pretty difficult; I don't know if this - information is stored anywhere. Also it's hard to say how one gets a - user name, maybe a path to their local hierarchy is all you could get. - [[ the history stuff does some of this, but not all ]] - 52. SCCS has a feature that I would *love* to see in CVS, as it is very useful. One may make a private copy of SCCS suid to a particular user, so other users in the authentication list may check files in and out of @@ -67,21 +50,6 @@ $CVSid: @(#)TODO 1.26 94/09/21 $ such as CVS with features that provide group-like functionality would be a huge help. -53. I'd suggest a way to notify users if/when a file(s) is being worked on. - I suggest: - + Always checkout/update files a readonly. - + To work on a file, the user should do: - cvs advise filename - + This would maintain their email address associated with that - file name in the repository and change the file mode to writable. - + If other references to that file exist, the registered individuals - are notified via email that another user(s) is going to be working - on same. - + When a committ occurs, the user is automatically 'unadvise'd (the - inverse command should be supported as well) and other's are notified - that a merge will be necessary before their checkin can be - successful. - 62. Consider using revision controlled files and directories to handle the new module format -- consider a cvs command front-end to add/delete/modify module contents, maybe. @@ -93,7 +61,7 @@ $CVSid: @(#)TODO 1.26 94/09/21 $ [[ it got better, then we added functionality, making it worse again ]] 66. Length of the CVS temporary files must be limited to 14 characters for - System-V stupid support. As weel as the length on the CVS.adm files. + System-V stupid support. As well as the length on the CVS.adm files. 67. cvs import should populate the vendor sources with CVS.adm files so that one could use the vendor sources directly without having the check @@ -108,10 +76,6 @@ $CVSid: @(#)TODO 1.26 94/09/21 $ 73. Consider an option (in .cvsrc?) to automatically add files that are new and specified to commit. -74. Consider adding a way to remove directories/files that you are done - with... somehow. - [[ cvs release sort of does this ]] - 76. Consider adding a layer of abstraction so that CVS can work with both RCS and SCCS files. Larry says this should be #ifdef'ed. @@ -140,10 +104,6 @@ $CVSid: @(#)TODO 1.26 94/09/21 $ 93. Need to think hard about release and development environments. Think about execsets as well. -97. The documentation should describe how to undo a change ("cvs -update -j 1.2 -j 1.1 foo.c" followed by a commit undoes the change -from 1.1 to 1.2). - 98. If diff3 bombs out (too many differences) cvs then thinks that the file has been updated and is OK to be commited even though the file has not yet been merged. diff --git a/gnu/usr.bin/cvs/acconfig.h b/gnu/usr.bin/cvs/acconfig.h index 53ae29e7fea..1632a96892a 100644 --- a/gnu/usr.bin/cvs/acconfig.h +++ b/gnu/usr.bin/cvs/acconfig.h @@ -1,10 +1,6 @@ /* Define if you have MIT Kerberos version 4 available. */ #undef HAVE_KERBEROS -/* This is always defined; it tells some library files to include - CVS-specific features. */ -#undef CVS_SUPPORT - /* Define if you want CVS to be able to be a remote repository client. */ #undef CLIENT_SUPPORT diff --git a/gnu/usr.bin/cvs/config.h.in b/gnu/usr.bin/cvs/config.h.in index b8b42f0b38c..7753304fb8b 100644 --- a/gnu/usr.bin/cvs/config.h.in +++ b/gnu/usr.bin/cvs/config.h.in @@ -89,10 +89,6 @@ /* Define if you have MIT Kerberos version 4 available. */ #undef HAVE_KERBEROS -/* This is always defined; it tells some library files to include - CVS-specific features. */ -#undef CVS_SUPPORT - /* Define if you want CVS to be able to be a remote repository client. */ #undef CLIENT_SUPPORT @@ -100,12 +96,6 @@ clients. */ #undef SERVER_SUPPORT -/* the path to the gnu diff program on your system */ -#undef DIFF - -/* the path to the gnu grep program on your system */ -#undef GREP - /* The number of bytes in a int. */ #undef SIZEOF_INT @@ -145,6 +135,21 @@ /* Define if you have the setvbuf function. */ #undef HAVE_SETVBUF +/* Define if you have the sigaction function. */ +#undef HAVE_SIGACTION + +/* Define if you have the sigblock function. */ +#undef HAVE_SIGBLOCK + +/* Define if you have the sigprocmask function. */ +#undef HAVE_SIGPROCMASK + +/* Define if you have the sigsetmask function. */ +#undef HAVE_SIGSETMASK + +/* Define if you have the sigvec function. */ +#undef HAVE_SIGVEC + /* Define if you have the timezone function. */ #undef HAVE_TIMEZONE @@ -193,6 +198,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_PARAM_H +/* Define if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H diff --git a/gnu/usr.bin/cvs/configure b/gnu/usr.bin/cvs/configure index 4cf2521b515..b5761b186d0 100644 --- a/gnu/usr.bin/cvs/configure +++ b/gnu/usr.bin/cvs/configure @@ -1,7 +1,7 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.3 +# Generated automatically using autoconf version 2.4 # Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation @@ -12,7 +12,7 @@ ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help - --with-krb4" + --with-krb4=value set default $(KRB4) from value" # Initialize some variables set by options. # The variables have the same names as the options, with @@ -218,7 +218,7 @@ EOF verbose=yes ;; -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.3" + echo "configure generated by autoconf version 2.4" exit 0 ;; -with-* | --with-*) @@ -402,11 +402,6 @@ fi -cat >> confdefs.h <<\EOF -#define CVS_SUPPORT 1 -EOF - - # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 @@ -480,6 +475,7 @@ else test "${CFLAGS+set}" = set || CFLAGS="-g" fi + echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then @@ -495,7 +491,7 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error @@ -509,7 +505,7 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error @@ -528,13 +524,15 @@ fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" fi -CPP="$ac_cv_prog_CPP" echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking for AIX""... $ac_c" 1>&6 cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext < EOF @@ -624,12 +622,76 @@ if test "$ISC" = yes; then CFLAGS="$CFLAGS -D_SYSV3" fi +if test "x$prefix" = xNONE; then +echo $ac_n "checking for prefix by ""... $ac_c" 1>&6 +# Extract the first word of "cvs", so it can be a program name with args. +set dummy cvs; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_path_CVS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$CVS" in + /*) + ac_cv_path_CVS="$CVS" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_CVS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +CVS="$ac_cv_path_CVS" +if test -n "$CVS"; then + echo "$ac_t""$CVS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -n "$ac_cv_path_CVS"; then + prefix=`echo $ac_cv_path_CVS|sed 's%/[^/][^/]*//*[^/][^/]*$%%'` + fi +fi + + +# If we cannot run a trivial program, we must be cross compiling. +echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_cross=yes +else +cat > conftest.$ac_ext </dev/null; then + ac_cv_c_cross=no +else + ac_cv_c_cross=yes +fi +fi +rm -fr conftest* +fi +cross_compiling=$ac_cv_c_cross +echo "$ac_t""$ac_cv_c_cross" 1>&6 + + echo $ac_n "checking for working const""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 -if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - ac_cv_c_cross=yes -else -cat > conftest.$ac_ext </dev/null; then - ac_cv_c_cross=no -else - ac_cv_c_cross=yes -fi -fi -rm -fr conftest* -fi -cross_compiling=$ac_cv_c_cross -echo "$ac_t""$ac_cv_c_cross" 1>&6 - echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -729,7 +766,7 @@ else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext < conftest.$ac_ext <&2 fi -for ac_prog in gnudiff diff -do -# Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -if eval "test \"`echo '$''{'ac_cv_path_gdiff_path'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - case "$gdiff_path" in - /*) - ac_cv_path_gdiff_path="$gdiff_path" # Let the user override the test with a path. - ;; - *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_path_gdiff_path="$ac_dir/$ac_word" - break - fi - done - IFS="$ac_save_ifs" - ;; -esac -fi -gdiff_path="$ac_cv_path_gdiff_path" -if test -n "$gdiff_path"; then - echo "$ac_t""$gdiff_path" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -test -n "$gdiff_path" && break -done -test -n "$gdiff_path" || gdiff_path="diff" - -echo $ac_n "checking to see if $gdiff_path supports -a""... $ac_c" 1>&6 -if $gdiff_path -a /dev/null /dev/null > /dev/null 2>&1 ; then - echo "$ac_t""yes; appending -a to $gdiff_path" 1>&6 - gdiff_path="$gdiff_path -a" -fi -cat >> confdefs.h <&6 -if eval "test \"`echo '$''{'ac_cv_path_ggrep_path'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - case "$ggrep_path" in - /*) - ac_cv_path_ggrep_path="$ggrep_path" # Let the user override the test with a path. - ;; - *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_path_ggrep_path="$ac_dir/$ac_word" - break - fi - done - IFS="$ac_save_ifs" - ;; -esac -fi -ggrep_path="$ac_cv_path_ggrep_path" -if test -n "$ggrep_path"; then - echo "$ac_t""$ggrep_path" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -test -n "$ggrep_path" && break -done -test -n "$ggrep_path" || ggrep_path="grep" - -echo $ac_n "checking to see if $ggrep_path supports -s""... $ac_c" 1>&6 -echo foostring | $ggrep_path -s foostring > conftest.out 2>/dev/null -if test $? -ne 0 ; then - echo "configure: warning: $ggrep_path does not support -s" 1>&2 -else - echo "$ac_t""yes" 1>&6 - echo $ac_n "checking to see if $ggrep_path -s means to work silently""... $ac_c" 1>&6 - if test -s conftest.out ; then - echo "$ac_t""no" 1>&6 - if test "$ggrep_path" != /usr/bin/grep ; then - echo $ac_n "checking to see if /usr/bin/grep has the right -s""... $ac_c" 1>&6 - echo foostring | /usr/bin/grep -s foostring > conftest.out 2>/dev/null - if test $? -eq 0 -a ! -s foostring ; then - echo "$ac_t""yes; using /usr/bin/grep" 1>&6 - ggrep_path=/usr/bin/grep - else - echo "$ac_t""no" 1>&6 - fi - fi - else - echo "$ac_t""yes" 1>&6 - fi -fi -cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1203,7 +1129,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1221,7 +1147,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1242,7 +1168,7 @@ if test "$cross_compiling" = yes; then ac_cv_header_stdc=no else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -1273,7 +1199,7 @@ fi for ac_hdr in errno.h unistd.h string.h memory.h utime.h fcntl.h ndbm.h \ sys/param.h sys/select.h sys/time.h sys/timeb.h \ - io.h direct.h sys/bsdtypes.h + io.h direct.h sys/bsdtypes.h sys/resource.h do ac_safe=`echo "$ac_hdr" | tr './\055' '___'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 @@ -1281,7 +1207,7 @@ if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF @@ -1314,7 +1240,7 @@ if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1354,7 +1280,7 @@ if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1408,7 +1334,7 @@ if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1445,7 +1371,7 @@ if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_hdr> @@ -1484,7 +1410,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&6 else cat > conftest.$ac_ext < #include @@ -1588,7 +1514,7 @@ if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF @@ -1620,7 +1546,7 @@ if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1651,7 +1577,7 @@ if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1682,7 +1608,7 @@ if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1715,7 +1641,7 @@ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext < conftest.$ac_ext < #include @@ -1899,7 +1825,7 @@ if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return 0; } @@ -1930,7 +1856,7 @@ if eval "test \"`echo '$''{'ac_cv_func_alloca'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < @@ -2176,14 +2102,12 @@ if test $ccvs_cv_sys_working_fnmatch = no; then fi echo "$ac_t""$ccvs_cv_sys_working_fnmatch" 1>&6 +KRB4=/usr/kerberos # Check whether --with-krb4 or --without-krb4 was given. withval="$with_krb4" if test -n "$withval"; then KRB4=$withval -else - KRB4=/usr/kerberos - fi echo "default place for krb4 is $KRB4" @@ -2196,7 +2120,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() @@ -2230,7 +2154,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() @@ -2257,36 +2181,10 @@ EOF - krb_h= -# If we cannot run a trivial program, we must be cross compiling. -echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6 -if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - ac_cv_c_cross=yes -else +echo $ac_n "checking for krb.h""... $ac_c" 1>&6 cat > conftest.$ac_ext </dev/null; then - ac_cv_c_cross=no -else - ac_cv_c_cross=yes -fi -fi -rm -fr conftest* -fi -cross_compiling=$ac_cv_c_cross -echo "$ac_t""$ac_cv_c_cross" 1>&6 - -echo "checking for krb.h" 1>&6 -cat > conftest.$ac_ext < int main() { return 0; } @@ -2302,9 +2200,8 @@ else if test "$cross_compiling" != yes && test -r $KRB4/include/krb.h; then hold_cflags=$CFLAGS CFLAGS="$CFLAGS -I$KRB4/include" - echo "checking for krb.h in $KRB4/include" 1>&6 -cat > conftest.$ac_ext < conftest.$ac_ext < int main() { return 0; } @@ -2323,6 +2220,47 @@ rm -f conftest* fi rm -f conftest* +if test -z "$krb_h"; then + cat > conftest.$ac_ext < +int main() { return 0; } +int t() { +int i; +; return 0; } +EOF +if eval $ac_link; then + rm -rf conftest* + krb_h=yes krb_incdir= +else + rm -rf conftest* + if test "$cross_compiling" != yes && test -r $KRB4/include/kerberosIV/krb.h; then + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -I$KRB4/include/kerberosIV" + cat > conftest.$ac_ext < +int main() { return 0; } +int t() { +int i; +; return 0; } +EOF +if eval $ac_link; then + rm -rf conftest* + krb_h=yes krb_incdir=$KRB4/include/kerberosIV +fi +rm -f conftest* + + CFLAGS=$hold_cflags + fi +fi +rm -f conftest* + +fi +echo "$ac_t""$krb_h" 1>&6 + if test -n "$krb_h"; then krb_lib= echo $ac_n "checking for -lkrb""... $ac_c" 1>&6 @@ -2332,7 +2270,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lkrb $LIBS" cat > conftest.$ac_ext <&6 -if test "$ac_cv_lib_krb" = yes; then +if eval "test \"`echo '$ac_cv_lib_'krb`\" = yes"; then + echo "$ac_t""yes" 1>&6 krb_lib=yes krb_libdir= else - if test "$cross_compiling" != yes && test -r $KRB4/lib/libkrb.a; then + echo "$ac_t""no" 1>&6 +if test "$cross_compiling" != yes && test -r $KRB4/lib/libkrb.a; then krb_lib=yes krb_libdir=$KRB4/lib fi fi @@ -2374,7 +2313,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldes $LIBS" cat > conftest.$ac_ext <&6 -if test "$ac_cv_lib_des" = yes; then +if eval "test \"`echo '$ac_cv_lib_'des`\" = yes"; then + echo "$ac_t""yes" 1>&6 LIBS="${LIBS} -ldes" +else + echo "$ac_t""no" 1>&6 fi if test -n "$krb_incdir"; then @@ -2411,7 +2352,7 @@ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext <&6 -case $LIBS in +case "$LIBS" in *-lnsl*) ;; *) echo $ac_n "checking for -lnsl_s""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_nsl_s'+set}'`\" = set"; then @@ -2512,7 +2453,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lnsl_s $LIBS" cat > conftest.$ac_ext <&6 if eval "test \"`echo '$''{'ac_cv_lib_nsl'+set}'`\" = set"; then @@ -2554,7 +2495,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&6 if eval "test \"`echo '$''{'ac_cv_lib_socket'+set}'`\" = set"; then @@ -2596,7 +2537,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&6 if eval "test \"`echo '$''{'ac_cv_lib_inet'+set}'`\" = set"; then @@ -2638,7 +2579,7 @@ else ac_save_LIBS="$LIBS" LIBS="-linet $LIBS" cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then diff --git a/gnu/usr.bin/cvs/configure.in b/gnu/usr.bin/cvs/configure.in index 5c43c46bfd0..b44a6d9ecb1 100644 --- a/gnu/usr.bin/cvs/configure.in +++ b/gnu/usr.bin/cvs/configure.in @@ -1,11 +1,11 @@ dnl configure.in for cvs +dnl "$CVSid$" AC_INIT(src/cvs.h) -AC_PREREQ(2.1)dnl Required Autoconf version. +AC_PREREQ(2.4)dnl Required Autoconf version. AC_CONFIG_HEADER(config.h src/options.h) -AC_DEFINE(CVS_SUPPORT) - AC_PROG_CC + AC_AIX AC_MINIX AC_ISC_POSIX @@ -13,6 +13,10 @@ if test "$ISC" = yes; then CFLAGS="$CFLAGS -D_SYSV3" fi +AC_PREFIX_PROGRAM(cvs) + +AC_C_CROSS + AC_C_CONST AC_C_CHAR_UNSIGNED AC_C_INLINE @@ -32,52 +36,10 @@ if test X"$ac_cv_sys_interpreter" != X"yes" ; then AC_MSG_WARN($ac_msg) fi -AC_PATH_PROGS(gdiff_path, gnudiff diff, diff) -AC_MSG_CHECKING(to see if $gdiff_path supports -a) -if $gdiff_path -a /dev/null /dev/null > /dev/null 2>&1 ; then - AC_MSG_RESULT(yes; appending -a to $gdiff_path) - gdiff_path="$gdiff_path -a" -fi -AC_DEFINE_UNQUOTED(DIFF, "$gdiff_path") - -AC_PATH_PROGS(ggrep_path, ggrep gnugrep grep, grep) -AC_MSG_CHECKING(to see if $ggrep_path supports -s) -[echo foostring | $ggrep_path -s foostring > conftest.out 2>/dev/null] -dnl -dnl FIXME: We use a work-around for SunOS users with /usr/5bin first in their -dnl FIXME: path but we should really iterate through all the possible grep's -dnl FIXME: for one that works the way we want it to. -dnl FIXME: On the other hand, we should handle the failure to find a "working" -dnl FIXME: -s option by doing the old fashioned ">/dev/null"..... -dnl -if test $? -ne 0 ; then - AC_MSG_WARN($ggrep_path does not support -s, used when checking for merge conflicts) -else - AC_MSG_RESULT(yes) - AC_MSG_CHECKING(to see if $ggrep_path -s means to work silently) - if test -s conftest.out ; then - AC_MSG_RESULT(no) - if test "$ggrep_path" != /usr/bin/grep ; then - AC_MSG_CHECKING(to see if /usr/bin/grep has the right -s) - [echo foostring | /usr/bin/grep -s foostring > conftest.out 2>/dev/null] - if test $? -eq 0 -a ! -s foostring ; then - AC_MSG_RESULT(yes; using /usr/bin/grep) - ggrep_path=/usr/bin/grep - else - AC_MSG_RESULT(no) - fi - fi - else - AC_MSG_RESULT(yes) - fi -fi -AC_DEFINE_UNQUOTED(GREP, "$ggrep_path") -rm -f conftest* - AC_HEADER_STDC AC_CHECK_HEADERS(errno.h unistd.h string.h memory.h utime.h fcntl.h ndbm.h \ sys/param.h sys/select.h sys/time.h sys/timeb.h \ - io.h direct.h sys/bsdtypes.h) + io.h direct.h sys/bsdtypes.h sys/resource.h) AC_HEADER_SYS_WAIT AC_HEADER_STAT AC_HEADER_TIME @@ -88,7 +50,7 @@ AC_TYPE_MODE_T AC_TYPE_SIZE_T AC_TYPE_PID_T AC_REPLACE_FUNCS(getwd mkdir rename strdup strstr dup2 strerror valloc waitpid memmove) -AC_CHECK_FUNCS(fchmod fsync ftime mkfifo putenv setvbuf vfork vprintf ftruncate timezone getpagesize fchdir) +AC_CHECK_FUNCS(fchmod fsync ftime mkfifo putenv setvbuf vfork vprintf ftruncate timezone getpagesize fchdir sigaction sigprocmask sigvec sigsetmask sigblock) AC_CHECK_FUNC(re_exec, :, LIBOBJS="$LIBOBJS regex.o") AC_FUNC_UTIME_NULL AC_FUNC_ALLOCA @@ -116,10 +78,11 @@ AC_MSG_RESULT($ccvs_cv_sys_working_fnmatch) dnl dnl set $(KRB4) from --with-krb4=value -- WITH_KRB4 dnl -define(WITH_KRB4,[ -AC_WITH([krb4], -KRB4=$withval, KRB4=/usr/kerberos +define(WITH_KRB4,[ +AC_ARG_WITH([krb4], + [ --with-krb4=value set default $(KRB4) from value], + [KRB4=$withval], )dnl echo "default place for krb4 is $KRB4" AC_SUBST(KRB4)])dnl @@ -128,21 +91,33 @@ WITH_KRB4 AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(int) -AC_REQUIRE([AC_CROSS_CHECK]) krb_h= -AC_COMPILE_CHECK(krb.h,[#include ],[int i;], +AC_MSG_CHECKING([for krb.h]) +AC_TRY_LINK([#include ],[int i;], [krb_h=yes krb_incdir=], [if test "$cross_compiling" != yes && test -r $KRB4/include/krb.h; then hold_cflags=$CFLAGS CFLAGS="$CFLAGS -I$KRB4/include" - AC_COMPILE_CHECK(krb.h in $KRB4/include, - [#include ],[int i;], + AC_TRY_LINK([#include ],[int i;], [krb_h=yes krb_incdir=$KRB4/include]) CFLAGS=$hold_cflags fi]) +if test -z "$krb_h"; then + AC_TRY_LINK([#include ],[int i;], + [krb_h=yes krb_incdir=], + [if test "$cross_compiling" != yes && test -r $KRB4/include/kerberosIV/krb.h; then + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -I$KRB4/include/kerberosIV" + AC_TRY_LINK([#include ],[int i;], + [krb_h=yes krb_incdir=$KRB4/include/kerberosIV]) + CFLAGS=$hold_cflags + fi]) +fi +AC_MSG_RESULT($krb_h) + if test -n "$krb_h"; then krb_lib= - AC_HAVE_LIBRARY(-lkrb,[krb_lib=yes krb_libdir=], + AC_CHECK_LIB(krb,main,[krb_lib=yes krb_libdir=], [if test "$cross_compiling" != yes && test -r $KRB4/lib/libkrb.a; then krb_lib=yes krb_libdir=$KRB4/lib fi]) @@ -150,7 +125,7 @@ if test -n "$krb_h"; then AC_DEFINE(HAVE_KERBEROS) test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}" LIBS="${LIBS} -lkrb" - AC_HAVE_LIBRARY(-ldes,[LIBS="${LIBS} -ldes"]) + AC_CHECK_LIB(des,main,[LIBS="${LIBS} -ldes"]) if test -n "$krb_incdir"; then includeopt="${includeopt} -I$krb_incdir" AC_SUBST(includeopt) @@ -165,19 +140,19 @@ AC_CHECK_FUNCS(krb_get_err_text) # it. unset ac_cv_func_connect AC_CHECK_FUNC(connect, :, -[case $LIBS in +[case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl_s, main) ;; esac -case $LIBS in +case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl, main) ;; esac -case $LIBS in +case "$LIBS" in *-lsocket*) ;; *) AC_CHECK_LIB(socket, connect) ;; esac -case $LIBS in +case "$LIBS" in *-linet*) ;; *) AC_CHECK_LIB(inet, connect) ;; esac @@ -201,4 +176,5 @@ test -f src/options.h && ( AC_OUTPUT(Makefile lib/Makefile src/Makefile doc/Makefile \ man/Makefile contrib/Makefile contrib/pcl-cvs/Makefile \ - examples/Makefile windows-NT/Makefile stamp-h) + examples/Makefile windows-NT/Makefile os2/Makefile \ + macintosh/Makefile stamp-h) diff --git a/gnu/usr.bin/cvs/contrib/.cvsignore b/gnu/usr.bin/cvs/contrib/.cvsignore new file mode 100644 index 00000000000..f2c988ff62a --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/.cvsignore @@ -0,0 +1,13 @@ +Makefile +clmerge +cln_hist +commit_prep +cvs_acls +cvscheck +log +log_accum +mfpipe +rcs-to-cvs +rcs2log +rcslock +sccs2rcs diff --git a/gnu/usr.bin/cvs/contrib/ChangeLog b/gnu/usr.bin/cvs/contrib/ChangeLog index f44f07e4206..80f16f1fb63 100644 --- a/gnu/usr.bin/cvs/contrib/ChangeLog +++ b/gnu/usr.bin/cvs/contrib/ChangeLog @@ -1,3 +1,21 @@ +Thu Jan 18 09:39:16 1996 Jim Kingdon + + * README: Talk about submitting changes to contrib directory. + +Tue Nov 14 15:28:25 1995 Greg A. Woods + + * README: fix some spelling and other typos + + * Makefile.in: if I need reminding to run cvsinit.... + +Tue Nov 14 13:47:40 1995 Greg A. Woods + + * log_accum.pl: + - Fix 'cvs status' to use global -Qq options + - fix up a couple of comments, incl., my proper address + + * log.pl: add a CVSid and fix a couple of comments + Sun Oct 1 02:02:57 1995 Peter Wemm * Makefile.in: supply a suffix rule to deal with .sh "source" diff --git a/gnu/usr.bin/cvs/contrib/Makefile.in b/gnu/usr.bin/cvs/contrib/Makefile.in index 2f16973daf4..96f8b09b8a3 100644 --- a/gnu/usr.bin/cvs/contrib/Makefile.in +++ b/gnu/usr.bin/cvs/contrib/Makefile.in @@ -94,6 +94,7 @@ install: all $(libdir)/cvs/contrib for f in $(PROGS) ; do\ $(INSTALL_PROGRAM) $$f $(bindir)/$$f; \ done + @echo "You might consider running 'cvsinit' to upgrade your repository(s)...." .PHONY: install $(libdir)/cvs/contrib: diff --git a/gnu/usr.bin/cvs/contrib/README b/gnu/usr.bin/cvs/contrib/README index 7ec14547022..98befbb2858 100644 --- a/gnu/usr.bin/cvs/contrib/README +++ b/gnu/usr.bin/cvs/contrib/README @@ -1,14 +1,21 @@ $CVSid: @(#)README 1.12 94/09/25 $ This "contrib" directory is a place holder for code/scripts sent to -me by contributors around the world. This READM file will be kept +me by contributors around the world. This README file will be kept up-to-date from release to release. BUT, I must point out that these -contributions are really, REALLY UNSSUPPORTED. In fact, I probably +contributions are really, REALLY UNSUPPORTED. In fact, I probably don't even know what they do. Nor do I guarantee to have tried them, or ported them to work with this CVS distribution. If you have questions, you might contact the author, but you should not necessarily expect a reply. USE AT YOUR OWN RISK -- and all that stuff. +"Unsupported" also means that noone has volunteered to accept and +check in changes to this directory. So submissions for new scripts to +add here are unlikely to be accepted. Suggested changes to the +existing scripts here conceivably might, but that isn't clear either. +The exception is pcl-cvs; that is more actively maintained (see +pcl-cvs/README). + Contents of this directory: README This file. @@ -24,7 +31,7 @@ Contents of this directory: log_accum provide for a way to combine the individual log messages of a multi-directory "commit" into a single log message, and mail the result somewhere. - Also does other checks for $Id and that you are + Can also do other checks for $Id and that you are committing the correct revision of the file. Read the comments carefully. Contributed by David Hampton . diff --git a/gnu/usr.bin/cvs/contrib/log.pl b/gnu/usr.bin/cvs/contrib/log.pl index 51f759cc4c5..5e3bf488377 100644 --- a/gnu/usr.bin/cvs/contrib/log.pl +++ b/gnu/usr.bin/cvs/contrib/log.pl @@ -1,9 +1,11 @@ #! xPERL_PATHx # -*-Perl-*- # +#ident "$CVSid$" +# # XXX: FIXME: handle multiple '-f logfile' arguments # -# XXX -- I HATE Perl! This will be re-written in shell/awk/sed soon! +# XXX -- I HATE Perl! This *will* be re-written in shell/awk/sed soon! # # Usage: log.pl [[-m user] ...] [-s] -f logfile 'dirname file ...' @@ -133,7 +135,7 @@ close(IN); print OUT "\n"; -# after log information, do an 'cvs -Qqv status' on each file in the arguments. +# after log information, do an 'cvs -Qq status -v' on each file in the arguments. # if ($dostatus != 0) { while (@files) { diff --git a/gnu/usr.bin/cvs/contrib/log_accum.pl b/gnu/usr.bin/cvs/contrib/log_accum.pl index 1b38033d430..b47f433b562 100644 --- a/gnu/usr.bin/cvs/contrib/log_accum.pl +++ b/gnu/usr.bin/cvs/contrib/log_accum.pl @@ -11,7 +11,7 @@ # # Contributed by David Hampton # -# hacked greatly by Greg A. Woods +# hacked greatly by Greg A. Woods # Usage: log_accum.pl [-d] [-s] [-M module] [[-m mailto] ...] [-f logfile] # -d - turn on debugging @@ -26,6 +26,10 @@ $MAILER = "Mail"; # set this to something that takes "-s" +# +# End user configurable options. +# + # Constants (don't change these!) # $STATE_NONE = 0; @@ -458,9 +462,9 @@ for ($i = 0; ; $i++) { next; # ignore the silly "dir" entries } if ($debug) { - print STDERR "main(): doing status on $dofile\n"; + print STDERR "main(): doing 'cvs -nQq status -v $dofile'\n"; } - open(STATUS, "-|") || exec 'cvs', '-n', 'status', '-Qqv', $dofile; + open(STATUS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $dofile; while () { chop; push(@status_txt, $_); diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/.cvsignore b/gnu/usr.bin/cvs/contrib/pcl-cvs/.cvsignore new file mode 100644 index 00000000000..d8c4f2ace56 --- /dev/null +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/.cvsignore @@ -0,0 +1,19 @@ +Makefile +pcl-cvs.info* +pcl-cvs.aux +pcl-cvs.cp +pcl-cvs.cps +pcl-cvs.dvi +pcl-cvs.fn +pcl-cvs.fns +pcl-cvs.ky +pcl-cvs.kys +pcl-cvs.log +pcl-cvs.pg +pcl-cvs.pgs +pcl-cvs.toc +pcl-cvs.tp +pcl-cvs.tps +pcl-cvs.vr +pcl-cvs.vrs +pcl-cvs.ps diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog index 1d6483d54fe..be1c834c6d4 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog @@ -1,3 +1,93 @@ +Tue Jan 23 13:02:24 1996 Greg A. Woods + + * pcl-cvs.el (pcl-cvs-bugs-address): change the default address + as suggested by Per Cederqvist. + * pcl-cvs.el: removed comments refering to Signum, etc. + +Sun Jan 21 12:51:12 1996 Greg A. Woods + + * pcl-cvs.el (cvs-parse-stderr): fix typo (missing '\') that was + causing occasional un-reported, un-traced, failures that simply + said something like "RE missing '\(' or '\\('" -- hopefully this + is the last such bug! + +Tue Jan 16 13:57:16 1996 Jim Kingdon + + * Makefile.in: Rename "dist" target back to "dist-dir". The + latter is what actually gets used. + (pcl-cvs.dvi): Restore srcdir to pcl-cvs.texinfo. Fix typo + (pcl-cvs.texifo -> pcl-cvs.texinfo). + (TEXINDEX,TEX,SET_TEXINPUTS): New variables. + (.el.elc): Copy .el file to build dir so .elc file gets put there. + (dist-dir): Fix typo (cvs.info -> pcl-cvs.info). + * cookie.el: New file, copied from elib 1.0. + * README: Remove note about requiring elib; it claimed that CVS + contained a copy of elib, but it lied. + * pcl-cvs.el: Change (require 'cookie) to (load "cookie.el"). + * pcl-cvs-lucid.el: Change (require 'pcl-cvs) to (load "pcl-cvs.el"). + +Fri Jan 12 10:32:14 1996 Greg A. Woods + + * pcl-cvs.elc, pcl-cvs-lucid.elc: removed + + * pcl-cvs.el: run through the spell checker... + - noted some free variables in comments + (cvs-inhibit-copyright-message): move this above + cvs-startup-message to keep the compiler quiet + + * compile-all.el: removed (use make for dependency checking!) + + * Makefile.in: tweak various comments and echo messages... + (elcfiles): removed this target. + (.SUFFIXES, .el.elc): added support for elisp files. + (CORE): new macro -- list of files all .elc depend on [still empty] + (BATCHFLAGS): new macro -- flags to pass to emacs + (OBJDIR_DISTFILES): added ELCFILES to be shipped in distribution + + * README: fix the RCS Id. + + * INSTALL: re-copy formatted makeinfo output from pcl-cvs.info, + just to keep everything in proper synchronisation. + + * pcl-cvs.texinfo (Pcl-cvs installation): update to match Karl's + new wording from INSTALL. + +Wed Jan 10 22:04:35 1996 Karl Fogel + + * INSTALL: make first item read a little more smoothly. + + * README: note that pcl-cvs has been tested under 19.30. + +Wed Jan 10 17:59:00 1996 Greg A. Woods + + * ChangeLog.woods: these are changes integrated in from my + own pcl-cvs repository module, and based on the original PCL-CVS + Version 1.05 release. They include most, if not all, of the + changes from the Cygnus and Cyclic CVS contrib versions of + PCL-CVS (i.e. the changes noted below). + +Sat Dec 30 15:01:45 1995 Karl Fogel + + * pcl-cvs.el (cvs-changelog-ours-p): check that + `add-log-full-name' and `add-log-mailing-address' are non-nil, in + addition to checking that they are boundp. + +Thu Dec 21 16:45:48 1995 Karl Fogel + + * pcl-cvs.el (cvs-parse-stderr): ignore kerberos connection + failure, since CVS will automatically try rsh next. I think this + is okay because if a person needs to know that kerberos failed, + then chances are the rsh failed too, and *that* error message will + clue them in that something's afoot. + +Wed Nov 22 11:01:50 1995 Joshua Cowan + + * pcl-cvs.el (cvs-changelog-ours-p): use `user-full-name' if + `add-log-full-name' unbound, as not every uses the stuff in + add-log.el. Same with `add-log-mailing-address'. + (cvs-changelog-entries): change to `change-log-mode' unless + already in it. + Sun Jul 9 20:57:11 1995 Karl Fogel * "/bin/rmdir" as default, not "/usr/local/bin/rmdir". diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL index 76799679ac5..2edbaf54f79 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL @@ -3,20 +3,26 @@ This text is copied from the TeXinfo manual for pcl-cvs. Installation of the pcl-cvs program =================================== - 1. Edit the file `Makefile' to reflect the situation at your site. - The only things you have to change is the definition of `lispdir' - and `infodir'. The elisp files will be copied to `lispdir', and - the info file to `infodir'. + 1. Possibly edit the file `Makefile' to reflect the situation at your + site. We say "possibly" because the version of pcl-cvs included + with CVS uses a configuration mechanism integrated with the overall + mechanisms used by the CVS build and install procedures. Thus the + file `Makefile' will be generated automatically from the file + `Makefile.in', and it should not be necessary to edit it further. + + If you do have to edit the `Makefile', the only things you have to + change is the definition of `lispdir' and `infodir'. The elisp + files will be copied to `lispdir', and the info file(s) to + `infodir'. 2. Configure pcl-cvs.el - There are a couple of paths that you have to check to make sure - that they match you system. They appear early in the file - pcl-cvs.el. - - *NOTE:* If your system is running emacs 18.57 or earlier you - MUST uncomment the line that says: + There are a couple of pathnames that you have to check to make + sure that they match your system. They appear early in the file + `pcl-cvs.el'. + *NOTE:* If your system is running emacs 18.57 or earlier you MUST + uncomment the line that says: (setq delete-exited-processes nil) Setting `delete-exited-processes' to `nil' works around a bug in @@ -24,66 +30,65 @@ Installation of the pcl-cvs program 18.58. 3. Release 1.05 and later of pcl-cvs requires parts of the Elib - library, version 0.07 or later. Elib is available via anonymous - ftp from prep.ai.mit.edu in `pub/gnu/elib-0.07.tar.z', and from - a lot of other sites that mirrors prep. Get Elib, and install - it, before proceeding. + library, version 1.0 or later. Elib is available via anonymous + ftp from prep.ai.mit.edu in `pub/gnu/elib-1.0.tar.gz', and from a + lot of other sites that mirror prep. Get Elib, and install it, + before proceeding. + + *NOTE:* The version of pcl-cvs included with CVS includes a copy + of Elib in the sub-directory `elib' under the `contrib/pcl-cvs' + directory. 4. Type `make install' in the source directory. This will - byte-compile all `.el' files and copy both the `.el' and the - `.elc' into the directory you specified in step 1. + byte-compile all `.el' files and copy the `*.elc' files into the + directory you specified in step 1. - If you don't want to install the `.el' files but only the `.elc' - files (the byte-compiled files), you can type ``make - install_elc'' instead of ``make install''. + If you want to install the `*.el' files too, you can type `make + install-el' to do so. If you only want to create the compiled elisp files, but don't - want to install them, you can type `make elcfiles' instead. - This is what happens if you only type `make' without parameters. + want to install them, you can type `make' without parameters. 5. Edit the file `default.el' in your emacs lisp directory (usually - `/usr/gnu/emacs/lisp' or something similar) and enter the - contents of the file `pcl-cvs-startup.el' into it. It contains - a couple of `auto-load's that facilitates the use of pcl-cvs. - + `/usr/gnu/lib/emacs/site-lisp' or something similar) and enter the + contents of the file `pcl-cvs-startup.el' into it. It contains a + couple of `auto-load's that facilitates the use of pcl-cvs. Installation of the on-line manual. =================================== - 1. Move the info file `pcl-cvs.info' to your standard info - directory. This might be called something like - `/usr/gnu/emacs/info'. - - 2. Edit the file `dir' in the info directory and enter one line to - contain a pointer to the info file `pcl-cvs.info'. The line can, - for instance, look like this: - - * Pcl-cvs: (pcl-cvs.info). An Emacs front-end to CVS. - + 1. Create the info file(s) `pcl-cvs.info*' from `pcl-cvs.texinfo' by + typing `make info'. If you don't have the program `makeinfo' you + can get it by anonymous ftp from e.g. `prep.ai.mit.edu' as + `pub/gnu/texinfo-3.7.tar.gz' (there might be a newer version there + when you read this). -How to make the on-line manual from pcl-cvs.texinfo -=================================================== + 2. Install the info file(s) `pcl-cvs.info*' into your standard `info' + directory. You should be able to do this by typing `make + install-info'. - 1. Create the info file `pcl-cvs.info' from `pcl-cvs.texinfo' by - typing `make info'. If you don't have the program `makeinfo' you - can get it by anonymous ftp from e.g. `ftp.gnu.ai.mit.edu' as - `pub/gnu/texinfo-2.14.tar.Z' (there might be a newer version - there when you read this). + 3. Edit the file `dir' in the `info' directory and enter one line to + contain a pointer to the info file(s) `pcl-cvs.info*'. The line + can, for instance, look like this: + * Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS. How to make typeset documentation from pcl-cvs.texinfo ====================================================== - If you have TeX installed at your site, you can make a typeset -manual from `pcl-cvs.texinfo'. + If you have TeX installed at your site, you can make a typeset manual +from `pcl-cvs.texinfo'. 1. Run TeX by typing ``make pcl-cvs.dvi''. You will not get the indices unless you have the `texindex' program. 2. Convert the resulting device independent file `pcl-cvs.dvi' to a form which your printer can output and print it. If you have a - postscript printer there is a program, `dvi2ps', which does. - There is also a program which comes together with TeX, `dvips', - which you can use. + postscript printer there is a program, `dvi2ps', which does. There + is also a program which comes together with TeX, `dvips', which + you can use. + +-- +#ident "@(#)cvs/contrib/pcl-cvs:$Name: $Id$" diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile.in b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile.in index a96f626e593..fa762a9ba41 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile.in +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile.in @@ -1,5 +1,9 @@ -# @(#) Id: dist-makefile,v 1.19 1993/05/31 22:43:45 ceder Exp -# Makefile for pcl-cvs release 1.05. +# +#ident "@(#)original: dist-makefile,v 1.19 1993/05/31 22:43:45 ceder Exp " +# +#ident "@(#)elisp/pcl-cvs:$Name: $:$Id: Makefile.in,v 1.1.1.2 1996/01/30 00:19:05 tholo Exp $" +# +# Makefile for pcl-cvs release 1.05-CVS-$Name: $. # Copyright (C) 1992, 1993 Per Cederqvist # # This program is free software; you can redistribute it and/or modify @@ -16,29 +20,57 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# This is the directory in which the ELFILES and ELCFILES will be -# installed. +SHELL = /bin/sh + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ -lispdir = /usr/local/lib/emacs/site-lisp/pcl-cvs +prefix = @prefix@ +exec_prefix = @exec_prefix@ -# Where to install the info file. +# Where to put the system-wide supplementary files +libdir = $(prefix)/lib -prefix=/usr/local +# Where to put the Info files infodir = $(prefix)/info -# Used to byte-compile files. +# Where to put the manual pages. +mandir = $(prefix)/man -EMACS=emacs +# Used to batch-byte-compile files. +EMACS = emacs +# compile with noninteractive and relatively clean environment +BATCHFLAGS = -batch -n -q -# -# The rest of this file should not need to be modified. -# +# This is the directory in which the ELCFILES will be installed. +lispdir = $(libdir)/emacs/site-lisp + +#### End of system configuration section. #### srcdir = @srcdir@ +top_srcdir = @top_srcdir@ VPATH = @srcdir@ # Just in case... SHELL = /bin/sh +@SET_MAKE@ + +DISTFILES = \ + .cvsignore ChangeLog INSTALL Makefile.in NEWS README \ + ${ELFILES} \ + pcl-cvs.texinfo texinfo.tex + +OBJDIR_DISTFILES = $(ELCFILES) pcl-cvs.aux pcl-cvs.ps + +# files that contain key macro definitions. almost everything +# depends on them because the byte-compiler inlines macro +# expansions. everything also depends on the byte compiler +# options file since this might do odd things like turn off +# certain compiler optimizations. +CORE = ELFILES = pcl-cvs.el pcl-cvs-lucid.el pcl-cvs-startup.el ELCFILES = pcl-cvs.elc pcl-cvs-lucid.elc @@ -48,52 +80,123 @@ TEXTMPS = pcl-cvs.aux pcl-cvs.log pcl-cvs.toc pcl-cvs.dvi pcl-cvs.cp \ pcl-cvs.cps pcl-cvs.fns pcl-cvs.kys pcl-cvs.pgs pcl-cvs.tps \ pcl-cvs.vrs -INSTALL = install -INSTALL_DATA = $(INSTALL) +# Use cp if you don't have install. +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +MAKEINFO = makeinfo + +SET_TEXINPUTS = TEXINPUTS=.:$(srcdir):$$TEXINPUTS + +# Don Knuth's TeX formatter +TEX = tex + +# auxiliary program for sorting Texinfo indices +TEXINDEX = texindex + +DVIPS = dvips +DVIPSFLAGS = + +# CYGNUS LOCAL: install does not depend on info +all: $(ELCFILES) # info +.PHONY: all + +.SUFFIXES: .el .elc +# We copy the .el file to the build dir--is there a cleaner way to get +# emacs to compile the .el file from srcdir and put the .elc in the build dir? +# (that is also why we have separate rules for pcl-cvs.elc and +# pcl-cvs-lucid.elc rather than just using a .el.elc rule). +pcl-cvs.elc: pcl-cvs.el + @echo "You can probably ignore free variable and unknown function warnings..." + if test -f pcl-cvs.el; then \ + : OK, we are building in srcdir ; \ + else \ + ln $(srcdir)/pcl-cvs.el . ; \ + fi + $(EMACS) $(BATCHFLAGS) -f batch-byte-compile pcl-cvs.el +pcl-cvs-lucid.elc: pcl-cvs-lucid.el + @echo "You can probably ignore free variable and unknown function warnings..." + if test -f pcl-cvs-lucid.el; then \ + : OK, we are building in srcdir ; \ + else \ + ln $(srcdir)/pcl-cvs-lucid.el . ; \ + fi + $(EMACS) $(BATCHFLAGS) -f batch-byte-compile pcl-cvs-lucid.el + +check installcheck: + @echo "$@ not supported in this makefile..." +.PHONY: check installcheck + +# CYGNUS LOCAL: install does not depend on install-info +install: install-elc # install-info install-el + +install-el: $(ELFILES) + for i in $(ELFILES) ; do \ + $(INSTALL_DATA) $$i $(lispdir)/$$i ; \ + done + +install-elc: $(ELCFILES) + for i in $(ELCFILES) ; do \ + $(INSTALL_DATA) $$i $(lispdir)/$$i ; \ + done + +install-info: info + test -f pcl-cvs.info || cd $(srcdir); \ + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done -pcl-cvs.elc pcl-cvs-lucid.elc elcfiles: - $(EMACS) -batch -l ${srcdir}/compile-all.el -f compile-pcl-cvs +.PHONY: install install-el install-elc install-info -all: elcfiles info +# mkinstalldirs isn't supported for CVS yet.... +installdirs: $(top_srcdir)/mkinstalldirs + $(SHELL) $(top_srcdir)/mkinstalldirs $(lispdir) $(infodir) +.PHONY: installdirs -# Don't install the info file yet, since it requires makeinfo -# version 2.something (and version 1.something is distributed with emacs). -# -# install: install_elc install_info -install: install_elc - for i in $(ELFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done +uninstall: + @echo "$@ not yet supported in this makefile..." +.PHONY: uninstall -install_elc: elcfiles - for i in $(ELCFILES); do $(INSTALL_DATA) $$i $(lispdir)/$$i; done +info: pcl-cvs.info +.PHONY: info -install_info: pcl-cvs.info - $(INSTALL_DATA) pcl-cvs.info* $(infodir)/pcl-cvs.info +pcl-cvs.info: pcl-cvs.texinfo + $(MAKEINFO) ${srcdir}/pcl-cvs.texinfo -o pcl-cvs.info -info pcl-cvs.info: pcl-cvs.texinfo - makeinfo --fill-column=70 ${srcdir}/pcl-cvs.texinfo +dvi: pcl-cvs.dvi +.PHONY: dvi -pcl-cvs.aux pcl-cvs.dvi: pcl-cvs.texinfo - tex ${srcdir}/pcl-cvs.texinfo - tex ${srcdir}/pcl-cvs.texinfo - -texindex pcl-cvs.cp pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky \ +# this mess seems to be necessary to make the index right... +pcl-cvs.dvi pcl-cvs.aux: pcl-cvs.texinfo + $(SET_TEXINPUTS) $(TEX) $(srcdir)/pcl-cvs.texinfo + $(SET_TEXINPUTS) $(TEX) $(srcdir)/pcl-cvs.texinfo + -$(TEXINDEX) pcl-cvs.cp pcl-cvs.fn pcl-cvs.vr pcl-cvs.tp pcl-cvs.ky \ pcl-cvs.pg - tex ${srcdir}/pcl-cvs.texinfo + $(SET_TEXINPUTS) $(TEX) $(srcdir)/pcl-cvs.texinfo -DVIPS=dvips pcl-cvs.ps: pcl-cvs.dvi - ${DVIPS} pcl-cvs.dvi -o pcl-cvs.ps + $(DVIPS) $(DVIPSFLAGS) pcl-cvs.dvi -o pcl-cvs.ps mostlyclean clean realclean: rm -f *~ core $(ELCFILES) $(INFOFILES) $(TEXTMPS) +.PHONY: mostlyclean clean +distclean: clean + rm -f Makefile tags TAGS +.PHONY: distclean + +realclean maintainer-clean: distclean + rm -f pcl-cvs.info* pcl-cvs.ps +.PHONY: realclean maintainer-clean + +# you can't use ctags for lisp... tags TAGS: etags *.el +.PHONY: tags -DISTFILES = \ - .cvsignore ChangeLog INSTALL Makefile.in NEWS README \ - ${ELFILES} ${ELCFILES} compile-all.el \ - pcl-cvs.texinfo texinfo.tex -OBJDIR_DISTFILES = pcl-cvs.aux pcl-cvs.ps +ls: + @echo $(DISTFILES) +.PHONY: ls dist-dir: ${OBJDIR_DISTFILES} ${DISTFILES} pcl-cvs.info mkdir ${DISTDIR} @@ -101,9 +204,20 @@ dist-dir: ${OBJDIR_DISTFILES} ${DISTFILES} pcl-cvs.info ln $(srcdir)/$${i} ${DISTDIR}; \ done ln ${OBJDIR_DISTFILES} ${DISTDIR} - ln pcl-cvs.info* ${DISTDIR} + if [ -f pcl-cvs.info-1 ]; \ + then ln -f pcl-cvs.info-* ${DISTDIR}; \ + else : Pacify Ultrix sh; \ + fi .PHONY: dist-dir subdir = contrib/pcl-cvs Makefile: ../../config.status Makefile.in cd ../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +# CYGNUS LOCAL: don't depend on auto-re-config +#../config.status: ../configure +# cd .. ; $(SHELL) config.status --recheck + +# CYGNUS LOCAL: don't depend on auto-re-config +#../configure: ../configure.in +# cd $(top_srcdir) ; autoconf diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS index 4f563ffc501..d206908da19 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS @@ -1,4 +1,39 @@ -This is the NEWS file for pcl-cvs, an Elisp front-end to CVS. +This is the NEWS file for pcl-cvs, an Emacs elisp front-end to CVS. + +User-visible changes in the un-official CVS release of pcl-cvs +from the official 1.05 release to 1.05-CVS-$Name: $: + +* Support for using ChangeLog files, including hooks to automatically + guess CVS log entries from ChangeLog contents. + +* Support for client/server CVS (versions 1.5 through 1.7 and newer). + +* New commands for tagging files and directory trees (still needs to + be made to run in the background). + +* Better support for recognizing and handling unknown directories. + +* An attempt at new ediff and emerge interfaces (still needs work!), + including attempts to make vendor-branch merging work. + +* In a possibly misguided attempt to make it easier to see the effects + of changes that affect several files, diff output is now stored in a + uniqe buffer for each file. + +* Some commands now have default flags (cvs-*-flags). + +* Proper quoting of command line arguments displayed in *cvs-tmp*. + +* More hacking with getting CVSROOT right, though probably all + pointless, since CVS should do the right thing all the time. + +* Elib is back, at least in the CVS distribution. + +* Lots of minor bug fixes, tweaks, cleanup, re-indentation, etc. + +* Some minor tweaks, fixes, re-indentation, etc., in the + documentation. + User-visible changes in pcl-cvs from 1.04 to 1.05: @@ -111,3 +146,4 @@ User-visible changes in pcl-cvs from 1.02 to 1.03: variable is set (otherwise it uses /tmp). ---End of file NEWS--- +#ident "@(#)cvs/contrib/pcl-cvs:$Name: $:$Id: NEWS,v 1.1.1.2 1996/01/30 00:19:06 tholo Exp $" diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/README b/gnu/usr.bin/cvs/contrib/pcl-cvs/README index a9b81066137..20c11f0ffe6 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/README +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/README @@ -1,29 +1,25 @@ -@(#) Id: README,v 1.14 1993/05/31 22:43:36 ceder Exp +This is the readme file for pcl-cvs, release 1.05-CVS-$Name: $. -This is the readme file for pcl-cvs, release 1.05. +Pcl-cvs is a front-end to CVS versions 1.5 through 1.7. It integrates +the most frequently used CVS commands into an emacs interface. -This release of pcl-cvs requires Elib 0.07 or later. Elib is no -longer distributed with pcl-cvs, since that caused too much confusion. -You can get Elib from ftp.lysator.liu.se in pub/emacs/elib-*.tar.?. +There may be some configuration that needs to be done in pcl-cvs.el to +get it to work. See the instructions in the file INSTALL. -Pcl-cvs is a front-end to CVS version 1.3. It integrates the most -frequently used CVS commands into emacs. +Full documentation is in Texinfo format in the file pcl-cvs.texinfo. To +browse this document online, or in the emacs info mode, you will need to +process this file with the makeinfo program, which can also be found on +prep.ai.mit.edu in pub/gnu. -There is some configuration that needs to be done in pcl-cvs.el to get -it to work. See the instructions in file INSTALL. +If you have been using a previous version of pcl-cvs (for instance the +official 1.05 release, or any previous releases) you should read through +the file NEWS to see what has changed. -Full documentation is in pcl-cvs.texinfo. Since it requires makeinfo -version 2 or 3 a preformatted info file is also included (pcl-cvs.info). +This release has been tested under, Emacs 19.28 and Emacs 19.30. -If you have been using a previous version of pcl-cvs (for instance -1.02 which is distributed with CVS 1.3) you should read through the -file NEWS to see what has changed. +Per Cederqvist +(updated by Jim Blandy, Greg A. Woods, Karl Fogel) -This release has been tested under Emacs 18.59, Emacs 19.28 and Lucid -Emacs 19.6. Emacs 19.10 unfortunately has a file named cookie.el that -collides with the cookie.el that is distributed in Elib. This -conflict was resolved in 19.11. For earlier versions, there are -instructions in Elib 0.07 for how to work around the problem. - - Per Cederqvist - (updated by Jim Blandy) +-- +#OrigId "@(#) Id: README,v 1.14 1993/05/31 22:43:36 ceder Exp " +#ident "@(#)cvs/contrib/pcl-cvs:$Name: $:$Id: README,v 1.1.1.2 1996/01/30 00:19:08 tholo Exp $" diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el index d1f69e313d4..8695f67aa11 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el @@ -31,7 +31,8 @@ ;; Middle-click runs find-file. -(require 'pcl-cvs) +;(require 'pcl-cvs) +(load "pcl-cvs.el") (defvar cvs-menu '("CVS" diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.elc b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.elc new file mode 100644 index 00000000000..dabb156839a Binary files /dev/null and b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.elc differ diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el index f9b2de0418a..7e0ed35145a 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el @@ -1,4 +1,7 @@ -;;; @(#) Id: pcl-cvs-startup.el,v 1.4 1993/05/31 18:40:33 ceder Exp +;;;#ident "@(#)OrigId: pcl-cvs-startup.el,v 1.4 1993/05/31 18:40:33 ceder Exp " +;;; +;;;#ident "@(#)cvs/contrib/pcl-cvs:$Name: $:$Id: pcl-cvs-startup.el,v 1.1.1.2 1996/01/30 00:19:13 tholo Exp $" +;;; (autoload 'cvs-update "pcl-cvs" "Run a 'cvs update' in the current working directory. Feed the output to a *cvs* buffer and run cvs-mode on it. diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el index 6e02183aaa0..7705f08e861 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el @@ -1,7 +1,12 @@ -;;; @(#) Id: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp -;;; pcl-cvs.el -- A Front-end to CVS 1.3 or later. Release 1.05. -;;; Copyright (C) 1991, 1992, 1993 Per Cederqvist ;;; +;;;#ident "@(#)OrigId: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp " +;;; +;;;#ident "@(#)cvs/contrib/pcl-cvs:$Name: $:$Id: pcl-cvs.el,v 1.1.1.2 1996/01/30 00:19:09 tholo Exp $" +;;; +;;; pcl-cvs.el -- A Front-end to CVS 1.3 or later. +;;; Release 1.05-CVS-$Name: $. +;;; Copyright (C) 1991, 1992, 1993 Per Cederqvist + ;;; This program is free software; you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 2 of the License, or @@ -16,55 +21,87 @@ ;;; along with this program; if not, write to the Free Software ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -;;;; See below for installation instructions. -;;;; -;;;; There is an TeXinfo file that describes this package. The GNU -;;;; General Public License is included in that file. You should read -;;;; it to get the most from this package. +;;; See below for installation instructions. + +;;; There is an TeXinfo file that describes this package. You should read it +;;; to get the most from this package. -;;;; Send bug reports and improvements to ceder@lysator.liu.se or -;;;; ceder@signum.se. Talk some about Signum Support here. +++FIXME +;;; Mail questions and bug reports regarding this version (as included in +;;; CVS-1.7 or newer) to the pcl-cvs support team at . -;;; Don't try to use this with CVS 1.2 or earlier. It won't work. Get -;;; CVS 1.3. This package works together with RCS 5.6 and probably 5.5 -;;; as well. +;;; Don't try to use this with CVS 1.2 or earlier. It won't work. Get CVS 1.7 +;;; or newer. Use the version of RCS best suited for the version of CVS you're +;;; using. -;;; Mail questions and bug reports to ceder@lysator.liu.se. +; (require 'cookie) ; from ELIB-1.0 +(load "cookie.el") +(require 'add-log) ; for all the ChangeLog goodies -(require 'cookie) (provide 'pcl-cvs) ;;; ------------------------------------------------------- ;;; START OF THINGS TO CHECK WHEN INSTALLING -(defvar cvs-program "/usr/local/bin/cvs" +;; also use $GNU here, since may folks might install CVS as a GNU package +;; +(defvar local-path (cond + ((getenv "LOCAL") + (getenv "LOCAL")) + ((getenv "GNU") + (getenv "GNU")) + (t + "/usr/local")) + "*Path prefix for most locally installed things.") + +;; this isn't likely to be right all the time.... +;; +(defvar local-gnu-path (cond + ((getenv "GNU") + (getenv "GNU")) + (t + "/usr/local")) ; or "/usr/gnu"? + "*Path prefix for locally installed GNU software.") + +(defvar cvs-program (concat local-path "/bin/cvs") "*Full path to the cvs executable.") -(defvar cvs-diff-program "/usr/local/bin/diff" - "*Full path to the diff program.") +;; SunOS-4.1.1_U1 has "diff.c 1.12 88/08/04 SMI; from UCB 4.6 86/04/03" +;; +(defvar cvs-diff-program (concat local-gnu-path "/bin/diff") + "*Full path to the best diff program you've got. +NOTE: there are some nasty bugs in the context diff variants of some vendor +versions, such as the one in SunOS-4.1.1_U1") (defvar cvs-rmdir-program "/bin/rmdir" - "*Full path to the rmdir program. Typically /bin/rmdir.") - -;; Uncomment the following line if you are running on 18.57 or earlier. -;(setq delete-exited-processes nil) -;; Emacs version 18.57 and earlier is likely to crash if -;; delete-exited-processes is t, since the sentinel uses lots of -;; memory, and 18.57 forgets to GCPROT a variable if -;; delete-exited-processes is t. + "*Full path to the rmdir program. Typically /bin/rmdir.") (defvar cvs-shell "/bin/sh" "*Full path to a shell that can do redirection on stdout.") -;;; END OF THINGS TO CHECK WHEN INSTALLING -;;; -------------------------------------------------------- +;;; Options to control various features: -(defvar cvs-cvsroot nil - "*Specifies where the (current) cvs master repository is. -Overrides the $CVSROOT variable by sending \" -d dir\" to all cvs commands. -This switch is useful if you have multiple CVS repositories.") +(defvar cvs-changelog-full-paragraphs t + "If non-nil, include full ChangeLog paragraphs in the CVS log. +This may be set in the ``local variables'' section of a ChangeLog, to +indicate the policy for that ChangeLog. -(defvar cvs-cvsroot-required t +A ChangeLog paragraph is a bunch of log text containing no blank lines; +a paragraph usually describes a set of changes with a single purpose, +but perhaps spanning several functions in several files. Changes in +different paragraphs are unrelated. + +You could argue that the CVS log entry for a file should contain the +full ChangeLog paragraph mentioning the change to the file, even though +it may mention other files, because that gives you the full context you +need to understand the change. This is the behaviour you get when this +variable is set to t. + +On the other hand, you could argue that the CVS log entry for a change +should contain only the text for the changes which occurred in that +file, because the CVS log is per-file. This is the behaviour you get +when this variable is set to nil.") + +(defvar cvs-cvsroot-required nil "*Specifies whether CVS needs to be told where the repository is. In CVS 1.3, if your CVSROOT environment variable is not set, and you @@ -78,6 +115,46 @@ advisable to leave your CVSROOT environment variable unset, set this variable to nil, and let CVS figure out where the repository is for itself.") +(defvar cvs-cvsroot nil + "*Specifies where the (current) cvs master repository is. +Overrides the $CVSROOT variable by sending \" -d dir\" to all cvs commands. +This switch is useful if you have multiple CVS repositories, and are not using +a modern version of CVS that stores the current repository in CVS/Root.") + +;; Uncomment the following line if you are running on 18.57 or earlier. +;(setq delete-exited-processes nil) +;; Emacs version 18.57 and earlier is likely to crash if +;; delete-exited-processes is t, since the sentinel uses lots of +;; memory, and 18.57 forgets to GCPROT a variable if +;; delete-exited-processes is t. + +;;; END OF THINGS TO CHECK WHEN INSTALLING +;;; -------------------------------------------------------- + +(defconst pcl-cvs-version "1.05-CVS-$Name: $" + "A string denoting the current release version of pcl-cvs.") + +;; You are NOT allowed to disable this message by default. However, you +;; are encouraged to inform your users that by adding +;; (setq cvs-inhibit-copyright-message t) +;; to their .emacs they can get rid of it. Just don't add that line +;; to your default.el! +(defvar cvs-inhibit-copyright-message nil + "*Non-nil means don't display a Copyright message in the ``*cvs*'' buffer.") + +(defconst cvs-startup-message + (if cvs-inhibit-copyright-message + "PCL-CVS release 1.05-CVS-$Name: $" + "PCL-CVS release 1.05 from CVS release $Name: $. +Copyright (C) 1992, 1993 Per Cederqvist +Pcl-cvs comes with absolutely no warranty; for details consult the manual. +This is free software, and you are welcome to redistribute it under certain +conditions; again, consult the TeXinfo manual for details.") + "*Startup message for CVS.") + +(defconst pcl-cvs-bugs-address "pcl-cvs-auto-bugs@cyclic.com" + "The destination address used for the default bug report form.") + (defvar cvs-stdout-file nil "Name of the file that holds the output that CVS sends to stdout. This variable is buffer local.") @@ -93,9 +170,14 @@ This variable is buffer local.") (defvar cvs-auto-remove-handled nil "*Non-nil if cvs-mode-remove-handled should be called automatically. -If this is set to any non-nil value entries that does not need to be -checked in will be removed from the *cvs* buffer after every cvs-mode-commit -command.") +If this is set to any non-nil value, entries that do not need to be checked in +will be removed from the *cvs* buffer after every cvs-mode-commit command.") + +(defvar cvs-auto-remove-handled-directories nil + "*Non-nil if cvs-mode-remove-handled and cvs-update should automatically +remove empty directories. +If this is set to any non-nil value, directories that do not contain any files +to be checked in will be removed from the *cvs* buffer.") (defvar cvs-sort-ignore-file t "*Non-nil if cvs-mode-ignore should sort the .cvsignore automatically.") @@ -136,53 +218,57 @@ or the file under the cursor if no files are marked. If this variable is set to a non-nil value they will always run diff on the file on the current line.") -(defvar cvs-status-flags nil - "*List of strings to pass to ``cvs status''.") +;;; (setq cvs-status-flags '("-v")) +(defvar cvs-status-flags '("-v") + "*List of flags to pass to ``cvs status''. Default is \"-v\".") +;;; (setq cvs-log-flags nil) (defvar cvs-log-flags nil - "*List of strings to pass to ``cvs log''.") + "*List of flags to pass to ``cvs log''. Default is none.") + +;;; (setq cvs-tag-flags nil) +(defvar cvs-tag-flags nil + "*List of extra flags to pass to ``cvs tag''. Default is none.") + +;;; (setq cvs-rtag-flags nil) +(defvar cvs-rtag-flags nil + "*List of extra flags to pass to ``cvs rtag''. Default is none.") + +;;; (setq cvs-diff-flags '("-u")) +(defvar cvs-diff-flags '("-u") + "*List of flags to use as flags to pass to ``diff'' and ``cvs diff''. +Used by cvs-mode-diff-cvs and cvs-mode-diff-backup. Default is \"-u\". + +Set this to \"-u\" to get a Unidiff format, or \"-c\" to get context diffs.") + +;;; (setq cvs-update-optional-flags nil) +(defvar cvs-update-optional-flags nil + "*List of strings to use as optional flags to pass to ``cvs update''. Used +by cvs-do-update, called by cvs-update, cvs-update-other-window, +cvs-mode-update-no-prompt, and cvs-examine. Default is none. -(defvar cvs-diff-flags nil - "*List of strings to use as flags to pass to ``diff'' and ``cvs diff''. -Used by cvs-mode-diff-cvs and cvs-mode-diff-backup. -Set this to '(\"-u\") to get a Unidiff format, or '(\"-c\") to get context diffs.") +For example set this to \"-j VENDOR_PREV_RELEASE -j VENDOR_TOP_RELEASE\" to +perform an update after a new vendor release has been imported. + +To restrict the update to the current working directory, set this to \"-l\".") (defvar cvs-update-prog-output-skip-regexp "$" "*A regexp that matches the end of the output from all cvs update programs. -That is, output from any programs that are run by CVS (by the flag -u -in the `modules' file - see cvs(5)) when `cvs update' is performed should -terminate with a line that this regexp matches. It is enough that -some part of the line is matched. +That is, output from any programs that are run by CVS (by the flag -u in the +`modules' file - see cvs(5)) when `cvs update' is performed should terminate +with a line that this regexp matches. It is enough that some part of the line +is matched. The default (a single $) fits programs without output.") -;; The variables below are used internally by pcl-cvs. You should -;; never change them. +;;; -------------------------------------------------------- +;;; The variables below are used internally by pcl-cvs. You should +;;; never change them. (defvar cvs-buffers-to-delete nil "List of temporary buffers that should be discarded as soon as possible. Due to a bug in emacs 18.57 the sentinel can't discard them reliably.") -;; You are NOT allowed to disable this message by default. However, you -;; are encouraged to inform your users that by adding -;; (setq cvs-inhibit-copyright-message t) -;; to their .emacs they can get rid of it. Just don't add that line -;; to your default.el! -(defvar cvs-inhibit-copyright-message nil - "*Non-nil means don't display a Copyright message in the ``*cvs*'' buffer.") - -(defconst pcl-cvs-version "1.05" - "A string denoting the current release version of pcl-cvs.") - -(defconst cvs-startup-message - (if cvs-inhibit-copyright-message - "PCL-CVS release 1.05" - "PCL-CVS release 1.05. Copyright (C) 1992, 1993 Per Cederqvist -Pcl-cvs comes with absolutely no warranty; for details consult the manual. -This is free software, and you are welcome to redistribute it under certain -conditions; again, consult the TeXinfo manual for details.") - "*Startup message for CVS.") - (defvar cvs-update-running nil "This is set to nil when no process is running, and to the process when a cvs update process is running.") @@ -190,53 +276,16 @@ the process when a cvs update process is running.") (defvar cvs-cookie-handle nil "Handle for the cookie structure that is displayed in the *cvs* buffer.") -(defvar cvs-mode-commit nil +(defvar cvs-commit-list nil "Used internally by pcl-cvs.") ;;; The cvs data structure: ;;; -;;; When the `cvs update' is ready we parse the output. Every file +;;; When the `cvs update' is ready we parse the output. Every file ;;; that is affected in some way is added as a cookie of fileinfo ;;; (as defined below). ;;; -;;; cvs-fileinfo -;;; -;;; marked t/nil -;;; type One of -;;; UPDATED - file copied from repository -;;; MODIFIED - modified by you, unchanged in -;;; repository -;;; ADDED - added by you, not yet committed -;;; REMOVED - removed by you, not yet committed -;;; CVS-REMOVED- removed, since file no longer exists -;;; in the repository. -;;; MERGED - successful merge -;;; CONFLICT - conflict when merging -;;; REM-CONFLICT-removed in repository, changed locally. -;;; MOD-CONFLICT-removed locally, changed in repository. -;;; REM-EXIST -removed locally, but still exists. -;;; DIRCHANGE - A change of directory. -;;; UNKNOWN - An unknown file. -;;; MOVE-AWAY - A file that is in the way. -;;; REPOS-MISSING- The directory is removed from the -;;; repository. Go fetch a backup. -;;; MESSAGE - This is a special fileinfo that is used -;;; to display a text that should be in -;;; full-log. -;;; dir Directory the file resides in. Should not end with -;;; slash. -;;; file-name The file name. -;;; base-revision The revision that the working file was based on. -;;; Only valid for MERGED and CONFLICT files. -;;; cvs-diff-buffer A buffer that contains a 'cvs diff file'. -;;; backup-diff-buffer A buffer that contains a 'diff file backup-file'. -;;; full-log The output from cvs, unparsed. -;;; mod-time Modification time of file used for *-diff-buffer. -;;; handled True if this file doesn't require further action. -;;; -;;; Constructor: - ;;; cvs-fileinfo ;;; Constructor: @@ -246,12 +295,14 @@ the process when a cvs update process is running.") file-name full-log) "Create a fileinfo from all parameters. -Arguments: TYPE DIR FILE-NAME FULL-LOG. -A fileinfo has the following fields: +Arguments: TYPE DIR FILE-NAME FULL-LOG. +A fileinfo is a vector with the following fields: - marked t/nil - type One of +[0] handled True if this file doesn't require further action. +[1] marked t/nil +[2] type One of UPDATED - file copied from repository + PATCHED - file update with patch from repository MODIFIED - modified by you, unchanged in repository ADDED - added by you, not yet committed @@ -259,31 +310,39 @@ A fileinfo has the following fields: CVS-REMOVED- removed, since file no longer exists in the repository. MERGED - successful merge - CONFLICT - conflict when merging + CONFLICT - conflict when merging (if pcl-cvs did it) REM-CONFLICT-removed in repository, but altered locally. MOD-CONFLICT-removed locally, changed in repository. REM-EXIST - removed locally, but still exists. DIRCHANGE - A change of directory. UNKNOWN - An unknown file. + UNKNOWN-DIR- An unknown directory. MOVE-AWAY - A file that is in the way. REPOS-MISSING- The directory has vanished from the repository. MESSAGE - This is a special fileinfo that is used to display a text that should be in full-log. - dir Directory the file resides in. Should not end with slash. - file-name The file name. - backup-file Name of the backup file if MERGED or CONFLICT. - cvs-diff-buffer A buffer that contains a 'cvs diff file'. - backup-diff-buffer A buffer that contains a 'diff file backup-file'. - full-log The output from cvs, unparsed. - mod-time Modification time of file used for *-diff-buffer. - handled True if this file doesn't require further action." +[3] dir Directory the file resides in. Should not end with slash. +[4] file-name The file name. +[5] backup-file The name of a backup file created during a merge. + Only valid for MERGED and CONFLICT files. +[6] base-revision The revision that the working file was based on. + Only valid for MERGED and CONFLICT files. +[7] head-revision The revision that the newly merged changes came from + Only valid for MERGED and CONFLICT files. +[8] backup-revision The revision of the cvs backup file (original working rev.) + Only valid for MERGED and CONFLICT files. +[9] cvs-diff-buffer A buffer that contains a 'cvs diff file'. +[10] vendor-diff-buffer A buffer that contains a 'diff base-file head-file'. +[11] backup-diff-buffer A buffer that contains a 'diff file backup-file'. +[12] full-log The output from cvs, unparsed. +[13] mod-time Modification time of file used for *-diff-buffer." + (cons 'CVS-FILEINFO - (vector nil nil type dir file-name nil nil nil full-log nil))) - + (vector nil nil type dir file-name nil nil nil nil nil nil nil full-log nil nil))) ;;; Selectors: @@ -297,39 +356,55 @@ A fileinfo has the following fields: (defun cvs-fileinfo->type (cvs-fileinfo) "Get type from CVS-FILEINFO. -Type is one of UPDATED, MODIFIED, ADDED, REMOVED, CVS-REMOVED, MERGED, -CONFLICT, REM-CONFLICT, MOD-CONFLICT, REM-EXIST, DIRCHANGE, UNKNOWN, MOVE-AWAY, -REPOS-MISSING or MESSAGE." +Type is one of UPDATED, PATCHED, MODIFIED, ADDED, REMOVED, CVS-REMOVED, MERGED, +CONFLICT, REM-CONFLICT, MOD-CONFLICT, REM-EXIST, DIRCHANGE, UNKNOWN, +UNKNOWN-DIR, MOVE-AWAY, REPOS-MISSING or MESSAGE." (elt (cdr cvs-fileinfo) 2)) (defun cvs-fileinfo->dir (cvs-fileinfo) "Get dir from CVS-FILEINFO. -The directory name does not end with a slash. " +The directory name does not end with a slash." (elt (cdr cvs-fileinfo) 3)) (defun cvs-fileinfo->file-name (cvs-fileinfo) "Get file-name from CVS-FILEINFO." (elt (cdr cvs-fileinfo) 4)) +(defun cvs-fileinfo->backup-file (cvs-fileinfo) + "Get backup-file from CVS-FILEINFO." + (elt (cdr cvs-fileinfo) 5)) + (defun cvs-fileinfo->base-revision (cvs-fileinfo) "Get the base revision from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 5)) + (elt (cdr cvs-fileinfo) 6)) + +(defun cvs-fileinfo->head-revision (cvs-fileinfo) + "Get the head revision from CVS-FILEINFO." + (elt (cdr cvs-fileinfo) 7)) + +(defun cvs-fileinfo->backup-revision (cvs-fileinfo) + "Get the backup revision from CVS-FILEINFO." + (elt (cdr cvs-fileinfo) 8)) (defun cvs-fileinfo->cvs-diff-buffer (cvs-fileinfo) "Get cvs-diff-buffer from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 6)) + (elt (cdr cvs-fileinfo) 9)) + +(defun cvs-fileinfo->vendor-diff-buffer (cvs-fileinfo) + "Get backup-diff-buffer from CVS-FILEINFO." + (elt (cdr cvs-fileinfo) 10)) (defun cvs-fileinfo->backup-diff-buffer (cvs-fileinfo) "Get backup-diff-buffer from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 7)) + (elt (cdr cvs-fileinfo) 11)) (defun cvs-fileinfo->full-log (cvs-fileinfo) "Get full-log from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 8)) + (elt (cdr cvs-fileinfo) 12)) (defun cvs-fileinfo->mod-time (cvs-fileinfo) "Get mod-time from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 9)) + (elt (cdr cvs-fileinfo) 13)) ;;; Modifiers: @@ -354,27 +429,41 @@ The directory should now end with a slash." "Set file-name in CVS-FILEINFO to NEWVAL." (aset (cdr cvs-fileinfo) 4 newval)) +(defun cvs-set-fileinfo->backup-file (cvs-fileinfo newval) + "Set backup-file in CVS-FILEINFO to NEWVAL." + (aset (cdr cvs-fileinfo) 5 newval)) + (defun cvs-set-fileinfo->base-revision (cvs-fileinfo newval) "Set base-revision in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 5 newval)) + (aset (cdr cvs-fileinfo) 6 newval)) + +(defun cvs-set-fileinfo->head-revision (cvs-fileinfo newval) + "Set head-revision in CVS-FILEINFO to NEWVAL." + (aset (cdr cvs-fileinfo) 7 newval)) + +(defun cvs-set-fileinfo->backup-revision (cvs-fileinfo newval) + "Set backup-revision in CVS-FILEINFO to NEWVAL." + (aset (cdr cvs-fileinfo) 8 newval)) (defun cvs-set-fileinfo->cvs-diff-buffer (cvs-fileinfo newval) "Set cvs-diff-buffer in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 6 newval)) + (aset (cdr cvs-fileinfo) 9 newval)) + +(defun cvs-set-fileinfo->vendor-diff-buffer (cvs-fileinfo newval) + "Set vendor-diff-buffer in CVS-FILEINFO to NEWVAL." + (aset (cdr cvs-fileinfo) 10 newval)) (defun cvs-set-fileinfo->backup-diff-buffer (cvs-fileinfo newval) "Set backup-diff-buffer in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 7 newval)) + (aset (cdr cvs-fileinfo) 11 newval)) (defun cvs-set-fileinfo->full-log (cvs-fileinfo newval) "Set full-log in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 8 newval)) + (aset (cdr cvs-fileinfo) 12 newval)) (defun cvs-set-fileinfo->mod-time (cvs-fileinfo newval) "Set full-log in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 9 newval)) - - + (aset (cdr cvs-fileinfo) 13 newval)) ;;; Predicate: @@ -384,6 +473,7 @@ The directory should now end with a slash." ;;;; End of types. +;;---------- (defun cvs-use-temp-buffer () "Display a temporary buffer in another window and select it. The selected window will not be changed. The temporary buffer will @@ -396,48 +486,59 @@ be erased and writable." (setq default-directory dir) (erase-buffer))) -; Too complicated to handle all the cases that are generated. -; Maybe later. -;(defun cvs-examine (directory &optional local) -; "Run a 'cvs -n update' in the current working directory. -;That is, check what needs to be done, but don't change the disc. -;Feed the output to a *cvs* buffer and run cvs-mode on it. -;If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run." -; (interactive (list (read-file-name "CVS Update (directory): " -; nil default-directory nil) -; current-prefix-arg)) -; (cvs-do-update directory local 'noupdate)) +;;---------- +(defun cvs-examine (directory &optional local) + "Run a 'cvs -n update' in the current working directory. +That is, check what needs to be done, but don't change the disc. +Feed the output to a *cvs* buffer and run cvs-mode on it. +If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run. +WARNING: this doesn't work very well yet...." + + ;; TODO: this should do everything cvs-update does... + ;; for example, for CONFLICT files, it should setup fileinfo appropriately + + (interactive (list (read-file-name "CVS Update (directory): " + nil default-directory nil) + current-prefix-arg)) + (cvs-do-update directory local 'noupdate)) +;;---------- (defun cvs-update (directory &optional local) - "Run a 'cvs update' in the current working directory. Feed the + "Run a 'cvs update' in the current working directory. Feed the output to a *cvs* buffer and run cvs-mode on it. If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run." + (interactive (list (read-file-name "CVS Update (directory): " nil default-directory nil) current-prefix-arg)) (cvs-do-update directory local nil) (switch-to-buffer cvs-buffer-name)) +;;---------- (defun cvs-update-other-window (directory &optional local) - "Run a 'cvs update' in the current working directory. Feed the + "Run a 'cvs update' in the current working directory. Feed the output to a *cvs* buffer, display it in the other window, and run cvs-mode on it. If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run." + (interactive (list (read-file-name "CVS Update other window (directory): " nil default-directory nil) current-prefix-arg)) (cvs-do-update directory local nil) (switch-to-buffer-other-window cvs-buffer-name)) +;;---------- (defun cvs-filter (predicate list &rest extra-args) "Apply PREDICATE to each element on LIST. -Args: PREDICATE LIST &rest EXTRA-ARGS. +Args: PREDICATE LIST &rest EXTRA-ARGS. + Return a new list consisting of those elements that PREDICATE returns non-nil for. If more than two arguments are given the remaining args are passed to PREDICATE." + ;; Avoid recursion - this should work for LONG lists also! (let* ((head (cons 'dummy-header nil)) (tail head)) @@ -447,30 +548,42 @@ passed to PREDICATE." (setq list (cdr list))) (cdr head))) +;;---------- (defun cvs-mode-update-no-prompt () "Run cvs update in current directory." + (interactive) (cvs-do-update default-directory nil nil)) +;;---------- (defun cvs-do-update (directory local dont-change-disc) "Do a 'cvs update' in DIRECTORY. -Args: DIRECTORY LOCAL DONT-CHANGE-DISC &optional NOTTHISWINDOW. +Args: DIRECTORY LOCAL DONT-CHANGE-DISC. + If LOCAL is non-nil 'cvs update -l' is executed. If DONT-CHANGE-DISC is non-nil 'cvs -n update' is executed. Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously. -*Note*: DONT-CHANGE-DISC does not yet work. The parser gets confused." +*Note*: DONT-CHANGE-DISC does not yet work. The parser gets confused." + (save-some-buffers) + ;; Ensure that it is safe to do an update. If not, ask user + ;; for confirmation. + (if (and (boundp 'cvs-cookie-handle) (collection-buffer cvs-cookie-handle)) + (if (collection-collect-tin + cvs-cookie-handle + '(lambda (cookie) (eq (cvs-fileinfo->type cookie) 'CONFLICT))) + (if (not + (yes-or-no-p + "Only update if conflicts have been resolved. Continue? ")) + (error "Update aborted by user request.")))) (if (not (file-exists-p cvs-program)) (error "%s: file not found (check setting of cvs-program)" cvs-program)) - (if (and cvs-cvsroot-required - (not (or (getenv "CVSROOT") cvs-cvsroot))) - (error "Both cvs-cvsroot and environment variable CVSROOT unset.")) (let* ((this-dir (file-name-as-directory (expand-file-name directory))) (update-buffer (generate-new-buffer - (concat (file-name-nondirectory - (substring this-dir 0 -1)) + (concat " " (file-name-nondirectory + (substring this-dir 0 -1)) "-update"))) (temp-name (make-temp-name (concat (file-name-as-directory @@ -484,6 +597,18 @@ Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously. (error "%s is not a directory." this-dir)) (if (not (file-directory-p (concat this-dir "CVS"))) (error "%s does not contain CVS controlled files." this-dir)) + (if (file-readable-p (concat this-dir "CVS/Root")) + (save-excursion ; read CVS/Root into cvs-cvsroot + (find-file (concat this-dir "CVS/Root")) + (goto-char (point-min)) + (setq cvs-cvsroot (buffer-substring (point) + (progn (end-of-line) (point)))) + (if (not cvs-cvsroot) + (error "Invalid contents of %sCVS/Root" this-dir)) + (kill-buffer (current-buffer))) + (if (and cvs-cvsroot-required + (not (or (getenv "CVSROOT") cvs-cvsroot))) + (error "Both cvs-cvsroot and environment variable CVSROOT are unset, and no CVS/Root."))) ;; Check that at most one `cvs update' is run at any time. @@ -492,11 +617,18 @@ Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously. (eq (process-status cvs-update-running) 'stop))) (error "Can't run two `cvs update' simultaneously.")) + (if (not (listp cvs-update-optional-flags)) + (error "cvs-update-optional-flags should be set using cvs-set-update-optional-flags")) + ;; Generate "-d /master -n update -l". (setq args (concat (if cvs-cvsroot (concat " -d " cvs-cvsroot)) (if dont-change-disc " -n ") " update " - (if local " -l "))) + (if local " -l ") + (if cvs-update-optional-flags + (mapconcat 'identity + (copy-sequence cvs-update-optional-flags) + " ")))) ;; Set up the buffer that receives the stderr output from "cvs update". (set-buffer update-buffer) @@ -526,7 +658,7 @@ Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously. (setq cvs-cookie-handle (collection-create cvs-buffer-name 'cvs-pp - cvs-startup-message ;Se comment above cvs-startup-message. + cvs-startup-message ;See comment above cvs-startup-message. "---------- End -----")) (cookie-enter-first @@ -548,10 +680,10 @@ Both LOCAL and DONT-CHANGE-DISC may be non-nil simultaneously. (cvs-delete-unused-temporary-buffers cvs-buffers-to-delete))) ;; The following line is said to improve display updates on some - ;; emacses. It shouldn't be needed, but it does no harm. + ;; emacses. It shouldn't be needed, but it does no harm. (sit-for 0)) - +;;---------- (defun cvs-delete-unused-temporary-buffers (list) "Delete all buffers on LIST that is not visible. Return a list of all buffers that still is alive." @@ -565,49 +697,57 @@ Return a list of all buffers that still is alive." (kill-buffer (car list)) (cvs-delete-unused-temporary-buffers (cdr list))))) - +;;---------- (put 'cvs-mode 'mode-class 'special) +;;---------- (defun cvs-mode () - "\\Mode used for pcl-cvs, a frontend to CVS. + "\\Mode used for pcl-cvs, a front-end to CVS. -To get the *cvs* buffer you should use ``\\[cvs-update]''. +To get to the \"*cvs*\" buffer you should use ``\\[execute-extended-command] cvs-update''. -Full documentation is in the Texinfo file. These are the most useful commands: +Full documentation is in the Texinfo file. Here are the most useful commands: \\[cvs-mode-previous-line] Move up. \\[cvs-mode-next-line] Move down. -\\[cvs-mode-commit] Commit file. \\[cvs-mode-update-no-prompt] Reupdate directory. +\\[cvs-mode-commit] Commit file. \\[cvs-mode-update-no-prompt] Re-update directory. \\[cvs-mode-mark] Mark file/dir. \\[cvs-mode-unmark] Unmark file/dir. \\[cvs-mode-mark-all-files] Mark all files. \\[cvs-mode-unmark-all-files] Unmark all files. \\[cvs-mode-find-file] Edit file/run Dired. \\[cvs-mode-find-file-other-window] Find file or run Dired in other window. -\\[cvs-mode-remove-handled] Remove processed entries. \\[cvs-mode-add-change-log-entry-other-window] Write ChangeLog in other window. +\\[cvs-mode-ignore] Add file to ./.cvsignore. \\[cvs-mode-add-change-log-entry-other-window] Write ChangeLog in other window. \\[cvs-mode-add] Add to repository. \\[cvs-mode-remove-file] Remove file. -\\[cvs-mode-diff-cvs] Diff between base revision. \\[cvs-mode-diff-backup] Diff backup file. -\\[cvs-mode-emerge] Run emerge on base revision/backup file. -\\[cvs-mode-acknowledge] Delete line from buffer. \\[cvs-mode-ignore] Add file to the .cvsignore file. +\\[cvs-mode-diff-cvs] Diff with base revision. \\[cvs-mode-diff-backup] Diff backup file. +\\[cvs-mode-ediff] Ediff base rev & backup. \\[cvs-mode-diff-vendor] Show merge from vendor branch. +\\[cvs-mode-emerge] Emerge base rev & backup. \\[cvs-mode-diff-backup] Diff backup file. +\\[cvs-mode-acknowledge] Delete line from buffer. \\[cvs-mode-remove-handled] Remove processed entries. \\[cvs-mode-log] Run ``cvs log''. \\[cvs-mode-status] Run ``cvs status''. -\\[cvs-mode-changelog-commit] Like \\[cvs-mode-commit], but get default log text from ChangeLog. -\\[cvs-mode-undo-local-changes] Revert the last checked in version - discard your changes to the file. +\\[cvs-mode-tag] Run ``cvs tag''. \\[cvs-mode-rtag] Run ``cvs rtag''. +\\[cvs-mode-changelog-commit] Like \\[cvs-mode-commit], but get default log text from ChangeLog. +\\[cvs-mode-undo-local-changes] Revert the last checked in version - discard your changes to the file. Entry to this mode runs cvs-mode-hook. -This description is updated for release 1.05 of pcl-cvs. +This description is updated for release 1.05-CVS-$Name: $ of pcl-cvs. All bindings: \\{cvs-mode-map}" + (interactive) (setq major-mode 'cvs-mode) (setq mode-name "CVS") (setq mode-line-process nil) - (buffer-flush-undo (current-buffer)) +;; for older v18 emacs +;;(buffer-flush-undo (current-buffer)) + (buffer-disable-undo (current-buffer)) (make-local-variable 'goal-column) (setq goal-column cvs-cursor-column) (use-local-map cvs-mode-map) (run-hooks 'cvs-mode-hook)) +;;---------- (defun cvs-sentinel (proc msg) "Sentinel for the cvs update process. This is responsible for parsing the output from the cvs update when it is finished." + (cond ((null (buffer-name (process-buffer proc))) ;; buffer killed @@ -626,6 +766,10 @@ it is finished." (symbol-name (process-status proc)))) (let* ((out-file cvs-stdout-file) (stdout-buffer (find-file-noselect out-file))) + (save-excursion + (set-buffer stdout-buffer) + (rename-buffer (concat " " + (file-name-nondirectory out-file)) t)) (cvs-parse-update stdout-buffer (process-buffer proc)) (setq cvs-buffers-to-delete (cons (process-buffer proc) @@ -641,11 +785,13 @@ it is finished." (goto-char opoint)) (set-buffer obuf)))))) +;;---------- (defun cvs-update-filter (proc string) "Filter function for pcl-cvs. -This function gets the output that CVS sends to stderr. It inserts it +This function gets the output that CVS sends to stderr. It inserts it into (process-buffer proc) but it also checks if CVS is waiting for a -lock file. If so, it inserts a message cookie in the *cvs* buffer." +lock file. If so, it inserts a message cookie in the *cvs* buffer." + (let ((old-buffer (current-buffer)) (data (match-data))) (unwind-protect @@ -665,26 +811,27 @@ lock file. If so, it inserts a message cookie in the *cvs* buffer." ;complete line. (cond ((looking-at - "^cvs update: \\[..:..:..\\] waiting \ -for \\(.*\\)lock in \\(.*\\)$") - (setq cvs-lock-file (buffer-substring (match-beginning 2) - (match-end 2))) + "^cvs \\(update\\|server\\): \\[..:..:..\\] waiting for \\(.*\\)lock in \\(.*\\)$") + (setq cvs-lock-file (buffer-substring (match-beginning 3) + (match-end 3))) (cookie-enter-last cvs-cookie-handle (cvs-create-fileinfo 'MESSAGE nil nil (concat "\tWaiting for " - (buffer-substring (match-beginning 1) - (match-end 1)) + (buffer-substring (match-beginning 2) + (match-end 2)) "lock in " cvs-lock-file ".\n\t (type M-x cvs-delete-lock to delete it)"))))))) (store-match-data data) (set-buffer old-buffer)))) +;;---------- (defun cvs-delete-lock () "Delete the lock file that CVS is waiting for. Note that this can be dangerous. You should only do this if you are convinced that the process that created the lock is dead." + (interactive) (cond ((not (or (file-exists-p @@ -703,24 +850,76 @@ if you are convinced that the process that created the lock is dead." (cvs-remove-directory (concat (file-name-as-directory cvs-lock-file) "#cvs.lock")))))) +;;---------- (defun cvs-remove-directory (dir) "Remove a directory." + (if (file-directory-p dir) (call-process cvs-rmdir-program nil nil nil dir) (error "Not a directory: %s" dir)) (if (file-exists-p dir) (error "Could not remove directory %s" dir))) +;;---------- (defun cvs-lock-file-p (file) "Return true if FILE looks like a CVS lock file." + (or (string-match "^#cvs.tfl.[0-9]+$" file) (string-match "^#cvs.rfl.[0-9]+$" file) (string-match "^#cvs.wfl.[0-9]+$" file))) +;;---------- +(defun cvs-quote-multiword-string (str) + "Return STR surrounded in single quotes if it contains whitespace." + (cond ((string-match "[ \t\n]" str) + (concat "'" str "'")) + (t + str))) + +;;---------- +;; this should be in subr.el or some similar place.... +(defun parse-string (str &optional regexp) + "Explode the string STR into a list of words ala strtok(3). Optional REGEXP +defines regexp matching word separator, which defaults to \"[ \\t\\n]+\"." + (let (str-list ; new list + str-token ; "index" of next token + (str-start 0) ; "index" of current token + (str-sep (if regexp + regexp + "[ \t\n]+"))) + (while (setq str-token (string-match str-sep str str-start)) + (setq str-list + (nconc str-list + (list (substring str str-start str-token)))) + (setq str-start (match-end 0))) + ;; tag on the remainder as the final item + (if (not (>= str-start (length str))) + (setq str-list + (nconc str-list + (list (substring str str-start))))) + str-list)) + +;;---------- +(defun cvs-make-list (str) + "Return list of words made from the string STR." + (cond ((string-match "[ \t\n]+" str) + (let ((new-str (parse-string str "[ \t\n]+"))) + ;; this is ugly, but assume if the first element is empty, there are + ;; no more elements. + (cond ((string= (car new-str) "") + nil) + (t + new-str)))) + ((string= str "") + nil) + (t + (list str)))) + +;;---------- (defun cvs-skip-line (stdout stderr regexp &optional arg) "Like forward-line, but check that the skipped line matches REGEXP. -Args: STDOUT STDERR REGEXP &optional ARG. +Args: STDOUT STDERR REGEXP &optional ARG. If it doesn't match REGEXP a bug report is generated and displayed. STDOUT and STDERR is only used to do that. @@ -728,6 +927,7 @@ STDOUT and STDERR is only used to do that. If optional ARG, a number, is given the ARGth parenthesized expression in the REGEXP is returned as a string. Point should be in column 1 when this function is called." + (cond ((looking-at regexp) (forward-line 1) @@ -735,25 +935,33 @@ Point should be in column 1 when this function is called." (buffer-substring (match-beginning arg) (match-end arg)))) (t - (cvs-parse-error stdout stderr - (if (eq (current-buffer) stdout) 'STDOUT 'STDERR) - (point))))) - + (cvs-parse-error stdout + stderr + (if (eq (current-buffer) stdout) + 'STDOUT + 'STDERR) + (point) + regexp)))) + +;;---------- (defun cvs-get-current-dir (root-dir dirname) "Return current working directory, suitable for cvs-parse-update. -Args: ROOT-DIR DIRNAME. +Args: ROOT-DIR DIRNAME. + Concatenates ROOT-DIR and DIRNAME to form an absolute path." + (if (string= "." dirname) (substring root-dir 0 -1) (concat root-dir dirname))) +;;---------- (defun cvs-compare-fileinfos (a b) "Compare fileinfo A with fileinfo B and return t if A is `less'." + (cond ;; Sort acording to directories. ((string< (cvs-fileinfo->dir a) (cvs-fileinfo->dir b)) t) ((not (string= (cvs-fileinfo->dir a) (cvs-fileinfo->dir b))) nil) - ;; The DIRCHANGE entry is always first within the directory. ((and (eq (cvs-fileinfo->type a) 'DIRCHANGE) (not (eq (cvs-fileinfo->type b) 'DIRCHANGE))) t) @@ -762,17 +970,20 @@ Concatenates ROOT-DIR and DIRNAME to form an absolute path." ;; All files are sorted by file name. ((string< (cvs-fileinfo->file-name a) (cvs-fileinfo->file-name b))))) -(defun cvs-parse-error (stdout-buffer stderr-buffer err-buf pos) +;;---------- +(defun cvs-parse-error (stdout-buffer stderr-buffer err-buf pos &optional indicator) "Handle a parse error when parsing the output from cvs. -Args: STDOUT-BUFFER STDERR-BUFFER ERR-BUF POS. +Args: STDOUT-BUFFER STDERR-BUFFER ERR-BUF POS &optional INDICATOR. + ERR-BUF should be 'STDOUT or 'STDERR." + (setq pos (1- pos)) (set-buffer cvs-buffer-name) (setq buffer-read-only nil) (erase-buffer) - (insert "To: ceder@lysator.liu.se\n") - (insert "Subject: pcl-cvs " pcl-cvs-version " parse error.\n") - (insert "--text follows this line--\n\n") + (insert "To: " pcl-cvs-bugs-address "\n") + (insert "Subject: pcl-cvs release" pcl-cvs-version " parse error.\n") + (insert (concat mail-header-separator "\n")) (insert "This bug report is automatically generated by pcl-cvs\n") (insert "because it doesn't understand some output from CVS. Below\n") (insert "is detailed information about the error. Please send\n") @@ -784,7 +995,7 @@ ERR-BUF should be 'STDOUT or 'STDERR." (insert "are encouraged to read through it before sending it.\n") (insert "\n") (insert "Press C-c C-c to send this email.\n\n") - (insert "Please state the version of these programs you are using:\n") + (insert "Please state the version of these programs you are using:\n\n") (insert "RCS: \ndiff: \n\n") (let* ((stdout (save-excursion (set-buffer stdout-buffer) (buffer-string))) @@ -796,9 +1007,13 @@ ERR-BUF should be 'STDOUT or 'STDERR." (insert errline) (insert "<\n") (insert "Sent to " (symbol-name err-buf) " at pos " (format "%d\n" pos)) - (insert "Emacs-version: " (emacs-version) "\n") - (insert "Pcl-cvs $" "Id:" "$" ": " "Id: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp \n") - (insert "\n") + (if indicator + (insert "Optional args: \"" indicator "\".\n")) + (insert "\nEmacs-version: " (emacs-version) "\n") + (insert "Pcl-cvs Version: " + "@(#)OrigId: pcl-cvs.el,v 1.93 1993/05/31 22:44:00 ceder Exp\n") + (insert "CVS Version: " + "@(#)cvs/contrib/pcl-cvs:$Name: $:$Id: pcl-cvs.el,v 1.1.1.2 1996/01/30 00:19:09 tholo Exp $\n\n") (insert (format "--- Contents of stdout buffer (%d chars) ---\n" (length stdout))) (insert stdout) @@ -807,60 +1022,69 @@ ERR-BUF should be 'STDOUT or 'STDERR." (length stderr))) (insert stderr) (insert "--- End of stderr buffer ---\n") - (insert "End of bug report.\n") + (insert "\nEnd of bug report.\n") (require 'sendmail) (mail-mode) (error "CVS parse error - please report this bug."))) +;;---------- (defun cvs-parse-update (stdout-buffer stderr-buffer) "Parse the output from `cvs update'. -Args: STDOUT-BUFFER STDERR-BUFFER. +Args: STDOUT-BUFFER STDERR-BUFFER. This functions parses the from `cvs update' (which should be separated in its stdout- and stderr-components) and prints a pretty representation of it in the *cvs* buffer. Signals an error if unexpected output was detected in the buffer." + (let* ((head (cons 'dummy nil)) (tail (cvs-parse-stderr stdout-buffer stderr-buffer head default-directory)) (root-dir default-directory)) (cvs-parse-stdout stdout-buffer stderr-buffer tail root-dir) (setq head (sort (cdr head) (function cvs-compare-fileinfos))) - (collection-clear cvs-cookie-handle) (collection-append-cookies cvs-cookie-handle head) (cvs-remove-stdout-shadows) - (cvs-remove-empty-directories) + (if cvs-auto-remove-handled-directories + (cvs-remove-empty-directories)) (set-buffer cvs-buffer-name) (cvs-mode) (goto-char (point-min)) (tin-goto-previous cvs-cookie-handle (point-min) 1) (setq default-directory root-dir))) +;;---------- (defun cvs-remove-stdout-shadows () "Remove entries in the *cvs* buffer that comes from both stdout and stderr. If there is two entries for a single file the second one should be -deleted. (Remember that sort uses a stable sort algorithm, so one can +deleted. (Remember that sort uses a stable sort algorithm, so one can be sure that the stderr entry is always first)." + (collection-filter-tins cvs-cookie-handle - (function - (lambda (tin) - (not (cvs-shadow-entry-p tin)))))) + (function + (lambda (tin) + (not (cvs-shadow-entry-p tin)))))) +;;---------- (defun cvs-shadow-entry-p (tin) "Return non-nil if TIN is a shadow entry. -Args: TIN. +Args: TIN. + A TIN is a shadow entry if the previous tin contains the same file." + (let* ((previous-tin (tin-previous cvs-cookie-handle tin)) (curr (tin-cookie cvs-cookie-handle tin)) (prev (and previous-tin (tin-cookie cvs-cookie-handle previous-tin)))) (and prev curr - (string= (cvs-fileinfo->file-name prev) (cvs-fileinfo->file-name curr)) - (string= (cvs-fileinfo->dir prev) (cvs-fileinfo->dir curr)) + (string= (cvs-fileinfo->file-name prev) + (cvs-fileinfo->file-name curr)) + (string= (cvs-fileinfo->dir prev) + (cvs-fileinfo->dir curr)) (or (and (eq (cvs-fileinfo->type prev) 'CONFLICT) (eq (cvs-fileinfo->type curr) 'CONFLICT)) @@ -869,11 +1093,30 @@ A TIN is a shadow entry if the previous tin contains the same file." (and (eq (cvs-fileinfo->type prev) 'REM-EXIST) (eq (cvs-fileinfo->type curr) 'REMOVED)))))) +;;---------- +(defun cvs-find-backup-file (filename &optional dirname) + "Look for a backup file for FILENAME, optionally in directory DIRNAME, and if +there is one, return the name of the first file found as a string." + + (if (eq dirname nil) + (setq dirname default-directory)) + (car (directory-files dirname nil (concat "^\\" cvs-bakprefix filename + "\\.")))) + +;;---------- +(defun cvs-find-backup-revision (filename) + "Take FILENAME as the name of a cvs backup file and return the revision of +that file as a string." + (substring filename + (+ 1 (string-match "\\.\\([0-9.]+\\)$" filename)))) + +;;---------- (defun cvs-parse-stderr (stdout-buffer stderr-buffer head dir) "Parse the output from CVS that is written to stderr. -Args: STDOUT-BUFFER STDERR-BUFFER HEAD DIR -STDOUT-BUFFER holds the output that cvs sent to stdout. It is only +Args: STDOUT-BUFFER STDERR-BUFFER HEAD DIR + +STDOUT-BUFFER holds the output that cvs sent to stdout. It is only used to create a bug report in case there is a parse error. STDERR-BUFFER is the buffer that holds the output to parse. HEAD is a cons-cell, the head of the list that is built. @@ -890,183 +1133,221 @@ This function returns the last cons-cell in the list that is built." (while (< (point) (point-max)) (cond - ;; RCVS support (for now, we simply ignore any output from - ;; RCVS, including error messages!) - - ((looking-at "updating of .* finished$") - (forward-line 1)) - - ((looking-at "REMOTE FOLDER:.*") - (forward-line 1) - (while (and (< (point) (point-max)) (not (looking-at "phase 2.*"))) - (forward-line 1)) - (forward-line 2)) - - ((looking-at "turn on remote mode$") - (forward-line 1) - (while (and (< (point) (point-max)) (not (looking-at "phase 2.*"))) - (forward-line 1)) - (forward-line 2)) - - ((looking-at "phase 3.*") - (goto-char (point-max))) - - ;; End of RCVS stuff. - ;; CVS is descending a subdirectory. - ;; (The "server" case is there to support Cyclic CVS.) - ((looking-at "cvs \\(update\\|server\\): Updating \\(.*\\)$") + + ((looking-at + "^cvs \\(server\\|update\\): Updating \\(.*\\)$") (setq current-dir (cvs-get-current-dir root-dir (buffer-substring (match-beginning 2) (match-end 2)))) (setcdr head (list (cvs-create-fileinfo - 'DIRCHANGE current-dir - nil (buffer-substring (match-beginning 0) - (match-end 0))))) + 'DIRCHANGE + current-dir + "." ; the old version had nil here??? + (buffer-substring (match-beginning 0) + (match-end 0))))) (setq head (cdr head)) (forward-line 1)) ;; File removed, since it is removed (by third party) in repository. ((or (looking-at - "cvs update: warning: \\(.*\\) is not (any longer) pertinent") + "^cvs \\(update\\|server\\): warning: \\(.*\\) is not (any longer) pertinent") (looking-at - "cvs update: \\(.*\\) is no longer in the repository")) + "^cvs \\(update\\|server\\): \\(.*\\) is no longer in the repository")) (setcdr head (list (cvs-create-fileinfo - 'CVS-REMOVED current-dir + 'CVS-REMOVED + current-dir (file-name-nondirectory - (buffer-substring (match-beginning 1) - (match-end 1))) + (buffer-substring (match-beginning 2) + (match-end 2))) (buffer-substring (match-beginning 0) (match-end 0))))) (setq head (cdr head)) (forward-line 1)) - ;; File removed by you, but recreated by cvs. Ignored. + ;; File removed by you, but recreated by cvs. Ignored. Will say + ;; "Updated" on the next line. - ((looking-at "cvs update: warning: .* was lost$") + ((looking-at + "^cvs \\(update\\|server\\): warning: .* was lost$") + (forward-line 1)) + + ;; File unknown for some reason. + ;; FIXME: is it really a good idea to add this as unknown here? + + ((looking-at + "cvs \\(update\\|server\\): nothing known about \\(.*\\)$") + (let ((filename (buffer-substring (match-beginning 2) + (match-end 2)))) + (if (file-directory-p filename) + (setcdr head (list (cvs-create-fileinfo + 'UNKNOWN-DIR + current-dir + "." + (buffer-substring (match-beginning 0) + (match-end 0))))) + (setcdr head (list (cvs-create-fileinfo + 'UNKNOWN + current-dir + (file-name-nondirectory filename) + (buffer-substring (match-beginning 0) + (match-end 0))))))) + (setq head (cdr head)) (forward-line 1)) ;; A file that has been created by you, but added to the cvs ;; repository by another. - ((looking-at "^cvs update: move away \\(.*\\); it is in the way$") + ((looking-at + "^cvs \\(update\\|server\\): move away \\(.*\\); it is in the way$") (setcdr head (list (cvs-create-fileinfo - 'MOVE-AWAY current-dir + 'MOVE-AWAY + current-dir (file-name-nondirectory - (buffer-substring (match-beginning 1) - (match-end 1))) + (buffer-substring (match-beginning 2) + (match-end 2))) (buffer-substring (match-beginning 0) (match-end 0))))) (setq head (cdr head)) (forward-line 1)) - ;; Empty line. Probably inserted by mistake by user (or developer :-) - ;; Ignore. - - ((looking-at "^$") - (forward-line 1)) - - ;; Cvs waits for a lock. Ignore. + ;; Cvs waits for a lock. Ignore. ((looking-at - "^cvs update: \\[..:..:..\\] waiting for .*lock in ") + "^cvs \\(update\\|server\\): \\[..:..:..\\] waiting for .*lock in ") (forward-line 1)) ;; File removed in repository, but edited by you. ((looking-at - "cvs update: conflict: \\(.*\\) is modified but no longer \ -in the repository$") + "^cvs \\(update\\|server\\): conflict: \\(.*\\) is modified but no longer in the repository$") (setcdr head (list (cvs-create-fileinfo - 'REM-CONFLICT current-dir + 'REM-CONFLICT + current-dir (file-name-nondirectory - (buffer-substring (match-beginning 1) (match-end 1))) + (buffer-substring (match-beginning 2) + (match-end 2))) (buffer-substring (match-beginning 0) (match-end 0))))) (setq head (cdr head)) (forward-line 1)) + ;; File removed in repository, but edited by someone else. + ((looking-at - "cvs update: conflict: removed \\(.*\\) was modified by \ -second party") + "^cvs \\(update\\|server\\): conflict: removed \\(.*\\) was modified by second party") (setcdr head (list (cvs-create-fileinfo - 'MOD-CONFLICT current-dir - (buffer-substring (match-beginning 1) (match-end 1)) - (buffer-substring (match-beginning 0) (match-end 0))))) + 'MOD-CONFLICT + current-dir + (buffer-substring (match-beginning 1) + (match-end 1)) + (buffer-substring (match-beginning 0) + (match-end 0))))) (setq head (cdr head)) (forward-line 1)) + ;; File removed in repository, but not in local directory. + ((looking-at - "cvs update: \\(.*\\) should be removed and is still there") + "^cvs \\(update\\|server\\): \\(.*\\) should be removed and is still there") (setcdr head (list (cvs-create-fileinfo - 'REM-EXIST current-dir - (buffer-substring (match-beginning 1) (match-end 1)) - (buffer-substring (match-beginning 0) (match-end 0))))) + 'REM-EXIST + current-dir + (buffer-substring (match-beginning 2) + (match-end 2)) + (buffer-substring (match-beginning 0) + (match-end 0))))) (setq head (cdr head)) (forward-line 1)) - ((looking-at "cvs update: in directory ") + ;; Error searching for repository + + ((looking-at + "^cvs \\(update\\|server\\): in directory ") (let ((start (point))) (forward-line 1) - (cvs-skip-line - stdout-buffer stderr-buffer - (regexp-quote "cvs [update aborted]: there is no repository ")) - (setcdr head (list - (cvs-create-fileinfo - 'REPOS-MISSING current-dir - nil - (buffer-substring start (point))))) + (cvs-skip-line stdout-buffer stderr-buffer + (regexp-quote "cvs [update aborted]: there is no repository ")) + (setcdr head (list (cvs-create-fileinfo + 'REPOS-MISSING + current-dir + nil + (buffer-substring start (point))))) (setq head (cdr head)))) - ;; Ignore other messages from Cyclic CVS. - ((looking-at "cvs server:") - (forward-line 1)) + ;; Silly warning from attempted conflict resolution. Ignored. + ;; FIXME: Should it be? + ;; eg.: "cvs update: cannot find revision APC-web-update in file .cvsignore" + ;; + ((looking-at + "^cvs \\(update\\|server\\): cannot find revision \\(.*\\) in file \\(.*\\)$") + (forward-line 1) + (message "%s" (buffer-substring (match-beginning 0) (match-end 0)))) - (t + ;; CVS has decided to merge someone elses changes into this document. + ;; About to start an rcsmerge operation... + ;; + ((looking-at + "^RCS file: ") - ;; CVS has decided to merge someone elses changes into this - ;; document. This leads to a lot of garbage being printed. - ;; First there is two lines that contains no information - ;; that we skip (but we check that we recognize them). + ;; skip the "RCS file:" line... + (forward-line 1) (let ((complex-start (point)) - initial-revision filename) + base-revision ; the first revision retrieved to merge from + head-revision ; the second revision retrieved to merge from + filename ; the name of the file being merged + backup-file ; the name of the backup of the working file + backup-revision) ; the revision of the original working file - (cvs-skip-line stdout-buffer stderr-buffer "^RCS file: .*$") - (setq initial-revision + (setq base-revision (cvs-skip-line stdout-buffer stderr-buffer - "^retrieving revision \\(.*\\)$" 1)) - (cvs-skip-line stdout-buffer stderr-buffer - "^retrieving revision .*$") - - ;; Get the file name from the next line. + "^retrieving revision \\(.*\\)$" + 1)) + (setq head-revision + (cvs-skip-line stdout-buffer stderr-buffer + "^retrieving revision \\(.*\\)$" + 1)) + (setq filename + (cvs-skip-line stdout-buffer stderr-buffer + "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$" + 1)) + (setq backup-file + (cvs-find-backup-file filename current-dir)) + (setq backup-revision + (cvs-find-backup-revision backup-file)) - (setq - filename - (cvs-skip-line - stdout-buffer stderr-buffer - "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$" - 1)) + ;; Was there a conflict during the merge? (cond - ;; Was it a conflict? + + ;;;; From CVS-1.3 & RCS-5.6.0.1 with GNU-Diffutils-2.5: + ;;;; "cvs update -j OLD-REV -j NEW-REV ." + ;; + ;; RCS file: /big/web-CVS/apc/cmd/Main/logout.sh,v + ;; retrieving revision 1.1.1.1 + ;; retrieving revision 1.1.1.2 + ;; Merging differences between 1.1.1.1 and 1.1.1.2 into logout.sh + ;; rcsmerge warning: overlaps during merge + ((looking-at - ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning"). - "^\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$") + ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning"). + "^\\(rcs\\)?merge[:]*\\( warning\\)?: \\((overlaps\\|conflicts\\) during merge$") ;; Yes, this is a conflict. - (cvs-skip-line - stdout-buffer stderr-buffer - "^\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$") + (cvs-skip-line stdout-buffer stderr-buffer + "^\\(rcs\\)?merge[:]*\\( warning\\)?: \\(overlaps\\|conflicts\\) during merge$") + ;; this line doesn't seem to appear in all cases -- perhaps only + ;; in "-j A -j B" usage, in which case this indicates ???? (cvs-skip-line stdout-buffer stderr-buffer "^cvs \\(update\\|server\\): conflicts found in ") @@ -1076,95 +1357,158 @@ second party") filename (buffer-substring complex-start (point))))) - (cvs-set-fileinfo->base-revision fileinfo initial-revision) + ;; squirrel away info about the files that were retrieved for merging + (cvs-set-fileinfo->base-revision fileinfo base-revision) + (cvs-set-fileinfo->head-revision fileinfo head-revision) + (cvs-set-fileinfo->backup-revision fileinfo backup-revision) + (cvs-set-fileinfo->backup-file fileinfo backup-file) (setcdr head (list fileinfo)) (setq head (cdr head)))) - ;; Was it a conflict, and was RCS compiled without DIFF3_BIN? + ;; Was it a conflict, and was RCS compiled without DIFF3_BIN, in + ;; which case this is a failed conflict resolution? ((looking-at - ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning"). - "^\\(rcs\\)?merge\\( warning\\)?: overlaps or other probl\ -ems during merge$") - - ;; Yes, this is a conflict. - (cvs-skip-line - stdout-buffer stderr-buffer - "^\\(rcs\\)?merge\\( warning\\)?: overlaps .*during merge$") + ;; Allow both RCS 5.5 and 5.6. (5.6 prints "rcs" and " warning"). + "^\\(rcs\\)?merge\\( warning\\)?: overlaps or other problems during merge$") + (cvs-skip-line stdout-buffer stderr-buffer + "^\\(rcs\\)?merge\\( warning\\)?: overlaps or other problems during merge$") (cvs-skip-line stdout-buffer stderr-buffer "^cvs update: could not merge ") (cvs-skip-line stdout-buffer stderr-buffer "^cvs update: restoring .* from backup file ") - (let ((fileinfo (cvs-create-fileinfo 'CONFLICT current-dir filename (buffer-substring complex-start (point))))) - (setcdr head (list fileinfo)) (setq head (cdr head)))) + ;; Not a conflict; it must be a succesful merge. + (t - ;; Not a conflict; it must be a succesful merge. (let ((fileinfo (cvs-create-fileinfo 'MERGED current-dir filename (buffer-substring complex-start (point))))) - (cvs-set-fileinfo->base-revision fileinfo initial-revision) + (cvs-set-fileinfo->base-revision fileinfo base-revision) + (cvs-set-fileinfo->head-revision fileinfo head-revision) + (cvs-set-fileinfo->backup-revision fileinfo backup-revision) + (cvs-set-fileinfo->backup-file fileinfo backup-file) (setcdr head (list fileinfo)) - (setq head (cdr head))))))))))) - head) + (setq head (cdr head))))))) + + ;; Error messages from CVS (incomplete) + + ((looking-at + "^cvs \\(update\\|server\\): \\(invalid option .*\\)$") + (error "Interface problem with CVS: %s" + (buffer-substring (match-beginning 2) (match-end 2)))) + + ;; network errors + + ;; Kerberos connection attempted but failed. This is not + ;; really an error, as CVS will automatically fall back to + ;; rsh. Plus it tries kerberos, if available, even when rsh + ;; is what you really wanted. + + ((looking-at + "^cvs update: kerberos connect:.*$") + (forward-line 1) + (message "Remote CVS: %s" + (buffer-substring (match-beginning 0) (match-end 0)))) + + ;; And when kerberos *does* fail, cvs prints out some stuff + ;; as it tries rsh. Ignore that stuff too. + + ((looking-at + "^cvs update: trying to start server using rsh$") + (forward-line 1)) + + ((looking-at + "^\\([^:]*\\) Connection timed out") + (error "Remote CVS: %s" + (buffer-substring (match-beginning 0) (match-end 0)))) + + ((looking-at + "^Permission denied.") + (error "Remote CVS: %s" + (buffer-substring (match-beginning 0) (match-end 0)))) + ((looking-at + "^cvs \\[update aborted\\]: premature end of file from server") + (error "Remote CVS: %s" + (buffer-substring (match-beginning 0) (match-end 0)))) + + ;; Empty line. Probably inserted by mistake by user (or developer :-) + ;; Ignore. + + ((looking-at + "^$") + (forward-line 1)) + ;; top-level parser (cond) default clause + + (t + (cvs-skip-line stdout-buffer stderr-buffer + "^UN-MATCHABLE-OUTPUT")))))) + + ;; cause this function to return the head of the parser output list + head) + +;;---------- (defun cvs-parse-stdout (stdout-buffer stderr-buffer head root-dir) - "Parse the output from CVS that is written to stdout. -Args: STDOUT-BUFFER STDERR-BUFFER HEAD ROOT-DIR + "Parse the output from CVS that is written to stderr. +Args: STDOUT-BUFFER STDERR-BUFFER HEAD ROOT-DIR + STDOUT-BUFFER is the buffer that holds the output to parse. -STDERR-BUFFER holds the output that cvs sent to stderr. It is only +STDERR-BUFFER holds the output that cvs sent to stderr. It is only used to create a bug report in case there is a parse error. HEAD is a cons-cell, the head of the list that is built. ROOT-DIR is the directory the `cvs update' was run in. This function doesn't return anything particular." + (save-window-excursion (set-buffer stdout-buffer) (goto-char (point-min)) (while (< (point) (point-max)) (cond - ;; M: The file is modified by the user, and untouched in the repository. - ;; A: The file is "cvs add"ed, but not "cvs ci"ed. - ;; R: The file is "cvs remove"ed, but not "cvs ci"ed. - ;; C: Conflict - ;; U, P: The file is copied from the repository. - ;; ?: Unknown file. - + ;; M: The file is modified by the user, and untouched in the repository. + ;; A: The file is "cvs add"ed, but not "cvs ci"ed. + ;; R: The file is "cvs remove"ed, but not "cvs ci"ed. + ;; C: Conflict (only useful if a join was done and stderr has info...) + ;; U: The file is copied from the repository. + ;; ?: Unknown file or directory. - ((looking-at "\\([MARCUP?]\\) \\(.*\\)$") + ((looking-at + "^\\([MARCUP?]\\) \\(.*\\)$") (let* - ((c (char-after (match-beginning 1))) - (full-path - (concat (file-name-as-directory root-dir) - (buffer-substring (match-beginning 2) (match-end 2)))) + ((c (char-after (match-beginning 1))) + (full-path (concat (file-name-as-directory root-dir) + (buffer-substring (match-beginning 2) + (match-end 2)))) + (isdir (file-directory-p full-path)) (fileinfo (cvs-create-fileinfo (cond ((eq c ?M) 'MODIFIED) ((eq c ?A) 'ADDED) ((eq c ?R) 'REMOVED) ((eq c ?C) 'CONFLICT) ((eq c ?U) 'UPDATED) - ;; generated when Cyclic CVS sends a - ;; patch instead of the full file: - ((eq c ?P) 'UPDATED) - ((eq c ??) 'UNKNOWN)) + ((eq c ?P) 'PATCHED) + ((eq c ??) (if isdir + 'UNKNOWN-DIR + 'UNKNOWN))) (substring (file-name-directory full-path) 0 -1) (file-name-nondirectory full-path) (buffer-substring (match-beginning 0) (match-end 0))))) - ;; Updated files require no further action. + ;; Updated and Patched files require no further action. (if (memq c '(?U ?P)) (cvs-set-fileinfo->handled fileinfo t)) @@ -1174,15 +1518,19 @@ This function doesn't return anything particular." (forward-line 1))) ;; Executing a program because of the -u option in modules. - ((looking-at "cvs update: Executing") + ((looking-at + "^cvs \\(update\\|server\\): Executing") ;; Skip by any output the program may generate to stdout. ;; Note that pcl-cvs will get seriously confused if the ;; program prints anything to stderr. (re-search-forward cvs-update-prog-output-skip-regexp) (forward-line 1)) - (t (cvs-parse-error stdout-buffer stderr-buffer 'STDOUT (point))))))) + (t + (cvs-parse-error stdout-buffer stderr-buffer 'STDOUT (point) + "cvs-parse-stdout")))))) +;;---------- (defun cvs-pp (fileinfo) "Pretty print FILEINFO. Insert a printed representation in current buffer. For use by the cookie package." @@ -1197,6 +1545,8 @@ For use by the cookie package." (cond ((eq a 'UPDATED) (format "%s Updated %s" s f)) + ((eq a 'PATCHED) + (format "%s Patched %s" s f)) ((eq a 'MODIFIED) (format "%s Modified %s %s" s ci f)) ((eq a 'MERGED) @@ -1209,6 +1559,8 @@ For use by the cookie package." (format "%s Removed %s %s" s ci f)) ((eq a 'UNKNOWN) (format "%s Unknown %s" s f)) + ((eq a 'UNKNOWN-DIR) + (format "%s Unknown dir %s" s f)) ((eq a 'CVS-REMOVED) (format "%s Removed from repository: %s" s f)) ((eq a 'REM-CONFLICT) @@ -1218,41 +1570,61 @@ For use by the cookie package." ((eq a 'REM-EXIST) (format "%s Conflict: Removed by you, but still exists: %s" s f)) ((eq a 'DIRCHANGE) - (format "\nIn directory %s:" - (cvs-fileinfo->dir fileinfo))) + (format "\nIn directory %s:" (cvs-fileinfo->dir fileinfo))) ((eq a 'MOVE-AWAY) (format "%s Move away %s - it is in the way" s f)) ((eq a 'REPOS-MISSING) - (format " This repository is missing! Remove this dir manually.")) + (format " This repository directory is missing! Remove this directory manually.")) ((eq a 'MESSAGE) (cvs-fileinfo->full-log fileinfo)) (t - (format "%s Internal error! %s" s f)))))) + (format "%s Internal error! %s" s f)))))) -;;; You can define your own keymap in .emacs. pcl-cvs.el won't overwrite it. +;;; You can define your own keymap in .emacs. pcl-cvs.el won't overwrite it. (if cvs-mode-map nil (setq cvs-mode-map (make-keymap)) (suppress-keymap cvs-mode-map) + (define-prefix-command 'cvs-mode-map-control-c-prefix) + (define-key cvs-mode-map "\C-?" 'cvs-mode-unmark-up) + (define-key cvs-mode-map "\C-k" 'cvs-mode-acknowledge) + (define-key cvs-mode-map "\C-n" 'cvs-mode-next-line) + (define-key cvs-mode-map "\C-p" 'cvs-mode-previous-line) + ;; ^C- keys are used to set various flags to control CVS features + (define-key cvs-mode-map "\C-c" 'cvs-mode-map-control-c-prefix) + (define-key cvs-mode-map "\C-cc" 'cvs-change-cvsroot) + (define-key cvs-mode-map "\C-cd" 'cvs-set-diff-flags) + (define-key cvs-mode-map "\C-cl" 'cvs-set-log-flags) + (define-key cvs-mode-map "\C-cs" 'cvs-set-status-flags) + (define-key cvs-mode-map "\C-cu" 'cvs-set-update-optional-flags) + ;; M- keys are usually those that operate on modules + (define-key cvs-mode-map "\M-\C-?" 'cvs-mode-unmark-all-files) + (define-key cvs-mode-map "\M-C" 'cvs-mode-rcs2log) ; i.e. "Create a ChangeLog" + (define-key cvs-mode-map "\M-a" 'cvs-mode-admin) + (define-key cvs-mode-map "\M-c" 'cvs-mode-checkout) + (define-key cvs-mode-map "\M-o" 'cvs-mode-checkout-other-window) + (define-key cvs-mode-map "\M-p" 'cvs-mode-rdiff) ; i.e. "create a Patch" + (define-key cvs-mode-map "\M-r" 'cvs-mode-release) + (define-key cvs-mode-map "\M-t" 'cvs-mode-rtag) + ;; keys that operate on files (define-key cvs-mode-map " " 'cvs-mode-next-line) (define-key cvs-mode-map "?" 'describe-mode) (define-key cvs-mode-map "A" 'cvs-mode-add-change-log-entry-other-window) + (define-key cvs-mode-map "B" 'cvs-mode-byte-compile-files) + (define-key cvs-mode-map "C" 'cvs-mode-changelog-commit) + (define-key cvs-mode-map "E" 'cvs-mode-emerge) + (define-key cvs-mode-map "G" 'cvs-update) (define-key cvs-mode-map "M" 'cvs-mode-mark-all-files) + (define-key cvs-mode-map "Q" 'cvs-examine) (define-key cvs-mode-map "R" 'cvs-mode-revert-updated-buffers) (define-key cvs-mode-map "U" 'cvs-mode-undo-local-changes) - (define-key cvs-mode-map "\C-?" 'cvs-mode-unmark-up) - (define-key cvs-mode-map "\C-k" 'cvs-mode-acknowledge) - (define-key cvs-mode-map "\C-n" 'cvs-mode-next-line) - (define-key cvs-mode-map "\C-p" 'cvs-mode-previous-line) - (define-key cvs-mode-map "\M-\C-?" 'cvs-mode-unmark-all-files) (define-key cvs-mode-map "a" 'cvs-mode-add) (define-key cvs-mode-map "b" 'cvs-mode-diff-backup) (define-key cvs-mode-map "c" 'cvs-mode-commit) - (define-key cvs-mode-map "C" 'cvs-mode-changelog-commit) (define-key cvs-mode-map "d" 'cvs-mode-diff-cvs) - (define-key cvs-mode-map "e" 'cvs-mode-emerge) + (define-key cvs-mode-map "e" 'cvs-mode-ediff) (define-key cvs-mode-map "f" 'cvs-mode-find-file) (define-key cvs-mode-map "g" 'cvs-mode-update-no-prompt) (define-key cvs-mode-map "i" 'cvs-mode-ignore) @@ -1264,46 +1636,60 @@ For use by the cookie package." (define-key cvs-mode-map "q" 'bury-buffer) (define-key cvs-mode-map "r" 'cvs-mode-remove-file) (define-key cvs-mode-map "s" 'cvs-mode-status) - (define-key cvs-mode-map "x" 'cvs-mode-remove-handled) - (define-key cvs-mode-map "u" 'cvs-mode-unmark)) - + (define-key cvs-mode-map "t" 'cvs-mode-tag) + (define-key cvs-mode-map "u" 'cvs-mode-unmark) + (define-key cvs-mode-map "v" 'cvs-mode-diff-vendor) + (define-key cvs-mode-map "x" 'cvs-mode-remove-handled)) -(defun cvs-get-marked (&optional ignore-marks) +;;---------- +(defun cvs-get-marked (&optional ignore-marks ignore-contents) "Return a list of all selected tins. -If there are any marked tins, and IGNORE-MARKS is nil, return them. -Otherwise, if the cursor selects a directory, return all files in it. -Otherwise return (a list containing) the file the cursor points to, or -an empty list if it doesn't point to a file at all. +Args: &optional IGNORE-MARKS IGNORE-CONTENTS. + +If there are any marked tins, and IGNORE-MARKS is nil, return them. Otherwise, +if the cursor selects a directory, return all files in it, unless there are +none, in which case just return the directory; or unless IGNORE-CONTENTS is not +nil, in which case also just return the directory. Otherwise return (a list +containing) the file the cursor points to, or an empty list if it doesn't point +to a file at all." -Args: &optional IGNORE-MARKS." - (cond ;; Any marked cookies? ((and (not ignore-marks) (collection-collect-tin cvs-cookie-handle 'cvs-fileinfo->marked))) ;; Nope. + ((and (not ignore-contents) + (let ((sel (tin-locate cvs-cookie-handle (point)))) + (cond + ;; If a directory is selected, all it members are returned. + ((and sel (eq (cvs-fileinfo->type (tin-cookie cvs-cookie-handle + sel)) + 'DIRCHANGE)) + (let ((retsel + (collection-collect-tin cvs-cookie-handle + 'cvs-dir-member-p + (cvs-fileinfo->dir (tin-cookie + cvs-cookie-handle sel))))) + (if retsel + retsel + (list sel)))) + (t + (list sel)))))) (t - (let ((sel (tin-locate cvs-cookie-handle (point)))) - (cond - ;; If a directory is selected, all it members are returned. - ((and sel (eq (cvs-fileinfo->type - (tin-cookie cvs-cookie-handle sel)) - 'DIRCHANGE)) - (collection-collect-tin - cvs-cookie-handle 'cvs-dir-member-p - (cvs-fileinfo->dir (tin-cookie cvs-cookie-handle sel)))) - (t - (list sel))))))) - + (list (tin-locate cvs-cookie-handle (point)))))) +;;---------- (defun cvs-dir-member-p (fileinfo dir) "Return true if FILEINFO represents a file in directory DIR." + (and (not (eq (cvs-fileinfo->type fileinfo) 'DIRCHANGE)) (string= (cvs-fileinfo->dir fileinfo) dir))) +;;---------- (defun cvs-dir-empty-p (tin) "Return non-nil if TIN is a directory that is empty. -Args: CVS-BUF TIN." +Args: CVS-BUF TIN." + (and (eq (cvs-fileinfo->type (tin-cookie cvs-cookie-handle tin)) 'DIRCHANGE) (or (not (tin-next cvs-cookie-handle tin)) (eq (cvs-fileinfo->type @@ -1311,14 +1697,18 @@ Args: CVS-BUF TIN." (tin-next cvs-cookie-handle tin))) 'DIRCHANGE)))) +;;---------- (defun cvs-mode-revert-updated-buffers () - "Revert any buffers that are UPDATED, MERGED or CONFLICT." + "Revert any buffers that are UPDATED, PATCHED, MERGED or CONFLICT." + (interactive) (cookie-map (function cvs-revert-fileinfo) cvs-cookie-handle)) +;;---------- (defun cvs-revert-fileinfo (fileinfo) "Revert the buffer that holds the file in FILEINFO if it has changed, -and if the type is UPDATED, MERGED or CONFLICT." +and if the type is UPDATED, PATCHED, MERGED or CONFLICT." + (let* ((type (cvs-fileinfo->type fileinfo)) (file (cvs-fileinfo->full-path fileinfo)) (buffer (get-file-buffer file))) @@ -1327,6 +1717,7 @@ and if the type is UPDATED, MERGED or CONFLICT." ((and ;; ...the type must be one that justifies a revert... (or (eq type 'UPDATED) + (eq type 'PATCHED) (eq type 'MERGED) (eq type 'CONFLICT)) ;; ...and the user must be editing the file... @@ -1340,46 +1731,50 @@ and if the type is UPDATED, MERGED or CONFLICT." ;; Go ahead and revert the file. (t (revert-buffer 'dont-use-auto-save-file 'dont-ask)))))))) - +;;---------- (defun cvs-mode-remove-handled () "Remove all lines that are handled. Empty directories are removed." + (interactive) - ;; Pass one: remove files that are handled. + ;; Pass one: remove files that are handled. (collection-filter-cookies cvs-cookie-handle - (function - (lambda (fileinfo) (not (cvs-fileinfo->handled fileinfo))))) - ;; Pass two: remove empty directories. - (cvs-remove-empty-directories)) - - + (function + (lambda (fileinfo) + (not (cvs-fileinfo->handled fileinfo))))) + ;; Pass two: remove empty directories. + (if cvs-auto-remove-handled-directories + (cvs-remove-empty-directories))) + +;;---------- (defun cvs-remove-empty-directories () "Remove empty directories in the *cvs* buffer." + (collection-filter-tins cvs-cookie-handle - (function - (lambda (tin) - (not (cvs-dir-empty-p tin)))))) + (function + (lambda (tin) + (not (cvs-dir-empty-p tin)))))) +;;---------- (defun cvs-mode-mark (pos) - "Mark a fileinfo. Args: POS. -If the fileinfo is a directory, all the contents of that directory are -marked instead. A directory can never be marked. -POS is a buffer position." + "Mark a fileinfo. +Args: POS. - (interactive "d") +If the fileinfo is a directory, all the contents of that directory are marked +instead. A directory can never be marked. POS is a buffer position." + (interactive "d") (let* ((tin (tin-locate cvs-cookie-handle pos)) (sel (tin-cookie cvs-cookie-handle tin))) - (cond - ;; Does POS point to a directory? If so, mark all files in that directory. + ;; Does POS point to a directory? If so, mark all files in that directory. ((eq (cvs-fileinfo->type sel) 'DIRCHANGE) (cookie-map (function (lambda (f dir) (cond ((cvs-dir-member-p f dir) (cvs-set-fileinfo->marked f t) - t)))) ;Tell cookie to redisplay this cookie. + t)))) ; Tell cookie to redisplay this cookie. cvs-cookie-handle (cvs-fileinfo->dir sel))) (t @@ -1387,12 +1782,13 @@ POS is a buffer position." (tin-invalidate cvs-cookie-handle tin) (tin-goto-next cvs-cookie-handle pos 1))))) - +;;---------- (defun cvs-committable (tin) "Check if the TIN is committable. It is committable if it a) is not handled and b) is either MODIFIED, ADDED, REMOVED, MERGED or CONFLICT." + (let* ((fileinfo (tin-cookie cvs-cookie-handle tin)) (type (cvs-fileinfo->type fileinfo))) (and (not (cvs-fileinfo->handled fileinfo)) @@ -1402,8 +1798,8 @@ It is committable if it (eq type 'MERGED) (eq type 'CONFLICT))))) +;;---------- (defun cvs-mode-commit () - "Check in all marked files, or the current file. The user will be asked for a log message in a buffer. If cvs-erase-input-buffer is non-nil that buffer will be erased. @@ -1411,7 +1807,6 @@ Otherwise mark and point will be set around the entire contents of the buffer so that it is easy to kill the contents of the buffer with \\[kill-region]." (interactive) - (let* ((cvs-buf (current-buffer)) (marked (cvs-filter (function cvs-committable) (cvs-get-marked)))) @@ -1428,12 +1823,13 @@ buffer so that it is easy to kill the contents of the buffer with \\[kill-region (setq cvs-commit-list marked) (message "Press C-c C-c when you are done editing.")))) - +;;---------- (defun cvs-edit-done () "Commit the files to the repository." + (interactive) (if (null cvs-commit-list) - (error "You have already commited the files")) + (error "You have already committed the files")) (if (and (> (point-max) 1) (/= (char-after (1- (point-max))) ?\n) (or (eq cvs-commit-buffer-require-final-newline t) @@ -1456,9 +1852,11 @@ buffer so that it is easy to kill the contents of the buffer with \\[kill-region (if (cvs-execute-list cc-list cvs-program (if cvs-cvsroot (list "-d" cvs-cvsroot "commit" "-m" msg) - (list "commit" "-m" msg))) - (error "Something went wrong. Check the %s buffer carefully." + (list "commit" "-m" msg)) + "Committing %s...") + (error "Something went wrong. Check the %s buffer carefully." cvs-temp-buffer-name)) + ;; FIXME: don't do any of this if the commit fails. (let ((ccl cc-list)) (while ccl (cvs-after-commit-function (tin-cookie cvs-cookie-handle (car ccl))) @@ -1472,9 +1870,11 @@ buffer so that it is easy to kill the contents of the buffer with \\[kill-region (message "Committing... Done.")) +;;---------- (defun cvs-after-commit-function (fileinfo) - "Do everything that needs to be done when FILEINFO has been commited. + "Do everything that needs to be done when FILEINFO has been committed. The fileinfo->handle is set, and if the buffer is present it is reverted." + (cvs-set-fileinfo->handled fileinfo t) (if cvs-auto-revert-after-commit (let* ((file (cvs-fileinfo->full-path fileinfo)) @@ -1488,39 +1888,44 @@ The fileinfo->handle is set, and if the buffer is present it is reverted." ;; ...but it must be unmodified. (revert-buffer 'dont-use-auto-save-file 'dont-ask))))))) - -(defun cvs-execute-list (tin-list program constant-args) +;;---------- +(defun cvs-execute-list (tin-list program constant-args &optional message-fmt) "Run PROGRAM on all elements on TIN-LIST. -Args: TIN-LIST PROGRAM CONSTANT-ARGS -The PROGRAM will be called with pwd set to the directory the -files reside in. CONSTANT-ARGS should be a list of strings. The -arguments given to the program will be CONSTANT-ARGS followed by all -the files (from TIN-LIST) that resides in that directory. If the files -in TIN-LIST resides in different directories the PROGRAM will be run -once for each directory (if all files in the same directory appears -after each other). +Args: TIN-LIST PROGRAM CONSTANT-ARGS. + +The PROGRAM will be called with pwd set to the directory the files reside +in. CONSTANT-ARGS should be a list of strings. The arguments given to the +program will be CONSTANT-ARGS followed by all the files (from TIN-LIST) that +resides in that directory. If the files in TIN-LIST resides in different +directories the PROGRAM will be run once for each directory (if all files in +the same directory appears after each other). Any output from PROGRAM will be inserted in the current buffer. -This function return nil if all went well, or the numerical exit -status or a signal name as a string. Note that PROGRAM might be called -several times. This will return non-nil if something goes wrong, but -there is no way to know which process that failed." +This function return nil if all went well, or the numerical exit status or a +signal name as a string. Note that PROGRAM might be called several times. This +will return non-nil if something goes wrong, but there is no way to know which +process that failed. + +If MESSAGE-FMT is not nil, then message is called to display progress with +MESSAGE-FMT as the string. MESSAGE-FMT should contain one %s for the arg-list +being passed to PROGRAM." + + ;; FIXME: something seems wrong with the error checking here.... (let ((exitstatus nil)) (while tin-list - (let ((current-dir (cvs-fileinfo->dir - (tin-cookie cvs-cookie-handle - (car tin-list)))) - arg-list arg-str) + (let ((current-dir (cvs-fileinfo->dir (tin-cookie cvs-cookie-handle + (car tin-list)))) + arg-list + arg-str) ;; Collect all marked files in this directory. (while (and tin-list - (string= - current-dir - (cvs-fileinfo->dir - (tin-cookie cvs-cookie-handle (car tin-list))))) + (string= current-dir + (cvs-fileinfo->dir (tin-cookie cvs-cookie-handle + (car tin-list))))) (setq arg-list (cons (cvs-fileinfo->file-name (tin-cookie cvs-cookie-handle (car tin-list))) @@ -1531,11 +1936,16 @@ there is no way to know which process that failed." ;; Execute the command on all the files that were collected. + (if message-fmt + (message message-fmt + (mapconcat 'cvs-quote-multiword-string + arg-list + " "))) (setq default-directory (file-name-as-directory current-dir)) (insert (format "=== cd %s\n" default-directory)) (insert (format "=== %s %s\n\n" program - (mapconcat '(lambda (foo) foo) + (mapconcat 'cvs-quote-multiword-string (nconc (copy-sequence constant-args) arg-list) " "))) @@ -1546,14 +1956,20 @@ there is no way to know which process that failed." (or (null exitstatus) (and (integerp exitstatus) (= 1 exitstatus)))) (setq exitstatus res))) - (goto-char (point-max)))) - exitstatus)) - - -(defun cvs-execute-single-file-list (tin-list extractor program constant-args) + (goto-char (point-max)) + (if message-fmt + (message message-fmt + (mapconcat 'cvs-quote-multiword-string + (nconc (copy-sequence arg-list) '("Done.")) + " "))) + exitstatus)))) + +;;---------- +;;;; +++ not currently used! +(defun cvs-execute-single-file-list (tin-list extractor program constant-args + &optional cleanup message-fmt) "Run PROGRAM on all elements on TIN-LIST. - -Args: TIN-LIST EXTRACTOR PROGRAM CONSTANT-ARGS +Args: TIN-LIST EXTRACTOR PROGRAM CONSTANT-ARGS &optional CLEANUP. The PROGRAM will be called with pwd set to the directory the files reside in. CONSTANT-ARGS is a list of strings to pass as arguments to @@ -1562,13 +1978,19 @@ followed by the list that EXTRACTOR returns. EXTRACTOR will be called once for each file on TIN-LIST. It is given one argument, the cvs-fileinfo. It can return t, which means ignore -this file, or a list of arguments to send to the program." +this file, or a list of arguments to send to the program. + +If CLEANUP is not nil, the filenames returned by EXTRACTOR are deleted. + +If MESSAGE-FMT is not nil, then message is called to display progress with +MESSAGE-FMT as the string. MESSAGE-FMT should contain one %s for the arg-list +being passed to PROGRAM." (while tin-list - (let ((default-directory (file-name-as-directory - (cvs-fileinfo->dir - (tin-cookie cvs-cookie-handle - (car tin-list))))) + (let ((current-dir (file-name-as-directory + (cvs-fileinfo->dir + (tin-cookie cvs-cookie-handle + (car tin-list))))) (arg-list (funcall extractor (tin-cookie cvs-cookie-handle (car tin-list))))) @@ -1577,43 +1999,59 @@ this file, or a list of arguments to send to the program." (if (eq arg-list t) nil + (setq default-directory current-dir) (insert (format "=== cd %s\n" default-directory)) (insert (format "=== %s %s\n\n" program - (mapconcat '(lambda (foo) foo) + (mapconcat 'cvs-quote-multiword-string (nconc (copy-sequence constant-args) arg-list) " "))) + (if message-fmt + (message message-fmt (mapconcat 'cvs-quote-multiword-string + arg-list + " "))) (apply 'call-process program nil t t (nconc (copy-sequence constant-args) arg-list)) - (goto-char (point-max)))) + (goto-char (point-max)) + (if message-fmt + (message message-fmt (mapconcat 'cvs-quote-multiword-string + (nconc arg-list '("Done.")) + " "))) + (if cleanup + (while arg-list +;;;; (kill-buffer ?????) + (delete-file (car arg-list)) + (setq arg-list (cdr arg-list)))))) (setq tin-list (cdr tin-list)))) - +;;---------- (defun cvs-edit-mode () "\\Mode for editing cvs log messages. Commands: \\[cvs-edit-done] checks in the file when you are ready. This mode is based on fundamental mode." + (interactive) (use-local-map cvs-edit-mode-map) (setq major-mode 'cvs-edit-mode) (setq mode-name "CVS Log") (auto-fill-mode 1)) - +;;---------- (if cvs-edit-mode-map nil (setq cvs-edit-mode-map (make-sparse-keymap)) - (define-prefix-command 'cvs-control-c-prefix) - (define-key cvs-edit-mode-map "\C-c" 'cvs-control-c-prefix) + (define-prefix-command 'cvs-edit-mode-control-c-prefix) + (define-key cvs-edit-mode-map "\C-c" 'cvs-edit-mode-control-c-prefix) (define-key cvs-edit-mode-map "\C-c\C-c" 'cvs-edit-done)) - +;;---------- (defun cvs-diffable (tins) "Return a list of all tins on TINS that it makes sense to run ``cvs diff'' on." - ;; +++ There is an unnecessary (nreverse) here. Get the list the + + ;; +++ There is an unnecessary (nreverse) here. Get the list the ;; other way around instead! (let ((result nil)) (while tins @@ -1621,6 +2059,7 @@ This mode is based on fundamental mode." (tin-cookie cvs-cookie-handle (car tins))))) (if (or (eq type 'MODIFIED) (eq type 'UPDATED) + (eq type 'PATCHED) (eq type 'MERGED) (eq type 'CONFLICT) (eq type 'REMOVED) ;+++Does this line make sense? @@ -1629,45 +2068,77 @@ This mode is based on fundamental mode." (setq tins (cdr tins)))) (nreverse result))) - +;;---------- (defun cvs-mode-diff-cvs (&optional ignore-marks) - "Diff the selected files against the repository. -The flags in the variable cvs-diff-flags (which should be a list -of strings) will be passed to ``cvs diff''. If the variable -cvs-diff-ignore-marks is non-nil any marked files will not be -considered to be selected. An optional prefix argument will invert -the influence from cvs-diff-ignore-marks." + "Diff the selected files against the head revisions in the repository. - (interactive "P") +If the variable cvs-diff-ignore-marks is non-nil any marked files will not be +considered to be selected. An optional prefix argument will invert the +influence from cvs-diff-ignore-marks. - (if (not (listp cvs-diff-flags)) - (error "cvs-diff-flags should be a list of strings")) +The flags in the variable cvs-diff-flags will be passed to ``cvs diff''. +The resulting diffs are placed in the cvs-fileinfo->cvs-diff-buffer." + + (interactive "P") + (if (not (listp cvs-diff-flags)) + (error "cvs-diff-flags should be set using cvs-set-diff-flags.")) (save-some-buffers) - (let ((marked (cvs-diffable + (message "cvsdiffing...") + (let ((marked-file-list (cvs-diffable (cvs-get-marked (or (and ignore-marks (not cvs-diff-ignore-marks)) (and (not ignore-marks) cvs-diff-ignore-marks)))))) - (cvs-use-temp-buffer) - (message "cvsdiffing...") - ;; Don't care much about the exit status since it is the _sum_ of - ;; the status codes from the different files (not the _max_ as it - ;; should be). - (if (cvs-execute-list marked cvs-program - (if cvs-cvsroot - (cons "-d" (cons cvs-cvsroot - (cons "diff" cvs-diff-flags))) - (cons "diff" cvs-diff-flags))) - (message "cvsdiffing... Done.") - (message "cvsdiffing... No differences found.")))) - - -(defun cvs-backup-diffable (tin) - "Check if the TIN is backup-diffable. -It must have a backup file to be diffable." - (file-readable-p - (cvs-fileinfo->backup-file (tin-cookie cvs-cookie-handle tin)))) + (while marked-file-list + (let ((fileinfo-to-diff (tin-cookie cvs-cookie-handle + (car marked-file-list))) + (local-def-directory (file-name-as-directory + (cvs-fileinfo->dir + (tin-cookie cvs-cookie-handle + (car marked-file-list)))))) + (message "cvsdiffing %s..." + (cvs-fileinfo->file-name fileinfo-to-diff)) + + ;; FIXME: this seems messy to test and set buffer name at this point.... + (if (not (cvs-fileinfo->cvs-diff-buffer fileinfo-to-diff)) + (cvs-set-fileinfo->cvs-diff-buffer fileinfo-to-diff + (concat "*cvs-diff-" + (cvs-fileinfo->file-name + fileinfo-to-diff) + "-in-" + local-def-directory + "*"))) + (display-buffer (get-buffer-create + (cvs-fileinfo->cvs-diff-buffer fileinfo-to-diff))) + (set-buffer (cvs-fileinfo->cvs-diff-buffer fileinfo-to-diff)) + (setq buffer-read-only nil) + (setq default-directory local-def-directory) + (erase-buffer) + (insert (format "=== cd %s\n" default-directory)) + (insert (format "=== cvs %s\n\n" + (mapconcat 'cvs-quote-multiword-string + (nconc (if cvs-cvsroot + (list "-d" cvs-cvsroot "diff") + '("diff")) + (copy-sequence cvs-diff-flags) + (list (cvs-fileinfo->file-name + fileinfo-to-diff))) + " "))) + (if (apply 'call-process cvs-program nil t t + (nconc (if cvs-cvsroot + (list "-d" cvs-cvsroot "diff") + '("diff")) + (copy-sequence cvs-diff-flags) + (list (cvs-fileinfo->file-name fileinfo-to-diff)))) + (message "cvsdiffing %s... Done." + (cvs-fileinfo->file-name fileinfo-to-diff)) + (message "cvsdiffing %s... No differences found." + (cvs-fileinfo->file-name fileinfo-to-diff))) + (goto-char (point-max)) + (setq marked-file-list (cdr marked-file-list))))) + (message "cvsdiffing... Done.")) +;;---------- (defun cvs-mode-diff-backup (&optional ignore-marks) "Diff the files against the backup file. This command can be used on files that are marked with \"Merged\" @@ -1677,32 +2148,171 @@ If the variable cvs-diff-ignore-marks is non-nil any marked files will not be considered to be selected. An optional prefix argument will invert the influence from cvs-diff-ignore-marks. -The flags in cvs-diff-flags will be passed to ``diff''." +The flags in cvs-diff-flags will be passed to ``diff''. - (interactive "P") +The resulting diffs are placed in the cvs-fileinfo->backup-diff-buffer." + (interactive "P") (if (not (listp cvs-diff-flags)) - (error "cvs-diff-flags should be a list of strings.")) + (error "cvs-diff-flags should be set using cvs-set-diff-flags.")) + (save-some-buffers) + (let ((marked-file-list (cvs-filter + (function cvs-backup-diffable) + (cvs-get-marked + (or + (and ignore-marks (not cvs-diff-ignore-marks)) + (and (not ignore-marks) cvs-diff-ignore-marks)))))) + (if (null marked-file-list) + (error "No ``Conflict'' or ``Merged'' file selected!")) + (message "backup diff...") + (while marked-file-list + (let ((fileinfo-to-diff (tin-cookie cvs-cookie-handle + (car marked-file-list))) + (local-def-directory (file-name-as-directory + (cvs-fileinfo->dir + (tin-cookie cvs-cookie-handle + (car marked-file-list))))) + (backup-temp-files (cvs-diff-backup-extractor + (tin-cookie cvs-cookie-handle + (car marked-file-list))))) + (message "backup diff %s..." + (cvs-fileinfo->file-name fileinfo-to-diff)) + + ;; FIXME: this seems messy to test and set buffer name at this point.... + (if (not (cvs-fileinfo->backup-diff-buffer fileinfo-to-diff)) + (cvs-set-fileinfo->backup-diff-buffer fileinfo-to-diff + (concat "*cvs-diff-" + (cvs-fileinfo->backup-file + fileinfo-to-diff) + "-to-" + (cvs-fileinfo->file-name + fileinfo-to-diff) + "-in" + local-def-directory + "*"))) + (display-buffer (get-buffer-create + (cvs-fileinfo->backup-diff-buffer fileinfo-to-diff))) + (set-buffer (cvs-fileinfo->backup-diff-buffer fileinfo-to-diff)) + (setq buffer-read-only nil) + (setq default-directory local-def-directory) + (erase-buffer) + (insert (format "=== cd %s\n" default-directory)) + (insert (format "=== %s %s\n\n" + cvs-diff-program + (mapconcat 'cvs-quote-multiword-string + (nconc (copy-sequence cvs-diff-flags) + backup-temp-files) + " "))) + (apply 'call-process cvs-diff-program nil t t + (nconc (copy-sequence cvs-diff-flags) backup-temp-files)) + (goto-char (point-max)) + (message "backup diff %s... Done." + (cvs-fileinfo->file-name fileinfo-to-diff)) + (setq marked-file-list (cdr marked-file-list))))) + (message "backup diff... Done.")) +;;---------- +(defun cvs-mode-diff-vendor (&optional ignore-marks) + "Diff the revisions merged into the current file. I.e. show what changes +were merged in. + +This command can be used on files that are marked with \"Merged\" +or \"Conflict\" in the *cvs* buffer. + +If the variable cvs-diff-ignore-marks is non-nil any marked files will +not be considered to be selected. An optional prefix argument will +invert the influence from cvs-diff-ignore-marks. + +The flags in cvs-diff-flags will be passed to ``diff''. + +The resulting diffs are placed in the cvs-fileinfo->vendor-diff-buffer." + + (interactive "P") + (if (not (listp cvs-diff-flags)) + (error "cvs-diff-flags should be set using cvs-set-diff-flags.")) (save-some-buffers) - (let ((marked (cvs-filter - (function cvs-backup-diffable) - (cvs-get-marked - (or - (and ignore-marks (not cvs-diff-ignore-marks)) - (and (not ignore-marks) cvs-diff-ignore-marks)))))) - (if (null marked) + (let ((marked-file-list (cvs-filter + (function cvs-vendor-diffable) + (cvs-get-marked + (or + (and ignore-marks (not cvs-diff-ignore-marks)) + (and (not ignore-marks) cvs-diff-ignore-marks)))))) + (if (null marked-file-list) (error "No ``Conflict'' or ``Merged'' file selected!")) - (cvs-use-temp-buffer) - (message "diffing...") - (cvs-execute-single-file-list - marked 'cvs-diff-backup-extractor cvs-diff-program cvs-diff-flags)) - (message "diffing... Done.")) + (message "vendor diff...") + (while marked-file-list + (let ((fileinfo-to-diff (tin-cookie cvs-cookie-handle + (car marked-file-list))) + (local-def-directory (file-name-as-directory + (cvs-fileinfo->dir + (tin-cookie cvs-cookie-handle + (car marked-file-list))))) + (vendor-temp-files (cvs-diff-vendor-extractor + (tin-cookie cvs-cookie-handle + (car marked-file-list))))) + (message "vendor diff %s..." + (cvs-fileinfo->file-name fileinfo-to-diff)) + (if (not (cvs-fileinfo->vendor-diff-buffer fileinfo-to-diff)) + (cvs-set-fileinfo->vendor-diff-buffer fileinfo-to-diff + (concat "*cvs-diff-" + (cvs-fileinfo->file-name + fileinfo-to-diff) + "-of-" + (cvs-fileinfo->base-revision + fileinfo-to-diff) + "-to-" + (cvs-fileinfo->head-revision + fileinfo-to-diff) + "-in-" + local-def-directory + "*"))) + (display-buffer (get-buffer-create + (cvs-fileinfo->vendor-diff-buffer fileinfo-to-diff))) + (set-buffer (cvs-fileinfo->vendor-diff-buffer fileinfo-to-diff)) + (setq buffer-read-only nil) + (setq default-directory local-def-directory) + (erase-buffer) + (insert (format "=== cd %s\n" default-directory)) + (insert (format "=== %s %s\n\n" + cvs-diff-program + (mapconcat 'cvs-quote-multiword-string + (nconc (copy-sequence cvs-diff-flags) + vendor-temp-files) + " "))) + (apply 'call-process cvs-diff-program nil t t + (nconc (copy-sequence cvs-diff-flags) vendor-temp-files)) + (goto-char (point-max)) + (message "vendor diff %s... Done." + (cvs-fileinfo->file-name fileinfo-to-diff)) + (while vendor-temp-files + (cvs-kill-buffer-visiting (car vendor-temp-files)) + (delete-file (car vendor-temp-files)) + (setq vendor-temp-files (cdr vendor-temp-files))) + (setq marked-file-list (cdr marked-file-list))))) + (message "vendor diff... Done.")) + +;;---------- +(defun cvs-backup-diffable (tin) + "Check if the TIN is backup-diffable. +It must have a backup file to be diffable." + (file-readable-p + (cvs-fileinfo->backup-file (tin-cookie cvs-cookie-handle tin)))) +;;---------- +(defun cvs-vendor-diffable (tin) + "Check if the TIN is vendor-diffable. +It must have head and base revision info to be diffable." + + (and + (cvs-fileinfo->base-revision (tin-cookie cvs-cookie-handle tin)) + (cvs-fileinfo->head-revision (tin-cookie cvs-cookie-handle tin)))) + +;;---------- (defun cvs-diff-backup-extractor (fileinfo) "Return the filename and the name of the backup file as a list. Signal an error if there is no backup file." + (if (not (file-readable-p (cvs-fileinfo->backup-file fileinfo))) (error "%s has no backup file." (concat @@ -1711,14 +2321,27 @@ Signal an error if there is no backup file." (list (cvs-fileinfo->backup-file fileinfo) (cvs-fileinfo->file-name fileinfo))) +;;---------- +(defun cvs-diff-vendor-extractor (fileinfo) + "Retrieve and return the filenames of the vendor branch revisions as a list. +Signal an error if there is no info for the vendor revisions." + + (list (cvs-retrieve-revision-to-tmpfile fileinfo + (cvs-fileinfo->base-revision + fileinfo)) + (cvs-retrieve-revision-to-tmpfile fileinfo + (cvs-fileinfo->head-revision + fileinfo)))) + +;;---------- (defun cvs-mode-find-file-other-window (pos) "Select a buffer containing the file in another window. -Args: POS" +Args: POS." + (interactive "d") (let ((tin (tin-locate cvs-cookie-handle pos))) (if tin - (let ((type (cvs-fileinfo->type (tin-cookie cvs-cookie-handle - tin)))) + (let ((type (cvs-fileinfo->type (tin-cookie cvs-cookie-handle tin)))) (cond ((or (eq type 'REMOVED) (eq type 'CVS-REMOVED)) @@ -1737,20 +2360,26 @@ Args: POS" (find-file-other-window (cvs-full-path tin))))) (error "There is no file to find.")))) +;;---------- (defun cvs-fileinfo->full-path (fileinfo) "Return the full path for the file that is described in FILEINFO." + (concat (file-name-as-directory (cvs-fileinfo->dir fileinfo)) (cvs-fileinfo->file-name fileinfo))) +;;---------- (defun cvs-full-path (tin) "Return the full path for the file that is described in TIN." + (cvs-fileinfo->full-path (tin-cookie cvs-cookie-handle tin))) +;;---------- (defun cvs-mode-find-file (pos) "Select a buffer containing the file in another window. -Args: POS" +Args: POS." + (interactive "d") (let* ((cvs-buf (current-buffer)) (tin (tin-locate cvs-cookie-handle pos))) @@ -1772,9 +2401,11 @@ Args: POS" (find-file (cvs-full-path tin))))) (error "There is no file to find.")))) +;;---------- (defun cvs-mode-mark-all-files () "Mark all files. Directories are not marked." + (interactive) (cookie-map (function (lambda (cookie) (cond @@ -1783,14 +2414,14 @@ Directories are not marked." t)))) cvs-cookie-handle)) - +;;---------- (defun cvs-mode-unmark (pos) - "Unmark a fileinfo. Args: POS." - (interactive "d") + "Unmark a fileinfo. +Args: POS." + (interactive "d") (let* ((tin (tin-locate cvs-cookie-handle pos)) (sel (tin-cookie cvs-cookie-handle tin))) - (cond ((eq (cvs-fileinfo->type sel) 'DIRCHANGE) (cookie-map @@ -1806,27 +2437,30 @@ Directories are not marked." (tin-invalidate cvs-cookie-handle tin) (tin-goto-next cvs-cookie-handle pos 1))))) +;;---------- (defun cvs-mode-unmark-all-files () "Unmark all files. Directories are also unmarked, but that doesn't matter, since they should always be unmarked." + (interactive) (cookie-map (function (lambda (cookie) (cvs-set-fileinfo->marked cookie nil) t)) cvs-cookie-handle)) - +;;---------- (defun cvs-do-removal (tins) "Remove files. -Args: TINS. -TINS is a list of tins that the -user wants to delete. The files are deleted. If the type of -the tin is 'UNKNOWN the tin is removed from the buffer. If it -is anything else the file is added to a list that should be -`cvs remove'd and the tin is changed to be of type 'REMOVED. +Args: TINS. + +TINS is a list of tins that the user wants to delete. The files are deleted. +If the type of the tin is 'UNKNOWN or 'UNKNOWN-DIR the tin is removed from the +buffer. If it is anything else the file is added to a list that should be `cvs +remove'd and the tin is changed to be of type 'REMOVED. Returns a list of tins files that should be `cvs remove'd." + (cvs-use-temp-buffer) (mapcar 'cvs-insert-full-path tins) (cond @@ -1835,26 +2469,32 @@ Returns a list of tins files that should be `cvs remove'd." (while tins (let* ((tin (car tins)) (fileinfo (tin-cookie cvs-cookie-handle tin)) + (filepath (cvs-full-path tin)) (type (cvs-fileinfo->type fileinfo))) - (if (not (or (eq type 'REMOVED) (eq type 'CVS-REMOVED))) - (progn - (delete-file (cvs-full-path tin)) - (cond - ((or (eq type 'UNKNOWN) (eq type 'MOVE-AWAY)) - (tin-delete cvs-cookie-handle tin)) - (t - (setq files-to-remove (cons tin files-to-remove)) - (cvs-set-fileinfo->type fileinfo 'REMOVED) - (cvs-set-fileinfo->handled fileinfo nil) - (tin-invalidate cvs-cookie-handle tin)))))) + (if (or (eq type 'REMOVED) + (eq type 'CVS-REMOVED)) + nil + ;; if it doesn't exist, as a file or directory, ignore it + (cond ((file-directory-p filepath) + (call-process cvs-rmdir-program nil nil nil filepath)) + ((file-exists-p filepath) + (delete-file filepath))) + (if (or (eq type 'UNKNOWN) + (eq type 'UNKNOWN-DIR) + (eq type 'MOVE-AWAY)) + (tin-delete cvs-cookie-handle tin) + (setq files-to-remove (cons tin files-to-remove)) + (cvs-set-fileinfo->type fileinfo 'REMOVED) + (cvs-set-fileinfo->handled fileinfo nil) + (tin-invalidate cvs-cookie-handle tin)))) (setq tins (cdr tins))) files-to-remove)) (t nil))) - - +;;---------- (defun cvs-mode-remove-file () "Remove all marked files." + (interactive) (let ((files-to-remove (cvs-do-removal (cvs-get-marked)))) (if (null files-to-remove) @@ -1864,13 +2504,16 @@ Returns a list of tins files that should be `cvs remove'd." (if (cvs-execute-list files-to-remove cvs-program (if cvs-cvsroot (list "-d" cvs-cvsroot "remove") - '("remove"))) + '("remove")) + "removing %s from repository...") (error "CVS exited with non-zero exit status.") - (message "removing from repository... done."))))) + (message "removing from repository... Done."))))) +;;---------- (defun cvs-mode-undo-local-changes () "Undo local changes to all marked files. The file is removed and `cvs update FILE' is run." + (interactive) (let ((tins-to-undo (cvs-get-marked))) (cvs-use-temp-buffer) @@ -1885,9 +2528,14 @@ The file is removed and `cvs update FILE' is run." (type (cvs-fileinfo->type fileinfo))) (cond ((or - (eq type 'UPDATED) (eq type 'MODIFIED) (eq type 'MERGED) - (eq type 'CONFLICT) (eq type 'CVS-REMOVED) - (eq type 'REM-CONFLICT) (eq type 'MOVE-AWAY) + (eq type 'UPDATED) + (eq type 'PATCHED) + (eq type 'MODIFIED) + (eq type 'MERGED) + (eq type 'CONFLICT) + (eq type 'CVS-REMOVED) + (eq type 'REM-CONFLICT) + (eq type 'MOVE-AWAY) (eq type 'REMOVED)) (if (not (eq type 'REMOVED)) (delete-file (cvs-full-path tin))) @@ -1914,26 +2562,29 @@ The file is removed and `cvs update FILE' is run." (setq tins-to-undo (cdr tins-to-undo)))) (cvs-use-temp-buffer) - (message "Regetting files from repository...") + (message "Re-getting files from repository...") (if (cvs-execute-list files-to-update cvs-program (if cvs-cvsroot (list "-d" cvs-cvsroot "update") - '("update"))) + '("update")) + "Re-getting %s from repository...") (error "CVS exited with non-zero exit status.") - (message "Regetting files from repository... done."))))))) + (message "Re-getting files from repository... Done."))))))) +;;---------- (defun cvs-mode-acknowledge () "Remove all marked files from the buffer." - (interactive) + (interactive) (mapcar (function (lambda (tin) (tin-delete cvs-cookie-handle tin))) (cvs-get-marked))) - +;;---------- (defun cvs-mode-unmark-up (pos) "Unmark the file on the previous line. Takes one argument POS, a buffer position." + (interactive "d") (let ((tin (tin-goto-previous cvs-cookie-handle pos 1))) (cond @@ -1942,99 +2593,152 @@ Takes one argument POS, a buffer position." nil) (tin-invalidate cvs-cookie-handle tin))))) +;;---------- (defun cvs-mode-previous-line (arg) "Go to the previous line. If a prefix argument is given, move by that many lines." + (interactive "p") (tin-goto-previous cvs-cookie-handle (point) arg)) +;;---------- (defun cvs-mode-next-line (arg) "Go to the next line. If a prefix argument is given, move by that many lines." + (interactive "p") (tin-goto-next cvs-cookie-handle (point) arg)) +;;---------- (defun cvs-add-file-update-buffer (tin) - "Subfunction to cvs-mode-add. Internal use only. -Update the display. Return non-nil if `cvs add' should be called on this -file. Args: TIN. -Returns 'ADD or 'RESURRECT." + "Sub-function to cvs-mode-add. Internal use only. Update the display. Return +non-nil if `cvs add' should be called on this file. +Args: TIN. + +Returns 'DIR, 'ADD, 'ADD-DIR, or 'RESURRECT." + (let ((fileinfo (tin-cookie cvs-cookie-handle tin))) (cond + ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN-DIR) + (cvs-set-fileinfo->full-log fileinfo "new directory added with cvs-mode-add") + 'ADD-DIR) ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN) (cvs-set-fileinfo->type fileinfo 'ADDED) + (cvs-set-fileinfo->full-log fileinfo "new file added with cvs-mode-add") (tin-invalidate cvs-cookie-handle tin) 'ADD) ((eq (cvs-fileinfo->type fileinfo) 'REMOVED) (cvs-set-fileinfo->type fileinfo 'UPDATED) + (cvs-set-fileinfo->full-log fileinfo "file resurrected with cvs-mode-add") (cvs-set-fileinfo->handled fileinfo t) (tin-invalidate cvs-cookie-handle tin) 'RESURRECT)))) +;;---------- (defun cvs-add-sub (cvs-buf candidates) "Internal use only. -Args: CVS-BUF CANDIDATES. -CANDIDATES is a list of tins. Updates the CVS-BUF and returns a pair of lists. +Args: CVS-BUF CANDIDATES. + +CANDIDATES is a list of tins. Updates the CVS-BUF and returns a list of lists. The first list is unknown tins that shall be `cvs add -m msg'ed. -The second list is removed files that shall be `cvs add'ed (resurrected)." - (let (add resurrect) +The second list is unknown directory tins that shall be `cvs add -m msg'ed. +The third list is removed files that shall be `cvs add'ed (resurrected)." + + (let (add add-dir resurrect) (while candidates (let ((type (cvs-add-file-update-buffer (car candidates)))) (cond ((eq type 'ADD) (setq add (cons (car candidates) add))) + ((eq type 'ADD-DIR) + (setq add-dir (cons (car candidates) add-dir))) ((eq type 'RESURRECT) (setq resurrect (cons (car candidates) resurrect))))) (setq candidates (cdr candidates))) - (cons add resurrect))) + (list add add-dir resurrect))) +;;---------- (defun cvs-mode-add () "Add marked files to the cvs repository." - (interactive) + (interactive) (let* ((buf (current-buffer)) - (result (cvs-add-sub buf (cvs-get-marked))) + (marked (cvs-get-marked)) + (result (cvs-add-sub buf marked)) (added (car result)) - (resurrect (cdr result)) - (msg (if added (read-from-minibuffer "Enter description: ")))) + (newdirs (car (cdr result))) + (resurrect (car (cdr (cdr result)))) + (msg (if (or added newdirs) + (read-from-minibuffer "Enter description: ")))) - (if (or resurrect added) + (if (or resurrect (or added newdirs)) (cvs-use-temp-buffer)) (cond (resurrect (message "Resurrecting files from repository...") - (if (cvs-execute-list resurrect cvs-program + (if (cvs-execute-list resurrect + cvs-program (if cvs-cvsroot (list "-d" cvs-cvsroot "add") - '("add"))) + '("add")) + "Resurrecting %s from repository...") (error "CVS exited with non-zero exit status.") - (message "Done.")))) + (message "Resurrecting files from repository... Done.")))) (cond (added (message "Adding new files to repository...") - (if (cvs-execute-list added cvs-program + (if (cvs-execute-list added + cvs-program (if cvs-cvsroot (list "-d" cvs-cvsroot "add" "-m" msg) - (list "add" "-m" msg))) + (list "add" "-m" msg)) + "Adding %s to repository...") (error "CVS exited with non-zero exit status.") - (message "Done.")))))) + (message "Adding new files to repository... Done.")))) + (cond (newdirs + (message "Adding new directories to repository...") + (if (cvs-execute-list newdirs + cvs-program + (if cvs-cvsroot + (list "-d" cvs-cvsroot "add" "-m" msg) + (list "add" "-m" msg)) + "Adding %s to repository...") + (error "CVS exited with non-zero exit status.") + (while newdirs + (let* ((tin (car newdirs)) + (fileinfo (tin-cookie cvs-cookie-handle tin)) + (newdir (cvs-fileinfo->file-name fileinfo))) + (cvs-set-fileinfo->dir fileinfo + (concat (cvs-fileinfo->dir fileinfo) + "/" + newdir)) + (cvs-set-fileinfo->type fileinfo 'DIRCHANGE) + (cvs-set-fileinfo->file-name fileinfo ".") + (tin-invalidate cvs-cookie-handle tin) + (setq newdirs (cdr newdirs)))) + ;; FIXME: this should really run cvs-update-no-prompt on the + ;; subdir and insert everthing in the current list. + (message "You must re-update to visit the new directories.")))))) + +;;---------- (defun cvs-mode-ignore () - "Arrange so that CVS ignores the selected files. -This command ignores files that are not flagged as `Unknown'." - (interactive) + "Arrange so that CVS ignores the selected files and directories. +This command ignores files/dirs that are flagged as `Unknown'." + (interactive) (mapcar (function (lambda (tin) - (cond - ((eq (cvs-fileinfo->type - (tin-cookie cvs-cookie-handle tin)) - 'UNKNOWN) - (cvs-append-to-ignore - (tin-cookie cvs-cookie-handle tin)) - (tin-delete cvs-cookie-handle tin))))) + (let* ((fileinfo (tin-cookie cvs-cookie-handle tin)) + (type (cvs-fileinfo->type fileinfo))) + (cond ((or (eq type 'UNKNOWN) + (eq type 'UNKNOWN-DIR)) + (cvs-append-to-ignore fileinfo) + (tin-delete cvs-cookie-handle tin)))))) (cvs-get-marked))) +;;---------- (defun cvs-append-to-ignore (fileinfo) "Append the file in fileinfo to the .cvsignore file" + (save-window-excursion (set-buffer (find-file-noselect (concat (file-name-as-directory (cvs-fileinfo->dir fileinfo)) @@ -2047,39 +2751,95 @@ This command ignores files that are not flagged as `Unknown'." (sort-lines nil (point-min) (point-max))) (save-buffer))) +;;---------- (defun cvs-mode-status () "Show cvs status for all marked files." - (interactive) + (interactive) (save-some-buffers) - (let ((marked (cvs-get-marked))) + (if (not (listp cvs-status-flags)) + (error "cvs-status-flags should be set using cvs-set-status-flags.")) + (let ((marked (cvs-get-marked nil t))) (cvs-use-temp-buffer) (message "Running cvs status ...") - (if (cvs-execute-list - marked cvs-program - (if cvs-cvsroot - (cons "-d" (cons cvs-cvsroot (cons "status" cvs-status-flags))) - (cons "status" cvs-status-flags))) + (if (cvs-execute-list marked + cvs-program + (append (if cvs-cvsroot (list "-d" cvs-cvsroot)) + (list "-Q" "status") + cvs-status-flags) + "Running cvs -Q status %s...") (error "CVS exited with non-zero exit status.") - (message "Running cvs status ... Done.")))) + (message "Running cvs -Q status ... Done.")))) +;;---------- (defun cvs-mode-log () "Display the cvs log of all selected files." - (interactive) - (let ((marked (cvs-get-marked))) + (interactive) + (if (not (listp cvs-log-flags)) + (error "cvs-log-flags should be set using cvs-set-log-flags.")) + (let ((marked (cvs-get-marked nil t))) (cvs-use-temp-buffer) (message "Running cvs log ...") - (if (cvs-execute-list marked cvs-program - (if cvs-cvsroot - (cons "-d" (cons cvs-cvsroot - (cons "log" cvs-log-flags))) - (cons "log" cvs-log-flags))) + (if (cvs-execute-list marked + cvs-program + (append (if cvs-cvsroot (list "-d" cvs-cvsroot)) + (list "log") + cvs-log-flags) + "Running cvs log %s...") (error "CVS exited with non-zero exit status.") (message "Running cvs log ... Done.")))) -(defun cvs-byte-compile-files () +;;---------- +(defun cvs-mode-tag () + "Run 'cvs tag' on all selected files." + + (interactive) + (if (not (listp cvs-tag-flags)) + (error "cvs-tag-flags should be set using cvs-set-tag-flags.")) + (let ((marked (cvs-get-marked nil t)) + (tag-args (cvs-make-list (read-string "Tag name (and flags): ")))) + (cvs-use-temp-buffer) + (message "Running cvs tag ...") + (if (cvs-execute-list marked + cvs-program + (append (if cvs-cvsroot (list "-d" cvs-cvsroot)) + (list "tag") + cvs-tag-flags + tag-args) + "Running cvs tag %s...") + (error "CVS exited with non-zero exit status.") + (message "Running cvs tag ... Done.")))) + +;;---------- +(defun cvs-mode-rtag () + "Run 'cvs rtag' on all selected files." + + (interactive) + (if (not (listp cvs-rtag-flags)) + (error "cvs-rtag-flags should be set using cvs-set-rtag-flags.")) + (let ((marked (cvs-get-marked nil t)) + ;; FIXME: should give selection from the modules file + (module-name (read-string "Module name: ")) + ;; FIXME: should also ask for an existing tag *or* date + (rtag-args (cvs-make-list (read-string "Tag name (and flags): ")))) + (cvs-use-temp-buffer) + (message "Running cvs rtag ...") + (if (cvs-execute-list marked + cvs-program + (append (if cvs-cvsroot (list "-d" cvs-cvsroot)) + (list "rtag") + cvs-rtag-flags + rtag-args + (list module-name)) + "Running cvs rtag %s...") + (error "CVS rtag exited with non-zero exit status.") + (message "Running cvs rtag ... Done.")))) + +;;---------- +(defun cvs-mode-byte-compile-files () "Run byte-compile-file on all selected files that end in '.el'." + (interactive) (let ((marked (cvs-get-marked))) (while marked @@ -2088,34 +2848,45 @@ This command ignores files that are not flagged as `Unknown'." (byte-compile-file filename))) (setq marked (cdr marked))))) +;;---------- (defun cvs-insert-full-path (tin) "Insert full path to the file described in TIN in the current buffer." - (insert (format "%s\n" (cvs-full-path tin)))) + (insert (format "%s\n" (cvs-full-path tin)))) +;;---------- (defun cvs-mode-add-change-log-entry-other-window (pos) "Add a ChangeLog entry in the ChangeLog of the current directory. -Args: POS." +Args: POS." + (interactive "d") (let* ((cvs-buf (current-buffer)) - (odir default-directory)) - (setq default-directory - (file-name-as-directory - (cvs-fileinfo->dir - (tin-cookie - cvs-cookie-handle - (tin-locate cvs-cookie-handle pos))))) - (if (not default-directory) ;In case there was no entries. - (setq default-directory odir)) + (odir default-directory) + (obfname buffer-file-name) + (tin (tin-locate cvs-cookie-handle pos)) + (fileinfo (tin-cookie cvs-cookie-handle tin)) + (fname (cvs-fileinfo->file-name fileinfo)) + (dname (file-name-as-directory (cvs-fileinfo->dir fileinfo)))) + (setq change-log-default-name nil) ; this rarely correct in 19.28 + (setq buffer-file-name (cond (fname + fname) + (t + nil))) + (setq default-directory (cond (dname + dname) + (t + odir))) (add-change-log-entry-other-window) (set-buffer cvs-buf) - (setq default-directory odir))) - + (setq default-directory odir) + (setq buffer-file-name obfname))) +;;---------- (defun print-cvs-tin (foo) "Debug utility." + (let ((cookie (tin-cookie cvs-cookie-handle foo)) - (stream (get-buffer-create "debug"))) + (stream (get-buffer-create "pcl-cvs-debug"))) (princ "==============\n" stream) (princ (cvs-fileinfo->file-name cookie) stream) (princ "\n" stream) @@ -2126,146 +2897,323 @@ Args: POS." (princ (cvs-fileinfo->marked cookie) stream) (princ "\n" stream))) +;;---------- +;; NOTE: the variable cvs-emerge-tmp-head-file will be "free" when compiling (defun cvs-mode-emerge (pos) "Emerge appropriate revisions of the selected file. -Args: POS" +Args: POS." + (interactive "d") (let* ((cvs-buf (current-buffer)) (tin (tin-locate cvs-cookie-handle pos))) + (if (boundp 'cvs-emerge-tmp-head-file) + (error "There can only be one emerge session active at a time.")) (if tin (let* ((fileinfo (tin-cookie cvs-cookie-handle tin)) (type (cvs-fileinfo->type fileinfo))) (cond - ((eq type 'MODIFIED) + ((eq type 'MODIFIED) ; merge repository head rev. with working file (require 'emerge) - (let ((tmp-file - (cvs-retrieve-revision-to-tmpfile fileinfo))) - (unwind-protect - (if (not (emerge-files - t - (cvs-fileinfo->full-path fileinfo) - tmp-file - (cvs-fileinfo->full-path fileinfo))) - (error "Emerge session failed")) - (delete-file tmp-file)))) - + (setq cvs-emerge-tmp-head-file ; trick to prevent multiple runs + (cvs-retrieve-revision-to-tmpfile fileinfo)) + (unwind-protect + (if (not (emerge-files + t ; arg + (cvs-fileinfo->full-path fileinfo) ; file-A + ;; this is an un-avoidable compiler reference to a free variable + cvs-emerge-tmp-head-file ; file-B + (cvs-fileinfo->full-path fileinfo) ; file-out + nil ; start-hooks + '(lambda () ; quit-hooks + (delete-file cvs-emerge-tmp-head-file) + (makunbound 'cvs-emerge-tmp-head-file)))) + (error "Emerge session failed")))) + + ;; re-do the same merge rcsmerge supposedly just did.... ((or (eq type 'MERGED) - (eq type 'CONFLICT)) + (eq type 'CONFLICT)) ; merge backup-working=A, head=B, base=ancestor (require 'emerge) - (let ((tmp-file - (cvs-retrieve-revision-to-tmpfile - fileinfo)) - (ancestor-file - (cvs-retrieve-revision-to-tmpfile - fileinfo - (cvs-fileinfo->base-revision fileinfo)))) + (setq cvs-emerge-tmp-head-file ; trick to prevent multiple runs + (cvs-retrieve-revision-to-tmpfile fileinfo + (cvs-fileinfo->head-revision + fileinfo))) + (let ((cvs-emerge-tmp-backup-working-file + (cvs-fileinfo->backup-file fileinfo)) + (cvs-emerge-tmp-ancestor-file + (cvs-retrieve-revision-to-tmpfile fileinfo + (cvs-fileinfo->base-revision + fileinfo)))) (unwind-protect (if (not (emerge-files-with-ancestor - t - (cvs-fileinfo->backup-file fileinfo) - tmp-file - ancestor-file - (cvs-fileinfo->full-path fileinfo))) - (error "Emerge session failed")) - (delete-file tmp-file) - (delete-file ancestor-file)))) + t ; arg + cvs-emerge-tmp-backup-working-file ; file-A + ;; this is an un-avoidable compiler reference to a free variable + cvs-emerge-tmp-head-file ; file-B + cvs-emerge-tmp-ancestor-file ; file-ancestor + (cvs-fileinfo->full-path fileinfo) ; file-out + nil ; start-hooks + '(lambda () ; quit-hooks + (delete-file cvs-emerge-tmp-backup-file) + (delete-file cvs-emerge-tmp-ancestor-file) + (delete-file cvs-emerge-tmp-head-file) + (makunbound 'cvs-emerge-tmp-head-file)))) + (error "Emerge session failed"))))) (t - (error "Can only emerge \"Modified\", \"Merged\" or \"Conflict\"%s" - " files")))) - (error "There is no file to emerge.")))) + (error "Can only e-merge \"Modified\", \"Merged\" or \"Conflict\" files")))) + (error "There is no file to e-merge.")))) + +;;---------- +;; NOTE: the variable ediff-version may be "free" when compiling +(defun cvs-mode-ediff (pos) + "Ediff appropriate revisions of the selected file. +Args: POS." + (interactive "d") + (if (boundp 'cvs-ediff-tmp-head-file) + (error "There can only be one ediff session active at a time.")) + (require 'ediff) + (if (and (boundp 'ediff-version) + (>= (string-to-number ediff-version) 2.0)) ; FIXME real number? + (run-ediff-from-cvs-buffer pos) + (cvs-old-ediff-interface pos))) + +(defun cvs-old-ediff-interface (pos) + "Emerge like interface for older ediffs. +Args: POS" + + (let* ((cvs-buf (current-buffer)) + (tin (tin-locate cvs-cookie-handle pos))) + (if tin + (let* ((fileinfo (tin-cookie cvs-cookie-handle tin)) + (type (cvs-fileinfo->type fileinfo))) + (cond + ((eq type 'MODIFIED) ; diff repository head rev. with working file + ;; should this be inside the unwind-protect, and should the + ;; makeunbound be an unwindform? + (setq cvs-ediff-tmp-head-file ; trick to prevent multiple runs + (cvs-retrieve-revision-to-tmpfile fileinfo)) + (unwind-protect + (if (not (ediff-files ; check correct ordering of args + (cvs-fileinfo->full-path fileinfo) ; file-A + ;; this is an un-avoidable compiler reference to a free variable + cvs-ediff-tmp-head-file ; file-B + '(lambda () ; startup-hooks + (make-local-hook 'ediff-cleanup-hooks) + (add-hook 'ediff-cleanup-hooks + '(lambda () + (ediff-janitor) + (delete-file cvs-ediff-tmp-head-file) + (makunbound 'cvs-ediff-tmp-head-file)) + nil t)))) + (error "Ediff session failed")))) + + ;; look at the merge rcsmerge supposedly just did.... + ((or (eq type 'MERGED) + (eq type 'CONFLICT)) ; diff backup-working=A, head=B, base=ancestor + (if (not (boundp 'ediff-version)) + (error "ediff version way too old for 3-way diff")) + (if (<= (string-to-number ediff-version) 1.9) ; FIXME real number? + (error "ediff version %s too old for 3-way diff" ediff-version)) + (setq cvs-ediff-tmp-head-file ; trick to prevent multiple runs + (cvs-retrieve-revision-to-tmpfile fileinfo + (cvs-fileinfo->head-revision + fileinfo))) + (let ((cvs-ediff-tmp-backup-working-file + (cvs-fileinfo->backup-file fileinfo)) + (cvs-ediff-tmp-ancestor-file + (cvs-retrieve-revision-to-tmpfile fileinfo + (cvs-fileinfo->base-revision + fileinfo)))) + (unwind-protect + (if (not (ediff-files3 ; check correct ordering of args + cvs-ediff-tmp-backup-working-file ; file-A + ;; this is an un-avoidable compiler reference to a free variable + cvs-ediff-tmp-head-file ; file-B + cvs-ediff-tmp-ancestor-file ; file-ancestor + '(lambda () ; start-hooks + (make-local-hook 'ediff-cleanup-hooks) + (add-hook 'ediff-cleanup-hooks + '(lambda () + (ediff-janitor) + (delete-file cvs-ediff-tmp-backup-file) + (delete-file cvs-ediff-tmp-ancestor-file) + (delete-file cvs-ediff-tmp-head-file) + (makunbound 'cvs-ediff-tmp-head-file)) + nil t)))) + (error "Ediff session failed"))))) + + ((not (or (eq type 'UNKNOWN) + (eq type 'UNKNOWN-DIR))) ; i.e. UPDATED or PATCHED ???? + ;; this should really diff the current working file with the previous + ;; rev. on the current branch (i.e. not the head, since that's what + ;; the current file should be) + (setq cvs-ediff-tmp-head-file ; trick to prevent multiple runs + (cvs-retrieve-revision-to-tmpfile fileinfo + (read-string "Rev #/tag to diff against: " + (cvs-fileinfo->head-revision + fileinfo)))) + (unwind-protect + (if (not (ediff-files ; check correct ordering of args + (cvs-fileinfo->full-path fileinfo) ; file-A + ;; this is an un-avoidable compiler reference to a free variable + cvs-ediff-tmp-head-file ; file-B + '(lambda () ; startup-hooks + (make-local-hook 'ediff-cleanup-hooks) + (add-hook 'ediff-cleanup-hooks + '(lambda () + (ediff-janitor) + (delete-file cvs-ediff-tmp-head-file) + (makunbound 'cvs-ediff-tmp-head-file)) + nil t)))) + (error "Ediff session failed")))) + (t + (error "Can not ediff \"Unknown\" files")))) + (error "There is no file to ediff.")))) + +;;---------- (defun cvs-retrieve-revision-to-tmpfile (fileinfo &optional revision) "Retrieve the latest revision of the file in FILEINFO to a temporary file. If second optional argument REVISION is given, retrieve that revision instead." + (let ((temp-name (make-temp-name (concat (file-name-as-directory (or (getenv "TMPDIR") "/tmp")) "pcl-cvs." revision)))) (cvs-kill-buffer-visiting temp-name) - (if revision + (if (and revision + (stringp revision) + (not (string= revision ""))) (message "Retrieving revision %s..." revision) (message "Retrieving latest revision...")) (let ((res (call-process cvs-shell nil nil nil "-c" (concat cvs-program " update -p " - (if revision + (if (and revision + (stringp revision) + (not (string= revision ""))) (concat "-r " revision " ") "") (cvs-fileinfo->full-path fileinfo) " > " temp-name)))) (if (and res (not (and (integerp res) (zerop res)))) - (error "Something went wrong: %s" res)) + (error "Something went wrong retrieving revision %s: %s" + revision res)) (if revision (message "Retrieving revision %s... Done." revision) (message "Retrieving latest revision... Done.")) - (find-file-noselect temp-name) + (save-excursion + (set-buffer (find-file-noselect temp-name)) + (rename-buffer (concat " " (file-name-nondirectory temp-name)) t)) temp-name))) -(defun cvs-fileinfo->backup-file (fileinfo) - "Construct the file name of the backup file for FILEINFO." - (if (cvs-fileinfo->base-revision fileinfo) - (concat cvs-bakprefix (cvs-fileinfo->file-name fileinfo) - "." (cvs-fileinfo->base-revision fileinfo)))) - +;;---------- (defun cvs-kill-buffer-visiting (filename) "If there is any buffer visiting FILENAME, kill it (without confirmation)." + (let ((l (buffer-list))) (while l (if (string= (buffer-file-name (car l)) filename) (kill-buffer (car l))) (setq l (cdr l))))) -(defun cvs-change-cvsroot (newroot) +;;---------- +(defun cvs-change-cvsroot () + "Ask for a new cvsroot." + + (interactive) + (cvs-set-cvsroot (read-file-name "New CVSROOT: " cvs-cvsroot))) + +;;---------- +(defun cvs-set-cvsroot (newroot) "Change the cvsroot." - (interactive "DNew repository: ") + (if (or (file-directory-p (expand-file-name "CVSROOT" newroot)) - (y-or-n-p (concat "Warning: no CVSROOT found inside repository." + (y-or-n-p (concat "Warning: no CVSROOT found inside repository." " Change cvs-cvsroot anyhow?"))) (setq cvs-cvsroot newroot))) -(if (string-match "Lucid" emacs-version) - (progn - (autoload 'pcl-cvs-fontify "pcl-cvs-lucid") - (add-hook 'cvs-mode-hook 'pcl-cvs-fontify))) +;;---------- +(defun cvs-set-diff-flags () + "Ask for new setting of cvs-diff-flags." + (interactive) + (let ((old-value (mapconcat 'identity + (copy-sequence cvs-diff-flags) " "))) + (setq cvs-diff-flags + (cvs-make-list (read-string "Diff flags: " old-value))))) + +;;---------- +(defun cvs-set-update-optional-flags () + "Ask for new setting of cvs-update-optional-flags." + + (interactive) + (let ((old-value (mapconcat 'identity + (copy-sequence cvs-update-optional-flags) " "))) + (setq cvs-update-optional-flags + (cvs-make-list (read-string "Update optional flags: " old-value))))) -(defvar cvs-changelog-full-paragraphs t - "If non-nil, include full ChangeLog paragraphs in the CVS log. -This may be set in the ``local variables'' section of a ChangeLog, to -indicate the policy for that ChangeLog. +;;---------- +(defun cvs-set-status-flags () + "Ask for new setting of cvs-status-flags." -A ChangeLog paragraph is a bunch of log text containing no blank lines; -a paragraph usually describes a set of changes with a single purpose, -but perhaps spanning several functions in several files. Changes in -different paragraphs are unrelated. + (interactive) + (let ((old-value (mapconcat 'identity + (copy-sequence cvs-status-flags) " "))) + (setq cvs-status-flags + (cvs-make-list (read-string "Status flags: " old-value))))) -You could argue that the CVS log entry for a file should contain the -full ChangeLog paragraph mentioning the change to the file, even though -it may mention other files, because that gives you the full context you -need to understand the change. This is the behavior you get when this -variable is set to t. +;;---------- +(defun cvs-set-log-flags () + "Ask for new setting of cvs-log-flags." -On the other hand, you could argue that the CVS log entry for a change -should contain only the text for the changes which occurred in that -file, because the CVS log is per-file. This is the behavior you get -when this variable is set to nil.") + (interactive) + (let ((old-value (mapconcat 'identity + (copy-sequence cvs-log-flags) " "))) + (setq cvs-log-flags + (cvs-make-list (read-string "Log flags: " old-value))))) + +;;---------- +(defun cvs-set-tag-flags () + "Ask for new setting of cvs-tag-flags." + + (interactive) + (let ((old-value (mapconcat 'identity + (copy-sequence cvs-tag-flags) " "))) + (setq cvs-tag-flags + (cvs-make-list (read-string "Tag flags: " old-value))))) + +;;---------- +(defun cvs-set-rtag-flags () + "Ask for new setting of cvs-rtag-flags." + + (interactive) + (let ((old-value (mapconcat 'identity + (copy-sequence cvs-rtag-flags) " "))) + (setq cvs-rtag-flags + (cvs-make-list (read-string "Rtag flags: " old-value))))) + +;;---------- +(if (string-match "Lucid" emacs-version) + (progn + (autoload 'pcl-cvs-fontify "pcl-cvs-lucid") + (add-hook 'cvs-mode-hook 'pcl-cvs-fontify))) (defun cvs-changelog-name (directory) "Return the name of the ChangeLog file that handles DIRECTORY. This is in DIRECTORY or one of its parents. Signal an error if we can't find an appropriate ChangeLog file." (let ((dir (file-name-as-directory directory)) - file) + file) (while (and dir - (not (file-exists-p - (setq file (expand-file-name "ChangeLog" dir))))) + (not (file-exists-p + (setq file (expand-file-name "ChangeLog" dir))))) (let ((last dir)) - (setq dir (file-name-directory (directory-file-name dir))) - (if (equal last dir) - (setq dir nil)))) + (setq dir (file-name-directory (directory-file-name dir))) + (if (equal last dir) + (setq dir nil)))) (or dir - (error "Can't find ChangeLog for %s" directory)) + (error "Can't find ChangeLog for %s" directory)) file)) (defun cvs-narrow-changelog () @@ -2293,28 +3241,28 @@ If we are between paragraphs, return the previous paragraph." (save-excursion (beginning-of-line) (if (looking-at "^[ \t]*$") - (skip-chars-backward " \t\n" (point-min))) + (skip-chars-backward " \t\n" (point-min))) (list (progn - (if (re-search-backward "^[ \t]*\n" nil 'or-to-limit) - (goto-char (match-end 0))) - (point)) - (if (re-search-forward "^[ \t\n]*$" nil t) - (match-beginning 0) - (point))))) + (if (re-search-backward "^[ \t]*\n" nil 'or-to-limit) + (goto-char (match-end 0))) + (point)) + (if (re-search-forward "^[ \t\n]*$" nil t) + (match-beginning 0) + (point))))) (defun cvs-changelog-subparagraph () "Return the bounds of the ChangeLog subparagraph containing point. A subparagraph is a block of non-blank lines beginning with an asterisk. -If we are between subparagraphs, return the previous subparagraph." +If we are between sub-paragraphs, return the previous subparagraph." (save-excursion (end-of-line) (if (search-backward "*" nil t) - (list (progn (beginning-of-line) (point)) - (progn - (forward-line 1) - (if (re-search-forward "^[ \t]*[\n*]" nil t) - (match-beginning 0) - (point-max)))) + (list (progn (beginning-of-line) (point)) + (progn + (forward-line 1) + (if (re-search-forward "^[ \t]*[\n*]" nil t) + (match-beginning 0) + (point-max)))) (list (point) (point))))) (defun cvs-changelog-entry () @@ -2326,26 +3274,34 @@ for more details." (cvs-changelog-paragraph) (cvs-changelog-subparagraph))) +;; NOTE: the variable user-full-name may be "free" when compiling (defun cvs-changelog-ours-p () "See if ChangeLog entry at point is for the current user, today. Return non-nil iff it is." ;; Code adapted from add-change-log-entry. (looking-at (concat (regexp-quote (substring (current-time-string) - 0 10)) - ".* " - (regexp-quote (substring (current-time-string) -4)) - "[ \t]+" - (regexp-quote add-log-full-name) - " <" (regexp-quote add-log-mailing-address)))) + 0 10)) + ".* " + (regexp-quote (substring (current-time-string) -4)) + "[ \t]+" + (regexp-quote (if (and (boundp 'add-log-full-name) + add-log-full-name) + add-log-full-name + user-full-name)) + " <" + (regexp-quote (if (and (boundp 'add-log-mailing-address) + add-log-mailing-address) + add-log-mailing-address + user-mail-address))))) (defun cvs-relative-path (base child) "Return a directory path relative to BASE for CHILD. If CHILD doesn't seem to be in a subdirectory of BASE, just return the full path to CHILD." (let ((base (file-name-as-directory (expand-file-name base))) - (child (expand-file-name child))) + (child (expand-file-name child))) (or (string= base (substring child 0 (length base))) - (error "cvs-relative-path: %s isn't in %s" child base)) + (error "cvs-relative-path: %s isn't in %s" child base)) (substring child (length base)))) (defun cvs-changelog-entries (file) @@ -2356,45 +3312,47 @@ where LOGBUFFER is the name of the ChangeLog buffer, and each \(ENTRYSTART . ENTRYEND\) pair is a buffer region." (save-excursion (set-buffer (find-file-noselect - (cvs-changelog-name - (file-name-directory - (expand-file-name file))))) + (cvs-changelog-name + (file-name-directory + (expand-file-name file))))) + (or (eq major-mode 'change-log-mode) + (change-log-mode)) (goto-char (point-min)) (if (looking-at "[ \t\n]*\n") - (goto-char (match-end 0))) + (goto-char (match-end 0))) (if (not (cvs-changelog-ours-p)) - (list (current-buffer)) + (list (current-buffer)) (save-restriction - (cvs-narrow-changelog) - (goto-char (point-min)) - - ;; Search for the name of FILE relative to the ChangeLog. If that - ;; doesn't occur anywhere, they're not using full relative - ;; filenames in the ChangeLog, so just look for FILE; we'll accept - ;; some false positives. - (let ((pattern (cvs-relative-path - (file-name-directory buffer-file-name) file))) - (if (or (string= pattern "") - (not (save-excursion - (search-forward pattern nil t)))) - (setq pattern file)) - - (let (texts) - (while (search-forward pattern nil t) - (let ((entry (cvs-changelog-entry))) - (setq texts (cons entry texts)) - (goto-char (elt entry 1)))) - - (cons (current-buffer) texts))))))) + (cvs-narrow-changelog) + (goto-char (point-min)) + + ;; Search for the name of FILE relative to the ChangeLog. If that + ;; doesn't occur anywhere, they're not using full relative + ;; filenames in the ChangeLog, so just look for FILE; we'll accept + ;; some false positives. + (let ((pattern (cvs-relative-path + (file-name-directory buffer-file-name) file))) + (if (or (string= pattern "") + (not (save-excursion + (search-forward pattern nil t)))) + (setq pattern file)) + + (let (texts) + (while (search-forward pattern nil t) + (let ((entry (cvs-changelog-entry))) + (setq texts (cons entry texts)) + (goto-char (elt entry 1)))) + + (cons (current-buffer) texts))))))) (defun cvs-changelog-insert-entries (buffer regions) "Insert those regions in BUFFER specified in REGIONS. Sort REGIONS front-to-back first." (let ((regions (sort regions 'car-less-than-car)) - (last)) + (last)) (while regions (if (and last (< last (car (car regions)))) - (newline)) + (newline)) (setq last (elt (car regions) 1)) (apply 'insert-buffer-substring buffer (car regions)) (setq regions (cdr regions))))) @@ -2403,7 +3361,7 @@ Sort REGIONS front-to-back first." "Return the union of SET1 and SET2, according to `equal'." (while set2 (or (member (car set2) set1) - (setq set1 (cons (car set2) set1))) + (setq set1 (cons (car set2) set1))) (setq set2 (cdr set2))) set1) @@ -2415,19 +3373,19 @@ Sort REGIONS front-to-back first." ;; of entries we want from that file. (while files (let* ((entries (cvs-changelog-entries (car files))) - (pair (assq (car entries) buffer-entries))) - (if pair - (setcdr pair (cvs-union (cdr pair) (cdr entries))) - (setq buffer-entries (cons entries buffer-entries)))) + (pair (assq (car entries) buffer-entries))) + (if pair + (setcdr pair (cvs-union (cdr pair) (cdr entries))) + (setq buffer-entries (cons entries buffer-entries)))) (setq files (cdr files))) ;; Now map over each buffer in buffer-entries, sort the entries for ;; each buffer, and extract them as strings. (while buffer-entries (cvs-changelog-insert-entries (car (car buffer-entries)) - (cdr (car buffer-entries))) + (cdr (car buffer-entries))) (if (and (cdr buffer-entries) (cdr (car buffer-entries))) - (newline)) + (newline)) (setq buffer-entries (cdr buffer-entries))))) (defun cvs-edit-delete-common-indentation () @@ -2436,23 +3394,22 @@ Sort REGIONS front-to-back first." (let ((common 100000)) (goto-char (point-min)) (while (< (point) (point-max)) - (if (not (looking-at "^[ \t]*$")) - (setq common (min common (current-indentation)))) - (forward-line 1)) + (if (not (looking-at "^[ \t]*$")) + (setq common (min common (current-indentation)))) + (forward-line 1)) (indent-rigidly (point-min) (point-max) (- common))))) (defun cvs-mode-changelog-commit () - "Check in all marked files, or the current file. Ask the user for a log message in a buffer. This is just like `\\[cvs-mode-commit]', except that it tries to provide -appropriate default log messages by looking at the ChangeLogs. The +appropriate default log messages by looking at the ChangeLog. The idea is to write your ChangeLog entries first, and then use this command to commit your changes. To select default log text, we: -- find the ChangeLogs for the files to be checked in, +- find the ChangeLog entries for the files to be checked in, - verify that the top entry in the ChangeLog is on the current date and by the current user; if not, we don't provide any default text, - search the ChangeLog entry for paragraphs containing the names of @@ -2462,24 +3419,26 @@ To select default log text, we: (interactive) (let* ((cvs-buf (current-buffer)) - (marked (cvs-filter (function cvs-committable) - (cvs-get-marked)))) + (marked (cvs-filter (function cvs-committable) + (cvs-get-marked)))) (if (null marked) - (error "Nothing to commit!") + (error "Nothing to commit!") (pop-to-buffer (get-buffer-create cvs-commit-prompt-buffer)) (goto-char (point-min)) (erase-buffer) (cvs-insert-changelog-entries (mapcar (lambda (tin) - (let ((cookie (tin-cookie cvs-cookie-handle tin))) - (expand-file-name - (cvs-fileinfo->file-name cookie) - (cvs-fileinfo->dir cookie)))) - marked)) + (let ((cookie (tin-cookie cvs-cookie-handle tin))) + (expand-file-name + (cvs-fileinfo->file-name cookie) + (cvs-fileinfo->dir cookie)))) + marked)) (cvs-edit-delete-common-indentation) (cvs-edit-mode) (make-local-variable 'cvs-commit-list) (setq cvs-commit-list marked) (message "Press C-c C-c when you are done editing.")))) + +;;;; end of file pcl-cvs.el diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.elc b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.elc new file mode 100644 index 00000000000..ec37822cfd8 Binary files /dev/null and b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.elc differ diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo index bb0a4fec3d8..6f865f0e27e 100644 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo +++ b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo @@ -1,6 +1,8 @@ \input texinfo @c -*-texinfo-*- -@comment Id: pcl-cvs.texinfo,v 1.45 1993/05/31 22:38:15 ceder Exp +@comment OrigId: pcl-cvs.texinfo,v 1.45 1993/05/31 22:38:15 ceder Exp +@comment @@(#)cvs/contrib/pcl-cvs:$Name: $:$Id: pcl-cvs.texinfo,v 1.1.1.2 1996/01/30 00:19:14 tholo Exp $ + @comment Documentation for the GNU Emacs CVS mode. @comment Copyright (C) 1992 Per Cederqvist @@ -62,12 +64,12 @@ Free Software Foundation instead of in the original English. @sp @center @titlefont{pcl-cvs - the Emacs Front-End to CVS} @sp 2 -@center release 1.05 +@center release 1.05-CVS-$Name: $ @comment -release- @sp 3 @center Per Cederqvist @sp 3 -@center last updated 31 May 1993 +@center last updated 20 Nov 1995 @comment -date- @comment The following two commands start the copyright page @@ -97,19 +99,19 @@ Free Software Foundation instead of in the original English. @comment The real text starts here @comment ================================================================ -@node Top, Copying, (dir), (dir) -@comment node-name, next, previous, up +@node Top, Installation, (dir), (dir) +@comment node-name, next, previous, up @ifinfo This info manual describes pcl-cvs which is a GNU Emacs front-end to -CVS. It works with CVS version 1.3. This manual is updated to release -1.05 of pcl-cvs. +CVS. It works with CVS versions 1.5 through 1.7 and newer, and possibly +CVS-1.3 and CVS-1.4A2. This manual is updated to release +1.05-CVS-$Name: $ of pcl-cvs. @end ifinfo @comment -release- @menu -* Copying:: GNU General Public License * Installation:: How to install pcl-cvs on your system. * About pcl-cvs:: Authors and ftp sites. @@ -120,6 +122,7 @@ CVS. It works with CVS version 1.3. This manual is updated to release * Customization:: How you can tailor pcl-cvs to suit your needs. * Future enhancements:: Future enhancements of pcl-cvs. * Bugs:: Bugs (known and unknown). +* COPYING:: GNU General Public License * Function and Variable Index:: List of functions and variables. * Concept Index:: List of concepts. * Key Index:: List of keystrokes. @@ -150,7 +153,7 @@ Commands * Marking files:: How to mark files that other commands will later operate on. * Committing changes:: Checking in your modifications to the - CVS repository. + CVS repository. * Editing files:: Loading files into Emacs. * Getting info about files:: Display the log and status of files. * Adding and removing files:: Adding and removing files @@ -158,404 +161,16 @@ Commands * Removing handled entries:: Uninteresting lines can easily be removed. * Ignoring files:: Telling CVS to ignore generated files. * Viewing differences:: Commands to @samp{diff} different versions. -* Emerge:: +* Invoking Ediff:: Running @samp{ediff} from @samp{*cvs*} buffer. +* Invoking Emerge:: Running @samp{emerge} from @samp{*cvs*} buffer. * Reverting your buffers:: Reverting your buffers * Miscellaneous commands:: Miscellaneous commands @end menu -@node Copying, Installation, Top, Top -@unnumbered GNU GENERAL PUBLIC LICENSE -@center Version 2, June 1991 - -@display -Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. -675 Mass Ave, Cambridge, MA 02139, USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. -@end display - -@unnumberedsec Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software---to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - -@iftex -@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -@end iftex -@ifinfo -@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -@end ifinfo - -@enumerate -@item -This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The ``Program'', below, -refers to any such program or work, and a ``work based on the Program'' -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term ``modification''.) Each licensee is addressed as ``you''. - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - -@item -You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - -@item -You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - -@enumerate a -@item -You must cause the modified files to carry prominent notices -stating that you changed the files and the date of any change. - -@item -You must cause any work that you distribute or publish, that in -whole or in part contains or is derived from the Program or any -part thereof, to be licensed as a whole at no charge to all third -parties under the terms of this License. - -@item -If the modified program normally reads commands interactively -when run, you must cause it, when started running for such -interactive use in the most ordinary way, to print or display an -announcement including an appropriate copyright notice and a -notice that there is no warranty (or else, saying that you provide -a warranty) and that users may redistribute the program under -these conditions, and telling the user how to view a copy of this -License. (Exception: if the Program itself is interactive but -does not normally print such an announcement, your work based on -the Program is not required to print an announcement.) -@end enumerate - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - -@item -You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - -@enumerate a -@item -Accompany it with the complete corresponding machine-readable -source code, which must be distributed under the terms of Sections -1 and 2 above on a medium customarily used for software interchange; or, - -@item -Accompany it with a written offer, valid for at least three -years, to give any third party, for a charge no more than your -cost of physically performing source distribution, a complete -machine-readable copy of the corresponding source code, to be -distributed under the terms of Sections 1 and 2 above on a medium -customarily used for software interchange; or, - -@item -Accompany it with the information you received as to the offer -to distribute corresponding source code. (This alternative is -allowed only for noncommercial distribution and only if you -received the program in object code or executable form with such -an offer, in accord with Subsection b above.) -@end enumerate - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - -@item -You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - -@item -You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - -@item -Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - -@item -If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - -@item -If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - -@item -The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and ``any -later version'', you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - -@item -If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - -@iftex -@heading NO WARRANTY -@end iftex -@ifinfo -@center NO WARRANTY -@end ifinfo - -@item -BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. -@item -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. -@end enumerate +@node Installation, About pcl-cvs, Top, Top +@comment node-name, next, previous, up -@iftex -@heading END OF TERMS AND CONDITIONS -@end iftex -@ifinfo -@center END OF TERMS AND CONDITIONS -@end ifinfo - -@page -@unnumberedsec Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the ``copyright'' line and a pointer to where the full notice is found. - -@smallexample -@var{one line to give the program's name and a brief idea of what it does.} -Copyright (C) 19@var{yy} @var{name of author} - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -@end smallexample - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - -@smallexample -Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author} -Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -This is free software, and you are welcome to redistribute it -under certain conditions; type `show c' for details. -@end smallexample - -The hypothetical commands @samp{show w} and @samp{show c} should show -the appropriate parts of the General Public License. Of course, the -commands you use may be called something other than @samp{show w} and -@samp{show c}; they could even be mouse-clicks or menu items---whatever -suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a ``copyright disclaimer'' for the program, if -necessary. Here is a sample; alter the names: - -@example -Yoyodyne, Inc., hereby disclaims all copyright interest in the program -`Gnomovision' (which makes passes at compilers) written by James Hacker. - -@var{signature of Ty Coon}, 1 April 1989 -Ty Coon, President of Vice -@end example - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. - -@node Installation, About pcl-cvs, Copying, Top -@comment node-name, next, previous, up @chapter Installation @cindex Installation @@ -574,6 +189,7 @@ directory. about pcl-cvs. @end menu + @node Pcl-cvs installation, On-line manual installation, Installation, Installation @comment node-name, next, previous, up @section Installation of the pcl-cvs program @@ -581,20 +197,27 @@ directory. @enumerate @item -Edit the file @file{Makefile} to reflect the situation at your site. -The only things you have to change is the definition of @code{lispdir} -and @code{infodir}. The elisp files will be copied to @code{lispdir}, -and the info file to @code{infodir}. +Possibly edit the file @file{Makefile} to reflect the situation at your +site. We say "possibly" because the version of pcl-cvs included with +CVS uses a configuration mechanism integrated with the overall +mechanisms used by the CVS build and install procedures. Thus the file +@code{Makefile} will be generated automatically from the file +@code{Makefile.in}, and it should not be necessary to edit it further. + +If you do have to edit the @file{Makefile}, the only things you have to +change is the definition of @code{lispdir} and @code{infodir}. The +elisp files will be copied to @code{lispdir}, and the info file(s) to +@code{infodir}. @item Configure pcl-cvs.el -There are a couple of paths that you have to check to make sure that -they match you system. They appear early in the file pcl-cvs.el. +There are a couple of pathnames that you have to check to make sure that +they match your system. They appear early in the file +@samp{pcl-cvs.el}. @strong{NOTE:} If your system is running emacs 18.57 or earlier you MUST uncomment the line that says: - @example (setq delete-exited-processes nil) @end example @@ -605,34 +228,38 @@ in emacs that causes it to dump core. The bug was fixed in emacs @item Release 1.05 and later of pcl-cvs requires parts of the Elib library, -version 0.07 or later. Elib is available via anonymous ftp from -prep.ai.mit.edu in @file{pub/gnu/elib-0.07.tar.z}, and from a lot of -other sites that mirrors prep. Get Elib, and install it, before +version 1.0 or later. Elib is available via anonymous ftp from +prep.ai.mit.edu in @file{pub/gnu/elib-1.0.tar.gz}, and from a lot of +other sites that mirror prep. Get Elib, and install it, before proceeding. +@strong{NOTE:} The version of pcl-cvs included with CVS includes a copy +of Elib in the sub-directory @file{elib} under the +@file{contrib/pcl-cvs} directory. + @item Type @samp{make install} in the source directory. This will -byte-compile all @file{.el} files and copy both the @file{.el} and the -@file{.elc} into the directory you specified in step 1. +byte-compile all @file{.el} files and copy the @file{*.elc} files into +the directory you specified in step 1. -If you don't want to install the @file{.el} files but only the -@file{.elc} files (the byte-compiled files), you can type `@samp{make -install_elc}' instead of `@samp{make install}'. +If you want to install the @file{*.el} files too, you can type +@samp{make install-el} to do so. If you only want to create the compiled elisp files, but don't want to -install them, you can type @samp{make elcfiles} instead. This is what -happens if you only type @samp{make} without parameters. +install them, you can type @samp{make} without parameters. @item Edit the file @file{default.el} in your emacs lisp directory (usually -@file{/usr/gnu/emacs/lisp} or something similar) and enter the contents -of the file @file{pcl-cvs-startup.el} into it. It contains a couple of -@code{auto-load}s that facilitates the use of pcl-cvs. +@file{/usr/gnu/lib/emacs/site-lisp} or something similar) and enter the +contents of the file @file{pcl-cvs-startup.el} into it. It contains a +couple of @code{auto-load}s that facilitates the use of pcl-cvs. @end enumerate + @node On-line manual installation, Typeset manual installation, Pcl-cvs installation, Installation @comment node-name, next, previous, up + @section Installation of the on-line manual. @cindex Manual installation (on-line) @cindex Installation of on-line manual @@ -642,30 +269,31 @@ of the file @file{pcl-cvs-startup.el} into it. It contains a couple of @enumerate @item -Create the info file @file{pcl-cvs} from @file{pcl-cvs.texinfo} by -typing @samp{make info}. If you don't have the program @samp{makeinfo} -you can get it by anonymous ftp from e.g. @samp{ftp.gnu.ai.mit.edu} as -@file{pub/gnu/texinfo-2.14.tar.Z} (there might be a newer version there -when you read this), or you could use the preformatted info file -@file{pcl-cvs.info} that is included in the distribution (type -@samp{cp pcl-cvs.info pcl-cvs}).@refill +Create the info file(s) @file{pcl-cvs.info*} from @file{pcl-cvs.texinfo} +by typing @samp{make info}. If you don't have the program +@samp{makeinfo} you can get it by anonymous ftp from +e.g. @samp{prep.ai.mit.edu} as @file{pub/gnu/texinfo-3.7.tar.gz} (there +might be a newer version there when you read this).@refill @item -Move the info file @file{pcl-cvs} to your standard info directory. -This might be called something like @file{/usr/gnu/emacs/info}.@refill +Install the info file(s) @file{pcl-cvs.info*} into your standard +@file{info} directory. You should be able to do this by typing +@samp{make install-info}.@refill @item -Edit the file @file{dir} in the info directory and enter one line to -contain a pointer to the info file @file{pcl-cvs}. The line can, for -instance, look like this:@refill +Edit the file @file{dir} in the @file{info} directory and enter one line +to contain a pointer to the info file(s) @file{pcl-cvs.info*}. The line +can, for instance, look like this:@refill @example -* Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS. +* Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS. @end example @end enumerate + @node Typeset manual installation, , On-line manual installation, Installation @comment node-name, next, previous, up + @section How to make typeset documentation from pcl-cvs.texinfo @cindex Manual installation (typeset) @cindex Installation of typeset manual @@ -690,21 +318,26 @@ you can use. @end enumerate + @node About pcl-cvs, Getting started, Installation, Top @comment node-name, next, previous, up + @chapter About pcl-cvs @cindex About pcl-cvs -Pcl-cvs is a front-end to CVS version 1.3. It integrates the most -frequently used CVS commands into emacs. +Pcl-cvs is a front-end to CVS versions 1.5 through 1.7 and newer; and +possibly verison 1.3 and 1.4A2. It integrates the most frequently used +CVS commands into an emacs interface. @menu * Contributors:: Contributors to pcl-cvs. * Archives:: Where can I get a copy of Pcl-Cvs? @end menu + @node Contributors, Archives, About pcl-cvs, About pcl-cvs @comment node-name, next, previous, up + @section Contributors to pcl-cvs @cindex Contributors @cindex Authors @@ -739,15 +372,33 @@ Jamie Zawinski (@samp{jwz@@lucid.com}) contributed @file{pcl-cvs-lucid.el}. @item -Leif Lonnblad contributed RCVS support. +Leif Lonnblad contributed RCVS support. (Since superceded by the new +remote CVS support.) + +@item +Jim Blandy (@samp{jimb@@cyclic.com}) contributed hooks to automatically +guess CVS log entries from ChangeLog contents; and initial support of +the new Cygnus / Cyclic remote CVS; as well as various sundry bug fixes +and cleanups. + +@item +Jim Kingdon (@samp{kingdon@@cyclic.com}) contributed lots of fixes to +the build and install procedure. + +@item +Greg A. Woods (@samp{woods@@planix.com}) contributed code to implement +the use of per-file diff buffers; and vendor join diffs with emerge and +ediff; as well as various an sundry bug fixes and cleanups. @end itemize Apart from these, a lot of people have send me suggestions, ideas, requests, bug reports and encouragement. Thanks a lot! Without your there would be no new releases of pcl-cvs. + @node Archives, , Contributors, About pcl-cvs @comment node-name, next, previous, up + @section Where can I get pcl-cvs? @cindex Sites @cindex Archives @@ -755,7 +406,9 @@ there would be no new releases of pcl-cvs. @cindex Getting pcl-cvs @cindex Email archives -The latest release of pcl-cvs can be fetched via anonymous ftp from +The current release of pcl-cvs is included in CVS-1.7. + +The author's release of pcl-cvs can be fetched via anonymous ftp from @code{ftp.lysator.liu.se}, (IP no. 130.236.254.1) in the directory @code{pub/emacs}. If you don't live in Scandinavia you should probably check with archie to see if there is a site closer to you that archives @@ -765,8 +418,10 @@ New releases will be announced to appropriate newsgroups. If you send your email address to me I will add you to my list of people to mail when I make a new release. + @node Getting started, Buffer contents, About pcl-cvs, Top @comment node-name, next, previous, up + @chapter Getting started @cindex Introduction @cindex Example run @@ -797,7 +452,7 @@ files that have been checked out from a CVS archive.) The output from @samp{*cvs*}. It might look something like this: @example -PCL-CVS release 1.05. +PCL-CVS release 1.05-CVS-$Name: $. @comment -release- In directory /users/ceder/FOO/test: @@ -811,7 +466,7 @@ In directory /users/ceder/FOO/test/sub: ---------- End ----- @end example -In this example the three files (@file{bar}, @file{file.txt} and +In this example the two files (@file{bar}, @file{file.txt}, and @file{newer}) that are marked with @samp{Updated} have been copied from the CVS repository to @file{/users/ceder/FOO/test/} since someone else have checked in newer versions of them. Two files (@file{namechange} @@ -821,7 +476,7 @@ checked in. You can move the cursor up and down in the buffer with @kbd{C-n} and @kbd{C-p} or @kbd{n} and @kbd{p}. If you press @kbd{c} on one of the @samp{Modified} files that file will be checked in to the CVS -repository. @xref{Committing changes}. You can press @kbd{x} to get rid +repository. @xref{Committing changes}. You can press @kbd{x} to get rid of the "uninteresting" files that have only been @samp{Updated} (and don't require any further action from you).@refill @@ -830,8 +485,10 @@ base version that you started from, and you can get the output from @samp{cvs log} and @samp{cvs status} on the listed files simply by pressing a key (@pxref{Getting info about files}). + @node Buffer contents, Commands, Getting started, Top @comment node-name, next, previous, up + @chapter Buffer contents @cindex Buffer contents @@ -842,7 +499,8 @@ The display contains four columns. They contain, from left to right: An asterisk when the file is @dfn{marked} (@pxref{Selected files}).@refill @item -The status of the file. See @xref{File status}, for more information.@refill +The status of the file. See @xref{File status}, for more +information.@refill @item A "need to be checked in"-marker (@samp{ci}). @item @@ -854,11 +512,14 @@ The file name. * Selected files:: How selection works. @end menu + @node File status, Selected files, Buffer contents, Buffer contents @comment node-name, next, previous, up + @section File status @cindex File status @cindex Updated (file status) +@cindex Patched (file status) @cindex Modified (file status) @cindex Merged (file status) @cindex Conflict (file status) @@ -874,12 +535,20 @@ The file name. The @samp{file status} field can have the following values: @table @samp + @item Updated The file was brought up to date with respect to the repository. This is done for any file that exists in the repository but not in your source, and for files that you haven't changed but are not the most recent versions available in the repository.@refill +@item Patched +The file was brought up to date with respect to a remote repository by +way of fetching and applying a patch to the file in your source. This +is done for any file that exists in a remote repository and in your +source; of which you haven't changed locally but is not the most recent +version available in the remote repository.@refill + @item Modified The file is modified in your working directory, and there was no modification to the same file in the repository.@refill @@ -938,14 +607,16 @@ file (see @pxref{Adding and removing files}).@refill For some reason CVS does not like the file @var{file}. Rename or remove it.@refill -@item This repository is missing! Remove this dir manually. +@item This repository is missing! Remove this dir manually. It is impossible to remove a directory in the CVS repository in a clean way. Someone have tried to remove one, and CVS gets confused. Remove your copy of the directory.@refill @end table + @node Selected files, , File status, Buffer contents @comment node-name, next, previous, up + @section Selected files @cindex Selected files @cindex Marked files @@ -971,8 +642,10 @@ it, it is quite powerful. @xref{Marking files} tells how you mark and unmark files. + @node Commands, Customization, Buffer contents, Top @comment node-name, next, previous, up + @chapter Commands @iftex @@ -989,7 +662,7 @@ you can use in pcl-cvs. They are grouped together by type. * Marking files:: How to mark files that other commands will later operate on. * Committing changes:: Checking in your modifications to the - CVS repository. + CVS repository. * Editing files:: Loading files into Emacs. * Getting info about files:: Display the log and status of files. * Adding and removing files:: Adding and removing files @@ -997,13 +670,16 @@ you can use in pcl-cvs. They are grouped together by type. * Removing handled entries:: Uninteresting lines can easily be removed. * Ignoring files:: Telling CVS to ignore generated files. * Viewing differences:: Commands to @samp{diff} different versions. -* Emerge:: +* Invoking Ediff:: Running @samp{ediff} from @samp{*cvs*} buffer. +* Invoking Emerge:: Running @samp{emerge} from @samp{*cvs*} buffer. * Reverting your buffers:: Reverting your buffers * Miscellaneous commands:: Miscellaneous commands @end menu + @node Updating the directory, Movement commands, Commands, Commands @comment node-name, next, previous, up + @section Updating the directory @findex cvs-update @findex cvs-mode-update-no-prompt @@ -1042,9 +718,17 @@ This will run @samp{cvs update} again. It will always use the same buffer that was used with the previous @samp{cvs update}. Give a prefix argument to avoid descending into subdirectories. This runs the command @samp{cvs-mode-update-no-prompt}.@refill + +@item G +This will run @samp{cvs update} and prompt for a new directory to +update. This runs the command @samp{cvs-update}.@refill + @end table + + @node Movement commands, Marking files, Updating the directory, Commands @comment node-name, next, previous, up + @section Movement Commands @cindex Movement Commands @findex cookie-next-cookie @@ -1073,8 +757,10 @@ These keys move one file backward, towards the beginning of the buffer (@code{cookie-previous-cookie}). @end table + @node Marking files, Committing changes, Movement commands, Commands @comment node-name, next, previous, up + @section Marking files @cindex Selecting files (commands to mark files) @cindex Marking files @@ -1099,7 +785,7 @@ positioned on a directory all files in that directory will be marked. (@code{cvs-mode-mark}). @item u -Unmark the file that the cursor is positioned on. If the cursor is on a +Unmark the file that the cursor is positioned on. If the cursor is on a directory, all files in that directory will be unmarked. (@code{cvs-mode-unmark}).@refill @@ -1114,13 +800,17 @@ Unmark the file on the previous line, and move point to that line (@code{cvs-mode-unmark-up}). @end table + @node Committing changes, Editing files, Marking files, Commands @comment node-name, next, previous, up + @section Committing changes @cindex Committing changes @cindex Ci @findex cvs-mode-commit +@findex cvs-mode-changelog-commit @kindex c - commit files +@kindex C - commit files with ChangeLog message @vindex cvs-erase-input-buffer (variable) @vindex cvs-auto-revert-after-commit (variable) @cindex Commit buffer @@ -1129,6 +819,7 @@ Unmark the file on the previous line, and move point to that line @cindex Reverting buffers after commit @table @kbd + @item c All files that have a "need to be checked in"-marker (@pxref{Buffer contents}) can be checked in with the @kbd{c} command. It checks in all @@ -1152,15 +843,43 @@ If you are editing the files in your emacs an automatic @samp{revert-buffer} will be performed. (If the file contains @samp{$@asis{Id}$} keywords @samp{cvs commit} will write a new file with the new values substituted. The auto-revert makes sure that you get -them into your buffer). The revert will not occur if you have modified +them into your buffer). The revert will not occur if you have modified your buffer, or if @samp{cvs-auto-revert-after-commit} is set to @samp{nil}.@refill + +@item C +This is just like @samp{cvs-mode-commit}, except that it tries to +provide appropriate default log messages by looking at the +@samp{ChangeLog}s in the current directory. The idea is to write your +ChangeLog entries first, and then use this command to commit your +changes. Pressing @kbd{C} causes @code{cvs-mode-changelog-commit} to be +run.@refill + +To select default log text, pcl-cvs: +@itemize @minus +@item +finds the ChangeLogs for the files to be checked in; +@item +verifies that the top entry in the ChangeLog is on the current date and +by the current user; if not, no default text is provided; +@item +search the ChangeLog entry for paragraphs containing the names of the +files we're checking in; and finally +@item +uses those paragraphs as the default log text in the +@samp{*cvs-commit-message*} buffer. +@end itemize + +You can then commit the @samp{ChangeLog} file once per day without any +log message.@refill + @end table + @node Editing files, Getting info about files, Committing changes, Commands @comment node-name, next, previous, up -@section Editing files +@section Editing files @cindex Editing files @cindex Finding files @cindex Loading files @@ -1197,8 +916,10 @@ directory of the file the cursor points to. (@code{cvs-mode-add-change-log-entry-other-window}).@refill @end table + @node Getting info about files, Adding and removing files, Editing files, Commands @comment node-name, next, previous, up + @section Getting info about files @cindex Status (cvs command) @cindex Log (RCS/cvs command) @@ -1221,8 +942,10 @@ Run @samp{cvs status} on all selected files, and show the result in a temporary buffer (@code{cvs-mode-status}). @end table + @node Adding and removing files, Undoing changes, Getting info about files, Commands @comment node-name, next, previous, up + @section Adding and removing files @cindex Adding files @cindex Removing files @@ -1265,8 +988,10 @@ disappear from the buffer. Otherwise their status will change to The command that is run is @code{cvs-mode-remove-file}. @end table + @node Undoing changes, Removing handled entries, Adding and removing files, Commands @comment node-name, next, previous, up + @section Undoing changes @cindex Undo changes @cindex Flush changes @@ -1281,8 +1006,10 @@ by removing your working copy of the file and then getting the latest version from the repository (@code{cvs-mode-undo-local-changes}. @end table + @node Removing handled entries, Ignoring files, Undoing changes, Commands @comment node-name, next, previous, up + @section Removing handled entries @cindex Expunging uninteresting entries @cindex Uninteresting entries, getting rid of them @@ -1293,7 +1020,6 @@ version from the repository (@code{cvs-mode-undo-local-changes}. @kindex C-k - remove selected entries @findex cvs-mode-remove-handled @findex cvs-mode-acknowledge -@findex cvs-mode-ignore @table @kbd @item x @@ -1313,9 +1039,13 @@ This command can be used for lines that @samp{cvs-mode-remove-handled} would not delete, but that you want to delete (@code{cvs-mode-acknowledge}). @end table + @node Ignoring files, Viewing differences, Removing handled entries, Commands @comment node-name, next, previous, up + @section Ignoring files +@kindex i - ignoring files +@findex cvs-mode-ignore @table @kbd @item i @@ -1329,10 +1059,14 @@ but you could ignore it also if you like it better that way. This runs @code{cvs-mode-ignore}. @end table -@node Viewing differences, Emerge, Ignoring files, Commands + +@node Viewing differences, Invoking Ediff, Ignoring files, Commands @comment node-name, next, previous, up + @section Viewing differences @cindex Diff +@cindex Ediff +@cindex Invoking ediff @cindex Conflicts, how to resolve them @cindex Viewing differences @kindex d - run @samp{cvs diff} @@ -1368,18 +1102,79 @@ prefix argument is given (but not both) any marked files will not be considered to be selected. (@code{cvs-mode-diff-backup}).@refill @end table -@node Emerge, Reverting your buffers, Viewing differences, Commands + +@node Invoking Ediff, Invoking Emerge, Viewing differences, Commands +@comment node-name, next, previous, up + +@section Running ediff +@cindex Ediff +@cindex Invoking ediff +@cindex Viewing differences +@cindex Conflicts, resolving +@cindex Resolving conflicts +@kindex e - invoke @samp{ediff} +@findex cvs-mode-ediff +@findex run-ediff-from-cvs-buffer +@findex cvs-old-ediff-interface + +@table @kbd +@item e +This command works +slightly different depending on the version of @samp{ediff} and the file +status.@refill + +With modern versions of @samp{ediff}, this command invokes +@samp{run-ediff-from-cvs-buffer} on one file.@refill + +@strong{Note:} When the file status is @samp{Merged} or @samp{Conflict}, +CVS has already performed a merge. The resulting file is not used in +any way if you use this command. If you use the @kbd{q} command inside +@samp{ediff} (to successfully terminate a merge) the file that CVS +created will be overwritten.@refill + +Older versions of @samp{ediff} use an interface similar to +@samp{emerge}. The function @samp{cvs-old-ediff-interface} is invoked +if the version of @samp{ediff} you have doesn't support +@samp{run-ediff-from-cvs-buffer}. These older versions do not support +merging of revisions.@refill + +@table @asis +@item @samp{Modified} +Run @samp{ediff-files} with your working file as file A, and the latest +revision in the repository as file B. + +@item @samp{Merged} +@itemx @samp{Conflict} +Run @samp{ediff-files3} with your working file (as it was prior to your +invocation of @samp{cvs-update}) as file A, the latest revision in the +repository as file B, and the revision that you based your local +modifications on as ancestor. + +@item @samp{Updated} +@itemx @samp{Patched} +Run @samp{ediff-files} with your working file as file A, and a given +revision in the repository as file B. You are prompted for the revision +to ediff against, and you may specify either a tag name or a numerical +revision number (@pxref{Getting info about files}). +@end table + +@end table + +@node Invoking Emerge, Reverting your buffers, Invoking Ediff, Commands @comment node-name, next, previous, up + @section Running emerge @cindex Emerge +@cindex Ediff +@cindex Viewing differences @cindex Invoking emerge @cindex Conflicts, resolving @cindex Resolving conflicts -@kindex e - invoke @samp{emerge} +@kindex E - invoke @samp{emerge} @findex cvs-mode-emerge @table @kbd -@item e +@item E Invoke @samp{emerge} on one file. This command works slightly different depending on the file status. @@ -1396,14 +1191,18 @@ revision in the repository as file B, and the revision that you based your local modifications on as ancestor. @end table -@strong{Note:} CVS has already performed a merge. The resulting file is -not used in any way if you use this command. If you use the @kbd{q} -command inside @samp{emerge} (to successfully terminate the merge) the -file that CVS created will be overwritten. +@strong{Note:} When the file status is @samp{Merged} or @samp{Conflict}, +CVS has already performed a merge. The resulting file is not used in +any way if you use this command. If you use the @kbd{q} command inside +@samp{emerge} (to successfully terminate the merge) the file that CVS +created will be overwritten. + @end table -@node Reverting your buffers, Miscellaneous commands, Emerge, Commands + +@node Reverting your buffers, Miscellaneous commands, Invoking Emerge, Commands @comment node-name, next, previous, up + @section Reverting your buffers @findex cvs-mode-revert-updated-buffers @kindex R - revert buffers @@ -1422,11 +1221,13 @@ are reverted from the disk. Any other files are ignored. Only files that you were already editing are read.@refill An error is signalled if you have modified the buffer since it was last -changed. (@code{cvs-mode-revert-updated-buffers}).@refill +changed. (@code{cvs-mode-revert-updated-buffers}).@refill @end table + @node Miscellaneous commands, , Reverting your buffers, Commands @comment node-name, next, previous, up + @section Miscellaneous commands @findex cvs-byte-compile-files @cindex Recompiling elisp files @@ -1451,12 +1252,14 @@ you so. You should wait a while before using this command in case someone else is running a cvs command. @item q -Bury the *cvs* buffer. (@code{bury-buffer}). +Bury the *cvs* buffer. (@code{bury-buffer}). @end table + @node Customization, Future enhancements, Commands, Top @comment node-name, next, previous, up + @chapter Customization @vindex cvs-erase-input-buffer (variable) @vindex cvs-inhibit-copyright-message (variable) @@ -1539,7 +1342,7 @@ entries}.@refill @item cvs-auto-revert-after-commit If this variable is set to any non-@samp{nil} value any buffers you have that visit a file that is committed will be automatically reverted. -This variable is default @samp{t}. @xref{Committing changes}.@refill +This variable is default @samp{t}. @xref{Committing changes}.@refill @item cvs-update-prog-output-skip-regexp The @samp{-u} flag in the @file{modules} file can be used to run a command @@ -1551,7 +1354,7 @@ outputs @emph{anything} to @samp{stderr}. @item cvs-cvsroot This variable can be set to override @samp{CVSROOT}. It should be a -string. If it is set then everytime a cvs command is run it will be +string. If it is set then everytime a cvs command is run it will be called as @samp{cvs -d @var{cvs-cvsroot}@dots{}} This can be useful if your site has several repositories. @@ -1576,8 +1379,11 @@ If this variable is set to any non-@samp{nil} value the default. @end table + + @node Future enhancements, Bugs, Customization, Top @comment node-name, next, previous, up + @chapter Future enhancements @cindex Enhancements @@ -1662,15 +1468,17 @@ that I will write it, but I will at least try to coordinate the efforts of making a good Emacs front end to CVS. See @xref{Bugs} for information about how to reach me.@refill -So far, I have written most of pcl-cvs in my all-to-rare spare time. If +So far, I have written most of pcl-cvs in my all-to-rare spare time. If you want pcl-cvs to be developed faster you can write a contract with Signum Support to do the extension. You can reach Signum Support by email to @samp{info@@signum.se} or via mail to Signum Support AB, Box -2044, S-580 02 Linkoping, Sweden. Phone: +46 (0) 13 - 21 46 00. Fax: +46 -(0) 13 - 21 47 00. +2044, S-580 02 Linkoping, Sweden. Phone: +46 (0) 13 - 21 46 00. Fax: ++46 (0) 13 - 21 47 00. -@node Bugs, Function and Variable Index, Future enhancements, Top + +@node Bugs, COPYING, Future enhancements, Top @comment node-name, next, previous, up + @chapter Bugs (known and unknown) @cindex Reporting bugs and ideas @cindex Bugs, how to report them @@ -1721,20 +1529,33 @@ bug report that you can mail to me. It should do something more civilized. @end table -@node Function and Variable Index, Concept Index, Bugs, Top + +@node COPYING, Function and Variable Index, Bugs, Top +@comment node-name, next, previous, up + +@appendix GNU GENERAL PUBLIC LICENSE +@c @include gpl.texinfo + + +@node Function and Variable Index, Concept Index, COPYING, Top @comment node-name, next, previous, up + @unnumbered Function and Variable Index @printindex fn + @node Concept Index, Key Index, Function and Variable Index, Top @comment node-name, next, previous, up + @unnumbered Concept Index @printindex cp + @node Key Index, , Concept Index, Top @comment node-name, next, previous, up + @unnumbered Key Index @printindex ky diff --git a/gnu/usr.bin/cvs/cvsinit.sh b/gnu/usr.bin/cvs/cvsinit.sh index cda042d8fa8..f8c933e3974 100644 --- a/gnu/usr.bin/cvs/cvsinit.sh +++ b/gnu/usr.bin/cvs/cvsinit.sh @@ -1,14 +1,15 @@ #! /bin/sh : # +#ident "@(#)cvs:$Name: $:$Id: cvsinit.sh,v 1.1.1.2 1996/01/30 00:17:16 tholo Exp $" # Copyright (c) 1992, Brian Berliner # # 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. -# -# $CVSid: @(#)cvsinit.sh 1.1 94/10/22 $ -# -# This script should be run once to help you setup your site for CVS. + +# This script should be run for each repository you create to help you +# setup your site for CVS. You may also run it to update existing +# repositories if you install a new version of CVS. # this line is edited by Makefile when creating cvsinit.inst CVSLIB="xLIBDIRx" @@ -33,7 +34,8 @@ if [ "x$CVSROOT" = x ]; then echo "plenty of free space." echo "" echo "Please enter the full path for your CVSROOT source repository:" - read CVSROOT + read CVSROOT junk + unset junk remind_cvsroot=yes else remind_cvsroot=no @@ -72,10 +74,13 @@ if [ ! -d $CVSROOT/CVSROOT ]; then exit 1 fi -# Create the special *info files within $CVSROOT/CVSROOT +# Create the special control files and templates within $CVSROOT/CVSROOT + +EXAMPLES="checkoutlist commitinfo cvswrappers editinfo loginfo modules +rcsinfo rcstemplate taginfo wrap unwrap notify" -for info in modules loginfo commitinfo rcsinfo editinfo rcstemplate \ - checkoutlist; do +NEWSAMPLE=false +for info in $EXAMPLES; do if [ -f $CVSROOT/CVSROOT/${info},v ]; then if [ ! -f $CVSROOT/CVSROOT/$info ]; then echo "Checking out $CVSROOT/CVSROOT/$info" @@ -83,42 +88,27 @@ for info in modules loginfo commitinfo rcsinfo editinfo rcstemplate \ (cd $CVSROOT/CVSROOT; co -q $info) fi else + NEWSAMPLE=true if [ -f $CVSROOT/CVSROOT/$info ]; then echo "Checking in $CVSROOT/CVSROOT/${info},v" echo " from $CVSROOT/CVSROOT/$info..." else - echo "Creating a simple $CVSROOT/CVSROOT/$info file..." + echo "Creating a sample $CVSROOT/CVSROOT/$info file..." case $info in modules) sed -n -e '/END_REQUIRED_CONTENT/q' \ -e p $CVSLIB/examples/modules > $CVSROOT/CVSROOT/modules ;; - loginfo) - # try to find perl; use fancy log script if we can - for perlpath in `echo $PATH | sed -e 's/:/ /g'` x; do - if [ -f $perlpath/perl ]; then - echo "#!$perlpath/perl" > $CVSROOT/CVSROOT/log - cat $CVSLIB/contrib/log >> $CVSROOT/CVSROOT/log - chmod 755 $CVSROOT/CVSROOT/log - cp $CVSLIB/examples/loginfo $CVSROOT/CVSROOT/loginfo - break - fi - done - if [ $perlpath = x ]; then - # we did not find perl, so make a simple loginfo file - grep '^#' $CVSLIB/examples/loginfo \ - > $CVSROOT/CVSROOT/loginfo - cat >> $CVSROOT/CVSROOT/loginfo <<"END_HERE_DOC" -DEFAULT (echo ""; echo $USER; date; cat) >> $CVSROOT/CVSROOT/commitlog -END_HERE_DOC - fi - ;; rcstemplate) cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info ;; + wrap|unwrap) + cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info + chmod +x $CVSROOT/CVSROOT/$info + ;; *) - sed -e 's/^\([^#]\)/#\1/' $CVSLIB/examples/$info \ - > $CVSROOT/CVSROOT/$info + # comment out everything in all the other examples.... + sed -e 's/^\([^#]\)/#\1/' $CVSLIB/examples/$info > $CVSROOT/CVSROOT/$info ;; esac fi @@ -126,6 +116,12 @@ END_HERE_DOC fi done +if $NEWSAMPLE ; then + echo "NOTE: You may wish to check out the CVSROOT module and edit any new" + echo "configuration files to match your local requirements." + echo "" +fi + # check to see if there are any references to the old CVSROOT.adm directory if grep CVSROOT.adm $CVSROOT/CVSROOT/modules >/dev/null 2>&1; then echo "Warning: your $CVSROOT/CVSROOT/modules file still" @@ -135,12 +131,14 @@ if grep CVSROOT.adm $CVSROOT/CVSROOT/modules >/dev/null 2>&1; then fi # These files are generated from the contrib files. -# FIXME: Is it really wise to overwrite local changes like this? -# Shouldn't anything which is really supposed to be upgraded with new -# versions of CVS be in the CVS binary, not the repository? -# Shouldn't we at *least* version control the file so they can get -# back their editted version after we clobber it? -for contrib in commit_prep log_accum cln_hist; do +# FIXME: Is it really wise to overwrite possible local changes like this? +# Normal folks will keep these up to date by modifying the source in +# their CVS module and re-installing CVS, but is everyone OK with that? +# +# +CONTRIBS="log commit_prep log_accum cln_hist" +# +for contrib in $CONTRIBS; do echo "Copying the new version of '${contrib}'" echo " to $CVSROOT/CVSROOT for you..." cp $CVSLIB/contrib/$contrib $CVSROOT/CVSROOT/$contrib @@ -152,6 +150,8 @@ done if [ ! -f $CVSROOT/CVSROOT/history ]; then echo "Enabling CVS history logging..." touch $CVSROOT/CVSROOT/history + chmod g+w $CVSROOT/CVSROOT/history + echo "(Remove $CVSROOT/CVSROOT/history to disable.)" fi # finish up by running mkmodules diff --git a/gnu/usr.bin/cvs/cvsnt.mak b/gnu/usr.bin/cvs/cvsnt.mak index 78e9ead32ed..ef7ca67209d 100644 --- a/gnu/usr.bin/cvs/cvsnt.mak +++ b/gnu/usr.bin/cvs/cvsnt.mak @@ -42,7 +42,7 @@ RSC=rc.exe OUTDIR=.\WinRel INTDIR=.\WinRel -ALL : .\WinRel\cvs.exe .\WinRel\cvsnt.bsc +ALL : $(OUTDIR)/cvs.exe $(OUTDIR)/cvsnt.bsc $(OUTDIR) : if not exist $(OUTDIR)/nul mkdir $(OUTDIR) @@ -61,74 +61,79 @@ BSC32=bscmake.exe # ADD BSC32 /nologo BSC32_FLAGS=/nologo /o$(OUTDIR)/"cvsnt.bsc" BSC32_SBRS= \ - .\WinRel\subr.sbr \ - .\WinRel\admin.sbr \ - .\WinRel\server.sbr \ - .\WinRel\diff.sbr \ - .\WinRel\client.sbr \ - .\WinRel\checkout.sbr \ - .\WinRel\no_diff.sbr \ - .\WinRel\entries.sbr \ - .\WinRel\tag.sbr \ - .\WinRel\rtag.sbr \ - .\WinRel\status.sbr \ - .\WinRel\root.sbr \ - .\WinRel\myndbm.sbr \ - .\WinRel\hash.sbr \ - .\WinRel\repos.sbr \ - .\WinRel\parseinfo.sbr \ - .\WinRel\vers_ts.sbr \ - .\WinRel\checkin.sbr \ - .\WinRel\commit.sbr \ - .\WinRel\version.sbr \ - .\WinRel\cvsrc.sbr \ - .\WinRel\remove.sbr \ - .\WinRel\update.sbr \ - .\WinRel\logmsg.sbr \ - .\WinRel\classify.sbr \ - .\WinRel\history.sbr \ - .\WinRel\add.sbr \ - .\WinRel\lock.sbr \ - .\WinRel\recurse.sbr \ - .\WinRel\modules.sbr \ - .\WinRel\find_names.sbr \ - .\WinRel\rcs.sbr \ - .\WinRel\create_adm.sbr \ - .\WinRel\main.sbr \ - .\WinRel\patch.sbr \ - .\WinRel\release.sbr \ - .\WinRel\rcscmds.sbr \ - .\WinRel\import.sbr \ - .\WinRel\ignore.sbr \ - .\WinRel\log.sbr \ - .\WinRel\wrapper.sbr \ - .\WinRel\getwd.sbr \ - .\WinRel\error.sbr \ - .\WinRel\sighandle.sbr \ - .\WinRel\getopt.sbr \ - .\WinRel\argmatch.sbr \ - .\WinRel\md5.sbr \ - .\WinRel\yesno.sbr \ - .\WinRel\getopt1.sbr \ - .\WinRel\valloc.sbr \ - .\WinRel\xgetwd.sbr \ - .\WinRel\regex.sbr \ - .\WinRel\fnmatch.sbr \ - .\WinRel\getdate.sbr \ - ".\WinRel\save-cwd.sbr" \ - .\WinRel\mkdir.sbr \ - .\WinRel\run.sbr \ - .\WinRel\pwd.sbr \ - .\WinRel\filesubr.sbr \ - .\WinRel\win32.sbr \ - .\WinRel\waitpid.sbr \ - .\WinRel\ndir.sbr \ - .\WinRel\strippath.sbr \ - .\WinRel\stripslash.sbr \ - .\WinRel\rcmd.sbr \ - .\WinRel\startserver.sbr - -.\WinRel\cvsnt.bsc : $(OUTDIR) $(BSC32_SBRS) + $(INTDIR)/subr.sbr \ + $(INTDIR)/admin.sbr \ + $(INTDIR)/server.sbr \ + $(INTDIR)/diff.sbr \ + $(INTDIR)/client.sbr \ + $(INTDIR)/checkout.sbr \ + $(INTDIR)/no_diff.sbr \ + $(INTDIR)/entries.sbr \ + $(INTDIR)/tag.sbr \ + $(INTDIR)/rtag.sbr \ + $(INTDIR)/status.sbr \ + $(INTDIR)/root.sbr \ + $(INTDIR)/myndbm.sbr \ + $(INTDIR)/hash.sbr \ + $(INTDIR)/repos.sbr \ + $(INTDIR)/parseinfo.sbr \ + $(INTDIR)/vers_ts.sbr \ + $(INTDIR)/checkin.sbr \ + $(INTDIR)/commit.sbr \ + $(INTDIR)/version.sbr \ + $(INTDIR)/cvsrc.sbr \ + $(INTDIR)/remove.sbr \ + $(INTDIR)/update.sbr \ + $(INTDIR)/logmsg.sbr \ + $(INTDIR)/classify.sbr \ + $(INTDIR)/history.sbr \ + $(INTDIR)/add.sbr \ + $(INTDIR)/lock.sbr \ + $(INTDIR)/recurse.sbr \ + $(INTDIR)/modules.sbr \ + $(INTDIR)/find_names.sbr \ + $(INTDIR)/rcs.sbr \ + $(INTDIR)/create_adm.sbr \ + $(INTDIR)/main.sbr \ + $(INTDIR)/patch.sbr \ + $(INTDIR)/release.sbr \ + $(INTDIR)/rcscmds.sbr \ + $(INTDIR)/import.sbr \ + $(INTDIR)/ignore.sbr \ + $(INTDIR)/log.sbr \ + $(INTDIR)/wrapper.sbr \ + $(INTDIR)/error.sbr \ + $(INTDIR)/expand_path.sbr \ + $(INTDIR)/edit.sbr \ + $(INTDIR)/fileattr.sbr \ + $(INTDIR)/watch.sbr \ + $(INTDIR)/getwd.sbr \ + $(INTDIR)/sighandle.sbr \ + $(INTDIR)/getopt.sbr \ + $(INTDIR)/argmatch.sbr \ + $(INTDIR)/md5.sbr \ + $(INTDIR)/yesno.sbr \ + $(INTDIR)/getopt1.sbr \ + $(INTDIR)/valloc.sbr \ + $(INTDIR)/xgetwd.sbr \ + $(INTDIR)/regex.sbr \ + $(INTDIR)/fnmatch.sbr \ + $(INTDIR)/getdate.sbr \ + $(INTDIR)/"save-cwd.sbr" \ + $(INTDIR)/getline.sbr \ + $(INTDIR)/mkdir.sbr \ + $(INTDIR)/run.sbr \ + $(INTDIR)/pwd.sbr \ + $(INTDIR)/filesubr.sbr \ + $(INTDIR)/win32.sbr \ + $(INTDIR)/waitpid.sbr \ + $(INTDIR)/ndir.sbr \ + $(INTDIR)/strippath.sbr \ + $(INTDIR)/stripslash.sbr \ + $(INTDIR)/rcmd.sbr \ + $(INTDIR)/startserver.sbr + +$(OUTDIR)/cvsnt.bsc : $(OUTDIR) $(BSC32_SBRS) $(BSC32) @<< $(BSC32_FLAGS) $(BSC32_SBRS) << @@ -142,74 +147,79 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ /PDB:$(OUTDIR)/"cvsnt.pdb" /MACHINE:I386 /OUT:"WinRel/cvs.exe" DEF_FILE= LINK32_OBJS= \ - .\WinRel\subr.obj \ - .\WinRel\admin.obj \ - .\WinRel\server.obj \ - .\WinRel\diff.obj \ - .\WinRel\client.obj \ - .\WinRel\checkout.obj \ - .\WinRel\no_diff.obj \ - .\WinRel\entries.obj \ - .\WinRel\tag.obj \ - .\WinRel\rtag.obj \ - .\WinRel\status.obj \ - .\WinRel\root.obj \ - .\WinRel\myndbm.obj \ - .\WinRel\hash.obj \ - .\WinRel\repos.obj \ - .\WinRel\parseinfo.obj \ - .\WinRel\vers_ts.obj \ - .\WinRel\checkin.obj \ - .\WinRel\commit.obj \ - .\WinRel\version.obj \ - .\WinRel\cvsrc.obj \ - .\WinRel\remove.obj \ - .\WinRel\update.obj \ - .\WinRel\logmsg.obj \ - .\WinRel\classify.obj \ - .\WinRel\history.obj \ - .\WinRel\add.obj \ - .\WinRel\lock.obj \ - .\WinRel\recurse.obj \ - .\WinRel\modules.obj \ - .\WinRel\find_names.obj \ - .\WinRel\rcs.obj \ - .\WinRel\create_adm.obj \ - .\WinRel\main.obj \ - .\WinRel\patch.obj \ - .\WinRel\release.obj \ - .\WinRel\rcscmds.obj \ - .\WinRel\import.obj \ - .\WinRel\ignore.obj \ - .\WinRel\log.obj \ - .\WinRel\wrapper.obj \ - .\WinRel\getwd.obj \ - .\WinRel\error.obj \ - .\WinRel\sighandle.obj \ - .\WinRel\getopt.obj \ - .\WinRel\argmatch.obj \ - .\WinRel\md5.obj \ - .\WinRel\yesno.obj \ - .\WinRel\getopt1.obj \ - .\WinRel\valloc.obj \ - .\WinRel\xgetwd.obj \ - .\WinRel\regex.obj \ - .\WinRel\fnmatch.obj \ - .\WinRel\getdate.obj \ - ".\WinRel\save-cwd.obj" \ - .\WinRel\mkdir.obj \ - .\WinRel\run.obj \ - .\WinRel\pwd.obj \ - .\WinRel\filesubr.obj \ - .\WinRel\win32.obj \ - .\WinRel\waitpid.obj \ - .\WinRel\ndir.obj \ - .\WinRel\strippath.obj \ - .\WinRel\stripslash.obj \ - .\WinRel\rcmd.obj \ - .\WinRel\startserver.obj - -.\WinRel\cvs.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(INTDIR)/subr.obj \ + $(INTDIR)/admin.obj \ + $(INTDIR)/server.obj \ + $(INTDIR)/diff.obj \ + $(INTDIR)/client.obj \ + $(INTDIR)/checkout.obj \ + $(INTDIR)/no_diff.obj \ + $(INTDIR)/entries.obj \ + $(INTDIR)/tag.obj \ + $(INTDIR)/rtag.obj \ + $(INTDIR)/status.obj \ + $(INTDIR)/root.obj \ + $(INTDIR)/myndbm.obj \ + $(INTDIR)/hash.obj \ + $(INTDIR)/repos.obj \ + $(INTDIR)/parseinfo.obj \ + $(INTDIR)/vers_ts.obj \ + $(INTDIR)/checkin.obj \ + $(INTDIR)/commit.obj \ + $(INTDIR)/version.obj \ + $(INTDIR)/cvsrc.obj \ + $(INTDIR)/remove.obj \ + $(INTDIR)/update.obj \ + $(INTDIR)/logmsg.obj \ + $(INTDIR)/classify.obj \ + $(INTDIR)/history.obj \ + $(INTDIR)/add.obj \ + $(INTDIR)/lock.obj \ + $(INTDIR)/recurse.obj \ + $(INTDIR)/modules.obj \ + $(INTDIR)/find_names.obj \ + $(INTDIR)/rcs.obj \ + $(INTDIR)/create_adm.obj \ + $(INTDIR)/main.obj \ + $(INTDIR)/patch.obj \ + $(INTDIR)/release.obj \ + $(INTDIR)/rcscmds.obj \ + $(INTDIR)/import.obj \ + $(INTDIR)/ignore.obj \ + $(INTDIR)/log.obj \ + $(INTDIR)/wrapper.obj \ + $(INTDIR)/error.obj \ + $(INTDIR)/expand_path.obj \ + $(INTDIR)/edit.obj \ + $(INTDIR)/fileattr.obj \ + $(INTDIR)/watch.obj \ + $(INTDIR)/getwd.obj \ + $(INTDIR)/sighandle.obj \ + $(INTDIR)/getopt.obj \ + $(INTDIR)/argmatch.obj \ + $(INTDIR)/md5.obj \ + $(INTDIR)/yesno.obj \ + $(INTDIR)/getopt1.obj \ + $(INTDIR)/valloc.obj \ + $(INTDIR)/xgetwd.obj \ + $(INTDIR)/regex.obj \ + $(INTDIR)/fnmatch.obj \ + $(INTDIR)/getdate.obj \ + $(INTDIR)/"save-cwd.obj" \ + $(INTDIR)/getline.obj \ + $(INTDIR)/mkdir.obj \ + $(INTDIR)/run.obj \ + $(INTDIR)/pwd.obj \ + $(INTDIR)/filesubr.obj \ + $(INTDIR)/win32.obj \ + $(INTDIR)/waitpid.obj \ + $(INTDIR)/ndir.obj \ + $(INTDIR)/strippath.obj \ + $(INTDIR)/stripslash.obj \ + $(INTDIR)/rcmd.obj \ + $(INTDIR)/startserver.obj + +$(OUTDIR)/cvs.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << @@ -227,7 +237,7 @@ LINK32_OBJS= \ OUTDIR=.\WinDebug INTDIR=.\WinDebug -ALL : .\WinDebug\cvs.exe .\WinDebug\cvsnt.bsc +ALL : $(OUTDIR)/cvs.exe $(OUTDIR)/cvsnt.bsc $(OUTDIR) : if not exist $(OUTDIR)/nul mkdir $(OUTDIR) @@ -246,74 +256,79 @@ BSC32=bscmake.exe # ADD BSC32 /nologo BSC32_FLAGS=/nologo /o$(OUTDIR)/"cvsnt.bsc" BSC32_SBRS= \ - .\WinDebug\subr.sbr \ - .\WinDebug\admin.sbr \ - .\WinDebug\server.sbr \ - .\WinDebug\diff.sbr \ - .\WinDebug\client.sbr \ - .\WinDebug\checkout.sbr \ - .\WinDebug\no_diff.sbr \ - .\WinDebug\entries.sbr \ - .\WinDebug\tag.sbr \ - .\WinDebug\rtag.sbr \ - .\WinDebug\status.sbr \ - .\WinDebug\root.sbr \ - .\WinDebug\myndbm.sbr \ - .\WinDebug\hash.sbr \ - .\WinDebug\repos.sbr \ - .\WinDebug\parseinfo.sbr \ - .\WinDebug\vers_ts.sbr \ - .\WinDebug\checkin.sbr \ - .\WinDebug\commit.sbr \ - .\WinDebug\version.sbr \ - .\WinDebug\cvsrc.sbr \ - .\WinDebug\remove.sbr \ - .\WinDebug\update.sbr \ - .\WinDebug\logmsg.sbr \ - .\WinDebug\classify.sbr \ - .\WinDebug\history.sbr \ - .\WinDebug\add.sbr \ - .\WinDebug\lock.sbr \ - .\WinDebug\recurse.sbr \ - .\WinDebug\modules.sbr \ - .\WinDebug\find_names.sbr \ - .\WinDebug\rcs.sbr \ - .\WinDebug\create_adm.sbr \ - .\WinDebug\main.sbr \ - .\WinDebug\patch.sbr \ - .\WinDebug\release.sbr \ - .\WinDebug\rcscmds.sbr \ - .\WinDebug\import.sbr \ - .\WinDebug\ignore.sbr \ - .\WinDebug\log.sbr \ - .\WinDebug\wrapper.sbr \ - .\WinDebug\getwd.sbr \ - .\WinDebug\error.sbr \ - .\WinDebug\sighandle.sbr \ - .\WinDebug\getopt.sbr \ - .\WinDebug\argmatch.sbr \ - .\WinDebug\md5.sbr \ - .\WinDebug\yesno.sbr \ - .\WinDebug\getopt1.sbr \ - .\WinDebug\valloc.sbr \ - .\WinDebug\xgetwd.sbr \ - .\WinDebug\regex.sbr \ - .\WinDebug\fnmatch.sbr \ - .\WinDebug\getdate.sbr \ - ".\WinDebug\save-cwd.sbr" \ - .\WinDebug\mkdir.sbr \ - .\WinDebug\run.sbr \ - .\WinDebug\pwd.sbr \ - .\WinDebug\filesubr.sbr \ - .\WinDebug\win32.sbr \ - .\WinDebug\waitpid.sbr \ - .\WinDebug\ndir.sbr \ - .\WinDebug\strippath.sbr \ - .\WinDebug\stripslash.sbr \ - .\WinDebug\rcmd.sbr \ - .\WinDebug\startserver.sbr - -.\WinDebug\cvsnt.bsc : $(OUTDIR) $(BSC32_SBRS) + $(INTDIR)/subr.sbr \ + $(INTDIR)/admin.sbr \ + $(INTDIR)/server.sbr \ + $(INTDIR)/diff.sbr \ + $(INTDIR)/client.sbr \ + $(INTDIR)/checkout.sbr \ + $(INTDIR)/no_diff.sbr \ + $(INTDIR)/entries.sbr \ + $(INTDIR)/tag.sbr \ + $(INTDIR)/rtag.sbr \ + $(INTDIR)/status.sbr \ + $(INTDIR)/root.sbr \ + $(INTDIR)/myndbm.sbr \ + $(INTDIR)/hash.sbr \ + $(INTDIR)/repos.sbr \ + $(INTDIR)/parseinfo.sbr \ + $(INTDIR)/vers_ts.sbr \ + $(INTDIR)/checkin.sbr \ + $(INTDIR)/commit.sbr \ + $(INTDIR)/version.sbr \ + $(INTDIR)/cvsrc.sbr \ + $(INTDIR)/remove.sbr \ + $(INTDIR)/update.sbr \ + $(INTDIR)/logmsg.sbr \ + $(INTDIR)/classify.sbr \ + $(INTDIR)/history.sbr \ + $(INTDIR)/add.sbr \ + $(INTDIR)/lock.sbr \ + $(INTDIR)/recurse.sbr \ + $(INTDIR)/modules.sbr \ + $(INTDIR)/find_names.sbr \ + $(INTDIR)/rcs.sbr \ + $(INTDIR)/create_adm.sbr \ + $(INTDIR)/main.sbr \ + $(INTDIR)/patch.sbr \ + $(INTDIR)/release.sbr \ + $(INTDIR)/rcscmds.sbr \ + $(INTDIR)/import.sbr \ + $(INTDIR)/ignore.sbr \ + $(INTDIR)/log.sbr \ + $(INTDIR)/wrapper.sbr \ + $(INTDIR)/error.sbr \ + $(INTDIR)/expand_path.sbr \ + $(INTDIR)/edit.sbr \ + $(INTDIR)/fileattr.sbr \ + $(INTDIR)/watch.sbr \ + $(INTDIR)/getwd.sbr \ + $(INTDIR)/sighandle.sbr \ + $(INTDIR)/getopt.sbr \ + $(INTDIR)/argmatch.sbr \ + $(INTDIR)/md5.sbr \ + $(INTDIR)/yesno.sbr \ + $(INTDIR)/getopt1.sbr \ + $(INTDIR)/valloc.sbr \ + $(INTDIR)/xgetwd.sbr \ + $(INTDIR)/regex.sbr \ + $(INTDIR)/fnmatch.sbr \ + $(INTDIR)/getdate.sbr \ + $(INTDIR)/"save-cwd.sbr" \ + $(INTDIR)/getline.sbr \ + $(INTDIR)/mkdir.sbr \ + $(INTDIR)/run.sbr \ + $(INTDIR)/pwd.sbr \ + $(INTDIR)/filesubr.sbr \ + $(INTDIR)/win32.sbr \ + $(INTDIR)/waitpid.sbr \ + $(INTDIR)/ndir.sbr \ + $(INTDIR)/strippath.sbr \ + $(INTDIR)/stripslash.sbr \ + $(INTDIR)/rcmd.sbr \ + $(INTDIR)/startserver.sbr + +$(OUTDIR)/cvsnt.bsc : $(OUTDIR) $(BSC32_SBRS) $(BSC32) @<< $(BSC32_FLAGS) $(BSC32_SBRS) << @@ -327,74 +342,79 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ /PDB:$(OUTDIR)/"cvsnt.pdb" /DEBUG /MACHINE:I386 /OUT:"WinDebug/cvs.exe" DEF_FILE= LINK32_OBJS= \ - .\WinDebug\subr.obj \ - .\WinDebug\admin.obj \ - .\WinDebug\server.obj \ - .\WinDebug\diff.obj \ - .\WinDebug\client.obj \ - .\WinDebug\checkout.obj \ - .\WinDebug\no_diff.obj \ - .\WinDebug\entries.obj \ - .\WinDebug\tag.obj \ - .\WinDebug\rtag.obj \ - .\WinDebug\status.obj \ - .\WinDebug\root.obj \ - .\WinDebug\myndbm.obj \ - .\WinDebug\hash.obj \ - .\WinDebug\repos.obj \ - .\WinDebug\parseinfo.obj \ - .\WinDebug\vers_ts.obj \ - .\WinDebug\checkin.obj \ - .\WinDebug\commit.obj \ - .\WinDebug\version.obj \ - .\WinDebug\cvsrc.obj \ - .\WinDebug\remove.obj \ - .\WinDebug\update.obj \ - .\WinDebug\logmsg.obj \ - .\WinDebug\classify.obj \ - .\WinDebug\history.obj \ - .\WinDebug\add.obj \ - .\WinDebug\lock.obj \ - .\WinDebug\recurse.obj \ - .\WinDebug\modules.obj \ - .\WinDebug\find_names.obj \ - .\WinDebug\rcs.obj \ - .\WinDebug\create_adm.obj \ - .\WinDebug\main.obj \ - .\WinDebug\patch.obj \ - .\WinDebug\release.obj \ - .\WinDebug\rcscmds.obj \ - .\WinDebug\import.obj \ - .\WinDebug\ignore.obj \ - .\WinDebug\log.obj \ - .\WinDebug\wrapper.obj \ - .\WinDebug\getwd.obj \ - .\WinDebug\error.obj \ - .\WinDebug\sighandle.obj \ - .\WinDebug\getopt.obj \ - .\WinDebug\argmatch.obj \ - .\WinDebug\md5.obj \ - .\WinDebug\yesno.obj \ - .\WinDebug\getopt1.obj \ - .\WinDebug\valloc.obj \ - .\WinDebug\xgetwd.obj \ - .\WinDebug\regex.obj \ - .\WinDebug\fnmatch.obj \ - .\WinDebug\getdate.obj \ - ".\WinDebug\save-cwd.obj" \ - .\WinDebug\mkdir.obj \ - .\WinDebug\run.obj \ - .\WinDebug\pwd.obj \ - .\WinDebug\filesubr.obj \ - .\WinDebug\win32.obj \ - .\WinDebug\waitpid.obj \ - .\WinDebug\ndir.obj \ - .\WinDebug\strippath.obj \ - .\WinDebug\stripslash.obj \ - .\WinDebug\rcmd.obj \ - .\WinDebug\startserver.obj - -.\WinDebug\cvs.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(INTDIR)/subr.obj \ + $(INTDIR)/admin.obj \ + $(INTDIR)/server.obj \ + $(INTDIR)/diff.obj \ + $(INTDIR)/client.obj \ + $(INTDIR)/checkout.obj \ + $(INTDIR)/no_diff.obj \ + $(INTDIR)/entries.obj \ + $(INTDIR)/tag.obj \ + $(INTDIR)/rtag.obj \ + $(INTDIR)/status.obj \ + $(INTDIR)/root.obj \ + $(INTDIR)/myndbm.obj \ + $(INTDIR)/hash.obj \ + $(INTDIR)/repos.obj \ + $(INTDIR)/parseinfo.obj \ + $(INTDIR)/vers_ts.obj \ + $(INTDIR)/checkin.obj \ + $(INTDIR)/commit.obj \ + $(INTDIR)/version.obj \ + $(INTDIR)/cvsrc.obj \ + $(INTDIR)/remove.obj \ + $(INTDIR)/update.obj \ + $(INTDIR)/logmsg.obj \ + $(INTDIR)/classify.obj \ + $(INTDIR)/history.obj \ + $(INTDIR)/add.obj \ + $(INTDIR)/lock.obj \ + $(INTDIR)/recurse.obj \ + $(INTDIR)/modules.obj \ + $(INTDIR)/find_names.obj \ + $(INTDIR)/rcs.obj \ + $(INTDIR)/create_adm.obj \ + $(INTDIR)/main.obj \ + $(INTDIR)/patch.obj \ + $(INTDIR)/release.obj \ + $(INTDIR)/rcscmds.obj \ + $(INTDIR)/import.obj \ + $(INTDIR)/ignore.obj \ + $(INTDIR)/log.obj \ + $(INTDIR)/wrapper.obj \ + $(INTDIR)/error.obj \ + $(INTDIR)/expand_path.obj \ + $(INTDIR)/edit.obj \ + $(INTDIR)/fileattr.obj \ + $(INTDIR)/watch.obj \ + $(INTDIR)/getwd.obj \ + $(INTDIR)/sighandle.obj \ + $(INTDIR)/getopt.obj \ + $(INTDIR)/argmatch.obj \ + $(INTDIR)/md5.obj \ + $(INTDIR)/yesno.obj \ + $(INTDIR)/getopt1.obj \ + $(INTDIR)/valloc.obj \ + $(INTDIR)/xgetwd.obj \ + $(INTDIR)/regex.obj \ + $(INTDIR)/fnmatch.obj \ + $(INTDIR)/getdate.obj \ + $(INTDIR)/"save-cwd.obj" \ + $(INTDIR)/getline.obj \ + $(INTDIR)/mkdir.obj \ + $(INTDIR)/run.obj \ + $(INTDIR)/pwd.obj \ + $(INTDIR)/filesubr.obj \ + $(INTDIR)/win32.obj \ + $(INTDIR)/waitpid.obj \ + $(INTDIR)/ndir.obj \ + $(INTDIR)/strippath.obj \ + $(INTDIR)/stripslash.obj \ + $(INTDIR)/rcmd.obj \ + $(INTDIR)/startserver.obj + +$(OUTDIR)/cvs.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << @@ -433,38 +453,41 @@ DEP_SUBR_=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\subr.obj : $(SOURCE) $(DEP_SUBR_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\subr.obj : $(SOURCE) $(DEP_SUBR_) $(INTDIR) +$(INTDIR)/subr.obj : $(SOURCE) $(DEP_SUBR_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\admin.c +DEP_ADMIN=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\admin.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\admin.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/admin.obj : $(SOURCE) $(DEP_ADMIN) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -472,6 +495,9 @@ SOURCE=.\src\admin.c SOURCE=.\src\server.c DEP_SERVE=\ .\src\cvs.h\ + .\src\watch.h\ + .\src\edit.h\ + .\src\fileattr.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -486,38 +512,41 @@ DEP_SERVE=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\server.obj : $(SOURCE) $(DEP_SERVE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\server.obj : $(SOURCE) $(DEP_SERVE) $(INTDIR) +$(INTDIR)/server.obj : $(SOURCE) $(DEP_SERVE) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\diff.c +DEP_DIFF_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\diff.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\diff.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/diff.obj : $(SOURCE) $(DEP_DIFF_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -525,7 +554,7 @@ SOURCE=.\src\diff.c SOURCE=.\src\client.c DEP_CLIEN=\ .\src\cvs.h\ - .\src\update.h\ + .\lib\getline.h\ .\lib\md5.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ @@ -541,20 +570,13 @@ DEP_CLIEN=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\client.obj : $(SOURCE) $(DEP_CLIEN) $(INTDIR) +$(INTDIR)/client.obj : $(SOURCE) $(DEP_CLIEN) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\client.obj : $(SOURCE) $(DEP_CLIEN) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -576,20 +598,13 @@ DEP_CHECK=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\checkout.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\checkout.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR) +$(INTDIR)/checkout.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -611,20 +626,13 @@ DEP_NO_DI=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\no_diff.obj : $(SOURCE) $(DEP_NO_DI) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\no_diff.obj : $(SOURCE) $(DEP_NO_DI) $(INTDIR) +$(INTDIR)/no_diff.obj : $(SOURCE) $(DEP_NO_DI) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -632,6 +640,7 @@ DEP_NO_DI=\ SOURCE=.\src\entries.c DEP_ENTRI=\ .\src\cvs.h\ + .\lib\getline.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -646,110 +655,155 @@ DEP_ENTRI=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\entries.obj : $(SOURCE) $(DEP_ENTRI) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\entries.obj : $(SOURCE) $(DEP_ENTRI) $(INTDIR) +$(INTDIR)/entries.obj : $(SOURCE) $(DEP_ENTRI) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\tag.c +DEP_TAG_C=\ + .\src\cvs.h\ + ".\lib\save-cwd.h"\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\tag.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\tag.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/tag.obj : $(SOURCE) $(DEP_TAG_C) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\rtag.c +DEP_RTAG_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\rtag.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\rtag.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/rtag.obj : $(SOURCE) $(DEP_RTAG_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\status.c +DEP_STATU=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\status.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\status.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/status.obj : $(SOURCE) $(DEP_STATU) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\root.c +DEP_ROOT_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\root.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\root.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/root.obj : $(SOURCE) $(DEP_ROOT_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\myndbm.c +DEP_MYNDB=\ + .\src\cvs.h\ + .\lib\getline.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\myndbm.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\myndbm.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/myndbm.obj : $(SOURCE) $(DEP_MYNDB) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -771,92 +825,126 @@ DEP_HASH_=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\hash.obj : $(SOURCE) $(DEP_HASH_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\hash.obj : $(SOURCE) $(DEP_HASH_) $(INTDIR) +$(INTDIR)/hash.obj : $(SOURCE) $(DEP_HASH_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\repos.c +DEP_REPOS=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\repos.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\repos.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\parseinfo.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\parseinfo.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/repos.obj : $(SOURCE) $(DEP_REPOS) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" +# End Source File +################################################################################ +# Begin Source File -.\WinDebug\parseinfo.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=.\src\parseinfo.c +DEP_PARSE=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!ENDIF +$(INTDIR)/parseinfo.obj : $(SOURCE) $(DEP_PARSE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) # End Source File ################################################################################ # Begin Source File SOURCE=.\src\vers_ts.c +DEP_VERS_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\vers_ts.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\vers_ts.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/vers_ts.obj : $(SOURCE) $(DEP_VERS_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\checkin.c +DEP_CHECKI=\ + .\src\cvs.h\ + .\src\fileattr.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\checkin.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\checkin.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/checkin.obj : $(SOURCE) $(DEP_CHECKI) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -864,6 +952,9 @@ SOURCE=.\src\checkin.c SOURCE=.\src\commit.c DEP_COMMI=\ .\src\cvs.h\ + .\lib\getline.h\ + .\src\edit.h\ + .\src\fileattr.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -878,135 +969,537 @@ DEP_COMMI=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\commit.obj : $(SOURCE) $(DEP_COMMI) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\commit.obj : $(SOURCE) $(DEP_COMMI) $(INTDIR) +$(INTDIR)/commit.obj : $(SOURCE) $(DEP_COMMI) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\version.c +DEP_VERSI=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\version.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\version.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/version.obj : $(SOURCE) $(DEP_VERSI) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\cvsrc.c +DEP_CVSRC=\ + .\src\cvs.h\ + .\lib\getline.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\cvsrc.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\cvsrc.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/cvsrc.obj : $(SOURCE) $(DEP_CVSRC) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\remove.c +DEP_REMOV=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\remove.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\remove.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/remove.obj : $(SOURCE) $(DEP_REMOV) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\update.c +DEP_UPDAT=\ + .\src\cvs.h\ + .\lib\md5.h\ + .\src\watch.h\ + .\src\fileattr.h\ + .\src\edit.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\update.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\update.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/update.obj : $(SOURCE) $(DEP_UPDAT) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\logmsg.c +DEP_LOGMS=\ + .\src\cvs.h\ + .\lib\getline.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\logmsg.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\logmsg.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/logmsg.obj : $(SOURCE) $(DEP_LOGMS) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\src\classify.c +DEP_CLASS=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\classify.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/classify.obj : $(SOURCE) $(DEP_CLASS) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\history.c +DEP_HISTO=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/history.obj : $(SOURCE) $(DEP_HISTO) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\add.c +DEP_ADD_C=\ + .\src\cvs.h\ + ".\lib\save-cwd.h"\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/add.obj : $(SOURCE) $(DEP_ADD_C) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\lock.c +DEP_LOCK_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/lock.obj : $(SOURCE) $(DEP_LOCK_) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\recurse.c +DEP_RECUR=\ + .\src\cvs.h\ + ".\lib\save-cwd.h"\ + .\src\fileattr.h\ + .\src\edit.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/recurse.obj : $(SOURCE) $(DEP_RECUR) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\modules.c +DEP_MODUL=\ + .\src\cvs.h\ + ".\lib\save-cwd.h"\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/modules.obj : $(SOURCE) $(DEP_MODUL) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\find_names.c +DEP_FIND_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/find_names.obj : $(SOURCE) $(DEP_FIND_) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\rcs.c +DEP_RCS_C=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/rcs.obj : $(SOURCE) $(DEP_RCS_C) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\create_adm.c +DEP_CREAT=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/create_adm.obj : $(SOURCE) $(DEP_CREAT) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\main.c +DEP_MAIN_=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/main.obj : $(SOURCE) $(DEP_MAIN_) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\patch.c +DEP_PATCH=\ + .\src\cvs.h\ + .\lib\getline.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/patch.obj : $(SOURCE) $(DEP_PATCH) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\release.c +DEP_RELEA=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" + +$(INTDIR)/release.obj : $(SOURCE) $(DEP_RELEA) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\src\rcscmds.c +DEP_RCSCM=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -.\WinDebug\classify.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/rcscmds.obj : $(SOURCE) $(DEP_RCSCM) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\history.c -DEP_HISTO=\ +SOURCE=.\src\import.c +DEP_IMPOR=\ .\src\cvs.h\ + ".\lib\save-cwd.h"\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -1021,26 +1514,19 @@ DEP_HISTO=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\history.obj : $(SOURCE) $(DEP_HISTO) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\history.obj : $(SOURCE) $(DEP_HISTO) $(INTDIR) +$(INTDIR)/import.obj : $(SOURCE) $(DEP_IMPOR) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\add.c -DEP_ADD_C=\ +SOURCE=.\src\ignore.c +DEP_IGNOR=\ .\src\cvs.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ @@ -1056,26 +1542,19 @@ DEP_ADD_C=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\add.obj : $(SOURCE) $(DEP_ADD_C) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\add.obj : $(SOURCE) $(DEP_ADD_C) $(INTDIR) +$(INTDIR)/ignore.obj : $(SOURCE) $(DEP_IGNOR) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\lock.c -DEP_LOCK_=\ +SOURCE=.\src\log.c +DEP_LOG_C=\ .\src\cvs.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ @@ -1091,44 +1570,19 @@ DEP_LOCK_=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\lock.obj : $(SOURCE) $(DEP_LOCK_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\lock.obj : $(SOURCE) $(DEP_LOCK_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\recurse.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\recurse.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\recurse.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/log.obj : $(SOURCE) $(DEP_LOG_C) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\modules.c -DEP_MODUL=\ +SOURCE=.\src\wrapper.c +DEP_WRAPP=\ .\src\cvs.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ @@ -1144,26 +1598,19 @@ DEP_MODUL=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\modules.obj : $(SOURCE) $(DEP_MODUL) $(INTDIR) +$(INTDIR)/wrapper.obj : $(SOURCE) $(DEP_WRAPP) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\modules.obj : $(SOURCE) $(DEP_MODUL) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\find_names.c -DEP_FIND_=\ +SOURCE=.\src\error.c +DEP_ERROR=\ .\src\cvs.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ @@ -1179,69 +1626,25 @@ DEP_FIND_=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\find_names.obj : $(SOURCE) $(DEP_FIND_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\find_names.obj : $(SOURCE) $(DEP_FIND_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\rcs.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\rcs.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\rcs.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\create_adm.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\create_adm.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\create_adm.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/error.obj : $(SOURCE) $(DEP_ERROR) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\main.c -DEP_MAIN_=\ +SOURCE=.\src\expand_path.c +DEP_EXPAN=\ .\src\cvs.h\ - .\src\patchlevel.h\ - ".\windows-NT\pwd.h"\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ .\lib\system.h\ .\src\hash.h\ .\src\server.h\ @@ -1251,27 +1654,24 @@ DEP_MAIN_=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\main.obj : $(SOURCE) $(DEP_MAIN_) $(INTDIR) +$(INTDIR)/expand_path.obj : $(SOURCE) $(DEP_EXPAN) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\main.obj : $(SOURCE) $(DEP_MAIN_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\patch.c -DEP_PATCH=\ +SOURCE=.\src\edit.c +DEP_EDIT_=\ .\src\cvs.h\ + .\lib\getline.h\ + .\src\watch.h\ + .\src\edit.h\ + .\src\fileattr.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -1286,63 +1686,22 @@ DEP_PATCH=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\patch.obj : $(SOURCE) $(DEP_PATCH) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\patch.obj : $(SOURCE) $(DEP_PATCH) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\release.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\release.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\release.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\rcscmds.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\rcscmds.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\rcscmds.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/edit.obj : $(SOURCE) $(DEP_EDIT_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\import.c -DEP_IMPOR=\ +SOURCE=.\src\fileattr.c +DEP_FILEA=\ .\src\cvs.h\ + .\lib\getline.h\ + .\src\fileattr.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -1357,63 +1716,23 @@ DEP_IMPOR=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\import.obj : $(SOURCE) $(DEP_IMPOR) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\import.obj : $(SOURCE) $(DEP_IMPOR) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\ignore.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\ignore.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\ignore.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\src\log.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\log.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\log.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/fileattr.obj : $(SOURCE) $(DEP_FILEA) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File -SOURCE=.\src\wrapper.c -DEP_WRAPP=\ +SOURCE=.\src\watch.c +DEP_WATCH=\ .\src\cvs.h\ + .\src\edit.h\ + .\src\fileattr.h\ + .\src\watch.h\ ".\windows-NT\config.h"\ ".\windows-NT\options.h"\ ".\windows-NT\alloca.h"\ @@ -1428,20 +1747,13 @@ DEP_WRAPP=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\wrapper.obj : $(SOURCE) $(DEP_WRAPP) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\wrapper.obj : $(SOURCE) $(DEP_WRAPP) $(INTDIR) +$(INTDIR)/watch.obj : $(SOURCE) $(DEP_WATCH) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File # End Group ################################################################################ @@ -1451,235 +1763,152 @@ DEP_WRAPP=\ # Begin Source File SOURCE=.\lib\getwd.c +DEP_GETWD=\ + ".\windows-NT\config.h"\ + .\lib\system.h\ + ".\windows-NT\alloca.h"\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\getwd.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\getwd.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\lib\error.c - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\error.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\error.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/getwd.obj : $(SOURCE) $(DEP_GETWD) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\sighandle.c +DEP_SIGHA=\ + ".\windows-NT\config.h"\ + .\lib\system.h\ + ".\windows-NT\alloca.h"\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\sighandle.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\sighandle.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/sighandle.obj : $(SOURCE) $(DEP_SIGHA) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\getopt.c +DEP_GETOP=\ + ".\windows-NT\config.h"\ + .\lib\getopt.h -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\getopt.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\getopt.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/getopt.obj : $(SOURCE) $(DEP_GETOP) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\argmatch.c +DEP_ARGMA=\ + ".\windows-NT\config.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\argmatch.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\argmatch.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/argmatch.obj : $(SOURCE) $(DEP_ARGMA) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\md5.c +DEP_MD5_C=\ + ".\windows-NT\config.h"\ + .\lib\md5.h -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\md5.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\md5.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/md5.obj : $(SOURCE) $(DEP_MD5_C) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\yesno.c +DEP_YESNO=\ + ".\windows-NT\config.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\yesno.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\yesno.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/yesno.obj : $(SOURCE) $(DEP_YESNO) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\getopt1.c +DEP_GETOPT=\ + ".\windows-NT\config.h"\ + .\lib\getopt.h -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\getopt1.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\getopt1.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/getopt1.obj : $(SOURCE) $(DEP_GETOPT) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\valloc.c +DEP_VALLO=\ + ".\windows-NT\config.h"\ + .\lib\system.h\ + ".\windows-NT\alloca.h"\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\valloc.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\valloc.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/valloc.obj : $(SOURCE) $(DEP_VALLO) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\xgetwd.c +DEP_XGETW=\ + ".\windows-NT\config.h"\ + .\lib\system.h\ + ".\windows-NT\alloca.h"\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\xgetwd.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\xgetwd.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/xgetwd.obj : $(SOURCE) $(DEP_XGETW) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\regex.c +DEP_REGEX=\ + ".\windows-NT\config.h"\ + .\lib\regex.h\ + ".\windows-NT\alloca.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\regex.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\regex.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/regex.obj : $(SOURCE) $(DEP_REGEX) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\fnmatch.c +DEP_FNMAT=\ + ".\windows-NT\config.h"\ + .\lib\fnmatch.h -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\fnmatch.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\fnmatch.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/fnmatch.obj : $(SOURCE) $(DEP_FNMAT) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=.\lib\getdate.c +DEP_GETDA=\ + ".\windows-NT\config.h"\ + ".\windows-NT\alloca.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\getdate.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\getdate.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/getdate.obj : $(SOURCE) $(DEP_GETDA) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -1688,19 +1917,21 @@ SOURCE=".\lib\save-cwd.c" DEP_SAVE_=\ ".\windows-NT\config.h"\ ".\lib\save-cwd.h"\ - .\lib\error.h - -!IF "$(CFG)" == "Win32 Release" + .\src\error.h -".\WinRel\save-cwd.obj" : $(SOURCE) $(DEP_SAVE_) $(INTDIR) +$(INTDIR)/"save-cwd.obj" : $(SOURCE) $(DEP_SAVE_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" +# End Source File +################################################################################ +# Begin Source File -".\WinDebug\save-cwd.obj" : $(SOURCE) $(DEP_SAVE_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) +SOURCE=.\lib\getline.c +DEP_GETLI=\ + ".\windows-NT\config.h" -!ENDIF +$(INTDIR)/getline.obj : $(SOURCE) $(DEP_GETLI) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) # End Source File # End Group @@ -1711,37 +1942,57 @@ DEP_SAVE_=\ # Begin Source File SOURCE=".\windows-NT\mkdir.c" +DEP_MKDIR=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\mkdir.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\mkdir.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/mkdir.obj : $(SOURCE) $(DEP_MKDIR) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=".\windows-NT\run.c" +DEP_RUN_C=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\run.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\run.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/run.obj : $(SOURCE) $(DEP_RUN_C) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -1750,36 +2001,37 @@ SOURCE=".\windows-NT\pwd.c" DEP_PWD_C=\ ".\windows-NT\pwd.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\pwd.obj : $(SOURCE) $(DEP_PWD_C) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\pwd.obj : $(SOURCE) $(DEP_PWD_C) $(INTDIR) +$(INTDIR)/pwd.obj : $(SOURCE) $(DEP_PWD_C) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=".\windows-NT\filesubr.c" +DEP_FILES=\ + .\src\cvs.h\ + ".\windows-NT\config.h"\ + ".\windows-NT\options.h"\ + ".\windows-NT\alloca.h"\ + .\lib\fnmatch.h\ + ".\windows-NT\pwd.h"\ + .\lib\system.h\ + .\src\hash.h\ + .\src\server.h\ + .\src\client.h\ + .\src\myndbm.h\ + .\lib\regex.h\ + .\lib\getopt.h\ + .\lib\wait.h\ + .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ + ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\filesubr.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\filesubr.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/filesubr.obj : $(SOURCE) $(DEP_FILES) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -1788,36 +2040,20 @@ SOURCE=".\windows-NT\win32.c" DEP_WIN32=\ ".\windows-NT\config.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\win32.obj : $(SOURCE) $(DEP_WIN32) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\win32.obj : $(SOURCE) $(DEP_WIN32) $(INTDIR) +$(INTDIR)/win32.obj : $(SOURCE) $(DEP_WIN32) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=".\windows-NT\waitpid.c" +DEP_WAITP=\ + ".\windows-NT\config.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\waitpid.obj : $(SOURCE) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\waitpid.obj : $(SOURCE) $(INTDIR) +$(INTDIR)/waitpid.obj : $(SOURCE) $(DEP_WAITP) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -1826,58 +2062,27 @@ SOURCE=".\windows-NT\ndir.c" DEP_NDIR_=\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\ndir.obj : $(SOURCE) $(DEP_NDIR_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\ndir.obj : $(SOURCE) $(DEP_NDIR_) $(INTDIR) +$(INTDIR)/ndir.obj : $(SOURCE) $(DEP_NDIR_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=".\windows-NT\strippath.c" -DEP_STRIP=\ - ".\windows-NT\config.h" - -!IF "$(CFG)" == "Win32 Release" -.\WinRel\strippath.obj : $(SOURCE) $(DEP_STRIP) $(INTDIR) +$(INTDIR)/strippath.obj : $(SOURCE) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\strippath.obj : $(SOURCE) $(DEP_STRIP) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ENDIF - # End Source File ################################################################################ # Begin Source File SOURCE=".\windows-NT\stripslash.c" -DEP_STRIPS=\ - ".\windows-NT\config.h" - -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\stripslash.obj : $(SOURCE) $(DEP_STRIPS) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" -.\WinDebug\stripslash.obj : $(SOURCE) $(DEP_STRIPS) $(INTDIR) +$(INTDIR)/stripslash.obj : $(SOURCE) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -1886,18 +2091,9 @@ SOURCE=".\windows-NT\rcmd.c" DEP_RCMD_=\ ".\windows-NT\rcmd.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\rcmd.obj : $(SOURCE) $(DEP_RCMD_) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\rcmd.obj : $(SOURCE) $(DEP_RCMD_) $(INTDIR) +$(INTDIR)/rcmd.obj : $(SOURCE) $(DEP_RCMD_) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File ################################################################################ # Begin Source File @@ -1920,20 +2116,13 @@ DEP_START=\ .\lib\getopt.h\ .\lib\wait.h\ .\src\rcs.h\ + .\src\error.h\ + .\src\update.h\ ".\windows-NT\ndir.h" -!IF "$(CFG)" == "Win32 Release" - -.\WinRel\startserver.obj : $(SOURCE) $(DEP_START) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -!ELSEIF "$(CFG)" == "Win32 Debug" - -.\WinDebug\startserver.obj : $(SOURCE) $(DEP_START) $(INTDIR) +$(INTDIR)/startserver.obj : $(SOURCE) $(DEP_START) $(INTDIR) $(CPP) $(CPP_PROJ) $(SOURCE) -!ENDIF - # End Source File # End Group # End Project diff --git a/gnu/usr.bin/cvs/doc/.cvsignore b/gnu/usr.bin/cvs/doc/.cvsignore new file mode 100644 index 00000000000..b3edee38154 --- /dev/null +++ b/gnu/usr.bin/cvs/doc/.cvsignore @@ -0,0 +1,33 @@ +*.dvi +Makefile +cvs-paper.ps +cvs.aux +cvs.cp +cvs.cps +cvs.dvi +cvs.fn +cvs.fns +cvs.info +cvs.info-* +cvs.ky +cvs.log +cvs.pg +cvs.ps +cvs.toc +cvs.tp +cvs.vr +cvsclient.info +cvsclient.aux +cvsclient.cp +cvsclient.cps +cvsclient.dvi +cvsclient.fn +cvsclient.info +cvsclient.info-* +cvsclient.ky +cvsclient.log +cvsclient.pg +cvsclient.ps +cvsclient.toc +cvsclient.tp +cvsclient.vr diff --git a/gnu/usr.bin/cvs/doc/ChangeLog b/gnu/usr.bin/cvs/doc/ChangeLog index 18b91ba42e2..583d9c066ae 100644 --- a/gnu/usr.bin/cvs/doc/ChangeLog +++ b/gnu/usr.bin/cvs/doc/ChangeLog @@ -1,3 +1,177 @@ +Sun Jan 28 09:00:34 1996 Jim Kingdon + + * cvsclient.texi (Modes): Add discussion what what the mode really + means (across diverse operating systems). + +Tue Jan 23 12:54:57 1996 Jim Kingdon + + * cvs.texinfo: Per mail from Per Cederqvist, change author to "Per + Cederqvist et al". Also remove sentence about Signum shipping + hardcopy manuals and add information on Cyclic. Change version + number to 1.6.87. + +Fri Jan 12 15:29:39 1996 Vince Demarco + + * cvs.texinfo: Fix the documentation for the com/uncom change + to wrap/unwrap. make everything consistant + +Wed Jan 10 16:11:54 1996 Jim Kingdon + + * cvs.texinfo (Concurrency): Add index entries; minor clarification. + +Tue Jan 9 16:03:39 1996 Jim Kingdon + + * cvs.texinfo (Getting Notified): Document users file. + + * cvs.texinfo (cvsignore): Add *.obj to list of ignored files. + +Wed Jan 3 17:01:58 1996 Jim Kingdon + + * cvs.texinfo (import): Adjust list of ignored files to match + recent change to CVS (CVS* -> CVS CVS.adm). Consolidate + discussion of ignored files in one place (with xrefs from others). + + * cvsclient.texi: Remove How To node. It was out of date + (again!), and I am getting sick of trying to update it (internals + documentation should be in the comments, where it at least has a + fighting chance of staying up to date). + (Protocol): Say what \n and \t mean in this document. + +Tue Jan 2 23:39:32 1996 Jim Kingdon + + * cvs.texinfo (Wrappers): Change comb/uncom to wrap/unwrap. + +Mon Jan 2 23:00:00 1996 Vince Demarco + + * cvs.texinfo: update the Wrappers documentation so it isn't + so NEXTSTEP centric. The wrappers code has alot of other + general uses. The new version of the documentation tryes + to show that to the reader. + +Mon Jan 1 13:09:39 1996 Jim Kingdon + + * cvsclient.texi (Responses): Clarify that Module-expansion is not + suitable for passing to co. + +Sun Dec 31 10:53:47 1995 Jim Kingdon + + * cvs.texinfo (Password authentication server): Suggest specifying + -b in inetd.conf. + + * cvs.texinfo (Password authentication): Variety of cleanups and + minor fixes, including shorter node names. + +Sun Dec 24 02:37:51 1995 Karl Fogel + + * cvs.texinfo (Using the client with password authentication): + tixed fypos. + +Sun Dec 24 00:00:16 1995 Karl Fogel + + * cvs.texinfo (Remote repositories): use @code{rsh} most places, + because it is the name of a program, and because I am a pedant. + Refer to new node "Password authenticated". + (Password authenticated): new node. + (Setting up the server for password authentication): new node. + (Using the client with password authentication): new node. + (Security considerations with password authentication): new node. + + These are all really long node names, but it seems necessary that + they be descriptive in case they're referenced elsewhere. If you + can think of a way out of this, please change them. + +Thu Dec 21 12:09:34 1995 Jim Kingdon + + * cvsclient.texi (Requests): Add Questionable. Revise + documentation of export and update to explain role of -I option. + +Tue Dec 19 16:44:18 1995 Jim Kingdon + + * cvs.texinfo: Update binary files info for -kb. + +Mon Dec 11 12:20:55 1995 Jim Kingdon + + * cvsclient.texi (Responses): Add Notified and Mode. + (Requests): Add Notify, noop, watch-on, watch-off, watch-add, + watch-remove, watchers, and editors. + * cvs.texinfo (Watches): New node, to describe new developer + communication features. + +Thu Nov 23 08:59:09 1995 Jim Kingdon + + * cvs.texinfo (admin options): In saying that cvs admin -o is not + such a good way to undo a change, refer to the section which + describes the preferred way. + +Thu Nov 13 16:39:03 1995 Fred Fish + + * Makefile.in: Remove extraneous tab from empty line. + +Mon Nov 13 15:00:26 1995 Jim Kingdon + + * cvs.texinfo (Concurrency): New node, to describe user-visible + behaviors associated with cvs locks. + + * cvs.texinfo (Remote repositories): Add more details of how to + set things up (with rsh and kerberos). + +Thu Nov 9 11:41:37 1995 Jim Kingdon + + * cvs.texinfo: Remove -Q and -q options from command synopses. + +Wed Nov 8 09:38:00 1995 Jim Kingdon + + * cvsclient.texi (Notes): Revise paragraph on server memory use + problem. + +Tue Nov 7 16:26:39 1995 Jim Kingdon + + * cvs.texinfo: Document merging more than once from a branch; + miscellaneous cleanups. + +Mon Oct 30 13:12:53 1995 Jim Kingdon + + * cvs.texinfo (modules): Document -e. + +Thu Oct 26 11:15:40 1995 Jim Kingdon + + * cvs.texinfo (Tags): Update "version" vs. "revision" for CVS 1.5. + (Index,BUGS): Change bug reporting address from Per Cederqvist to + bug-cvs@prep.ai.mit.edu. + +Wed Oct 25 15:37:05 1995 Jim Kingdon + + * cvs.texinfo: Miscellaneous minor changes (clean up CVS/Root + stuff, don't say release requires a module entry, etc.). + +Tue Oct 24 11:01:22 1995 Jim Kingdon + + * cvs.texinfo: More precisely describe scope of document. + * cvsclient.texi: Describe scope of document + +Thu Oct 12 11:25:40 1995 Karl Fogel + + * cvs.texinfo: cover page now refers to CVS 1.6, and "last + updated" date has been upped to today. + +Wed Oct 11 22:30:10 1995 Jim Kingdon + + * Makefile.in (info): Look for *.info* either in build dir or in + srcdir. + +Mon Oct 2 17:10:49 1995 Norbert Kiesel + + * cvs.texinfo (admin): Describe usage of CVS_ADMIN_GROUP to + restrict usage of admin. + +Fri Oct 6 21:17:50 1995 Jim Kingdon + + * cvs.texinfo (~/.cvsrc): Document change to command name matching. + +Thu Oct 5 18:03:41 1995 Jim Kingdon + + * Makefile.in (install-info): Add comment about srcdir. + Wed Sep 13 12:45:53 1995 Jim Kingdon * cvs.texinfo (Moving files): Rewrite "Outside" node to clarify diff --git a/gnu/usr.bin/cvs/doc/Makefile.in b/gnu/usr.bin/cvs/doc/Makefile.in index 0bcd591df6b..e605aaca166 100644 --- a/gnu/usr.bin/cvs/doc/Makefile.in +++ b/gnu/usr.bin/cvs/doc/Makefile.in @@ -79,7 +79,12 @@ cvs.info: cvs.texinfo cvsclient.info: cvsclient.texi $(MAKEINFO) $(srcdir)/cvsclient.texi -o cvsclient.info +# If the user gets a distribution (which contains *.info), unpacks +# it, and builds it in a seperate build dir, then *.info* are in srcdir. +# If the user builds *.info (e.g. after editing *.texi), then *.info* are +# in the build dir. install-info: info + test -f cvs.info || cd $(srcdir); \ for i in *.info* ; do \ $(INSTALL_DATA) $$i $(infodir)/$$i ; \ done @@ -109,7 +114,7 @@ cvs-paper.ps: cvs-paper.ms cvsclient.ps: cvsclient.dvi $(DVIPS) $(DVIPSFLAGS) cvsclient.dvi -o cvsclient.ps - + tags: .PHONY: tags diff --git a/gnu/usr.bin/cvs/doc/cvs.texinfo b/gnu/usr.bin/cvs/doc/cvs.texinfo index aa329c25d97..614bf676d84 100644 --- a/gnu/usr.bin/cvs/doc/cvs.texinfo +++ b/gnu/usr.bin/cvs/doc/cvs.texinfo @@ -1,5 +1,5 @@ \input texinfo @c -*-texinfo-*- -@comment cvs.texinfo,v 1.3 1994/09/15 23:39:26 zoo Exp +@comment cvs.texinfo,v 1.6 1995/10/12 23:39:26 kfogel Exp @comment Documentation for CVS. @comment Copyright (C) 1992, 1993 Signum Support AB @comment Copyright (C) 1993 Free Software Foundation, Inc. @@ -73,12 +73,12 @@ Free Software Foundation instead of in the original English. @sp @center @titlefont{CVS} @sp 2 -@center release 0.9, for @sc{cvs} 1.3+ +@center for @sc{cvs} 1.6.87+ @comment -release- @sp 3 -@center Per Cederqvist +@center Per Cederqvist et al @sp 3 -@center last updated 2 Nov 1993 +@center last updated 23 Jan 1996 @comment -date- @comment The following two commands start the copyright page @@ -113,8 +113,9 @@ Free Software Foundation instead of in the original English. @node Top @top -This info manual describes @sc{cvs} and is updated to -release 1.4 or something similar. +This info manual describes how to use and administer +@sc{cvs} and is updated to release 1.4 or something +similar. @end ifinfo @menu @@ -134,6 +135,7 @@ release 1.4 or something similar. * Moving files:: Moving and renaming files * Moving directories:: Moving and renaming directories * Keyword substitution:: CVS can include the revision inside the file +* Binary files:: CVS can handle binary files * Revision management:: Policy questions for revision management * Invoking CVS:: Reference manual for CVS commands * Administrative files:: Reference manual for the Administrative files @@ -192,8 +194,7 @@ copy both this manual and the @sc{cvs} program. @c -- Check this reference! It has been bogus in the past. support contracts and binary distribution for many programs, such as @sc{cvs}, @sc{gnu} Emacs, the -@sc{gnu} C compiler and others. You can also buy -hardcopies of this manual from us. Write to us for +@sc{gnu} C compiler and others. Write to us for more information. @example @@ -207,6 +208,10 @@ Phone: +46 (0)13 - 21 46 00 Fax: +46 (0)13 - 21 47 00 @end example +Another company selling support for @sc{cvs} is Cyclic +Software, web: @code{http://www.cyclic.com/}, email: +@code{info@@cyclic.com}. + @c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @menu * Checklist:: @@ -289,8 +294,8 @@ and Michael Brown <@t{brown@@wi.extrel.com}>. @cindex Bugs, known in this manual @cindex Known bugs in this manual -This manual is still very new. Here is a -list of known deficiencies in it: +This manual is known to have room for improvement. +Here is a list of known deficiencies: @itemize @bullet @item @@ -317,7 +322,7 @@ noted by comments in the @file{cvs.texinfo} file. @cindex Errors, reporting (manual) This list is not complete. If you notice any error, omission, or something that is unclear, please send -mail to @t{ceder@@signum.se}. +mail to @t{bug-cvs@@prep.ai.mit.edu}. @end itemize I hope that you will find this manual useful, despite @@ -936,12 +941,12 @@ override the @code{$CVSROOT} environment variable. Once you've checked a working copy out from the repository, it will remember where its repository is (the information is recorded in the -@file{@sc{cvs}/Root} file in the working copy). +@file{CVS/Root} file in the working copy). -The @code{-d} option and the @file{@sc{cvs}/Root} file +The @code{-d} option and the @file{CVS/Root} file both override the @code{$CVSROOT} environment variable; however, @sc{CVS} will complain if the @file{-d} -argument and the @file{@sc{cvs}/Root} file disagree. +argument and the @file{CVS/Root} file disagree. There is nothing magical about the name @file{/usr/local/cvsroot}. You can choose to place the @@ -1120,25 +1125,18 @@ In some situations it is a good idea to have more than one repository, for instance if you have two development groups that work on separate projects without sharing any code. All you have to do to have -several repositories is to set @code{$CVSROOT} to the -repository you want to use at the moment. - -There are disadvantages to having more than one -repository. In @sc{cvs} 1.3 you @emph{must} make sure -that @code{$CVSROOT} always points to the correct -repository. If the same filename is used in two -repositories, and you mix up the setting of -@code{$CVSROOT}, you might lose data. @sc{cvs} 1.4 -solves this problem by saving the repository -information in the local @file{CVS} administration -files. If you try to use the wrong repository, -@sc{cvs} will warn you of the attempt and then exit. +several repositories is to specify the appropriate +repository, using the @code{CVSROOT} environment +variable, the @samp{-d} option to @sc{cvs}, or (once +you have checked out a working directories) by +simply allowing @sc{cvs} to use the repository that was +used to check out the working directory (@pxref{Repository}). Notwithstanding, it can be confusing to have two or more repositories. -All examples in this manual assume that you have a -single repository. +None of the examples in this manual show multiple +repositories. @c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @node Creating a repository @@ -1155,49 +1153,309 @@ See the instructions in the @file{INSTALL} file in the @cindex Remote repositories @cindex Client/Server Operation -@c I'm only documenting the rsh method, as I've never -@c used kerberos access... - -The repository and your working copy of the sources can -be on different machines. To access a remote -repository, use the following format for its name: + Your working copy of the sources can be on a +different machine than the repository. Generally, +using a remote repository is just like using a local +one, except that the format of the repository name is: @example user@@hostname:/path/to/repository @end example -(The @file{user@@} can be omitted if it's the same on -both the local and remote hosts.) +The details of exactly what needs to be set up depend +on how you are connecting to the server. + +@menu +* Connecting via rsh:: Using the @code{rsh} program to connect +* Password authenticated:: Direct connections using passwords +* Kerberos authenticated:: Direct connections with kerberos +@end menu + +@node Connecting via rsh +@subsection Connecting with rsh +@cindex rsh CVS uses the @file{rsh} protocol to perform these operations, so the remote user host needs to have a @file{.rhosts} file which grants access to the local user. For example, suppose you are the user @file{mozart} on -the local machine @file{anklet.grunge.com}. You want -to access the module @file{foo} in the repository -@file{/usr/local/sources/}, on machine -@file{chainsaw.brickyard.com}. +the local machine @file{anklet.grunge.com}, and the +server machine is @file{chainsaw.brickyard.com}. On +chainsaw, put the following line into the file +@file{.rhosts} in @file{bach}'s home directory: + +@example +anklet.grunge.com mozart +@end example - If your username is also @file{bach} on -@file{chainsaw.brickyard.com}, then you need only type +Then test that @code{rsh} is working with @example -cvs -d bach@@chainsaw.brickyard.com:/user/local/sources checkout foo +rsh -l bach chainsaw.brickyard.com echo $PATH @end example - Remember, for this to work, @file{bach}'s -@file{.rhosts} file must contain the line: +@cindex CVS_SERVER +Next you have to make sure that @code{rsh} will be able +to find the server. Make sure that the path which +@code{rsh} printed in the above example includes the +directory containing a program named @code{cvs} which +is the server. You need to set the path in +@file{.bashrc}, @file{.cshrc}, etc., not @file{.login} +or @file{.profile}. Alternately, you can set the +environment variable @code{CVS_SERVER} on the client +machine to the filename of the server you want to use, +for example @file{/usr/local/bin/cvs-1.6}. + +There is no need to edit @code{inetd.conf} or start a +@sc{cvs} server daemon. + +Continuing our example, supposing you want to access +the module @file{foo} in the repository +@file{/usr/local/cvsroot/}, on machine +@file{chainsaw.brickyard.com}, you are ready to go: @example -anklet.grunge.com mozart +cvs -d bach@@chainsaw.brickyard.com:/user/local/cvsroot checkout foo +@end example + +(The @file{bach@@} can be omitted if the username is +the same on both the local and remote hosts.) + +@node Password authenticated +@subsection Direct connection with password authentication + +The @sc{cvs} client can also connect to the server +using a password protocol. This is particularly useful +if using @code{rsh} is not feasible (for example, +the server is behind a firewall), and Kerberos also is +not available. + + To use this method, it is necessary to make +some adjustments on both the server and client sides. + +@menu +* Password authentication server:: Setting up the server +* Password authentication client:: Using the client +* Password authentication security:: What this method does and does not do +@end menu + +@node Password authentication server +@subsubsection Setting up the server for password authentication + +@cindex Pserver (subcommand) +@cindex password server, setting up +@cindex authenticating server, setting up +On the server side, the file @file{/etc/inetd.conf} +needs to be edited so @code{inetd} knows to run the +command @code{cvs pserver} when it receives a +connection on the right port. By default, the port +number is 2401; it would be different if your client +were compiled with @code{CVS_AUTH_PORT} defined to +something else, though. + + If your @code{inetd} allows raw port numbers in +@file{/etc/inetd.conf}, then the following (all on a +single line in @file{inetd.conf}) should be sufficient: + +@example +2401 stream tcp nowait root /usr/local/bin/cvs +cvs -b /usr/local/bin pserver @end example - Once the working copy is checked out, it is not -necessary to specify the repository explicitly for -every subsequent operation --- the working copy records -it in the @file{CVS/Root} file. +The @samp{-b} option specifies the directory which contains +the @sc{rcs} binaries on the server. + + If your @code{inetd} wants a symbolic service +name instead of a raw port number, then put this in +@file{/etc/services}: + +@example +cvspserver 2401/tcp +@end example + + and put @code{cvspserver} instead of +@code{2401} in @file{inetd.conf}. + + Once the above is taken care of, restart your +@code{inetd}, or do whatever is necessary to force it +to reread its initialization files. + +@cindex CVS passwd file +@cindex passwd file +Because the client stores and transmits passwords in +cleartext (almost---see @ref{Password authentication +security} for details), a separate @sc{cvs} password +file may be used, so people don't compromise their +regular passwords when they access the repository. +This file is @file{$CVSROOT/CVSROOT/passwd} +(@pxref{Intro administrative files}). Its format is +similar to @file{/etc/passwd}, except that it only has +two fields, username and password. For example: + +@example +bach:ULtgRLXo7NRxs +cwang:1sOp854gDF3DY +@end example + +The password is encrypted according to the standard +Unix @code{crypt()} function, so it is possible to +paste in passwords directly from regular Unix +@file{passwd} files. + +When authenticating a password, the server first checks +for the user in the @sc{cvs} @file{passwd} file. If it +finds the user, it compares against that password. If +it does not find the user, or if the @sc{cvs} +@file{passwd} file does not exist, then the server +tries the system's @file{/etc/passwd} file. In either +case, assuming the password is correct, the server +switches to run as that user immediately after +authentication, so that it will have no privileges +which that user would not have. Therefore it is +necessary that usernames in the @sc{cvs} @file{passwd} +file be valid usernames on the system. + +Right now, the only way to put a password in the +@sc{cvs} @file{passwd} file is to paste it there from +somewhere else. Someday, there may be a @code{cvs +passwd} command. + +@node Password authentication client +@subsubsection Using the client with password authentication +@cindex Login (subcommand) +@cindex password client, using +@cindex authenticated client, using +Before connecting to the server, the client must @dfn{log +in} with the command @code{cvs login}. Logging in +verifies a password with the server, and also records +the password for later transactions with the server. +The @code{cvs login} command needs to know the +username, server hostname, and full repository path, +and it gets this information from the repository +argument or the @code{CVSROOT} environment variable. + +@code{cvs login} is interactive --- it prompts for a +password: + +@example +cvs -d bach@@chainsaw.brickyard.com:/usr/local/cvsroot login +CVS password: +@end example + +The password is checked with the server; if it is +correct, the @code{login} succeeds, else it fails, +complaining that the password was incorrect. + +Once you have logged in, you can force @sc{cvs} to +connect directly to the server and authenticate with +the stored password by prefixing the repository with +@samp{:pserver:}: + +@example +cvs -d :pserver:bach@@chainsaw.brickyard.com:/usr/local/cvsroot checkout foo +@end example + +The @samp{:pserver:} is necessary because without it, +@sc{cvs} will assume it should use @code{rsh} to +connect with the server (@pxref{Connecting via rsh}). +(Once you have a working copy checked out and are +running @sc{cvs} commands from within it, there is no +longer any need to specify the repository explicitly, +because @sc{cvs} records it in the working copy's +@file{CVS} subdirectory.) + +@cindex CVS_PASSFILE, environment variable +Passwords are stored by default in the file +@file{$HOME/.cvspass}. Its format is human-readable, +but don't edit it unless you know what you are doing. +The passwords are not stored in cleartext, but are +trivially encoded to protect them from "innocent" +compromise (i.e., inadvertently being seen by a system +administrator who happens to look at that file). + +The @code{CVS_PASSFILE} environment variable overrides +this default. If you use this variable, make sure you +set it @emph{before} @code{cvs login} is run. If you +were to set it after running @code{cvs login}, then +later @sc{cvs} commands would be unable to look up the +password for transmission to the server. + +@cindex CVS_PASSWORD, environment variable +The @code{CVS_PASSWORD} environment variable overrides +@emph{all} stored passwords. If it is set, @sc{cvs} +will use it for all password-authenticated +connections. + +@node Password authentication security +@subsubsection Security considerations with password authentication + +The passwords are stored on the client side in a +trivial encoding of the cleartext, and transmitted in +the same encoding. The encoding is done only to +prevent inadvertent password compromises (i.e., a +system administrator accidentally looking at the file), +and will not prevent even a naive attacker from gaining +the password. + +The separate @sc{cvs} password file (@pxref{Password +authentication server}) allows people +to use a different password for repository access than +for login access. On the other hand, once a user has +access to the repository, she can execute programs on +the server system through a variety of means. Thus, repository +access implies fairly broad system access as well. It +might be possible to modify @sc{cvs} to prevent that, +but no one has done so as of this writing. +Furthermore, there may be other security problems with +@sc{cvs}; it is not a simple program and determining +how people might use it to gain access to a system is +difficult. + +In summary, anyone who gets the password gets +repository access, and some measure of general system +access as well. The password is available to anyone +who can sniff network packets or read a protected +(i.e., user read-only) file. If you want real +security, get Kerberos. + +@node Kerberos authenticated +@subsection Direct connection with kerberos + +@cindex kerberos +The main disadvantage of using rsh is that all the data +needs to pass through additional programs, so it may be +slower. So if you have kerberos installed you can +connect via a direct @sc{tcp} connection, +authenticating with kerberos (note that the data +transmitted is @emph{not} encrypted). + +To do this, @sc{cvs} needs to be compiled with kerberos +support; when configuring @sc{cvs} it tries to detect +whether kerberos is present or you can use the +@file{--with-krb4} flag to configure. + +@cindex CVS_CLIENT_PORT +You need to edit @code{inetd.conf} on the server +machine to run @code{cvs kserver}. The client uses +port 1999 by default; if you want to use another port +specify it in the @code{CVS_CLIENT_PORT} environment +variable on the client. Set @code{CVS_CLIENT_PORT} to +@samp{-1} to force an rsh connection. + +@cindex kinit +When you want to use @sc{cvs}, get a ticket in the +usual way (generally @code{kinit}); it must be a ticket +which allows you to log into the server machine. Then +you are ready to go: + +@example +cvs -d chainsaw.brickyard.com:/user/local/cvsroot checkout foo +@end example + +If @sc{cvs} fails to connect, it will fall back to +trying rsh. @c --------------------------------------------------------------------- @node Starting a new project @@ -1210,7 +1468,7 @@ Since @sc{cvs} 1.x is bad at renaming files and moving them between directories, the first thing you do when you start a new project should be to think through your file organization. It is not impossible---just -awkward---to rename or move files in @sc{cvs} 1.x. +awkward---to rename or move files. @xref{Moving files}. What to do next depends on the situation at hand. @@ -1325,10 +1583,10 @@ directories inside @samp{$CVSROOT} are reasonable. @cindex Module, defining @cindex Modules file, changing -The next step is to define the module in the @file{modules} file. Some -@sc{cvs} commands work without this step, but others (most notably -@code{release}) require that all modules are properly defined in the -@file{modules} file. +The next step is to define the module in the +@file{modules} file. This is not strictly necessary, +but modules can be convenient in grouping together +related files and directories. In simple cases these steps are sufficient to define a module. @@ -1411,6 +1669,8 @@ automating that process. @xref{Informing others}. * Updating a file:: Bringing a file up-to-date * Conflicts example:: An informative example * Informing others:: To cooperate you must inform +* Concurrency:: Simultaneous repository access +* Watches:: Mechanisms to track who is editing files @end menu @c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1672,6 +1932,327 @@ message to all developers, or post a message to a local newsgroup. @c -- More text would be nice here. +@node Concurrency +@section Several developers simultaneously attempting to run CVS + +@cindex locks, cvs +If several developers try to run @sc{cvs} at the same +time, one may get the following message: + +@example +[11:43:23] waiting for bach's lock in /usr/local/cvsroot/foo +@end example + +@sc{cvs} will try again every 30 seconds, and either +continue with the operation or print the message again, +if it still needs to wait. If a lock seems to stick +around for an undue amount of time, find the person +holding the lock and ask them about the cvs command +they are running. If they aren't running a cvs +command, look for and remove files starting with +@file{#cvs.tfl}, @file{#cvs.rfl}, or @file{#cvs.wfl} +from the repository. + +Note that these locks are to protect @sc{cvs}'s +internal data structures and have no relationship to +the word @dfn{lock} in the sense used by @sc{rcs}--a +way to prevent other developers from working on a +particular file. + +Any number of people can be reading from a given +repository at a time; only when someone is writing do +the locks prevent other people from reading or writing. + +@cindex Atomic transactions, lack of +@cindex Transactions, atomic, lack of +One might hope for the following property + +@example +If someone commits some changes in one cvs command, +then an update by someone else will either get all the +changes, or none of them. +@end example + +but @sc{cvs} does @emph{not} have this property. For +example, given the files + +@example +a/one.c +a/two.c +b/three.c +b/four.c +@end example + +if someone runs + +@example +cvs ci a/two.c b/three.c +@end example + +and someone else runs @code{cvs update} at the same +time, the person running @code{update} might get only +the change to @file{b/three.c} and not the change to +@file{a/two.c}. + +@node Watches +@section Mechanisms to track who is editing files +@cindex Watches + +For many groups, use of @sc{cvs} in its default mode is +perfectly satisfactory. Users may sometimes go to +check in a modification only to find that another +modification has intervened, but they deal with it and +proceed with their check in. Other groups prefer to be +able to know who is editing what files, so that if two +people try to edit the same file they can choose to +talk about who is doing what when rather than be +surprised at check in time. The features in this +section allow such coordination, while retaining the +ability of two developers to edit the same file at the +same time. + +For maximum benefit developers should use @code{cvs +edit} (not @code{chmod}) to make files read-write to +edit them, and @code{cvs release} (not @code{rm}) to +discard a working directory which is no longer in use, +but @sc{cvs} is not able to enforce this behavior. + +@c I'm a little dissatisfied with this presentation, +@c because "watch on"/"edit"/"editors" are one set of +@c functionality, and "watch add"/"watchers" is another +@c which is somewhat orthogonal even though they interact in +@c various ways. But I think it might be +@c confusing to describe them separately (e.g. "watch +@c add" with loginfo). I don't know. + +@menu +* Setting a watch:: Telling CVS to watch certain files +* Getting Notified:: Telling CVS to notify you +* Editing files:: How to edit a file which is being watched +* Watch information:: Information about who is watching and editing +* Watches Compatibility:: Watches interact poorly with CVS 1.6 or earlier +@end menu + +@node Setting a watch +@subsection Telling CVS to watch certain files + +To enable the watch features, you first specify that +certain files are to be watched. + +@cindex watch on (subcommand) +@deffn Command {cvs watch on} [@code{-l}] files @dots{} + +Specify that developers should run @code{cvs edit} +before editing @var{files}. CVS will create working +copies of @var{files} read-only, to remind developers +to run the @code{cvs edit} command before working on +them. + +If @var{files} includes the name of a directory, CVS +arranges to watch all files added to the corresponding +repository directory, and sets a default for files +added in the future; this allows the user to set +notification policies on a per-directory basis. The +contents of the directory are processed recursively, +unless the @code{-l} option is given. + +If @var{files} is omitted, it defaults to the current directory. + +@cindex watch off (subcommand) +@end deffn + +@deffn Command {cvs watch off} [@code{-l}] files @dots{} + +Do not provide notification about work on @var{files}. CVS will create +working copies of @var{files} read-write. + +The @var{files} and @code{-l} arguments are processed as for @code{cvs +watch on}. + +@end deffn + +@node Getting Notified +@subsection Telling CVS to notify you + +You can tell @sc{cvs} that you want to receive +notifications about various actions taken on a file. +You can do this without using @code{cvs watch on} for +the file, but generally you will want to use @code{cvs +watch on}, so that developers use the @code{cvs edit} +command. + +@cindex watch add (subcommand) +@deffn Command {cvs watch add} [@code{-a} action] [@code{-l}] files @dots{} + +Add the current user to the list of people to receive notification of +work done on @var{files}. + +The @code{-a} option specifies what kinds of events CVS should notify +the user about. @var{action} is one of the following: + +@table @code + +@item edit +Another user has applied the @code{cvs edit} command (described +below) to a file. + +@item unedit +Another user has applied the @code{cvs unedit} command (described +below) or the @code{cvs release} command to a file, or has deleted +the file and allowed @code{cvs update} to recreate it. + +@item commit +Another user has committed changes to a file. + +@item all +All of the above. + +@item none +None of the above. (This is useful with @code{cvs edit}, +described below.) + +@end table + +The @code{-a} option may appear more than once, or not at all. If +omitted, the action defaults to @code{all}. + +The @var{files} and @code{-l} option are processed as for the +@code{cvs watch} commands. + +@end deffn + + +@cindex watch remove (subcommand) +@deffn Command {cvs watch remove} [@code{-a} action] [@code{-l}] files @dots{} + +Remove a notification request established using @code{cvs watch add}; +the arguments are the same. If the @code{-a} option is present, only +watches for the specified actions are removed. + +@end deffn + +When the conditions exist for notification, @sc{cvs} +calls the @file{notify} administrative file, passing it +the user to receive the notification and the user who +is taking the action which results in notification. +Normally @file{notify} will just send an email message. + +@cindex users (admin file) +Note that if you set this up in the straightforward +way, users receive notifications on the server machine. +One could of course write a @file{notify} script which +directed notifications elsewhere, but to make this +easy, @sc{cvs} allows you to associate a notification +address for each user. To do so create a file +@file{users} in @file{CVSROOT} with a line for each +user in the format @var{user}:@var{value}. Then +instead of passing the name of the user to be notified +to @file{notify}, @sc{cvs} will pass the @var{value} +(normally an email address on some other machine). + +@node Editing files +@subsection How to edit a file which is being watched + +Since a file which is being watched is checked out +read-only, you cannot simply edit it. To make it +read-write, and inform others that you are planning +to edit it, use the @code{cvs edit} command. + +@cindex edit (subcommand) +@deffn Command {cvs edit} [options] files @dots{} + +Prepare to edit the working files @var{files}. CVS makes the +@var{files} read-write, and notifies users who have requested +@code{edit} notification for any of @var{files}. + +The @code{cvs edit} command accepts the same @var{options} as the +@code{cvs watch add} command, and establishes a temporary watch for the +user on @var{files}; CVS will remove the watch when @var{files} are +@code{unedit}ed or @code{commit}ted. If the user does not wish to +receive notifications, she should specify @code{-a none}. + +The @var{files} and @code{-l} option are processed as for the @code{cvs +watch} commands. + +@end deffn + +Normally when you are done with a set of changes, you +use the @code{cvs commit} command, which checks in your +changes and returns the watched files to their usual +read-only state. But if you instead decide to abandon +your changes, or not to make any changes, you can use +the @code{cvs unedit} command. + +@cindex unedit (subcommand) +@deffn Command {cvs unedit} [@code{-l}] files @dots{} + +Abandon work on the working files @var{files}, and revert them to the +repository versions on which they are based. CVS makes those +@var{files} read-only for which users have requested notification using +@code{cvs watch on}. CVS notifies users who have requested @code{unedit} +notification for any of @var{files}. + +The @var{files} and @code{-l} option are processed as for the +@code{cvs watch} commands. + +@end deffn + +When using client/server @sc{cvs}, you can use the +@code{cvs edit} and @code{cvs unedit} commands even if +@sc{cvs} is unable to succesfully communicate with the +server; the notifications will be sent upon the next +successful @sc{cvs} command. + +@node Watch information +@subsection Information about who is watching and editing + +@cindex watchers (subcommand) +@deffn Command {cvs watchers} [@code{-l}] files @dots{} + +List the users currently watching changes to @var{files}. The report +includes the files being watched, and the mail address of each watcher. + +The @var{files} and @code{-l} arguments are processed as for the +@code{cvs watch} commands. + +@end deffn + + +@cindex editors (subcommand) +@deffn Command {cvs editors} [@code{-l}] files @dots{} + +List the users currently working on @var{files}. The report +includes the mail address of each user, the time when the user began +working with the file, and the host and path of the working directory +containing the file. + +The @var{files} and @code{-l} arguments are processed as for the +@code{cvs watch} commands. + +@end deffn + +@node Watches Compatibility +@subsection Using watches with old versions of CVS + +@cindex CVS 1.6, and watches +If you use the watch features on a repository, it +creates @file{CVS} directories in the repository and +stores the information about watches in that directory. +If you attempt to use @sc{cvs} 1.6 or earlier with the +repository, you get an error message such as + +@example +cvs update: cannot open CVS/Entries for reading: No such file or directory +@end example + +and your operation will likely be aborted. To use the +watch features, you must upgrade all copies of @sc{cvs} +which use that repository in local or server mode. If +you cannot upgrade, use the @code{watch off} and +@code{watch remove} commands to remove all watches, and +that will restore the repository to a state which +@sc{cvs} 1.6 can cope with. + @c --------------------------------------------------------------------- @node Branches @chapter Branches @@ -1732,9 +2313,7 @@ rcsutil.c 5.10 You can use the @code{tag} command to give a symbolic name to a certain revision of a file. You can use the @samp{-v} flag to the @code{status} command to see all tags that a file has, and -which revision numbers they represent. (The output of @code{status} -unfortunately uses the word ``version'' instead of ``revision''.) -@c -- Is this fixed in CVS 1.3.1? +which revision numbers they represent. @cindex Adding a tag @cindex tag, example @@ -2002,6 +2581,7 @@ copy the changes onto another branch. @menu * Merging a branch:: Merging an entire branch +* Merging more than once:: Merging from a branch several times * Merging two revisions:: Merging differences between two revisions @end menu @@ -2018,10 +2598,7 @@ point where the branch forked and newest revision on that branch (into your working copy). @cindex Join -The @samp{-j} stands for ``join''. In previous -versions of @sc{cvs} there was a special command, -@samp{cvs join}, that was used to merge changes between -branches. +The @samp{-j} stands for ``join''. @cindex Branch merge example @cindex Example, branch merge @@ -2029,14 +2606,14 @@ branches. Consider this revision tree: @example -+-----+ +-----+ +-----+ +-----+ +-----+ -! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk -+-----+ +-----+ +-----+ +-----+ +-----+ ++-----+ +-----+ +-----+ +-----+ +! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- The main trunk ++-----+ +-----+ +-----+ +-----+ ! ! - ! +---------+ +---------+ +---------+ -Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 ! - +---------+ +---------+ +---------+ + ! +---------+ +---------+ +Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 ! + +---------+ +---------+ @end example @noindent @@ -2045,14 +2622,14 @@ following example assumes that the module @samp{mod} contains only one file, @file{m.c}. @example -$ cvs checkout mod # @r{Retrieve the latest revision, 1.5} +$ cvs checkout mod # @r{Retrieve the latest revision, 1.4} $ cvs update -j R1fix m.c # @r{Merge all changes made on the branch,} # @r{i.e. the changes between revision 1.2} - # @r{and 1.2.2.3, into your working copy} + # @r{and 1.2.2.2, into your working copy} # @r{of the file.} -$ cvs commit -m "Included R1fix" # @r{Create revision 1.6.} +$ cvs commit -m "Included R1fix" # @r{Create revision 1.5.} @end example A conflict can result from a merge operation. If that @@ -2067,6 +2644,74 @@ $ cvs checkout -j R1fix mod $ cvs commit -m "Included R1fix" @end example +@node Merging more than once +@section Merging from a branch several times + +Continuing our example, the revision tree now looks +like this: + +@example ++-----+ +-----+ +-----+ +-----+ +-----+ +! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk ++-----+ +-----+ +-----+ +-----+ +-----+ + ! * + ! * + ! +---------+ +---------+ +Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 ! + +---------+ +---------+ +@end example + +where the starred line represents the merge from the +@samp{R1fix} branch to the main trunk, as just +discussed. + +Now suppose that development continues on the +@samp{R1fix} branch: + +@example ++-----+ +-----+ +-----+ +-----+ +-----+ +! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk ++-----+ +-----+ +-----+ +-----+ +-----+ + ! * + ! * + ! +---------+ +---------+ +---------+ +Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 ! + +---------+ +---------+ +---------+ +@end example + +and then you want to merge those new changes onto the +main trunk. If you just use the @code{cvs update -j +R1fix m.c} command again, @sc{cvs} will attempt to +merge again the changes which you have already merged, +which can have undesirable side effects. + +So instead you need to specify that you only want to +merge the changes on the branch which have not yet been +merged into the trunk. To do that you specify two +@samp{-j} options, and @sc{cvs} merges the changes from +the first revision to the second revision. For +example, in this case the simplest way would be + +@example +cvs update -j 1.2.2.2 -j R1fix m.c # @r{Merge changes from 1.2.2.2 to the} + # @r{head of the R1fix branch} +@end example + +The problem with this is that you need to specify the +1.2.2.2 revision manually. A slightly better approach +might be to use the date the last merge was done: + +@example +cvs update -j R1fix:yesterday -j R1fix m.c +@end example + +Better yet, tag the R1fix branch after every merge into +the trunk, and then use that tag for subsequent merges: + +@example +cvs update -j merged_from_R1fix_to_trunk -j R1fix m.c +@end example + @c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @node Merging two revisions @section Merging differences between any two revisions @@ -2088,12 +2733,12 @@ $ cvs update -j 1.5 -j 1.3 backend.c will @emph{remove} all changes made between revision 1.3 and 1.5. Note the order of the revisions! -If you try to use this option with the @code{checkout} -command, remember that the numeric revisions will +If you try to use this option when operating on +multiple files, remember that the numeric revisions will probably be very different between the various files that make up a module. You almost always use symbolic -tags rather than revision numbers with the -@code{checkout} command. +tags rather than revision numbers when operating on +multiple files. @c --------------------------------------------------------------------- @node Recursive behavior @@ -2359,9 +3004,10 @@ since yesterday into the working copy. If any conflicts arise during the merge they should be resolved in the normal way (@pxref{Conflicts example}). Then, the modified files may be committed. -@sc{cvs} assumes that you do not import more than one -release of a product per day. If you do, you can always -use something like this instead: +Using a date, as suggested above, assumes that you do +not import more than one release of a product per +day. If you do, you can always use something like this +instead: @example $ cvs checkout -jWDIFF_0_04 -jWDIFF_0_05 wdiff @@ -2832,9 +3478,7 @@ into something like @samp{$@asis{}Author: ceder $}. There is unfortunately no way to selectively turn off keyword substitution. You can use @samp{-ko} (@pxref{Substitution modes}) to turn off keyword -substitution entirely. (If you put binaries under -version control you are strongly encouraged to use that -option, for obvious reasons). +substitution entirely. In many cases you can avoid using @sc{rcs} keywords in the source, even though they appear in the final @@ -2856,7 +3500,7 @@ options}). The @samp{-k} option is available with the @code{add}, @code{checkout}, @code{diff} and @code{update} commands. -Five different modes are available. They are: +The modes available are: @table @samp @item -kkv @@ -2884,10 +3528,17 @@ file just before it was checked in. For example, for the @code{Revision} keyword, generate the string @code{$@asis{}Revision: 1.1 $} instead of @code{$@asis{}Revision: 5.7 $} if that is how the -string appeared when the file was checked in. This can -be useful for binary file formats that cannot tolerate -any changes to substrings that happen to take the form -of keyword strings. +string appeared when the file was checked in. + +@item -kb +Like @samp{-ko}, but also inhibit conversion of line +endings between the canonical form in which they are +stored in the repository (linefeed only), and the form +appropriate to the operating system in use on the +client. For systems, like unix, which use linefeed +only to terminate lines, this is the same as +@samp{-ko}. For more information on binary files, see +@ref{Binary files}. @item -kv Generate only keyword values for keyword strings. For @@ -2900,8 +3551,9 @@ further keyword substitution cannot be performed once the keyword names are removed, so this option should be used with care. -This option is always use by @code{cvs -export}---@pxref{export}. +One often would like to use @samp{-kv} with @code{cvs +export}---@pxref{export}. But be aware that doesn't +handle an export containing binary files correctly. @end table @@ -2935,6 +3587,65 @@ not in the files header, if it is to be used at all. That way the long list of change messages will not interfere with everyday source file browsing. +@c --------------------------------------------------------------------- +@node Binary files +@chapter Handling binary files +@cindex Binary files + +There are two issues with using @sc{cvs} to store +binary files. The first is that @sc{cvs} by default +convert line endings between the canonical form in +which they are stored in the repository (linefeed +only), and the form appropriate to the operating system +in use on the client (for example, carriage return +followed by line feed for Windows NT). + +The second is that a binary file might happen to +contain data which looks like a keyword (@pxref{Keyword +substitution}), so keyword expansion must be turned +off. + +The @samp{-kb} option available with some @sc{cvs} +commands insures that neither line ending conversion +nor keyword expansion will be done. If you are using +an old version of @sc{rcs} without this option, and you +are using an operating system, such as unix, which +terminates lines with linefeeds only, you can use +@samp{-ko} instead; if you are on another operating +system, upgrade to a version of @sc{rcs}, such as 5.7 +or later, which supports @samp{-kb}. + +Here is an example of how you can create a new file +using the @samp{-kb} flag: + +@example +$ echo '$@asis{}Id$' > kotest +$ cvs add -kb -m"A test file" kotest +$ cvs ci -m"First checkin; contains a keyword" kotest +@end example + +If a file accidentally gets added without @samp{-kb}, +one can use the @code{cvs admin} command to recover. +For example: + +@example +$ echo '$@asis{}Id$' > kotest +$ cvs add -m"A test file" kotest +$ cvs ci -m"First checkin; contains a keyword" kotest +$ cvs admin -kb kotest +$ rm kotest +$ cvs update kotest +@end example + +When you check in the file @file{kotest} the keywords +are expanded. (Try the above example, and do a +@code{cat kotest} after every command). The @code{cvs +admin -kb} command sets the default keyword +substitution method for this file, but it does not +alter the working copy of the file that you have. The +easiest way to get the unexpanded version of +@file{kotest} is to remove it and check it out again. + @c --------------------------------------------------------------------- @node Revision management @chapter Revision management @@ -2994,8 +3705,10 @@ goal, which is to get software written. @cindex Reference, commands @cindex Invoking CVS -This appendix describes every subcommand of @sc{cvs} in -detail. It also describes how to invoke CVS. +This appendix describes how to invoke @sc{cvs}, and +describes in detail those subcommands of @sc{cvs} which +are not fully described elsewhere. To look up a +particular subcommand, see @ref{Index}. @menu * Structure:: Overall structure of CVS commands @@ -3078,12 +3791,11 @@ the documentation instead. There are some @code{command_options} that are used so often that you might have set up an alias or some other means to make sure you always specify that option. One -example @footnote{being the one that drove the -implementation of the .cvsrc support} is that many -people find the default output of the @samp{diff} -command to be very hard to read, and that either -context diffs or unidiffs are much easier to -understand. +example (the one that drove the implementation of the +.cvsrc support, actually) is that many people find the +default output of the @samp{diff} command to be very +hard to read, and that either context diffs or unidiffs +are much easier to understand. The @file{~/.cvsrc} file is a way that you can add default options to @code{cvs_commands} within cvs, @@ -3098,9 +3810,10 @@ added to the command arguments @emph{before} any options from the command line. If a command has two names (e.g., @code{checkout} and -@code{co}), only the name used on the command line will -be used to match against the file. So if this is the -contents of the user's @file{~/.cvsrc} file: +@code{co}), the official name, not necessarily the one +used on the command line, will be used to match against +the file. So if this is the contents of the user's +@file{~/.cvsrc} file: @example log -N @@ -3110,17 +3823,17 @@ co -P @end example @noindent -the command @samp{cvs checkout foo} would not have the -@samp{-P} option added to the arguments, while -@samp{cvs co foo} would. +the command @samp{cvs checkout foo} would have the +@samp{-P} option added to the arguments, as well as +@samp{cvs co foo}. With the example file above, the output from @samp{cvs diff foobar} will be in unidiff format. @samp{cvs diff --c foobar} will provide context diffs, as usual. Since -@code{diff} doesn't have an option to specify use of -the "old" format, you would need to use the @samp{-f} -option to @samp{cvs} to turn off use of the -@file{~/.cvsrc} options. +-c foobar} will provide context diffs, as usual. +Getting "old" format diffs would be slightly more +complicated, because @code{diff} doesn't have an option +to specify use of the "old" format, so you would need +@samp{cvs -f diff foobar}. @@ -3148,8 +3861,7 @@ specified as an absolute pathname. @item -d @var{cvs_root_directory} Use @var{cvs_root_directory} as the root directory pathname of the repository. Overrides the setting of -the @code{$CVSROOT} environment variable. This parameter -should be specified as an absolute pathname. +the @code{$CVSROOT} environment variable. @xref{Repository}. @cindex EDITOR, overriding @cindex Overriding EDITOR @@ -3500,17 +4212,11 @@ There are only two options you can give to @samp{add}: @table @code @item -k @var{kflag} This option specifies the default way that this file -will be checked out. See rcs(1) and co(1). The -@var{kflag} argument (@pxref{Substitution modes}) is -stored in the @sc{rcs} file and can be changed with -@code{admin -k} (@pxref{admin options}). Specifying -@samp{-ko} is useful for checking in binaries that -should not have the @sc{rcs} id strings expanded. - -@strong{Warning:} this option is reported to be broken in -version 1.3 and 1.3-s2 of @sc{cvs}. Use @samp{admin -k} -after the commit instead. @xref{admin examples}. -@c -- broken-- +will be checked out. The @var{kflag} argument +(@pxref{Substitution modes}) is stored in the @sc{rcs} +file and can be changed with @code{admin -k} +(@pxref{admin options}). See @ref{Binary files}, for +information on using this option for binary files. @item -m @var{description} Using this option, you can give a description for the file. This @@ -3558,6 +4264,12 @@ all its options and arguments to the @code{rcs} command; it does no filtering or other processing. This command @emph{does} work recursively, however, so extreme care should be used. +If there is a group whose name matches a compiled in +value which defaults to @code{cvsadmin}, only members +of that group can use @code{cvs admin}. To disallow +@code{cvs admin} for all users, create a group with no +users in it. + @menu * admin options:: admin options * admin examples:: admin examples @@ -3680,7 +4392,7 @@ working files. @cindex Outdating revisions @cindex Saving space @item -o@var{range} -Useful, but dangerous, with @sc{cvs} (see below). +Potentially useful, but dangerous, with @sc{cvs} (see below). Deletes (@dfn{outdates}) the revisions given by @var{range}. A range consisting of a single revision number means that revision. A range consisting of a @@ -3701,9 +4413,9 @@ cannot be specified symbolically if it is a branch. Make sure that no-one has checked out a copy of the revision you outdate. Strange things will happen if he starts to edit it and tries to check it back in. For -this reason, you should never use this option to take -back a bogus commit unless you work alone. Instead, -you should fix the file and commit a new revision. +this reason, this option is not a good way to take back +a bogus commit; commit a new revision undoing the bogus +change instead (@pxref{Merging two revisions}). @item -q Run quietly; do not print diagnostics. @@ -3802,37 +4514,6 @@ the tags R_1_02 and R_1_03. So not only will it be impossible to retrieve R_1_02; R_1_03 will also have to be restored from the tapes! -@need 1200 -@appendixsubsubsec Handling binary files -@cindex Binary files (inhibit keyword expansion) -@cindex Inhibiting keyword expansion -@cindex Keyword expansion, inhibiting - -If you use @sc{cvs} to store binary files, where -keyword strings (@pxref{Keyword substitution}) might -accidentally appear inside the file, you should use -@code{cvs admin -ko} to make sure that they are not -modified automatically. Here is an example of how you -can create a new file using the @samp{-ko} flag: - -@example -$ echo '$@asis{}Id$' > kotest -$ cvs add -m"A test file" kotest -$ cvs ci -m"First checkin; contains a keyword" kotest -$ cvs admin -ko kotest -$ rm kotest -$ cvs update kotest -@end example - -When you check in the file @file{kotest} the keywords -are expanded. (Try the above example, and do a -@code{cat kotest} after every command!) The @code{cvs -admin -ko} command sets the default keyword -substitution method for this file, but it does not -alter the working copy of the file that you have. The -easiest way to get the unexpanded version of -@file{kotest} is to remove it and check it out again. - @appendixsubsubsec Comment leaders @cindex Comment leader @cindex Log keyword, selecting comment leader @@ -3904,6 +4585,16 @@ sure that it will be a sub-directory, and that each file as it is extracted into your private work area (unless you specify the @samp{-Q} global option). +The files created by @code{checkout} are created +read-write, unless the @samp{-r} option to @sc{cvs} +(@pxref{Global options}) is specified, the +@code{CVSREAD} environment variable is specified +(@pxref{Environment variables}), or a watch is in +effect for that file (@pxref{Watches}). + +@c FIXME: misleading--checkout takes a module as +@c argument, and update does not--so -d behavior is not the only +@c difference. Running @code{checkout} on a directory that was already built by a prior @code{checkout} is also permitted, and has the same effect as specifying the @samp{-d} option @@ -3985,28 +4676,26 @@ also use @samp{-N}, the paths created under @var{dir} will be as short as possible. @item -j @var{tag} -Merge the changes made between the resulting revision -and the revision that it is based on (e.g., if -@var{tag} refers to a branch, @sc{cvs} will merge all -changes made on that branch into your working file). - -With two @samp{-j @var{tag}} options, @sc{cvs} will merge in the -changes between the two respective revisions. This can -be used to undo changes made between two revisions -(@pxref{Merging two revisions}) in your working copy, -or to move changes between different branches. +With two @samp{-j} options, merge changes from the +revision specified with the first @samp{-j} option to +the revision specified with the second @samp{j} option, +into the working directory. + +With one @samp{-j} option, merge changes from the +ancestor revision to the revision specified with the +@samp{-j} option, into the working directory. The +ancestor revision is the common ancestor of the +revision which the working directory is based on, and +the revision specified in the @samp{-j} option. In addition, each -j option can contain an optional date specification which, when used with branches, can limit the chosen revision to one within a specific date. An optional date is specified by adding a colon -(:) to the tag. An example might be what @code{import} -tells you to do when you have just imported sources -that have conflicts with local changes: +(:) to the tag: +@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}. -@example -$ cvs checkout -jTAG:yesterday -jTAG module -@end example +@xref{Merging}. @item -N Only useful together with @samp{-d @var{dir}}. With this @@ -4410,7 +5099,7 @@ $ cvs diff -u | less @itemize @bullet @item -Synopsis: export [-flNnQq] -r rev|-D date [-d dir] module@dots{} +Synopsis: export [-flNn] -r rev|-D date [-d dir] module@dots{} @item Requires: repository. @item @@ -4692,29 +5381,9 @@ in the two branches of development; use @samp{checkout -j} to reconcile the differences, as import instructs you to do. -By default, certain file names are ignored during -@code{import}: names associated with @sc{cvs} -administration, or with other common source control -systems; common names for patch files, object files, -archive files, and editor backup files; and other names -that are usually artifacts of assorted utilities. -Currently, the default list of ignored files includes -files matching these names: - -@example - RCSLOG RCS SCCS - CVS* cvslog.* - tags TAGS - .make.state .nse_depinfo - *~ #* .#* ,* - *.old *.bak *.BAK *.orig *.rej .del-* - *.a *.o *.so *.Z *.elc *.ln - core -@end example - -If the file @file{$CVSROOT/CVSROOT/cvsignore} exists, -any files whose names match the specifications in that -file will also be ignored. +If @sc{cvs} decides a file should be ignored +(@pxref{cvsignore}), it does not import it and prints +@samp{I } followed by the filename If the file @file{$CVSROOT/CVSROOT/cvswrappers} exists, any file whose names match the specifications in that @@ -4767,16 +5436,11 @@ reset to 1.1.1. Warning: This behavior might change in the future. @item -k @var{subst} -Indicate the RCS keyword expansion mode desired. This setting will -apply to all files created during the import, but not to any files that -previously existed in the repository. See co(1) for a complete list of -valid @samp{-k} settings. - -If you are checking in sources that contain @sc{rcs} keywords, and you -wish those keywords to remain intact, use the @samp{-ko} flag when -importing the files. This setting indicates that no keyword expansion -is to be performed by @sc{rcs} when checking files out. It is also -useful for checking in binaries. +Indicate the RCS keyword expansion mode desired. This +setting will apply to all files created during the +import, but not to any files that previously existed in +the repository. See @ref{Substitution modes} for a +list of valid @samp{-k} settings. @item -I @var{name} Specify file names that should be ignored during @@ -5107,7 +5771,7 @@ File bar.h,v changed from revision 1.29.2.1 to 1.2 @itemize @bullet @item -release [-dQq] modules@dots{} +release [-d] modules@dots{} @item Requires: Working directory. @item @@ -5210,7 +5874,8 @@ Note that no warning message like this is printed for spurious directories that @sc{cvs} encounters. The directory, and all its contents, are silently ignored. -@c FIXME -- this should be fixed for CVS 1.4 +@c FIXME -- CVS should be fixed to print "? foo" for +@c such spurious directories @end table @c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -5340,7 +6005,7 @@ U oj.c @itemize @bullet @item -rtag [-falnRQq] [-b] [-d] [-r tag | -Ddate] symbolic_tag modules@dots{} +rtag [-falnR] [-b] [-d] [-r tag | -Ddate] symbolic_tag modules@dots{} @item Requires: repository. @item @@ -5510,7 +6175,7 @@ to. @itemize @bullet @item -tag [-lQqR] [-b] [-d] symbolic_tag [files@dots{}] +tag [-lR] [-b] [-d] symbolic_tag [files@dots{}] @item Requires: working directory, repository. @item @@ -5608,7 +6273,7 @@ be valuable. @itemize @bullet @item -update [-AdflPpQqR] [-d] [-r tag|-D date] files@dots{} +update [-AdflPpR] [-d] [-r tag|-D date] files@dots{} @item Requires: repository, working directory. @item @@ -5657,7 +6322,7 @@ this file in this working directory will use the same to see the sticky options. @xref{status}. @item -l -Local; run only in current working directory. +Local; run only in current working directory. @xref{Recursive behavior}. @item -P Prune empty directories. @@ -5666,7 +6331,8 @@ Prune empty directories. Pipe files to the standard output. @item -R -Commit directories recursively. This is on by default. +Operate recursively. This is on by default. +@xref{Recursive behavior}. @item -r tag Retrieve revision @var{tag}. This option is sticky, @@ -5707,23 +6373,9 @@ those directories, which may not be what you want. Ignore files whose names match @var{name} (in your working directory) during the update. You can specify @samp{-I} more than once on the command line to specify -several files to ignore. By default, @code{update} -ignores files whose names match any of the following: - -@example - RCSLOG RCS SCCS - CVS* cvslog.* - tags TAGS - .make.state .nse_depinfo - *~ #* .#* ,* - *.old *.bak *.BAK *.orig *.rej .del-* - *.a *.o *.so *.Z *.elc *.ln - core -@end example - -Use @samp{-I !} to avoid ignoring any files at all. -@xref{cvsignore}, for other ways to make @sc{cvs} ignore -some files. +several files to ignore. Use @samp{-I !} to avoid +ignoring any files at all. @xref{cvsignore}, for other +ways to make @sc{cvs} ignore some files. @item -W@var{spec} Specify file names that should be filtered during @@ -5733,22 +6385,18 @@ update. You can use this option repeatedly. that you can specify in the @file{.cvswrappers} file. @xref{Wrappers}. -@item -j@var{branch} -Merge the changes made between the resulting revision -and the revision that it is based on (e.g., if the tag -refers to a branch, @sc{cvs} will merge all changes made in -that branch into your working file). +@item -j@var{revision} +With two @samp{-j} options, merge changes from the +revision specified with the first @samp{-j} option to +the revision specified with the second @samp{j} option, +into the working directory. -With two @samp{-j} options, @sc{cvs} will merge in the -changes between the two respective revisions. This can -be used to remove a certain delta from your working -file; if the file @file{foo.c} is based on -revision 1.6 and you want to remove the changes made -between 1.3 and 1.5, you might do: - -@example -$ cvs update -j1.5 -j1.3 foo.c # @r{note the order@dots{}} -@end example +With one @samp{-j} option, merge changes from the +ancestor revision to the revision specified with the +@samp{-j} option, into the working directory. The +ancestor revision is the common ancestor of the +revision which the working directory is based on, and +the revision specified in the @samp{-j} option. In addition, each -j option can contain an optional date specification which, when used with branches, can @@ -5756,6 +6404,9 @@ limit the chosen revision to one within a specific date. An optional date is specified by adding a colon (:) to the tag: @samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}. + +@xref{Merging}. + @end table @c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . @@ -5977,6 +6628,12 @@ module, in your working directory. Name the working directory something other than the module name. +@cindex Export program +@item -e @var{prog} +Specify a program @var{prog} to run whenever files in a +module are exported. @var{prog} runs with a single +argument, the module name. + @cindex Checkin program @item -i @var{prog} Specify a program @var{prog} to run whenever files in a @@ -6028,26 +6685,17 @@ this module. @cindex CVSWRAPPERS, environment variable @cindex Wrappers -Wrappers are essentially -directories that are to be treated as "files." This -package allows such wrappers to be "processed" on the -way in and out of CVS. The intended use is to wrap up -a wrapper into a single tar, such that that tar can be -treated as a single binary file in CVS. Apparently -this is particularly useful on NEXTSTEP. To solve -the problem effectively, it was also necessary to be -able to prevent rcsmerge application at appropriate -times. +Wrappers allow you to set a hook which transforms files on +their way in and out of cvs The file @file{cvswrappers} defines the script that will be run on a file when its name matches a regular expresion. There are two scripts that can be run on a -file or directory. -@c FIXME: Is this talking about comb and uncom? If so, -@c mention them by name -A script to filter the directory/file before it gets -checked in and another that is run when the -file/directory gets checked out. +file or directory. One script is executed on the file/directory +before being checked into the repository (this is denoted +with the @code{-t} flag) and the other when the file is +checked out of the repository (this is denoted with the +@code{-f} flag) The @file{cvswrappers} also specifies the merge methodology that should be used when the file is @@ -6070,33 +6718,37 @@ and value is a single-quote delimited value. @end example @example -*.nib -f 'uncom %s' -t 'comb %s %s' -m 'COPY' -*.rtfd -f 'uncom %s' -t 'comb %s %s' -m 'COPY' +*.nib -f 'unwrap %s' -t 'wrap %s %s' -m 'COPY' +*.c -t 'indent %s %s' @end example @noindent The above example of a @file{cvswrappers} file states that all files/directories that end with a @code{.nib} -should be filtered with the @file{comb} program before +should be filtered with the @file{wrap} program before checking the file into the repository. The file should -be filtered though the @file{uncom} program when the +be filtered though the @file{unwrap} program when the file is checked out of the repository. The @file{cvswrappers} file also states that a @code{COPY} methodology should be used when updating the files in the repository (that is no merging should be performed). +The last example line says that all files that end with +a @code{*.c} should be filtered with @file{indent} +before being checked into the repository. Unlike the previous +example no filtering of the @code{*.c} file is done when +it is checked out of the repository. @noindent -The @file{comb} filter is called with two arguments, +The @code{-t} filter is called with two arguments, the first is the name of the file/directory to filter and the second is the pathname to where the resulting filtered file should be placed. @noindent -The @file{uncom} filter is called with one argument, +The @code{-f} filter is called with one argument, which is the name of the file to filter from. The end -result of the @file{uncom} filter will be a -file/directory in the users current working directory, -that represents the source before being filtered. +result of this filter will be a file in the users directory +that they can work on as they normally would. @c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @node commit files @@ -6466,19 +7118,25 @@ This list is constructed in the following way. @itemize @bullet @item -The list is initialized to the following file name -patterns: +The list is initialized to include certain file name +patterns: names associated with @sc{cvs} +administration, or with other common source control +systems; common names for patch files, object files, +archive files, and editor backup files; and other names +that are usually artifacts of assorted utilities. +Currently, the default list of ignored file name +patterns is: @cindex Ignored files @cindex Automatically ignored files @example - RCSLOG RCS SCCS - CVS* cvslog.* + RCS SCCS CVS CVS.adm + RCSLOG cvslog.* tags TAGS .make.state .nse_depinfo *~ #* .#* ,* *.old *.bak *.BAK *.orig *.rej .del-* - *.a *.o *.so *.Z *.elc *.ln + *.a *.o *.obj *.so *.Z *.elc *.ln core @end example @@ -6585,21 +7243,11 @@ kept). This information must be available to @sc{cvs} for most commands to execute; if @code{$CVSROOT} is not set, or if you wish to override it for one invocation, you can supply it on the command line: @samp{cvs -d cvsroot -cvs_command@dots{}} You may not need to set -@code{$CVSROOT} if your @sc{cvs} binary has the right path -compiled in. - -@ignore -@c FIXME--update the rest of this manual to reflect CVS/Root. -If your site has several repositories, you must be -careful to set @code{$CVSROOT} to the appropriate one -when you use @sc{cvs}, even if you just run @samp{cvs -update} inside an already checked-out module. Future -releases of @sc{cvs} will probably store information about -which repository the module came from inside the -@file{CVS} directory, but version 1.3 relies totally on -@code{$CVSROOT}. -@end ignore +cvs_command@dots{}} Once you have checked out a working +directory, @sc{cvs} stores the appropriate root (in +the file @file{CVS/Root}), so normally you only need to +worry about this when initially checking out a working +directory. @cindex EDITOR @cindex CVSEDITOR @@ -6738,10 +7386,6 @@ no way to see how the tag was assigned yesterday). @unnumbered Index @cindex Index -If you cannot find what you are looking for here write -to <@t{ceder@@signum.se}> so that an entry can be added -to the next release of this manual. - @printindex cp @summarycontents diff --git a/gnu/usr.bin/cvs/doc/cvsclient.texi b/gnu/usr.bin/cvs/doc/cvsclient.texi index 56844b1a1f2..33fd4bc3184 100644 --- a/gnu/usr.bin/cvs/doc/cvsclient.texi +++ b/gnu/usr.bin/cvs/doc/cvsclient.texi @@ -5,10 +5,13 @@ @node Top @top CVS Client/Server +This manual describes the client/server protocol used by CVS. It does +not describe how to use or administer client/server CVS; see the +regular CVS manual for that. + @menu * Goals:: Basic design decisions, requirements, scope, etc. * Notes:: Notes on the current implementation -* How To:: How to remote your favorite CVS command * Protocol Notes:: Possible enhancements, limitations, etc. of the protocol * Protocol:: Complete description of the protocol @end menu @@ -72,100 +75,11 @@ The server can also be started by @code{cvs kserver}, in which case it does an initial Kerberos authentication on stdin. If the authentication succeeds, it subsequently runs identically to @code{cvs server}. -The current server implementation can use up huge amounts of memory when -transmitting a lot of data. Avoiding this would be a bit tricky because -it is not acceptable to have the server block on the network (which may -be very slow) when it has locks open. The buffer code has been -rewritten so that this does not appear to be a serious problem in -practice. However, if it is seen to be a problem several solutions are -possible. The two-pass design would involve first noting what versions -of everything we need (with locks in place) and then sending the data, -blocking on the network, with no locks needed. The lather-rinse-repeat -design would involve doing things as it does now until a certain amount -of server memory is being used (10M?), then releasing locks, and trying -the whole update again (some of it is presumably already done). One -problem with this is getting merges to work right. - -@node How To -@chapter How to add more remote commands - -It's the usual simple twelve step process. Let's say you're making -the existing @code{cvs fix} command work remotely. - -@itemize @bullet -@item -Add a declaration for the @code{fix} function, which already implements -the @code{cvs fix} command, to @file{server.c}. -@item -Now, the client side. -Add a function @code{client_fix} to @file{client.c}, which calls -@code{parse_cvsroot} and then calls the usual @code{fix} function. -@item -Add a declaration for @code{client_fix} to @file{client.h}. -@item -Add @code{client_fix} to the "fix" entry in the table of commands in -@file{main.c}. -@item -Now for the server side. -Add the @code{serve_fix} routine to @file{server.c}; make it do: -@example @code -static void -serve_fix (arg) - char *arg; -@{ - do_cvs_command (fix); -@} -@end example -@item -Add the server command @code{"fix"} to the table of requests in @file{server.c}. -@item -The @code{fix} function can now be entered in three different situations: -local (the old situation), client, and server. On the server side it probably -will not need any changes to cope. -Modify the @code{fix} function so that if it is run when the variable -@code{client_active} is set, it starts the server, sends over parsed -arguments and possibly files, sends a "fix" command to the server, -and handles responses from the server. Sample code: -@example @code - if (!client_active) @{ - /* Do whatever you used to do */ - @} else @{ - /* We're the local client. Fire up the remote server. */ - start_server (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - send_option_string (options); - - send_files (argc, argv, local); - - if (fprintf (to_server, "fix\n") == EOF) - error (1, errno, "writing to server"); - err = get_responses_and_close (); - @} -@end example -@item -Build it locally. Copy the new version into somewhere on the -remote system, in your path so that @code{rsh host cvs} finds it. -Now you can test it. -@item -You may want to set the environment variable @code{CVS_CLIENT_PORT} to --1 to prevent the client from contacting the server via a direct TCP -link. That will force the client to fall back to using @code{rsh}, -which will run your new binary. -@item -Set the environment variable @code{CVS_CLIENT_LOG} to a filename prefix -such as @file{/tmp/cvslog}. Whenever you run a remote CVS command, -the commands and responses sent across the client/server connection -will be logged in @file{/tmp/cvslog.in} and @file{/tmp/cvslog.out}. -Examine them for problems while you're testing. -@end itemize - -This should produce a good first cut at a working remote @code{cvs fix} -command. You may have to change exactly how arguments are passed, -whether files or just their names are sent, and how some of the deeper -infrastructure of your command copes with remoteness. +The current server implementation can use up huge amounts of memory +when transmitting a lot of data over a slow link (i.e. the network is +slower than the server can generate the data). There is some +experimental code (see @code{SERVER_FLOWCONTROL} in options.h) which +should help significantly. @node Protocol Notes @chapter Notes on the Protocol @@ -207,6 +121,9 @@ repositories are implemented, and the rcsmerge is done by the client. @node Protocol @chapter The CVS client/server protocol +In the following, @samp{\n} refers to a linefeed and @samp{\t} refers +to a horizontal tab. + @menu * Entries Lines:: * Modes:: @@ -248,11 +165,10 @@ A mode is any number of repetitions of separated by @samp{,}. @var{mode-type} is an identifier composed of alphanumeric characters. -Currently specified: @samp{u} for user, @samp{g} for group, @samp{o} for -other, as specified in POSIX. If at all possible, give these their -POSIX meaning and use other mode-types for other behaviors. For -example, on VMS it shouldn't be hard to make the groups behave like -POSIX, but you would need to use ACLs for some cases. +Currently specified: @samp{u} for user, @samp{g} for group, @samp{o} +for other (see below for discussion of whether these have their POSIX +meaning or are more loose). Unrecognized values of @var{mode-type} +are silently ignored. @var{data} consists of any data not containing @samp{,}, @samp{\0} or @samp{\n}. For @samp{u}, @samp{g}, and @samp{o} mode types, data @@ -260,6 +176,19 @@ consists of alphanumeric characters, where @samp{r} means read, @samp{w} means write, @samp{x} means execute, and unrecognized letters are silently ignored. +The two most obvious ways in which the mode matters are: (1) is it +writeable? This is used by the developer communication features, and +is implemented even on OS/2 (and could be implemented on DOS), whose +notion of mode is limited to a readonly bit. (2) is it executable? +Unix CVS users need CVS to store this setting (for shell scripts and +the like). The current CVS implementation on unix does a little bit +more than just maintain these two settings, but it doesn't really have +a nice general facility to store or version control the mode, even on +unix, much less across operating systems with diverse protection +features. So all the ins and outs of what the mode means across +operating systems haven't really been worked out (e.g. should the VMS +port use ACLs to get POSIX semantics for groups?). + @node Requests @section Requests @@ -383,6 +312,29 @@ unchanged. This is necessary for correct behavior since only the server knows what possible files may exist, and thus what files are nonexistent. +@item Notify @var{filename} \n +Tell the server that a @code{edit} or @code{unedit} command has taken +place. The server needs to send a @code{Notified} response, but such +response is deferred until the next time that the server is sending +responses. Response expected: no. Additional data: +@example +@var{notification-type} \t @var{time} \t @var{clienthost} \t +@var{working-dir} \t @var{watches} \n +@end example +where @var{notification-type} is @samp{E} for edit or @samp{U} for +unedit, @var{time} is the time at which the edit or unedit took place, +@var{clienthost} is the name of the host on which the edit or unedit +took place, and @var{working-dir} is the pathname of the working +directory where the edit or unedit took place. @var{watches} are the +temporary watches to set; if it is followed by \t then the tab and the +rest of the line are ignored. + +@item Questionable @var{filename} \n +Response expected: no. Additional data: no. Tell the server to check +whether @var{filename} should be ignored, and if not, next time the +server sends responses, send (in a @code{M} response) @samp{?} followed +by the directory and filename. + @item Argument @var{text} \n Response expected: no. Save argument for use in a subsequent command. Arguments @@ -409,7 +361,6 @@ rdiff; the latter do not access the working directory and thus have no need to expand modules on the client side. @item co \n -@itemx update \n @itemx ci \n @itemx diff \n @itemx tag \n @@ -419,11 +370,11 @@ need to expand modules on the client side. @itemx remove \n @itemx rdiff \n @itemx rtag \n -@itemx import \n @itemx admin \n @itemx export \n @itemx history \n -@itemx release \n +@itemx watchers \n +@itemx editors \n Response expected: yes. Actually do a cvs command. This uses any previous @code{Argument}, @code{Repository}, @code{Entry}, @code{Modified}, or @code{Lost} requests, if they have been sent. The @@ -432,6 +383,47 @@ of the operation. No provision is made for any input from the user. This means that @code{ci} must use a @code{-m} argument if it wants to specify a log message. +@itemx update \n +Response expected: yes. Actually do a @code{cvs update} command. This +uses any previous @code{Argument}, @code{Repository}, @code{Entry}, +@code{Modified}, or @code{Lost} requests, if they have been sent. The +last @code{Repository} sent specifies the working directory at the time +of the operation. The @code{-I} option is not used--files which the +client can decide whether to ignore are not mentioned and the client +sends the @code{Questionable} request for others. + +@item import \n +Response expected: yes. Actually do a @code{cvs import} command. This +uses any previous @code{Argument}, @code{Repository}, @code{Entry}, +@code{Modified}, or @code{Lost} requests, if they have been sent. The +last @code{Repository} sent specifies the working directory at the time +of the operation. The files to be imported are sent in @code{Modified} +requests (files which the client knows should be ignored are not sent; +the server must still process the CVSROOT/cvsignore file unless -I ! is +sent). A log message must have been specified with a @code{-m} +argument. + +@item watch-on \n +@itemx watch-off \n +@itemx watch-add \n +@itemx watch-remove \n +Response expected: yes. Actually do the @code{cvs watch on}, @code{cvs +watch off}, @code{cvs watch add}, and @code{cvs watch remove} commands, +respectively. This uses any previous @code{Argument}, +@code{Repository}, @code{Entry}, @code{Modified}, or @code{Lost} +requests, if they have been sent. The last @code{Repository} sent +specifies the working directory at the time of the operation. + +@item release \n +Response expected: yes. Note that a @code{cvs release} command has +taken place and update the history file accordingly. + +@item noop \n +Response expected: yes. This request is a null command in the sense +that it doesn't do anything, but merely (as with any other requests +expecting a response) sends back any responses pertaining to pending +errors, pending @code{Notified} responses, etc. + @item update-patches \n This request does not actually do anything. It is used as a signal that the server is able to generate patches when given an @code{update} @@ -526,6 +518,12 @@ This will only be used when the client has an exact copy of an earlier revision of a file. This response is only used if the @code{update} command is given the @samp{-u} argument. +@item Mode @var{mode} \n +This @var{mode} applies to the next file mentioned in +@code{Checked-in}. It does not apply to any request which follows a +@code{Checked-in}, @code{New-entry}, @code{Updated}, @code{Merged}, or +@code{Patched} response. + @item Checksum @var{checksum}\n The @var{checksum} applies to the next file sent over via @code{Updated}, @code{Merged}, or @code{Patched}. In the case of @@ -581,10 +579,21 @@ Additional data: @var{prog} \n. Tell the client to set an update program, which should be supplied with the @code{Update-prog} request for future operations. -@item Module-expansion @var{pathname} \n -Return a file or directory which is included in a particular module. -@var{pathname} is relative to cvsroot, unlike most pathnames in -responses. +@item Notified @var{pathname} \n +Indicate to the client that the notification for @var{pathname} has been +done. There should be one such response for every @code{Notify} +request; if there are several @code{Notify} requests for a single file, +the requests should be processed in order; the first @code{Notified} +response pertains to the first @code{Notify} request, etc. + +@item Module-expansion @var{pathname} \n Return a file or directory +which is included in a particular module. @var{pathname} is relative +to cvsroot, unlike most pathnames in responses. @var{pathname} should +be used to look and see whether some or all of the module exists on +the client side; it is not necessarily suitable for passing as an +argument to a @code{co} request (for example, if the modules file +contains the @samp{-d} option, it will be the directory specified with +@samp{-d}, not the name of the module). @item M @var{text} \n A one-line message for the user. diff --git a/gnu/usr.bin/cvs/examples/.cvsignore b/gnu/usr.bin/cvs/examples/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/gnu/usr.bin/cvs/examples/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/gnu/usr.bin/cvs/examples/ChangeLog b/gnu/usr.bin/cvs/examples/ChangeLog index f4225c663fa..d8480f833aa 100644 --- a/gnu/usr.bin/cvs/examples/ChangeLog +++ b/gnu/usr.bin/cvs/examples/ChangeLog @@ -1,3 +1,45 @@ +Wed Jan 10 08:38:27 1996 Jim Kingdon + + * Makefile.in (DISTFILES): Include EXAMPLE_FILES rather than + duplicating the list. + (EXAMPLE_FILES): Add notify. + +Sun Dec 10 23:10:32 1995 Jim Kingdon + + * notify: New file. + +Tue Nov 14 18:19:22 1995 Greg A. Woods + + * commitinfo, editinfo, loginfo, rcsinfo: new rcs id + + * modules: + - new rcs id + - add mention of new CVSROOT admin files + + * taginfo: + - new rcs id + - leave the DEFAULT uncommented -- cvsinit comments it out + + * checkoutlist: add wrap & unwrap as useful examples + + * cvswrappers: + - renamed comb/uncom to wrap/unwrap + - re-formatted comments, etc. + + * Makefile.in: renamed comb/uncom to wrap/unwrap + + * unwrap, wrap: renamed from comb and uncom + +Mon Oct 9 09:25:23 1995 Norbert Kiesel + + * taginfo: document "mov" for tag -F + +Thu Aug 3 01:42:28 1995 Vince DeMarco + + * cvswrappers: Cleaned up old file to use $CVSROOT stuff and + shortened all of the lines to under 80 columns. File is now a + working example of a cvswrappers file. + Mon Jul 24 17:08:25 1995 Vince DeMarco * Updated comb program to work when the user runs update/commit diff --git a/gnu/usr.bin/cvs/examples/Makefile.in b/gnu/usr.bin/cvs/examples/Makefile.in index 2c285ebf7a3..4e3800e0e1c 100644 --- a/gnu/usr.bin/cvs/examples/Makefile.in +++ b/gnu/usr.bin/cvs/examples/Makefile.in @@ -42,12 +42,10 @@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ EXAMPLE_FILES = commitinfo editinfo loginfo modules rcsinfo taginfo \ - rcstemplate checkoutlist cvswrappers uncom comb + rcstemplate checkoutlist cvswrappers wrap unwrap notify DISTFILES = \ - .cvsignore Makefile.in ChangeLog \ - commitinfo editinfo loginfo modules rcsinfo taginfo \ - rcstemplate checkoutlist cvswrappers uncom comb + .cvsignore Makefile.in ChangeLog $(EXAMPLE_FILES) all: Makefile .PHONY: all @@ -56,6 +54,7 @@ install: all $(libdir)/cvs/examples for f in $(EXAMPLE_FILES) ; do\ $(INSTALL_DATA) $(srcdir)/$$f $(libdir)/cvs/examples/$$f; \ done + @echo "You might consider running 'cvsinit' to upgrade your repository(s)...." .PHONY: install $(libdir)/cvs/examples: diff --git a/gnu/usr.bin/cvs/examples/checkoutlist b/gnu/usr.bin/cvs/examples/checkoutlist index ab8c39254e8..ce969ed756d 100644 --- a/gnu/usr.bin/cvs/examples/checkoutlist +++ b/gnu/usr.bin/cvs/examples/checkoutlist @@ -1,5 +1,5 @@ # -#ident "@(#)cvs/examples:$Name: $:$Id: checkoutlist,v 1.1.1.1 1995/12/19 09:21:43 deraadt Exp $ +#ident "@(#)cvs/examples:$Name: $:$Id: checkoutlist,v 1.1.1.2 1996/01/30 00:19:25 tholo Exp $" # # The "checkoutlist" file is used to support additional version controlled # administrative files in $CVSROOT/CVSROOT, such as template files. @@ -16,3 +16,5 @@ # comment lines begin with '#' # rcstemplate +wrap +unwrap diff --git a/gnu/usr.bin/cvs/examples/commitinfo b/gnu/usr.bin/cvs/examples/commitinfo index f189215977b..869358667b8 100644 --- a/gnu/usr.bin/cvs/examples/commitinfo +++ b/gnu/usr.bin/cvs/examples/commitinfo @@ -1,5 +1,5 @@ # -# $Id: commitinfo,v 1.1.1.1 1995/12/19 09:21:42 deraadt Exp $ +#ident "@(#)cvs/examples:$Name: $:$Id: commitinfo,v 1.1.1.2 1996/01/30 00:19:19 tholo Exp $" # # The "commitinfo" file is used to control pre-commit checks. # The filter on the right is invoked with the repository and a list diff --git a/gnu/usr.bin/cvs/examples/cvswrappers b/gnu/usr.bin/cvs/examples/cvswrappers index 494dbd56442..68570f51510 100644 --- a/gnu/usr.bin/cvs/examples/cvswrappers +++ b/gnu/usr.bin/cvs/examples/cvswrappers @@ -1,13 +1,17 @@ # -# This file describes wrappers and other binary files to CVS -# Wrappers are the concept where directories of files are to be treated -# as a single file. The intended use is to wrap up a wrapper into a single tar -# such that the tar archive can be treated as a single binary file -# in CVS. +#ident "@(#)cvs/examples:$Name: $:$Id: cvswrappers,v 1.1.1.2 1996/01/30 00:19:25 tholo Exp $" +# +# This file describes wrappers and other binary files to CVS. +# +# Wrappers are the concept where directories of files are to be +# treated as a single file. The intended use is to wrap up a wrapper +# into a single tar such that the tar archive can be treated as a +# single binary file in CVS. +# # To solve the problem effectively, it was also necessary to be able to # prevent rcsmerge from merging these files. -# ------------------ -# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) +# +# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) # # wildcard [option value][option value]... # @@ -19,25 +23,7 @@ # and value is a single-quote delimited value. # # - -*.nib -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.rtfd -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.draw -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.Mesa -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.diagram2 -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.taskmaster -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.concur -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.nb -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.wub -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.pub -f '/Local/testRep/CVSROOT/uncom %s' -t -Local/testRep/CVSROOT/comb %s %s' -m 'COPY' -*.tiff -m 'COPY' +*.nib -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s' +*.rtfd -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s' +*.draw -f '$CVSROOT/CVSROOT/unwrap %s' -t '$CVSROOT/CVSROOT/wrap %s %s' +*.tiff -m 'COPY' diff --git a/gnu/usr.bin/cvs/examples/editinfo b/gnu/usr.bin/cvs/examples/editinfo index 5e36df846a1..1f058e5245b 100644 --- a/gnu/usr.bin/cvs/examples/editinfo +++ b/gnu/usr.bin/cvs/examples/editinfo @@ -1,5 +1,5 @@ # -# $Id: editinfo,v 1.1.1.1 1995/12/19 09:21:42 deraadt Exp $ +#ident "@(#)cvs/examples:$Name: $:$Id: editinfo,v 1.1.1.2 1996/01/30 00:19:20 tholo Exp $" # # The "editinfo" file is used to allow verification of logging # information. It works best when a template (as specified in the @@ -27,4 +27,6 @@ # supported. There can be only one entry that matches a given # repository. # +# Note there is no "edit" example script currently available.... +# DEFAULT $CVSROOT/CVSROOT/edit "%s" diff --git a/gnu/usr.bin/cvs/examples/loginfo b/gnu/usr.bin/cvs/examples/loginfo index f1def1a8a28..0327962bb22 100644 --- a/gnu/usr.bin/cvs/examples/loginfo +++ b/gnu/usr.bin/cvs/examples/loginfo @@ -1,5 +1,5 @@ # -# $CVSid: @(#)loginfo 1.5 92/03/31 $ +#ident "@(#)cvs/examples:$Name: $:$Id: loginfo,v 1.1.1.2 1996/01/30 00:19:20 tholo Exp $" # # The "loginfo" file is used to control where "cvs commit" log information # is sent. The first entry on a line is a regular expression which is tested @@ -33,4 +33,7 @@ # -f logfile - save messages to logfile [optional] # %s - must follow other options at the end of the line # +# without perl you could do this: +#DEFAULT (echo ""; who am i; date; cat) >> $CVSROOT/CVSROOT/commitlog +# DEFAULT $CVSROOT/CVSROOT/log -f $CVSROOT/CVSROOT/commitlog %s diff --git a/gnu/usr.bin/cvs/examples/modules b/gnu/usr.bin/cvs/examples/modules index aea294362f2..fac5f1a8b2f 100644 --- a/gnu/usr.bin/cvs/examples/modules +++ b/gnu/usr.bin/cvs/examples/modules @@ -1,7 +1,7 @@ # # The CVS Modules File # -# $CVSid: @(#)modules 1.5 92/03/31 $ +#ident "@(#)cvs/examples:$Name: $:$Id: modules,v 1.1.1.2 1996/01/30 00:19:21 tholo Exp $" # # Three different line formats are valid: # key -a aliases... @@ -11,6 +11,7 @@ # Where "options" are composed of: # -i prog Run "prog" on "cvs commit" from top-level of module. # -o prog Run "prog" on "cvs checkout" of module. +# -e prog Run "prog" on "cvs export" of module. # -t prog Run "prog" on "cvs rtag" of module. # -u prog Run "prog" on "cvs update" of module. # -d dir Place module in directory "dir" instead of module name. @@ -32,10 +33,14 @@ world -a . # CVSROOT support CVSROOT -i /usr/local/bin/mkmodules CVSROOT +commitinfo -i /usr/local/bin/mkmodules CVSROOT commitinfo +cvswrappers -i /usr/local/bin/mkmodules CVSROOT cvswrappers +editinfo -i /usr/local/bin/mkmodules CVSROOT editinfo modules -i /usr/local/bin/mkmodules CVSROOT modules loginfo -i /usr/local/bin/mkmodules CVSROOT loginfo -commitinfo -i /usr/local/bin/mkmodules CVSROOT commitinfo rcsinfo -i /usr/local/bin/mkmodules CVSROOT rcsinfo +rcstemplate -i /usr/local/bin/mkmodules CVSROOT rcstemplate +taginfo -i /usr/local/bin/mkmodules CVSROOT taginfo # Add more modules here # diff --git a/gnu/usr.bin/cvs/examples/notify b/gnu/usr.bin/cvs/examples/notify new file mode 100644 index 00000000000..2be867e4f2e --- /dev/null +++ b/gnu/usr.bin/cvs/examples/notify @@ -0,0 +1,11 @@ +# The "notify" file controls where notifications from watches set by +# "cvs watch add" or "cvs edit" are sent. The first entry on a line is +# a regular expression which is tested against the directory that the +# change is being made to, relative to the $CVSROOT. If it matches, +# then the remainder of the line is a filter program that should contain +# one occurrence of %s for the user to notify, and information on its +# standard input. +# +# "ALL" or "DEFAULT" can be used in place of the regular expression. +# +ALL mail %s -s "CVS notification" diff --git a/gnu/usr.bin/cvs/examples/rcsinfo b/gnu/usr.bin/cvs/examples/rcsinfo index 185e1cf3533..1eb161089ca 100644 --- a/gnu/usr.bin/cvs/examples/rcsinfo +++ b/gnu/usr.bin/cvs/examples/rcsinfo @@ -1,5 +1,5 @@ # -# $Id: rcsinfo,v 1.1.1.1 1995/12/19 09:21:43 deraadt Exp $ +#ident "@(#)cvs/examples:$Name: $:$Id: rcsinfo,v 1.1.1.2 1996/01/30 00:19:22 tholo Exp $" # # The "rcsinfo" file is used to control templates with which the editor # is invoked on commit and import. diff --git a/gnu/usr.bin/cvs/examples/taginfo b/gnu/usr.bin/cvs/examples/taginfo index 9e1e8712ce8..04ebfddaac3 100644 --- a/gnu/usr.bin/cvs/examples/taginfo +++ b/gnu/usr.bin/cvs/examples/taginfo @@ -1,11 +1,11 @@ # -# $Id: taginfo,v 1.1.1.1 1995/12/19 09:21:43 deraadt Exp $ +#ident "@(#)cvs/examples:$Name: $:$Id: taginfo,v 1.1.1.2 1996/01/30 00:19:23 tholo Exp $" # # The "taginfo" file is used to control pre-tag checks. # The filter on the right is invoked with the following arguments: # # $1 -- tagname -# $2 -- operation "add" for tag and "del" for tag -d +# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d # $3 -- repository # $4-> file revision [file revision ...] # @@ -22,4 +22,4 @@ # If the name "ALL" appears as a regular expression it is always used # in addition to the first matching regex or "DEFAULT". # -#DEFAULT $CVSROOT/CVSROOT/tag_logging_program +DEFAULT $CVSROOT/CVSROOT/tag_logging_program diff --git a/gnu/usr.bin/cvs/examples/unwrap b/gnu/usr.bin/cvs/examples/unwrap new file mode 100644 index 00000000000..99d48acb996 --- /dev/null +++ b/gnu/usr.bin/cvs/examples/unwrap @@ -0,0 +1,21 @@ +#! /bin/sh +# +# unwrap - extract the combined package (created with wrap) +# +#ident "@(#)cvs/examples:$Name: $:$Id: unwrap,v 1.1.1.1 1996/01/30 00:19:26 tholo Exp $" + +# move the file to a new name with an extension +rm -rf $1.cvswrap +mv $1 $1.cvswrap + +# untar the file + +if `gzip -t $1.cvswrap > /dev/null 2>&1` +then + gzcat -d $1.cvswrap | gnutar --preserve --sparse -x -f - +else + gnutar --preserve --sparse -x -f $1.cvswrap +fi + +# remove the original +rm -rf $1.cvswrap diff --git a/gnu/usr.bin/cvs/examples/wrap b/gnu/usr.bin/cvs/examples/wrap new file mode 100644 index 00000000000..4448771a0a9 --- /dev/null +++ b/gnu/usr.bin/cvs/examples/wrap @@ -0,0 +1,21 @@ +#! /bin/sh +# +# wrap - Combine a directory into a single tar package. +# +#ident "@(#)cvs/examples:$Name: $:$Id: wrap,v 1.1.1.1 1996/01/30 00:19:26 tholo Exp $" + +# This script is always called with the current directory set to +# where the file to be combined exists. but i may get called with a +# path to where cvs first started executing. (this probably should be +# fixed in cvs) so strip out all of the directory information. The +# first sed expression will only work if the path has a leading / +# if it doesn't the one in the if statement will work. +DIRNAME=`echo $1 | sed -e "s|/.*/||g"` +if [ ! -d $DIRNAME ] ; then + DIRNAME=`echo $1 | sed -e "s|.*/||g"` +fi +# +# Now tar up the directory but we now will only get a relative path +# even if the user did a cvs commit . at the top. +# +gnutar --preserve --sparse -cf - $DIRNAME | gzip --no-name --best -c > $2 diff --git a/gnu/usr.bin/cvs/lib/.cvsignore b/gnu/usr.bin/cvs/lib/.cvsignore new file mode 100644 index 00000000000..3ad620cb65e --- /dev/null +++ b/gnu/usr.bin/cvs/lib/.cvsignore @@ -0,0 +1,2 @@ +Makefile +.pure diff --git a/gnu/usr.bin/cvs/lib/ChangeLog b/gnu/usr.bin/cvs/lib/ChangeLog index 0494e1bfefa..ce886e0cea7 100644 --- a/gnu/usr.bin/cvs/lib/ChangeLog +++ b/gnu/usr.bin/cvs/lib/ChangeLog @@ -1,3 +1,146 @@ +Thu Jan 25 00:14:06 1996 Jim Kingdon + + * yesno.c (yesno): fflush stdout as well as stderr. + +Wed Jan 3 18:16:50 1996 Jim Kingdon + + * sighandle.c (SIG_register): Use memset not bzero. + * system.h: Remove defines for index, rindex, bcmp, and bzero. + All the calls to those functions are gone from CVS. + +Tue Jan 2 13:00:00 1996 Jim Kingdon + + Visual C++ lint: + * sighandle.c: Prototype SIG_handle and SIG_defaults. + Use SIG_ERR where appropriate. + +Mon Dec 18 10:15:05 1995 Jim Kingdon + + * rename.c: Check ENOENT rather than existence_error. The latter + is undefined in this file, and including system.h is said to cause + (unspecified) problems. + +Sun Dec 17 23:58:06 1995 Jim Kingdon + + * vasprintf.c: Removed (it is no longer used). + * Makefile.in (SOURCES): Remove vasprintf.c. + +Sat Dec 16 17:18:33 1995 Jim Kingdon + + * vasprintf.c: Added. + * Makefile.in (SOURCES): Add vasprintf.c + +Mon Dec 4 10:54:04 1995 Jim Kingdon + + * getdate.c: Remove #line directives. I know, this is a kludge, + but Visual C++ 2.1 seems to require it (why, I have no idea. It + has no trouble with the #line directives in getdate in CVS 1.6). + +Sat Nov 18 16:20:37 1995 Karl Fogel + + * rename.c: same. + + * mkdir.c: Use new macro `existence_error', instead of comparing + errno to ENOENT directly. + + * system.h (existence_error): new macro, tries to portably ask if + errno represents a file-not-exist error. + +Fri Nov 17 20:08:58 1995 Karl Fogel + + * system.h (NEED_DECOY_PERMISSIONS): moved this section to where + it belongs, duh. + + * getdate.c: if STDC_HEADERS, then just include instead + of declaring malloc() and realloc() to be char *. + + * system.h: ifdef NEED_DECOY_PERMISSIONS, then define the S_I* + permission masks for USR, GRP, and OTH in terms of the simpler + OS/2 masks. + +Wed Nov 15 15:36:03 1995 Karl Fogel + + * system.h: ifdef USE_OWN_TCPIP_H, then include "tcpip.h". Only + OS/2 does this right now. + +Tue Nov 14 18:44:57 1995 Greg A. Woods + + * getdate.c: OK, this one is from SunOS-4.1 yacc and may be more + portable -- at least it compiles silently here! ;-) + +Mon Nov 13 03:53:45 1995 Karl Fogel + + * fnmatch.c: conform to 80 column standard (yes, I'm a pedant). + +Wed Nov 8 11:10:59 1995 Karl Fogel + + * system.h (STAT_MACROS): ifdef S_IFMT, then use it as before; but + if it's not defined, then just do a single mask and assume + acceptance any of non-zero result. Norbert, I trust you'll let me + know if this is unsatisfactory. :-) + Ifdef HAVE_SYS_UTIME_H, then include . Only OS/2 + defines this right now. + +Wed Nov 8 13:18:51 1995 Norbert Kiesel + + * valloc.c: omit malloc declaration (it's already in system.h + which is included and conflicts with on some + systems). + +Tue Nov 7 19:38:48 1995 Norbert Kiesel + + * system.h (STAT_MACROS_BROKEN): undo previous change, because + else all regular files will be identified as links (the mask for + links is S_IFREG|S_IFCHR). + +Mon Nov 6 19:20:56 1995 Karl Fogel + + * system.h (STAT_MACROS_BROKEN): in defining the S_IF* macros, + don't fold to 1 or 0 by first masking with S_IFMT; not all + systems have that macro, and anyway it's only necessary that we + return non-zero. + +Fri Oct 27 13:43:35 1995 Karl Fogel + + * save-cwd.c: use __PROTO instead of __P (see below). + + * getline.h (__PROTO): same as below. + + * save-cwd.h (__PROTO): replaces __P. New name, so don't ask if + already defined. The conflict was that OS/2 w/ IBM C/C++ uses + `__P' for something else, in of all places. + + * system.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB (see + ../src/ChangeLog). + +Tue Oct 24 13:01:25 1995 Norbert Kiesel + + * wait.h: include sys/resource.h if available. This is needed at + least under AIX-3.2 where doesn't include it. + +Mon Oct 23 17:39:11 1995 Norbert Kiesel + + * valloc.c (valloc): change parameter definition + +Sun Oct 22 14:15:44 1995 Jim Meyering (meyering@comco.com) + + * getline.c, getline.h: New files. + * Makefile.in (SOURCES, OBJECTS, HEADERS): Add getline.c, getline.o, + and getline.h, respectively. + +Tue Oct 10 18:01:50 1995 Karl Fogel + + * Makefile.in (cvs_srcdir): define cvs_srcdir to be ../src, then + include it with -I so save_cwd.c can find error.h (for example). + +Sun Oct 8 12:27:57 1995 Peter Wemm + + * system.h: define POSIX_SIGNALS or BSD_SIGNALS if configure has + located all the necessary functions for each "type". + * sighandle.c: detect/use POSIX/BSD reliable signals (especially + for blocking signals in critical sections). Helps prevent stray + locks on interruption. + Mon Oct 2 18:11:23 1995 Jim Blandy * system.h: Doc fix. @@ -19,9 +162,9 @@ Sun Oct 1 21:03:40 1995 Karl Fogel * regex.c: reverted below change. Thu Sep 28 13:37:04 1995 Larry Jones - + * regexp.c: check for ISC. - + Thu Sep 7 19:18:00 1995 Jim Blandy * save-cwd.c: #include and , on systems that diff --git a/gnu/usr.bin/cvs/lib/Makefile.in b/gnu/usr.bin/cvs/lib/Makefile.in index 12f89c8e248..07457034804 100644 --- a/gnu/usr.bin/cvs/lib/Makefile.in +++ b/gnu/usr.bin/cvs/lib/Makefile.in @@ -19,6 +19,7 @@ # $CVSid: @(#)Makefile.in 1.21 94/09/24 $ srcdir = @srcdir@ top_srcdir = @top_srcdir@ +cvs_srcdir = @top_srcdir@/src VPATH = @srcdir@ SHELL = /bin/sh @@ -30,11 +31,11 @@ SOURCES = \ alloca.c \ argmatch.c \ dup2.c \ - error.c \ fnmatch.c \ ftruncate.c \ getdate.c \ getdate.y \ + getline.c \ getopt.c \ getopt1.c \ getwd.c \ @@ -56,12 +57,12 @@ SOURCES = \ xgetwd.c \ yesno.c -HEADERS = getopt.h fnmatch.h regex.h system.h wait.h md5.h error.h save-cwd.h +HEADERS = getline.h getopt.h fnmatch.h regex.h system.h wait.h md5.h save-cwd.h OBJECTS = \ @ALLOCA@ @LIBOBJS@ \ argmatch.o \ - error.o \ + getline.o \ getopt.o \ getopt1.o \ md5.o \ @@ -87,7 +88,8 @@ CPPFLAGS= YACC = @YACC@ .c.o: - $(CC) $(CPPFLAGS) -I.. -I$(srcdir) $(DEFS) $(CFLAGS) -c $< + $(CC) $(CPPFLAGS) -I.. -I$(srcdir) -I$(cvs_srcdir) \ + $(DEFS) $(CFLAGS) -c $< all: libcvs.a .PHONY: all diff --git a/gnu/usr.bin/cvs/lib/fnmatch.c b/gnu/usr.bin/cvs/lib/fnmatch.c index ff17ab0de16..9cb847e8b1d 100644 --- a/gnu/usr.bin/cvs/lib/fnmatch.c +++ b/gnu/usr.bin/cvs/lib/fnmatch.c @@ -23,11 +23,11 @@ Cambridge, MA 02139, USA. */ #include "config.h" #endif -/* Some file systems are case-insensitive. If FOLD_FN_CHAR is #defined, it maps - the character C onto its "canonical" form. In a case-insensitive system, - it would map all alphanumeric characters to lower case. Under Windows NT, - / and \ are both path component separators, so FOLD_FN_CHAR would map them both - to /. */ +/* Some file systems are case-insensitive. If FOLD_FN_CHAR is + #defined, it maps the character C onto its "canonical" form. In a + case-insensitive system, it would map all alphanumeric characters + to lower case. Under Windows NT, / and \ are both path component + separators, so FOLD_FN_CHAR would map them both to /. */ #ifndef FOLD_FN_CHAR #define FOLD_FN_CHAR(c) (c) #endif diff --git a/gnu/usr.bin/cvs/lib/getdate.c b/gnu/usr.bin/cvs/lib/getdate.c index 214ef13642e..d7b9cccf83c 100644 --- a/gnu/usr.bin/cvs/lib/getdate.c +++ b/gnu/usr.bin/cvs/lib/getdate.c @@ -1,25 +1,3 @@ - -/* A Bison parser, made from ./getdate.y with Bison version GNU Bison version 1.22 - */ - -#define YYBISON 1 /* Identify Bison output. */ - -#define tAGO 258 -#define tDAY 259 -#define tDAYZONE 260 -#define tID 261 -#define tMERIDIAN 262 -#define tMINUTE_UNIT 263 -#define tMONTH 264 -#define tMONTH_UNIT 265 -#define tSEC_UNIT 266 -#define tSNUMBER 267 -#define tUNUMBER 268 -#define tZONE 269 -#define tDST 270 - -#line 1 "./getdate.y" - /* ** Originally written by Steven M. Bellovin while ** at the University of North Carolina at Chapel Hill. Later tweaked by @@ -42,6 +20,12 @@ #endif #endif +#if STDC_HEADERS +#include +#else +char *malloc (), *realloc (); +#endif + /* Since the code of getdate.y is not included in the Emacs executable itself, there is no need to #define static in this file. Even if the code were included in the Emacs executable, it probably @@ -104,1214 +88,121 @@ struct timeb { #if defined (STDC_HEADERS) || defined (USG) #include -#endif - -/* Some old versions of bison generate parsers that use bcopy. - That loses on systems that don't provide the function, so we have - to redefine it here. */ -#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy) -#define bcopy(from, to, len) memcpy ((to), (from), (len)) -#endif - -#if defined (STDC_HEADERS) -#include -#endif - -#if defined (HAVE_ALLOCA_H) -#include -#endif - -extern struct tm *gmtime(); -extern struct tm *localtime(); - -#define yyparse getdate_yyparse -#define yylex getdate_yylex -#define yyerror getdate_yyerror - -#if !defined(lint) && !defined(SABER) -static char RCS[] = "$CVSid: @(#)getdate.y 1.11 94/09/21 $"; -#endif /* !defined(lint) && !defined(SABER) */ - -static int yylex (); -static int yyerror (); - -#define EPOCH 1970 -#define HOUR(x) ((time_t)(x) * 60) -#define SECSPERDAY (24L * 60L * 60L) - - -/* -** An entry in the lexical lookup table. -*/ -typedef struct _TABLE { - char *name; - int type; - time_t value; -} TABLE; - - -/* -** Daylight-savings mode: on, off, or not yet known. -*/ -typedef enum _DSTMODE { - DSTon, DSToff, DSTmaybe -} DSTMODE; - -/* -** Meridian: am, pm, or 24-hour style. -*/ -typedef enum _MERIDIAN { - MERam, MERpm, MER24 -} MERIDIAN; - - -/* -** Global variables. We could get rid of most of these by using a good -** union as the yacc stack. (This routine was originally written before -** yacc had the %union construct.) Maybe someday; right now we only use -** the %union very rarely. -*/ -static char *yyInput; -static DSTMODE yyDSTmode; -static time_t yyDayOrdinal; -static time_t yyDayNumber; -static int yyHaveDate; -static int yyHaveDay; -static int yyHaveRel; -static int yyHaveTime; -static int yyHaveZone; -static time_t yyTimezone; -static time_t yyDay; -static time_t yyHour; -static time_t yyMinutes; -static time_t yyMonth; -static time_t yySeconds; -static time_t yyYear; -static MERIDIAN yyMeridian; -static time_t yyRelMonth; -static time_t yyRelSeconds; - - -#line 175 "./getdate.y" -typedef union { - time_t Number; - enum _MERIDIAN Meridian; -} YYSTYPE; - -#ifndef YYLTYPE -typedef - struct yyltype - { - int timestamp; - int first_line; - int first_column; - int last_line; - int last_column; - char *text; - } - yyltype; - -#define YYLTYPE yyltype -#endif - -#include - -#ifndef __cplusplus -#ifndef __STDC__ -#define const -#endif -#endif - - - -#define YYFINAL 52 -#define YYFLAG -32768 -#define YYNTBASE 19 - -#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 29) - -static const char yytranslate[] = { 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 17, 2, 2, 18, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 -}; - -#if YYDEBUG != 0 -static const short yyprhs[] = { 0, - 0, 1, 4, 6, 8, 10, 12, 14, 16, 19, - 24, 29, 36, 43, 45, 47, 50, 52, 55, 58, - 62, 68, 72, 76, 79, 84, 87, 91, 94, 96, - 99, 102, 104, 107, 110, 112, 115, 118, 120, 122, - 123 -}; - -static const short yyrhs[] = { -1, - 19, 20, 0, 21, 0, 22, 0, 24, 0, 23, - 0, 25, 0, 27, 0, 13, 7, 0, 13, 16, - 13, 28, 0, 13, 16, 13, 12, 0, 13, 16, - 13, 16, 13, 28, 0, 13, 16, 13, 16, 13, - 12, 0, 14, 0, 5, 0, 14, 15, 0, 4, - 0, 4, 17, 0, 13, 4, 0, 13, 18, 13, - 0, 13, 18, 13, 18, 13, 0, 13, 12, 12, - 0, 13, 9, 12, 0, 9, 13, 0, 9, 13, - 17, 13, 0, 13, 9, 0, 13, 9, 13, 0, - 26, 3, 0, 26, 0, 13, 8, 0, 12, 8, - 0, 8, 0, 12, 11, 0, 13, 11, 0, 11, - 0, 12, 10, 0, 13, 10, 0, 10, 0, 13, - 0, 0, 7, 0 -}; - -#endif - -#if YYDEBUG != 0 -static const short yyrline[] = { 0, - 189, 190, 193, 196, 199, 202, 205, 208, 211, 217, - 223, 230, 236, 246, 250, 254, 261, 265, 269, 275, - 279, 284, 290, 296, 300, 305, 309, 316, 320, 323, - 326, 329, 332, 335, 338, 341, 344, 347, 352, 379, - 382 -}; - -static const char * const yytname[] = { "$","error","$illegal.","tAGO","tDAY", -"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT", -"tSNUMBER","tUNUMBER","tZONE","tDST","':'","','","'/'","spec","item","time", -"zone","day","date","rel","relunit","number","o_merid","" -}; -#endif - -static const short yyr1[] = { 0, - 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, - 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, - 24, 24, 24, 24, 24, 24, 24, 25, 25, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 27, 28, - 28 -}; - -static const short yyr2[] = { 0, - 0, 2, 1, 1, 1, 1, 1, 1, 2, 4, - 4, 6, 6, 1, 1, 2, 1, 2, 2, 3, - 5, 3, 3, 2, 4, 2, 3, 2, 1, 2, - 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, - 1 -}; - -static const short yydefact[] = { 1, - 0, 17, 15, 32, 0, 38, 35, 0, 39, 14, - 2, 3, 4, 6, 5, 7, 29, 8, 18, 24, - 31, 36, 33, 19, 9, 30, 26, 37, 34, 0, - 0, 0, 16, 28, 0, 23, 27, 22, 40, 20, - 25, 41, 11, 0, 10, 0, 40, 21, 13, 12, - 0, 0 -}; - -static const short yydefgoto[] = { 1, - 11, 12, 13, 14, 15, 16, 17, 18, 45 -}; - -static const short yypact[] = {-32768, - 0, -1,-32768,-32768, 4,-32768,-32768, 25, 11, -8, --32768,-32768,-32768,-32768,-32768,-32768, 21,-32768,-32768, 9, --32768,-32768,-32768,-32768,-32768,-32768, -10,-32768,-32768, 16, - 19, 24,-32768,-32768, 26,-32768,-32768,-32768, 18, 13, --32768,-32768,-32768, 27,-32768, 28, -6,-32768,-32768,-32768, - 38,-32768 -}; - -static const short yypgoto[] = {-32768, --32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -5 -}; - - -#define YYLAST 42 - - -static const short yytable[] = { 51, - 42, 36, 37, 2, 3, 49, 33, 4, 5, 6, - 7, 8, 9, 10, 24, 19, 20, 25, 26, 27, - 28, 29, 30, 34, 42, 35, 31, 38, 32, 43, - 46, 39, 21, 44, 22, 23, 40, 52, 41, 47, - 48, 50 -}; - -static const short yycheck[] = { 0, - 7, 12, 13, 4, 5, 12, 15, 8, 9, 10, - 11, 12, 13, 14, 4, 17, 13, 7, 8, 9, - 10, 11, 12, 3, 7, 17, 16, 12, 18, 12, - 18, 13, 8, 16, 10, 11, 13, 0, 13, 13, - 13, 47 -}; -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/lib/bison.simple" - -/* Skeleton output parser for bison, - Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -#ifndef alloca -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not GNU C. */ -#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) -#include -#else /* not sparc */ -#if defined (MSDOS) && !defined (__TURBOC__) -#include -#else /* not MSDOS, or __TURBOC__ */ -#if defined(_AIX) -#include - #pragma alloca -#else /* not MSDOS, __TURBOC__, or _AIX */ -#ifdef __hpux -#ifdef __cplusplus -extern "C" { -void *alloca (unsigned int); -}; -#else /* not __cplusplus */ -void *alloca (); -#endif /* not __cplusplus */ -#endif /* __hpux */ -#endif /* not _AIX */ -#endif /* not MSDOS, or __TURBOC__ */ -#endif /* not sparc. */ -#endif /* not GNU C. */ -#endif /* alloca not defined. */ - -/* This is the parser code that is written into each bison parser - when the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* Note: there must be only one dollar sign in this file. - It is replaced by the list of actions, each action - as one case of the switch. */ - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 -#define YYEOF 0 -#define YYACCEPT return(0) -#define YYABORT return(1) -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. - This remains here temporarily to ease the - transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ -#define YYFAIL goto yyerrlab -#define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(token, value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { yychar = (token), yylval = (value); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { yyerror ("syntax error: cannot back up"); YYERROR; } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -#ifndef YYPURE -#define YYLEX yylex() -#endif - -#ifdef YYPURE -#ifdef YYLSP_NEEDED -#define YYLEX yylex(&yylval, &yylloc) -#else -#define YYLEX yylex(&yylval) -#endif -#endif - -/* If nonreentrant, generate the variables here */ - -#ifndef YYPURE - -int yychar; /* the lookahead symbol */ -YYSTYPE yylval; /* the semantic value of the */ - /* lookahead symbol */ - -#ifdef YYLSP_NEEDED -YYLTYPE yylloc; /* location data for the lookahead */ - /* symbol */ -#endif - -int yynerrs; /* number of parse errors so far */ -#endif /* not YYPURE */ - -#if YYDEBUG != 0 -int yydebug; /* nonzero means print parse trace */ -/* Since this is uninitialized, it does not stop multiple parsers - from coexisting. */ -#endif - -/* YYINITDEPTH indicates the initial size of the parser's stacks */ - -#ifndef YYINITDEPTH -#define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH is the maximum size the stacks can grow to - (effective only if the built-in stack extension method is used). */ - -#if YYMAXDEPTH == 0 -#undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -#define YYMAXDEPTH 10000 -#endif - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -int yyparse (void); -#endif - -#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ -#define __yy_bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) -#else /* not GNU C or C++ */ -#ifndef __cplusplus - -/* This is the most reliable way to avoid incompatibilities - in available built-in functions on various systems. */ -static void -__yy_bcopy (from, to, count) - char *from; - char *to; - int count; -{ - register char *f = from; - register char *t = to; - register int i = count; - - while (i-- > 0) - *t++ = *f++; -} - -#else /* __cplusplus */ - -/* This is the most reliable way to avoid incompatibilities - in available built-in functions on various systems. */ -static void -__yy_bcopy (char *from, char *to, int count) -{ - register char *f = from; - register char *t = to; - register int i = count; - - while (i-- > 0) - *t++ = *f++; -} - -#endif -#endif - -#line 184 "/usr/lib/bison.simple" -int -yyparse() -{ - register int yystate; - register int yyn; - register short *yyssp; - register YYSTYPE *yyvsp; - int yyerrstatus; /* number of tokens to shift before error messages enabled */ - int yychar1 = 0; /* lookahead token as an internal (translated) token number */ - - short yyssa[YYINITDEPTH]; /* the state stack */ - YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ - - short *yyss = yyssa; /* refer to the stacks thru separate pointers */ - YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ - -#ifdef YYLSP_NEEDED - YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; - -#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -#define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - int yystacksize = YYINITDEPTH; - -#ifdef YYPURE - int yychar; - YYSTYPE yylval; - int yynerrs; -#ifdef YYLSP_NEEDED - YYLTYPE yylloc; -#endif -#endif - - YYSTYPE yyval; /* the variable used to return */ - /* semantic values from the action */ - /* routines */ - - int yylen; - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Starting parse\n"); -#endif - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss - 1; - yyvsp = yyvs; -#ifdef YYLSP_NEEDED - yylsp = yyls; -#endif - -/* Push a new state, which is found in yystate . */ -/* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. */ -yynewstate: - - *++yyssp = yystate; - - if (yyssp >= yyss + yystacksize - 1) - { - /* Give user a chance to reallocate the stack */ - /* Use copies of these so that the &'s don't force the real ones into memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; -#ifdef YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; -#endif - - /* Get the current used size of the three stacks, in elements. */ - int size = yyssp - yyss + 1; - -#ifdef yyoverflow - /* Each stack pointer address is followed by the size of - the data in use in that stack, in bytes. */ -#ifdef YYLSP_NEEDED - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow("parser stack overflow", - &yyss1, size * sizeof (*yyssp), - &yyvs1, size * sizeof (*yyvsp), - &yyls1, size * sizeof (*yylsp), - &yystacksize); -#else - yyoverflow("parser stack overflow", - &yyss1, size * sizeof (*yyssp), - &yyvs1, size * sizeof (*yyvsp), - &yystacksize); -#endif - - yyss = yyss1; yyvs = yyvs1; -#ifdef YYLSP_NEEDED - yyls = yyls1; -#endif -#else /* no yyoverflow */ - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - { - yyerror("parser stack overflow"); - return 2; - } - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); - __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); - yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); - __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); -#ifdef YYLSP_NEEDED - yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); - __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); -#endif -#endif /* no yyoverflow */ - - yyssp = yyss + size - 1; - yyvsp = yyvs + size - 1; -#ifdef YYLSP_NEEDED - yylsp = yyls + size - 1; -#endif - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Stack size increased to %d\n", yystacksize); -#endif - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Entering state %d\n", yystate); -#endif - - goto yybackup; - yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Reading a token: "); -#endif - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Now at end of input.\n"); -#endif - } - else - { - yychar1 = YYTRANSLATE(yychar); - -#if YYDEBUG != 0 - if (yydebug) - { - fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise meaning - of a token, for further debugging info. */ -#ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -#endif - fprintf (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); -#endif - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#ifdef YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* count tokens shifted since error; after three, turn off error status. */ - if (yyerrstatus) yyerrstatus--; - - yystate = yyn; - goto yynewstate; - -/* Do the default action for the current state. */ -yydefault: - - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - -/* Do a reduction. yyn is the number of a rule to reduce with. */ -yyreduce: - yylen = yyr2[yyn]; - if (yylen > 0) - yyval = yyvsp[1-yylen]; /* implement default value of the action */ - -#if YYDEBUG != 0 - if (yydebug) - { - int i; - - fprintf (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) - fprintf (stderr, "%s ", yytname[yyrhs[i]]); - fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - - switch (yyn) { - -case 3: -#line 193 "./getdate.y" -{ - yyHaveTime++; - ; - break;} -case 4: -#line 196 "./getdate.y" -{ - yyHaveZone++; - ; - break;} -case 5: -#line 199 "./getdate.y" -{ - yyHaveDate++; - ; - break;} -case 6: -#line 202 "./getdate.y" -{ - yyHaveDay++; - ; - break;} -case 7: -#line 205 "./getdate.y" -{ - yyHaveRel++; - ; - break;} -case 9: -#line 211 "./getdate.y" -{ - yyHour = yyvsp[-1].Number; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = yyvsp[0].Meridian; - ; - break;} -case 10: -#line 217 "./getdate.y" -{ - yyHour = yyvsp[-3].Number; - yyMinutes = yyvsp[-1].Number; - yySeconds = 0; - yyMeridian = yyvsp[0].Meridian; - ; - break;} -case 11: -#line 223 "./getdate.y" -{ - yyHour = yyvsp[-3].Number; - yyMinutes = yyvsp[-1].Number; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); - ; - break;} -case 12: -#line 230 "./getdate.y" -{ - yyHour = yyvsp[-5].Number; - yyMinutes = yyvsp[-3].Number; - yySeconds = yyvsp[-1].Number; - yyMeridian = yyvsp[0].Meridian; - ; - break;} -case 13: -#line 236 "./getdate.y" -{ - yyHour = yyvsp[-5].Number; - yyMinutes = yyvsp[-3].Number; - yySeconds = yyvsp[-1].Number; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); - ; - break;} -case 14: -#line 246 "./getdate.y" -{ - yyTimezone = yyvsp[0].Number; - yyDSTmode = DSToff; - ; - break;} -case 15: -#line 250 "./getdate.y" -{ - yyTimezone = yyvsp[0].Number; - yyDSTmode = DSTon; - ; - break;} -case 16: -#line 255 "./getdate.y" -{ - yyTimezone = yyvsp[-1].Number; - yyDSTmode = DSTon; - ; - break;} -case 17: -#line 261 "./getdate.y" -{ - yyDayOrdinal = 1; - yyDayNumber = yyvsp[0].Number; - ; - break;} -case 18: -#line 265 "./getdate.y" -{ - yyDayOrdinal = 1; - yyDayNumber = yyvsp[-1].Number; - ; - break;} -case 19: -#line 269 "./getdate.y" -{ - yyDayOrdinal = yyvsp[-1].Number; - yyDayNumber = yyvsp[0].Number; - ; - break;} -case 20: -#line 275 "./getdate.y" -{ - yyMonth = yyvsp[-2].Number; - yyDay = yyvsp[0].Number; - ; - break;} -case 21: -#line 279 "./getdate.y" -{ - yyMonth = yyvsp[-4].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; - ; - break;} -case 22: -#line 284 "./getdate.y" -{ - /* ISO 8601 format. yyyy-mm-dd. */ - yyYear = yyvsp[-2].Number; - yyMonth = -yyvsp[-1].Number; - yyDay = -yyvsp[0].Number; - ; - break;} -case 23: -#line 290 "./getdate.y" -{ - /* e.g. 17-JUN-1992. */ - yyDay = yyvsp[-2].Number; - yyMonth = yyvsp[-1].Number; - yyYear = -yyvsp[0].Number; - ; - break;} -case 24: -#line 296 "./getdate.y" -{ - yyMonth = yyvsp[-1].Number; - yyDay = yyvsp[0].Number; - ; - break;} -case 25: -#line 300 "./getdate.y" -{ - yyMonth = yyvsp[-3].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; - ; - break;} -case 26: -#line 305 "./getdate.y" -{ - yyMonth = yyvsp[0].Number; - yyDay = yyvsp[-1].Number; - ; - break;} -case 27: -#line 309 "./getdate.y" -{ - yyMonth = yyvsp[-1].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; - ; - break;} -case 28: -#line 316 "./getdate.y" -{ - yyRelSeconds = -yyRelSeconds; - yyRelMonth = -yyRelMonth; - ; - break;} -case 30: -#line 323 "./getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; - ; - break;} -case 31: -#line 326 "./getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; - ; - break;} -case 32: -#line 329 "./getdate.y" -{ - yyRelSeconds += yyvsp[0].Number * 60L; - ; - break;} -case 33: -#line 332 "./getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number; - ; - break;} -case 34: -#line 335 "./getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number; - ; - break;} -case 35: -#line 338 "./getdate.y" -{ - yyRelSeconds++; - ; - break;} -case 36: -#line 341 "./getdate.y" -{ - yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; - ; - break;} -case 37: -#line 344 "./getdate.y" -{ - yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; - ; - break;} -case 38: -#line 347 "./getdate.y" -{ - yyRelMonth += yyvsp[0].Number; - ; - break;} -case 39: -#line 352 "./getdate.y" -{ - if (yyHaveTime && yyHaveDate && !yyHaveRel) - yyYear = yyvsp[0].Number; - else { - if(yyvsp[0].Number>10000) { - yyHaveDate++; - yyDay= (yyvsp[0].Number)%100; - yyMonth= (yyvsp[0].Number/100)%100; - yyYear = yyvsp[0].Number/10000; - } - else { - yyHaveTime++; - if (yyvsp[0].Number < 100) { - yyHour = yyvsp[0].Number; - yyMinutes = 0; - } - else { - yyHour = yyvsp[0].Number / 100; - yyMinutes = yyvsp[0].Number % 100; - } - yySeconds = 0; - yyMeridian = MER24; - } - } - ; - break;} -case 40: -#line 379 "./getdate.y" -{ - yyval.Meridian = MER24; - ; - break;} -case 41: -#line 382 "./getdate.y" -{ - yyval.Meridian = yyvsp[0].Meridian; - ; - break;} -} - /* the action file gets copied in in place of this dollarsign */ -#line 465 "/usr/lib/bison.simple" - - yyvsp -= yylen; - yyssp -= yylen; -#ifdef YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG != 0 - if (yydebug) - { - short *ssp1 = yyss - 1; - fprintf (stderr, "state stack now"); - while (ssp1 != yyssp) - fprintf (stderr, " %d", *++ssp1); - fprintf (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; - -#ifdef YYLSP_NEEDED - yylsp++; - if (yylen == 0) - { - yylsp->first_line = yylloc.first_line; - yylsp->first_column = yylloc.first_column; - yylsp->last_line = (yylsp-1)->last_line; - yylsp->last_column = (yylsp-1)->last_column; - yylsp->text = 0; - } - else - { - yylsp->last_line = (yylsp+yylen-1)->last_line; - yylsp->last_column = (yylsp+yylen-1)->last_column; - } -#endif - - /* Now "shift" the result of the reduction. - Determine what state that goes to, - based on the state we popped back to - and the rule number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - -yyerrlab: /* here on detecting error */ - - if (! yyerrstatus) - /* If not already recovering from an error, report this error. */ - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - int size = 0; - char *msg; - int x, count; - - count = 0; - /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ - for (x = (yyn < 0 ? -yyn : 0); - x < (sizeof(yytname) / sizeof(char *)); x++) - if (yycheck[x + yyn] == x) - size += strlen(yytname[x]) + 15, count++; - msg = (char *) malloc(size + 15); - if (msg != 0) - { - strcpy(msg, "parse error"); - - if (count < 5) - { - count = 0; - for (x = (yyn < 0 ? -yyn : 0); - x < (sizeof(yytname) / sizeof(char *)); x++) - if (yycheck[x + yyn] == x) - { - strcat(msg, count == 0 ? ", expecting `" : " or `"); - strcat(msg, yytname[x]); - strcat(msg, "'"); - count++; - } - } - yyerror(msg); - free(msg); - } - else - yyerror ("parse error; also virtual memory exceeded"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror("parse error"); - } - - goto yyerrlab1; -yyerrlab1: /* here on error raised explicitly by an action */ - - if (yyerrstatus == 3) - { - /* if just tried and failed to reuse lookahead token after an error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; +#endif -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +/* Some old versions of bison generate parsers that use bcopy. + That loses on systems that don't provide the function, so we have + to redefine it here. */ +#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy) +#define bcopy(from, to, len) memcpy ((to), (from), (len)) #endif - yychar = YYEMPTY; - } +#if defined (STDC_HEADERS) +#include +#endif - /* Else will try to reuse lookahead token - after shifting the error token. */ +#if defined (HAVE_ALLOCA_H) +#include +#endif - yyerrstatus = 3; /* Each real token shifted decrements this */ +extern struct tm *gmtime(); +extern struct tm *localtime(); - goto yyerrhandle; +#define yyparse getdate_yyparse +#define yylex getdate_yylex +#define yyerror getdate_yyerror -yyerrdefault: /* current state does not do anything special for the error token. */ +#if !defined(lint) && !defined(SABER) +static char RCS[] = "$CVSid: @(#)getdate.y 1.11 94/09/21 $"; +#endif /* !defined(lint) && !defined(SABER) */ -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ - if (yyn) goto yydefault; -#endif +static int yylex (); +static int yyerror (); -yyerrpop: /* pop the current state because it cannot handle the error token */ +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) - if (yyssp == yyss) YYABORT; - yyvsp--; - yystate = *--yyssp; -#ifdef YYLSP_NEEDED - yylsp--; -#endif -#if YYDEBUG != 0 - if (yydebug) - { - short *ssp1 = yyss - 1; - fprintf (stderr, "Error: state stack now"); - while (ssp1 != yyssp) - fprintf (stderr, " %d", *++ssp1); - fprintf (stderr, "\n"); - } -#endif +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; -yyerrhandle: - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - if (yyn == YYFINAL) - YYACCEPT; +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; -#if YYDEBUG != 0 - if (yydebug) - fprintf(stderr, "Shifting error token, "); -#endif - *++yyvsp = yylval; -#ifdef YYLSP_NEEDED - *++yylsp = yylloc; +typedef union { + time_t Number; + enum _MERIDIAN Meridian; +} YYSTYPE; +# define tAGO 257 +# define tDAY 258 +# define tDAYZONE 259 +# define tID 260 +# define tMERIDIAN 261 +# define tMINUTE_UNIT 262 +# define tMONTH 263 +# define tMONTH_UNIT 264 +# define tSEC_UNIT 265 +# define tSNUMBER 266 +# define tUNUMBER 267 +# define tZONE 268 +# define tDST 269 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 +extern int yychar; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 #endif +YYSTYPE yylval, yyval; +# define YYERRCODE 256 - yystate = yyn; - goto yynewstate; -} -#line 387 "./getdate.y" /* Month and day table. */ @@ -1922,3 +813,800 @@ main(ac, av) /* NOTREACHED */ } #endif /* defined(TEST) */ +int yyexca[] ={ +-1, 1, + 0, -1, + -2, 0, + }; +# define YYNPROD 42 +# define YYLAST 228 +int yyact[]={ + + 13, 11, 22, 28, 16, 12, 18, 17, 15, 9, + 10, 38, 39, 20, 48, 44, 47, 46, 36, 43, + 50, 32, 35, 34, 33, 29, 37, 31, 41, 45, + 40, 30, 14, 8, 7, 6, 5, 4, 3, 2, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 21, 0, 0, 19, 25, 24, 27, + 26, 23, 44, 0, 0, 0, 0, 42 }; +int yypact[]={ + + -1000, -258, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -45, + -266, -1000, -242, -13, -230, -241, -1000, -1000, -1000, -1000, + -245, -1000, -249, -240, -255, -1000, -1000, -1000, -1000, -14, + -1000, -1000, -1000, -1000, -1000, -39, -18, -1000, -1000, -1000, + -250, -1000, -1000, -251, -1000, -253, -1000, -246, -1000, -1000, + -1000 }; +int yypgo[]={ + + 0, 28, 40, 39, 38, 37, 36, 35, 34, 33, + 32 }; +int yyr1[]={ + + 0, 2, 2, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 5, 5, 5, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, + 1, 1 }; +int yyr2[]={ + + 0, 0, 4, 3, 3, 3, 3, 3, 2, 5, + 9, 9, 13, 13, 3, 3, 5, 3, 5, 5, + 7, 11, 7, 7, 5, 9, 5, 7, 5, 2, + 5, 5, 3, 5, 5, 3, 5, 5, 3, 3, + 1, 3 }; +int yychk[]={ + + -1000, -2, -3, -4, -5, -6, -7, -8, -9, 267, + 268, 259, 263, 258, -10, 266, 262, 265, 264, 261, + 58, 258, 47, 266, 263, 262, 265, 264, 269, 267, + 44, 257, 262, 265, 264, 267, 267, 266, 266, 267, + 44, -1, 266, 58, 261, 47, 267, 267, 267, -1, + 266 }; +int yydef[]={ + + 1, -2, 2, 3, 4, 5, 6, 7, 8, 39, + 14, 15, 0, 17, 29, 0, 32, 35, 38, 9, + 0, 19, 0, 0, 26, 30, 34, 37, 16, 24, + 18, 28, 31, 33, 36, 40, 20, 22, 23, 27, + 0, 10, 11, 0, 41, 0, 25, 40, 21, 12, + 13 }; +typedef struct { char *t_name; int t_val; } yytoktype; +#ifndef YYDEBUG +# define YYDEBUG 0 /* don't allow debugging */ +#endif + +#if YYDEBUG + +yytoktype yytoks[] = +{ + "tAGO", 257, + "tDAY", 258, + "tDAYZONE", 259, + "tID", 260, + "tMERIDIAN", 261, + "tMINUTE_UNIT", 262, + "tMONTH", 263, + "tMONTH_UNIT", 264, + "tSEC_UNIT", 265, + "tSNUMBER", 266, + "tUNUMBER", 267, + "tZONE", 268, + "tDST", 269, + "-unknown-", -1 /* ends search */ +}; + +char * yyreds[] = +{ + "-no such reduction-", + "spec : /* empty */", + "spec : spec item", + "item : time", + "item : zone", + "item : date", + "item : day", + "item : rel", + "item : number", + "time : tUNUMBER tMERIDIAN", + "time : tUNUMBER ':' tUNUMBER o_merid", + "time : tUNUMBER ':' tUNUMBER tSNUMBER", + "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid", + "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER", + "zone : tZONE", + "zone : tDAYZONE", + "zone : tZONE tDST", + "day : tDAY", + "day : tDAY ','", + "day : tUNUMBER tDAY", + "date : tUNUMBER '/' tUNUMBER", + "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", + "date : tUNUMBER tSNUMBER tSNUMBER", + "date : tUNUMBER tMONTH tSNUMBER", + "date : tMONTH tUNUMBER", + "date : tMONTH tUNUMBER ',' tUNUMBER", + "date : tUNUMBER tMONTH", + "date : tUNUMBER tMONTH tUNUMBER", + "rel : relunit tAGO", + "rel : relunit", + "relunit : tUNUMBER tMINUTE_UNIT", + "relunit : tSNUMBER tMINUTE_UNIT", + "relunit : tMINUTE_UNIT", + "relunit : tSNUMBER tSEC_UNIT", + "relunit : tUNUMBER tSEC_UNIT", + "relunit : tSEC_UNIT", + "relunit : tSNUMBER tMONTH_UNIT", + "relunit : tUNUMBER tMONTH_UNIT", + "relunit : tMONTH_UNIT", + "number : tUNUMBER", + "o_merid : /* empty */", + "o_merid : tMERIDIAN", +}; +#endif /* YYDEBUG */ +/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */ + +/* +** Skeleton parser driver for yacc output +*/ + +/* +** yacc user known macros and defines +*/ +#define YYERROR goto yyerrlab +#define YYACCEPT { free(yys); free(yyv); return(0); } +#define YYABORT { free(yys); free(yyv); return(1); } +#define YYBACKUP( newtoken, newvalue )\ +{\ + if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\ + {\ + yyerror( "syntax error - cannot backup" );\ + goto yyerrlab;\ + }\ + yychar = newtoken;\ + yystate = *yyps;\ + yylval = newvalue;\ + goto yynewstate;\ +} +#define YYRECOVERING() (!!yyerrflag) +#ifndef YYDEBUG +# define YYDEBUG 1 /* make debugging available */ +#endif + +/* +** user known globals +*/ +int yydebug; /* set to 1 to get debugging */ + +/* +** driver internal defines +*/ +#define YYFLAG (-1000) + +/* +** static variables used by the parser +*/ +static YYSTYPE *yyv; /* value stack */ +static int *yys; /* state stack */ + +static YYSTYPE *yypv; /* top of value stack */ +static int *yyps; /* top of state stack */ + +static int yystate; /* current state */ +static int yytmp; /* extra var (lasts between blocks) */ + +int yynerrs; /* number of errors */ + +int yyerrflag; /* error recovery flag */ +int yychar; /* current input token number */ + + +/* +** yyparse - return 0 if worked, 1 if syntax error not recovered from +*/ +int +yyparse() +{ + register YYSTYPE *yypvt; /* top of value stack for $vars */ + unsigned yymaxdepth = YYMAXDEPTH; + + /* + ** Initialize externals - yyparse may be called more than once + */ + yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE)); + yys = (int*)malloc(yymaxdepth*sizeof(int)); + if (!yyv || !yys) + { + yyerror( "out of memory" ); + return(1); + } + yypv = &yyv[-1]; + yyps = &yys[-1]; + yystate = 0; + yytmp = 0; + yynerrs = 0; + yyerrflag = 0; + yychar = -1; + + goto yystack; + { + register YYSTYPE *yy_pv; /* top of value stack */ + register int *yy_ps; /* top of state stack */ + register int yy_state; /* current state */ + register int yy_n; /* internal state number info */ + + /* + ** get globals into registers. + ** branch to here only if YYBACKUP was called. + */ + yynewstate: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + goto yy_newstate; + + /* + ** get globals into registers. + ** either we just started, or we just finished a reduction + */ + yystack: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + + /* + ** top of for (;;) loop while no reductions done + */ + yy_stack: + /* + ** put a state and value onto the stacks + */ +#if YYDEBUG + /* + ** if debugging, look up token value in list of value vs. + ** name pairs. 0 and negative (-1) are special values. + ** Note: linear search is used since time is not a real + ** consideration while debugging. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "State %d, token ", yy_state ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */ + { + /* + ** reallocate and recover. Note that pointers + ** have to be reset, or bad things will happen + */ + int yyps_index = (yy_ps - yys); + int yypv_index = (yy_pv - yyv); + int yypvt_index = (yypvt - yyv); + yymaxdepth += YYMAXDEPTH; + yyv = (YYSTYPE*)realloc((char*)yyv, + yymaxdepth * sizeof(YYSTYPE)); + yys = (int*)realloc((char*)yys, + yymaxdepth * sizeof(int)); + if (!yyv || !yys) + { + yyerror( "yacc stack overflow" ); + return(1); + } + yy_ps = yys + yyps_index; + yy_pv = yyv + yypv_index; + yypvt = yyv + yypvt_index; + } + *yy_ps = yy_state; + *++yy_pv = yyval; + + /* + ** we have a new state - find out what to do + */ + yy_newstate: + if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG ) + goto yydefault; /* simple state */ +#if YYDEBUG + /* + ** if debugging, need to mark whether new token grabbed + */ + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) ) + goto yydefault; + if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/ + { + yychar = -1; + yyval = yylval; + yy_state = yy_n; + if ( yyerrflag > 0 ) + yyerrflag--; + goto yy_stack; + } + + yydefault: + if ( ( yy_n = yydef[ yy_state ] ) == -2 ) + { +#if YYDEBUG + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + /* + ** look through exception table + */ + { + register int *yyxi = yyexca; + + while ( ( *yyxi != -1 ) || + ( yyxi[1] != yy_state ) ) + { + yyxi += 2; + } + while ( ( *(yyxi += 2) >= 0 ) && + ( *yyxi != yychar ) ) + ; + if ( ( yy_n = yyxi[1] ) < 0 ) + YYACCEPT; + } + } + + /* + ** check for syntax error + */ + if ( yy_n == 0 ) /* have an error */ + { + /* no worry about speed here! */ + switch ( yyerrflag ) + { + case 0: /* new error */ + yyerror( "syntax error" ); + goto skip_init; + yyerrlab: + /* + ** get globals into registers. + ** we have a user generated syntax type error + */ + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + yynerrs++; + skip_init: + case 1: + case 2: /* incompletely recovered error */ + /* try again... */ + yyerrflag = 3; + /* + ** find state where "error" is a legal + ** shift action + */ + while ( yy_ps >= yys ) + { + yy_n = yypact[ *yy_ps ] + YYERRCODE; + if ( yy_n >= 0 && yy_n < YYLAST && + yychk[yyact[yy_n]] == YYERRCODE) { + /* + ** simulate shift of "error" + */ + yy_state = yyact[ yy_n ]; + goto yy_stack; + } + /* + ** current state has no shift on + ** "error", pop stack + */ +#if YYDEBUG +# define _POP_ "Error recovery pops state %d, uncovers state %d\n" + if ( yydebug ) + (void)printf( _POP_, *yy_ps, + yy_ps[-1] ); +# undef _POP_ +#endif + yy_ps--; + yy_pv--; + } + /* + ** there is no state on stack with "error" as + ** a valid shift. give up. + */ + YYABORT; + case 3: /* no shift yet; eat a token */ +#if YYDEBUG + /* + ** if debugging, look up token in list of + ** pairs. 0 and negative shouldn't occur, + ** but since timing doesn't matter when + ** debugging, it doesn't hurt to leave the + ** tests here. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "Error recovery discards " ); + if ( yychar == 0 ) + (void)printf( "token end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "token -none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "token %s\n", + yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( yychar == 0 ) /* reached EOF. quit */ + YYABORT; + yychar = -1; + goto yy_newstate; + } + }/* end if ( yy_n == 0 ) */ + /* + ** reduction by production yy_n + ** put stack tops, etc. so things right after switch + */ +#if YYDEBUG + /* + ** if debugging, print the string that is the user's + ** specification of the reduction which is just about + ** to be done. + */ + if ( yydebug ) + (void)printf( "Reduce by (%d) \"%s\"\n", + yy_n, yyreds[ yy_n ] ); +#endif + yytmp = yy_n; /* value to switch over */ + yypvt = yy_pv; /* $vars top of value stack */ + /* + ** Look in goto table for next state + ** Sorry about using yy_state here as temporary + ** register variable, but why not, if it works... + ** If yyr2[ yy_n ] doesn't have the low order bit + ** set, then there is no action to be done for + ** this reduction. So, no saving & unsaving of + ** registers done. The only difference between the + ** code just after the if and the body of the if is + ** the goto yy_stack in the body. This way the test + ** can be made before the choice of what to do is needed. + */ + { + /* length of production doubled with extra bit */ + register int yy_len = yyr2[ yy_n ]; + + if ( !( yy_len & 01 ) ) + { + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = + yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + goto yy_stack; + } + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + } + /* save until reenter driver code */ + yystate = yy_state; + yyps = yy_ps; + yypv = yy_pv; + } + /* + ** code supplied by user is placed in this switch + */ + switch( yytmp ) + { + +case 3: +{ + yyHaveTime++; + } break; +case 4: +{ + yyHaveZone++; + } break; +case 5: +{ + yyHaveDate++; + } break; +case 6: +{ + yyHaveDay++; + } break; +case 7: +{ + yyHaveRel++; + } break; +case 9: +{ + yyHour = yypvt[-1].Number; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = yypvt[-0].Meridian; + } break; +case 10: +{ + yyHour = yypvt[-3].Number; + yyMinutes = yypvt[-1].Number; + yySeconds = 0; + yyMeridian = yypvt[-0].Meridian; + } break; +case 11: +{ + yyHour = yypvt[-3].Number; + yyMinutes = yypvt[-1].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - (yypvt[-0].Number % 100 + (yypvt[-0].Number / 100) * 60); + } break; +case 12: +{ + yyHour = yypvt[-5].Number; + yyMinutes = yypvt[-3].Number; + yySeconds = yypvt[-1].Number; + yyMeridian = yypvt[-0].Meridian; + } break; +case 13: +{ + yyHour = yypvt[-5].Number; + yyMinutes = yypvt[-3].Number; + yySeconds = yypvt[-1].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - (yypvt[-0].Number % 100 + (yypvt[-0].Number / 100) * 60); + } break; +case 14: +{ + yyTimezone = yypvt[-0].Number; + yyDSTmode = DSToff; + } break; +case 15: +{ + yyTimezone = yypvt[-0].Number; + yyDSTmode = DSTon; + } break; +case 16: +{ + yyTimezone = yypvt[-1].Number; + yyDSTmode = DSTon; + } break; +case 17: +{ + yyDayOrdinal = 1; + yyDayNumber = yypvt[-0].Number; + } break; +case 18: +{ + yyDayOrdinal = 1; + yyDayNumber = yypvt[-1].Number; + } break; +case 19: +{ + yyDayOrdinal = yypvt[-1].Number; + yyDayNumber = yypvt[-0].Number; + } break; +case 20: +{ + yyMonth = yypvt[-2].Number; + yyDay = yypvt[-0].Number; + } break; +case 21: +{ + yyMonth = yypvt[-4].Number; + yyDay = yypvt[-2].Number; + yyYear = yypvt[-0].Number; + } break; +case 22: +{ + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = yypvt[-2].Number; + yyMonth = -yypvt[-1].Number; + yyDay = -yypvt[-0].Number; + } break; +case 23: +{ + /* e.g. 17-JUN-1992. */ + yyDay = yypvt[-2].Number; + yyMonth = yypvt[-1].Number; + yyYear = -yypvt[-0].Number; + } break; +case 24: +{ + yyMonth = yypvt[-1].Number; + yyDay = yypvt[-0].Number; + } break; +case 25: +{ + yyMonth = yypvt[-3].Number; + yyDay = yypvt[-2].Number; + yyYear = yypvt[-0].Number; + } break; +case 26: +{ + yyMonth = yypvt[-0].Number; + yyDay = yypvt[-1].Number; + } break; +case 27: +{ + yyMonth = yypvt[-1].Number; + yyDay = yypvt[-2].Number; + yyYear = yypvt[-0].Number; + } break; +case 28: +{ + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } break; +case 30: +{ + yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number * 60L; + } break; +case 31: +{ + yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number * 60L; + } break; +case 32: +{ + yyRelSeconds += yypvt[-0].Number * 60L; + } break; +case 33: +{ + yyRelSeconds += yypvt[-1].Number; + } break; +case 34: +{ + yyRelSeconds += yypvt[-1].Number; + } break; +case 35: +{ + yyRelSeconds++; + } break; +case 36: +{ + yyRelMonth += yypvt[-1].Number * yypvt[-0].Number; + } break; +case 37: +{ + yyRelMonth += yypvt[-1].Number * yypvt[-0].Number; + } break; +case 38: +{ + yyRelMonth += yypvt[-0].Number; + } break; +case 39: +{ + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = yypvt[-0].Number; + else { + if(yypvt[-0].Number>10000) { + yyHaveDate++; + yyDay= (yypvt[-0].Number)%100; + yyMonth= (yypvt[-0].Number/100)%100; + yyYear = yypvt[-0].Number/10000; + } + else { + yyHaveTime++; + if (yypvt[-0].Number < 100) { + yyHour = yypvt[-0].Number; + yyMinutes = 0; + } + else { + yyHour = yypvt[-0].Number / 100; + yyMinutes = yypvt[-0].Number % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + } break; +case 40: +{ + yyval.Meridian = MER24; + } break; +case 41: +{ + yyval.Meridian = yypvt[-0].Meridian; + } break; + } + goto yystack; /* reset registers in driver code */ +} diff --git a/gnu/usr.bin/cvs/lib/getline.c b/gnu/usr.bin/cvs/lib/getline.c new file mode 100644 index 00000000000..c69946148f6 --- /dev/null +++ b/gnu/usr.bin/cvs/lib/getline.c @@ -0,0 +1,126 @@ +/* getline.c -- Replacement for GNU C library function getline + +Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#define NDEBUG +#include + +#if STDC_HEADERS +#include +#else +char *malloc (), *realloc (); +#endif + +/* Always add at least this many bytes when extending the buffer. */ +#define MIN_CHUNK 64 + +/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR + + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from + malloc (or NULL), pointing to *N characters of space. It is realloc'd + as necessary. Return the number of characters read (not including the + null terminator), or -1 on error or EOF. */ + +int +getstr (lineptr, n, stream, terminator, offset) + char **lineptr; + size_t *n; + FILE *stream; + char terminator; + int offset; +{ + int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ + char *read_pos; /* Where we're reading into *LINEPTR. */ + int ret; + + if (!lineptr || !n || !stream) + return -1; + + if (!*lineptr) + { + *n = MIN_CHUNK; + *lineptr = malloc (*n); + if (!*lineptr) + return -1; + } + + nchars_avail = *n - offset; + read_pos = *lineptr + offset; + + for (;;) + { + register int c = getc (stream); + + /* We always want at least one char left in the buffer, since we + always (unless we get an error while reading the first char) + NUL-terminate the line buffer. */ + + assert(*n - nchars_avail == read_pos - *lineptr); + if (nchars_avail < 2) + { + if (*n > MIN_CHUNK) + *n *= 2; + else + *n += MIN_CHUNK; + + nchars_avail = *n + *lineptr - read_pos; + *lineptr = realloc (*lineptr, *n); + if (!*lineptr) + return -1; + read_pos = *n - nchars_avail + *lineptr; + assert(*n - nchars_avail == read_pos - *lineptr); + } + + if (c == EOF || ferror (stream)) + { + /* Return partial line, if any. */ + if (read_pos == *lineptr) + return -1; + else + break; + } + + *read_pos++ = c; + nchars_avail--; + + if (c == terminator) + /* Return the line. */ + break; + } + + /* Done - NUL terminate and return the number of chars read. */ + *read_pos = '\0'; + + ret = read_pos - (*lineptr + offset); + return ret; +} + +int +getline (lineptr, n, stream) + char **lineptr; + size_t *n; + FILE *stream; +{ + return getstr (lineptr, n, stream, '\n', 0); +} diff --git a/gnu/usr.bin/cvs/lib/getline.h b/gnu/usr.bin/cvs/lib/getline.h new file mode 100644 index 00000000000..30bcc258373 --- /dev/null +++ b/gnu/usr.bin/cvs/lib/getline.h @@ -0,0 +1,15 @@ +#ifndef _getline_h_ +#define _getline_h_ 1 + +#include + +#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +#define __PROTO(args) args +#else +#define __PROTO(args) () +#endif /* GCC. */ + +int + getline __PROTO ((char **_lineptr, size_t *_n, FILE *_stream)); + +#endif /* _getline_h_ */ diff --git a/gnu/usr.bin/cvs/lib/mkdir.c b/gnu/usr.bin/cvs/lib/mkdir.c index a70c1d86619..89ed4b6c6f0 100644 --- a/gnu/usr.bin/cvs/lib/mkdir.c +++ b/gnu/usr.bin/cvs/lib/mkdir.c @@ -54,7 +54,7 @@ mkdir (dpath, dmode) } /* If stat fails for a reason other than non-existence, return error. */ - if (errno != ENOENT) + if (! existence_error (errno)) return -1; cpid = fork (); diff --git a/gnu/usr.bin/cvs/lib/rename.c b/gnu/usr.bin/cvs/lib/rename.c index a36713b1687..ce2805b3a04 100644 --- a/gnu/usr.bin/cvs/lib/rename.c +++ b/gnu/usr.bin/cvs/lib/rename.c @@ -39,6 +39,8 @@ rename (from, to) if (stat (from, &from_stats) == 0) { + /* We don't check existence_error because the systems which need it + have rename(). */ if (unlink (to) && errno != ENOENT) return -1; if ((from_stats.st_mode & S_IFMT) == S_IFDIR) @@ -72,6 +74,8 @@ rename (from, to) } else { + /* We don't check existence_error because the systems which need it + have rename(). */ if (link (from, to) == 0 && (unlink (from) == 0 || errno == ENOENT)) return 0; } diff --git a/gnu/usr.bin/cvs/lib/save-cwd.c b/gnu/usr.bin/cvs/lib/save-cwd.c index 5e48d4f5912..1bdf7911510 100644 --- a/gnu/usr.bin/cvs/lib/save-cwd.c +++ b/gnu/usr.bin/cvs/lib/save-cwd.c @@ -34,7 +34,7 @@ extern int errno; #include "save-cwd.h" #include "error.h" -char *xgetwd __P((void)); +char *xgetwd __PROTO((void)); /* Record the location of the current working directory in CWD so that the program may change to other directories and later use restore_cwd diff --git a/gnu/usr.bin/cvs/lib/save-cwd.h b/gnu/usr.bin/cvs/lib/save-cwd.h index 4b31071c452..f9802f8ca2f 100644 --- a/gnu/usr.bin/cvs/lib/save-cwd.h +++ b/gnu/usr.bin/cvs/lib/save-cwd.h @@ -7,16 +7,14 @@ struct saved_cwd char *name; }; -#ifndef __P #if defined (__GNUC__) || (defined (__STDC__) && __STDC__) -#define __P(args) args +#define __PROTO(args) args #else -#define __P(args) () +#define __PROTO(args) () #endif /* GCC. */ -#endif /* Not __P. */ -int save_cwd __P((struct saved_cwd *cwd)); -int restore_cwd __P((const struct saved_cwd *cwd, const char *dest)); -void free_cwd __P((struct saved_cwd *cwd)); +int save_cwd __PROTO((struct saved_cwd *cwd)); +int restore_cwd __PROTO((const struct saved_cwd *cwd, const char *dest)); +void free_cwd __PROTO((struct saved_cwd *cwd)); #endif /* SAVE_CWD_H */ diff --git a/gnu/usr.bin/cvs/lib/sighandle.c b/gnu/usr.bin/cvs/lib/sighandle.c index 1db41776634..ace7db33d24 100644 --- a/gnu/usr.bin/cvs/lib/sighandle.c +++ b/gnu/usr.bin/cvs/lib/sighandle.c @@ -37,11 +37,21 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include "system.h" #include #include #include +/* Add prototype support. */ +#ifndef PROTO +#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) +#define PROTO(ARGS) ARGS +#else +#define PROTO(ARGS) () +#endif +#endif + #ifdef STDC_HEADERS #include #else @@ -54,10 +64,6 @@ char *malloc(); #endif /* __STDC__ */ #endif /* STDC_HEADERS */ -#ifdef _MINIX -#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */ -#endif - /* Define the highest signal number (usually) */ #ifndef SIGMAX #define SIGMAX 64 @@ -78,19 +84,19 @@ static struct SIG_hlist **SIG_handlers; /* Define array of default signal vectors */ -#ifdef POSIX +#ifdef POSIX_SIGNALS static struct sigaction *SIG_defaults; #else #ifdef BSD_SIGNALS static struct sigvec *SIG_defaults; #else -static RETSIGTYPE (**SIG_defaults)(); +static RETSIGTYPE (**SIG_defaults) PROTO ((int)); #endif #endif /* Critical section housekeeping */ static int SIG_crSectNest = 0; /* Nesting level */ -#ifdef POSIX +#ifdef POSIX_SIGNALS static sigset_t SIG_crSectMask; /* Signal mask */ #else static int SIG_crSectMask; /* Signal mask */ @@ -103,14 +109,14 @@ static int SIG_crSectMask; /* Signal mask */ static int SIG_init() { int i; -#ifdef POSIX +#ifdef POSIX_SIGNALS sigset_t sigset_test; #endif if (SIG_defaults && SIG_handlers) /* already allocated */ return (0); -#ifdef POSIX +#ifdef POSIX_SIGNALS (void) sigfillset(&sigset_test); for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++) ; @@ -129,8 +135,8 @@ static int SIG_init() calloc(i, sizeof(struct sigvec)); #else if (!SIG_defaults) - SIG_defaults = (RETSIGTYPE (**)()) - calloc(i, sizeof(RETSIGTYPE (**)())); + SIG_defaults = (RETSIGTYPE (**) PROTO ((int)) ) + calloc(i, sizeof(RETSIGTYPE (**) PROTO ((int)) )); #endif SIG_crSectMask = 0; #endif @@ -144,6 +150,7 @@ static int SIG_init() * The following invokes each signal handler in the reverse order in which * they were registered. */ +static RETSIGTYPE SIG_handle PROTO ((int)); static RETSIGTYPE SIG_handle(sig) int sig; @@ -175,7 +182,7 @@ RETSIGTYPE (*fn)(); { int val; struct SIG_hlist *this; -#ifdef POSIX +#ifdef POSIX_SIGNALS struct sigaction act; sigset_t sigset_mask, sigset_omask; #else @@ -191,7 +198,7 @@ RETSIGTYPE (*fn)(); val = 0; /* Block this signal while we look at handler chain */ -#ifdef POSIX +#ifdef POSIX_SIGNALS (void) sigemptyset(&sigset_mask); (void) sigaddset(&sigset_mask, sig); (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); @@ -220,19 +227,18 @@ RETSIGTYPE (*fn)(); if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) { -#ifdef POSIX +#ifdef POSIX_SIGNALS act.sa_handler = SIG_handle; (void) sigemptyset(&act.sa_mask); act.sa_flags = 0; val = sigaction(sig, &act, &SIG_defaults[sig]); #else #ifdef BSD_SIGNALS - bzero((char *)&vec, sizeof(vec)); + memset (&vec, 0, sizeof (vec)); vec.sv_handler = SIG_handle; val = sigvec(sig, &vec, &SIG_defaults[sig]); #else - if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == - (RETSIGTYPE (*)()) -1) + if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR) val = -1; #endif #endif @@ -257,7 +263,7 @@ RETSIGTYPE (*fn)(); } /* Unblock the signal */ -#ifdef POSIX +#ifdef POSIX_SIGNALS (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); #else #ifdef BSD_SIGNALS @@ -280,7 +286,7 @@ RETSIGTYPE (*fn)(); int val; struct SIG_hlist *this; struct SIG_hlist *last; -#ifdef POSIX +#ifdef POSIX_SIGNALS sigset_t sigset_mask, sigset_omask; #else #ifdef BSD_SIGNALS @@ -295,7 +301,7 @@ RETSIGTYPE (*fn)(); last = (struct SIG_hlist *) NULL; /* Block this signal while we look at handler chain */ -#ifdef POSIX +#ifdef POSIX_SIGNALS (void) sigemptyset(&sigset_mask); (void) sigaddset(&sigset_mask, sig); (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); @@ -330,21 +336,21 @@ RETSIGTYPE (*fn)(); /* Restore default behavior if there are no registered handlers */ if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) { -#ifdef POSIX +#ifdef POSIX_SIGNALS val = sigaction(sig, &SIG_defaults[sig], (struct sigaction *) NULL); #else #ifdef BSD_SIGNALS val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL); #else - if (signal(sig, SIG_defaults[sig]) == (RETSIGTYPE (*)()) -1) + if (signal(sig, SIG_defaults[sig]) == SIG_ERR) val = -1; #endif #endif } /* Unblock the signal */ -#ifdef POSIX +#ifdef POSIX_SIGNALS (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); #else #ifdef BSD_SIGNALS @@ -365,7 +371,7 @@ void SIG_beginCrSect() { if (SIG_crSectNest == 0) { -#ifdef POSIX +#ifdef POSIX_SIGNALS sigset_t sigset_mask; (void) sigfillset(&sigset_mask); @@ -394,7 +400,7 @@ void SIG_endCrSect() SIG_crSectNest--; if (SIG_crSectNest == 0) { -#ifdef POSIX +#ifdef POSIX_SIGNALS (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL); #else #ifdef BSD_SIGNALS diff --git a/gnu/usr.bin/cvs/lib/system.h b/gnu/usr.bin/cvs/lib/system.h index aafef3e618d..75023aef7dd 100644 --- a/gnu/usr.bin/cvs/lib/system.h +++ b/gnu/usr.bin/cvs/lib/system.h @@ -29,7 +29,11 @@ /* AIX alloca decl has to be the first thing in the file, bletch! */ #pragma alloca #else /* not _AIX */ +#ifdef ALLOCA_IN_STDLIB + /* then we need do nothing */ +#else char *alloca (); +#endif /* not ALLOCA_IN_STDLIB */ #endif /* not _AIX */ #endif /* not HAVE_ALLOCA_H */ #endif /* not __GNUS__ */ @@ -50,38 +54,104 @@ char *alloca (); #undef S_ISNWK #endif +/* Not all systems have S_IFMT, but we probably want to use it if we + do. See ChangeLog for a more detailed discussion. */ + #if !defined(S_ISBLK) && defined(S_IFBLK) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# if defined(S_IFMT) +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# else +# define S_ISBLK(m) ((m) & S_IFBLK) +# endif #endif + #if !defined(S_ISCHR) && defined(S_IFCHR) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# if defined(S_IFMT) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(m) ((m) & S_IFCHR) +# endif #endif + #if !defined(S_ISDIR) && defined(S_IFDIR) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# if defined(S_IFMT) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# else +# define S_ISDIR(m) ((m) & S_IFDIR) +# endif #endif + #if !defined(S_ISREG) && defined(S_IFREG) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# if defined(S_IFMT) +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# else +# define S_ISREG(m) ((m) & S_IFREG) +# endif #endif + #if !defined(S_ISFIFO) && defined(S_IFIFO) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# if defined(S_IFMT) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(m) ((m) & S_IFIFO) +# endif #endif + #if !defined(S_ISLNK) && defined(S_IFLNK) -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# if defined(S_IFMT) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# else +# define S_ISLNK(m) ((m) & S_IFLNK) +# endif #endif + #if !defined(S_ISSOCK) && defined(S_IFSOCK) -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# if defined(S_IFMT) +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) ((m) & S_IFSOCK) +# endif #endif + #if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ -#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) -#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +# if defined(S_IFMT) +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +# else +# define S_ISMPB(m) ((m) & S_IFMPB) +# define S_ISMPC(m) ((m) & S_IFMPC) +# endif #endif + #if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ -#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +# if defined(S_IFMT) +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +# else +# define S_ISNWK(m) ((m) & S_IFNWK) +# endif #endif + #if !defined(HAVE_MKFIFO) #define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) #endif +#ifdef NEED_DECOY_PERMISSIONS /* OS/2, really */ + +#define S_IRUSR S_IREAD +#define S_IWUSR S_IWRITE +#define S_IXUSR S_IEXEC +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#define S_IRGRP S_IREAD +#define S_IWGRP S_IWRITE +#define S_IXGRP S_IEXEC +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#define S_IROTH S_IREAD +#define S_IWOTH S_IWRITE +#define S_IXOTH S_IEXEC +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) + +#else /* ! NEED_DECOY_PERMISSIONS */ + #ifndef S_IRUSR #define S_IRUSR 0400 #define S_IWUSR 0200 @@ -100,7 +170,8 @@ char *alloca (); #define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */ /* Read, write, and execute by others. */ #define S_IRWXO (S_IRWXG >> 3) -#endif +#endif /* !def S_IRUSR */ +#endif /* NEED_DECOY_PERMISSIONS */ #if defined(POSIX) || defined(HAVE_UNISTD_H) #include @@ -221,6 +292,8 @@ extern long timezone; have to debug the configure check across all the machines). */ #if defined (HAVE_UTIME_H) && !defined (NeXT) #include +#elif defined (HAVE_SYS_UTIME_H) +# include #else #ifndef ALTOS struct utimbuf @@ -233,34 +306,36 @@ int utime (); #endif #if STDC_HEADERS || HAVE_STRING_H -#include -/* An ANSI string.h and pre-ANSI memory.h might conflict. */ -#if !STDC_HEADERS && HAVE_MEMORY_H -#include -#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ - -#ifndef index -#define index strchr -#endif /* index */ +# include + /* An ANSI string.h and pre-ANSI memory.h might conflict. */ +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif /* not STDC_HEADERS and HAVE_MEMORY_H */ +#else /* not STDC_HEADERS and not HAVE_STRING_H */ +# include + /* memory.h and strings.h conflict on some systems. */ +#endif /* not STDC_HEADERS and not HAVE_STRING_H */ -#ifndef rindex -#define rindex strrchr -#endif /* rindex */ +#include -#ifndef bcmp -#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) -#endif /* bcmp */ +/* Not all systems set the same error code on a non-existent-file + error. This tries to ask the question somewhat portably. + On systems that don't have ENOTEXIST, this should behave just like + x == ENOENT. "x" is probably errno, of course. */ -#ifndef bzero -#define bzero(s, n) memset ((s), 0, (n)) -#endif /* bzero */ +#ifdef ENOTEXIST +# ifdef EOS2ERR +# define existence_error(x) \ + (((x) == ENOTEXIST) || ((x) == ENOENT) || ((x) == EOS2ERR)) +# else +# define existence_error(x) \ + (((x) == ENOTEXIST) || ((x) == ENOENT)) +# endif +#else +# define existence_error(x) ((x) == ENOENT) +#endif -#else /* not STDC_HEADERS and not HAVE_STRING_H */ -#include -/* memory.h and strings.h conflict on some systems. */ -#endif /* not STDC_HEADERS and not HAVE_STRING_H */ -#include #ifdef STDC_HEADERS #include #else @@ -277,6 +352,29 @@ char *getcwd (); char *getwd (); #endif +/* check for POSIX signals */ +#if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK) +# define POSIX_SIGNALS +#endif + +/* MINIX 1.6 doesn't properly support sigaction */ +#if defined(_MINIX) +# undef POSIX_SIGNALS +#endif + +/* If !POSIX, try for BSD.. Reason: 4.4BSD implements these as wrappers */ +#if !defined(POSIX_SIGNALS) +# if defined(HAVE_SIGVEC) && defined(HAVE_SIGSETMASK) && defined(HAVE_SIGBLOCK) +# define BSD_SIGNALS +# endif +#endif + +/* Under OS/2, this must be included _after_ stdio.h; that's why we do + it here. */ +#ifdef USE_OWN_TCPIP_H +#include "tcpip.h" +#endif + #ifdef HAVE_FCNTL_H #include #else @@ -335,7 +433,6 @@ char *getwd (); #define S_IWOTH 0000002 /* write permission, other */ #endif - /* Under MS-DOS and its derivatives (like Windows NT), mkdir takes only one argument; permission is handled very differently on those systems than in in Unix. So we leave such systems a hook on which they can hang their diff --git a/gnu/usr.bin/cvs/lib/valloc.c b/gnu/usr.bin/cvs/lib/valloc.c index ce37da7ad3a..674b60f6e91 100644 --- a/gnu/usr.bin/cvs/lib/valloc.c +++ b/gnu/usr.bin/cvs/lib/valloc.c @@ -1,14 +1,18 @@ /* valloc -- return memory aligned to the page size. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "system.h" + #ifndef HAVE_GETPAGESIZE #define getpagesize() 4096 #endif -extern char *malloc (); - -char * +void * valloc (bytes) - int bytes; + size_t bytes; { long pagesize; char *ret; diff --git a/gnu/usr.bin/cvs/lib/wait.h b/gnu/usr.bin/cvs/lib/wait.h index 2e477730f54..db60434144a 100644 --- a/gnu/usr.bin/cvs/lib/wait.h +++ b/gnu/usr.bin/cvs/lib/wait.h @@ -17,6 +17,9 @@ #ifdef HAVE_SYS_WAIT_H #include /* For pid_t. */ +#ifdef HAVE_SYS_RESOURCE_H +#include /* for rusage */ +#endif #include #else #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f) diff --git a/gnu/usr.bin/cvs/lib/yesno.c b/gnu/usr.bin/cvs/lib/yesno.c index 7014803f480..86b0798086f 100644 --- a/gnu/usr.bin/cvs/lib/yesno.c +++ b/gnu/usr.bin/cvs/lib/yesno.c @@ -32,6 +32,7 @@ yesno () int rv; fflush (stderr); + fflush (stdout); c = getchar (); rv = (c == 'y') || (c == 'Y'); while (c != EOF && c != '\n') diff --git a/gnu/usr.bin/cvs/macintosh/Makefile.in b/gnu/usr.bin/cvs/macintosh/Makefile.in new file mode 100644 index 00000000000..8843a248d00 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/Makefile.in @@ -0,0 +1,66 @@ +#### Under MacOS and CodeWarrier, we use project files, not +#### this makefile. However, we need this file in order for 'make +#### dist' to work properly on Unix machines. + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +cvs_srcdir = @top_srcdir@/src +VPATH = @srcdir@ + +SHELL = /bin/sh + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + + +HEADERS = \ + config.h \ + options.h \ + maccvs.pch + +SOURCES = \ + macos_filesys.c \ + pwd.c \ + rcmd.c \ + run.c \ + server_if.c + +DISTFILES = \ + ${HEADERS} \ + ${SOURCES} \ + README.MacCVS \ + Makefile.in \ + services \ + maccvs.rsrc.sit.hqx \ + maccvs165.patch \ + maccvs.projects.sit.hqx + +all: + +.PHONY: all install uninstall +all install uninstall: + +.PHONY: tags TAGS +tags TAGS: + +.PHONY: ls +ls: + @echo ${DISTFILES} + +.PHONY: clean distclean realclean mostlyclean +clean distclean realclean mostlyclean: + +.PHONY: lint +lint: + +.PHONY: dist-dir +dist-dir: + mkdir ${DISTDIR} + for i in ${DISTFILES}; do \ + ln $(srcdir)/$${i} ${DISTDIR}; \ + done + ln Makefile ${DISTDIR} + +clean: + @echo make clean does nothing in macintosh subdir + diff --git a/gnu/usr.bin/cvs/macintosh/README.MacCVS b/gnu/usr.bin/cvs/macintosh/README.MacCVS new file mode 100644 index 00000000000..7adddd571b9 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/README.MacCVS @@ -0,0 +1,125 @@ +NOTE: this port is still in progress and should not be considered a + finished product. Use at your own risk. + +__________________________________ +MacOS / Concurrent Versions System (CVS) +Current Mac port version: d5 + +Mike Ladwig +__________________________________ + +This is a port of the CVS client (1.6.5 ) to MacOS. + +1. Setup + +In order to use this, you must be willing to consider the Macintosh +a trusted host to the UN*X box where the CVS 1.6.3 server resides. +This is a really dumb thing to do if you have any security concerns. +I don't, so I can live with the problem. + +For the following example, "twinpeaks" is the repository host, and +"cicily" is the Macintosh client. "maggie" is the login account on +twinpeaks + +* 'twinpeaks' must have a login account which trusts 'cicily'. For +me this is 'maggie', and 'maggie' has a .rhosts file that contains +the line 'cicily joel'. + +* 'cicily' must have the Sharing Setup control panel configured +to have "Owner Name" set to "joel" and "Macintosh Name" set to +'cicily'. + +* 'cicily' must have the 'services' file (included) located in +the "Preferences" folder. You must rename this file to be +'sys/services'. + + +2. Usage + +Well, the interface is about as ugly as it could be. When you launch +MacCVS, it allows you to enter the command line and redirect the +output of CVS to the screen or to a file. If you send it to the screen, +you can choose to save it to a file when you quit. + +I've been keeping the basic command line +("-d maggie@twinpeaks:/projects/repository/eM2") in the Mac Note +Pad, and just cut-n-pasting it into MacCVS, then adding the command +-specific ("checkout commonFiles") stuff manually. + +On "checkin" or "commit" operations, use the '-m ' +command line option. + +Due to the strange way it is implemented in CVS, the 'release' +command does not work. Tell me if fixing this should be a priority. + +To change the file type and creator of files that MacCVS creates, you +need ResEdit 2.1.3. Edit the MacCVS file, and open the GUZ(sp)I resource +and make the changes you want. + + +3. Building MacCVS + +I have included the the two MacCVS project files as a binhex stuffit +archive ('maccvs.projects.sit.hqx'). You will also have to extract the +MacCVS resource file (maccvs.rsrc.sit.hqx). + +**** Note for the intrim release (pre- cvs baseline integration): You must apply +**** the maccvs-165.patch file to the base cvs 1.6.5 distribution with GNU patch. +**** Hopefully this patch will be applied and part of the base distribution soon, +**** it has not yet been accepted by the cvs maintainers. + +If you are building MacCVS for an Open Transport system, you will need to +work around a problem between OT and GUSI: + +Open the project file for GUSI (GUSI.PPC.µ). In the file "GUSITCP.cp", find the ~TCPSocket (destructor) method. Change the line: + + pb->csCode = TCPClose; +to: + pb->csCode = TCPAbort; + +Recompile GUSI. + +You may also have to fiddle with the access paths. I have a "Projects" folder, +where I have the cvs-x.y.z folder and the CWGUSI folder. + + +4. Feedback + +Please tell me how this works for you (criticism, praise, flames, etc.). +Any ideas for improvements, stuff for the 'README.MacOS' file, or +anything else would be appreciated. + + +5. Pre mainstream distribution MacCVS History + +Wed Jan 10 11:40:32 1995 Mike Ladwig + + * CVS Code base updated to cvs-1.6.5 1/8/95 snapshot + +Fri Dec 27 14:20:12 1995 Mike Ladwig + + * Cleanup of rcmd code, removing inappropriate tests + * CVS Code base updated to cvs-1.6.3 12/27/95 snapshot + * Again fixed(?) binary/text file handling. + * OT problem traced to GUSI - OT bug. Corresponding with Matthias. + +Fri Dec 08 12:39:22 1995 Mike Ladwig + + * Fixed problem with 'stat' emulation + * Used better GUSI resource template so file type/creator was available + +Thurs Dec 07 16:13:09 1995 Mike Ladwig + + * Port cleanup for inclusion into main cvs distribution + * Fixed(?) binary file handling + * Better SIOUX feedback + * Updates only via whole files (no '-u' to update) + +Wed Nov 29 09:33:16 1995 Mike Ladwig + + * Initial port of CVS 1.6.1 snapshot 11/14/95 + * Requires CW GUSI 1.6.4 and CodeWarrier 7 + * 68k version is essentially untested, due to lack of a 68k machine + * 'release' doesn't work, due to cvs implementation approach + * Tons of obvious "TODOs", but at least the heavy stuff is done + diff --git a/gnu/usr.bin/cvs/macintosh/maccvs.pch b/gnu/usr.bin/cvs/macintosh/maccvs.pch new file mode 100644 index 00000000000..fe5b5c06bb9 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/maccvs.pch @@ -0,0 +1,7 @@ +#ifdef __POWERPC__ +#include +#else +#include +#endif + +#define HAVE_CONFIG_H \ No newline at end of file diff --git a/gnu/usr.bin/cvs/macintosh/maccvs.projects.sit.hqx b/gnu/usr.bin/cvs/macintosh/maccvs.projects.sit.hqx new file mode 100644 index 00000000000..5321000db86 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/maccvs.projects.sit.hqx @@ -0,0 +1,270 @@ +(This file must be converted with BinHex 4.0) +:$d0A)&"bEfTPBh4c,R0TG!"6594%8dP8)3#3"$+q!*!%c(*6593K!!%!!$+qFNa +KG3,r!*!$&[rr)#!,3eFJ8(*[DQ9MG(-!N"35l`#3!c%!$J&V!0B!N!-#!*!2KJ! +!!3$rN!3"!+cdQ2ZY'C(1!*!&!D1m!*!'-MJ!N!VU-Jd0#NeKBd0@8bif1'X!N"8 +(i`#3%4B!!"SB!*!$&J!(!%f3!e"53eG*43%!Ukq,G+dCNLi!!#S9!!#S$J!!#)8 +!!"#GjiZP&3#3"Y)#$F"&C5Yci+Dj+DIAE5CKQr+9dddVc9mh)q`fB8P@IT'0ClG +ZHYQ[am36DTaD4ikIYqD!hFTDmmPUY9PHrRUecq`B18iSf@66ifGZFT[G*VIC2X+ +2NLdPR2!Nciq5Ci344RK(RT&R8I+E--)lb@EENc$#)XF**icX*j56b9DJm0PeqG8 +40NPEphTN$fLEEA,F)rc)l5H$6BlMb3BQH1",-a02*)MSLeZ*lXCAqJ'+41&Jm"b +#1MNrGS`LR1rE4p&JX06Pp6RDh,DPbajTNp$+j9*D(*j9$8!aR9cFr%m[aZ1jjrF +QL(j56R4[G6#iEar`EHFFq(C`(Jc5Bj`[@8)l18I,A8%%jV'EFr4,FSkA+Fl4VjX +cp0ZM9BQq`9AdqbERk2FijqMh,Fl4i3R1dHrE@VG5-Sf14k*Tb1iPXejRHZ6$-Y' +P#[9&4ChLS1NjIQQjMfKQ%plG3bC"Q)XHjmi*$Ll9TP-1EH*%Up'ja1b+4Vbqk#6 +f)U!U&8HNC$DI#!C@k5G6"CMEl,BZAEE'kJa&(JR%,c6+G&!8aq81XjE(BZ'rmZ& +kE-4hZD)iM3&`q+1q,Q-!(#l&fCM[8qi-G9KAGFDLm346j')2PmZj`L!!KmIa0@1 +!ZEDi@bi"[)8MVXCpaJ!ie-hKMJ)rP)E'2$r84*G"!)l@K[C@bCBEVFAPX6Uqj*J +rrbU+0!k6c6Gr[L%!ML+ElrT!rS8MCKJ`epJNN!!E1#6Ej[raV#+,irTBk62!SAK +9RcImi8$5Fiej9D-!(,l*bHERbS+0FCJCal80FJ1(C2Y!Yif&'6KD!YZ[pfKh0"I +d8!8h+@aBb%SE9&SHc,93''YHZaUC+00ELK)8ZGMMYX+pLX-`3*NfVeKY,Fc$TAM +bmc$q8,LiSehXF9[KAX(aNF+p`V,E#MH(ikE#,H#B8VL&Z8iTh"b1Q`Vh%Sj2&1l +9JGa5Z(NF8`Vh%Sb2&@i1Kc'!`Z8`#&#QRP"Nb@,VYQ9,,b[6NSmf-)$N0YA8"Xl +KZ,Nj#r1BfTaj($Ffc#8F(fqB()iL@di0&J-(L&q3!*iQ@cJd+H21+qi2'F)iSKe +E*R%dGfc*ibKaA6RVCiIUFV",`3!JrVEaLM%0MBPr`B%0%jl8-*pP(''[UPSGdFj +B+(aKZKP'BpF(f1cak9`re3`M'LqR&@rJb'r12-p'0PjLNQC68E+!(5l`dd`6m-4 +)G[[J8m9LX+q#+PHr3qXIHSISQ"DdrY'6I6fdq[iK5Uk-0kc8fmm@Jdr9X2&)Lar +63CKA""AMa@LN(lp5l'p$Ye1LYjj-dmqpk[mbdId$H+MjD,jh@'+#F!MJ2dj9Vle +)kcIF``rHCpX5m10G$q`qCj'R*8cYdF-MN`639reYY0iMDbMl+NpShpkhV@,`J%N +-2XeA1G-%pM4Jp0%Vi-"dZpd1$@$r$`GLBXdr1&"X!-#"INbDD[F-+0P*AZ$!c(V +YfrYQE*`$BpKe$XbX(qF!cQ[rjF!rpi!4!!H)lX)Hf"@M+Q@"d3!(bX!"Zm1cmN( +h+[XR('JAGaNRF%!cN!"Cr6eA1G#l-CEq[RDm`!(dd5X9*-fbTmrilUiB+e9l8m$ +V$m491qh@*PP4h8qdBjfF+MiYTfUIKDX1`@piMZE(derZ90d[UKqSS@9cIddd`,1 +G3lrEhL5UAcK-*RP[Z)lS`"I`LVpk92I,HlFm3E5QMYjpEdK1lMmT*hpiLZZLik( +Ab9*j31YTUBc)b5LFIqZ1bmR)#8V*+6NT*ppL([1eQYQ5iC)N*pq%Mj(M)""ch$Q +#0[R'LBC4A96G$fhYB!l-RZ!!$J"aEc`881e'+KbSQH!!UTP9B1$#!5Akp8"F#AX +M#F-8$M549(pC$baIkejPc46IPj1rHTH4kbK+Kj!$diTLhKmj25UR(YiPjKhUiET +`RYSSR&e0F[+C8RL-5GjMHSRS-(VK,U&p$r@3!-RCMClkGra9ad[m"Dp+bAbb(Kf +H"TT'cM'&d8R)UB&D1I8m@*2'4R4(cI$`(6A8661)0#G'Yh"ZI8E-qm-L)"M#c)E +I@T5Ga-+h$eNVj"5)8icHCHj3Cb`FX+i)"(*hIm15B&dVM&p)J+M5EQImd9hKZL@ +m(0Fd[1'2rZB)Hp4e*rie6dSZ[ST)Zpf+cV4ri"Vr0jjXm8(4)b4T"dqVprY%Mql +N4d9RaKSZcRVXcCeHRfqVkX-&9ldmcD`p[P46(TPA3qHV4N'aBB1Dm-Ce1@I8%&A +iUi'flRMVMEil5Y11'),-9e51rA(#1#CHCPCBq%,D#"p(Dd"0f(kQ1'biN!#0@QM +1UaCG8FJiMijHlSd,5$ZUErkXES6Tlhm+-8+*qLNHQ%P#)qajkN&Q"-!G#5K`mc% +-#2ll#NhcfU*GNd)"QiI0,ZP%chNhP%Jl*QE$-IDIQI'rlSMlkKC8iA*1Fm4fNQ* +a@*8q4c@a0RBcL8ChD`[ZGk,&0*!![EM4fQlk20)UVUdj3`Z4DMlaRH[S+dKEZ,C +e$V'AA611H9iQ0p)qVRApPYU4iRU&im,$Y!(A+qj$Qhj$m0$2HBaVR@m3r%#eZ"- +54AE6EY4`&b3+,U6[S2B#epcl'FqGflKQ5p'282XTeaE2SKG4'p4`2dQ[`&AaADi +e2dNr4qeCVPRISb'L1XfYTIb5AXH*8X0DYjp1BiPSA[AD"qMh4(2ADV@B!)[QJLf +BhfQ"[`I0e@i@,AeL0PLNmB"q`4I4ZmrESG!(5qDXpNj6%618H(4,`*H`JPYU+"U +aC1UZN!$UQk'lB60@XNcGiie(3T&0DRQQ@F1f40bVQK[mS83dEQU-4K,Q9Qpm8b" +K@Hlc"@"'8lb*cAL[Y5RMhaBiS[l!bN#NG13A"YSc(9"jfT5B`DfA-l$0MNBAQTA +aMhNb1%CqdM1G5h##Dmpe2"EBAdI3D%l&E,Q-[DSC'#1q9HfCh[lr!!i!Yc*YeYR +e$MU[Th9H4l2dbXc-kc`lZIETG5[A,h[6m056'Tj6hrKU9ekpChQC6Ic1RKb,h#D +hcmK[ApY("Ta`-YKN5ik6hbFCm#2mb2',E(+EE-QafmG+mY`VYXeB*Q'%8q!'bGE +Vm,'2RTGA+Xm"l6Gj6QDEc2J"N!!06!m2[!*eATCZAIFKK$$mRi$3Vek%rkp$cJA +rXq$r-H4%dj%$P6MpLPXh%+VSH#%IiCTak"m&5a$U@MFLTq3`q[60)'$4F$J!$k' +5B8E)A3crihLM`m-rk-AcDBh&m$q1jkLDGq`-hS34LqYVPaCADidK*D5TKQU82r6 +RLZHU0Rl!`m5$S289eY`C4I1SRZ,'pQ*5`fNm+"+9S"0G4fJ1RhL9rHLbCR3MbR+ +-[f9F0pDrk&F&1K`kmJ8DLEDLVN03`#&#(Kl34rSIS9cJ@5lldF6#lLU+#AjqMH+ +ZA&9E0QYf5rH2)B,Npd9G0&!4r8R4Zr!02AU(I(I"phlbIB4rGePjrRZ#YlqSm#d +)q'Eel%FII%,Lh@l13,hi"XH[mI[$pU!C+-raqE$2&bLK!"%+)-A258kJ$81iBKK +*M&Q`(&KC-P-VRqfC8P`*R9a@"U`63*hDcXPiFifVZSTNJ'G1mUY#`N1#3r$LR5H +S"hrh%8H&$"V'DXd$YUbS,3201!0*DchHB0Ck[!&Pm3kjUQ[$)5hJVBS%h%DCeaG +4ZdYiqB@D,B"D8lf3!'5J2`j+A,FHD0+mCFepTD*pZ5[$Z+0ZdHSkNN(C$$92$iB +e2@!NB6X2[IBq3b8CP-03Xd0Z[kI-RDJ8DR@qYChA#KR3%iTDB+LK9MA8S$Ae331 +@4k"k8"j9Gq482!1PSReM2rXE4i8-bQHS1BV(V`95Z"CU!820FcHVlTB8VS9Db&$ +c+DSH#5GJ,G6K*UT2-3bYUIele"%-0GIYdp4!XY*6U%8QUZlhDqG44c,83RG)9F* +U!e#T&pP#(F@Cjfk&QHSmmbjLU0NHV5NK#eqKAXcj#P3J`p)3AbrK(9*$)6ed[N1 +M'HT`Y5fS"$`035AFr"@fK6U'Xla*mkP'T$&ClVkaarDBU-IfS,'FH8dD9"T3r)R +@@V@1iaaU9ScHe[5KAXSje+`CB6f8P+%ikQ9F864[3!qTja4P[)RU$qUKXcTd8+! +HK'QIpG@RZeX'qaT$[Cc2$6lGQjNEBUKAF'd!e-cF%%1pN[F982e'UP`,YCMheDm +-P"T(RFMjkYFp%G#80&pMU&Ia$[RE!jl'2KdrJhSeVc@J0``)Xi8kLD%@"*@3!+& +UJ5Bp-HIeS%lQc!0KGDIPbd+pKLXP4I@TVDU[Gi3&V,m+e,qLDlNfK'#Z[U!0*9( +8j(KpZYBTR%1!#Y2b1Ek@QULU1`)X'N+GbMN88S0kZV-@kR9FKd+kRY,N8kM6605 +`-L#`&QSCeb(Q!D4FLTkjSGa%$5[K5+Ua9Uh6HBI5FpFCe1Xjb`IE'NHG`6X8#AT +J9KlSd)F#p80d3`pUQJda4CR*Y3%)C)"TNpD'@+hJ#!V8K[#!$X93Ch(8p5%P'!6 +#ISpk%rKX%2P+b1Y2bcPJ(4#S"p"XKTVA&"J!MD2Hc&'pDRL!HKEUR*1S2Le`$R8 +Z3md&9$$-"PJH3lhPC+f!H[e3VEFbe"a!ACpf[Lc8H3c9kIIFQ&'['1TmAQY)pDT +YjfZYi#`hP&CeQVZr54EU!SCDB'MHCM"5I!RZ@CUhd%3&SbHBp&j1S9Bbe%++DS$ +4eJGVSGl'@Gif5$d,G4(R8,YU"")6laR8UJVULHBBBBqQTkE+cN96Ad38P@B@Fp6 +f9X@ARN8lelea18FPQ5A-`bi`fSebm,kJ5lh)Hprqr4''5M0,'DSc#&4)6lfGllc +f@eiVbGc18,1TAjk#lIcCRLFj+XNXLhBSh"i%Gk1[3ep-[**hL'5U'HS)f2YS"Ld +[9`+'GJEij8rIhF43DDD'S4DCU)PkAjVAqNH'5M2,'I1bkc4rDPiMI*dqhq3VC&B +`e0cDX)IX$L4a1l@lrmj45FB9CB2EScBPfI$f(hjMmK8bGc"8i[@#6UCU(6AT,la +@NPNCV9A6hH%q'`AYV94'meT*TMD+fZ31*&%lR42'mPT*TSkKjK08-Y%RHJ5+d#5 +dS3R9-`jGA+N(2"TC9P"mX&B4!TqM'ljcBXFE(*9N9R%fH,33mFZ6E!$QV"%F@S2 +Zj2TDPp)JaYI2rQRb&6+V1FXAY8+T+9LV3hIa@UZ)3jbZY3IeESCDX#!Bp+PeLUm +P`E`He(XBkSM+ZSAeBFd(01SYf8*G`e$cABUl4I(f0mP#[CHK&VTFPA@`ZE93Eq[ +&Y9$A4V8KR0,B[@qrQ@Ib&6)0$,@3!#S+Z-4U(p1"fqm*PVq(eR'qNZN`N!$DQ1R +8'Pif@3iCKGFD8--`0S6,`E[YVIAcjda9*TP'KTS$L*l8!)"HfR4G2Cmf5-E0eB[ +d0G*A*iPA[Rceh`b9CM`F04)!5cmeY1epGAX*la$*U&%1TC'"Eq-%mmDK*SBkdTb +L9""RjA5RA[)IAFRl5M*HbqP*Y)K1b#GRj@DZP'ibUU@9F[94&qFVb@JQbf&938N +-+!4edG44BX)HKHlMYDERC)CDqNX6&6)Yh$N!$S99rcNrchGKFiZcJ@6m[+mq$9C +kdY2'SY)$SN-(8)$V8#3YVS5[*qC`cD-CRD1QCcbU$9m8(cERFXJ%BrXSU9RCBX2 +p24Y13`jaU'HrBBKj4VI[eGmL#cAFi`)1e4TKU0RV&GM!1Xq'eZjGTB%1aGL`RU% +kB3IV[jX+EA%rV`rD3Qf21SiADYeJqDrT#5#+qS#Bf$aJ,3pSHDR3mP,d)%20DaL +%IH@YSMra+BTN(Z+e`RDH#VY+DAeY&[VDM$DbhFhKY8YAe+mqY94k%PAVfSdlf-C +RefkdL8d!a)[5M3Dk+pCqaU(I0p*4`0N!'G6"8+NcPrCkVGh0c4`e"!0P'R9IlJ1 +ri,9#"Mem39'L%pX@dph8p%KDAi'PTMp%-P[&lSY29Fl[[Mc#*i#3!1VA@mpZB-4 +3YrAXS`bK2XTCAZRb43cb[fqh&lKG+PKHLVBce(aLKi!U''9kEkel2cBUF-H+KEF +AN`akM+'1U3(6'e""8XbYjCjpjI[RE1De3JBpcQF8a3GEFmUj6B8RQ$ENJ`i4SJI +G#DHR4e'HC+J&($8%HjqpU)F2&1%1mQZ538p9X(e+-2'@U)S(YP*k9kSlJjp-3Kd +e0C9,D'B(Ua9fjNLY+4fkY!jfL!NUbD#Gd5e-*4a1$P,@&,@,ckmUq)f$%eX-p@N +qXDdIF$C1S6l6M6U`24$EXpNGlqYh1m62a[TkINm8EDY!,NUqfI30"KBdBmmY)ME +allZTeiI4(G4laULHjqrKhmh8ZF(SB6T&B,5+ZV)Bh8GG&Sa@FabGqJ`BhFAcASj +h1pdQ`-K223q-UURMMe%6GCm`UU&H2ND0e'A$5+%H(8CVH"hhmZqPG*F")iek3KK +9dHd,M&C3IakMGG34a-K&RAH-PY#0#BaUUFq0d8VUNQ2832e'M*L6MG&DkPTLY)c +Z,f$NTViG4LVee$"D6VF'-,U6qXSBHDK$Ke'!ZM%B,DEl("MG6jQ*NC-k3KLemRb +Bmb$)[hG3&F3Sa22C9,Fa+Z&jJhqAFI`@RVq"IdIB0rkbMrrf"#UL3rV&reEF"Zb +p0Xjrqad)%6Nrm2mFldfqbd0iE[+EmlCIGc-HMSM0XV+jbhj*434rb8G#S,[b&pk +[jrfA([!I,DH[A$RLr,Gp1K&2m1qRU)G'p@6B4e"$A%mb$Tk)*pNRU&)ZiDFM#f` +jq-pMPb0VCd@-RrMi'p0YIJ*q"FGh%I`B2dPYCqHN6Cf($fk'1SrLBbC[!A-G[%e +&P-q&Mlpqa1'FAq()HJTHjqSkJG#S'AaQ2I4D)q%Ym2*H`P[i*[P3jb((h%[qJY# +8KcX2Ieb,5L#IYB1pXJ8[6N%Ya-Qi"IkAd(jP1h,amilpl1F&qr(cBcTLrF,2I9D +4d"2RKLhGHX,bVI`l$0mEUCk`r)jp)jdMU*ii0fcYeK2RKNHSRMJh%0dYirQ@IEP +hMDGkiYb`MHS*r6hT&c6UCZDP4ZI*c"Y,)[+N9r0%f`pcTD8$pUYC)[*PAh0PFJk +`hcm685"0i[p1DB+rC1Q!rD+G#21&5'RA(*!!i[rJfi3LKNZrjX!4MT(!hMParYZ +[6)SB)8hLr`DH6qT!1mrrT!GM(16Pi,QRp@$`r9!4l0PIQC%Hl1+rLrX$YMj)#qC +%qi9B%@6+N!#5qBAf@lmL4NQMjN4T`4aJ[piXiL,Teaa`KD1BlMr&qCpj88$%Xl) +bI`!pcAlI[eH5HDGGa-@bX$Nak5[E,qq,Z%6DS3-2d(HRC"4km#"pf8T#i4rC0a@ +)'*h4!ar[Trc+2dMX&pM[')RBEHR!3r6Y04R5rU'd`9HdVkF3-8Efj5[fljGNlZ! +3-9C@aRrlSK%4jVdldM(qflHTL,K89XCrqmSB%CG*[rD+%[k`I5q1L2(5+rlrq#k +4I3'3!!Li$da10JIDYab*Z&a@aRrl+LF49dM,I)$-I98LVT3Qm9rDX$pUAm`PJQb +TbcPdB!ZpJd&Q-JpF`r2bJ2F+-lH3!)QB+![c"r[I+mYFYbEL+NX(j%IlSp+'[9( +lEMN49m[+r%,l!Md4Nf4PIU&p5k#)bG)`[c$jVRhQcN-4edUAI!&j`6Y8Dp%kb[f +[G#"c+J-0FY8""1J*ZHcJD232*NhmCErIN!#jm9(%&1RA[*Pi[mDqeP*%UI5)rmR +hlk30Hk[f*9-LYXV+I%Ml*Ld4MmM+q'rIibTLUUb-rrCPY5+ZNjIa2h0-VKR6T&q +qB1*GE2Zk2"(ET%Rl"r)"Ih$SAHaqIbKcel+)FQRCI2MYfkBNTNZrjX2NIYU3!$d +!YfR,V[Krl[f#j(dYQH["4Fb3!'lY$rhS$pLARSZB+5[c"qbEh8AF+2hb"a*cSAd +9USKRT'YcBHBUIa'cT&pci5Um'YKl0E[T0qSACDll&I(i%2p0hTYmP`IF9bU2Z+I +8j#hRCC*AqA!P0$Y-2-1XQk3e['V#j*@0bA&HLA[2EF'Dr31[iR0+FMk4Mr"X,5E +[R%`ka61iU[Xl)rRQrmf&mK3G5r1,ALeZmfZ1aDrN2PrmEKRj#Fmbr$)[DrpkVTd +VRCQr62rK'rd#IPhr0F()KDYb'hjYa131f*)i[h+!AppG4(hVMh0ZmJlQRh`iqB6 +[CXePTNq@e$GkLrkhqh6cC$AqMAP(BY,(JIG-['VE0`bE,l[a&dcr&qr!Zi!PTDG +m5%0T9DHjrc0+Q*F6bh2Q#01[0hPSlQfDFm8f["hB0#A1a`*$mcE$S9SqfrPC)+h +JSlaLVb)jhbAmq3)$cSJ,IRdY'%),T6AqI)*AKC4A"KcpQL&@TE5'9`Nr+,GYb"# +k,F1VT%mXEjRRKZD&R(E9#0K[J*0B*+haJkV3%RS[HTBe,bbZVeeD9UdePXfD[@b +!9qEHSPQ(XkH1iE9,9p5[*N@3!',5G@`FV'2-JZ@e5iY,CQVPXce6LLY6"CPhVbI +Ub+Y4h#YUbhaRHd(#e*PN2fTJ4)8'3"r-V[6eil%-2bTG[SK"rQGkmQLQ(klU@TM +`!YkU5!"H3[Ek)QTI35E2%hANeqQk$aTTP1Q$r#!ZLJPmd`6`Z"a9F*c*E&H9cq# +rJ4G2*`+VYe@iUSe`9$$)*14`eDVHVLla)lMUae&#IN1km(m0$3T0B@0$9P-Z8&" +$!*!901%!N"''!!!b6J#3!aB!"J#r68e38N0A588"!+Z[LaLY'C)V!!!V'3!!TS! +!!!IK!!!2jBcE3Ki!N!DS#3h!e@8Q@cIpc'BVffaPjc8JE0eXhA66c6CYhIMpK+f +Gc*0jQmTdVmI1*h[#$Nrah@CD+eZIi,ZkPG#pNNf[h16S*TX0pNSfBEF*Zhf-E0T +Y`MEGM1`RqbKKK*&pj2D4hib`c3MEM'c#b$2#0KRXBq3Bf8mf)i``mTYX`XLa)jZ +4hib`&EKE*r9fK'dfXh@[arB6'Q'E(([#0VP0IKrCj$B!fF!%ViN&E1+"!b!!X,J +2B"&qKD(qRek*VX*,kr%@c3d3@'@C"pDB9M@mlEH*kcU(*0[Dh@DRdpBZB!f(`qQ +bG63h)S8'IS)AlYfi(Grjr[BC!--$!+DCS0dp,f'0IEdUDYN+PK%26,0JKEJD+ZJ +j0P39M@fVLSkS`C!!lNPXII%(kYm"EF-!Y"k@S!rV6"hTKfQ(Yd+XrhGrLSi-`Bb +4Z6$VAMh$3$mBqNpFL9S1B&06pc%%+-+6$Y5M69U#[8X'P8Fqp'09+M&ITrS%qDT +k$lZq('!D!X0L8"0)*0*P%JP#JkEHR6c5f,H2(9Z3!+&%i`J'*$NicUj#+Kdj,Ja +NcQ0"`5SmS#j(jEDjM5KFBkX[X0'Vh#Rd[-,dqP$)reFp2!ZUZRURXj82`1%*bVe +m!!k(Xl8TAkHdeGGPE0i8#LS4+T(l04b1eJC1!%H(E58IS+mZYqX"i'X1*Dc)I!# +1F,HrUk!2Cf06AKrK5#mRJ'00BqFD`CaVVGl4BE5pefBb2DC)FUM0XXR%"H"3QH9 +R$IN(4iJEd0I31-J,$X(Fr9qGP@FiRV89hS8F6LNX5riR$8Rf055&H3%FmRKRmhf +PKSebD#M(d`RbJN-`hr9YYd+$(#i[Q[fRd@PV+rLKFPUN-'(49TV4TH9KRSD6XLD +GDChPSa`@CrVD8D*%lYGiih!IFh!$R'PE3iZad!q(Xb2I$rk(`kfcE,aIiih$IF6 +abZ%q8YNEKj[MH1P`#a`6$VI3e`Q(Qq0ikA!IF2c6i6jZb'Z(QqHBF,J2-0ikh"` +((m$KdZ!%10-1Aq$pYFDSTHkK-bej0B%4*$HT*LC`MZ2Pj#cdBf*bjMPH6*J(('m +R6)j$CFkj35ebS2!,eP0Yp[['EGa0are%)C3Mf08ccY(@eC2R+(%mqUfIDDV$4VF +81!$aYiQRa@i`*Ik&!bH-Ipc$6+BFILNF0YU#Qd)qrjhZTK@0Xpll'5j!ArrR'E) +H,qF9Ah$N*fGHCpQ*&aQAf86SDZL'#ql6&"(FL4&%86+G)Y+5-c$PPhT`&HN"6V- +!ec``1@(PSQr!J&eTY,2La6#65+CcXSHZif"m#`lLmJS"EH*@*#prEE'RR8M[186 +%DY!@*djkPJ&mD!3[XMfDhFF%+K!D"*RL-1h6+m'PBG2Y"PeE3RkmK`C1Z)cRQPm +G)")B,jFl+3%,"$hTDBH2h9M2+$piVBCpa4qH)G)bV,Q88UM(f*2!@#H933d8Lk+ +)(N$NB@L!'-kI"q2[MGLrlr))0)#recJD'VKdQ8HJJ5QS!G(@B9rVEKCp!GRIkr' ++[!S0'-VT,,ci'al",#`Ee3!DAr(e()J4E"4IB3jFL(-(jS!GK1PLFTA"h4ZLEPe +FjC8mAL8XCUVC(AmNpYAAmA`ikkX1cSH+2LX2`*ra#))Um"e9@PcTrZf0d[kPHjM +-lrd#IZ08!c2(0)#c3*%8RcHY!Mk+"QD0D3#cYdB"Rd8$cZ!@Vq,d5i%)0d8$D$H +U(rU"qYAZCZ-GFm!ak"MpNUX,2J`Vm*+1A$A'KGQGbkb$-+@Q&Qm)Q"f'LPpdirH +6hBPV9X`2iEd6S&ZUTh8a(iIb%dHYJeqUaGaQkk!`Qj,Xq(D+jA2@`ChcDBjFrI9 +kc1r(lblNUd!i,@jH6h,l0SAmAQ1$ej[EIH#@"2@eK2mL!Sa+p[m`*BR4+-8rLQM +Gk5GemcMGfLq5c-(Hb,pa9f!N0rl)31IGcIPrm@55DdQFP!LI(42kEFVDc$X$QNf +5,'m1brJA1ra`Pc+M#"fq@C!![AAfCTBA&1[@K515mTr"`J1)5RcCJBdl1[9'ljf +!STpc3IT,+QkpYm'2L4p49@L5Ek`m,S,[Uc3RAB[U8[),q$qNmaJ23E5MrQBYf8N +q*F6SD0Uc(k$2M0I9IhmYKBF5e4-kd)#!KA$13aa22!$Y#%LKi`KdNEj!mpaKXcp +aE*6M)AAqXr00HP4mC5IEjYX[$j(P"RmPrMN(!qN$)D6JZYB-Q"9UTaYGT-QpaP@ +&CjGkK+dq-GGFY3(Qi,'5jK`%PZ+4lFT2RJXI`D1,jXVUJHlcXq8jX3RS82d+c@Q +h3bFH,p#FS3c@!8bKGD#P'[!GJ6R-TEI["Gb*QVZ$jZbVS"pcKfKZkKEi)ZCq3(- +I(kBmaKM0Z@r!0c&hK1D#Tq%SjYK-A[%(q$(!I-EGGJ4qKVR[d9a2&jc&,QkQ19m +#cZ(JB+`P0q!L`))@*UE*F!9J)H[Pqlj-8%8,f@*Vl5j5LVR2Xh&cR-a%&H'V5KL +Rk%E%SVY[)DJZXhYX"Dl-U34l[(,%L0S+qi)"I6V[m)APXY4'F(UG,Th[N!#8J#q +`)9bD,YBBM5K5@02Sm8@#LVST')KSeNM+"Qp%Abr,APc)FdU4EVc2bNbL6cIBJKk +[h4[3CCpaB0G53+A*aF`dGbUGaYEBQKaBE"*pR#M0NAfSU*LQF"ZHA8rak(%&1%[ +$YM8ck8PdAcH0NGhGCGG5jIm2!*!$$J#h-UICjpE,cTl@Q6P)'h4ZhfZJVCaH([I +Xj(63@@G(`e221MbR[R(m9ei0Y%EfpMESb$&b@h,l*IX)IieXXXQaMJ`ff8HfNAd +qH5lC4ijI*pRN0RPfjA@5fek%GejQ%Ti(h#$CHTcL+cZpr%f9MfK2"M`b@Sk-@!" +N!j2eJ2&!RCHP6pH$##%-[p-4qZ%hi(FKj"VJ0`pqhd2jD#(bS0NPpBT[E90&Jfj +BHh%aU[Mp&"b',a(mAS!@`AmH([)&3V-,IGeQK@Ri%2jJVrMdI8mY$[qbp5#DJaI +8fLRHffJ@V@maI,NBkMYr%'pkqFU@TVU+e9UlS4LDDUTQ[+L"S2@9eDq2SIP9Id9 +lE`@T!3SD$1Lhb"hX(d*,8"lqU(+JIbm$4!RHJ8Xm@`D+Z+%"Vc+rqaH%*Y)H&#m +ZQdcUV@aSm&Bd@BUPk@(&k-A2HXl$cp(I,X$Ehi8TlrV`UZKqP"pPTCbeB5HT"Dq +b5#dN0Z&9h4&HY`Dr[I6l8XL9HRV69+$3m0[Be1Jpp#@T$rT&kSGq,IS!YH$lm&@ +HQi#$aH1ZcGYFT4KKI"&&LY,F+QXRlGFiK*H2)pq9eB8Ye3JS2K@i0P4lrpSI,-I +E6#[D6M,)`e!,ka@VFaL3!-EZlfcJU#5$aM(8m[VehXCSf0*#DZ9Km2kI+Mei@hh +$kKU53AN-G6c3VaNd$a$05RfSeNFL8'ZVGfd0bD"mhU%Qbqr0GZJAMrbFG`JbU)" +hU'S0D*5A-(ki3m'RTr-133B98ZDKI-A[Vr5PqEYRkMYra(h0eDh0*)1+''UKiJp +Ti65ZJeV-8)YpRDU[+ihVS*B`e"++UNHY*+b$@QUM"KA6e!+pAk+@-G3LAe"6`kP ++"e((fkKk++3G3beRU'8q3e8XY3fSG!6C3Ch!Q3H6Lq%laVb*$,A!V`8#'CSlU*- +iAi%+C)!CiqY*[%1UBHM'X3j0CUMMeCk)%[Dh48#F$f-lU0rJ,!pS3G@-YUI+h62 +e[9dfkRZld-QFH3%0+JdVS@4VR9URF!je+ZD4eJbM6Z8FkY4-5cG5-T4!2B8VLYB +4eJheU+*-Xe&$%CLBXkL[#Y4AdDQmVd(GecADecMUDAaZ#1SGZENKMMUGD`1JjZD +'11VT[%-K*3ZD3$f$-bqNqk1J$KRQa9(2j"`+pBEplF1+2)4D`@X0kfeCLA93Cc$ +8dSKLQ+S@$ZM$Z!lU@Ca$)*'qM"!jU'Gc[KUq%5B-SFlNI398AmKrP%2Rf+LU,`U +G(81GaCPRU#'pqcqD&dFpPl2"8#0kTV-1kQbZ+)DZTh9b%(@1M@ST@G&c81Ib[TT +J[d66,A*3jr&D-e20%1TjR1@M$8UJcZFGLNEm-)PQ1r5D3(d09A+@GkZ'#EC5KZ9 +ae!8ae$BVUbKae)8FGE1K4#,U##%Fe%A%Z!0828*m,l1bFaLerifRAf+S*!1q%d@ +&D6iFd$T5S'K28D2&Di8-Z)A8I5RZ8+dXLD!["d5($S$,+&#$@[JSkK+'@J5Sd0S +XAq1ShcaB+k!Z'U[e3SCD#+LE-`k4JhS43md2qCING#L1HM'[e9!le*jMY5jPU#@ +QdUh1piddDFqdVLU1#KQdM+'@QPT(*aJ1`56hS-*A4+f[S%XimhT'kH#JAXVlfUZ +DiH5-0i4k'GGbF(T'41J3kZA,UAS9QTCIdp1irGAc[SqBjT(-FSlDfkd%-pAfEhV +QG)j+-PAJde-1pCS,`1f"hKj"hVh[9fma9*TC`@U&HFJ2e[Y)XIhDeArLYC+-Pp9 +D&!f$NH)I3GfpGrYXAL[*A"(VN!$2V`D5[GfplpNIf4f#6(8-eHU0J(F`M2U['@G +b9*+TBDMP)FAA#9Uq3!QEfK$`%hrrc9D'5M-V'HS%'c9Clq1AGIq@SG*-,H03362 +aSG2Ld&qpm(+EjC!!U@1ePT'qCRLdHppcTpKXJ-b9$,@%XL&G,f!9#p4LY%U`h0$ +#k5QUAfYl`QBjC&Ec'583$P&h)`P,PHkJjY9cpI)4mQ68UrAG"PiVbDaKIFf2J*! +!Cr5erpG2ri5MNXaDZkpJc5R"G&qVjdd5qMS*0I!1C955SFjpc%D&c&9mfJ$Q@@S +S2BN16!#0-Ei5cb'*frrSVJ#[P@5D@)FQHr@`Ak0V)N&B[M(!8rNB[Rp'hc-FP@5 +D14Z#'KMIkF%"ZRP!p28!DQ%G+SaQj)4ShJG,Z6E3c$U1'[#&V66a3*8VhV49'6, +VBeUH3Hl2Rck9GiKN@[QdiGF-XJF`-QhXHhDMQ"XfSJeaKcJY+3jIVlEp)G8!8b6 +,mVMAHmh!TX)BkXB"Gh0-8DlpH#iIDDb$HYf!5c&@DaY$,GLX`#E&-3jYLVQEafG +PjH00K@aIiaaU(h$,a[VULcNLac[NGrbKc$`83e86MXJ`V)-Di&X4e&F1UYhUX&3 +kU"em!S!Y'a9f$M)63+HB!$T4*p2A!VUEPTPI(pfe3m`S1j!!aP8CpQbJ5HPD*mh +m!dFPQHYM%i#Qqe)6`'k[FM,AFT,TiK0EFhVqTl9Ulrc0RPmK%q4XU1i'8Fl-3`0 +69)MA@N1f@$+e$U#''@TT95359*Z9B&GbXKP!e4PUZEGj4BZP"@(81e+bJaTKU#8 +0LUp,k4KTNS0k!d-YipY[+r6KiF&"0@)ZK3Nl+HS`df(LHP(-ALmLNk1'93Z%dPS +!Qb*(82rj,G[T)4Q,cj5!k%pE8HMaVHHem%Q8C+*FKjL2-J,lj)Glrm&3DDDES8k +dR4i9"QhP%2VMSAFEHDdNXrQJ@kBB'4qPHYjFi6I-46d-YEKY&2E*&bDmc$Y%-Vh +(R@q'5M0Ef,444TbHL!RVGX0,+FlFF12!e$Zf&A'6lGU5@P-lBS1ehXbh-*[UeVD +dMLa'`QEN8qY`(pZ-I'SGZX@HE)+`'D@N2B!I2cq(+`V*E'8F+Q9pEG15Zd"lmPr +`m`j""[8ae!)$YQbbfalj,f`AU0[40P4!Q8HR+'JTDHeKEIMhfaI`[N)'hFUC"cY +B)61p*Z)`lcE(QIYbHq"fX3N89*9MQd"h-$C3Cbkc2H$XEGc*8)Q6UTYYG#1`GfL +rC-p%6bQ[&6,SVZ-ZHmaah-ilC)$mCrFELQlm(Um9-ZKZfj[Ap'M'4`%&YldSNVQ +(+`VdP66*)2[YKe(I2$!"pj'[53EGbe",1'V%PjcB"MLdBcRE`J6VVeC9r,#MFd4 +5qL0r$D'qqRT[,FhFap@,eCTQ`l6Vh`!G!P553II(GMF9bdSC-)llmJ"$,9$"T4c +eKq+S1aPUiHDXUcb)qZ$(U0QpMIM@d82a$KhE%hdi`BB[pTA4lDqMHNm4I(JaI8f +""Ffi1LML6[lr&MUrB"5Q8cK''R92-'VLHChrVkIZ18Ch85A%U*9kRaJe8-mDSb$ +(@8Ip9ia#2,qDih95,`FMjJ9M9%2h)$$UT[-Z4L[TKJ0'&Tfe-6,TT)j4K0Ga!rq +rK[Va'+fP$MY'Pp00&Sa@d(d4M&E4M3+-VU!l(4K9dHd6M0C6KaHMkkR2Jj&"r31 +-'UN2MY'9G(m"SfUkeB&4P%l['0A4E3L-DZNZ"8CGe2("b%Xh66"US5ie4X[TEJa +'ee#'BV5B6XNB+6ar(HI""[lr2UU'''hNq898L6(Da22Am[pAFrbVH,kGrfpMrcd +&`cVJ6P%LlT!!KHN!lXBp`1*c%cVJHJXLq[MrSr`rbRZElr)3RY[mjV`GdGqF4b" +LZba-If'[M,aMj%RSJ1[%L,LArpp"[C84AA%G4K&ErdpAj$PkFKR[[a4K[KrhCmJ +RG#$R#iUiKrhe)!pakbSmHFhl8He"RZ,hReRSb@YkUiZraB6IrpPE6hjB'+pJ2k$ +PHI)H)fpEX9VbQMF"AKQS@ar"FcfRVQprkNG8hBb`1kZZKp,GZ@V,lp!i9b02HKl +PZETmb8XSrc1185GHEK$i3aJTPMda8F`$"pm3ScVJ[X8NJU$,`HD"FJpjPfeT3JI +Fel9%&%ZAG1"qDB,rkqL"qfkDL"+CQ%m`V!1M,q'*+*@'kF!8cbR!iQ8*(A$I0K3 +"VSjN53Im2*r5!ar2Ikd,ChJUL+ee5"G'Akm8-9kDT!X2m1m5rS'V%p+#qG&pTe4 +%ZHc-Ah4IRK8a36Se2dS,jJ,h6@%4pL[LmUqjB*D([&0rkD!1j2EG46`N1r-2d%l +frFKq5ZieF4'6T'2cBp+2GYq*&h'5p%-20Y1AQ@38ZY"$hhk582K-lL8!)LD2k8) +[lk[mbPp)lLHi,q1)H$LT"ahdj8%CdRkMY-'(G'q!%!(ATNM#I-M8RNVZUJX4*m[ +1G-#pdd2%&0QC$VLAPiLB+M[6!IH@&K(%TCD$k8$59hD[Sa%a6CUP!qS*Rb"hpik +)8f9Rmk&lbC!!L00NCcVJhUBN!LjANjcj",Rhm8AF+Ph5!@R$RUTlICD)dk8IHR! +h[6T!CM)I"(KH([$HBZkq-"&R5-Ima06lDVR,d85FQG3$qG'HUV4K2p@p$8i%fAk +@Q[Q,lV9h)QE)c[a&phir%@G*arc&T"kiPaQ+1&[Dj"[)&rb#h-f0)QC+`qE%j,X +hlK@9)Xk4*ZP!kPdpDF2qURYENiMEC@HqSRXhUBKCXM-GF#pK&A'Zl%`(h0YQ4GK +ACd[-G#"h$+iGFk4K1T!!I*rE[E42a)h5TId#qB#IH24plT52P,Y6@F4FkGRFq2P +EUL6Q5F0d),@A0QBI`1hCXL`G1,T[NVS6*RFPZ)MjdUjpT"2qJAX2ZSK+fCPri&l +i,Q+"0%`(N[1LHcfTL!HPEI0LlUCr%IE9JI)`Rj(H%acc'4ArPhHUfLFT5X0m4Kc +!j2$'Fa*ki&kD,1)frYr9J46r8lcrIll,)qj5YIR-q6V#-lJYr3Y$pr`6ZT[JQlb +%CpIK6F#5QBGj4QpiGhPfJD0RUEfla$dcmK1HjIKPhjRrb3Ljj+Yj3AkL@rCmpjP +q!Em@I8+`EdT[q(8R*TIqcNR`Ua$ipF@PcKGq0BIppclMVrd1qB5riFaRYJq4dVR +mN!"rb4Fqe%A5'CeclP6%B4`"GX`De$P$l9"l2Q2BaE)F[m(ffm6Ge`lI5NbP@jh +[qh5d@(V#4j-2h(XYRq#ElBID[12q*ViIl`6@c%h`VY681MVKJ+fJkrJXNel-Fr) ++hcSeekh$VF#QX`ra%Fk1Lhab64K#0mPUjVS8VmSSVd`i,MC(V#h5'PiPrD#LRM& +$k*+aq5(P&mYEI+'aZD'`9cA$lP[G*#k9e[K"0DL@hLe1VJU2c`dV@jVU+PGVlC8 +0$GiXVlEarhBGq30eM'qU@p[55SSJa@6UZ(QdMX)QbqmGVB#&MCZXSk`ZE+P'32' +TZ@,X1mj6rDL(8IAcIYMlP-NkbZ[AHaZMB8X,UD-%XA8[a60J@,1Z"k%'Xe,2p-2 +QHDSI9@ZDkLUmRa)fGP%j[R!k61@H'MLD`G03%c6j0q"hcDL&KdeIEeKY@M&#A%( +q0$5T(4pp*$k#DedmXmNhT![r!b%K#d0A)&"bEfTPBh4c!*!C-3!1!@X!eJ#3!`% +!!"SB!*!(&J#3!iB!!!%!rj!%!3#Xp*MlV4Q4cJ#3"3'M[!#3"M()!*!+0U&*&`!!: diff --git a/gnu/usr.bin/cvs/macintosh/maccvs.rsrc.sit.hqx b/gnu/usr.bin/cvs/macintosh/maccvs.rsrc.sit.hqx new file mode 100644 index 00000000000..8b5b8dfe0c3 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/maccvs.rsrc.sit.hqx @@ -0,0 +1,14 @@ +(This file must be converted with BinHex 4.0) +:$feKBf0fFbjbFh*M,R0TG!"6594%8dP8)3#3"!*E!*!%l,p6593K!!%!!!*EFNa +KG3,r!*!$&[rr$3!,E@&MBhCc,R*cFQ-")mTJ!$9PbJ#3!i!!N!3"+qi1R+d!N"V +rN!4bFh*M8P0&4!%!Um#*JDcYi3m!!!,1!*!'!G8!N!5ed!#3##))%3!)!$cFi3b +Kcj0pmpAd3HjfE-CVb5I(RG%UGI`KVAa[[pEUH-IPG9`C'53PC9#Q6f5+&)m6f%5 +%$,B2PA@Nk%XlV2H"NJ-ZbeDiQhUf5Y@pIZ[3TQ9ddh2D[2h+eUK[rHbfjqBDIeM +P2M@GeT%hfc'pbIGI'cp1-h-GrXf#C9)pII0(SA,,VQdM15pQElr#VbM6&0$i3h# +qe))emidrbQReS3jp8Q0eaX*18,$6``8R*[I'I3+GNfp*lUkQeh4fAe8X0$4+-Hq +28`3PNSCardJkc3`P*rK,Y0D1(['aH@C#PZ3C4%C55(Vk8*`CM6#FNL8bZ8KXY@Q +S8$+A1#Xc`P*a5PSi)LTADG@UIDK!3SS6`AV)QC,)E)mBDKh!B8)c1$2bfX4jFNE +R`3bhjLb6Te1YZl[56#S'dI!hBPjh+M)MR1(+BFiU5@H$9TC+UqMG-T+c-S*CrIY +(8QKQjpE*S4a9p3X'3kec'YZ!$XNf0p(T60mhfb20ZJE,&XpIkGbd'!$)ZH%SJ`! +&3dNp3kelY%q#PVALkpA54frpEXJ0l9rC10C4+23#6mJIk14SqF(f[A5A`VEGcQh +[F+Ab1cq3!)KbdK[3$Hh'9-l@hSKZD$Xk9SG0!J"093!!: diff --git a/gnu/usr.bin/cvs/macintosh/maccvs165.patch b/gnu/usr.bin/cvs/macintosh/maccvs165.patch new file mode 100644 index 00000000000..68f7733ca74 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/maccvs165.patch @@ -0,0 +1,2509 @@ +diff -r -C 2 -P base/cvs-1.6.5/ChangeLog cvs-1.6.5/ChangeLog +*** base/cvs-1.6.5/ChangeLog Tue Jan 9 06:20:05 1996 +--- cvs-1.6.5/ChangeLog Wed Jan 10 13:41:54 1996 +*************** +*** 1,2 **** +--- 1,12 ---- ++ Tue Jan 9 12:39:22 1995 Mike Ladwig ++ ++ * Port of CVS (CVS 1.6.5 snapshot 1/9/96) to MacOS 7.x ++ * Virtually all "cvs base" changes are to wrap filesystem calls ++ (e.g. CVS_FOPEN) to allow for pathname changes and permission ++ parameter removal ++ * Mac-specific code (rcmd port, fs stuff) all in 'macintosh' subdir ++ * Build requires CW GUSI 1.6.4 and CodeWarrier 7 ++ * 'release' doesn't work, due to cvs implementation approach ++ + Mon Jan 8 11:42:40 1996 Jim Kingdon + +diff -r -C 2 -P base/cvs-1.6.5/lib/regex.c cvs-1.6.5/lib/regex.c +*** base/cvs-1.6.5/lib/regex.c Tue Oct 10 07:20:24 1995 +--- cvs-1.6.5/lib/regex.c Tue Jan 9 05:33:05 1996 +*************** +*** 231,236 **** +--- 231,240 ---- + #define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + ++ #ifndef MAX + #define MAX(a, b) ((a) > (b) ? (a) : (b)) ++ #endif ++ #ifndef MIN + #define MIN(a, b) ((a) < (b) ? (a) : (b)) ++ #endif + + typedef char boolean; +diff -r -C 2 -P base/cvs-1.6.5/lib/save-cwd.c cvs-1.6.5/lib/save-cwd.c +*** base/cvs-1.6.5/lib/save-cwd.c Sat Oct 28 07:20:10 1995 +--- cvs-1.6.5/lib/save-cwd.c Wed Jan 10 13:22:50 1996 +*************** +*** 122,126 **** + } + } +! else if (chdir (cwd->name) < 0) + { + error (0, errno, "%s", cwd->name); +--- 122,126 ---- + } + } +! else if (CVS_CHDIR (cwd->name) < 0) + { + error (0, errno, "%s", cwd->name); +diff -r -C 2 -P base/cvs-1.6.5/lib/system.h cvs-1.6.5/lib/system.h +*** base/cvs-1.6.5/lib/system.h Thu Jan 4 06:20:14 1996 +--- cvs-1.6.5/lib/system.h Tue Jan 9 05:33:06 1996 +*************** +*** 434,443 **** + #endif + +! /* Under MS-DOS and its derivatives (like Windows NT), mkdir takes only one +! argument; permission is handled very differently on those systems than in +! in Unix. So we leave such systems a hook on which they can hang their +! own definitions. */ + #ifndef CVS_MKDIR + #define CVS_MKDIR mkdir + #endif + +--- 434,483 ---- + #endif + +! /* Under non-UNIX operating systems (MS-DOS, WinNT, MacOS), many filesystem +! calls take only one argument; permission is handled very differently on +! those systems than in Unix. So we leave such systems a hook on which they +! can hang their own definitions. */ + #ifndef CVS_MKDIR + #define CVS_MKDIR mkdir ++ #endif ++ ++ #ifndef CVS_MKDIR ++ #define CVS_MKDIR mkdir ++ #endif ++ ++ #ifndef CVS_OPEN ++ #define CVS_OPEN open ++ #endif ++ ++ #ifndef CVS_CREAT ++ #define CVS_CREAT creat ++ #endif ++ ++ #ifndef CVS_FOPEN ++ #define CVS_FOPEN fopen ++ #endif ++ ++ #ifndef CVS_CHDIR ++ #define CVS_CHDIR chdir ++ #endif ++ ++ #ifndef CVS_ACCESS ++ #define CVS_ACCESS access ++ #endif ++ ++ #ifndef CVS_OPENDIR ++ #define CVS_OPENDIR opendir ++ #endif ++ ++ #ifndef CVS_STAT ++ #define CVS_STAT stat ++ #endif ++ ++ #ifndef CVS_RENAME ++ #define CVS_RENAME rename ++ #endif ++ ++ #ifndef CVS_UNLINK ++ #define CVS_UNLINK unlink + #endif + +diff -r -C 2 -P base/cvs-1.6.5/src/add.c cvs-1.6.5/src/add.c +*** base/cvs-1.6.5/src/add.c Thu Jan 4 06:20:24 1996 +--- cvs-1.6.5/src/add.c Tue Jan 9 05:33:07 1996 +*************** +*** 381,385 **** + if (save_cwd (&cwd)) + return (1); +! if (chdir (dir) < 0) + { + error (0, errno, "cannot chdir to %s", dir); +--- 381,385 ---- + if (save_cwd (&cwd)) + return (1); +! if (CVS_CHDIR (dir) < 0) + { + error (0, errno, "cannot chdir to %s", dir); +diff -r -C 2 -P base/cvs-1.6.5/src/checkout.c cvs-1.6.5/src/checkout.c +*** base/cvs-1.6.5/src/checkout.c Thu Jan 4 06:20:25 1996 +--- cvs-1.6.5/src/checkout.c Tue Jan 9 05:33:07 1996 +*************** +*** 351,355 **** + + (void) CVS_MKDIR (where, 0777); +! if (chdir (where) < 0) + error (1, errno, "cannot chdir to %s", where); + preload_update_dir = xstrdup (where); +--- 351,355 ---- + + (void) CVS_MKDIR (where, 0777); +! if (CVS_CHDIR (where) < 0) + error (1, errno, "cannot chdir to %s", where); + preload_update_dir = xstrdup (where); +*************** +*** 402,406 **** + *slash = '\0'; + +! if (chdir (where) < 0) + error (1, errno, "cannot chdir to %s", where); + +--- 402,406 ---- + *slash = '\0'; + +! if (CVS_CHDIR (where) < 0) + error (1, errno, "cannot chdir to %s", where); + +*************** +*** 716,720 **** + if (pipeout) + { +! if (chdir (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); +--- 716,720 ---- + if (pipeout) + { +! if (CVS_CHDIR (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); +*************** +*** 855,859 **** + *slash2 = '\0'; + (void) CVS_MKDIR (cp, 0777); +! if (chdir (cp) < 0) + { + error (0, errno, "cannot chdir to %s", cp); +--- 855,859 ---- + *slash2 = '\0'; + (void) CVS_MKDIR (cp, 0777); +! if (CVS_CHDIR (cp) < 0) + { + error (0, errno, "cannot chdir to %s", cp); +*************** +*** 883,887 **** + } + (void) CVS_MKDIR (cp, 0777); +! if (chdir (cp) < 0) + { + error (0, errno, "cannot chdir to %s", cp); +--- 883,887 ---- + } + (void) CVS_MKDIR (cp, 0777); +! if (CVS_CHDIR (cp) < 0) + { + error (0, errno, "cannot chdir to %s", cp); +diff -r -C 2 -P base/cvs-1.6.5/src/client.c cvs-1.6.5/src/client.c +*** base/cvs-1.6.5/src/client.c Tue Jan 9 06:20:21 1996 +--- cvs-1.6.5/src/client.c Tue Jan 9 05:33:07 1996 +*************** +*** 375,382 **** + error (1, 0, "premature end of file from server"); + } +- +- if (c == '\n') +- break; + + result[input_index++] = c; + while (input_index + 1 >= result_size) +--- 375,382 ---- + error (1, 0, "premature end of file from server"); + } + ++ if (c == '\012') ++ break; ++ + result[input_index++] = c; + while (input_index + 1 >= result_size) +*************** +*** 691,697 **** + "could not get working directory: %s", toplevel_wd); + +! if (chdir (toplevel_wd) < 0) + error (1, errno, "could not chdir to %s", toplevel_wd); +! if (chdir (dirname) < 0) + { + char *dir; +--- 691,697 ---- + "could not get working directory: %s", toplevel_wd); + +! if (CVS_CHDIR (toplevel_wd) < 0) + error (1, errno, "could not chdir to %s", toplevel_wd); +! if (CVS_CHDIR (dirname) < 0) + { + char *dir; +*************** +*** 838,842 **** + free (dir); + /* Now it better work. */ +! if (chdir (dirname) < 0) + error (1, errno, "could not chdir to %s", dirname); + } +--- 838,842 ---- + free (dir); + /* Now it better work. */ +! if (CVS_CHDIR (dirname) < 0) + error (1, errno, "could not chdir to %s", dirname); + } +*************** +*** 1087,1091 **** + bin = 0; + +! fd = open (temp_filename, + O_WRONLY | O_CREAT | O_TRUNC | (bin ? OPEN_BINARY : 0), + 0777); +--- 1087,1091 ---- + bin = 0; + +! fd = CVS_OPEN (temp_filename, + O_WRONLY | O_CREAT | O_TRUNC | (bin ? OPEN_BINARY : 0), + 0777); +*************** +*** 1134,1138 **** + convert_file (temp_filename, O_RDONLY | OPEN_BINARY, + filename, O_WRONLY | O_CREAT | O_TRUNC); +! if (unlink (temp_filename) < 0) + error (0, errno, "warning: couldn't delete %s", + temp_filename); +--- 1134,1138 ---- + convert_file (temp_filename, O_RDONLY | OPEN_BINARY, + filename, O_WRONLY | O_CREAT | O_TRUNC); +! if (CVS_UNLINK (temp_filename) < 0) + error (0, errno, "warning: couldn't delete %s", + temp_filename); +*************** +*** 1156,1160 **** + error (1, 0, "patch original file %s does not exist", + short_pathname); +! if (stat (temp_filename, &s) < 0) + error (1, 1, "can't stat patch file %s", temp_filename); + if (s.st_size == 0) +--- 1156,1160 ---- + error (1, 0, "patch original file %s does not exist", + short_pathname); +! if (CVS_STAT (temp_filename, &s) < 0) + error (1, 1, "can't stat patch file %s", temp_filename); + if (s.st_size == 0) +*************** +*** 1227,1231 **** + * way they were transmitted. + */ +! e = fopen (filename, "r"); + if (e == NULL) + error (1, errno, "could not open %s", short_pathname); +--- 1227,1231 ---- + * way they were transmitted. + */ +! e = CVS_FOPEN (filename, "r"); + if (e == NULL) + error (1, errno, "could not open %s", short_pathname); +*************** +*** 1639,1643 **** + if (toplevel_wd[0] != '\0') + { +! if (chdir (toplevel_wd) < 0) + error (1, errno, "could not chdir to %s", toplevel_wd); + } +--- 1639,1643 ---- + if (toplevel_wd[0] != '\0') + { +! if (CVS_CHDIR (toplevel_wd) < 0) + error (1, errno, "could not chdir to %s", toplevel_wd); + } +*************** +*** 1685,1689 **** + struct dirent *dp; + +! if ((dirp = opendir (dir)) == NULL) + { + if (! existence_error (errno)) +--- 1685,1689 ---- + struct dirent *dp; + +! if ((dirp = CVS_OPENDIR (dir)) == NULL) + { + if (! existence_error (errno)) +*************** +*** 1742,1746 **** + if (toplevel_wd[0] != '\0') + { +! if (chdir (toplevel_wd) < 0) + error (1, errno, "could not chdir to %s", toplevel_wd); + } +--- 1742,1746 ---- + if (toplevel_wd[0] != '\0') + { +! if (CVS_CHDIR (toplevel_wd) < 0) + error (1, errno, "could not chdir to %s", toplevel_wd); + } +*************** +*** 1828,1832 **** + sprintf (adm_name, "%s/%s", dir, CVSADM_TAG); + +! f = fopen (adm_name, "r"); + if (f == NULL) + { +--- 1828,1832 ---- + sprintf (adm_name, "%s/%s", dir, CVSADM_TAG); + +! f = CVS_FOPEN (adm_name, "r"); + if (f == NULL) + { +*************** +*** 1860,1864 **** + sprintf (adm_name, "%s/%s", dir, CVSADM_CIPROG); + +! f = fopen (adm_name, "r"); + if (f == NULL) + { +--- 1860,1864 ---- + sprintf (adm_name, "%s/%s", dir, CVSADM_CIPROG); + +! f = CVS_FOPEN (adm_name, "r"); + if (f == NULL) + { +*************** +*** 1895,1899 **** + sprintf (adm_name, "%s/%s", dir, CVSADM_UPROG); + +! f = fopen (adm_name, "r"); + if (f == NULL) + { +--- 1895,1899 ---- + sprintf (adm_name, "%s/%s", dir, CVSADM_UPROG); + +! f = CVS_FOPEN (adm_name, "r"); + if (f == NULL) + { +*************** +*** 3181,3185 **** + + /* Don't think we can assume fstat exists. */ +! if (stat (file, &sb) < 0) + error (1, errno, "reading %s", short_pathname); + +--- 3181,3185 ---- + + /* Don't think we can assume fstat exists. */ +! if (CVS_STAT (file, &sb) < 0) + error (1, errno, "reading %s", short_pathname); + +*************** +*** 3202,3206 **** + bin = 0; + +! fd = open (file, O_RDONLY | (bin ? OPEN_BINARY : 0)); + + if (fd < 0) +--- 3202,3206 ---- + bin = 0; + +! fd = CVS_OPEN (file, O_RDONLY | (bin ? OPEN_BINARY : 0)); + + if (fd < 0) +*************** +*** 3256,3260 **** + the translation mode to created processes via environment + variables, ick. */ +! fd = open (tempfile, O_RDONLY | OPEN_BINARY); + if (fd < 0) + error (1, errno, "reading %s", short_pathname); +--- 3256,3260 ---- + the translation mode to created processes via environment + variables, ick. */ +! fd = CVS_OPEN (tempfile, O_RDONLY | OPEN_BINARY); + if (fd < 0) + error (1, errno, "reading %s", short_pathname); +*************** +*** 3297,3301 **** + if (converting) + { +! if (unlink (tempfile) < 0) + error (0, errno, + "warning: can't remove temp file %s", tempfile); +--- 3297,3301 ---- + if (converting) + { +! if (CVS_UNLINK (tempfile) < 0) + error (0, errno, + "warning: can't remove temp file %s", tempfile); +*************** +*** 3800,3804 **** + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", CVSADM_NOTIFY); +! if (unlink (CVSADM_NOTIFY) < 0) + error (0, errno, "cannot remove %s", CVSADM_NOTIFY); + return; +--- 3800,3804 ---- + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", CVSADM_NOTIFY); +! if (CVS_UNLINK (CVSADM_NOTIFY) < 0) + error (0, errno, "cannot remove %s", CVSADM_NOTIFY); + return; +*************** +*** 3845,3849 **** + return; + } +! if (rename (CVSADM_NOTIFYTMP, CVSADM_NOTIFY) < 0) + error (0, errno, "cannot rename %s to %s", CVSADM_NOTIFYTMP, + CVSADM_NOTIFY); +--- 3845,3849 ---- + return; + } +! if (CVS_RENAME (CVSADM_NOTIFYTMP, CVSADM_NOTIFY) < 0) + error (0, errno, "cannot rename %s to %s", CVSADM_NOTIFYTMP, + CVSADM_NOTIFY); +diff -r -C 2 -P base/cvs-1.6.5/src/commit.c cvs-1.6.5/src/commit.c +*** base/cvs-1.6.5/src/commit.c Fri Jan 5 06:20:20 1996 +--- cvs-1.6.5/src/commit.c Tue Jan 9 05:33:07 1996 +*************** +*** 297,301 **** + error (1, 0, "cannot specify both a message and a log file"); + +! if ((logfd = open (logfile, O_RDONLY | OPEN_BINARY)) < 0) + error (1, errno, "cannot open log file %s", logfile); + +--- 297,301 ---- + error (1, 0, "cannot specify both a message and a log file"); + +! if ((logfd = CVS_OPEN (logfile, O_RDONLY | OPEN_BINARY)) < 0) + error (1, errno, "cannot open log file %s", logfile); + +*************** +*** 1088,1092 **** + FILE *fp; + +! if ((fp = fopen (CVSADM_CIPROG, "r")) != NULL) + { + char *line; +--- 1088,1092 ---- + FILE *fp; + +! if ((fp = CVS_FOPEN (CVSADM_CIPROG, "r")) != NULL) + { + char *line; +*************** +*** 1414,1418 **** + #ifdef DEATH_SUPPORT + if (strcmp (rcs, tmp) != 0 +! && rename (rcs, tmp) == -1 + && (isreadable (rcs) || !isreadable (tmp))) + { +--- 1414,1418 ---- + #ifdef DEATH_SUPPORT + if (strcmp (rcs, tmp) != 0 +! && CVS_RENAME (rcs, tmp) == -1 + && (isreadable (rcs) || !isreadable (tmp))) + { +*************** +*** 1434,1438 **** + #else /* No DEATH_SUPPORT */ + +! if ((strcmp (rcs, tmp) == 0 || rename (rcs, tmp) != -1) || + (!isreadable (rcs) && isreadable (tmp))) + { +--- 1434,1438 ---- + #else /* No DEATH_SUPPORT */ + +! if ((strcmp (rcs, tmp) == 0 || CVS_RENAME (rcs, tmp) != -1) || + (!isreadable (rcs) && isreadable (tmp))) + { +*************** +*** 1589,1593 **** + + if (strcmp (oldfile, rcs) == 0 +! || rename (oldfile, rcs) != 0 + || isreadable (oldfile) + || !isreadable (rcs)) +--- 1589,1593 ---- + + if (strcmp (oldfile, rcs) == 0 +! || CVS_RENAME (oldfile, rcs) != 0 + || isreadable (oldfile) + || !isreadable (rcs)) +*************** +*** 1872,1876 **** + struct stat sb; + +! if (stat (user, &sb) != -1) + (void) chmod (rcs, (int) sb.st_mode & ~0222); + } +--- 1872,1876 ---- + struct stat sb; + +! if (CVS_STAT (user, &sb) != -1) + (void) chmod (rcs, (int) sb.st_mode & ~0222); + } +diff -r -C 2 -P base/cvs-1.6.5/src/create_adm.c cvs-1.6.5/src/create_adm.c +*** base/cvs-1.6.5/src/create_adm.c Fri Sep 8 07:20:21 1995 +--- cvs-1.6.5/src/create_adm.c Tue Jan 9 05:33:07 1996 +*************** +*** 66,70 **** + else + (void) strcpy (tmp, CVSADM_REP); +! fout = fopen (tmp, "w+"); + if (fout == NULL) + { +--- 66,70 ---- + else + (void) strcpy (tmp, CVSADM_REP); +! fout = CVS_FOPEN (tmp, "w+"); + if (fout == NULL) + { +*************** +*** 112,116 **** + else + (void) strcpy (tmp, CVSADM_ENT); +! fout = fopen (tmp, "w+"); + if (fout == NULL) + { +--- 112,116 ---- + else + (void) strcpy (tmp, CVSADM_ENT); +! fout = CVS_FOPEN (tmp, "w+"); + if (fout == NULL) + { +diff -r -C 2 -P base/cvs-1.6.5/src/cvs.h cvs-1.6.5/src/cvs.h +*** base/cvs-1.6.5/src/cvs.h Wed Jan 3 06:20:23 1996 +--- cvs-1.6.5/src/cvs.h Tue Jan 9 05:33:06 1996 +*************** +*** 231,236 **** +--- 231,241 ---- + #endif + ++ #ifndef FALSE + #define FALSE 0 ++ #endif ++ ++ #ifndef TRUE + #define TRUE 1 ++ #endif + + /* +diff -r -C 2 -P base/cvs-1.6.5/src/diff.c cvs-1.6.5/src/diff.c +*** base/cvs-1.6.5/src/diff.c Thu Jan 4 06:20:27 1996 +--- cvs-1.6.5/src/diff.c Tue Jan 9 05:33:07 1996 +*************** +*** 373,377 **** + if (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY) == -1) + { +! (void) unlink (tmp); + error (1, errno, "fork failed during checkout of %s", + vers->srcfile->path); +--- 373,377 ---- + if (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY) == -1) + { +! (void) CVS_UNLINK (tmp); + error (1, errno, "fork failed during checkout of %s", + vers->srcfile->path); +*************** +*** 423,427 **** + + if (empty_file == DIFF_REMOVED) +! (void) unlink (tmp); + + (void) fflush (stdout); +--- 423,427 ---- + + if (empty_file == DIFF_REMOVED) +! (void) CVS_UNLINK (tmp); + + (void) fflush (stdout); +*************** +*** 611,620 **** + if (xcmp (file, tmp) == 0) + { +! (void) unlink (tmp); + return (1); + } + break; + case -1: /* fork failed */ +! (void) unlink (tmp); + error (1, errno, "fork failed during checkout of %s", + vers->srcfile->path); +--- 611,620 ---- + if (xcmp (file, tmp) == 0) + { +! (void) CVS_UNLINK (tmp); + return (1); + } + break; + case -1: /* fork failed */ +! (void) CVS_UNLINK (tmp); + error (1, errno, "fork failed during checkout of %s", + vers->srcfile->path); +*************** +*** 622,626 **** + break; + } +! (void) unlink (tmp); + return (0); + } +--- 622,626 ---- + break; + } +! (void) CVS_UNLINK (tmp); + return (0); + } +diff -r -C 2 -P base/cvs-1.6.5/src/edit.c cvs-1.6.5/src/edit.c +*** base/cvs-1.6.5/src/edit.c Thu Jan 4 06:20:27 1996 +--- cvs-1.6.5/src/edit.c Tue Jan 9 05:33:07 1996 +*************** +*** 180,184 **** + is most sensible. */ + +! fp = fopen (CVSADM_NOTIFY, "r"); + if (fp == NULL) + { +--- 180,184 ---- + is most sensible. */ + +! fp = CVS_FOPEN (CVSADM_NOTIFY, "r"); + if (fp == NULL) + { +*************** +*** 225,229 **** + error (0, errno, "cannot close %s", CVSADM_NOTIFY); + +! if (unlink (CVSADM_NOTIFY) < 0) + error (0, errno, "cannot remove %s", CVSADM_NOTIFY); + +--- 225,229 ---- + error (0, errno, "cannot close %s", CVSADM_NOTIFY); + +! if (CVS_UNLINK (CVSADM_NOTIFY) < 0) + error (0, errno, "cannot remove %s", CVSADM_NOTIFY); + +*************** +*** 810,814 **** + is most sensible. */ + +! fp = fopen (CVSADM_NOTIFY, "r"); + if (fp == NULL) + { +--- 810,814 ---- + is most sensible. */ + +! fp = CVS_FOPEN (CVSADM_NOTIFY, "r"); + if (fp == NULL) + { +diff -r -C 2 -P base/cvs-1.6.5/src/entries.c cvs-1.6.5/src/entries.c +*** base/cvs-1.6.5/src/entries.c Thu Jan 4 06:20:28 1996 +--- cvs-1.6.5/src/entries.c Tue Jan 9 05:33:07 1996 +*************** +*** 280,284 **** + { + struct stat sb; +! if (strlen (ts) > 30 && stat (user, &sb) == 0) + { + char *c = ctime (&sb.st_mtime); +--- 280,284 ---- + { + struct stat sb; +! if (strlen (ts) > 30 && CVS_STAT (user, &sb) == 0) + { + char *c = ctime (&sb.st_mtime); +*************** +*** 373,377 **** + } + +! fpin = fopen (CVSADM_ENT, "r"); + if (fpin == NULL) + error (0, errno, "cannot open %s for reading", CVSADM_ENT); +--- 373,377 ---- + } + +! fpin = CVS_FOPEN (CVSADM_ENT, "r"); + if (fpin == NULL) + error (0, errno, "cannot open %s for reading", CVSADM_ENT); +*************** +*** 384,390 **** + + fclose (fpin); + } + +! fpin = fopen (CVSADM_ENTLOG, "r"); + if (fpin != NULL) + { +--- 384,391 ---- + + fclose (fpin); ++ fpin = NULL; + } + +! fpin = CVS_FOPEN (CVSADM_ENTLOG, "r"); + if (fpin != NULL) + { +*************** +*** 395,398 **** +--- 396,400 ---- + do_rewrite = 1; + fclose (fpin); ++ fpin = NULL; + } + +*************** +*** 528,532 **** + if (datep) + *datep = (char *) NULL; +! fp = fopen (CVSADM_TAG, "r"); + if (fp) + { +--- 530,534 ---- + if (datep) + *datep = (char *) NULL; +! fp = CVS_FOPEN (CVSADM_TAG, "r"); + if (fp) + { +diff -r -C 2 -P base/cvs-1.6.5/src/error.c cvs-1.6.5/src/error.c +*** base/cvs-1.6.5/src/error.c Sat Dec 16 06:20:29 1995 +--- cvs-1.6.5/src/error.c Tue Jan 9 05:33:07 1996 +*************** +*** 67,71 **** +--- 67,73 ---- + #endif /* STDC_HEADERS */ + ++ #ifndef macintosh + extern char *strerror (); ++ #endif + + typedef void (*fn_returning_void) PROTO((void)); +diff -r -C 2 -P base/cvs-1.6.5/src/fileattr.c cvs-1.6.5/src/fileattr.c +*** base/cvs-1.6.5/src/fileattr.c Fri Dec 22 06:20:27 1995 +--- cvs-1.6.5/src/fileattr.c Tue Jan 9 05:33:07 1996 +*************** +*** 79,83 **** + + attr_read_attempted = 1; +! fp = fopen (fname, "r"); + if (fp == NULL) + { +--- 79,83 ---- + + attr_read_attempted = 1; +! fp = CVS_FOPEN (fname, "r"); + if (fp == NULL) + { +*************** +*** 440,444 **** + + omask = umask (cvsumask); +! fp = fopen (fname, "w"); + if (fp == NULL) + { +--- 440,444 ---- + + omask = umask (cvsumask); +! fp = CVS_FOPEN (fname, "w"); + if (fp == NULL) + { +*************** +*** 465,469 **** + free (repname); + +! fp = fopen (fname, "w"); + } + if (fp == NULL) +--- 465,469 ---- + free (repname); + +! fp = CVS_FOPEN (fname, "w"); + } + if (fp == NULL) +diff -r -C 2 -P base/cvs-1.6.5/src/filesubr.c cvs-1.6.5/src/filesubr.c +*** base/cvs-1.6.5/src/filesubr.c Tue Jan 2 06:20:27 1996 +--- cvs-1.6.5/src/filesubr.c Tue Jan 9 05:48:57 1996 +*************** +*** 61,69 **** + return; + +! if ((fdin = open (from, O_RDONLY)) < 0) + error (1, errno, "cannot open %s for copying", from); + if (fstat (fdin, &sb) < 0) + error (1, errno, "cannot fstat %s", from); +! if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0) + error (1, errno, "cannot create %s for copying", to); + if (sb.st_size > 0) +--- 61,69 ---- + return; + +! if ((fdin = CVS_OPEN (from, O_RDONLY)) < 0) + error (1, errno, "cannot open %s for copying", from); + if (fstat (fdin, &sb) < 0) + error (1, errno, "cannot fstat %s", from); +! if ((fdout = CVS_CREAT (to, (int) sb.st_mode & 07777)) < 0) + error (1, errno, "cannot create %s for copying", to); + if (sb.st_size > 0) +*************** +*** 122,126 **** + struct stat sb; + +! if (stat (file, &sb) < 0) + return (0); + return (S_ISDIR (sb.st_mode)); +--- 122,126 ---- + struct stat sb; + +! if (CVS_STAT (file, &sb) < 0) + return (0); + return (S_ISDIR (sb.st_mode)); +*************** +*** 192,196 **** + int uid; + +! if (stat(file, &sb) == -1) + return 0; + if (mode == F_OK) +--- 192,196 ---- + int uid; + +! if (CVS_STAT(file, &sb) == -1) + return 0; + if (mode == F_OK) +*************** +*** 232,236 **** + return (sb.st_mode & omask) == omask; + #else +! return access(file, mode) == 0; + #endif + } +--- 232,236 ---- + return (sb.st_mode & omask) == omask; + #else +! return CVS_ACCESS (file, mode) == 0; + #endif + } +*************** +*** 246,250 **** + FILE *fp; + +! if ((fp = fopen (name, mode)) == NULL) + error (1, errno, "cannot open %s", name); + return (fp); +--- 246,250 ---- + FILE *fp; + +! if ((fp = CVS_FOPEN (name, mode)) == NULL) + error (1, errno, "cannot open %s", name); + return (fp); +*************** +*** 260,266 **** + struct stat sb; + +! if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) + error (0, 0, "%s already exists but is not a directory", name); +! if (!noexec && mkdir (name, 0777) < 0) + error (1, errno, "cannot make directory %s", name); + } +--- 260,266 ---- + struct stat sb; + +! if (CVS_STAT (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) + error (0, 0, "%s already exists but is not a directory", name); +! if (!noexec && CVS_MKDIR (name, 0777) < 0) + error (1, errno, "cannot make directory %s", name); + } +*************** +*** 279,283 **** + return; + +! if (mkdir (name, 0777) == 0 || errno == EEXIST) + return; + if (! existence_error (errno)) +--- 279,283 ---- + return; + +! if (CVS_MKDIR (name, 0777) == 0 || errno == EEXIST) + return; + if (! existence_error (errno)) +*************** +*** 293,297 **** + if (*cp == '\0') + return; +! (void) mkdir (name, 0777); + } + +--- 293,297 ---- + if (*cp == '\0') + return; +! (void) CVS_MKDIR (name, 0777); + } + +*************** +*** 308,312 **** + mode_t mode, oumask; + +! if (stat (fname, &sb) < 0) + { + if (!noexec) +--- 308,312 ---- + mode_t mode, oumask; + +! if (CVS_STAT (fname, &sb) < 0) + { + if (!noexec) +*************** +*** 360,364 **** + return; + +! if (rename (from, to) < 0) + error (1, errno, "cannot rename file %s to %s", from, to); + } +--- 360,364 ---- + return; + +! if (CVS_RENAME (from, to) < 0) + error (1, errno, "cannot rename file %s to %s", from, to); + } +*************** +*** 384,388 **** +--- 384,392 ---- + return (0); + ++ #ifdef macintosh ++ return (symlink (from, to)); ++ #else + return (link (from, to)); ++ #endif + } + +*************** +*** 404,408 **** + return (0); + +! return (unlink (f)); + } + +--- 408,412 ---- + return (0); + +! return (CVS_UNLINK (f)); + } + +*************** +*** 426,430 **** + return (0); + +! if (unlink (f) != 0) + { + /* under NEXTSTEP errno is set to return EPERM if +--- 430,434 ---- + return (0); + +! if (CVS_UNLINK (f) != 0) + { + /* under NEXTSTEP errno is set to return EPERM if +*************** +*** 461,465 **** + if ( rmdir (path) != 0 && errno == ENOTEMPTY ) + { +! if ((dirp = opendir (path)) == NULL) + /* If unable to open the directory return + * an error +--- 465,469 ---- + if ( rmdir (path) != 0 && errno == ENOTEMPTY ) + { +! if ((dirp = CVS_OPENDIR (path)) == NULL) + /* If unable to open the directory return + * an error +*************** +*** 475,479 **** + sprintf (buf, "%s/%s", path, dp->d_name); + +! if (unlink (buf) != 0 ) + { + if (errno == EISDIR || errno == EPERM) +--- 479,483 ---- + sprintf (buf, "%s/%s", path, dp->d_name); + +! if (CVS_UNLINK (buf) != 0 ) + { + if (errno == EISDIR || errno == EPERM) +*************** +*** 550,556 **** + int ret; + +! if ((fd1 = open (file1, O_RDONLY)) < 0) + error (1, errno, "cannot open file %s for comparing", file1); +! if ((fd2 = open (file2, O_RDONLY)) < 0) + error (1, errno, "cannot open file %s for comparing", file2); + if (fstat (fd1, &sb1) < 0) +--- 554,560 ---- + int ret; + +! if ((fd1 = CVS_OPEN (file1, O_RDONLY)) < 0) + error (1, errno, "cannot open file %s for comparing", file1); +! if ((fd2 = CVS_OPEN (file2, O_RDONLY)) < 0) + error (1, errno, "cannot open file %s for comparing", file2); + if (fstat (fd1, &sb1) < 0) +diff -r -C 2 -P base/cvs-1.6.5/src/find_names.c cvs-1.6.5/src/find_names.c +*** base/cvs-1.6.5/src/find_names.c Sat Dec 16 06:20:30 1995 +--- cvs-1.6.5/src/find_names.c Tue Jan 9 05:33:07 1996 +*************** +*** 129,133 **** + /* look only for CVS controlled sub-directories */ + if (find_dirs (".", dirlist, 1) != 0) +! error (1, errno, "cannot open current directory"); + } + +--- 129,133 ---- + /* look only for CVS controlled sub-directories */ + if (find_dirs (".", dirlist, 1) != 0) +! error (1, errno, "cannot open current directory\n"); + } + +*************** +*** 171,175 **** + + /* set up to read the dir */ +! if ((dirp = opendir (dir)) == NULL) + return (1); + +--- 171,175 ---- + + /* set up to read the dir */ +! if ((dirp = CVS_OPENDIR (dir)) == NULL) + return (1); + +*************** +*** 211,217 **** + + /* set up to read the dir */ +! if ((dirp = opendir (dir)) == NULL) + return (1); +- + /* read the dir, grabbing sub-dirs */ + while ((dp = readdir (dirp)) != NULL) +--- 211,216 ---- + + /* set up to read the dir */ +! if ((dirp = CVS_OPENDIR (dir)) == NULL) + return (1); + /* read the dir, grabbing sub-dirs */ + while ((dp = readdir (dirp)) != NULL) +diff -r -C 2 -P base/cvs-1.6.5/src/history.c cvs-1.6.5/src/history.c +*** base/cvs-1.6.5/src/history.c Thu Jan 4 06:20:28 1996 +--- cvs-1.6.5/src/history.c Tue Jan 9 05:33:07 1996 +*************** +*** 702,706 **** + if (noexec) + return; +! if ((fd = open (fname, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0) + error (1, errno, "cannot open history file: %s", fname); + +--- 702,706 ---- + if (noexec) + return; +! if ((fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0) + error (1, errno, "cannot open history file: %s", fname); + +*************** +*** 729,737 **** + if (!getwd (workdir)) + error (1, errno, "can't getwd in history"); +! if (chdir (pw->pw_dir) < 0) + error (1, errno, "can't chdir(%s)", pw->pw_dir); + if (!getwd (homedir)) + error (1, errno, "can't getwd in %s", pw->pw_dir); +! (void) chdir (workdir); + + i = strlen (homedir); +--- 729,737 ---- + if (!getwd (workdir)) + error (1, errno, "can't getwd in history"); +! if (CVS_CHDIR (pw->pw_dir) < 0) + error (1, errno, "can't chdir(%s)", pw->pw_dir); + if (!getwd (homedir)) + error (1, errno, "can't getwd in %s", pw->pw_dir); +! (void) CVS_CHDIR (workdir); + + i = strlen (homedir); +*************** +*** 1001,1005 **** + struct stat st_buf; + +! if ((fd = open (fname, O_RDONLY)) < 0) + error (1, errno, "cannot open history file: %s", fname); + +--- 1001,1005 ---- + struct stat st_buf; + +! if ((fd = CVS_OPEN (fname, O_RDONLY)) < 0) + error (1, errno, "cannot open history file: %s", fname); + +diff -r -C 2 -P base/cvs-1.6.5/src/ignore.c cvs-1.6.5/src/ignore.c +*** base/cvs-1.6.5/src/ignore.c Thu Jan 4 06:20:29 1996 +--- cvs-1.6.5/src/ignore.c Tue Jan 9 05:33:07 1996 +*************** +*** 132,136 **** + + /* load the file */ +! fp = fopen (file, "r"); + if (fp == NULL) + { +--- 132,136 ---- + + /* load the file */ +! fp = CVS_FOPEN (file, "r"); + if (fp == NULL) + { +*************** +*** 317,321 **** + xdir = update_dir; + +! dirp = opendir ("."); + if (dirp == NULL) + return; +--- 317,321 ---- + xdir = update_dir; + +! dirp = CVS_OPENDIR ("."); + if (dirp == NULL) + return; +diff -r -C 2 -P base/cvs-1.6.5/src/import.c cvs-1.6.5/src/import.c +*** base/cvs-1.6.5/src/import.c Thu Jan 4 06:20:29 1996 +--- cvs-1.6.5/src/import.c Tue Jan 9 05:33:08 1996 +*************** +*** 250,256 **** + + /* Create the logfile that will be logged upon completion */ +! if ((logfp = fopen (tmpnam (tmpfile), "w+")) == NULL) + error (1, errno, "cannot create temporary file `%s'", tmpfile); +! (void) unlink (tmpfile); /* to be sure it goes away */ + (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]); + (void) fprintf (logfp, "Release Tags:\t"); +--- 250,256 ---- + + /* Create the logfile that will be logged upon completion */ +! if ((logfp = CVS_FOPEN (tmpnam (tmpfile), "w+")) == NULL) + error (1, errno, "cannot create temporary file `%s'", tmpfile); +! (void) CVS_UNLINK (tmpfile); /* to be sure it goes away */ + (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]); + (void) fprintf (logfp, "Release Tags:\t"); +*************** +*** 302,306 **** + /* Make sure the temporary file goes away, even on systems that don't let + you delete a file that's in use. */ +! unlink (tmpfile); + + if (message) +--- 302,306 ---- + /* Make sure the temporary file goes away, even on systems that don't let + you delete a file that's in use. */ +! CVS_UNLINK (tmpfile); + + if (message) +*************** +*** 329,333 **** + wrap_add_file (CVSDOTWRAPPER, 1); + +! if ((dirp = opendir (".")) == NULL) + { + err++; +--- 329,333 ---- + wrap_add_file (CVSDOTWRAPPER, 1); + +! if ((dirp = CVS_OPENDIR (".")) == NULL) + { + err++; +*************** +*** 867,871 **** + tocvsPath = wrap_tocvs_process_file (user); + userfile = (tocvsPath == NULL ? user : tocvsPath); +! fpuser = fopen (userfile, "r"); + if (fpuser == NULL) { + /* not fatal, continue import */ +--- 867,871 ---- + tocvsPath = wrap_tocvs_process_file (user); + userfile = (tocvsPath == NULL ? user : tocvsPath); +! fpuser = CVS_FOPEN (userfile, "r"); + if (fpuser == NULL) { + /* not fatal, continue import */ +*************** +*** 874,878 **** + goto read_error; + } +! fprcs = fopen (rcs, "w+"); + if (fprcs == NULL) { + ierrno = errno; +--- 874,878 ---- + goto read_error; + } +! fprcs = CVS_FOPEN (rcs, "w+"); + if (fprcs == NULL) { + ierrno = errno; +*************** +*** 1036,1040 **** + if (ierrno == ENOSPC) + { +! (void) unlink (rcs); + fperror (logfp, 0, 0, "ERROR: out of space - aborting"); + error (1, 0, "ERROR: out of space - aborting"); +--- 1036,1040 ---- + if (ierrno == ENOSPC) + { +! (void) CVS_UNLINK (rcs); + fperror (logfp, 0, 0, "ERROR: out of space - aborting"); + error (1, 0, "ERROR: out of space - aborting"); +*************** +*** 1149,1153 **** + #endif + +! if (chdir (dir) < 0) + { + ierrno = errno; +--- 1149,1153 ---- + #endif + +! if (CVS_CHDIR (dir) < 0) + { + ierrno = errno; +diff -r -C 2 -P base/cvs-1.6.5/src/lock.c cvs-1.6.5/src/lock.c +*** base/cvs-1.6.5/src/lock.c Mon Dec 18 06:20:26 1995 +--- cvs-1.6.5/src/lock.c Tue Jan 9 05:33:08 1996 +*************** +*** 84,88 **** + { + (void) sprintf (tmp, "%s/%s", repository, readlock); +! if (unlink (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + } +--- 84,88 ---- + { + (void) sprintf (tmp, "%s/%s", repository, readlock); +! if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + } +*************** +*** 91,95 **** + { + (void) sprintf (tmp, "%s/%s", repository, writelock); +! if (unlink (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + } +--- 91,95 ---- + { + (void) sprintf (tmp, "%s/%s", repository, writelock); +! if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + } +*************** +*** 133,137 **** + /* Check if the uidlock is in the lock directory */ + sprintf(uidlock, "%s/uidlock%d", lockdir, geteuid() ); +! if( stat(uidlock, &sb) != -1) + return 1; /* The file exists, therefore we own the lock */ + else +--- 133,137 ---- + /* Check if the uidlock is in the lock directory */ + sprintf(uidlock, "%s/uidlock%d", lockdir, geteuid() ); +! if( CVS_STAT (uidlock, &sb) != -1) + return 1; /* The file exists, therefore we own the lock */ + else +*************** +*** 140,144 **** + */ + #else +! if (stat (lockdir, &sb) != -1 && sb.st_uid == geteuid ()) + return 1; + else +--- 140,144 ---- + */ + #else +! if (CVS_STAT (lockdir, &sb) != -1 && sb.st_uid == geteuid ()) + return 1; + else +*************** +*** 190,203 **** + #endif + getpid()); +! if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + error (0, errno, "cannot create read lock in repository `%s'", + xrepository); + readlock[0] = '\0'; +! if (unlink (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + return (1); + } +! if (unlink (tmp) < 0) + error (0, errno, "failed to remove lock %s", tmp); + #endif +--- 190,203 ---- + #endif + getpid()); +! if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + error (0, errno, "cannot create read lock in repository `%s'", + xrepository); + readlock[0] = '\0'; +! if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + return (1); + } +! if (CVS_UNLINK (tmp) < 0) + error (0, errno, "failed to remove lock %s", tmp); + #endif +*************** +*** 214,218 **** + /* write a read-lock */ + (void) sprintf (tmp, "%s/%s", xrepository, readlock); +! if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + error (0, errno, "cannot create read lock in repository `%s'", +--- 214,218 ---- + /* write a read-lock */ + (void) sprintf (tmp, "%s/%s", xrepository, readlock); +! if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + error (0, errno, "cannot create read lock in repository `%s'", +*************** +*** 328,340 **** + #endif + getpid ()); +! if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + error (0, errno, "cannot create write lock in repository `%s'", + repository); +! if (unlink (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + return (L_ERROR); + } +! if (unlink (tmp) < 0) + error (0, errno, "failed to remove lock %s", tmp); + #endif +--- 328,340 ---- + #endif + getpid ()); +! if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + error (0, errno, "cannot create write lock in repository `%s'", + repository); +! if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + return (L_ERROR); + } +! if (CVS_UNLINK (tmp) < 0) + error (0, errno, "failed to remove lock %s", tmp); + #endif +*************** +*** 359,367 **** + /* write the write-lock file */ + (void) sprintf (tmp, "%s/%s", repository, writelock); +! if ((fp = fopen (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + int xerrno = errno; + +! if (unlink (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + +--- 359,367 ---- + /* write the write-lock file */ + (void) sprintf (tmp, "%s/%s", repository, writelock); +! if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) + { + int xerrno = errno; + +! if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) + error (0, errno, "failed to remove lock %s", tmp); + +*************** +*** 402,406 **** + #endif + +! if ((dirp = opendir (repository)) == NULL) + error (1, 0, "cannot open directory %s", repository); + +--- 402,406 ---- + #endif + +! if ((dirp = CVS_OPENDIR (repository)) == NULL) + error (1, 0, "cannot open directory %s", repository); + +*************** +*** 417,421 **** + line = xmalloc (strlen (repository) + strlen (dp->d_name) + 5); + (void) sprintf (line, "%s/%s", repository, dp->d_name); +! if (stat (line, &sb) != -1) + { + #ifdef CVS_FUDGELOCKS +--- 417,421 ---- + line = xmalloc (strlen (repository) + strlen (dp->d_name) + 5); + (void) sprintf (line, "%s/%s", repository, dp->d_name); +! if (CVS_STAT (line, &sb) != -1) + { + #ifdef CVS_FUDGELOCKS +*************** +*** 425,429 **** + * successful, re-open the directory and try again. + */ +! if (now >= (sb.st_ctime + CVSLCKAGE) && unlink (line) != -1) + { + (void) closedir (dirp); +--- 425,429 ---- + * successful, re-open the directory and try again. + */ +! if (now >= (sb.st_ctime + CVSLCKAGE) && CVS_UNLINK (line) != -1) + { + (void) closedir (dirp); +*************** +*** 503,507 **** + + sprintf(uidlock, "%s/uidlock%d", masterlock, geteuid() ); +! if ((fp = fopen(uidlock, "w+")) == NULL) + { + /* We failed to create the uidlock, +--- 503,507 ---- + + sprintf(uidlock, "%s/uidlock%d", masterlock, geteuid() ); +! if ((fp = CVS_FOPEN (uidlock, "w+")) == NULL) + { + /* We failed to create the uidlock, +*************** +*** 539,543 **** + * someone probably just removed it (thus releasing the lock) + */ +! if (stat (masterlock, &sb) < 0) + { + if (existence_error (errno)) +--- 539,543 ---- + * someone probably just removed it (thus releasing the lock) + */ +! if (CVS_STAT (masterlock, &sb) < 0) + { + if (existence_error (errno)) +diff -r -C 2 -P base/cvs-1.6.5/src/login.c cvs-1.6.5/src/login.c +*** base/cvs-1.6.5/src/login.c Sun Dec 24 06:20:24 1995 +--- cvs-1.6.5/src/login.c Tue Jan 9 05:33:08 1996 +*************** +*** 192,196 **** + inefficient, but we're not talking about a gig of data here. */ + +! fp = fopen (passfile, "r"); + if (fp != NULL) + { +--- 192,196 ---- + inefficient, but we're not talking about a gig of data here. */ + +! fp = CVS_FOPEN (passfile, "r"); + if (fp != NULL) + { +*************** +*** 232,236 **** + + tmp_name = tmpnam (NULL); +! if ((tmp_fp = fopen (tmp_name, "w")) == NULL) + { + error (1, errno, "unable to open temp file %s", tmp_name); +--- 232,236 ---- + + tmp_name = tmpnam (NULL); +! if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL) + { + error (1, errno, "unable to open temp file %s", tmp_name); +*************** +*** 239,243 **** + chmod (tmp_name, 0600); + +! fp = fopen (passfile, "r"); + if (fp == NULL) + { +--- 239,243 ---- + chmod (tmp_name, 0600); + +! fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) + { +*************** +*** 268,272 **** + else + { +! if ((fp = fopen (passfile, "a")) == NULL) + { + error (1, errno, "could not open %s", passfile); +--- 268,272 ---- + else + { +! if ((fp = CVS_FOPEN (passfile, "a")) == NULL) + { + error (1, errno, "could not open %s", passfile); +*************** +*** 327,331 **** + /* Else get it from the file. */ + passfile = construct_cvspass_filename (); +! fp = fopen (passfile, "r"); + if (fp == NULL) + { +--- 327,331 ---- + /* Else get it from the file. */ + passfile = construct_cvspass_filename (); +! fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) + { +diff -r -C 2 -P base/cvs-1.6.5/src/logmsg.c cvs-1.6.5/src/logmsg.c +*** base/cvs-1.6.5/src/logmsg.c Mon Dec 25 06:20:18 1995 +--- cvs-1.6.5/src/logmsg.c Tue Jan 9 05:33:08 1996 +*************** +*** 145,149 **** + (void) tmpnam (fname); + again: +! if ((fp = fopen (fname, "w+")) == NULL) + error (1, 0, "cannot create temporary file %s", fname); + +--- 145,149 ---- + (void) tmpnam (fname); + again: +! if ((fp = CVS_FOPEN (fname, "w+")) == NULL) + error (1, 0, "cannot create temporary file %s", fname); + +*************** +*** 180,184 **** + if (fclose (fp) == EOF) + error (1, errno, "%s", fname); +! if (stat (fname, &pre_stbuf) == -1) + pre_stbuf.st_mtime = 0; + +--- 180,184 ---- + if (fclose (fp) == EOF) + error (1, errno, "%s", fname); +! if (CVS_STAT (fname, &pre_stbuf) == -1) + pre_stbuf.st_mtime = 0; + +*************** +*** 205,209 **** + free (*messagep); + +! if (stat (fname, &post_stbuf) != 0) + error (1, errno, "cannot find size of temp file %s", fname); + +--- 205,209 ---- + free (*messagep); + +! if (CVS_STAT (fname, &post_stbuf) != 0) + error (1, errno, "cannot find size of temp file %s", fname); + +*************** +*** 293,297 **** + last_template = xstrdup (template); + +! if ((tfp = fopen (template, "r")) != NULL) + { + char *line = NULL; +--- 293,297 ---- + last_template = xstrdup (template); + +! if ((tfp = CVS_FOPEN (template, "r")) != NULL) + { + char *line = NULL; +diff -r -C 2 -P base/cvs-1.6.5/src/main.c cvs-1.6.5/src/main.c +*** base/cvs-1.6.5/src/main.c Sat Dec 16 06:20:32 1995 +--- cvs-1.6.5/src/main.c Tue Jan 9 05:33:08 1996 +*************** +*** 37,40 **** +--- 37,44 ---- + #include "patchlevel.h" + ++ #ifdef macintosh ++ #include ++ #endif ++ + #if HAVE_KERBEROS + #include +*************** +*** 269,272 **** +--- 273,285 ---- + don't use it. */ + int option_index = 0; ++ ++ #ifdef macintosh ++ GUSIDefaultSetup(); ++ argc = ccommand(&argv); ++ ++ SIOUXSettings.showstatusline = TRUE; ++ SIOUXSettings.asktosaveonclose = FALSE; ++ ++ #endif + + error_set_cleanup (error_cleanup); +diff -r -C 2 -P base/cvs-1.6.5/src/modules.c cvs-1.6.5/src/modules.c +*** base/cvs-1.6.5/src/modules.c Thu Jan 4 06:20:30 1996 +--- cvs-1.6.5/src/modules.c Tue Jan 9 05:33:08 1996 +*************** +*** 338,342 **** + instead of just at the bottom */ + make_directories (dir); +! if (chdir (dir) < 0) + { + error (0, errno, "cannot chdir to %s", dir); +--- 338,342 ---- + instead of just at the bottom */ + make_directories (dir); +! if (CVS_CHDIR (dir) < 0) + { + error (0, errno, "cannot chdir to %s", dir); +*************** +*** 643,647 **** + static int s_count = 0; /* Number of elements used */ + +! static int Status; /* Nonzero if the user is + interested in status + information as well as +--- 643,647 ---- + static int s_count = 0; /* Number of elements used */ + +! static int capsstatus; /* Nonzero if the user is + interested in status + information as well as +*************** +*** 663,667 **** + const struct sortrec *right = (const struct sortrec *) r; + +! if (Status) + { + /* If Sort by status field, compare them. */ +--- 663,667 ---- + const struct sortrec *right = (const struct sortrec *) r; + +! if (capsstatus) + { + /* If Sort by status field, compare them. */ +*************** +*** 682,686 **** + struct sortrec *s_rec; + +! if (Status && *d == '-' && *(d + 1) == 'a') + return; /* We want "cvs co -s" and it is an alias! */ + +--- 682,686 ---- + struct sortrec *s_rec; + +! if (capsstatus && *d == '-' && *(d + 1) == 'a') + return; /* We want "cvs co -s" and it is an alias! */ + +*************** +*** 716,720 **** + + /* Look for the "-s statusvalue" text */ +! if (Status) + { + s_rec->status = def_status; +--- 716,720 ---- + + /* Look for the "-s statusvalue" text */ +! if (capsstatus) + { + s_rec->status = def_status; +*************** +*** 779,788 **** + struct winsize ws; + +! (void) ioctl (0, TIOCGWINSZ, &ws); + cols = ws.ws_col; + #endif + #endif + +! Status = status; + + /* Read the whole modules file into allocated records */ +--- 779,792 ---- + struct winsize ws; + +! #ifdef __MWERKS__ +! (void) ioctl (0, TIOCGWINSZ, (long *) &ws); +! #else +! (void) ioctl (0, TIOCGWINSZ, &ws); +! #endif + cols = ws.ws_col; + #endif + #endif + +! capsstatus = status; + + /* Read the whole modules file into allocated records */ +diff -r -C 2 -P base/cvs-1.6.5/src/myndbm.c cvs-1.6.5/src/myndbm.c +*** base/cvs-1.6.5/src/myndbm.c Wed Jan 3 06:20:24 1996 +--- cvs-1.6.5/src/myndbm.c Tue Jan 9 05:33:08 1996 +*************** +*** 37,41 **** + DBM *db; + +! fp = fopen (file, "r"); + if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT))) + return ((DBM *) 0); +--- 37,41 ---- + DBM *db; + +! fp = CVS_FOPEN (file, "r"); + if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT))) + return ((DBM *) 0); +*************** +*** 77,81 **** + { + FILE *fp; +! fp = fopen (db->name, "w"); + if (fp == NULL) + error (1, errno, "cannot write %s", db->name); +--- 77,81 ---- + { + FILE *fp; +! fp = CVS_FOPEN (db->name, "w"); + if (fp == NULL) + error (1, errno, "cannot write %s", db->name); +diff -r -C 2 -P base/cvs-1.6.5/src/no_diff.c cvs-1.6.5/src/no_diff.c +*** base/cvs-1.6.5/src/no_diff.c Fri Sep 8 07:20:28 1995 +--- cvs-1.6.5/src/no_diff.c Tue Jan 9 05:33:08 1996 +*************** +*** 98,102 **** + * has been set to 1. */ + if (trace) +! (void) fprintf (stderr, "%c-> unlink (%s)\n", + #ifdef SERVER_SUPPORT + (server_active) ? 'S' : ' ', +--- 98,102 ---- + * has been set to 1. */ + if (trace) +! (void) fprintf (stderr, "%c-> CVS_UNLINK (%s)\n", + #ifdef SERVER_SUPPORT + (server_active) ? 'S' : ' ', +*************** +*** 105,109 **** + #endif + tocvsPath); +! if (unlink (tocvsPath) < 0) + error (0, errno, "could not remove %s", tocvsPath); + } +--- 105,109 ---- + #endif + tocvsPath); +! if (CVS_UNLINK (tocvsPath) < 0) + error (0, errno, "could not remove %s", tocvsPath); + } +*************** +*** 127,133 **** + (server_active) ? 'S' : ' ', tmp); + #else +! (void) fprintf (stderr, "-> unlink (%s)\n", tmp); + #endif +! if (unlink (tmp) < 0) + error (0, errno, "could not remove %s", tmp); + free (options); +--- 127,133 ---- + (server_active) ? 'S' : ' ', tmp); + #else +! (void) fprintf (stderr, "-> CVS_UNLINK (%s)\n", tmp); + #endif +! if (CVS_UNLINK (tmp) < 0) + error (0, errno, "could not remove %s", tmp); + free (options); +diff -r -C 2 -P base/cvs-1.6.5/src/parseinfo.c cvs-1.6.5/src/parseinfo.c +*** base/cvs-1.6.5/src/parseinfo.c Tue Oct 17 07:20:14 1995 +--- cvs-1.6.5/src/parseinfo.c Tue Jan 9 05:33:08 1996 +*************** +*** 48,52 **** + (void) sprintf (infopath, "%s/%s/%s", CVSroot, + CVSROOTADM, infofile); +! if ((fp_info = fopen (infopath, "r")) == NULL) + return (0); /* no file -> nothing special done */ + +--- 48,52 ---- + (void) sprintf (infopath, "%s/%s/%s", CVSroot, + CVSROOTADM, infofile); +! if ((fp_info = CVS_FOPEN (infopath, "r")) == NULL) + return (0); /* no file -> nothing special done */ + +diff -r -C 2 -P base/cvs-1.6.5/src/patch.c cvs-1.6.5/src/patch.c +*** base/cvs-1.6.5/src/patch.c Thu Jan 4 06:20:30 1996 +--- cvs-1.6.5/src/patch.c Tue Jan 9 05:33:08 1996 +*************** +*** 302,306 **** + + /* cd to the starting repository */ +! if (chdir (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); +--- 302,306 ---- + + /* cd to the starting repository */ +! if (CVS_CHDIR (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); +*************** +*** 428,436 **** + return (0); + } +! if ((fp1 = fopen (tmpnam (tmpfile1), "w+")) != NULL) + (void) fclose (fp1); +! if ((fp2 = fopen (tmpnam (tmpfile2), "w+")) != NULL) + (void) fclose (fp2); +! if ((fp3 = fopen (tmpnam (tmpfile3), "w+")) != NULL) + (void) fclose (fp3); + if (fp1 == NULL || fp2 == NULL || fp3 == NULL) +--- 428,436 ---- + return (0); + } +! if ((fp1 = CVS_FOPEN (tmpnam (tmpfile1), "w+")) != NULL) + (void) fclose (fp1); +! if ((fp2 = CVS_FOPEN (tmpnam (tmpfile2), "w+")) != NULL) + (void) fclose (fp2); +! if ((fp3 = CVS_FOPEN (tmpnam (tmpfile3), "w+")) != NULL) + (void) fclose (fp3); + if (fp1 == NULL || fp2 == NULL || fp3 == NULL) +diff -r -C 2 -P base/cvs-1.6.5/src/rcs.c cvs-1.6.5/src/rcs.c +*** base/cvs-1.6.5/src/rcs.c Mon Dec 4 06:20:22 1995 +--- cvs-1.6.5/src/rcs.c Tue Jan 9 05:33:08 1996 +*************** +*** 144,148 **** + + (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT); +! if ((fp = fopen (rcsfile, "r")) != NULL) + { + rcs = RCS_parsercsfile_i(fp, rcsfile); +--- 144,148 ---- + + (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT); +! if ((fp = CVS_FOPEN (rcsfile, "r")) != NULL) + { + rcs = RCS_parsercsfile_i(fp, rcsfile); +*************** +*** 166,170 **** + + (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT); +! if ((fp = fopen (rcsfile, "r")) != NULL) + { + rcs = RCS_parsercsfile_i(fp, rcsfile); +--- 166,170 ---- + + (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT); +! if ((fp = CVS_FOPEN (rcsfile, "r")) != NULL) + { + rcs = RCS_parsercsfile_i(fp, rcsfile); +*************** +*** 204,208 **** + + /* open the rcsfile */ +! if ((fp = fopen (rcsfile, "r")) == NULL) + { + error (0, errno, "Couldn't open rcs file `%s'", rcsfile); +--- 204,208 ---- + + /* open the rcsfile */ +! if ((fp = CVS_FOPEN (rcsfile, "r")) == NULL) + { + error (0, errno, "Couldn't open rcs file `%s'", rcsfile); +*************** +*** 308,312 **** + #endif + +! fp = fopen(rcsfile, "r"); + if (fp == NULL) + error (1, 0, "unable to reopen `%s'", rcsfile); +--- 308,312 ---- + #endif + +! fp = CVS_FOPEN (rcsfile, "r"); + if (fp == NULL) + error (1, 0, "unable to reopen `%s'", rcsfile); +diff -r -C 2 -P base/cvs-1.6.5/src/recurse.c cvs-1.6.5/src/recurse.c +*** base/cvs-1.6.5/src/recurse.c Sat Dec 16 06:20:33 1995 +--- cvs-1.6.5/src/recurse.c Tue Jan 9 05:33:08 1996 +*************** +*** 519,523 **** + + /* cd to the sub-directory */ +! if (chdir (dir) < 0) + error (1, errno, "could not chdir to %s", dir); + +--- 519,523 ---- + + /* cd to the sub-directory */ +! if (CVS_CHDIR (dir) < 0) + error (1, errno, "could not chdir to %s", dir); + +*************** +*** 631,635 **** + if (save_cwd (&cwd)) + exit (1); +! if (chdir (p->key) < 0) + error (1, errno, "could not chdir to %s", p->key); + +--- 631,635 ---- + if (save_cwd (&cwd)) + exit (1); +! if (CVS_CHDIR (p->key) < 0) + error (1, errno, "could not chdir to %s", p->key); + +diff -r -C 2 -P base/cvs-1.6.5/src/release.c cvs-1.6.5/src/release.c +*** base/cvs-1.6.5/src/release.c Tue Jan 9 06:20:21 1996 +--- cvs-1.6.5/src/release.c Tue Jan 9 05:33:08 1996 +*************** +*** 143,147 **** + if (isdir (thisarg)) + { +! if (chdir (thisarg) < 0) + { + if (!really_quiet) +--- 143,147 ---- + if (isdir (thisarg)) + { +! if (CVS_CHDIR (thisarg) < 0) + { + if (!really_quiet) +*************** +*** 273,280 **** + ino_t ino; + +! (void) stat (".", &st); + ino = st.st_ino; +! (void) chdir (".."); +! (void) stat (dir, &st); + if (ino != st.st_ino) + { +--- 273,280 ---- + ino_t ino; + +! (void) CVS_STAT (".", &st); + ino = st.st_ino; +! (void) CVS_CHDIR (".."); +! (void) CVS_STAT (dir, &st); + if (ino != st.st_ino) + { +diff -r -C 2 -P base/cvs-1.6.5/src/remove.c cvs-1.6.5/src/remove.c +*** base/cvs-1.6.5/src/remove.c Thu Jan 4 06:20:31 1996 +--- cvs-1.6.5/src/remove.c Tue Jan 9 05:33:08 1996 +*************** +*** 128,132 **** + if (!noexec) + { +! if (unlink (file) < 0 && ! existence_error (errno)) + { + if (update_dir[0] == '\0') +--- 128,132 ---- + if (!noexec) + { +! if (CVS_UNLINK (file) < 0 && ! existence_error (errno)) + { + if (update_dir[0] == '\0') +diff -r -C 2 -P base/cvs-1.6.5/src/root.c cvs-1.6.5/src/root.c +*** base/cvs-1.6.5/src/root.c Tue Dec 12 06:20:28 1995 +--- cvs-1.6.5/src/root.c Tue Jan 9 05:33:08 1996 +*************** +*** 136,142 **** + int ret; + +! if (stat (dir1, &sb1) < 0) + return (0); +! if (stat (dir2, &sb2) < 0) + return (0); + +--- 136,142 ---- + int ret; + +! if (CVS_STAT (dir1, &sb1) < 0) + return (0); +! if (CVS_STAT (dir2, &sb2) < 0) + return (0); + +diff -r -C 2 -P base/cvs-1.6.5/src/rtag.c cvs-1.6.5/src/rtag.c +*** base/cvs-1.6.5/src/rtag.c Thu Jan 4 06:20:31 1996 +--- cvs-1.6.5/src/rtag.c Tue Jan 9 05:33:08 1996 +*************** +*** 279,283 **** + + /* chdir to the starting directory */ +! if (chdir (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); +--- 279,283 ---- + + /* chdir to the starting directory */ +! if (CVS_CHDIR (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); +diff -r -C 2 -P base/cvs-1.6.5/src/run.c cvs-1.6.5/src/run.c +*** base/cvs-1.6.5/src/run.c Fri Dec 15 06:20:21 1995 +--- cvs-1.6.5/src/run.c Tue Jan 9 05:33:08 1996 +*************** +*** 216,220 **** + mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); + +! if (stin && (shin = open (stin, O_RDONLY)) == -1) + { + rerrno = errno; +--- 216,220 ---- + mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); + +! if (stin && (shin = CVS_OPEN (stin, O_RDONLY)) == -1) + { + rerrno = errno; +*************** +*** 223,227 **** + goto out0; + } +! if (stout && (shout = open (stout, mode_out, 0666)) == -1) + { + rerrno = errno; +--- 223,227 ---- + goto out0; + } +! if (stout && (shout = CVS_OPEN (stout, mode_out, 0666)) == -1) + { + rerrno = errno; +*************** +*** 232,236 **** + if (sterr && (flags & RUN_COMBINED) == 0) + { +! if ((sherr = open (sterr, mode_err, 0666)) == -1) + { + rerrno = errno; +--- 232,236 ---- + if (sterr && (flags & RUN_COMBINED) == 0) + { +! if ((sherr = CVS_OPEN (sterr, mode_err, 0666)) == -1) + { + rerrno = errno; +diff -r -C 2 -P base/cvs-1.6.5/src/server.c cvs-1.6.5/src/server.c +*** base/cvs-1.6.5/src/server.c Thu Jan 4 06:20:33 1996 +--- cvs-1.6.5/src/server.c Tue Jan 9 05:33:08 1996 +*************** +*** 392,396 **** + return; + } +! if (chdir (dirname) < 0) + { + pending_error = errno; +--- 392,396 ---- + return; + } +! if (CVS_CHDIR (dirname) < 0) + { + pending_error = errno; +*************** +*** 411,415 **** + return; + } +! f = fopen (CVSADM_REP, "w"); + if (f == NULL) + { +--- 411,415 ---- + return; + } +! f = CVS_FOPEN (CVSADM_REP, "w"); + if (f == NULL) + { +*************** +*** 428,432 **** + return; + } +! f = fopen (CVSADM_ENT, "w+"); + if (f == NULL) + { +--- 428,432 ---- + return; + } +! f = CVS_FOPEN (CVSADM_ENT, "w+"); + if (f == NULL) + { +*************** +*** 493,497 **** + { + FILE *f; +! f = fopen (CVSADM_ENTSTAT, "w+"); + if (f == NULL) + { +--- 493,497 ---- + { + FILE *f; +! f = CVS_FOPEN (CVSADM_ENTSTAT, "w+"); + if (f == NULL) + { +*************** +*** 515,519 **** + { + FILE *f; +! f = fopen (CVSADM_TAG, "w+"); + if (f == NULL) + { +--- 515,519 ---- + { + FILE *f; +! f = CVS_FOPEN (CVSADM_TAG, "w+"); + if (f == NULL) + { +*************** +*** 626,630 **** + + /* Write the file. */ +! fd = open (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) + { +--- 626,630 ---- + + /* Write the file. */ +! fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) + { +*************** +*** 798,802 **** + { + struct utimbuf ut; +! int fd = open (arg, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0 || close (fd) < 0) + { +--- 798,802 ---- + { + struct utimbuf ut; +! int fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0 || close (fd) < 0) + { +*************** +*** 914,918 **** + if (!error_pending ()) + { +! f = fopen (CVSADM_ENT, "w"); + if (f == NULL) + { +--- 914,918 ---- + if (!error_pending ()) + { +! f = CVS_FOPEN (CVSADM_ENT, "w"); + if (f == NULL) + { +*************** +*** 1091,1095 **** + while (notify_list != NULL) + { +! if (chdir (notify_list->dir) < 0) + { + error (0, errno, "cannot change to %s", notify_list->dir); +--- 1091,1095 ---- + while (notify_list != NULL) + { +! if (CVS_CHDIR (notify_list->dir) < 0) + { + error (0, errno, "cannot change to %s", notify_list->dir); +*************** +*** 2300,2304 **** + #endif /* SERVER_FLOWCONTROL */ + +! dev_null_fd = open ("/dev/null", O_RDONLY); + if (dev_null_fd < 0) + { +--- 2300,2304 ---- + #endif /* SERVER_FLOWCONTROL */ + +! dev_null_fd = CVS_OPEN ("/dev/null", O_RDONLY); + if (dev_null_fd < 0) + { +*************** +*** 2943,2947 **** + char *mode_string; + +! if (stat (file, &sb) < 0) + { + /* Not clear to me why the file would fail to exist, but it +--- 2943,2947 ---- + char *mode_string; + +! if (CVS_STAT (file, &sb) < 0) + { + /* Not clear to me why the file would fail to exist, but it +*************** +*** 3217,3221 **** + } + +! if (chdir (tempdir) < 0) + { + printf ("E Cannot change to directory %s\n", tempdir); +--- 3217,3221 ---- + } + +! if (CVS_CHDIR (tempdir) < 0) + { + printf ("E Cannot change to directory %s\n", tempdir); +*************** +*** 3283,3287 **** + char size_text[80]; + +! if (stat (file, &sb) < 0) + { + if (existence_error (errno)) +--- 3283,3287 ---- + char size_text[80]; + +! if (CVS_STAT (file, &sb) < 0) + { + if (existence_error (errno)) +*************** +*** 3370,3374 **** + pid_t gzip_pid; + +! fd = open (file, O_RDONLY, 0); + if (fd < 0) + error (1, errno, "reading %s", short_pathname); +--- 3370,3374 ---- + pid_t gzip_pid; + +! fd = CVS_OPEN (file, O_RDONLY, 0); + if (fd < 0) + error (1, errno, "reading %s", short_pathname); +*************** +*** 3396,3400 **** + + size = sb.st_size; +! f = fopen (file, "r"); + if (f == NULL) + error (1, errno, "reading %s", short_pathname); +--- 3396,3400 ---- + + size = sb.st_size; +! f = CVS_FOPEN (file, "r"); + if (f == NULL) + error (1, errno, "reading %s", short_pathname); +*************** +*** 3427,3431 **** + join_file. */ + && !joining ()) +! unlink (file); + } + else if (scratched_file != NULL && entries_line == NULL) +--- 3427,3431 ---- + join_file. */ + && !joining ()) +! CVS_UNLINK (file); + } + else if (scratched_file != NULL && entries_line == NULL) +*************** +*** 3673,3677 **** + { + FILE *f; +! f = fopen (CVSADM_CIPROG, "w+"); + if (f == NULL) + { +--- 3673,3677 ---- + { + FILE *f; +! f = CVS_FOPEN (CVSADM_CIPROG, "w+"); + if (f == NULL) + { +*************** +*** 3702,3706 **** + { + FILE *f; +! f = fopen (CVSADM_UPROG, "w+"); + if (f == NULL) + { +--- 3702,3706 ---- + { + FILE *f; +! f = CVS_FOPEN (CVSADM_UPROG, "w+"); + if (f == NULL) + { +*************** +*** 3919,3923 **** + if (temp_dir == NULL || temp_dir[0] == '\0') + temp_dir = "/tmp"; +! chdir(temp_dir); + + len = strlen (server_temp_dir) + 80; +--- 3919,3923 ---- + if (temp_dir == NULL || temp_dir[0] == '\0') + temp_dir = "/tmp"; +! CVS_CHDIR (temp_dir); + + len = strlen (server_temp_dir) + 80; +*************** +*** 4160,4164 **** + memset (linebuf, 0, linelen); + +! fp = fopen (filename, "r"); + if (fp == NULL) + { +--- 4160,4164 ---- + memset (linebuf, 0, linelen); + +! fp = CVS_FOPEN (filename, "r"); + if (fp == NULL) + { +diff -r -C 2 -P base/cvs-1.6.5/src/tag.c cvs-1.6.5/src/tag.c +*** base/cvs-1.6.5/src/tag.c Thu Jan 4 06:20:33 1996 +--- cvs-1.6.5/src/tag.c Tue Jan 9 05:33:08 1996 +*************** +*** 729,733 **** + if (save_cwd (&cwd)) + exit (1); +! if (chdir (repository) < 0) + error (1, errno, "cannot change to %s directory", repository); + } +--- 729,733 ---- + if (save_cwd (&cwd)) + exit (1); +! if (CVS_CHDIR (repository) < 0) + error (1, errno, "cannot change to %s directory", repository); + } +diff -r -C 2 -P base/cvs-1.6.5/src/update.c cvs-1.6.5/src/update.c +*** base/cvs-1.6.5/src/update.c Thu Jan 4 06:20:34 1996 +--- cvs-1.6.5/src/update.c Tue Jan 9 05:33:09 1996 +*************** +*** 255,259 **** +--- 255,261 ---- + if (rq->status == rq_supported) + { ++ #ifndef macintosh + send_arg("-u"); ++ #endif + } + break; +*************** +*** 275,279 **** + + if (toplevel_wd[0] != '\0' +! && chdir (toplevel_wd) < 0) + { + error (1, errno, "could not chdir to %s", toplevel_wd); +--- 277,281 ---- + + if (toplevel_wd[0] != '\0' +! && CVS_CHDIR (toplevel_wd) < 0) + { + error (1, errno, "could not chdir to %s", toplevel_wd); +*************** +*** 814,818 **** + /* run the update_prog if there is one */ + if (err == 0 && !pipeout && !noexec && +! (fp = fopen (CVSADM_UPROG, "r")) != NULL) + { + char *cp; +--- 816,820 ---- + /* run the update_prog if there is one */ + if (err == 0 && !pipeout && !noexec && +! (fp = CVS_FOPEN (CVSADM_UPROG, "r")) != NULL) + { + char *cp; +*************** +*** 837,841 **** + /* FIXME: chdir ("..") loses with symlinks. */ + /* Prune empty dirs on the way out - if necessary */ +! (void) chdir (".."); + if (update_prune_dirs && isemptydir (dir)) + { +--- 839,843 ---- + /* FIXME: chdir ("..") loses with symlinks. */ + /* Prune empty dirs on the way out - if necessary */ +! (void) CVS_CHDIR (".."); + if (update_prune_dirs && isemptydir (dir)) + { +*************** +*** 859,863 **** + struct dirent *dp; + +! if ((dirp = opendir (dir)) == NULL) + { + error (0, 0, "cannot open directory %s for empty check", dir); +--- 861,865 ---- + struct dirent *dp; + +! if ((dirp = CVS_OPENDIR (dir)) == NULL) + { + error (0, 0, "cannot open directory %s for empty check", dir); +*************** +*** 1207,1211 **** + else + { +! e = fopen (file1, "r"); + if (e == NULL) + fail = 1; +--- 1209,1213 ---- + else + { +! e = CVS_FOPEN (file1, "r"); + if (e == NULL) + fail = 1; +*************** +*** 1244,1248 **** + && !fileattr_get (file, "_watched")) + xchmod (file2, 1); +! e = fopen (file2, "r"); + if (e == NULL) + fail = 1; +--- 1246,1250 ---- + && !fileattr_get (file, "_watched")) + xchmod (file2, 1); +! e = CVS_FOPEN (file2, "r"); + if (e == NULL) + fail = 1; +*************** +*** 1303,1307 **** + + /* Check the diff output to make sure patch will be handle it. */ +! e = fopen (file, "r"); + if (e == NULL) + error (1, errno, "could not open diff output file %s", file); +--- 1305,1309 ---- + + /* Check the diff output to make sure patch will be handle it. */ +! e = CVS_FOPEN (file, "r"); + if (e == NULL) + error (1, errno, "could not open diff output file %s", file); +*************** +*** 1333,1337 **** + xvers_ts->tag, xvers_ts->date, NULL); + +! if (stat (file2, file_info) < 0) + error (1, errno, "could not stat %s", file2); + +--- 1335,1339 ---- + xvers_ts->tag, xvers_ts->date, NULL); + +! if (CVS_STAT (file2, file_info) < 0) + error (1, errno, "could not stat %s", file2); + +diff -r -C 2 -P base/cvs-1.6.5/src/vers_ts.c cvs-1.6.5/src/vers_ts.c +*** base/cvs-1.6.5/src/vers_ts.c Sat Dec 2 06:20:24 1995 +--- cvs-1.6.5/src/vers_ts.c Tue Jan 9 05:33:09 1996 +*************** +*** 220,224 **** + char *cp; + +! if (stat (file, &sb) < 0) + { + if (! existence_error (errno)) +--- 220,224 ---- + char *cp; + +! if (CVS_STAT (file, &sb) < 0) + { + if (! existence_error (errno)) +*************** +*** 280,284 **** + char *ts; + +! if (stat (file, &sb) < 0) + { + ts = NULL; +--- 280,284 ---- + char *ts; + +! if (CVS_STAT (file, &sb) < 0) + { + ts = NULL; +diff -r -C 2 -P base/cvs-1.6.5/src/wrapper.c cvs-1.6.5/src/wrapper.c +*** base/cvs-1.6.5/src/wrapper.c Tue Oct 10 07:20:42 1995 +--- cvs-1.6.5/src/wrapper.c Tue Jan 9 05:33:09 1996 +*************** +*** 97,101 **** + + /* load the file */ +! if (!(fp = fopen (file, "r"))) + return; + while (fgets (line, sizeof (line), fp)) +--- 97,101 ---- + + /* load the file */ +! if (!(fp = CVS_FOPEN (file, "r"))) + return; + while (fgets (line, sizeof (line), fp)) diff --git a/gnu/usr.bin/cvs/macintosh/macos_filesys.c b/gnu/usr.bin/cvs/macintosh/macos_filesys.c new file mode 100644 index 00000000000..26a93847c81 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/macos_filesys.c @@ -0,0 +1,211 @@ +/* + * macos_filesys.c + * Filesystem handling stuff for macos + * + * Some of this stuff is not "regular", but there are a number of weird + * conditions that a plain filepath translation didn't seem to handle. + * For now, this seems to work. + * + * Michael Ladwig --- November 1995 + */ + +#include + +#include +#include +#include + +static char *macos_fixpath (const char *path); +static char scratchPath[1024]; + +int +macos_mkdir( const char *path, int oflag ) +{ + char macPath[1024], *sepCh; + + strcpy( macPath, ":" ); + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + return mkdir(macPath); +} + +int +macos_open( const char *path, int oflag, ... ) +{ + char macPath[1024], *sepCh; + + strcpy( macPath, ":" ); + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + return open(macPath, oflag); +} + +int +macos_chmod( const char *path, mode_t mode ) +{ + char macPath[1024], *sepCh; + + strcpy( macPath, ":" ); + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + return chmod(macPath, mode); +} + +int +macos_creat( const char *path, mode_t mode ) +{ + char macPath[1024], *sepCh; + + strcpy( macPath, ":" ); + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + return creat(macPath); +} + +FILE * +macos_fopen( const char *path, const char *mode ) +{ + FILE *fp; + char macPath[1024], *sepCh; + + strcpy( macPath, ":" ); + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + fp = fopen(macPath, mode); + + /* Don't know why I'm getting ENOTDIR, but it should be ENOENT */ + + if( (fp == NULL) && (errno == ENOTDIR) ) errno = ENOENT; + + return fp; +} + +int +macos_chdir( const char *path ) +{ + char macPath[1024], *sepCh; + int r; + + strcpy( macPath, ":" ); + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + r = chdir(macPath+1); + if( r < 0 ) + return chdir(macPath); + + return r; +} + +int +macos_access(const char *path, int amode) +{ + return access( macos_fixpath(path), amode ); +} + +DIR * +macos_opendir(const char *path) +{ + FILE *fp; + char macPath[1024], *sepCh; + + strcpy( macPath, ":" ); + + if( strcmp(path, ".") != 0 ) + strcat( macPath, path ); + while( (sepCh = strchr(macPath, '/')) != NULL ) + *sepCh = ':'; + + return opendir( macPath ); +} + +int +macos_stat (const char *path, struct stat *ststr) +{ + return stat( macos_fixpath(path), ststr ); +} + +int +macos_rename (const char *path, const char *newpath) +{ + char macPath_from[1024], macPath_to[1024]; + + strcpy( macPath_from, macos_fixpath(path) ); + strcpy( macPath_to, macos_fixpath(newpath) ); + + return rename( macPath_from, macPath_to ); +} + +int +macos_unlink (const char *path) +{ + return unlink( macos_fixpath(path) ); +} + +char * +macos_fixpath (const char *path) +{ + char *sepCh; + + strcpy( scratchPath, ":" ); + + if( (*path == '.') && (*(path+1) == '/') ) + strcat( scratchPath, path+2 ); + else + strcat( scratchPath, path ); + while( (sepCh = strchr(scratchPath, '/')) != NULL ) + *sepCh = ':'; + + return scratchPath; +} + +/* Shamelessly stolen from the OS2 port. Oddly, only the fopen calls + seem to respect the binary-text distinction, so I have rewritten + the code to use fopen, fread, fwrite, and fclose instead of open. */ + +void +convert_file (char *infile, int inflags, + char *outfile, int outflags) +{ + FILE *infd, *outfd; + char buf[8192]; + int len; + char iflags[10], oflags[10]; + + if( inflags & OPEN_BINARY ) + strcpy( iflags, "rb" ); + else + strcpy( iflags, "r" ); + + if( outflags & OPEN_BINARY ) + strcpy( oflags, "wb" ); + else + strcpy( oflags, "w" ); + + if ((infd = CVS_FOPEN (infile, iflags)) == NULL) + error (1, errno, "couldn't read %s", infile); + if ((outfd = CVS_FOPEN (outfile, oflags)) == NULL) + error (1, errno, "couldn't write %s", outfile); + + while ((len = fread (buf, sizeof (char), sizeof (buf), infd)) > 0) + if (fwrite (buf, sizeof (char), len, outfd) < 0) + error (1, errno, "error writing %s", outfile); + if (len < 0) + error (1, errno, "error reading %s", infile); + + if (fclose (outfd) < 0) + error (0, errno, "warning: couldn't close %s", outfile); + if (fclose (infd) < 0) + error (0, errno, "warning: couldn't close %s", infile); +} \ No newline at end of file diff --git a/gnu/usr.bin/cvs/macintosh/options.h b/gnu/usr.bin/cvs/macintosh/options.h new file mode 100644 index 00000000000..fe0820f5f31 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/options.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1992, Brian Berliner and Jeff Polk + * Copyright (c) 1989-1992, Brian Berliner + * + * 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. + * + * This file holds (most of) the configuration tweaks that can be made to + * customize CVS for your site. CVS comes configured for a typical SunOS 4.x + * environment. The comments for each configurable item are intended to be + * self-explanatory. All #defines are tested first to see if an over-riding + * option was specified on the "make" command line. + * + * If special libraries are needed, you will have to edit the Makefile.in file + * or the configure script directly. Sorry. + */ + +/* + * CVS provides the most features when used in conjunction with the Version-5 + * release of RCS. Thus, it is the default. This also assumes that GNU diff + * Version-1.15 is being used as well -- you will have to configure your RCS + * V5 release separately to make this the case. If you do not have RCS V5 and + * GNU diff V1.15, comment out this define. You should not try mixing and + * matching other combinations of these tools. + */ +#ifndef HAVE_RCS5 +#define HAVE_RCS5 +#endif + +/* + * If, before installing this version of CVS, you were running RCS V4 AND you + * are installing this CVS and RCS V5 and GNU diff 1.15 all at the same time, + * you should turn on the following define. It only exists to try to do + * reasonable things with your existing checked out files when you upgrade to + * RCS V5, since the keyword expansion formats have changed with RCS V5. + * + * If you already have been running with RCS5, or haven't been running with CVS + * yet at all, or are sticking with RCS V4 for now, leave the commented out. + */ +#ifndef HAD_RCS4 +/* #define HAD_RCS4 */ +#endif + +/* + * For portability and heterogeneity reasons, CVS is shipped by default using + * my own text-file version of the ndbm database library in the src/myndbm.c + * file. If you want better performance and are not concerned about + * heterogeneous hosts accessing your modules file, turn this option off. + */ +#ifndef MY_NDBM +#define MY_NDBM +#endif + +/* + * The "diff" program to execute when creating patch output. This "diff" + * must support the "-c" option for context diffing. Specify a full + * pathname if your site wants to use a particular diff. If you are + * using the GNU version of diff (version 1.15 or later), this should + * be "diff -a". + * + * NOTE: this program is only used for the ``patch'' sub-command (and + * for ``update'' if you are using the server). The other commands + * use rcsdiff which will use whatever version of diff was specified + * when rcsdiff was built on your system. + */ + +#ifndef DIFF +#define DIFF "@gdiff_path@" +#endif + +/* + * The "grep" program to execute when checking to see if a merged file had + * any conflicts. This "grep" must support the "-s" option and a standard + * regular expression as an argument. Specify a full pathname if your site + * wants to use a particular grep. + */ + +#ifndef GREP +#define GREP "@ggrep_path@" +#endif + +/* + * The "rm" program to execute when pruning directories that are not part of + * a release. This "rm" must support the "-fr" options. Specify a full + * pathname if your site wants to use a particular rm. + */ +#ifndef RM +#define RM "rm" +#endif + +/* + * The "sort" program to execute when displaying the module database. Specify + * a full pathname if your site wants to use a particular sort. + */ +#ifndef SORT +#define SORT "sort" +#endif + +/* + * The "patch" program to run when using the CVS server and accepting + * patches across the network. Specify a full pathname if your site + * wants to use a particular patch. + */ +#ifndef PATCH_PROGRAM +#define PATCH_PROGRAM "patch" +#endif + +/* + * By default, RCS programs are executed with the shell or through execlp(), + * so the user's PATH environment variable is searched. If you'd like to + * bind all RCS programs to a certain directory (perhaps one not in most + * people's PATH) then set the default in RCSBIN_DFLT. Note that setting + * this here will cause all RCS programs to be executed from this directory, + * unless the user overrides the default with the RCSBIN environment variable + * or the "-b" option to CVS. + * + * This define should be either the empty string ("") or a full pathname to the + * directory containing all the installed programs from the RCS distribution. + */ +#ifndef RCSBIN_DFLT +#define RCSBIN_DFLT "" +#endif + +/* + * The default editor to use, if one does not specify the "-e" option to cvs, + * or does not have an EDITOR environment variable. I set this to just "vi", + * and use the shell to find where "vi" actually is. This allows sites with + * /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH + * is reasonable). + * + * The notepad program seems to be Windows NT's bare-bones text editor. + */ +#ifndef EDITOR_DFLT +#define EDITOR_DFLT "notepad" +#endif + +/* + * The default umask to use when creating or otherwise setting file or + * directory permissions in the repository. Must be a value in the + * range of 0 through 0777. For example, a value of 002 allows group + * rwx access and world rx access; a value of 007 allows group rwx + * access but no world access. This value is overridden by the value + * of the CVSUMASK environment variable, which is interpreted as an + * octal number. + */ +#ifndef UMASK_DFLT +#define UMASK_DFLT 002 +#endif + +/* + * The cvs admin command is restricted to the members of the group + * CVS_ADMIN_GROUP. If this group does not exist, all users are + * allowed to run cvs admin. To disable the cvs admin for all users, + * create an empty group CVS_ADMIN_GROUP. To disable access control for + * cvs admin, comment out the define below. + * + * Under Windows NT and OS/2, this must not be used because it tries + * to include . + */ +#ifdef CVS_ADMIN_GROUP +/* #define CVS_ADMIN_GROUP "cvsadmin" */ +#endif + +/* + * The Repository file holds the path to the directory within the source + * repository that contains the RCS ,v files for each CVS working directory. + * This path is either a full-path or a path relative to CVSROOT. + * + * The only advantage that I can see to having a relative path is that One can + * change the physical location of the master source repository, change one's + * CVSROOT environment variable, and CVS will work without problems. I + * recommend using full-paths. + */ +#ifndef RELATIVE_REPOS +/* #define RELATIVE_REPOS */ +#endif + +/* + * When committing or importing files, you must enter a log message. + * Normally, you can do this either via the -m flag on the command line or an + * editor will be started for you. If you like to use logging templates (the + * rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to + * force people to use the editor even if they specify a message with -m. + * Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the + * temp file when the editor is started. + */ +#ifndef FORCE_USE_EDITOR +/* #define FORCE_USE_EDITOR */ +#endif + +/* + * When locking the repository, some sites like to remove locks and assume + * the program that created them went away if the lock has existed for a long + * time. This used to be the default for previous versions of CVS. CVS now + * attempts to be much more robust, so lock files should not be left around + * by mistake. The new behaviour will never remove old locks (they must now + * be removed by hand). Enabling CVS_FUDGELOCKS will cause CVS to remove + * locks that are older than CVSLCKAGE seconds. + * Use of this option is NOT recommended. + */ +#ifndef CVS_FUDGELOCKS +/* #define CVS_FUDGELOCKS */ +#endif + +/* + * When committing a permanent change, CVS and RCS make a log entry of + * who committed the change. If you are committing the change logged in + * as "root" (not under "su" or other root-priv giving program), CVS/RCS + * cannot determine who is actually making the change. + * + * As such, by default, CVS disallows changes to be committed by users + * logged in as "root". You can disable this option by commenting + * out the lines below. + * + * Under Windows NT, privileges are associated with groups, not users, + * so the case in which someone has logged in as root does not occur. + * Thus, there is no need for this hack. + * + * todo: I don't know about OS/2 yet. -kff + */ +#undef CVS_BADROOT + +/* + * The "cvs admin" command allows people to get around most of the logging + * and info procedures within CVS. For exmaple, "cvs tag tagname filename" + * will perform some validity checks on the tag, while "cvs admin -Ntagname" + * will not perform those checks. For this reason, some sites may wish to + * disable the admin function completely. + * + * To disable the admin function, uncomment the lines below. + */ +#ifndef CVS_NOADMIN +/* #define CVS_NOADMIN */ +#endif + +/* + * The "cvs diff" command accepts all the single-character options that GNU + * diff (1.15) accepts. Except -D. GNU diff uses -D as a way to put + * cpp-style #define's around the output differences. CVS, by default, uses + * -D to specify a free-form date (like "cvs diff -D '1 week ago'"). If + * you would prefer that the -D option of "cvs diff" work like the GNU diff + * option, then comment out this define. + */ +#ifndef CVS_DIFFDATE +#define CVS_DIFFDATE +#endif + +/* + * define this to enable the SETXID support (see FAQ 4D.13) + * [ We have no such thing under OS/2, so far as I know. ] + */ +#undef SETXID_SUPPORT + +/* + * "cvs login" is under construction. Don't define this unless you're + * testing it, in which case you're me and you already know that. + */ +/* #define CVS_LOGIN */ + +/* End of CVS configuration section */ + +/* + * Externs that are included in libc, but are used frequently enough to + * warrant defining here. + */ +#ifndef STDC_HEADERS +extern void exit (); +#endif + +#ifndef getwd +extern char *getwd (); +#endif + diff --git a/gnu/usr.bin/cvs/macintosh/pwd.c b/gnu/usr.bin/cvs/macintosh/pwd.c new file mode 100644 index 00000000000..5d2ba9713ca --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/pwd.c @@ -0,0 +1,65 @@ +/* pwd.c - Try to approximate UN*X's getuser...() functions under MS-DOS. + Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Header: /home/cvs/src/gnu/usr.bin/cvs/macintosh/Attic/pwd.c,v 1.1.1.1 1996/01/30 00:19:39 tholo Exp $ +*/ + +/* This 'implementation' is conjectured from the use of this functions in + the RCS and BASH distributions. Of course these functions don't do too + much useful things under MS-DOS, but using them avoids many "#ifdef + MSDOS" in ported UN*X code ... */ + +/* Stripped out stuff - MDLadwig --- Nov 1995 */ + +#include + +#include +#include +#include + +static char *home_dir = "."; /* we feel (no|every)where at home */ +static struct passwd pw; /* should we return a malloc()'d structure */ +static struct group gr; /* instead of pointers to static structures? */ + +#if !__POWERPC__ +pid_t getpid( void ) { return 0; } /* getpid */ +#endif + +pid_t waitpid(pid_t, int *, int) { return 0; } /* waitpid */ + +mode_t umask(mode_t) { return 0; } /* Umask */ + +/* return something like a username in a (butchered!) passwd structure. */ + +struct passwd * +getpwuid (int uid) +{ + pw.pw_name = NULL; /* getlogin (); */ + pw.pw_dir = home_dir; + pw.pw_shell = NULL; + pw.pw_uid = 0; + + return &pw; +} + +/* Misc uid stuff */ + +struct passwd * getpwnam (char *name) { return (struct passwd *) 0; } +int getuid () { return 0; } +int geteuid () { return 0; } +int getegid () { return 0; } + diff --git a/gnu/usr.bin/cvs/macintosh/rcmd.c b/gnu/usr.bin/cvs/macintosh/rcmd.c new file mode 100644 index 00000000000..877be42a2bc --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/rcmd.c @@ -0,0 +1,247 @@ +/* $NetBSD: rcmd.c,v 1.12 1995/06/03 22:33:34 mycroft Exp $ */ + +/* + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; +#else +static char *rcsid = "$NetBSD: rcmd.c,v 1.12 1995/06/03 22:33:34 mycroft Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#define MAXPATHLEN 1024 +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +rcmd(ahost, rport, locuser, remuser, cmd, fd2p) + char **ahost; + u_short rport; + const char *locuser, *remuser, *cmd; + int *fd2p; +{ + struct hostent *hp; + struct sockaddr_in sin, from; + fd_set reads; + long oldmask; + pid_t pid; + int s, lport, timo; + char c; + + pid = getpid(); + hp = gethostbyname(*ahost); + if (hp == NULL) { + /*herror(*ahost);*/ + (void)fprintf(stderr, + "rcmd: socket: gethostbyname failed for %s\n", *ahost); + return (-1); + } + *ahost = hp->h_name; + /* oldmask = sigblock(sigmask(SIGURG)); */ + for (timo = 1, lport = IPPORT_RESERVED - 1;;) { + s = rresvport(&lport); + if (s < 0) { + if (errno == EDEADLK) /* EDEADLK */ + (void)fprintf(stderr, + "rcmd: socket: All ports in use\n"); + else + (void)fprintf(stderr, "rcmd: socket: %s\n", + strerror(errno)); + /* sigsetmask(oldmask); */ + return (-1); + } + fcntl(s, F_SETOWN, pid); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = hp->h_addrtype; + sin.sin_port = rport; + bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + break; + (void)close(s); + if (errno == EADDRINUSE) { + lport--; + continue; + } + if (errno == ECONNREFUSED && timo <= 16) { + (void)sleep(timo); + timo *= 2; + continue; + } + if (hp->h_addr_list[1] != NULL) { + int oerrno = errno; + + (void)fprintf(stderr, "connect to address %s: ", + inet_ntoa(sin.sin_addr)); + errno = oerrno; + perror(0); + hp->h_addr_list++; + bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); + (void)fprintf(stderr, "Trying %s...\n", + inet_ntoa(sin.sin_addr)); + continue; + } + (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); + /* sigsetmask(oldmask); */ + return (-1); + } + lport--; + if (fd2p == 0) { + write(s, "", 1); + lport = 0; + } else { + char num[8]; + int s2 = rresvport(&lport), s3; + int len = sizeof(from); + if (s2 < 0) + goto bad; + listen(s2, 1); + /*(void)snprintf(num, sizeof(num), "%d", lport);*/ + sprintf(num,"%d", lport); + if (write(s, num, strlen(num)+1) != strlen(num)+1) { + (void)fprintf(stderr, + "rcmd: write (setting up stderr): %s\n", + strerror(errno)); + (void)close(s2); + goto bad; + } + FD_ZERO(&reads); + FD_SET(s, &reads); + FD_SET(s2, &reads); + errno = 0; + if (select(MAX(s, s2) + 1, &reads, 0, 0, 0) < 1 || + !FD_ISSET(s2, &reads)) { + if (errno != 0) + (void)fprintf(stderr, + "rcmd: select (setting up stderr): %s\n", + strerror(errno)); + else + (void)fprintf(stderr, + "select: protocol failure in circuit setup\n"); + (void)close(s2); + goto bad; + } + s3 = accept(s2, (struct sockaddr *)&from, &len); + (void)close(s2); + if (s3 < 0) { + (void)fprintf(stderr, + "rcmd: accept: %s\n", strerror(errno)); + lport = 0; + goto bad; + } + *fd2p = s3; + from.sin_port = ntohs(from.sin_port); + if (from.sin_family != AF_INET || + from.sin_port >= IPPORT_RESERVED || + from.sin_port < IPPORT_RESERVED / 2) { + (void)fprintf(stderr, + "socket: protocol failure in circuit setup.\n"); + goto bad2; + } + } + (void)write(s, locuser, strlen(locuser)+1); + (void)write(s, remuser, strlen(remuser)+1); + (void)write(s, cmd, strlen(cmd)+1); + if (read(s, &c, 1) != 1) { + (void)fprintf(stderr, + "rcmd: %s: %s\n", *ahost, strerror(errno)); + goto bad2; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void)write(STDERR_FILENO, &c, 1); + if (c == '\n') + break; + } + goto bad2; + } + /* sigsetmask(oldmask); */ + return (s); +bad2: + if (lport) + (void)close(*fd2p); +bad: + (void)close(s); + /* sigsetmask(oldmask); */ + return (-1); +} + +int +rresvport(alport) + int *alport; +{ + struct sockaddr_in sin; + int s; + + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return (-1); + for (;;) { + sin.sin_port = htons((u_short)*alport); + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void)close(s); + return (-1); + } + (*alport)--; + if (*alport == IPPORT_RESERVED/2) { + (void)close(s); + errno = EDEADLK; /* close */ + return (-1); + } + } +} + diff --git a/gnu/usr.bin/cvs/macintosh/run.c b/gnu/usr.bin/cvs/macintosh/run.c new file mode 100644 index 00000000000..bdc59160398 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/run.c @@ -0,0 +1,19 @@ +/* + * run.c --- stubs for unused cvs functions in 'src/run.c' + * + * MDLadwig --- Nov 1995 + */ + +#include +#include + +void run_arg (const char *s) { } +void run_print (FILE * fp) { } +void run_setup (const char *fmt,...) { } +void run_args (const char *fmt,...) { } +int run_exec (char *stin, char *stout, char *sterr, int flags) { return 0; } +FILE * Popen (const char *, const char *) { return NULL; } +int pclose(FILE *fp) { return 0; } +int piped_child (char **, int *, int *) { return 0; } +void close_on_exec (int) { } +int filter_stream_through_program (int, int, char **, pid_t *) { return 0; } diff --git a/gnu/usr.bin/cvs/macintosh/server_if.c b/gnu/usr.bin/cvs/macintosh/server_if.c new file mode 100644 index 00000000000..8b676d57e9b --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/server_if.c @@ -0,0 +1,63 @@ +/* + * server_if.c + * Open connection to the CVS server under MacOS + * + * Michael Ladwig --- November 1995 + */ + +#include "cvs.h" + +#include +#include + +static int read_fd, write_fd; + +void +macos_start_server (int *tofd, int *fromfd, + char *client_user, + char *server_user, + char *server_host, + char *server_cvsroot) +{ + char *cvs_server; + char *command; + struct servent *s; + unsigned short port; + + if (! (cvs_server = getenv ("CVS_SERVER"))) + cvs_server = "cvs"; + command = alloca (strlen (cvs_server) + + strlen (server_cvsroot) + + 50); + sprintf (command, "%s -d %s server", cvs_server, server_cvsroot); + + if ((s = getservbyname("shell", "tcp")) == NULL) + error (1, errno, "cannot getservbyname for shell, tcp"); + + else + port = s->s_port; + + read_fd = rcmd (&server_host, + port, + client_user, + (server_user ? server_user : client_user), + command, + 0); + if (read_fd < 0) + error (1, errno, "cannot start server via rcmd"); + + /* Split the socket into a reading and a writing half. */ + if ((write_fd = dup (read_fd)) < 0) + error (1, errno, "duplicating server connection"); + + *tofd = write_fd; + *fromfd = read_fd; +} + + +void +macos_shutdown_server (int to_server) +{ + if( close (read_fd) != 0 ) perror( "close on read_fd"); + if( close (write_fd) != 0 ) perror( "close on write_fd"); +} diff --git a/gnu/usr.bin/cvs/macintosh/services b/gnu/usr.bin/cvs/macintosh/services new file mode 100644 index 00000000000..60013751f99 --- /dev/null +++ b/gnu/usr.bin/cvs/macintosh/services @@ -0,0 +1,91 @@ +# +# Network services, Internet style +# +# @(#)services 8.1 (Berkeley) 6/9/93 +# +tcpmux 1/tcp # TCP port multiplexer (RFC1078) +echo 7/tcp +echo 7/udp +discard 9/tcp sink null +discard 9/udp sink null +systat 11/tcp users +daytime 13/tcp +daytime 13/udp +netstat 15/tcp +qotd 17/tcp quote +chargen 19/tcp ttytst source +chargen 19/udp ttytst source +ftp 21/tcp +telnet 23/tcp +smtp 25/tcp mail +time 37/tcp timserver +time 37/udp timserver +rlp 39/udp resource # resource location +nameserver 42/tcp name # IEN 116 +whois 43/tcp nicname +domain 53/tcp nameserver # name-domain server +domain 53/udp nameserver +mtp 57/tcp # deprecated +# Bootp experimental (sellgren@vangogh) +bootp 67/udp # bootp server +#bootpc 68/udp # bootp client +# +tftp 69/udp +rje 77/tcp netrjs +finger 79/tcp +link 87/tcp ttylink +supdup 95/tcp +hostnames 101/tcp hostname # usually from sri-nic +tsap 102/tcp # part of ISODE. +#csnet-cs 105/? +pop 110/tcp postoffice # POP3 +sunrpc 111/tcp +sunrpc 111/udp +auth 113/tcp authentication +sftp 115/tcp +uucp-path 117/tcp +nntp 119/tcp readnews untp # USENET News Transfer Protocol +ntp 123/udp +snmp 161/udp +snmp-trap 162/udp +portmap 211/tcp # port mapper +portmap 211/udp # port mapper +# +# UNIX specific services +# +exec 512/tcp +biff 512/udp comsat +login 513/tcp +who 513/udp whod +shell 514/tcp cmd # no passwords used +syslog 514/udp +printer 515/tcp spooler # line printer spooler +talk 517/udp +ntalk 518/udp +route 520/udp router routed +timed 525/udp timeserver +tempo 526/tcp newdate +courier 530/tcp rpc +conference 531/tcp chat +netnews 532/tcp readnews +netwall 533/udp # -for emergency broadcasts +uucp 540/tcp uucpd # uucp daemon +rdist 541/tcp rdistd # rdist daemon +remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem +supfilesrv 871/tcp supserver # Software upgrade protocol + +ingreslock 1524/tcp +# +# Kerberos (Project Athena/MIT) services +# +kerberos 750/udp kdc # Kerberos (server) udp +kerberos 750/tcp kdc # Kerberos (server) tcp +krbupdate 760/tcp kreg # Kerberos registration +kpasswd 761/tcp kpwd # Kerberos "passwd" +klogin 543/tcp # Kerberos rlogin +eklogin 2105/tcp # Kerberos encrypted rlogin +kshell 544/tcp krcmd # Kerberos remote shell +* +* MachTen tcptraffic socket +* +tcptraffic 4002/tcp diff --git a/gnu/usr.bin/cvs/man/.cvsignore b/gnu/usr.bin/cvs/man/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/gnu/usr.bin/cvs/man/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/gnu/usr.bin/cvs/man/ChangeLog b/gnu/usr.bin/cvs/man/ChangeLog index d9907faa4f1..6184ce87e76 100644 --- a/gnu/usr.bin/cvs/man/ChangeLog +++ b/gnu/usr.bin/cvs/man/ChangeLog @@ -1,3 +1,25 @@ +Tue Nov 14 15:47:44 1995 Greg A. Woods + + * cvs.5: + - list filenames in alpha sort order + - describe the cvswrappers file + - describe the taginfo file + - fix cvsinit chapter number + (This is by no means complete -- it's just stuff I noticed.) + + * cvs.1: put the filenames in alpha sort order + + * cvsinit.8: remove the .pl extension from filenames + +Wed Oct 18 11:07:07 1995 Vince Demarco + + * cvs.1 (Flag): Updated the CVSROOT/wrappers stuff. Everyone seems + to think this is a NEXT specific thing it isn't. + +Tue Oct 17 17:38:27 1995 Warren Jones + + * cvs.1: Change \. to \&. at start of line. + Tue Oct 3 13:43:33 1995 Del * cvs.1: Updated man page for all the new features of 1.6 diff --git a/gnu/usr.bin/cvs/man/cvs.1 b/gnu/usr.bin/cvs/man/cvs.1 index a703fa72506..f7e9a683d6e 100644 --- a/gnu/usr.bin/cvs/man/cvs.1 +++ b/gnu/usr.bin/cvs/man/cvs.1 @@ -2,7 +2,7 @@ .ds Rv \\$3 .ds Dt \\$4 .. -.Id $Id: cvs.1,v 1.1.1.1 1995/12/19 09:21:35 deraadt Exp $ +.Id $Id: cvs.1,v 1.1.1.2 1996/01/30 00:18:40 tholo Exp $ .TH CVS 1 "\*(Dt" .\" Full space in nroff; half space in troff .de SP @@ -1924,7 +1924,7 @@ supporting files, see .I Files in home directories: .TP -\.cvsrc +\&.cvsrc The .B cvs initialisation file. Lines in this file can be used to specify default @@ -1938,7 +1938,7 @@ is always passed the .B \-c option in addition to any other options passed on the command line. .TP -\.cvswrappers +\&.cvswrappers Specifies wrappers to be used in addition to those specified in the CVSROOT/cvswrappers file in the repository. .LP @@ -2010,38 +2010,36 @@ Records programs for filtering .` "cvs commit" requests. .TP +CVSROOT/cvswrappers,v +Records +.B cvs +wrapper commands to be used when checking files into and out of the +repository. Wrappers allow the file or directory to be processed +on the way in and out of CVS. The intended uses are many, one +possible use would be to reformat a C file before the file is checked +in, so all of the code in the repository looks the same. +.TP +CVSROOT/editinfo,v +Records programs for editing/validating +.` "cvs commit" +log entries. +.TP CVSROOT/history Log file of \fBcvs\fP transactions. .TP -CVSROOT/modules,v -Definitions for modules in this repository. -.TP CVSROOT/loginfo,v Records programs for piping .` "cvs commit" log entries. .TP +CVSROOT/modules,v +Definitions for modules in this repository. +.TP CVSROOT/rcsinfo,v Records pathnames to templates used during a .` "cvs commit" operation. .TP -CVSROOT/editinfo,v -Records programs for editing/validating -.` "cvs commit" -log entries. -.TP -CVSROOT/cvswrappers,v -Records -.B cvs -wrapper commands to be used when checking files into and out of the -repository. Wrappers are essentially directories that are to be -treated as files. This file allows wrappers to be processed -on the way in and out of CVS. The intended use is to wrap up a wrapper -into a single tar, such that that tar can be treated as a single -binary file in -.BR cvs . -.TP CVSROOT/taginfo,v Records programs for validating/logging .` "cvs tag" @@ -2049,7 +2047,7 @@ and .` "cvs rtag" operations. .TP -Attic +MODULE/Attic Directory for removed source files. .TP #cvs.lock diff --git a/gnu/usr.bin/cvs/man/cvs.5 b/gnu/usr.bin/cvs/man/cvs.5 index 9c477f3340a..cb4f4558804 100644 --- a/gnu/usr.bin/cvs/man/cvs.5 +++ b/gnu/usr.bin/cvs/man/cvs.5 @@ -10,19 +10,23 @@ cvs \- Concurrent Versions System support files .hy 0 .na .TP -.B $CVSROOT/CVSROOT/modules,v -.TP .B $CVSROOT/CVSROOT/commitinfo,v .TP -.B $CVSROOT/CVSROOT/loginfo,v +.B $CVSROOT/CVSROOT/cvsignore,v .TP -.B $CVSROOT/CVSROOT/rcsinfo,v +.B $CVSROOT/CVSROOT/cvswrappers,v .TP .B $CVSROOT/CVSROOT/editinfo,v .TP -.B $CVSROOT/CVSROOT/cvsignore,v -.TP .B $CVSROOT/CVSROOT/history +.TP +.B $CVSROOT/CVSROOT/loginfo,v +.TP +.B $CVSROOT/CVSROOT/modules,v +.TP +.B $CVSROOT/CVSROOT/rcsinfo,v +.TP +.B $CVSROOT/CVSROOT/taginfo,v .ad b .hy 1 .SH DESCRIPTION @@ -67,6 +71,14 @@ source repository from a particular person or group. Or, perhaps, to verify that the changed files conform to the site's standards for coding practice. .SP +You can use the `\|cvswrappers\|' file to record +.B cvs +wrapper commands to be used when checking files into and out of the +repository. Wrappers allow the file or directory to be processed +on the way in and out of CVS. The intended uses are many, one +possible use would be to reformat a C file before the file is checked +in, so all of the code in the repository looks the same. +.SP You can use the `\|loginfo\|' file to define programs to execute after any .BR commit , @@ -75,6 +87,14 @@ These logging programs might be used to append the log message to a file. Or send the log message through electronic mail to a group of developers. Or, perhaps, post the log message to a particular newsgroup. .SP +You can use the `\|taginfo\|' file to define programs to execute after +any +.BR tag or rtag +operation. These programs might be used to append a message to a file +listing the new tag name and the programmer who created it, or send mail +to a group of developers, or, perhaps, post a message to a particular +newsgroup. +.SP You can use the `\|rcsinfo\|' file to define forms for log messages. .SP You can use the `\|editinfo\|' file to define a program to execute for @@ -127,7 +147,7 @@ to get an editable copy of the file. You should define similar module entries for the other configuration files described here (except \&`\|history\|'). The -.BR cvsinit ( 1 ) +.BR cvsinit ( 8 ) script will setup a smilar `\|modules\|' file for you automatically. .SP The `\|modules\|' file may contain blank lines and comments (lines @@ -210,6 +230,10 @@ source repository. The `\|commitinfo\|', `\|loginfo\|', and to run whenever files in a module are checked out. \fIprog\fP runs with a single argument, the module name. .SP +`\|\fB\-e\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP +to run whenever files in a module are exported. \fIprog\fP runs +with a single argument, the module name. +.SP `\|\fB\-t\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP to run whenever files in a module are tagged. \fIprog\fP runs with two arguments: the module name and the symbolic tag specified to \fBrtag\fP. @@ -241,6 +265,23 @@ repository where the change is being made. The remaining arguments list the files that are being modified, added, or removed by this \fBcommit\fP invocation. .SP +For `\|taginfo\|', the rest of the +line is a command-line template to execute. +The arguments passed to the command are, in order, the +.I tagname , +.I operation +(i.e. +.B add +for `tag', +.B mov +for `tag -F', and +.B del +for `tag -d`), +.I repository , +and any remaining are pairs of +.B "filename revision" . +A non-zero exit of the filter program will cause the tag to be aborted. +.SP For `\|commitinfo\|', the rest of the line is a command-line template to execute. The template can include not only a program name, but whatever diff --git a/gnu/usr.bin/cvs/man/cvsinit.8 b/gnu/usr.bin/cvs/man/cvsinit.8 index 1df73875af8..2c670d9497d 100644 --- a/gnu/usr.bin/cvs/man/cvsinit.8 +++ b/gnu/usr.bin/cvs/man/cvsinit.8 @@ -1,8 +1,8 @@ .de Id -.ds Rv \\$3 -.ds Dt \\$4 +.ds Rv \\$4 +.ds Dt \\$5 .. -.Id $Id: cvsinit.8,v 1.1.1.1 1995/12/19 09:21:35 deraadt Exp $ +.Id @(#)ccvs/man:$Name: $:$Id: cvsinit.8,v 1.1.1.2 1996/01/30 00:18:43 tholo Exp $ .TH CVSINIT 8 "\*(Dt" .\" Full space in nroff; half space in troff .de SP @@ -65,22 +65,22 @@ Records programs for editing/validating .` "cvs commit" log entries. .TP -$CVSROOT/log.pl +$CVSROOT/log Sample logging script for use in .IR loginfo . .TP -$CVSROOT/commit_prep.pl +$CVSROOT/commit_prep Sample logging script for use in .I commitinfo with the -.I log_accum.pl +.I log_accum script .TP -$CVSROOT/log_accum.pl +$CVSROOT/log_accum Sample loggin script for use in .I loginfo with the -.I commit_prep.pl +.I commit_prep script .\" .SH "ENVIRONMENT VARIABLES" diff --git a/gnu/usr.bin/cvs/os2/.cvsignore b/gnu/usr.bin/cvs/os2/.cvsignore new file mode 100644 index 00000000000..fc6daa165c6 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/.cvsignore @@ -0,0 +1,3 @@ +Makefile +cvs.exe +icc.in diff --git a/gnu/usr.bin/cvs/os2/ChangeLog b/gnu/usr.bin/cvs/os2/ChangeLog new file mode 100644 index 00000000000..0a6070f4b08 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/ChangeLog @@ -0,0 +1,589 @@ +Sun Jan 28 12:31:03 1996 Jim Kingdon (kingdon@beezley) + + * filesubr.c (unlink_file): Use xchmod, not chmod, to make the + file read-write. + (xchmod): Translate / to \ in file name. If file doesn't exist, + return ENOENT rather than passing it to attrib (which will print an + error message). + +Sun Jan 28 01:51:27 1996 Jim Kingdon (kingdon@beezley) + + * config.h: Fix unclosed comment. + +Sun Jan 28 00:16:58 1996 Karl Fogel (kfogel@floss.cyclic.com) + + * filesubr.c (xchmod): rewritten for OS/2. + +Sat Jan 27 16:18:20 1996 Karl Fogel (kfogel@floss.cyclic.com) + + * config.h (CHMOD_BROKEN): define to 1. + + * filesubr.c (rename_file): rename() returns non-zero error codes, + not necessarily negative. + +Fri Jan 26 00:52:12 1996 unknown (unknown@beezley) + + * filesubr.c (copy_file): Open the file we are writing, not + just the one we are reading, in binary mode. + +Thu Jan 18 14:53:58 1996 Jim Kingdon + + * Makefile.in (CFLAGS): Don't use +=. This makefile must be + portable because it is used on all platforms (e.g. for "make dist"). + +Thu Jan 11 12:04:42 1996 Norbert Kiesel + + * options.h: remove CVS_NOADMIN + +Wed Jan 10 15:56:46 1996 Karl Fogel + + * options.h, config.h: moved NO_SOCKET_TO_FD definition from + options.h to config.h, which is where it belongs. + +Tue Jan 9 16:43:15 1996 Karl Fogel + + * run.c (sleep): commented out this definition. + * config.h: #define sleep() in terms of DosSleep(), unless sleep() + is defined already. Normally it's defined in + tcpip/include/utils.h, however on beezley that definition is + commented out for some reason. + Don't prototype sleep(). + +Tue Jan 9 16:22:35 1996 Jim Kingdon + + * .cvsignore: Add cvs.exe and icc.in. + +Tue Jan 09 16:43:59 1996 Jim Kingdon (kingdon@beezley.cyclic.com) + + * filesubr.c (link_file): New function (copied from + ../windows-NT/filesubr.c) + +Fri Jan 5 17:03:09 1996 Karl Fogel + + * Makefile.in: "lib_dir", not "libdir", to avoid conflict with + top-level Makefile. + +Mon Jan 1 22:59:46 1996 Jim Kingdon + + * Makefile.in (DISTFILES): Makefile is not in srcdir. + +Sat Dec 23 23:08:43 1995 Karl Fogel + + * README: adjust for below change. + + * Makefile.in (install-cvs): replaces `install', which must remain + a dummy rule so it will work under Unix. + +Wed Dec 20 15:18:06 1995 Karl Fogel + + * Makefile.in: build scramble.obj. + +Mon Dec 18 22:49:28 1995 Karl Fogel + + * Reverted all changes between Mon Dec 18 14:54:04 1995 and + present, non-inclusive. + +Mon Dec 18 21:59:07 1995 Karl Fogel + + * getpass.c: removed -- getpass() lives in os2/login.c now. + + * cvslogin.c: filled in. + + * login.c: new file. + + * Makefile.in: moved login.c and login.obj from COMMON to OS2 + section. + +Mon Dec 18 19:55:43 1995 Karl Fogel + + * cvslogin.c: added long explanatory comment. + +Mon Dec 18 18:13:57 1995 Karl Fogel + + * Makefile.in (DISTFILES): include cvslogin.c. + +Mon Dec 18 18:07:26 1995 Karl Fogel + + * README: updated. + + * Makefile.in (cvslogin.exe): new rule. + (install): new rule. + (install_dir): new var. + + * cvslogin.c: new file. + +Mon Dec 18 14:54:04 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * getpass.c (getpass): removed debugging garbage. + + * options.h (NO_SOCKET_TO_FD): fixed comment (Windows 95, not NT, + has this problem). + (AUTH_CLIENT_SUPPORT): on by default. + + * porttcp.c (SockStrError): fixed typo. + (IbmSockSend): `Buffer' arg is const void * again. + (IbmSockRecv): `Buffer' arg is const void * again. + + * tcpip.h (send): move send/recv redef section farther down to + avoid type conflicts with the real send() and recv(). + (IbmSockSend, IbmSockRecv): adjust prototype. + +Mon Dec 18 12:31:22 1995 Karl Fogel + + * tcpip.h: reformatted. + (send, recv): redefine to IbmSockSend and IbmSockRecv. + + * porttcp.c: reformatted. + +Mon Dec 18 04:59:52 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * tcpip.h (send, recv): don't define these to be anything else. + + * porttcp.c (IbmSockSend, IbmSockRecv): make `Buffer' argument + char * instead of void *, to evade an over-eager compiler. + +Sun Dec 17 21:16:17 1995 Karl Fogel + + * options.h (NO_SOCKET_TO_FD): define to 1. + +Sat Dec 16 21:31:02 1995 Karl Fogel + + * run.c: mark unimplemented routines more clearly. Hopefully I'll + get time to implement them soon. + +Fri Dec 15 17:50:17 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * tcpip.h, porttcp.c: new files. + + * makefile.in: added new files (for the "cvs watch" and "cvs edit" + commands just checked in by Jim Kingdon). + +Thu Dec 14 12:18:20 1995 Karl Fogel + + * config.h (RSH_NEEDS_BINARY_FLAG): define to 1. + + * run.c (filter_stream_through_program): die, rather than return + -1, if spawn failed. + + * options.h (AUTH_CLIENT_SUPPORT): leave unset by default. + +Wed Dec 13 21:31:10 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * waitpid.c (waitpid): Don't deal specially with statusp after all. + The problem lies elsewhere. + +Wed Dec 13 20:58:12 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * waitpid.c (waitpid): oops, make sure there is storage for + local_statusp. + Don't assign to *statusp if statusp is NULL. + +Wed Dec 13 19:52:08 1995 Karl Fogel + + * waitpid.c (waitpid): be more careful about child's exit status, + and about return status of this function. + +Wed Dec 13 20:10:50 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * makefile.in (clean): pass /NOE to the linker, to avoid duplicate + symbols when linking with setargv.obj. + +Wed Dec 13 18:44:47 1995 Karl Fogel + + * Makefile.in (ARGVLIB): new lib, link with this so command-line + wildcard expansion works. No, I'm not making this up. + +Tue Dec 12 20:43:56 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * getpass.c (getpass): new file and function. + + * options.h: prototype getpass() for OS/2. + + * makefile.in: include new file getpass.c. + +Tue Dec 12 19:21:05 1995 Karl Fogel + + * options.h (RCSBIN_DFLT): expand comment. + (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): replace obsolete + CVS_AUTH_CLIENT_SUPPORT and CVS_AUTH_SERVER_SUPPORT. + +Mon Dec 11 16:03:01 1995 Karl Fogel (kfogel@beezley.cyclic.com) + + * makefile.in: removed various and sundry cruft... + +Mon Dec 11 15:57:03 1995 Karl Fogel (kfogel@beezley.cyclic.com) + + * Removed cvs.exe; we don't need to keep the binary in the + repository, now that binary file handling has been tested. + +Mon Dec 11 15:53:51 1995 Karl Fogel (kfogel@beezley.cyclic.com) + + * rcmd.c (init_sockets): use sock_init(), not SockInit(). + +Mon Dec 11 12:43:35 1995 Adam Glass + + * config.h: Remove NEED_CALL_SOCKINIT macro in favor of the more + generic INITIALIZE_SOCKET_SUBSYSTEM. + * rcmd.c: Move old NEED_CALL_SOCKINIT code here and wrap it in a + function, i.e init_sockets() + +Sat Dec 09 21:16:09 1995 Karl Fogel (kfogel@beezley.cyclic.com) + + * Added cvs.exe, mainly to test binary file handling. Once we + know it works, we can remove it. + +Sat Dec 09 15:29:16 1995 Karl Fogel (kfogel@beezley.cyclic.com) + + * options.h (DIFF, GREP): don't expect autoconf to help us out. + +Sat Dec 09 15:05:41 1995 Karl Fogel (kfogel@beezley.cyclic.com) + + * makefile.in (libdir): Fixed. + + * options.h: define CVS_AUTH_CLIENT_SUPPORT and + CVS_AUTH_SERVER_SUPPORT, instead of CVS_LOGIN. + +Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com) + + * filesubr.c (isaccessible): Rename from isaccessable. + +Mon Dec 4 11:28:10 1995 Norbert Kiesel + + * Makefile.in (DISTFILES): prefix all filenames with + ${srcdir}${PS} + (dist-dir): remove ${srcdir}${PS} (some files already had this + prefix, now all have it) + +Fri Dec 1 14:29:44 1995 Karl Fogel + + * Makefile.in (srcdir, libdir, cvs_srcdir): use autoconf vars. + (dist-dir): use above vars now that they are autoconf-friendly. + (clean): same. + +Thu Nov 30 18:09:50 1995 Karl Fogel + + * waitpid.c (waitpid): if _cwait() returns -1, test errno. If + ECHILD, then just return pid, else return -1. This is for OS/2, + which doesn't have zombie processes, or any other way of + remembering a child process after it exits, as far as I can tell. + + * run.c (close_on_exec): don't error, just silently do nothing. + + * Makefile.in: use src/client.c, not os2/client.c. + + * config.h (EXECUTE_PERMISSION_LOSES): define to 1 (see + src/client.c for why). + (START_RSH_WITH_POPEN_RW): define to 1 (see src/client.c). + +Wed Nov 29 16:34:34 1995 Karl Fogel + + * client.c (start_server): declare pipes[] as int, not FILE *. + Kinda nice that it worked anyway, but scary. Ugh. + +Wed Nov 22 11:29:11 1995 Karl Fogel + + * config.h (KFF_DEBUG): expand to nothing; we don't want to print + out debugging messages in a production copy. + +Tue Nov 21 17:36:16 1995 unknown (unknown@beezley) + + * popen.c: #include . + +Tue Nov 21 16:18:37 1995 Karl Fogel + + * popen.h (popenRW): prototype popenRW()... why wasn't I doing + this before? + + * client.c (start_server): set tofd and fromfd with popenRW, now + that it handles int file descriptors. + Log to a file if asked, now that we have + filter_stream_through_program(). + + * popen.c (popenRW): put int file descriptors into the `pipes' + array, not FILE *'s. We'll fdopen in start_server, just like + the good old days. + +Tue Nov 21 16:34:37 1995 unknown (unknown@beezley) + + * run.c (filter_stream_through_program): defined for OS/2. + + * client.c (start_server): pass a char **argv to popenRW and get a + pid in return (instead of a return code). + + * popen.c (popenRW): use a char **argv and spawnvp(), instead of a + char *command and DosExecPgm(). + +Mon Nov 20 23:31:54 1995 unknown (unknown@beezley) + + * filesubr.c (convert_file): pass (S_IREAD | S_IWRITE) to open(); + we need it if O_CREAT, and it won't hurt if not. + +Sun Nov 19 13:43:02 1995 unknown (unknown@beezley) + + * makefile.in (clean): remove obj files in src/ and lib/ dirs too. + +Sun Nov 19 12:35:08 1995 Karl Fogel + + * client.c (start_server): took out old debug statements. + + * dirent.c, dirent.h: took out ^M's. + +Sat Nov 18 13:39:06 1995 Karl Fogel + + * client.c (start_server): took out debug statements. + + * filesubr.c (make_directories): compare errno to EACCESS, not + EEXIST, to see if the dir already exists. + + * client.c, filesubr.c: Use new macro `existence_error', instead + of comparing errno to ENOENT directly. + + * popen.c (popenRW): fixed misleading comment. + + * client.c: + (rsh_pid): no more need for this var; the handle-to-PID library in + popen.c manages PID's for us now. + (start_rsh_server): removed this func, since we don't use it -- we + do use `rsh', but we call it directly from popenRW(). + (get_responses_and_close): removed cruft that doesn't apply to + this port -- i.e., blocks conditional on HAVE_KERBEROS or + RSH_NOT_TRANSPARENT. + (start_server): Just check return code, instead of recording + rsh_pid. + +Fri Nov 17 21:13:22 1995 Karl Fogel + + * client.c (call_in_directory): Ask EACCESS even though we're + looking for EEXIST. That's just The Way Things Are Done here, + apparently. Ick. + + * getdate.c: took out some cruft that the more portable versions + need. + + * Makefile.in: use getdate.c from os2/ subdir, not lib/. + We don't use startserver.c anymore, so don't build it. + + * client.c (change_mode): never set anything executable, until we + understand what that means in OS/2. + + * config.h (NEED_DECOY_PERMISSIONS): define to 1 (& see + system.h). + +Fri Nov 17 15:02:05 1995 Karl Fogel + + * client.c: fixed up more error codes. + + * client.c: (send_repository): take into account the cornucopia of + error codes so generously offered by OS/2. + +Fri Nov 17 14:53:22 1995 Karl Fogel + + * client.c, client.h: new files, copied from ../src/. + + * config.h (HAVE_POPEN_RW): don't define this anymore, since we'll + just be using our own version of client.c. + + * Makefile.in: reflect the fact that os2/client.c is now used + instead of src/client.c. + +Thu Nov 16 21:47:22 1995 Karl Fogel + + * startserver.c: removed. We don't need this anymore. + + * config.h (RSH_NOT_TRANSPARENT): undef this. We have a + transparent rsh. + (HAVE_POPEN_RW): define to 1. + + * popen.c (popenRW): open writing and reading streams in binary + mode (i.e., "wb" and "rb"). + + * Makefile.in (clean): use `rm' not `del' to remove files. + +Wed Nov 15 15:21:53 1995 Karl Fogel + + * config.h: don't prototype gethostname() here anymore. + (USE_OWN_TCPIP_H): define to 1. + (NEED_CALL_SOCKINIT): define to 1. + (KFF_DEBUG): debugging macro. + +Tue Nov 14 12:20:22 1995 Greg A. Woods + + * .cvsignore: "Makefile" generated by ../configure + +Mon Nov 13 13:21:43 1995 Karl Fogel + + * Makefile.in (PS): note to maintainers about this var. + +Mon Nov 13 07:28:04 1995 Karl Fogel + + * README: updated. + + * rcmd.c: #include . + + * Makefile.in: Include lib/regex, lib/getdate, strippath. + (PS): default to "/", since we always "make dist" on Unix + systems. + Ahem, "save-cwd" with a hyphen, not an underscore. Oops. + + * strippath.c: new file. + + * popen.c: set DIAGNOSTIC off. Reformat for readability. + + * popen.h: new file. + + * config.h (USE_OWN_POPEN): define to 1. + + * run.c (Popen): make this work now that we have popen(). + +Mon Nov 13 01:23:27 1995 Karl Fogel + + * Makefile.in: + (cvs.exe): broke up OBJECTS into components to create icc.in in + more steps. OBJECTS had gotten so big that it formed too long a + command line all by itself. Sheesh. + Include stripslash (see below), lib/save_cwd, lib/sighandle, + lib/yesno, startserver (see below), rcmd (see below), lib/xgetwd, + lib/md5, waitpid (see below), lib/fnmatch, popen (see below). + + * popen.c, rcmd.c, rcmd.h, startserver.c, stripslash.c, waitpid.c: + New files. + + * run.c (close_on_exec): new func (skeleton). + (sleep): new func (OS/2 doesn't seem to have this). + + * pwd.c (getlogin): Don't call win32getlogin(), obviously. + + * config.h (W_OK, R_OK, X_OK, F_OK): define masks for access(). + Include for getpid(). + + * filesubr.c (isaccessable): define. Don't know why I left it out + before. For that matter, I don't know how the Windows NT port + gets along without it. Hmmm. + +Sat Nov 11 15:00:01 1995 Karl Fogel + + * Makefile.in: Use backslashes in pathnames, so ICC doesn't + mistake them for options. + + * run.c (run_setup): cleared away Windows NT stuff, left skeleton + functions that just complain and die for now. + (run_exec): correctly check return of spawn under OS/2; return + child's exit status. + (run_args): declare as returning void, in agreement with cvs.h. + +Fri Nov 10 14:21:14 1995 Karl Fogel + + * Makefile.in (COMMON_SOURCES, COMMON_OBJECTS): removed filesubr + and run, since we have OS/2-specific versions of them now. + (DISTFILES): Include Makefile in distribution, since people won't + be running configure on their OS/2 systems. + (LIB_SOURCES, LIB_OBJECTS): new vars; we'll just build stuff in + the lib directory and link it in directly. + Made rules for compiling objects and for the full executable. + (SHELL): got rid of this var, no need for it here. + Use a pattern rule for obj files. + Some other minor tweaks for OS/2. + + * threads.c: new file. + +Wed Nov 8 11:14:46 1995 Karl Fogel + + * run.c: include and . + Change all VA_START to va_start. + Don't ask HAVE_VPRINTF -- this is an OS/2-specific file and we can + take things for granted. + Started simplifying old NT `HANDLE' code. + + * Makefile.in (OS2_SOURCES): added run.c. + + * run.c: new file, copied from ../windows-NT/run.c. Started + making changes for OS/2. + + * test-makefile (all): don't bother to echo $CFLAGS; we can just + read the compilation command. + + * filesubr.c (unlink_file): make this work on OS/2. + (unlink_file_dir): don't ask if errno == EISDIR. We ain't + got EISDIR in OS/2. + (deep_remove_dir): use EACCESS to determine if directory + nonempty. We ain't got ENOTEMPTY in OS/2. + (that_swing): removed references. We ain't got that_swing in + OS/2. + (rename_file): just use unlink_file(); move to after definition of + unlink_file() so we don't have to deal with IBM C/C++'s strange + prototyping rituals. + (link_file): removed this function -- no one uses it anymore. + It still exists in src/filesubr.c, though. + (OS2_filename_classes): new table (well, old table, new name). + All references changed. + + * config.h (HAVE_SYS_UTIME_H): define to 1. + + * options.h: undef SETXID_SUPPORT, to correspond with Norbert + Kiesel's recent change to ../src/options.h.in, etc. + +Mon Nov 6 16:29:00 1995 Karl Fogel + + * test-makefile (CFLAGS): -DHAVE_CONFIG_H -- this turns out to be + important for stuff in lib/. + Other trivial changes. + + * config.h (HAVE_DIRENT_H): define to 1, now that we have our own + dirent.h and dirent.c. + + * Makefile.in (OS2_SOURCES): added filesubr.c; this may not be + permanent. + +Sun Nov 5 16:17:33 1995 Karl Fogel + + * Makefile.in (OS2_HEADERS, OS2_SOURCES): added dirent.h and + dirent.c, respectively. + + * dirent.c, dirent.h: new files. + +Sat Oct 28 14:41:38 1995 Karl Fogel + + * Makefile.in (DISTFILES): include `test-makefile'. + + * test-makefile: new file; to be removed when the port is done. + +Fri Oct 27 13:03:28 1995 Karl Fogel + + * Makefile.in (OS2_HEADERS, OS2_SOURCES): adjust as necessary for + below changes. + + * config.h: oops, don't forget second argument, MODE. + + * mkdir.c (os2_mkdir): new file, new function. + Can probably be merged with wnt_mkdir at some point. + + * config.h (ALLOCA_IN_STDLIB): new #define. + + * pwd.h, pwd.c: new files (for now, copied from ../windows-NT + directory. We'll modify/merge them as necessary.) + + * config.h: don't use __stdcall in declaration of gethostname(). + + * Makefile.in (DISTFILES): include config.h and options.h. + +Wed Oct 25 12:52:54 1995 Karl Fogel + + * config.h: new file; will maintain by hand. + Made first pass through to cast it into OS/2-ish condition. + + * Makefile.in: started adding lots of OS/2 gunk. + Took out autoconf stuff; just don't want to fool around with that + until after it compiles on beezley. + (cvs.exe): moved this rule to bottom. + +Tue Oct 24 13:51:05 1995 Norbert Kiesel + + * Makefile.in: add autoconf variables + + * Makefile.in (dist): use $(srcdir) + +Mon Oct 23 17:37:36 1995 Karl Fogel + + * Makefile.in (clean): new rule. + + * init os2 directory. Made dummy Makefile.in, README. diff --git a/gnu/usr.bin/cvs/os2/Makefile.in b/gnu/usr.bin/cvs/os2/Makefile.in new file mode 100644 index 00000000000..dfa66b4fd80 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/Makefile.in @@ -0,0 +1,303 @@ +# Makefile for OS/2. Generated from Makefile.in when CVS is +# configured for a dist-build. Configure never gets run on OS/2, so +# we must include the generated Makefile in the distribution. See the +# `dist-dir' rule. + +project: cvs.exe +# .SUFFIXES .c .obj .exe + +# path slash +# Maintainers: always leave this set to "/", because `make dist' has +# to work on Unix systems. See os2/README to find out why we have +# this var. +SL = / + +# Directory in which to install executables. +install_dir = s:${SL}gnu${SL}util + +# srcdir is usually "." +srcdir = @srcdir@ + +# top_srcdir is usually ".." +top_srcdir = @top_srcdir@ + +lib_dir = @top_srcdir@${SL}lib +cvs_srcdir = @top_srcdir@${SL}src + +# Do we need these? +# prefix = /usr/local +# exec_prefix = ${prefix} + +# taken straight from the example project +LIB = s:${SL}ibmcpp${SL}lib;s:${SL}toolkt21${SL}os2lib; +CINC = -Is:${SL}ibmcpp${SL}include -Is:${SL}toolkt21${SL}c${SL}os2h +# This says we are building an object file, not a full executable. +OBJ_CFLAGS = -C+ +CFLAGS = -W3 -Wpro+rea+tru+use+ -Ti+ -Ss+ -Gd+ -Gm+ -G4 -Q+ -Sm ${CINC} \ + -I${srcdir} -I${lib_dir} -I${cvs_srcdir} \ + -DIBM_CPP -DHAVE_CONFIG_H \ + -DTCPIP_IBM -Is:${SL}ibmtcpip${SL}include + +# needed to make command-line wildcard expansion work right. That's +# right, DOS-descendants handle this from the program, not the shell. +ARGVLIB = s:${SL}ibmcpp${SL}lib${SL}setargv.obj + +# TCP/IP stuff +TCPIPLIB = s:${SL}ibmtcpip${SL}lib${SL}tcp32dll.lib s:${SL}ibmtcpip${SL}lib${SL}so32dll.lib + + +# headers specific to OS/2 + +# We list OS2_HEADERS so we know what to include when we make dist-dir +# here. +OS2_HEADERS = \ + ${srcdir}${SL}tcpip.h \ + ${srcdir}${SL}config.h \ + ${srcdir}${SL}options.h \ + ${srcdir}${SL}pwd.h \ + ${srcdir}${SL}dirent.h \ + ${srcdir}${SL}rcmd.h \ + ${srcdir}${SL}popen.h + +# headers we use from the common src dir, ..${SL}src +COMMON_HEADERS = \ + ${cvs_srcdir}${SL}client.h \ + ${cvs_srcdir}${SL}cvs.h \ + ${cvs_srcdir}${SL}rcs.h \ + ${cvs_srcdir}${SL}hash.h \ + ${cvs_srcdir}${SL}myndbm.h \ + ${cvs_srcdir}${SL}patchlevel.h \ + ${cvs_srcdir}${SL}update.h \ + ${cvs_srcdir}${SL}server.h \ + ${cvs_srcdir}${SL}error.h + +# sources specific to OS/2 +OS2_SOURCES = \ + ${srcdir}${SL}mkdir.c \ + ${srcdir}${SL}pwd.c \ + ${srcdir}${SL}filesubr.c \ + ${srcdir}${SL}dirent.c \ + ${srcdir}${SL}run.c \ + ${srcdir}${SL}stripslash.c \ + ${srcdir}${SL}rcmd.c \ + ${srcdir}${SL}waitpid.c \ + ${srcdir}${SL}popen.c \ + ${srcdir}${SL}porttcp.c \ + ${srcdir}${SL}strippath.c \ + ${srcdir}${SL}getdate.c \ + ${srcdir}${SL}getpass.c + +# sources we use from the common src dir, ..${SL}src +COMMON_SOURCES = \ + ${cvs_srcdir}${SL}add.c \ + ${cvs_srcdir}${SL}admin.c \ + ${cvs_srcdir}${SL}checkin.c \ + ${cvs_srcdir}${SL}checkout.c \ + ${cvs_srcdir}${SL}classify.c \ + ${cvs_srcdir}${SL}client.c \ + ${cvs_srcdir}${SL}commit.c \ + ${cvs_srcdir}${SL}create_adm.c \ + ${cvs_srcdir}${SL}cvsrc.c \ + ${cvs_srcdir}${SL}diff.c \ + ${cvs_srcdir}${SL}edit.c \ + ${cvs_srcdir}${SL}entries.c \ + ${cvs_srcdir}${SL}error.c \ + ${cvs_srcdir}${SL}expand_path.c \ + ${cvs_srcdir}${SL}fileattr.c \ + ${cvs_srcdir}${SL}find_names.c \ + ${cvs_srcdir}${SL}hash.c \ + ${cvs_srcdir}${SL}history.c \ + ${cvs_srcdir}${SL}ignore.c \ + ${cvs_srcdir}${SL}import.c \ + ${cvs_srcdir}${SL}lock.c \ + ${cvs_srcdir}${SL}log.c \ + ${cvs_srcdir}${SL}login.c \ + ${cvs_srcdir}${SL}logmsg.c \ + ${cvs_srcdir}${SL}main.c \ + ${cvs_srcdir}${SL}modules.c \ + ${cvs_srcdir}${SL}myndbm.c \ + ${cvs_srcdir}${SL}no_diff.c \ + ${cvs_srcdir}${SL}parseinfo.c \ + ${cvs_srcdir}${SL}patch.c \ + ${cvs_srcdir}${SL}rcs.c \ + ${cvs_srcdir}${SL}rcscmds.c \ + ${cvs_srcdir}${SL}recurse.c \ + ${cvs_srcdir}${SL}release.c \ + ${cvs_srcdir}${SL}remove.c \ + ${cvs_srcdir}${SL}repos.c \ + ${cvs_srcdir}${SL}root.c \ + ${cvs_srcdir}${SL}rtag.c \ + ${cvs_srcdir}${SL}scramble.c \ + ${cvs_srcdir}${SL}server.c \ + ${cvs_srcdir}${SL}status.c \ + ${cvs_srcdir}${SL}subr.c \ + ${cvs_srcdir}${SL}tag.c \ + ${cvs_srcdir}${SL}update.c \ + ${cvs_srcdir}${SL}watch.c \ + ${cvs_srcdir}${SL}wrapper.c \ + ${cvs_srcdir}${SL}vers_ts.c \ + ${cvs_srcdir}${SL}version.c +# end of $COMMON_SOURCES + +# sources from ..${SL}lib +LIB_SOURCES = \ + ${lib_dir}${SL}getopt.c \ + ${lib_dir}${SL}getopt1.c \ + ${lib_dir}${SL}getline.c \ + ${lib_dir}${SL}getwd.c \ + ${lib_dir}${SL}save-cwd.c \ + ${lib_dir}${SL}sighandle.c \ + ${lib_dir}${SL}yesno.c \ + ${lib_dir}${SL}xgetwd.c \ + ${lib_dir}${SL}md5.c \ + ${lib_dir}${SL}fnmatch.c \ + ${lib_dir}${SL}regex.c + +# object files from OS/2 sources +OS2_OBJECTS = \ + ${srcdir}${SL}mkdir.obj \ + ${srcdir}${SL}pwd.obj \ + ${srcdir}${SL}filesubr.obj \ + ${srcdir}${SL}dirent.obj \ + ${srcdir}${SL}run.obj \ + ${srcdir}${SL}stripslash.obj \ + ${srcdir}${SL}rcmd.obj \ + ${srcdir}${SL}waitpid.obj \ + ${srcdir}${SL}popen.obj \ + ${srcdir}${SL}porttcp.obj \ + ${srcdir}${SL}strippath.obj \ + ${srcdir}${SL}getdate.obj \ + ${srcdir}${SL}getpass.obj + +# object files from ..${SL}src +COMMON_OBJECTS = \ + ${cvs_srcdir}${SL}add.obj \ + ${cvs_srcdir}${SL}admin.obj \ + ${cvs_srcdir}${SL}checkin.obj \ + ${cvs_srcdir}${SL}checkout.obj \ + ${cvs_srcdir}${SL}classify.obj \ + ${cvs_srcdir}${SL}client.obj \ + ${cvs_srcdir}${SL}commit.obj \ + ${cvs_srcdir}${SL}create_adm.obj \ + ${cvs_srcdir}${SL}cvsrc.obj \ + ${cvs_srcdir}${SL}diff.obj \ + ${cvs_srcdir}${SL}edit.obj \ + ${cvs_srcdir}${SL}entries.obj \ + ${cvs_srcdir}${SL}error.obj \ + ${cvs_srcdir}${SL}expand_path.obj \ + ${cvs_srcdir}${SL}fileattr.obj \ + ${cvs_srcdir}${SL}find_names.obj \ + ${cvs_srcdir}${SL}hash.obj \ + ${cvs_srcdir}${SL}history.obj \ + ${cvs_srcdir}${SL}ignore.obj \ + ${cvs_srcdir}${SL}import.obj \ + ${cvs_srcdir}${SL}lock.obj \ + ${cvs_srcdir}${SL}log.obj \ + ${cvs_srcdir}${SL}login.obj \ + ${cvs_srcdir}${SL}logmsg.obj \ + ${cvs_srcdir}${SL}main.obj \ + ${cvs_srcdir}${SL}modules.obj \ + ${cvs_srcdir}${SL}myndbm.obj \ + ${cvs_srcdir}${SL}no_diff.obj \ + ${cvs_srcdir}${SL}parseinfo.obj \ + ${cvs_srcdir}${SL}patch.obj \ + ${cvs_srcdir}${SL}rcs.obj \ + ${cvs_srcdir}${SL}rcscmds.obj \ + ${cvs_srcdir}${SL}recurse.obj \ + ${cvs_srcdir}${SL}release.obj \ + ${cvs_srcdir}${SL}remove.obj \ + ${cvs_srcdir}${SL}repos.obj \ + ${cvs_srcdir}${SL}root.obj \ + ${cvs_srcdir}${SL}rtag.obj \ + ${cvs_srcdir}${SL}scramble.obj \ + ${cvs_srcdir}${SL}server.obj \ + ${cvs_srcdir}${SL}status.obj \ + ${cvs_srcdir}${SL}subr.obj \ + ${cvs_srcdir}${SL}tag.obj \ + ${cvs_srcdir}${SL}update.obj \ + ${cvs_srcdir}${SL}watch.obj \ + ${cvs_srcdir}${SL}wrapper.obj \ + ${cvs_srcdir}${SL}vers_ts.obj \ + ${cvs_srcdir}${SL}version.obj +# end of $COMMON_OBJECTS + +# objects from ..${SL}lib +LIB_OBJECTS = \ + ${lib_dir}${SL}getopt.obj \ + ${lib_dir}${SL}getopt1.obj \ + ${lib_dir}${SL}getline.obj \ + ${lib_dir}${SL}getwd.obj \ + ${lib_dir}${SL}save-cwd.obj \ + ${lib_dir}${SL}sighandle.obj \ + ${lib_dir}${SL}yesno.obj \ + ${lib_dir}${SL}xgetwd.obj \ + ${lib_dir}${SL}md5.obj \ + ${lib_dir}${SL}fnmatch.obj \ + ${lib_dir}${SL}regex.obj + +SOURCES = ${COMMON_SOURCES} ${LIB_SOURCES} ${OS2_SOURCES} +HEADERS = ${COMMON_HEADERS} ${OS2_HEADERS} +OBJECTS = ${COMMON_OBJECTS} ${LIB_OBJECTS} ${OS2_OBJECTS} + +DISTFILES = ${OS2_HEADERS} ${OS2_SOURCES} \ + ${srcdir}${SL}README ${srcdir}${SL}ChangeLog \ + ${srcdir}${SL}Makefile.in ${srcdir}${SL}.cvsignore \ + ${srcdir}${SL}test-makefile Makefile + +all: + +.PHONY: all install uninstall +all install uninstall: + +.PHONY: tags TAGS +tags TAGS: + +.PHONY: ls +ls: + @echo ${DISTFILES} + +.PHONY: clean distclean realclean mostlyclean +clean distclean realclean mostlyclean: + +.PHONY: lint +lint: + +.PHONY: dist-dir +dist-dir: + mkdir ${DISTDIR} + for i in ${DISTFILES}; do \ + ln $${i} ${DISTDIR}; \ + done + +# We don't have a real distclean or anything like that, but at least +# we can get rid of the obj files and cvs.exe. +clean: + rm -f cvs.exe + rm -f ${srcdir}${SL}*.obj + rm -f ${lib_dir}${SL}*.obj + rm -f ${cvs_srcdir}${SL}*.obj + +install-cvs: cvs.exe + cp ${srcdir}${SL}cvs.exe ${install_dir}${SL}cvs.exe + +%.obj: %.c + icc ${OBJ_CFLAGS} ${CFLAGS} /Fo$@ $*.c + +# There seems to be no ICC option for specifying library locations, so +# we must `set' the path in the compilation environment. Urgkle. +cvs.exe: ${OBJECTS} + echo Creating icc.in... + echo -Q+ -Ti+ -Fe$@ -B"/batch" -B"/NOE" > icc.in + echo ${OS2_OBJECTS} >> icc.in + echo ${LIB_OBJECTS} >> icc.in + echo ${COMMON_OBJECTS} >> icc.in + echo ${TCPIPLIB} >> icc.in + echo ${ARGVLIB} >> icc.in + echo Creating icc.in... done. + set LIB=${LIB} & icc @icc.in + +# cvs.obj: ${OBJECTS} ${SOURCES} ${HEADERS} + +subdir = os2 +Makefile: ../config.status $(srcdir)/Makefile.in + cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status diff --git a/gnu/usr.bin/cvs/os2/README b/gnu/usr.bin/cvs/os2/README new file mode 100644 index 00000000000..50ed61625fd --- /dev/null +++ b/gnu/usr.bin/cvs/os2/README @@ -0,0 +1,31 @@ + This port requires IBM C/C++ and the IBM TCPIP library. +You'll need to edit the makefile to reflect your system's paths +(unless you're our customer for this port, in which case the paths +are correct because we did the port on your machine. :-) ). + + I'm having some weird problem with "\" vs. "/". If I build +with "\" as the path separator in the makefile, the compiler dumps +core. Go figure. If I build with "/" as the path separator, the +object files compile fine but the linker thinks the "/" is indicating +options and gets all confused (though at least it doesn't dump core). + + Right now the solution is to have a makefile variable called +SL, which must be set to "/" for the first invocation of make and "\" +for the second (the first pass will successfully build the object +files, but you can expect it do die with "unknown options" errors at +link time). + + $SL is defined near the top of the makefile. If you're going +to set $SL in the makefile itself, make sure to quote it ("\\"). On +the command line (i.e., "make SL=\"), I believe just one will do. + + That should be all -- edit the makefile, do "make" twice +(changing $SL the second time), and get os2\cvs.exe. Assuming you +have edited the `install_dir' variable in the Makefile, you may type +"make install-cvs" to put cvs.exe in the right place. + + You will get warnings during the compilation; ignore them. +Report bugs to . + +-Karl + diff --git a/gnu/usr.bin/cvs/os2/dirent.c b/gnu/usr.bin/cvs/os2/dirent.c new file mode 100644 index 00000000000..01bd92f56e7 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/dirent.c @@ -0,0 +1,180 @@ +/* + * Author: Bob Withers + * Copyright (c) 1993, All Rights Reserved + * + * NOTICE + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * The author makes no representations about the suitability of this + * software for any purpose. This software is provided ``as is'' + * without express or implied warranty. + */ + +#include +#include + +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#include + +#include "dirent.h" + + +#define DIRENT_INCR 25 + + +DIR *opendir(char *filename) +{ + auto size_t len; + auto DIR *dirp; + auto char *p; + auto HDIR hdir; + +#ifdef OS2_16 + auto USHORT rc; /* for 16 bit OS/2 */ + auto FILEFINDBUF ff; + auto USHORT cnt; +#else + auto APIRET rc; /* for 32 bit OS/2 */ + auto FILEFINDBUF3 ff; + auto ULONG cnt; +#endif /* OS2_16 */ + + if (NULL == filename || '\0' == filename[0]) + filename = "."; + + dirp = malloc(sizeof(*dirp)); + if (NULL == dirp) + return(NULL); + + len = strlen(filename); + dirp->dirname = malloc(len + 5); + if (NULL == dirp->dirname) + { + free(dirp); + return(NULL); + } + + dirp->max_ent = 0; + dirp->tot_ent = 0; + dirp->cur_ent = 0; + dirp->entp = NULL; + strcpy(dirp->dirname, filename); + for (p = dirp->dirname; *p; ++p) + { + if ('/' == *p) + *p = '\\'; + } + + if ('\\' != dirp->dirname[len - 1]) + strcat(dirp->dirname, "\\"); + + strcat(dirp->dirname, "*.*"); + + hdir = HDIR_SYSTEM; + cnt = 1; + rc = DosFindFirst(dirp->dirname, &hdir, + FILE_NORMAL | FILE_READONLY | FILE_HIDDEN | + FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED, + &ff, sizeof(ff), &cnt, FIL_STANDARD); + + while (NO_ERROR == rc) + { + auto struct dirent *entp; + + if (dirp->tot_ent >= dirp->max_ent) + { + auto struct dirent **p; + + dirp->max_ent += DIRENT_INCR; + p = realloc(dirp->entp, dirp->max_ent * sizeof(entp)); + if (NULL == p) + { + rc = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + dirp->entp = p; + } + + entp = malloc(sizeof(*entp) + (size_t) ff.cchName); + if (NULL == entp) + { + rc = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + entp->d_ino = 0; + entp->d_off = dirp->tot_ent; + entp->d_namlen = (unsigned short) ff.cchName; + memcpy(entp->d_name, ff.achName, entp->d_namlen); + entp->d_name[entp->d_namlen] = '\0'; + dirp->entp[dirp->tot_ent++] = entp; + + cnt = 1; + rc = DosFindNext(hdir, &ff, sizeof(ff), &cnt); + } + + DosFindClose(hdir); + if (ERROR_NO_MORE_FILES == rc) + return(dirp); + + closedir(dirp); + return(NULL); +} + + +struct dirent *readdir(DIR *dirp) +{ + if (dirp->cur_ent < 0 || dirp->cur_ent >= dirp->tot_ent) + return(NULL); + + return(dirp->entp[dirp->cur_ent++]); +} + + +long telldir(DIR *dirp) +{ + return((long) dirp->cur_ent); +} + + +void seekdir(DIR *dirp, long loc) +{ + dirp->cur_ent = (int) loc; + return; +} + + +void rewinddir(DIR *dirp) +{ + dirp->cur_ent = 0; + return; +} + + +void closedir(DIR *dirp) +{ + if (dirp) + { + if (dirp->dirname) + free(dirp->dirname); + + if (dirp->entp) + { + register int i; + + for (i = 0; i < dirp->tot_ent; ++i) + free(dirp->entp[i]); + + free(dirp->entp); + } + } + + return; +} diff --git a/gnu/usr.bin/cvs/os2/dirent.h b/gnu/usr.bin/cvs/os2/dirent.h new file mode 100644 index 00000000000..bc218b5fdc6 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/dirent.h @@ -0,0 +1,50 @@ +/* + * Author: Bob Withers + * Copyright (c) 1993, All Rights Reserved + * + * NOTICE + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * The author makes no representations about the suitability of this + * software for any purpose. This software is provided ``as is'' + * without express or implied warranty. + */ + +#ifndef DIRENT_H +#define DIRENT_H + +/* Unix style directory(3C) support for OS/2 V2.x */ + +struct dirent +{ + long d_ino; /* not used in this implementation */ + long d_off; /* not used in this implementation */ + unsigned short d_namlen; + char d_name[1]; +}; + + +struct S_Dir +{ + char *dirname; + int max_ent; + int tot_ent; + int cur_ent; + struct dirent **entp; +}; +typedef struct S_Dir DIR; + + +DIR * opendir(char *filename); +struct dirent * readdir(DIR *dirp); +long telldir(DIR *dirp); +void seekdir(DIR *dirp, long loc); +void rewinddir(DIR *dirp); +void closedir(DIR *dirp); + +#endif /* DIRENT_H */ diff --git a/gnu/usr.bin/cvs/os2/filesubr.c b/gnu/usr.bin/cvs/os2/filesubr.c new file mode 100644 index 00000000000..849915afa3a --- /dev/null +++ b/gnu/usr.bin/cvs/os2/filesubr.c @@ -0,0 +1,737 @@ +/* filesubr.c --- subroutines for dealing with files under OS/2 + Jim Blandy and Karl Fogel + + This file is part of GNU CVS. + + GNU CVS is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* These functions were moved out of subr.c because they need different + definitions under operating systems (like, say, Windows NT) with different + file system semantics. */ + +#include + +#include "cvs.h" + +#ifndef lint +static const char rcsid[] = "$CVSid:$"; +USE(rcsid); +#endif + +/* + * I don't know of a convenient way to test this at configure time, or else + * I'd certainly do it there. -JimB + */ +#if defined(NeXT) +#define LOSING_TMPNAM_FUNCTION +#endif + +static int deep_remove_dir PROTO((const char *path)); + +/* + * Copies "from" to "to". + */ +void +copy_file (from, to) + const char *from; + const char *to; +{ + struct stat sb; + struct utimbuf t; + int fdin, fdout; + + if (trace) +#ifdef SERVER_SUPPORT + (void) fprintf (stderr, "%c-> copy(%s,%s)\n", + (server_active) ? 'S' : ' ', from, to); +#else + (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to); +#endif + if (noexec) + return; + + if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0) + error (1, errno, "cannot open %s for copying", from); + if (fstat (fdin, &sb) < 0) + error (1, errno, "cannot fstat %s", from); + if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, + (int) sb.st_mode & 07777)) < 0) + error (1, errno, "cannot create %s for copying", to); + if (sb.st_size > 0) + { + char buf[BUFSIZ]; + int n; + + for (;;) + { + n = read (fdin, buf, sizeof(buf)); + if (n == -1) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + error (1, errno, "cannot read file %s for copying", from); + } + else if (n == 0) + break; + + if (write(fdout, buf, n) != n) { + error (1, errno, "cannot write file %s for copying", to); + } + } + +#ifdef HAVE_FSYNC + if (fsync (fdout)) + error (1, errno, "cannot fsync file %s after copying", to); +#endif + } + + if (close (fdin) < 0) + error (0, errno, "cannot close %s", from); + if (close (fdout) < 0) + error (1, errno, "cannot close %s", to); + + /* now, set the times for the copied file to match those of the original */ + memset ((char *) &t, 0, sizeof (t)); + t.actime = sb.st_atime; + t.modtime = sb.st_mtime; + (void) utime (to, &t); +} + +/* + * link a file, if possible. Warning: the Windows NT version of this + * function just copies the file, so only use this function in ways + * that can deal with either a link or a copy. + */ +int +link_file (from, to) + const char *from; + const char *to; +{ + copy_file (from, to); + return 0; +} + +/* FIXME-krp: these functions would benefit from caching the char * & + stat buf. */ + +/* + * Returns non-zero if the argument file is a directory, or is a symbolic + * link which points to a directory. + */ +int +isdir (file) + const char *file; +{ + struct stat sb; + + if (stat (file, &sb) < 0) + return (0); + return (S_ISDIR (sb.st_mode)); +} + +/* + * Returns non-zero if the argument file is a symbolic link. + */ +int +islink (file) + const char *file; +{ +#ifdef S_ISLNK + struct stat sb; + + if (lstat (file, &sb) < 0) + return (0); + return (S_ISLNK (sb.st_mode)); +#else + return (0); +#endif +} + +/* + * Returns non-zero if the argument file exists. + */ +int +isfile (file) + const char *file; +{ + struct stat sb; + + if (stat (file, &sb) < 0) + return (0); + return (1); +} + +/* + * Returns non-zero if the argument file is readable. + * XXX - must be careful if "cvs" is ever made setuid! + */ +int +isreadable (file) + const char *file; +{ + return (access (file, R_OK) != -1); +} + +/* + * Returns non-zero if the argument file is writable + * XXX - muct be careful if "cvs" is ever made setuid! + */ +int +iswritable (file) + const char *file; +{ + return (access (file, W_OK) != -1); +} + +/* + * Returns non-zero if the argument file is accessable according to + * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid + * bits set. + */ +int +isaccessible (file, mode) + const char *file; + const int mode; +{ + return access(file, mode) == 0; +} + + +/* + * Open a file and die if it fails + */ +FILE * +open_file (name, mode) + const char *name; + const char *mode; +{ + FILE *fp; + + if ((fp = fopen (name, mode)) == NULL) + error (1, errno, "cannot open %s", name); + return (fp); +} + +/* + * Make a directory and die if it fails + */ +void +make_directory (name) + const char *name; +{ + struct stat buf; + + if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode))) + error (0, 0, "%s already exists but is not a directory", name); + if (!noexec && mkdir (name) < 0) + error (1, errno, "cannot make directory %s", name); +} + +/* + * Make a path to the argument directory, printing a message if something + * goes wrong. + */ +void +make_directories (name) + const char *name; +{ + char *cp; + + if (noexec) + return; + + if (mkdir (name) == 0 || errno == EACCESS) + return; + if (! existence_error (errno)) + { + error (0, errno, "cannot make path to %s", name); + return; + } + if ((cp = strrchr (name, '/')) == NULL) + return; + *cp = '\0'; + make_directories (name); + *cp++ = '/'; + if (*cp == '\0') + return; + (void) mkdir (name); +} + +/* + * Change the mode of a file, either adding write permissions, or removing + * all write permissions. Adding write permissions honors the current umask + * setting. + */ +void +xchmod (fname, writable) + char *fname; + int writable; +{ + char *attrib_cmd; + char *attrib_option; + char *whole_cmd; + char *p; + char *q; + + if (!isfile (fname)) + return ENOENT; + + attrib_cmd = "attrib "; /* No, really? */ + + if (writable) + attrib_option = "-r "; /* make writeable */ + else + attrib_option = "+r "; /* make read-only */ + + whole_cmd = xmalloc (strlen (attrib_cmd) + + strlen (attrib_option) + + strlen (fname) + + 1); + + strcpy (whole_cmd, attrib_cmd); + strcat (whole_cmd, attrib_option); + + /* Copy fname to the end of whole_cmd, translating / to \. + Attrib doesn't take / but many parts of CVS rely + on being able to use it. */ + p = whole_cmd + strlen (whole_cmd); + q = fname; + while (*q) + { + if (*q == '/') + *p++ = '\\'; + else + *p++ = *q; + ++q; + } + *p = '\0'; + + system (whole_cmd); + free (whole_cmd); +} + + +/* Read the value of a symbolic link. + Under OS/2, this function always returns EINVAL. */ +int +readlink (char *path, char *buf, int buf_size) +{ + errno = EINVAL; + return -1; +} + +/* + * unlink a file, if possible. + */ +int +unlink_file (f) + const char *f; +{ + if (trace) +#ifdef SERVER_SUPPORT + (void) fprintf (stderr, "%c-> unlink(%s)\n", + (server_active) ? 'S' : ' ', f); +#else + (void) fprintf (stderr, "-> unlink(%s)\n", f); +#endif + if (noexec) + return (0); + + /* Win32 unlink is stupid - it fails if the file is read-only. + * OS/2 is similarly stupid. It does have a remove() function, + * but the documentation does not make clear why remove() is or + * isn't preferable to unlink(). I'll use unlink() because the + * name is closer to our interface, what the heck. Also, we know + * unlink()'s error code when trying to remove a directory. + */ + xchmod (f, 1); + return (unlink (f)); +} + +/* + * Unlink a file or dir, if possible. If it is a directory do a deep + * removal of all of the files in the directory. Return -1 on error + * (in which case errno is set). + */ +int +unlink_file_dir (f) + const char *f; +{ + if (trace) +#ifdef SERVER_SUPPORT + (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n", + (server_active) ? 'S' : ' ', f); +#else + (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f); +#endif + if (noexec) + return (0); + + if (unlink_file (f) != 0) + { + /* under OS/2, unlink returns EACCESS if the path + is a directory. */ + if (errno == EACCESS) + return deep_remove_dir (f); + else + /* The file wasn't a directory and some other + * error occured + */ + return -1; + } + /* We were able to remove the file from the disk */ + return 0; +} + +/* Remove a directory and everything it contains. Returns 0 for + * success, -1 for failure (in which case errno is set). + */ + +static int +deep_remove_dir (path) + const char *path; +{ + DIR *dirp; + struct dirent *dp; + char buf[PATH_MAX]; + + if ( rmdir (path) != 0 && errno == EACCESS ) + { + if ((dirp = opendir (path)) == NULL) + /* If unable to open the directory return + * an error + */ + return -1; + + while ((dp = readdir (dirp)) != NULL) + { + if (strcmp (dp->d_name, ".") == 0 || + strcmp (dp->d_name, "..") == 0) + continue; + + sprintf (buf, "%s/%s", path, dp->d_name); + + if (unlink_file (buf) != 0 ) + { + if (errno == EACCES) + { + if (deep_remove_dir (buf)) + { + closedir (dirp); + return -1; + } + } + else + { + /* buf isn't a directory, or there are + * some sort of permision problems + */ + closedir (dirp); + return -1; + } + } + } + closedir (dirp); + return rmdir (path); + } + /* Was able to remove the directory return 0 */ + return 0; +} + + +/* + * Rename a file and die if it fails + */ +void +rename_file (from, to) + const char *from; + const char *to; +{ + if (trace) +#ifdef SERVER_SUPPORT + (void) fprintf (stderr, "%c-> rename(%s,%s)\n", + (server_active) ? 'S' : ' ', from, to); +#else + (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to); +#endif + if (noexec) + return; + + unlink_file (to); + if (rename (from, to) != 0) + error (1, errno, "cannot rename file %s to %s", from, to); +} + + +/* Read NCHARS bytes from descriptor FD into BUF. + Return the number of characters successfully read. + The number returned is always NCHARS unless end-of-file or error. */ +static size_t +block_read (fd, buf, nchars) + int fd; + char *buf; + size_t nchars; +{ + char *bp = buf; + size_t nread; + + do + { + nread = read (fd, bp, nchars); + if (nread == (size_t)-1) + { +#ifdef EINTR + if (errno == EINTR) + continue; +#endif + return (size_t)-1; + } + + if (nread == 0) + break; + + bp += nread; + nchars -= nread; + } while (nchars != 0); + + return bp - buf; +} + + +/* + * Compare "file1" to "file2". Return non-zero if they don't compare exactly. + */ +int +xcmp (file1, file2) + const char *file1; + const char *file2; +{ + char *buf1, *buf2; + struct stat sb1, sb2; + int fd1, fd2; + int ret; + + if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0) + error (1, errno, "cannot open file %s for comparing", file1); + if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0) + error (1, errno, "cannot open file %s for comparing", file2); + if (fstat (fd1, &sb1) < 0) + error (1, errno, "cannot fstat %s", file1); + if (fstat (fd2, &sb2) < 0) + error (1, errno, "cannot fstat %s", file2); + + /* A generic file compare routine might compare st_dev & st_ino here + to see if the two files being compared are actually the same file. + But that won't happen in CVS, so we won't bother. */ + + if (sb1.st_size != sb2.st_size) + ret = 1; + else if (sb1.st_size == 0) + ret = 0; + else + { + /* FIXME: compute the optimal buffer size by computing the least + common multiple of the files st_blocks field */ + size_t buf_size = 8 * 1024; + size_t read1; + size_t read2; + + buf1 = xmalloc (buf_size); + buf2 = xmalloc (buf_size); + + do + { + read1 = block_read (fd1, buf1, buf_size); + if (read1 == (size_t)-1) + error (1, errno, "cannot read file %s for comparing", file1); + + read2 = block_read (fd2, buf2, buf_size); + if (read2 == (size_t)-1) + error (1, errno, "cannot read file %s for comparing", file2); + + /* assert (read1 == read2); */ + + ret = memcmp(buf1, buf2, read1); + } while (ret == 0 && read1 == buf_size); + + free (buf1); + free (buf2); + } + + (void) close (fd1); + (void) close (fd2); + return (ret); +} + + +/* The equivalence class mapping for filenames. + OS/2 filenames are case-insensitive, but case-preserving. Both / + and \ are path element separators. + Thus, this table maps both upper and lower case to lower case, and + both / and \ to /. + + Much thanks to Jim Blandy, who already invented this wheel in the + Windows NT port. */ + +#if 0 +main () +{ + int c; + + for (c = 0; c < 256; c++) + { + int t; + + if (c == '\\') + t = '/'; + else + t = tolower (c); + + if ((c & 0x7) == 0x0) + printf (" "); + printf ("0x%02x,", t); + if ((c & 0x7) == 0x7) + putchar ('\n'); + else if ((c & 0x7) == 0x3) + putchar (' '); + } +} +#endif + + +unsigned char +OS2_filename_classes[] = +{ + 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37, + 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f, + 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, + 0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, + 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, + 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f, + 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97, + 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f, + 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7, + 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7, + 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf, + 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7, + 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7, + 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf, + 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7, + 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef, + 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7, + 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff, +}; + +/* Like strcmp, but with the appropriate tweaks for file names. + Under OS/2, filenames are case-insensitive but case-preserving, and + both \ and / are path element separators. */ +int +fncmp (const char *n1, const char *n2) +{ + while (*n1 && *n2 + && (OS2_filename_classes[(unsigned char) *n1] + == OS2_filename_classes[(unsigned char) *n2])) + n1++, n2++; + return (OS2_filename_classes[(unsigned char) *n1] + - OS2_filename_classes[(unsigned char) *n1]); +} + +/* Fold characters in FILENAME to their canonical forms. + If FOLD_FN_CHAR is not #defined, the system provides a default + definition for this. */ +void +fnfold (char *filename) +{ + while (*filename) + { + *filename = FOLD_FN_CHAR (*filename); + filename++; + } +} + + +/* Return non-zero iff FILENAME is absolute. + Trivial under Unix, but more complicated under other systems. */ +int +isabsolute (filename) + const char *filename; +{ + return (ISDIRSEP (filename[0]) + || (filename[0] != '\0' + && filename[1] == ':' + && ISDIRSEP (filename[2]))); +} + +/* Return a pointer into PATH's last component. */ +char * +last_component (char *path) +{ + char *scan; + char *last = 0; + + for (scan = path; *scan; scan++) + if (ISDIRSEP (*scan)) + last = scan; + + if (last) + return last + 1; + else + return path; +} + + +/* Read data from INFILE, and copy it to OUTFILE. + Open INFILE using INFLAGS, and OUTFILE using OUTFLAGS. + This is useful for converting between CRLF and LF line formats. */ +void +convert_file (char *infile, int inflags, + char *outfile, int outflags) +{ + int infd, outfd; + char buf[8192]; + int len; + + if ((infd = open (infile, inflags, S_IREAD | S_IWRITE)) < 0) + error (1, errno, "couldn't read %s", infile); + if ((outfd = open (outfile, outflags, S_IREAD | S_IWRITE)) < 0) + error (1, errno, "couldn't write %s", outfile); + + while ((len = read (infd, buf, sizeof (buf))) > 0) + if (write (outfd, buf, len) < 0) + error (1, errno, "error writing %s", outfile); + if (len < 0) + error (1, errno, "error reading %s", infile); + + if (close (outfd) < 0) + error (0, errno, "warning: couldn't close %s", outfile); + if (close (infd) < 0) + error (0, errno, "warning: couldn't close %s", infile); +} diff --git a/gnu/usr.bin/cvs/os2/getdate.c b/gnu/usr.bin/cvs/os2/getdate.c new file mode 100644 index 00000000000..dcfcdf39e9c --- /dev/null +++ b/gnu/usr.bin/cvs/os2/getdate.c @@ -0,0 +1,1578 @@ +/* stolen from lib/getdate.c */ + +#include "config.h" +#include +#include +#include + +/* The code at the top of get_date which figures out the offset of the + current time zone checks various CPP symbols to see if special + tricks are need, but defaults to using the gettimeofday system call. + Include if that will be used. */ + +#if defined(vms) + +#include +#include + +#else + +#include + +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#ifdef timezone +#undef timezone /* needed for sgi */ +#endif + +#if defined(HAVE_SYS_TIMEB_H) +#include +#else +/* +** We use the obsolete `struct timeb' as part of our interface! +** Since the system doesn't have it, we define it here; +** our callers must do likewise. +*/ +struct timeb { + time_t time; /* Seconds since the epoch */ + unsigned short millitm; /* Field not used */ + short timezone; /* Minutes west of GMT */ + short dstflag; /* Field not used */ +}; +#endif /* defined(HAVE_SYS_TIMEB_H) */ + +#endif /* defined(vms) */ + +#if defined (STDC_HEADERS) || defined (USG) +#include +#endif + +/* Some old versions of bison generate parsers that use bcopy. + That loses on systems that don't provide the function, so we have + to redefine it here. */ +#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy) +#define bcopy(from, to, len) memcpy ((to), (from), (len)) +#endif + +#if defined (STDC_HEADERS) +#include +#endif + +#if defined (HAVE_ALLOCA_H) +#include +#endif + +extern struct tm *gmtime(); +extern struct tm *localtime(); + +#define yyparse getdate_yyparse +#define yylex getdate_yylex +#define yyerror getdate_yyerror + +#if !defined(lint) && !defined(SABER) +static char RCS[] = "$CVSid: @(#)getdate.y 1.11 94/09/21 $"; +#endif /* !defined(lint) && !defined(SABER) */ + +static int yylex (); +static int yyerror (); + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; + + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + + +typedef union { + time_t Number; + enum _MERIDIAN Meridian; +} YYSTYPE; +# define tAGO 257 +# define tDAY 258 +# define tDAYZONE 259 +# define tID 260 +# define tMERIDIAN 261 +# define tMINUTE_UNIT 262 +# define tMONTH 263 +# define tMONTH_UNIT 264 +# define tSEC_UNIT 265 +# define tSNUMBER 266 +# define tUNUMBER 267 +# define tZONE 268 +# define tDST 269 +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 +extern int yychar; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval, yyval; +# define YYERRCODE 256 + + + +/* Month and day table. */ +static TABLE const MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL } +}; + +/* Time units table. */ +static TABLE const UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, + { "week", tMINUTE_UNIT, 7 * 24 * 60 }, + { "day", tMINUTE_UNIT, 1 * 24 * 60 }, + { "hour", tMINUTE_UNIT, 60 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL } +}; + +/* Assorted relative-time words. */ +static TABLE const OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 2 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL } +}; + +/* The timezone table. */ +/* Some of these are commented out because a time_t can't store a float. */ +static TABLE const TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR( 0) }, + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "wat", tZONE, HOUR( 1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR(11) }, /* Nome */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR(3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Stanard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { NULL } +}; + +/* Military timezone table. */ +static TABLE const MilitaryTable[] = { + { "a", tZONE, HOUR( 1) }, + { "b", tZONE, HOUR( 2) }, + { "c", tZONE, HOUR( 3) }, + { "d", tZONE, HOUR( 4) }, + { "e", tZONE, HOUR( 5) }, + { "f", tZONE, HOUR( 6) }, + { "g", tZONE, HOUR( 7) }, + { "h", tZONE, HOUR( 8) }, + { "i", tZONE, HOUR( 9) }, + { "k", tZONE, HOUR( 10) }, + { "l", tZONE, HOUR( 11) }, + { "m", tZONE, HOUR( 12) }, + { "n", tZONE, HOUR(- 1) }, + { "o", tZONE, HOUR(- 2) }, + { "p", tZONE, HOUR(- 3) }, + { "q", tZONE, HOUR(- 4) }, + { "r", tZONE, HOUR(- 5) }, + { "s", tZONE, HOUR(- 6) }, + { "t", tZONE, HOUR(- 7) }, + { "u", tZONE, HOUR(- 8) }, + { "v", tZONE, HOUR(- 9) }, + { "w", tZONE, HOUR(-10) }, + { "x", tZONE, HOUR(-11) }, + { "y", tZONE, HOUR(-12) }, + { "z", tZONE, HOUR( 0) }, + { NULL } +}; + + + + +/* ARGSUSED */ +static int +yyerror(s) + char *s; +{ + return 0; +} + + +static time_t +ToSeconds(Hours, Minutes, Seconds, Meridian) + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + switch (Meridian) { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; + default: + abort (); + } + /* NOTREACHED */ +} + + +static time_t +Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) + time_t Month; + time_t Day; + time_t Year; + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; + DSTMODE DSTmode; +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + int i; + + if (Year < 0) + Year = -Year; + if (Year < 100) + Year += 1900; + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + if (Year < EPOCH || Year > 1999 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + for (Julian = Day - 1, i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(Start, Future) + time_t Start; + time_t Future; +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(Start, DayOrdinal, DayNumber) + time_t Start; + time_t DayOrdinal; + time_t DayNumber; +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(Start, RelMonth) + time_t Start; + time_t RelMonth; +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord(buff) + char *buff; +{ + register char *p; + register char *q; + register const TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + + if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen(buff) == 3) + abbrev = 1; + else if (strlen(buff) == 4 && buff[3] == '.') { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) { + if (abbrev) { + if (strncmp(buff, tp->name, 3) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen(buff) - 1; + if (buff[i] == 's') { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && isalpha(*buff)) { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + + +static int +yylex() +{ + register char c; + register char *p; + char buff[20]; + int Count; + int sign; + + for ( ; ; ) { + while (isspace(*yyInput)) + yyInput++; + + if (isdigit(c = *yyInput) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + if (!isdigit(*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; isdigit(c = *yyInput++); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (isalpha(c)) { + for (p = buff; isalpha(c = *yyInput++) || c == '.'; ) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord(buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (a, b) + struct tm *a, *b; +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + int days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay/100 - by/100) + + ((ay/100 >> 2) - (by/100 >> 2)) + /* + difference in years * 365 */ + + (long)(ay-by) * 365 + ); + return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date(p, now) + char *p; + struct timeb *now; +{ + struct tm *tm, gmt; + struct timeb ftz; + time_t Start; + time_t tod; + + yyInput = p; + if (now == NULL) { + now = &ftz; + (void)time(&ftz.time); + + if (! (tm = gmtime (&ftz.time))) + return -1; + gmt = *tm; /* Make a copy, in case localtime modifies *tm. */ + + if (! (tm = localtime (&ftz.time))) + return -1; + + ftz.timezone = difftm (&gmt, tm) / 60; + if(tm->tm_isdst) + ftz.timezone += 60; + } + + tm = localtime(&now->time); + yyYear = tm->tm_year; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = now->timezone; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now->time; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +int +main(ac, av) + int ac; + char *av[]; +{ + char buff[128]; + time_t d; + + (void)printf("Enter date, or blank line to exit.\n\t> "); + (void)fflush(stdout); + while (gets(buff) && buff[0]) { + d = get_date(buff, (struct timeb *)NULL); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("%s", ctime(&d)); + (void)printf("\t> "); + (void)fflush(stdout); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ +int yyexca[] ={ +-1, 1, + 0, -1, + -2, 0, + }; +# define YYNPROD 42 +# define YYLAST 228 +int yyact[]={ + + 13, 11, 22, 28, 16, 12, 18, 17, 15, 9, + 10, 38, 39, 20, 48, 44, 47, 46, 36, 43, + 50, 32, 35, 34, 33, 29, 37, 31, 41, 45, + 40, 30, 14, 8, 7, 6, 5, 4, 3, 2, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 21, 0, 0, 19, 25, 24, 27, + 26, 23, 44, 0, 0, 0, 0, 42 }; +int yypact[]={ + + -1000, -258, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -45, + -266, -1000, -242, -13, -230, -241, -1000, -1000, -1000, -1000, + -245, -1000, -249, -240, -255, -1000, -1000, -1000, -1000, -14, + -1000, -1000, -1000, -1000, -1000, -39, -18, -1000, -1000, -1000, + -250, -1000, -1000, -251, -1000, -253, -1000, -246, -1000, -1000, + -1000 }; +int yypgo[]={ + + 0, 28, 40, 39, 38, 37, 36, 35, 34, 33, + 32 }; +int yyr1[]={ + + 0, 2, 2, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 5, 5, 5, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 8, 8, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, + 1, 1 }; +int yyr2[]={ + + 0, 0, 4, 3, 3, 3, 3, 3, 2, 5, + 9, 9, 13, 13, 3, 3, 5, 3, 5, 5, + 7, 11, 7, 7, 5, 9, 5, 7, 5, 2, + 5, 5, 3, 5, 5, 3, 5, 5, 3, 3, + 1, 3 }; +int yychk[]={ + + -1000, -2, -3, -4, -5, -6, -7, -8, -9, 267, + 268, 259, 263, 258, -10, 266, 262, 265, 264, 261, + 58, 258, 47, 266, 263, 262, 265, 264, 269, 267, + 44, 257, 262, 265, 264, 267, 267, 266, 266, 267, + 44, -1, 266, 58, 261, 47, 267, 267, 267, -1, + 266 }; +int yydef[]={ + + 1, -2, 2, 3, 4, 5, 6, 7, 8, 39, + 14, 15, 0, 17, 29, 0, 32, 35, 38, 9, + 0, 19, 0, 0, 26, 30, 34, 37, 16, 24, + 18, 28, 31, 33, 36, 40, 20, 22, 23, 27, + 0, 10, 11, 0, 41, 0, 25, 40, 21, 12, + 13 }; +typedef struct { char *t_name; int t_val; } yytoktype; +#ifndef YYDEBUG +# define YYDEBUG 0 /* don't allow debugging */ +#endif + +#if YYDEBUG + +yytoktype yytoks[] = +{ + "tAGO", 257, + "tDAY", 258, + "tDAYZONE", 259, + "tID", 260, + "tMERIDIAN", 261, + "tMINUTE_UNIT", 262, + "tMONTH", 263, + "tMONTH_UNIT", 264, + "tSEC_UNIT", 265, + "tSNUMBER", 266, + "tUNUMBER", 267, + "tZONE", 268, + "tDST", 269, + "-unknown-", -1 /* ends search */ +}; + +char * yyreds[] = +{ + "-no such reduction-", + "spec : /* empty */", + "spec : spec item", + "item : time", + "item : zone", + "item : date", + "item : day", + "item : rel", + "item : number", + "time : tUNUMBER tMERIDIAN", + "time : tUNUMBER ':' tUNUMBER o_merid", + "time : tUNUMBER ':' tUNUMBER tSNUMBER", + "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid", + "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER", + "zone : tZONE", + "zone : tDAYZONE", + "zone : tZONE tDST", + "day : tDAY", + "day : tDAY ','", + "day : tUNUMBER tDAY", + "date : tUNUMBER '/' tUNUMBER", + "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", + "date : tUNUMBER tSNUMBER tSNUMBER", + "date : tUNUMBER tMONTH tSNUMBER", + "date : tMONTH tUNUMBER", + "date : tMONTH tUNUMBER ',' tUNUMBER", + "date : tUNUMBER tMONTH", + "date : tUNUMBER tMONTH tUNUMBER", + "rel : relunit tAGO", + "rel : relunit", + "relunit : tUNUMBER tMINUTE_UNIT", + "relunit : tSNUMBER tMINUTE_UNIT", + "relunit : tMINUTE_UNIT", + "relunit : tSNUMBER tSEC_UNIT", + "relunit : tUNUMBER tSEC_UNIT", + "relunit : tSEC_UNIT", + "relunit : tSNUMBER tMONTH_UNIT", + "relunit : tUNUMBER tMONTH_UNIT", + "relunit : tMONTH_UNIT", + "number : tUNUMBER", + "o_merid : /* empty */", + "o_merid : tMERIDIAN", +}; +#endif /* YYDEBUG */ +/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */ + +/* +** Skeleton parser driver for yacc output +*/ + +/* +** yacc user known macros and defines +*/ +#define YYERROR goto yyerrlab +#define YYACCEPT { free(yys); free(yyv); return(0); } +#define YYABORT { free(yys); free(yyv); return(1); } +#define YYBACKUP( newtoken, newvalue )\ +{\ + if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\ + {\ + yyerror( "syntax error - cannot backup" );\ + goto yyerrlab;\ + }\ + yychar = newtoken;\ + yystate = *yyps;\ + yylval = newvalue;\ + goto yynewstate;\ +} +#define YYRECOVERING() (!!yyerrflag) +#ifndef YYDEBUG +# define YYDEBUG 1 /* make debugging available */ +#endif + +/* +** user known globals +*/ +int yydebug; /* set to 1 to get debugging */ + +/* +** driver internal defines +*/ +#define YYFLAG (-1000) + +/* +** static variables used by the parser +*/ +static YYSTYPE *yyv; /* value stack */ +static int *yys; /* state stack */ + +static YYSTYPE *yypv; /* top of value stack */ +static int *yyps; /* top of state stack */ + +static int yystate; /* current state */ +static int yytmp; /* extra var (lasts between blocks) */ + +int yynerrs; /* number of errors */ + +int yyerrflag; /* error recovery flag */ +int yychar; /* current input token number */ + + +/* +** yyparse - return 0 if worked, 1 if syntax error not recovered from +*/ +int +yyparse() +{ + register YYSTYPE *yypvt; /* top of value stack for $vars */ + unsigned yymaxdepth = YYMAXDEPTH; + + /* + ** Initialize externals - yyparse may be called more than once + */ + yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE)); + yys = (int*)malloc(yymaxdepth*sizeof(int)); + if (!yyv || !yys) + { + yyerror( "out of memory" ); + return(1); + } + yypv = &yyv[-1]; + yyps = &yys[-1]; + yystate = 0; + yytmp = 0; + yynerrs = 0; + yyerrflag = 0; + yychar = -1; + + goto yystack; + { + register YYSTYPE *yy_pv; /* top of value stack */ + register int *yy_ps; /* top of state stack */ + register int yy_state; /* current state */ + register int yy_n; /* internal state number info */ + + /* + ** get globals into registers. + ** branch to here only if YYBACKUP was called. + */ + yynewstate: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + goto yy_newstate; + + /* + ** get globals into registers. + ** either we just started, or we just finished a reduction + */ + yystack: + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + + /* + ** top of for (;;) loop while no reductions done + */ + yy_stack: + /* + ** put a state and value onto the stacks + */ +#if YYDEBUG + /* + ** if debugging, look up token value in list of value vs. + ** name pairs. 0 and negative (-1) are special values. + ** Note: linear search is used since time is not a real + ** consideration while debugging. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "State %d, token ", yy_state ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */ + { + /* + ** reallocate and recover. Note that pointers + ** have to be reset, or bad things will happen + */ + int yyps_index = (yy_ps - yys); + int yypv_index = (yy_pv - yyv); + int yypvt_index = (yypvt - yyv); + yymaxdepth += YYMAXDEPTH; + yyv = (YYSTYPE*)realloc((char*)yyv, + yymaxdepth * sizeof(YYSTYPE)); + yys = (int*)realloc((char*)yys, + yymaxdepth * sizeof(int)); + if (!yyv || !yys) + { + yyerror( "yacc stack overflow" ); + return(1); + } + yy_ps = yys + yyps_index; + yy_pv = yyv + yypv_index; + yypvt = yyv + yypvt_index; + } + *yy_ps = yy_state; + *++yy_pv = yyval; + + /* + ** we have a new state - find out what to do + */ + yy_newstate: + if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG ) + goto yydefault; /* simple state */ +#if YYDEBUG + /* + ** if debugging, need to mark whether new token grabbed + */ + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val == yychar ) + break; + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) ) + goto yydefault; + if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/ + { + yychar = -1; + yyval = yylval; + yy_state = yy_n; + if ( yyerrflag > 0 ) + yyerrflag--; + goto yy_stack; + } + + yydefault: + if ( ( yy_n = yydef[ yy_state ] ) == -2 ) + { +#if YYDEBUG + yytmp = yychar < 0; +#endif + if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) ) + yychar = 0; /* reached EOF */ +#if YYDEBUG + if ( yydebug && yytmp ) + { + register int yy_i; + + (void)printf( "Received token " ); + if ( yychar == 0 ) + (void)printf( "end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "-none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "%s\n", yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + /* + ** look through exception table + */ + { + register int *yyxi = yyexca; + + while ( ( *yyxi != -1 ) || + ( yyxi[1] != yy_state ) ) + { + yyxi += 2; + } + while ( ( *(yyxi += 2) >= 0 ) && + ( *yyxi != yychar ) ) + ; + if ( ( yy_n = yyxi[1] ) < 0 ) + YYACCEPT; + } + } + + /* + ** check for syntax error + */ + if ( yy_n == 0 ) /* have an error */ + { + /* no worry about speed here! */ + switch ( yyerrflag ) + { + case 0: /* new error */ + yyerror( "syntax error" ); + goto skip_init; + yyerrlab: + /* + ** get globals into registers. + ** we have a user generated syntax type error + */ + yy_pv = yypv; + yy_ps = yyps; + yy_state = yystate; + yynerrs++; + skip_init: + case 1: + case 2: /* incompletely recovered error */ + /* try again... */ + yyerrflag = 3; + /* + ** find state where "error" is a legal + ** shift action + */ + while ( yy_ps >= yys ) + { + yy_n = yypact[ *yy_ps ] + YYERRCODE; + if ( yy_n >= 0 && yy_n < YYLAST && + yychk[yyact[yy_n]] == YYERRCODE) { + /* + ** simulate shift of "error" + */ + yy_state = yyact[ yy_n ]; + goto yy_stack; + } + /* + ** current state has no shift on + ** "error", pop stack + */ +#if YYDEBUG +# define _POP_ "Error recovery pops state %d, uncovers state %d\n" + if ( yydebug ) + (void)printf( _POP_, *yy_ps, + yy_ps[-1] ); +# undef _POP_ +#endif + yy_ps--; + yy_pv--; + } + /* + ** there is no state on stack with "error" as + ** a valid shift. give up. + */ + YYABORT; + case 3: /* no shift yet; eat a token */ +#if YYDEBUG + /* + ** if debugging, look up token in list of + ** pairs. 0 and negative shouldn't occur, + ** but since timing doesn't matter when + ** debugging, it doesn't hurt to leave the + ** tests here. + */ + if ( yydebug ) + { + register int yy_i; + + (void)printf( "Error recovery discards " ); + if ( yychar == 0 ) + (void)printf( "token end-of-file\n" ); + else if ( yychar < 0 ) + (void)printf( "token -none-\n" ); + else + { + for ( yy_i = 0; + yytoks[yy_i].t_val >= 0; + yy_i++ ) + { + if ( yytoks[yy_i].t_val + == yychar ) + { + break; + } + } + (void)printf( "token %s\n", + yytoks[yy_i].t_name ); + } + } +#endif /* YYDEBUG */ + if ( yychar == 0 ) /* reached EOF. quit */ + YYABORT; + yychar = -1; + goto yy_newstate; + } + }/* end if ( yy_n == 0 ) */ + /* + ** reduction by production yy_n + ** put stack tops, etc. so things right after switch + */ +#if YYDEBUG + /* + ** if debugging, print the string that is the user's + ** specification of the reduction which is just about + ** to be done. + */ + if ( yydebug ) + (void)printf( "Reduce by (%d) \"%s\"\n", + yy_n, yyreds[ yy_n ] ); +#endif + yytmp = yy_n; /* value to switch over */ + yypvt = yy_pv; /* $vars top of value stack */ + /* + ** Look in goto table for next state + ** Sorry about using yy_state here as temporary + ** register variable, but why not, if it works... + ** If yyr2[ yy_n ] doesn't have the low order bit + ** set, then there is no action to be done for + ** this reduction. So, no saving & unsaving of + ** registers done. The only difference between the + ** code just after the if and the body of the if is + ** the goto yy_stack in the body. This way the test + ** can be made before the choice of what to do is needed. + */ + { + /* length of production doubled with extra bit */ + register int yy_len = yyr2[ yy_n ]; + + if ( !( yy_len & 01 ) ) + { + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = + yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + goto yy_stack; + } + yy_len >>= 1; + yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */ + yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] + + *( yy_ps -= yy_len ) + 1; + if ( yy_state >= YYLAST || + yychk[ yy_state = yyact[ yy_state ] ] != -yy_n ) + { + yy_state = yyact[ yypgo[ yy_n ] ]; + } + } + /* save until reenter driver code */ + yystate = yy_state; + yyps = yy_ps; + yypv = yy_pv; + } + /* + ** code supplied by user is placed in this switch + */ + switch( yytmp ) + { + +case 3: +{ + yyHaveTime++; + } break; +case 4: +{ + yyHaveZone++; + } break; +case 5: +{ + yyHaveDate++; + } break; +case 6: +{ + yyHaveDay++; + } break; +case 7: +{ + yyHaveRel++; + } break; +case 9: +{ + yyHour = yypvt[-1].Number; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = yypvt[-0].Meridian; + } break; +case 10: +{ + yyHour = yypvt[-3].Number; + yyMinutes = yypvt[-1].Number; + yySeconds = 0; + yyMeridian = yypvt[-0].Meridian; + } break; +case 11: +{ + yyHour = yypvt[-3].Number; + yyMinutes = yypvt[-1].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - (yypvt[-0].Number % 100 + (yypvt[-0].Number / 100) * 60); + } break; +case 12: +{ + yyHour = yypvt[-5].Number; + yyMinutes = yypvt[-3].Number; + yySeconds = yypvt[-1].Number; + yyMeridian = yypvt[-0].Meridian; + } break; +case 13: +{ + yyHour = yypvt[-5].Number; + yyMinutes = yypvt[-3].Number; + yySeconds = yypvt[-1].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - (yypvt[-0].Number % 100 + (yypvt[-0].Number / 100) * 60); + } break; +case 14: +{ + yyTimezone = yypvt[-0].Number; + yyDSTmode = DSToff; + } break; +case 15: +{ + yyTimezone = yypvt[-0].Number; + yyDSTmode = DSTon; + } break; +case 16: +{ + yyTimezone = yypvt[-1].Number; + yyDSTmode = DSTon; + } break; +case 17: +{ + yyDayOrdinal = 1; + yyDayNumber = yypvt[-0].Number; + } break; +case 18: +{ + yyDayOrdinal = 1; + yyDayNumber = yypvt[-1].Number; + } break; +case 19: +{ + yyDayOrdinal = yypvt[-1].Number; + yyDayNumber = yypvt[-0].Number; + } break; +case 20: +{ + yyMonth = yypvt[-2].Number; + yyDay = yypvt[-0].Number; + } break; +case 21: +{ + yyMonth = yypvt[-4].Number; + yyDay = yypvt[-2].Number; + yyYear = yypvt[-0].Number; + } break; +case 22: +{ + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = yypvt[-2].Number; + yyMonth = -yypvt[-1].Number; + yyDay = -yypvt[-0].Number; + } break; +case 23: +{ + /* e.g. 17-JUN-1992. */ + yyDay = yypvt[-2].Number; + yyMonth = yypvt[-1].Number; + yyYear = -yypvt[-0].Number; + } break; +case 24: +{ + yyMonth = yypvt[-1].Number; + yyDay = yypvt[-0].Number; + } break; +case 25: +{ + yyMonth = yypvt[-3].Number; + yyDay = yypvt[-2].Number; + yyYear = yypvt[-0].Number; + } break; +case 26: +{ + yyMonth = yypvt[-0].Number; + yyDay = yypvt[-1].Number; + } break; +case 27: +{ + yyMonth = yypvt[-1].Number; + yyDay = yypvt[-2].Number; + yyYear = yypvt[-0].Number; + } break; +case 28: +{ + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } break; +case 30: +{ + yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number * 60L; + } break; +case 31: +{ + yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number * 60L; + } break; +case 32: +{ + yyRelSeconds += yypvt[-0].Number * 60L; + } break; +case 33: +{ + yyRelSeconds += yypvt[-1].Number; + } break; +case 34: +{ + yyRelSeconds += yypvt[-1].Number; + } break; +case 35: +{ + yyRelSeconds++; + } break; +case 36: +{ + yyRelMonth += yypvt[-1].Number * yypvt[-0].Number; + } break; +case 37: +{ + yyRelMonth += yypvt[-1].Number * yypvt[-0].Number; + } break; +case 38: +{ + yyRelMonth += yypvt[-0].Number; + } break; +case 39: +{ + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = yypvt[-0].Number; + else { + if(yypvt[-0].Number>10000) { + yyHaveDate++; + yyDay= (yypvt[-0].Number)%100; + yyMonth= (yypvt[-0].Number/100)%100; + yyYear = yypvt[-0].Number/10000; + } + else { + yyHaveTime++; + if (yypvt[-0].Number < 100) { + yyHour = yypvt[-0].Number; + yyMinutes = 0; + } + else { + yyHour = yypvt[-0].Number / 100; + yyMinutes = yypvt[-0].Number % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + } break; +case 40: +{ + yyval.Meridian = MER24; + } break; +case 41: +{ + yyval.Meridian = yypvt[-0].Meridian; + } break; + } + goto yystack; /* reset registers in driver code */ +} diff --git a/gnu/usr.bin/cvs/os2/getpass.c b/gnu/usr.bin/cvs/os2/getpass.c new file mode 100644 index 00000000000..b1113aedfc2 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/getpass.c @@ -0,0 +1,25 @@ +#include +#include +#include "cvs.h" + +char * +getpass (char *prompt) +{ + static char passbuf[30]; + int i; + char *p; + int ch; + + printf ("%s", prompt); + fflush (stdout); + + p = passbuf, i = 0; + while (((ch = getchar ()) != '\n') && (ch != EOF)) + { + if (i++ < 24) + *p++ = ch; + } + *p = '\0'; + + return passbuf; +} diff --git a/gnu/usr.bin/cvs/os2/mkdir.c b/gnu/usr.bin/cvs/os2/mkdir.c new file mode 100644 index 00000000000..2c9df546847 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/mkdir.c @@ -0,0 +1,17 @@ +/* mkdir.c --- mkdir for OS/2 + Karl Fogel --- October 1995 */ + +#include + +#include "cvs.h" + +int +os2_mkdir (const char *path, int mode) +{ + /* This is true for all extant calls to CVS_MKDIR. If + someone adds a call that uses something else later, + we should tweak this function to handle that. */ + assert (mode == 0777); + + return mkdir (path); +} diff --git a/gnu/usr.bin/cvs/os2/options.h b/gnu/usr.bin/cvs/os2/options.h new file mode 100644 index 00000000000..d0bbac10cb3 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/options.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1992, Brian Berliner and Jeff Polk + * Copyright (c) 1989-1992, Brian Berliner + * + * 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. + * + * This file holds (most of) the configuration tweaks that can be made to + * customize CVS for your site. CVS comes configured for a typical SunOS 4.x + * environment. The comments for each configurable item are intended to be + * self-explanatory. All #defines are tested first to see if an over-riding + * option was specified on the "make" command line. + * + * If special libraries are needed, you will have to edit the Makefile.in file + * or the configure script directly. Sorry. + */ + +/* + * CVS provides the most features when used in conjunction with the Version-5 + * release of RCS. Thus, it is the default. This also assumes that GNU diff + * Version-1.15 is being used as well -- you will have to configure your RCS + * V5 release separately to make this the case. If you do not have RCS V5 and + * GNU diff V1.15, comment out this define. You should not try mixing and + * matching other combinations of these tools. + */ +#ifndef HAVE_RCS5 +#define HAVE_RCS5 +#endif + +/* + * If, before installing this version of CVS, you were running RCS V4 AND you + * are installing this CVS and RCS V5 and GNU diff 1.15 all at the same time, + * you should turn on the following define. It only exists to try to do + * reasonable things with your existing checked out files when you upgrade to + * RCS V5, since the keyword expansion formats have changed with RCS V5. + * + * If you already have been running with RCS5, or haven't been running with CVS + * yet at all, or are sticking with RCS V4 for now, leave the commented out. + */ +#ifndef HAD_RCS4 +/* #define HAD_RCS4 */ +#endif + +/* + * For portability and heterogeneity reasons, CVS is shipped by default using + * my own text-file version of the ndbm database library in the src/myndbm.c + * file. If you want better performance and are not concerned about + * heterogeneous hosts accessing your modules file, turn this option off. + */ +#ifndef MY_NDBM +#define MY_NDBM +#endif + +/* + * The "diff" program to execute when creating patch output. This "diff" + * must support the "-c" option for context diffing. Specify a full + * pathname if your site wants to use a particular diff. If you are + * using the GNU version of diff (version 1.15 or later), this should + * be "diff -a". + * + * NOTE: this program is only used for the ``patch'' sub-command (and + * for ``update'' if you are using the server). The other commands + * use rcsdiff which will use whatever version of diff was specified + * when rcsdiff was built on your system. + */ + +#ifndef DIFF +#define DIFF "diff" +#endif + +/* + * The "grep" program to execute when checking to see if a merged file had + * any conflicts. This "grep" must support the "-s" option and a standard + * regular expression as an argument. Specify a full pathname if your site + * wants to use a particular grep. + */ + +#ifndef GREP +#define GREP "grep" +#endif + +/* + * The "rm" program to execute when pruning directories that are not part of + * a release. This "rm" must support the "-fr" options. Specify a full + * pathname if your site wants to use a particular rm. + */ +#ifndef RM +#define RM "rm" +#endif + +/* + * The "sort" program to execute when displaying the module database. Specify + * a full pathname if your site wants to use a particular sort. + */ +#ifndef SORT +#define SORT "sort" +#endif + +/* + * The "patch" program to run when using the CVS server and accepting + * patches across the network. Specify a full pathname if your site + * wants to use a particular patch. + */ +#ifndef PATCH_PROGRAM +#define PATCH_PROGRAM "patch" +#endif + +/* + * By default, RCS programs are executed with the shell or through execlp(), + * so the user's PATH environment variable is searched. If you'd like to + * bind all RCS programs to a certain directory (perhaps one not in most + * people's PATH) then set the default in RCSBIN_DFLT. Note that setting + * this here will cause all RCS programs to be executed from this directory, + * unless the user overrides the default with the RCSBIN environment variable + * or the "-b" option to CVS. + * + * If you're compiling the authenticating server (see + * AUTH_SERVER_SUPPORT farther down), then you probably want to set + * RCSBIN_DFLT. The authenticating server starts out running as root, + * and then switches to run as the appropriate user once + * authentication is complete. No shell is ever started by that user, + * so the PATH environment variable may not contain the directory with + * the RCS binaries, even though if that user logged in normally, PATH + * would include the directory. An alternative to setting RCSBIN_DFLT + * is to make sure that root has the right directory in its path + * already. + * + * This define should be either the empty string ("") or a full pathname to the + * directory containing all the installed programs from the RCS distribution. + */ +#ifndef RCSBIN_DFLT +#define RCSBIN_DFLT "" +#endif + +/* + * The default editor to use, if one does not specify the "-e" option to cvs, + * or does not have an EDITOR environment variable. I set this to just "vi", + * and use the shell to find where "vi" actually is. This allows sites with + * /usr/bin/vi or /usr/ucb/vi to work equally well (assuming that your PATH + * is reasonable). + * + * The notepad program seems to be Windows NT's bare-bones text editor. + */ +#ifndef EDITOR_DFLT +#define EDITOR_DFLT "notepad" +#endif + +/* + * The default umask to use when creating or otherwise setting file or + * directory permissions in the repository. Must be a value in the + * range of 0 through 0777. For example, a value of 002 allows group + * rwx access and world rx access; a value of 007 allows group rwx + * access but no world access. This value is overridden by the value + * of the CVSUMASK environment variable, which is interpreted as an + * octal number. + */ +#ifndef UMASK_DFLT +#define UMASK_DFLT 002 +#endif + +/* + * The cvs admin command is restricted to the members of the group + * CVS_ADMIN_GROUP. If this group does not exist, all users are + * allowed to run cvs admin. To disable the cvs admin for all users, + * create an empty group CVS_ADMIN_GROUP. To disable access control for + * cvs admin, comment out the define below. + * + * Under Windows NT and OS/2, this must not be used because it tries + * to include . + */ +#ifdef CVS_ADMIN_GROUP +/* #define CVS_ADMIN_GROUP "cvsadmin" */ +#endif + +/* + * The Repository file holds the path to the directory within the source + * repository that contains the RCS ,v files for each CVS working directory. + * This path is either a full-path or a path relative to CVSROOT. + * + * The only advantage that I can see to having a relative path is that One can + * change the physical location of the master source repository, change one's + * CVSROOT environment variable, and CVS will work without problems. I + * recommend using full-paths. + */ +#ifndef RELATIVE_REPOS +/* #define RELATIVE_REPOS */ +#endif + +/* + * When committing or importing files, you must enter a log message. + * Normally, you can do this either via the -m flag on the command line or an + * editor will be started for you. If you like to use logging templates (the + * rcsinfo file within the $CVSROOT/CVSROOT directory), you might want to + * force people to use the editor even if they specify a message with -m. + * Enabling FORCE_USE_EDITOR will cause the -m message to be appended to the + * temp file when the editor is started. + */ +#ifndef FORCE_USE_EDITOR +/* #define FORCE_USE_EDITOR */ +#endif + +/* + * When locking the repository, some sites like to remove locks and assume + * the program that created them went away if the lock has existed for a long + * time. This used to be the default for previous versions of CVS. CVS now + * attempts to be much more robust, so lock files should not be left around + * by mistake. The new behaviour will never remove old locks (they must now + * be removed by hand). Enabling CVS_FUDGELOCKS will cause CVS to remove + * locks that are older than CVSLCKAGE seconds. + * Use of this option is NOT recommended. + */ +#ifndef CVS_FUDGELOCKS +/* #define CVS_FUDGELOCKS */ +#endif + +/* + * When committing a permanent change, CVS and RCS make a log entry of + * who committed the change. If you are committing the change logged in + * as "root" (not under "su" or other root-priv giving program), CVS/RCS + * cannot determine who is actually making the change. + * + * As such, by default, CVS disallows changes to be committed by users + * logged in as "root". You can disable this option by commenting + * out the lines below. + * + * Under Windows NT, privileges are associated with groups, not users, + * so the case in which someone has logged in as root does not occur. + * Thus, there is no need for this hack. + * + * todo: I don't know about OS/2 yet. -kff + */ +#undef CVS_BADROOT + +/* + * The "cvs diff" command accepts all the single-character options that GNU + * diff (1.15) accepts. Except -D. GNU diff uses -D as a way to put + * cpp-style #define's around the output differences. CVS, by default, uses + * -D to specify a free-form date (like "cvs diff -D '1 week ago'"). If + * you would prefer that the -D option of "cvs diff" work like the GNU diff + * option, then comment out this define. + */ +#ifndef CVS_DIFFDATE +#define CVS_DIFFDATE +#endif + +/* + * define this to enable the SETXID support (see FAQ 4D.13) + * [ We have no such thing under OS/2, so far as I know. ] + */ +#undef SETXID_SUPPORT + +/* + * Under OS/2, we build the authenticated client by default. + * But not the server, because there is no server support for OS/2 + * yet. + */ +#define AUTH_CLIENT_SUPPORT 1 +/* #define AUTH_SERVER_SUPPORT 1 */ + +/* End of CVS configuration section */ + +/* + * Externs that are included in libc, but are used frequently enough to + * warrant defining here. + */ +#ifndef STDC_HEADERS +extern void exit (); +#endif + +#ifndef getwd +extern char *getwd (); +#endif + +#ifdef AUTH_CLIENT_SUPPORT +char *getpass (char *passbuf); +#endif /* AUTH_CLIENT_SUPPORT */ diff --git a/gnu/usr.bin/cvs/os2/popen.c b/gnu/usr.bin/cvs/os2/popen.c new file mode 100644 index 00000000000..9f8199764d5 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/popen.c @@ -0,0 +1,380 @@ +/* popen.c -- popen/pclose for OS/2. */ + +/* Set to 0 for distribution. + Search for "DIAGNOSTIC" in the code to see what it's for. */ +#define DIAGNOSTIC 0 + +#define INCL_DOSQUEUES +#define INCL_DOSPROCESS +#define INCL_DOSSESMGR +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define LL_VAL ULONG +#define LL_KEY PID /* also ULONG, really */ + + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +/* ********************************************************************* * + * * + * First, a little linked-list library to help keep track of pipes: * + * * + * ********************************************************************* */ + +/* Map integer PID's onto integer termination codes. */ +struct pid_list +{ + HFILE pid; /* key */ + ULONG term_code; /* val */ + struct pid_list *next; /* duh */ +}; + +static struct pid_list *pid_ll = (struct pid_list *) NULL; + +/* The ll_*() functions all make use of the global var `pid_ll'. */ + +void +ll_insert (HFILE key, ULONG val) +{ + struct pid_list *new; + new = (struct pid_list *) malloc (sizeof (*new)); + + new->pid = key; + new->term_code = val; + new->next = pid_ll; + + pid_ll = new; +} + + +void +ll_delete (int key) +{ + struct pid_list *this, *last; + + this = pid_ll; + last = (struct pid_list *) NULL; + + while (this) + { + if (this->pid == key) + { + /* Delete this node and leave. */ + if (last) + last->next = this->next; + else + pid_ll = this->next; + free (this); + return; + } + + /* Else no match, so try the next one. */ + last = this; + this = this->next; + } +} + +ULONG +ll_lookup (HFILE key) +{ + struct pid_list *this = pid_ll; + + while (this) + { + if (this->pid == key) + return this->term_code; + + /* Else no match, so try the next one. */ + this = this->next; + } + + /* Zero is special in this context anyway. */ + return 0; +} + +#if DIAGNOSTIC +ULONG +ll_length () +{ + struct pid_list *this = pid_ll; + unsigned long int len; + + for (len = 0; this; len++) + this = this->next; + + return len; +} + +ULONG +ll_print () +{ + struct pid_list *this = pid_ll; + unsigned long int i; + + for (i = 0; this; i++) + { + printf ("pid_ll[%d] == (%5d --> %5d)\n", + i, this->pid, this->term_code); + this = this->next; + } + + if (i == 0) + printf ("No entries.\n"); + + return i; +} +#endif /* DIAGNOSTIC */ + +/* ********************************************************************* * + * * + * End of linked-list library, beginning of popen/pclose: * + * * + * ********************************************************************* */ + +/* + * Routine: popen + * Returns: FILE pointer to pipe. + * Action : Exec program connected via pipe, connect a FILE * to the + * pipe and return it. + * Params : Command - Program to run + * Mode - Mode to open pipe. "r" implies pipe is connected + * to the programs stdout, "w" connects to stdin. + */ +FILE * +popen (const char *Command, const char *Mode) +{ + HFILE End1, End2, Std, Old1, Old2, Tmp; + + FILE *File; + + char Fail[256], + *Args, + CmdLine[256], + *CmdExe; + + RESULTCODES + Result; + + int Rc; + + if (DosCreatePipe (&End1, &End2, 4096)) + return NULL; + + Std = (*Mode == 'w') ? STDIN : STDOUT ; + if (Std == STDIN) + { + Tmp = End1; End1 = End2; End2 = Tmp; + } + + Old1 = -1; /* save stdin or stdout */ + DosDupHandle (Std, &Old1); + DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT); + Tmp = Std; /* redirect stdin or stdout */ + DosDupHandle (End2, &Tmp); + + if (Std == 1) + { + Old2 = -1; /* save stderr */ + DosDupHandle (STDERR, &Old2); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + Tmp = STDERR; + DosDupHandle (End2, &Tmp); + } + + DosClose (End2); + DosSetFHState (End1, OPEN_FLAGS_NOINHERIT); + + if ((CmdExe = getenv ("COMSPEC")) == NULL ) + CmdExe = "cmd.exe"; + + strcpy (CmdLine, CmdExe); + Args = CmdLine + strlen (CmdLine) + 1; /* skip zero */ + strcpy (Args, "/c "); + strcat (Args, Command); + Args[strlen (Args) + 1] = '\0'; /* two zeroes */ + Rc = DosExecPgm (Fail, sizeof (Fail), EXEC_ASYNCRESULT, + (unsigned char *) CmdLine, 0, &Result, + (unsigned char *) CmdExe); + + Tmp = Std; /* restore stdin or stdout */ + DosDupHandle (Old1, &Tmp); + DosClose (Old1); + + if (Std == STDOUT) + { + Tmp = STDERR; /* restore stderr */ + DosDupHandle (Old2, &Tmp); + DosClose (Old2); + } + + if (Rc) + { + DosClose (End1); + return NULL; + } + + File = fdopen (End1, Mode); + ll_insert ((LL_KEY) End1, (LL_VAL) Result.codeTerminate); + + return File; +} + + +/* + * Routine: popenRW + * Returns: PID of child process + * Action : Exec program connected via pipe, connect int fd's to + * both the stdin and stdout of the process. + * Params : Command - Program to run + * Pipes - Array of 2 ints to store the pipe descriptors + * Pipe[0] writes to child's stdin, + * Pipe[1] reads from child's stdout/stderr + */ +int +popenRW (const char **argv, int *pipes) +{ + HFILE Out1, Out2, In1, In2; + HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp; + + PID pid; + + if (DosCreatePipe (&Out2, &Out1, 4096)) + return FALSE; + + if (DosCreatePipe (&In1, &In2, 4096)) + { + DosClose (Out1); + DosClose (Out2); + return FALSE; + } + + /* Save std{in,out,err} */ + DosDupHandle (STDIN, &Old0); + DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT); + DosDupHandle (STDOUT, &Old1); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + DosDupHandle (STDERR, &Old2); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + + /* Redirect std{in,out,err} */ + Tmp = STDIN; + DosDupHandle (In1, &Tmp); + Tmp = STDOUT; + DosDupHandle (Out1, &Tmp); + Tmp = STDERR; + DosDupHandle (Out1, &Tmp); + + /* Close file handles not needed in child */ + + DosClose (In1); + DosClose (Out1); + DosSetFHState (In2, OPEN_FLAGS_NOINHERIT); + DosSetFHState (Out2, OPEN_FLAGS_NOINHERIT); + + /* Spawn we now our hoary brood. */ + pid = spawnvp (P_NOWAIT, argv[0], argv); + + /* Restore std{in,out,err} */ + Tmp = STDIN; + DosDupHandle (Old0, &Tmp); + DosClose (Old0); + Tmp = STDOUT; + DosDupHandle (Old1, &Tmp); + DosClose (Old1); + Tmp = STDERR; + DosDupHandle (Old2, &Tmp); + DosClose (Old2); + + if(pid < 0) + { + DosClose (In2); + DosClose (Out2); + return -1; + } + + pipes[0] = In2; + _setmode (pipes[0], O_BINARY); + pipes[1] = Out2; + _setmode (pipes[1], O_BINARY); + + /* Save ID of write-to-child pipe for pclose() */ + ll_insert ((LL_KEY) In2, (LL_VAL) pid); + + return pid; +} + + +/* + * Routine: pclose + * Returns: TRUE on success + * Action : Close a pipe opened with popen(); + * Params : Pipe - pipe to close + */ +int +pclose (FILE *Pipe) +{ + RESULTCODES rc; + PID pid, pid1; + int Handle = fileno (Pipe); + + fclose (Pipe); + + rc.codeTerminate = -1; + + pid1 = (PID) ll_lookup ((LL_KEY) Handle); + /* if pid1 is zero, something's seriously wrong */ + if (pid1 != 0) + { + DosWaitChild (DCWA_PROCESSTREE, DCWW_WAIT, &rc, &pid, pid1); + ll_delete ((LL_KEY) Handle); + } + return rc.codeTerminate == 0 ? rc.codeResult : -1; +} + + +#if DIAGNOSTIC +void +main () +{ + FILE *fp1, *fp2, *fp3; + int c; + + ll_print (); + fp1 = popen ("gcc --version", "r"); + ll_print (); + fp2 = popen ("link386 /?", "r"); + ll_print (); + fp3 = popen ("dir", "r"); + ll_print (); + + while ((c = getc (fp1)) != EOF) + printf ("%c", c); + + while ((c = getc (fp2)) != EOF) + printf ("%c", c); + + while ((c = getc (fp3)) != EOF) + printf ("%c", c); + + pclose (fp1); + ll_print (); + pclose (fp2); + ll_print (); + pclose (fp3); + ll_print (); + + return; +} + +#endif /* DIAGNOSTIC */ diff --git a/gnu/usr.bin/cvs/os2/popen.h b/gnu/usr.bin/cvs/os2/popen.h new file mode 100644 index 00000000000..8daf29eaef0 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/popen.h @@ -0,0 +1,6 @@ +/* We roll our own popen()/pclose() in OS/2. + Thanks, Glenn Gribble! */ + +FILE *popen (char *cmd, char *mode); +int popenRW (char **cmd, int *pipes); +int pclose (FILE *stream); diff --git a/gnu/usr.bin/cvs/os2/porttcp.c b/gnu/usr.bin/cvs/os2/porttcp.c new file mode 100644 index 00000000000..a64b511f82d --- /dev/null +++ b/gnu/usr.bin/cvs/os2/porttcp.c @@ -0,0 +1,227 @@ +/**************************************************************** +** +** PORTTCP.C - Support for portable TCP/IP +** +****************************************************************/ + +#define TCPIP_IBM_NOHIDE +#include +#include "tcpip.h" + +/* + * Common unknown error buffer + */ +static char ErrUnknownBuf[36]; + +#ifndef SockStrError + +/**************************************************************** + * Routine: SockStrError + * Returns: Pointer to static buffer + * Action : Convert SOCK_ERRNO into error text + ****************************************************************/ + +const char * +SockStrError(int SockErrno) +{ +#if defined (TCPIP_IBM) && defined (IBM_CPP) + switch (SockErrno) + { + case SOCEPERM: return "Not owner"; + case SOCESRCH: return "No such process"; + case SOCEINTR: return "Interrupted system call"; + case SOCENXIO: return "No such device or address"; + case SOCEBADF: return "Bad file number"; + case SOCEACCES: return "Permission denied"; + case SOCEFAULT: return "Bad address"; + case SOCEINVAL: return "Invalid argument"; + case SOCEMFILE: return "Too many open files"; + case SOCEPIPE: return "Broken pipe"; + case SOCEOS2ERR: return "OS/2 Error"; + case SOCEWOULDBLOCK: return "Operation would block"; + case SOCEINPROGRESS: return "Operation now in progress"; + case SOCEALREADY: return "Operation already in progress"; + case SOCENOTSOCK: return "Socket operation on non-socket"; + case SOCEDESTADDRREQ: return "Destination address required"; + case SOCEMSGSIZE: return "Message too long"; + case SOCEPROTOTYPE: return "Protocol wrong type for socket"; + case SOCENOPROTOOPT: return "Protocol not available"; + case SOCEPROTONOSUPPORT: return "Protocol not supported"; + case SOCESOCKTNOSUPPORT: return "Socket type not supported"; + case SOCEOPNOTSUPP: return "Operation not supported on socket"; + case SOCEPFNOSUPPORT: return "Protocol family not supported"; + case SOCEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case SOCEADDRINUSE: return "Address already in use"; + case SOCEADDRNOTAVAIL: return "Can't assign requested address"; + case SOCENETDOWN: return "Network is down"; + case SOCENETUNREACH: return "Network is unreachable"; + case SOCENETRESET: return "Network dropped connection on reset"; + case SOCECONNABORTED: return "Software caused connection abort"; + case SOCECONNRESET: return "Connection reset by peer"; + case SOCENOBUFS: return "No buffer space available"; + case SOCEISCONN: return "Socket is already connected"; + case SOCENOTCONN: return "Socket is not connected"; + case SOCESHUTDOWN: return "Can't send after socket shutdown"; + case SOCETOOMANYREFS: return "Too many references: can't splice"; + case SOCETIMEDOUT: return "Connection timed out"; + case SOCECONNREFUSED: return "Connection refused"; + case SOCELOOP: return "Too many levels of symbolic links"; + case SOCENAMETOOLONG: return "File name too long"; + case SOCEHOSTDOWN: return "Host is down"; + case SOCEHOSTUNREACH: return "No route to host"; + case SOCENOTEMPTY: return "Directory not empty"; + + default: + sprintf( ErrUnknownBuf, "SockStrErrno( %d ) unknown", SockErrno ); + return ErrUnknownBuf; + } +#else +#error SockStrError not supported for this OS +#endif +} + +#endif /* SockStrError */ + + +/**************************************************************** + * Routine: HostStrError + * Returns: Pointer to static buffer + * Action : Convert HOST_ERRNO into error text + ****************************************************************/ + +const char * +HostStrError(int HostErrno) +{ + switch (HostErrno) + { + case HOST_NOT_FOUND: + return "Host not found"; + case TRY_AGAIN: + return "Host not found (suggest try again)"; + case NO_RECOVERY: + return "Non-recoverable error: FORMERR, REFUSED, NOTIMP"; + case NO_DATA: + return "No Data (valid name, but no record of requested type)"; + + default: + sprintf( ErrUnknownBuf, "HostStrErrno( %d ) unknown", HostErrno ); + return ErrUnknownBuf; + } +} + + +#if defined( TCPIP_IBM ) +/**************************************************************** + * Routine: IbmSockSend + * Returns: same as send + * Action : Do the right thing for IBM TCP/IP which includes + * the following two stupidities: + * 1) Never try to send more than 32K + * 2) Never pass a buffer that crosses a 64K boundary + * If Flags is non-zero, this function only attempts + * to deal with condition (1) above. + ****************************************************************/ + +int +IbmSockSend (int Socket, const void *Buffer, int Len, int Flags) +{ + int Sent, ToSend, TotalSent = 0; + + const char *Tmp = Buffer; + + /* + * If Flags have been passed in, the 64K boundary optimization + * can not be performed. For example, MSG_PEEK would not work + * correctly. + */ + if (Flags) + return send (Socket, (char *) Buffer, min (0x7FFF, Len), Flags); + + do + { + /* Never send across a 64K boundary */ + ToSend = min (Len, (int) (0x10000 - (0xFFFF & (long) Tmp))); + + /* Never send more than 32K */ + if (ToSend > 0x7FFF) + ToSend = 0x7FFF; + + Sent = send (Socket, (char *) Tmp, ToSend, 0); + if (Sent < 0) + { + if ((TotalSent > 0) && (SOCK_ERRNO == EWOULDBLOCK)) + return TotalSent; + if (SOCK_ERRNO == EINTR) + continue; + return Sent; + } + if (Sent < ToSend) + return TotalSent + Sent; + + Tmp += Sent; + TotalSent += Sent; + Len -= Sent; + } while (Len > 0); + + return TotalSent; +} + + + +/**************************************************************** + * Routine: IbmSockRecv + * Returns: same as recv + * Action : Do the right thing for IBM TCP/IP which includes + * the following two stupidities: + * 1) Never try to recv more than 32K + * 2) Never pass a buffer that crosses a 64K boundary + * If Flags is non-zero, this function only attempts + * to deal with condition (1) above. + ****************************************************************/ + +int +IbmSockRecv (int Socket, const void *Buffer, int Len, int Flags) +{ + int Recvd, ToRecv, TotalRecvd = 0; + + char *Tmp = Buffer; + + /* If Flags have been passed in, the 64K boundary optimization + probably can not be performed. */ + + if (Flags) + return recv (Socket, Buffer, min (0x7FFF, Len), Flags); + + do + { + /* Never send across a 64K boundary */ + ToRecv = min( Len, (int)( 0x10000 - ( 0xFFFF & (long)Tmp ))); + + /* Never send more than 32K */ + if( ToRecv > 0x7FFF ) + ToRecv = 0x7FFF; + + Recvd = recv (Socket, Tmp, ToRecv, 0); + if (Recvd <= 0) + { + if ((TotalRecvd > 0) + && (Recvd == 0 || (SOCK_ERRNO == EWOULDBLOCK ))) + return TotalRecvd; + if (SOCK_ERRNO == EINTR) + continue; + + return Recvd; + } + if (Recvd < ToRecv) + return TotalRecvd + Recvd; + + Tmp += Recvd; + TotalRecvd += Recvd; + Len -= Recvd; + } while (Len > 0); + + return TotalRecvd; +} +#endif /* defined( TCPIP_IBM ) */ + diff --git a/gnu/usr.bin/cvs/os2/pwd.c b/gnu/usr.bin/cvs/os2/pwd.c new file mode 100644 index 00000000000..1cdf16c799d --- /dev/null +++ b/gnu/usr.bin/cvs/os2/pwd.c @@ -0,0 +1,205 @@ +/* pwd.c - Try to approximate UN*X's getuser...() functions under MS-DOS. + Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Header: /home/cvs/src/gnu/usr.bin/cvs/os2/pwd.c,v 1.1.1.1 1996/01/30 00:19:38 tholo Exp $ +*/ + +/* This 'implementation' is conjectured from the use of this functions in + the RCS and BASH distributions. Of course these functions don't do too + much useful things under MS-DOS, but using them avoids many "#ifdef + MSDOS" in ported UN*X code ... */ + + +#include +#include +#include +#include + +static char *lookup_env (char **); + +/* where people might scribble their name into the environment ... */ + +static char *login_strings[] = +{ + "LOGIN", "USER", "MAILNAME", (char *) 0 +}; + +static char *group_strings[] = +{ + "GROUP", (char *) 0 +}; + + +static char *anonymous = "anonymous"; /* if all else fails ... */ + +static char *home_dir = "."; /* we feel (no|every)where at home */ +static char *login_shell = "not cmd.exe!"; + +static char *login = (char *) 0;/* cache the names here */ +static char *group = (char *) 0; + +static struct passwd pw; /* should we return a malloc()'d structure */ +static struct group gr; /* instead of pointers to static structures? */ + +/* return something like a username in a (butchered!) passwd structure. */ +struct passwd * +getpwuid (int uid) +{ + pw.pw_name = getlogin (); + pw.pw_dir = home_dir; + pw.pw_shell = login_shell; + pw.pw_uid = 0; + + return &pw; +} + +struct passwd * +getpwnam (char *name) +{ + return (struct passwd *) 0; +} + +/* return something like a groupname in a (butchered!) group structure. */ +struct group * +getgrgid (int uid) +{ + gr.gr_name = getgr_name (); + gr.gr_gid = 0; + + return &gr; +} + +struct group * +getgrnam (char *name) +{ + return (struct group *) 0; +} + +/* return something like a username. */ +char * +getlogin () +{ + if (!login) /* have we been called before? */ + login = lookup_env (login_strings); + + if (!login) /* have we been successful? */ + login = anonymous; + + return login; +} + +/* return something like a group. */ +char * +getgr_name () +{ + if (!group) /* have we been called before? */ + group = lookup_env (group_strings); + + if (!group) /* have we been successful? */ + group = anonymous; + + return group; +} + +/* return something like a uid. */ +int +getuid () +{ + return 0; /* every user is a super user ... */ +} + +int +getgid () +{ + return 0; +} + +int +geteuid () +{ + return 0; +} + +int +getegid () +{ + return 0; +} + +struct passwd * +getpwent () +{ + return (struct passwd *) 0; +} + +void +setpwent () +{ +} + +void +endpwent () +{ +} + +void +endgrent () +{ +} + +/* return groups. */ +int +getgroups (int ngroups, int *groups) +{ + *groups = 0; + return 1; +} + +/* lookup environment. */ +static char * +lookup_env (char *table[]) +{ + char *ptr; + char *entry; + size_t len; + + while (*table && !(ptr = getenv (*table++))) ; /* scan table */ + + if (!ptr) + return (char *) 0; + + len = strcspn (ptr, " \n\t\n\r"); /* any WS? */ + if (!(entry = malloc (len + 1))) + { + fprintf (stderr, "Out of memory.\nStop."); + exit (-1); + } + + strncpy (entry, ptr, len); + entry[len] = '\0'; + + return entry; + +} + +/* + * Local Variables: + * mode:C + * ChangeLog:ChangeLog + * compile-command:make + * End: + */ diff --git a/gnu/usr.bin/cvs/os2/pwd.h b/gnu/usr.bin/cvs/os2/pwd.h new file mode 100644 index 00000000000..c3e22cab328 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/pwd.h @@ -0,0 +1,77 @@ +/* pwd.h - Try to approximate UN*X's getuser...() functions under MS-DOS. + Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Header: /home/cvs/src/gnu/usr.bin/cvs/os2/pwd.h,v 1.1.1.1 1996/01/30 00:19:37 tholo Exp $ +*/ + +/* This 'implementation' is conjectured from the use of this functions in + the RCS and BASH distributions. Of course these functions don't do too + much useful things under MS-DOS, but using them avoids many "#ifdef + MSDOS" in ported UN*X code ... */ + +#if 0 +/* This is taken care of in Windows-NT/config.h. */ +typedef int uid_t; +#endif + +struct passwd +{ + /* ... */ + /* missing stuff */ + /* ... */ + char *pw_name; /* login user id */ + char *pw_dir; /* home directory */ + char *pw_shell; /* login shell */ + int pw_uid; +}; + +struct group +{ + /* ... */ + /* missing stuff */ + /* ... */ + char *gr_name; /* login user id */ + int gr_gid; +}; + +extern struct passwd *getpwuid (int); +extern struct passwd *getpwnam (char *); +extern struct group *getgrgid (int); +extern struct group *getgrnam (char *); +extern char *getlogin (void); +extern char *getgr_name (void); +extern int getuid (void); +extern int getgid (void); +extern int geteuid (void); +extern int getegid (void); + +extern int *groups; +extern int ngroups; +extern int getgroups (int, int *); + +extern struct passwd *getpwent (void); +extern void setpwent (void); +extern void endpwent (void); +extern void endgrent (void); + +/* + * Local Variables: + * mode:C + * ChangeLog:ChangeLog + * compile-command:make + * End: + */ diff --git a/gnu/usr.bin/cvs/os2/rcmd.c b/gnu/usr.bin/cvs/os2/rcmd.c new file mode 100644 index 00000000000..36b17516dd5 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/rcmd.c @@ -0,0 +1,66 @@ +/* rcmd.c --- execute a command on a remote host from OS/2 + Karl Fogel --- November 1995 */ + +#include +#include +#include +#include +#include +/* wants `off_t': */ +#include +/* This should get us ibmtcpip\include\sys\socket.h: */ +#include +#include + +#include "rcmd.h" + +void +init_sockets () +{ + int rc; + + rc = sock_init (); + if (rc != 0) + { + fprintf (stderr, "sock_init() failed -- returned %d!\n", rc); + exit (1); + } +} + + +static int +resolve_address (const char **ahost, struct sockaddr_in *sai) +{ + fprintf (stderr, + "Error: resolve_address() doesn't work.\n"); + exit (1); +} + +static int +bind_and_connect (struct sockaddr_in *server_sai) +{ + fprintf (stderr, + "Error: bind_and_connect() doesn't work.\n"); + exit (1); +} + +static int +rcmd_authenticate (int fd, char *locuser, char *remuser, char *command) +{ + fprintf (stderr, + "Error: rcmd_authenticate() doesn't work.\n"); + exit (1); +} + +int +rcmd (const char **ahost, + unsigned short inport, + char *locuser, + char *remuser, + char *cmd, + int *fd2p) +{ + fprintf (stderr, + "Error: rcmd() doesn't work.\n"); + exit (1); +} diff --git a/gnu/usr.bin/cvs/os2/rcmd.h b/gnu/usr.bin/cvs/os2/rcmd.h new file mode 100644 index 00000000000..2bc915a36bd --- /dev/null +++ b/gnu/usr.bin/cvs/os2/rcmd.h @@ -0,0 +1,30 @@ +/* rcmd.h --- interface to executing commands on remote hosts + Karl Fogel --- November 1995 */ + +/* Run the command CMD on the host *AHOST, and return a file descriptor for + a bidirectional stream socket connected to the command's standard input + and output. + + rcmd looks up *AHOST using gethostbyname, and sets *AHOST to the host's + canonical name. If *AHOST is not found, rcmd returns -1. + + rcmd connects to the remote host at TCP port INPORT. This should + probably be the "shell" service, port 514. + + LOCUSER is the name of the user on the local machine, and REMUSER is + the name of the user on the remote machine; the remote machine uses this, + along with the source address of the TCP connection, to authenticate + the connection. + + CMD is the command to execute. The remote host will tokenize it any way + it damn well pleases. Welcome to Unix. + + FD2P is a feature we don't support, but there's no point in making mindless + deviations from the interface. Callers should always pass this argument + as zero. */ +extern int rcmd (const char **AHOST, + unsigned short INPORT, + char *LOCUSER, + char *REMUSER, + char *CMD, + int *fd2p); diff --git a/gnu/usr.bin/cvs/os2/run.c b/gnu/usr.bin/cvs/os2/run.c new file mode 100644 index 00000000000..358812b3a1f --- /dev/null +++ b/gnu/usr.bin/cvs/os2/run.c @@ -0,0 +1,602 @@ +/* run.c --- routines for executing subprocesses under OS/2. + + This file is part of GNU CVS. + + GNU CVS is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "cvs.h" + +#define INCL_DOSQUEUES +#define INCL_DOSPROCESS +#define INCL_DOSSESMGR +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +static void run_add_arg PROTO((const char *s)); +static void run_init_prog PROTO((void)); + +extern char *strtok (); + +/* + * To exec a program under CVS, first call run_setup() to setup any initial + * arguments. The options to run_setup are essentially like printf(). The + * arguments will be parsed into whitespace separated words and added to the + * global run_argv list. + * + * Then, optionally call run_arg() for each additional argument that you'd like + * to pass to the executed program. + * + * Finally, call run_exec() to execute the program with the specified + * arguments. + * The execvp() syscall will be used, so that the PATH is searched correctly. + * File redirections can be performed in the call to run_exec(). + */ +static char *run_prog; +static char **run_argv; +static int run_argc; +static int run_argc_allocated; + +void +run_setup (const char *fmt,...) +{ + va_list args; + char *cp; + int i; + + run_init_prog (); + + /* clean out any malloc'ed values from run_argv */ + for (i = 0; i < run_argc; i++) + { + if (run_argv[i]) + { + free (run_argv[i]); + run_argv[i] = (char *) 0; + } + } + run_argc = 0; + + /* process the varargs into run_prog */ + va_start (args, fmt); + (void) vsprintf (run_prog, fmt, args); + va_end (args); + + /* put each word into run_argv, allocating it as we go */ + for (cp = strtok (run_prog, " \t"); cp; cp = strtok ((char *) NULL, " \t")) + run_add_arg (cp); +} + +void +run_arg (s) + const char *s; +{ + run_add_arg (s); +} + +void +run_args (const char *fmt,...) +{ + va_list args; + + run_init_prog (); + + /* process the varargs into run_prog */ + va_start (args, fmt); + (void) vsprintf (run_prog, fmt, args); + va_end (args); + + /* and add the (single) argument to the run_argv list */ + run_add_arg (run_prog); +} + +/* Return a malloc'd copy of s, with double quotes around it. */ +static char * +quote (const char *s) +{ + size_t s_len = strlen (s); + char *copy = xmalloc (s_len + 3); + char *scan = copy; + + *scan++ = '"'; + strcpy (scan, s); + scan += s_len; + *scan++ = '"'; + *scan++ = '\0'; + + return copy; +} + +static void +run_add_arg (s) + const char *s; +{ + /* allocate more argv entries if we've run out */ + if (run_argc >= run_argc_allocated) + { + run_argc_allocated += 50; + run_argv = (char **) xrealloc ((char *) run_argv, + run_argc_allocated * sizeof (char **)); + } + + if (s) + { + run_argv[run_argc] = (run_argc ? quote (s) : xstrdup (s)); + run_argc++; + } + else + /* not post-incremented on purpose! */ + run_argv[run_argc] = (char *) 0; +} + +static void +run_init_prog () +{ + /* make sure that run_prog is allocated once */ + if (run_prog == (char *) 0) + run_prog = xmalloc (10 * 1024); /* 10K of args for _setup and _arg */ +} + + +int +run_exec (stin, stout, sterr, flags) + char *stin; + char *stout; + char *sterr; + int flags; +{ + int shin, shout, sherr; + int sain, saout, saerr; /* saved handles */ + int mode_out, mode_err; + int status = -1; + int rerrno = 0; + int rval = -1; + void (*old_sigint) (int); + + if (trace) /* if in trace mode */ + { + (void) fprintf (stderr, "-> system("); + run_print (stderr); + (void) fprintf (stderr, ")\n"); + } + if (noexec && (flags & RUN_REALLY) == 0) /* if in noexec mode */ + return (0); + + /* + * start the engine and take off + */ + + /* make sure that we are null terminated, since we didn't calloc */ + run_add_arg ((char *) 0); + + /* setup default file descriptor numbers */ + shin = 0; + shout = 1; + sherr = 2; + + /* set the file modes for stdout and stderr */ + mode_out = mode_err = O_WRONLY | O_CREAT; + mode_out |= ((flags & RUN_STDOUT_APPEND) ? O_APPEND : O_TRUNC); + mode_err |= ((flags & RUN_STDERR_APPEND) ? O_APPEND : O_TRUNC); + + /* open the files as required, shXX are shadows of stdin... */ + if (stin && (shin = open (stin, O_RDONLY)) == -1) + { + rerrno = errno; + error (0, errno, "cannot open %s for reading (prog %s)", + stin, run_argv[0]); + goto out0; + } + if (stout && (shout = open (stout, mode_out, 0666)) == -1) + { + rerrno = errno; + error (0, errno, "cannot open %s for writing (prog %s)", + stout, run_argv[0]); + goto out1; + } + if (sterr && (flags & RUN_COMBINED) == 0) + { + if ((sherr = open (sterr, mode_err, 0666)) == -1) + { + rerrno = errno; + error (0, errno, "cannot open %s for writing (prog %s)", + sterr, run_argv[0]); + goto out2; + } + } + /* now save the standard handles */ + sain = saout = saerr = -1; + sain = dup( 0); /* dup stdin */ + saout = dup( 1); /* dup stdout */ + saerr = dup( 2); /* dup stderr */ + + /* the new handles will be dup'd to the standard handles + * for the spawn. + */ + + if (shin != 0) + { + (void) dup2 (shin, 0); + (void) close (shin); + } + if (shout != 1) + { + (void) dup2 (shout, 1); + (void) close (shout); + } + if (flags & RUN_COMBINED) + (void) dup2 (1, 2); + else if (sherr != 2) + { + (void) dup2 (sherr, 2); + (void) close (sherr); + } + + /* Ignore signals while we're running this. */ + old_sigint = signal (SIGINT, SIG_IGN); + + /* dup'ing is done. try to run it now */ + rval = spawnvp ( P_WAIT, run_argv[0], run_argv); + + /* Restore signal handling. */ + signal (SIGINT, old_sigint); + + /* restore the original file handles */ + if (sain != -1) { + (void) dup2( sain, 0); /* re-connect stdin */ + (void) close( sain); + } + if (saout != -1) { + (void) dup2( saout, 1); /* re-connect stdout */ + (void) close( saout); + } + if (saerr != -1) { + (void) dup2( saerr, 2); /* re-connect stderr */ + (void) close( saerr); + } + + /* Recognize the return code for a failed subprocess. */ + if (rval == -1) + return 2; + else + return rval; /* return child's exit status */ + + /* error cases */ + /* cleanup the open file descriptors */ + out2: + if (stout) + (void) close (shout); + out1: + if (stin) + (void) close (shin); + + out0: + if (rerrno) + errno = rerrno; + return (status); +} + + +void +run_print (fp) + FILE *fp; +{ + int i; + + for (i = 0; i < run_argc; i++) + { + (void) fprintf (fp, "'%s'", run_argv[i]); + if (i != run_argc - 1) + (void) fprintf (fp, " "); + } +} + +static char * +requote (const char *cmd) +{ + char *requoted = xmalloc (strlen (cmd) + 1); + char *p = requoted; + + strcpy (requoted, cmd); + while ((p = strchr (p, '\'')) != NULL) + { + *p++ = '"'; + } + + return requoted; +} + +FILE * +Popen (cmd, mode) + const char *cmd; + const char *mode; +{ + if (trace) +#ifdef SERVER_SUPPORT + (void) fprintf (stderr, "%c-> Popen(%s,%s)\n", + (server_active) ? 'S' : ' ', cmd, mode); +#else + (void) fprintf (stderr, "-> Popen(%s,%s)\n", cmd, mode); +#endif + + if (noexec) + return (NULL); + + /* If the command string uses single quotes, turn them into + double quotes. */ + { + char *requoted = requote (cmd); + FILE *result = popen (requoted, mode); + free (requoted); + return result; + } +} + + +/* Running children with pipes connected to them. */ + +/* Create a pipe. Set READWRITE[0] to its reading end, and + READWRITE[1] to its writing end. */ + +static int +my_pipe (int *readwrite) +{ + fprintf (stderr, + "Error: my_pipe() is unimplemented.\n"); + exit (1); +} + + +/* Create a child process running COMMAND with IN as its standard input, + and OUT as its standard output. Return a handle to the child, or + INVALID_HANDLE_VALUE. */ +static int +start_child (char *command, int in, int out) +{ + fprintf (stderr, + "Error: start_child() is unimplemented.\n"); + exit (1); +} + + +/* Given an array of arguments that one might pass to spawnv, + construct a command line that one might pass to CreateProcess. + Try to quote things appropriately. */ +static char * +build_command (char **argv) +{ + int len; + + /* Compute the total length the command will have. */ + { + int i; + + len = 0; + for (i = 0; argv[i]; i++) + { + char *p; + + len += 2; /* for the double quotes */ + + for (p = argv[i]; *p; p++) + { + if (*p == '"') + len += 2; + else + len++; + } + } + len++; /* for the space or the '\0' */ + } + + { + char *command = (char *) malloc (len); + int i; + char *p; + + if (! command) + { + errno = ENOMEM; + return command; + } + + p = command; + /* copy each element of argv to command, putting each command + in double quotes, and backslashing any quotes that appear + within an argument. */ + for (i = 0; argv[i]; i++) + { + char *a; + *p++ = '"'; + for (a = argv[i]; *a; a++) + { + if (*a == '"') + *p++ = '\\', *p++ = '"'; + else + *p++ = *a; + } + *p++ = '"'; + *p++ = ' '; + } + p[-1] = '\0'; + + return command; + } +} + + +/* Create an asynchronous child process executing ARGV, + with its standard input and output connected to the + parent with pipes. Set *TO to the file descriptor on + which one writes data for the child; set *FROM to + the file descriptor from which one reads data from the child. + Return the handle of the child process (this is what + _cwait and waitpid expect). */ +int +piped_child (char **argv, int *to, int *from) +{ + fprintf (stderr, + "Error: piped_child() is unimplemented.\n"); + exit (1); +} + +/* + * dir = 0 : main proc writes to new proc, which writes to oldfd + * dir = 1 : main proc reads from new proc, which reads from oldfd + * + * If this returns at all, then it was successful and the return value + * is a file descriptor; else it errors and exits. + */ +int +filter_stream_through_program (int oldfd, int dir, + char **prog, int *pidp) +{ + int newfd; /* Gets set to one end of the pipe and returned. */ + HFILE from, to; + HFILE Old0 = -1, Old1 = -1, Old2 = -1, Tmp; + + if (DosCreatePipe (&from, &to, 4096)) + return FALSE; + + /* Save std{in,out,err} */ + DosDupHandle (STDIN, &Old0); + DosSetFHState (Old1, OPEN_FLAGS_NOINHERIT); + DosDupHandle (STDOUT, &Old1); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + DosDupHandle (STDERR, &Old2); + DosSetFHState (Old2, OPEN_FLAGS_NOINHERIT); + + /* Redirect std{in,out,err} */ + if (dir) /* Who goes where? */ + { + Tmp = STDIN; + DosDupHandle (oldfd, &Tmp); + Tmp = STDOUT; + DosDupHandle (to, &Tmp); + Tmp = STDERR; + DosDupHandle (to, &Tmp); + + newfd = from; + _setmode (newfd, O_BINARY); + + DosClose (oldfd); + DosClose (to); + DosSetFHState (from, OPEN_FLAGS_NOINHERIT); + } + else + { + Tmp = STDIN; + DosDupHandle (from, &Tmp); + Tmp = STDOUT; + DosDupHandle (oldfd, &Tmp); + Tmp = STDERR; + DosDupHandle (oldfd, &Tmp); + + newfd = to; + _setmode (newfd, O_BINARY); + + DosClose (oldfd); + DosClose (from); + DosSetFHState (to, OPEN_FLAGS_NOINHERIT); + } + + /* Spawn we now our hoary brood. */ + *pidp = spawnvp (P_NOWAIT, prog[0], prog); + + /* Restore std{in,out,err} */ + Tmp = STDIN; + DosDupHandle (Old0, &Tmp); + DosClose (Old0); + Tmp = STDOUT; + DosDupHandle (Old1, &Tmp); + DosClose (Old1); + Tmp = STDERR; + DosDupHandle (Old2, &Tmp); + DosClose (Old2); + + if(*pidp < 0) + { + DosClose (from); + DosClose (to); + error (1, 0, "error spawning %s", prog[0]); + } + + return newfd; +} + + +int +pipe (int *filedesc) +{ + /* todo: actually, we can use DosCreatePipe(). Fix this. */ + fprintf (stderr, + "Error: pipe() should not have been called in client.\n"); + exit (1); +} + + +void +close_on_exec (int fd) +{ + /* Just does nothing for now... */ + + /* Actually, we probably *can* implement this one. Let's see... */ + /* Nope. OS/2 has , but no fcntl() ! Wow. */ + /* Well, I'll leave this stuff in for future reference. */ +} + + +/* Actually, we #define sleep() in config.h now. */ +#ifndef sleep +unsigned int +sleep (unsigned int seconds) +{ + /* I don't want to interfere with alarm signals, so I'm going to do + this the nasty way. */ + + time_t base; + time_t tick; + int i; + + /* Init. */ + time (&base); + time (&tick); + + /* Loop until time has passed. */ + while (difftime (tick, base) < seconds) + { + /* This might be more civilized than calling time over and over + again. */ + for (i = 0; i < 10000; i++) + ; + time (&tick); + } + + return 0; +} +#endif /* sleep */ diff --git a/gnu/usr.bin/cvs/os2/strippath.c b/gnu/usr.bin/cvs/os2/strippath.c new file mode 100644 index 00000000000..8a61a1ed393 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/strippath.c @@ -0,0 +1,60 @@ +/* strippath.c -- remove unnecessary components from a path specifier + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +static void remove_component(char *beginc, char *endc); +void strip_trailing_slashes(char *path); + +/* Remove unnecessary components from PATH. */ + +void +strip_path (path) + char *path; +{ + int stripped = 0; + char *cp, *slash; + + for (cp = path; *(slash = cp + strcspn (cp, "/\\")) != '\0'; cp = slash) + { + *slash = '\0'; + if ((!*cp && (cp != path || stripped)) || + strcmp(cp, ".") == 0 || strcmp(cp, "/") == 0) + { + stripped = 1; + remove_component(cp, slash); + slash = cp; + } + else + { + *slash++ = '/'; + } + } + strip_trailing_slashes(path); +} + +/* Remove the component delimited by BEGINC and ENDC from the path */ + +static void +remove_component (beginc, endc) + char *beginc; + char *endc; +{ + for (endc++; *endc; endc++) + *beginc++ = *endc; + *beginc = '\0'; +} diff --git a/gnu/usr.bin/cvs/os2/stripslash.c b/gnu/usr.bin/cvs/os2/stripslash.c new file mode 100644 index 00000000000..629dad9393d --- /dev/null +++ b/gnu/usr.bin/cvs/os2/stripslash.c @@ -0,0 +1,31 @@ +/* stripslash.c -- remove trailing slashes from a string + Copyright (C) 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +/* Remove trailing slashes from PATH. */ + +void +strip_trailing_slashes (path) + char *path; +{ + int last; + + last = strlen (path) - 1; + while (last > 0 && (path[last] == '/' || path[last] == '\\')) + path[last--] = '\0'; +} diff --git a/gnu/usr.bin/cvs/os2/tcpip.h b/gnu/usr.bin/cvs/os2/tcpip.h new file mode 100644 index 00000000000..4d19448650a --- /dev/null +++ b/gnu/usr.bin/cvs/os2/tcpip.h @@ -0,0 +1,107 @@ +/**************************************************************** + * + * TCPIP.H - Portable TCP/IP header file + * + * TCP/IP on OS/2 is an add-on and thus is not fully integrated + * with the operating system. To ensure portability, follow + * these rules: + * + * * Always call SockInit() at the beginning of your program + * and check that it returns TRUE. + * + * * Use SockSend() & SockRecv() instead of read(), write(), + * send(), or recv() when working with sockets. + * + * * Use SockClose() instead of close() with sockets. + * + * * Use SOCK_ERRNO when using functions that use or return + * sockets, such as SockSend() or accept(). + * + * * Use HOST_ERRNO when using gethostbyname() or gethostbyaddr() + * functions. + * + * * As far as I can tell, getservbyname() and related functions + * never set any error variable. + * + * * Use SockStrError() & HostStrError() to convert SOCK_ERRNO + * and HOST_ERRNO to error strings. + * + * * In .MAK files, include $(TCPIP_MAK) & use $(TCPIPLIB) + * when linking applications using TCP/IP. + * + ****************************************************************/ + +#if !defined( IN_TCPIP_H ) +#define IN_TCPIP_H + +#include +#include +#include +#include +#include +#include +#include + +#if defined( TCPIP_IBM ) +# include +# if !defined( TCPIP_IBM_NOHIDE ) +# define send IbmSockSend +# define recv IbmSockRecv +# endif +#endif + +#if defined( TCPIP_IBM ) +# define BSD_SELECT +# include +# include +# include +# include +# if defined( MICROSOFT ) +# define SOCK_ERRNO (tcperrno()) +# else +# define SOCK_ERRNO (sock_errno()) +# endif +# define HOST_ERRNO (h_errno) +# define SockClose(S) soclose(S) +# define SockInit() (!sock_init()) +# define SockSend IbmSockSend +# define SockRecv IbmSockRecv + +const char *HostStrError(int HostErrno); +const char *SockStrError(int SockErrno); + +int IbmSockSend (int Socket, const void *Buffer, int Len, int Flags); +int IbmSockRecv (int Socket, const void *Buffer, int Len, int Flags); + +#if !defined( h_errno ) +extern int h_errno; /* IBM forgot to declare this in current header files */ +#endif + +#elif defined( __unix ) +# if defined( sgi ) /* SGI incorrectly defines FD_ZERO in sys/select.h */ +# include +# endif +# if defined( sunos ) +extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +# else +# include +# endif +# include +# include +# include +# define SOCK_ERRNO errno +# define HOST_ERRNO h_errno +# define SockClose(S) close(S) +# define SockInit() TRUE +# define SockSend send +# define SockRecv recv +# define SockStrError(E) strerror(E) + +const char *HostStrError( int HostErrno ); + +#else +# error Undefined version of TCP/IP specified + +#endif + +#endif diff --git a/gnu/usr.bin/cvs/os2/test-makefile b/gnu/usr.bin/cvs/os2/test-makefile new file mode 100644 index 00000000000..d6179ee386e --- /dev/null +++ b/gnu/usr.bin/cvs/os2/test-makefile @@ -0,0 +1,40 @@ +# I use this for single compilation while porting; once the port is +# done it can be removed. + +THIS_BASENAME = ../src/add + +CC = icc + +LIB = s:\ibmcpp\lib;s:\toolkt21\os2lib; +CINC = -Is:/ibmcpp/include -Is:/toolkt21/c/os2h +CFLAGS = -C+ +CFLAGS += -W3 -Wpro+rea+tru+use+ -Ti+ -Ss+ -Gd+ -Gm+ -G4 -Q+ -Sm ${CINC} +CFLAGS += -DIBM_CPP -DHAVE_CONFIG_H + +# translation of most important CFLAGS -- others are trivial +# ICC sez -C+ -W3 -Ti+ ${CINC} +# GCC sez -c -Wall -g ${CINC} + +# "-I../os2" below ought to be equivalent to "-I." +CFLAGS += -I../os2 -I../lib -I../src + +# Preprocesses to stdout. +# CFLAGS += -Pd+ + +# TCP/IP stuff +TCPIPLIB = s:\ibmtcpip\lib\tcp32dll.lib s:\ibmtcpip\lib\so32dll.lib porttcp.obj + +# We probably don't need these. +# RPCLIB = s:\ibmtcpip\lib\rpc32dll.lib +# FTPLIB = s:\ibmtcpip\lib\ftpapi.lib + +CFLAGS += -DTCPIP_IBM -Is:\ibmtcpip\include + +all: ${THIS_BASENAME}.obj +# all: ${THIS_BASENAME}.exe + +${THIS_BASENAME}.obj: ${THIS_BASENAME}.c + ${CC} ${CFLAGS} /Fo${THIS_BASENAME}.obj ${THIS_BASENAME}.c + +${THIS_BASENAME}.exe: ${THIS_BASENAME}.c + ${CC} ${CFLAGS} /Fe${THIS_BASENAME}.exe ${THIS_BASENAME}.c diff --git a/gnu/usr.bin/cvs/os2/waitpid.c b/gnu/usr.bin/cvs/os2/waitpid.c new file mode 100644 index 00000000000..2b64f5dcce2 --- /dev/null +++ b/gnu/usr.bin/cvs/os2/waitpid.c @@ -0,0 +1,36 @@ +/* waitpid.c --- waiting for process termination, under OS/2 + Karl Fogel --- November 1995 */ + +#include +#include +#include +#include + +#include "config.h" + +/* Wait for the process PID to exit. Put the return status in *statusp. + OPTIONS is not supported yet under OS/2. We hope it's always zero. */ +pid_t waitpid (pid, statusp, options) + pid_t pid; + int *statusp; + int options; +{ + pid_t rc; + + /* We don't know how to deal with any options yet. */ + assert (options == 0); + + rc = _cwait (statusp, pid, WAIT_CHILD); + + if (rc == -1) + { + if (errno == ECHILD) + return pid; + else + return -1; + } + else if (rc == pid) + return pid; + else + return -1; +} diff --git a/gnu/usr.bin/cvs/src/.cvsignore b/gnu/usr.bin/cvs/src/.cvsignore new file mode 100644 index 00000000000..be8c63aa45b --- /dev/null +++ b/gnu/usr.bin/cvs/src/.cvsignore @@ -0,0 +1,10 @@ +.pure +Makefile +TAGS +check.log +check.plog +cvs +cvsbug +mkmodules +options.h +options.h-SAVED diff --git a/gnu/usr.bin/cvs/src/ChangeLog b/gnu/usr.bin/cvs/src/ChangeLog index 1937aef1d7b..5e731b5ab46 100644 --- a/gnu/usr.bin/cvs/src/ChangeLog +++ b/gnu/usr.bin/cvs/src/ChangeLog @@ -1,3 +1,1610 @@ +Sun Jan 28 09:45:53 1996 Jim Kingdon + + * edit.c, edit.h (mark_up_to_date): New function, to remove file + in CVS/Base. + * client.c (update_entries): Call it if file is up to date. + * checkin.c (Checkin): Call it in non-server (local) case. + * sanity.sh: New test 182.5, tests for above-fixed bug. + +Sun Jan 28 01:07:22 1996 Jim Kingdon (kingdon@beezley) + + * client.c (change_mode): Separate out CHMOD_BROKEN code to parse + mode_string, rather than going through a mode_t. Cleaner than + the previous CHMOD_BROKEN code (which also had a typo of && not &). + +Sat Jan 27 23:29:46 1996 Jim Kingdon (kingdon@beezley) + + * edit.c (edit_fileproc): Check for EACCESS as well as EEXIST. + +Sat Jan 27 16:26:30 1996 Karl Fogel (kfogel@floss.cyclic.com) + + * client.c (notified_a_file): use rename_file() instead of + rename() (but temporarily set `noexec' to 0 so it runs + unconditionally). + (change_mode): deal with CHMOD_BROKEN. + +Fri Jan 26 00:14:00 1996 Karl Fogel + + * server.c: renamed `dirname' to `dir_name', to avoid conflicts + with system headers. + + * client.c: renamed `dirname' and `last_dirname' to `dir_name' and + last_dir_name' (see above). Not strictly necessary, but + consistency is nice -- as long as you do it all the time. + +Thu Jan 25 00:41:59 1996 Karl Fogel + + * options.h.in (AUTH_SERVER_SUPPORT, AUTH_CLIENT_SUPPORT): change + comment now that no longer under construction. + +Wed Jan 24 15:25:22 1996 Jim Kingdon + + * Version 1.7.1. + + * Version 1.7. + +Sat Jan 20 00:05:08 1996 Jim Kingdon + + * Version 1.6.87. + +Mon Jan 15 18:14:55 1996 Gary Oberbrunner + and Jim Kingdon + + * tag.c (val_direntproc): New function to ignore + nonexistent dirs when recursing to check tag validity. + (tag_check_valid): Pass it to start_recursion. + * sanity.sh (death): New tests 65a0-65a6 cause test 74 to test for + above-fixed bug. + +Mon Jan 15 12:55:37 1996 Jim Kingdon + + * main.c: Revert change to run getopt_long twice. This can go in + after 1.7. + +Mon Jan 15 13:03:28 1996 Norbert Kiesel + + * filesubr.c (deep_remove_dir): added test of EEXIST for nonempty + directory (Posix states that both ENOTEMPTY (BSD) and EEXIST + (SYSV) are valid) + + * main.c (main): run getopt_long twice to allow command-line + suppression of reading the cvsrc file + +Fri Jan 12 10:02:43 1996 Jim Kingdon + + * Version 1.6.86. + +Thu Jan 11 23:28:05 1996 J.T. Conklin + and Jim Kingdon + + * fileattr.h (fileattr_startdir): Add comment about REPOS == NULL. + * fileattr.c (fileattr_read, fileattr_write): Assert that + fileattr_stored_repos != NULL. + (fileattr_free): If fileattr_stored_repos is NULL, don't free it. + +Thu Jan 11 18:03:21 1996 Karl Fogel + + * scramble.c (descramble): deal with DIAGNOSTIC better. + +Thu Jan 11 12:04:42 1996 Norbert Kiesel + + * main.c: remove CVS_NOADMIN. + + * options.h.in: remove CVS_NOADMIN + +Thu Jan 11 10:28:44 1996 Karl Fogel + + * scramble.c (descramble): make sure the string returned is safe + to free(). + +Wed Jan 10 01:11:23 1996 Jim Kingdon + + * server.c (serve_notify): Cast return value from malloc. + + * edit.c (notify_do): Use struct assignment, not struct + initialization (which SunOS4 /bin/cc doesn't have). + +Tue Jan 9 09:41:29 1996 Jim Kingdon + + * Version 1.6.85. + + We use version numbers instead of patchlevels. But there was some + confusing patchlevel stuff lying around. Nuke it: + * Makefile.in (HEADERS): Remove patchlevel.h + * patchlevel.h: Removed. + * main.c: Don't include patchlevel.h. + (main): Don't print patch level. + + * server.c (check_repository_password): Check for errors from + system calls; reindent function. + +Tue Jan 9 23:15:30 1996 Karl Fogel + + * expand_path.c: fix comments (explain expand_path()'s behavior + correctly). + +Tue Jan 9 09:41:29 1996 Jim Kingdon + + * edit.c (notify_proc): After copying in string following %s, + don't clobber it. Instead set up q to end of string. + + * watch.c (watch_modify_watchers), edit.c (editor_set): Fix sense + of test in trying to decide whether attributes are changed. + + * cvs.h (CVSROOTADM_USERS): New macro. + * edit.c (notify_do): Look up notifyee in CVSROOTADM_USERS if it + exists. + +Tue Jan 9 21:39:45 1996 Karl Fogel + + * expand_path.c: don't redundantly #include things that cvs.h + already #includes (i.e., stdio.h, ctype.h, string[s].h). + +Tue Jan 9 09:41:29 1996 Jim Kingdon + + * ignore.c (ign_default): Add *.obj. + + * server.c: Put /* */ around #endif comment. + +Mon Jan 8 20:37:17 1996 Karl Fogel + + * client.c (connect_to_pserver): check return value of recv(). + +Mon Jan 8 11:37:57 1996 Jim Kingdon + + * client.c (connect_to_pserver): Check for error from connect; + reindent function. + + * sanity.sh (4.75): Use dotest, so we get a PASS if test passes. + + * sanity.sh (dotest): New argument OUTPUT2. + (188a): Use it instead of \|. + + * sanity.sh (import): Avoid using string $ followed by Id followed + by $ in sanity.sh source, in case sanity.sh itself is under CVS. + I hate keyword expansion. + + * sanity.sh: If expr cannot handle multiline expressions, fail and + tell the user to get one which can. + + * release.c (release_delete): Remove unused variable retcode. + +Fri Jan 5 13:30:00 1996 Jim Kingdon + + * release.c (release_delete): Call unlink_file_dir rather + than "rm -rf". + +Thu Jan 4 09:58:30 1996 Jim Kingdon + + * commit.c (find_fileproc): Print "nothing known about foo" and + return 1 if the file doesn't exist and isn't in CVS/Entries. + (commit): If the recursion over find_fileproc returns an error, + print "correct above errors first!" just like local CVS. + * sanity.sh (basica): Test for above-fixed bug. + + * release.c (release): If we are the client, only unedit if the + server supports it. + + * sanity.sh: Remove STARTANCHOR stuff; expr patterns are + automatically anchored to the start. ENDANCHOR remains. + + * commit.c (commit): Don't start the server until we have + determined that there is something to commit. + +Thu Jan 4 09:48:33 1996 Ben Laurie + and Jim Kingdon + + * client.c (start_server): dup the file descriptor before + fdopening it. + +Wed Jan 3 18:25:25 1996 Jim Kingdon + + * sanity.sh: Remove tests 5, 5.5, and 5.75. All that stuff is + tested elsewhere. + + * ignore.c (ign_default): Change CVS* to CVS CVS.adm. CVS* is too + broad, especially in a case-insensitive filesystem. + + * Makefile.in (cvsbug): version.c is in srcdir. + +Wed Jan 3 17:30:45 1996 Phi-Long Tran + + * modules.c (do_module): Honor error_use_protocol in printing trace. + * server.c (server_register): Move check for options NULL to above + printing of the trace. + +Wed Jan 3 01:19:53 1996 Mark Immel + and Jim Kingdon + + * update.c (checkout_file): Do not resurrect file on join if it + doesn't contain the revisions we are joining. Probably not a + perfect test, but should be an improvement. + * sanity.sh (death): New death-file4-* tests, for bug fixed above. + +Wed Jan 3 01:19:53 1996 Jim Kingdon + + * add.c, admin.c, checkout.c, client.c, commit.c, diff.c, edit.c, + history.c, import.c, log.c, patch.c, release.c, remove.c, rtag.c, + status.c, tag.c, update.c, watch.c: In calling send_to_server, + pass \012 not \n. On the Mac \n is CR, not LF, and we want to + send LF. I didn't try to deal with whether files in CVSADM should + contain CR or LF--in fact there is some code in client.c which + reads \n from CVSADM files and passes it to send_to_server; it + needs to be cleaned up one way or the other. + + * entries.c (Entries_Open): Don't try to close fpin twice. + + * client.c (update_entries): Fix typo ("strlen (filename + 10)" + -> "strlen (filename) + 10"). + + * commit.c (checkaddfile): Remove arbitrary limit. + +Tue Jan 2 11:25:22 1996 Jim Kingdon + + * commit.c (commit): Only pass files which were modified, added, + or removed to send_file_names. This has as a side effect a + semantic change--the up-to-date check is now skipped for other + files--but probably a good one, or at least not a bad one. + * sanity.sh (basica): New test; tests for bug fixed above. + * sanity.sh (187a3): Adjust for new 'cvs commit' output. Set up + DOTSTAR to match arbitrary text (another GNU expr bug/misfeature, + sigh). + + * sanity.sh: Test that the commit in test 43 actually worked. + Merge tests basic2 and basic3 and make them independent of basic1. + (pass,fail): Don't insert spurious space. + (45.5): Fix typo in directory name. + +Tue Jan 2 13:00:00 1996 Jim Kingdon + + Visual C++ lint: + * myndbm.c: Prototype write_item. + +Tue Jan 2 11:25:22 1996 Jim Kingdon + + gcc -Wall lint: + * client.c (client_expand_modules): Pass error message not "" to error. + * client.c (supported_request), server.c (supported_response): + Return a value (gcc -Wall can't know that error doesn't return). + * commit.c (copy_ulist): Return a value. + * history.c (fill_hrec): Don't make assumptions about whether + time_t is "int" or "long" or what. + * cvs.h: Declare link_file. + * server.c: Include fileattr.h. + * server.c (server_notify): Remove unused variable val. + * tag.c (val_fileproc): Remove unused variable foundtag. + +Mon Jan 1 09:49:16 1996 Jim Kingdon + + * Version 1.6.5. + + * Version 1.6.4. + + * filesubr.c (link_file): Add comment about link vs. copy semantics. + + * cvs.h (struct vers_ts): Fix comments. + * commit.c (commit): Before we ask for a log message, figure out + what is modified and what is not and pass the information to + do_editor. + (copy_ulist,find_fileproc): New helper functions for above code. + + * client.c (read_line): When writing to from_server_logfile, write + the \n too. + + * client.c (send_files): No longer call send_file_names. + * client.h: Update comment. + * add.c, admin.c, commit.c, diff.c, edit.c, log.c, remove.c, + status.c, tag.c, update.c, watch.c: Call send_file_names before + send_files. + * client.c: New variables module_argc, module_argv. + (client_expand_modules): Set them, to arguments. + (client_send_expansions): Use them instead of modules_vector to + send arguments. + * sanity.sh (modules): Add test of modules -d flag. + +Sun Dec 31 17:33:47 1995 Jim Kingdon + + * import.c (add_rev): Revert portion of 31 Aug 95 change which + passes -u to ci instead of using a hard link. + * sanity.sh (import): Add test for above-fixed bug. + +Sun Dec 31 16:40:41 1995 Peter Chubb + and Jim Kingdon + + * admin.c (admin_fileproc): Call freevers_ts before returning. + +Mon Dec 25 12:20:06 1995 Peter Wemm + + * logmsg.c (rcsinfo_proc): initialise line and + line_chars_allocated so they dont cause malloc problems within + getline(). This was causing rcsinfo templates to not work. + +Sun Dec 24 01:38:36 1995 Karl Fogel + + * server.c (authenticate_connection): clarify protocol. + + * login.c (login): deprolixify the password prompt. + +Sat Dec 23 10:46:41 1995 Jim Kingdon + + * myndbm.h, myndbm.c (dbm_store): New function. + * myndbm.h (DBM): Add modified and filename fields. + * myndbm.c (dbm_open, dbm_close): Manipulate new fields. dbm_open + no longer fails if the file doesn't exist and O_CREAT is set. + * cvs.h (CVSROOTADM_VALTAGS): Added. + * tag.c, cvs.h (tag_check_valid): New function. + * update.c (update), checkout.c (checkout_proc), commit.c (commit), + diff.c (diff), patch.c (patch_proc), rtag.c (rtag_proc), tag.c (tag): + Call it. + * sanity.sh: Test for rejection of invalid tagname. + +Fri Dec 22 18:21:39 1995 Karl Fogel + + * client.c (start_server): don't use kerberos if authenticating + server was specified. + +Fri Dec 22 16:35:57 1995 Karl Fogel + + * login.c (login): deal with new scramble methods. + (get_cvs_password): same. + + * server.c (check_repository_password): remove arbitrary limit on + line length. + (authenticate_connection): use a separate variable for the + descrambled password, now that we no longer scramble in place. + Set `error_use_protocol' to 1 and just use error() where used to + do its job inline. + + * cvs.h (scramble, descramble): adjust prototype. + + * scramble.c (scramble, descramble): return char *. + +Fri Dec 22 13:00:00 1995 Jim Kingdon + + * release.c (release): If SERVER_SUPPORT is not defined, still + set up arg_start_idx. + + * release.c (release): When calling unedit, set argv[1] to + NULL (since argc is only 1). + + * edit.c: Pass dosrcs 0 to all calls to start_recursion. + None of the fileprocs were using it, so it just slowed things + down and caused potentially harmful checks for rcs files. + + * edit.c (send_notifications): In client case, do not readlock. + +Thu Dec 21 16:00:00 1995 Jim Kingdon + + Clean up Visual C++ lint: + * client.c (read_line): Change input_index and result_size to size_t. + (update_entries): Remove unused variables buf2, size_left, size_read. + (handle_mode): Prototype. + * client.c, client.h (send_to_server, read_from_server): Change + len to size_t. + * client.c (send_to_server): Change wrtn to size_t. + (read_from_server): Change red to size_t. + * client.c, myndbm.c, edit.c, fileattr.c: Include getline.h. + * checkin.c, commit.c, update.c: Include fileattr.h. + * commit.c, update.c: Include edit.h. + * edit.c (onoff_filesdoneproc): Prototype. + (ncheck_fileproc,edit_fileproc): Change "return" to "return 0". + (notify_do): Cast a signed value to unsigned before comparing + with unsigned value. + +Thu Dec 21 15:24:37 1995 Karl Fogel + + * client.c: don't include socket headers twice just because + both HAVE_KERBEROS and AUTH_CLIENT_SUPPORT are set. + (start_kerberos_server): if fail to connect to kerberos, print out + a more specific error message, mainly so pcl-cvs can know what + happened and not panic. + (start_server): don't assume sprintf() returns len + written (only some systems provide this); instead, have + send_to_server() calculate the length itself. + (send_modified): same. + (send_fileproc): same. + (send_file_names): same. + +Wed Dec 20 14:00:28 1995 Jim Kingdon + + * update.c (ignore_files): Move from here... + * ignore.c (ignore_files): ...to here. No longer static. Take + new argument PROC. + * cvs.h (ignore_files): Declare. + * client.c (send_filesdoneproc): Split off from + update_filesdone_proc. Pass new function send_ignproc to + ignore_files (to ask server about ignored file before printing + "?"). + * server.c: Rename outbuf from but_to_net and take it from + do_cvs_command to a global. Move initialization accordingly. + (serve_questionable): New function. + (requests): Add it. + * update.c (update_filesdone_proc): Remove client stuff. Pass new + function update_ignproc to ignore_files. + * cvs.h (joining, do_update): Move declarations from here... + * update.h: ...to here. + * cvs.h: Include update.h. + * update.c, client.c: Don't include update.h + * ignore.c, cvs.h: New variable ign_inhibit_server, set on -I !. + * import.c (import): Pass -I ! to server if specified. + (import_descend): If server, ignore CVS directories even if -I !. + * update.c (update), import.c (import): Only call ign_setup before + argument processing; don't call it again afterwards in client case. + * sanity.sh (ignore): Test above-fixed bugs and other ignore behaviors. + (dotest): New function. + Move modules checkin from modules test to start, so that other + tests can use mkmodules without a warning message. + +Wed Dec 20 13:06:17 1995 Karl Fogel + + * client.c (send_to_server): don't check string's length twice. + +Wed Dec 20 02:05:19 1995 Karl Fogel + + * login.c (login): took out debugging printf's. + (login): Removed unused variable `p'. + +Wed Dec 20 00:27:36 1995 Karl Fogel + + * login.c (login): prefix scrambled password with 'A', so we know + which version of scrambling was used. This may be useful in the + future. + (get_cvs_password): skip past the leading 'A'. + Scramble $CVS_PASSWORD before returning it. + + * scramble.c: made this work. + +Tue Dec 19 17:45:11 1995 Karl Fogel + + * login.c (cvs_password): new static var, init to NULL. + (login): scramble() the password before using it. + Verify the password with the server. + Check CVSroot more carefully to insure that it is + "fully-qualified". + (get_cvs_password): if cvs_password is not NULL, just return it. + Never prompt -- just tell user why failed, then exit. + Try CVS_PASSWORD environment variable first. + (construct_cvspass_filename): try CVS_PASSFILE environment + variable first. + + * client.h (connect_to_pserver): update prototype. + + * client.c (cvsroot_parsed): new static var. + (parse_cvsroot): set `cvsroot_parsed' to 1 when done. + (connect_to_pserver): return int. + Take `verify_only' arg. If it is non-zero, perform password + verification with the server and then shut down the connection and + return. + Call parse_cvsroot() before doing anything. + + * server.c (authenticate_connection): deal with verification + requests as well as authorization requests. + descramble() the password before hashing it. + + * cvs.h: prototype scramble() and descramble(). + + * Makefile.in: build scramble.o. + + * scramble.c: new file, provides trivial encoding but NOT real + encryption. + +Mon Dec 18 20:57:58 1995 Karl Fogel + + * login.c (login): don't insert extra newlines. They were + harmless, but confusing. + +Mon Dec 18 15:32:32 1995 Jim Kingdon + + * hash.c, hash.h (findnode_fn): New function. + * hash.c (hashp): Tweak hash function so that findnode_fn works. + * update.c (ignore_files): Call findnode_fn, not findnode. + +Mon Dec 18 09:34:56 1995 Jim Kingdon + + * myndbm.c: Remove arbitrary limit. + + * client.c: Fix comment--Windows 95 requires NO_SOCKET_TO_FD, not + Windows NT. + +Mon Dec 18 01:06:20 1995 Karl Fogel + + * client.c (server_sock): replaces `server_socket'. + (start_kerberos_server): added FIXME comment about how + NO_SOCKET_TO_FD is not dealt with in the kerberos case. + (connect_to_pserver): deal with NO_SOCKET_TO_FD case. + (read_line): deal with NO_SOCKET_TO_FD case. + (read_from_server): deal with NO_SOCKET_TO_FD case. + (send_to_server): deal with NO_SOCKET_TO_FD case. + (get_responses_and_close): deal with NO_SOCKET_TO_FD case. + + * client.c (send_to_server): error check logging. + (start_server): error check opening of logfiles. + (read_from_server): error check logging. + (read_line): use fwrite() to log, & error_check it. + Don't log if using socket style, because read_from_server() + already logged for us. + +Mon Dec 18 00:52:26 1995 Karl Fogel + + * client.c (use_socket_style): new static var, init to 0. + (server_socket): new static var. + (connect_to_pserver): don't deal with logging here. + Caller changed. + (start_kerberos_server): don't deal with logging here either. + Caller changed. + +Mon Dec 18 00:40:46 1995 Karl Fogel + + * client.c (send_modified): don't error-check `to_server'; + send_to_server() does that now. + +Mon Dec 18 00:19:16 1995 Karl Fogel + + * login.c (get_cvs_password): Init `linebuf' to NULL. + free() `linebuf' and reset it for each new line. + (login): same as above. + + * client.c: Removed all the varargs prototyping gunk. + (to_server, from_server): make these static. + (from_server_logfile, to_server_logfile): new vars. + (start_server): init above two new vars to NULL. + (send_to_server): return void. + Correct bug in which amount to be written would be too high if the + loop ever ran more than once. + Log to `to_server_logfile' if it's non-NULL. + (read_from_server): new func, does raw reading from server. + Logs to `from_server_logfile' if it's non-NULL. + (update_entries): just use read_from_server() instead of looping + to fread() directly from `from_server'. + (read_line): Log to `from_server_logfile' if it's non-NULL. + + * client.h: send_to_server() returns void now. + (read_from_server): prototype. + +Sun Dec 17 19:38:03 1995 Jim Kingdon + + * checkout.c (checkout_proc), client.c, lock.c (readers_exist), + login.c, modules.c (cat_module, do_module): Remove arbitrary limits. + + * client.c (send_to_server): Fix typo (NULL -> '\0'). + (get_responses_and_close): Set server_started to 0 instead of + setting to_server and from_server to NULL. + * client.c: Make to_server and from_server static. + +Sun Dec 17 17:59:04 1995 Karl Fogel + + * client.h (to_server, from_server): don't declare these anymore. + They are now entirely private to client.c (and in fact will go + away soon there too). + +Sun Dec 17 15:40:58 1995 Karl Fogel + + * client.h: update prototype of send_to_server(). + + * client.c, watch.c, update.c, tag.c, status.c, rtag.c, remove.c, + release.c, patch.c, log.c, import.c, history.c, edit.c, diff.c, + commit.c, client.c, checkout.c, admin.c, add.c: + Convert all send_to_server() calls that used formatting to send + pre-formatted strings instead. And don't error check + send_to_server(), because it does its own error checking now. + + * client.c (send_to_server): don't use vasprintf(), just fwrite a + certain number of bytes to the server. And do error checking + here, so our callers don't have to. + (send_arg): use send_to_server() instead of putc()'ing + directly to `to_server'. + +Sun Dec 17 14:37:52 1995 Karl Fogel + + * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): + Define to 1 but leave commented out, instead of #undef'ing them. + This treats them like everything else in this file. + + * client.c: define server_started, init to 0. + (start_server): set server_started to 1. + + * client.h: declare `server_started', extern. + AUTH_CLIENT_SUPPORT moved here from cvs.h. + + * cvs.h: moved AUTH_CLIENT_SUPPORT stuff to client.h. + + * edit.c (notify_check): use new var server_started. + +Sun Dec 17 00:44:17 1995 Jim Kingdon + + * client.c (get_responses_and_close): Really stop ignoring ECHILD + errors. The Nov 30 1995 change claimed to do this, but the code + was not actually changed. + + * update.c (ignore_files): Revert H.J. Lu change; it was wrong for + directories and sometimes looked at sb.st_mode when it wasn't set. + * import.c (import_descend): Revert H.J. Lu change; it was wrong + for directories and the extra lstat call was an unnecessary + performance hit. + * sanity.sh (import): Add test for the second of these two bugs. + +Sat Dec 16 17:26:08 1995 Jim Kingdon + + * client.c (send_to_server): Remove arbitrary limit. Also remove + !HAVE_VPRINTF code; all relevant systems have vprintf these days. + +Sat Dec 16 21:35:31 1995 Karl Fogel + + * checkout.c (checkout): use send_to_server() now. + +Sat Dec 16 21:18:16 1995 H.J. Lu (hjl@gnu.ai.mit.edu) + (applied by kfogel@cyclic.com) + + * import.c (import_descend): We ignore an entry if it is + 1. not a file, nor a link, nor a directory, or + 2. a file and on the ignore list. + + * update.c (ignore_files): We ignore any thing which is + 1. not a file, or + 2. it is a file on the ignore list. + +Sat Dec 16 00:14:19 1995 Karl Fogel + + * client.c (send_to_server): corrected comment. + + * client.h: prototype new func send_to_server(). + + * add.c, admin.c, client.c, commit.c, diff.c, edit.c, history.c, + import.c, log.c, patch.c, release.c, remove.c, rtag.c, status.c, + tag.c, update.c, watch.c: + Use send_to_server() instead of writing directly to to_server. + + * client.c: conditionally include the right stuff for variable arg + lists. + (send_to_server): new func. + +Fri Dec 15 23:10:22 1995 Karl Fogel + + * error.c: expanded comments. + + * client.c (connect_to_pserver): verbosify errors. + (connect_to_pserver): use send() and recv(), not write() and + read(). Sockets are not file descriptors on all systems. + +Fri Dec 15 22:36:05 1995 Karl Fogel + + * client.c (connect_to_pserver): oops, removed old debugging + printf. + +Fri Dec 15 18:21:16 1995 Karl Fogel (kfogel@floss.cyclic.com) + + * client.c (auth_server_port_number): don't call htons(); + init_sockaddr() does that for us. + (init_sockaddr): zero the sockadder_in struct before doing + anything with it. IBM TCP/IP docs recommend this, and it can't + hurt. + +Fri Dec 15 15:21:53 1995 Karl Fogel + + * client.c (connect_to_pserver): new var `port_number', initialize + with new func auth_server_port_number() and pass to + init_sockaddr(). + (auth_server_port_number): new func. Right now it just returns + `htons (CVS_AUTH_PORT)'. We'll probably add the ability to + specify the port at run time soon, anyway, so having this function + will make that easier. + +Wed Dec 6 18:08:40 1995 Jim Kingdon + + * cvs.h: Add CVSREP. + * find_names.c (find_dirs): Skip CVSREP too. + * fileattr.h, fileattr.c: New files, to manipulate file attributes. + * hash.c (nodetypestring), hash.h (enum ntype): Add FILEATTR. + * hash.c, hash.h (list_isempty): New function. + * recurse.c (do_recursion): Call fileattr_startdir before + processing files in a directory and fileattr_write and + fileattr_free (after files, before recursing). + * watch.c, watch.h: New files, to handle notification features. + * edit.c, edit.h: New file, to handle new read-only checkout features. + * client.c, server.c: Add "Mode" request, to change the mode of a file + when it is checked in. + * main.c (cmds): Add "watch", "edit", "unedit", "watchers", "editors". + * main.c: Split command help from usg into new variable cmd_usage, + which. + (main): Add --help-commands option to print out cmd_usage. + * cvs.h: Declare watch, edit, unedit, watchers, editors. + * client.c, client.h: Add client_watch, client_edit, client_unedit, + client_watchers, client_editors. + * client.c, server.c: Add notification stuff. + * update.c (checkout_file, patch_file), checkin.c (Checkin): Check + _watched attribute when deciding read-only or read-write. + * commit.c (checkaddfile): Call fileattr_newfile to set attributes + on newly created files. + * release.c (release): + * cvs.h: Add CVSADM_NOTIFY and CVSADM_NOTIFYBAK. + * recurse.c (do_recursion): Call notify_check. + * commit.c (commit_fileproc): Call notify_do after committing file. + * client.c (get_responses_and_close): Set to_server and from_server + to NULL so that it is possible to tell whether we are speaking to + the server. + * cvs.h: Add CVSROOTADM_NOTIFY. + * mkmodules.c (main): Add CVSROOTADM_NOTIFY to filelist. + * Makefile.in (SOURCES,OBJECTS,HEADERS): Add new files mentioned above. + * lock.c, cvs.h (lock_tree_for_write, lock_tree_cleanup): New + functions, taken from old commit.c writelock code. As part of + this, fsortcmp and lock_filesdoneproc go from commit.c to lock.c. + So does locklist but it gets renamed to lock_tree_list. + * commit.c: Use lock_tree_*. + +Fri Dec 15 10:37:00 1995 J.T. Conklin + + * tag.c (tag_usage): Added -r and -D flags to usage string. + (tag): Detect when user specifies both -r and -D arguments. + Pass -r and -D arguments to server. + +Thu Dec 14 11:56:13 1995 Karl Fogel + + * client.c (start_rsh_server): use RSH_NEEDS_BINARY_FLAG to + conditionalize "-b" option to "rsh". + + * run.c (filter_stream_through_program): document return value and + error behavior. + + * client.c (filter_through_gunzip): pass the supposedly + superfluous "-d" option to gunzip, to avoid stimulating what seems + to be an argument-passing bug in spawn() under OS/2 with IBM + C/C++. Yucko. + +Wed Dec 13 20:08:37 1995 Jim Kingdon + + * options.h.in (RCSBIN_DFLT): Recommend specifying -b in + inetd.conf for pserver. That is a pretty good solution. + +Wed Dec 13 18:29:59 1995 Preston L. Bannister + and Karl Fogel + + * client.c (send_modified): make sure that vers and vers->options + are non-NULL before strcmp()'ing them with "-kb". + Initialize `bin' near where it is used, not at beginning of + function. + (update_entries): make sure `options' is non-NULL before + strcmp()'ing with "-kb". + Initialize `bin' near where it is used, not at beginning of + function. + +Tue Dec 12 18:56:38 1995 Karl Fogel + + * options.h.in (RCSBIN_DFLT): document the probable need for this + to be set in the authenticating server. + +Tue Dec 12 11:56:43 1995 Jim Kingdon + + * server.c (expand_proc): If mfile is non-NULL, return it too as + part of the expansion. + * sanity.sh (modules): Add tests for above-fixed bug. + +Mon Dec 11 21:39:07 1995 Karl Fogel + + * dog.c (flea_bath): Take `suds' arg. + All collars changed. + +Mon Dec 11 15:58:47 1995 Karl Fogel + + * login.c (login): if client password file doesn't exist, create + it, duh. + + * main.c (main): die if CVSroot has access-method but no + username. + + * root.c: added some comments. + + * main.c: removed all code pertaining to the "-a" option. We + specify access-method in CVSroot now. + + * client.c (parse_cvsroot): new var, `access_method'. If CVSroot + is prepended with an access method (i.e., + ":pserver:user@host:/path"), then handle it. + + * login.c (login): use || when checking if CVSroot is "fully + qualified". + Prepend ":pserver:" before writing to ~/.cvspass. + (get_cvs_password): Take no parameters; we'll just use CVSroot to + get the password. + +Mon Dec 11 12:43:35 1995 adamg + + * error.c, client.c, remove.c, main.c: Add explicit casts for some + function pointers to remove warnings under MS VC. + * main.c (main): remove use of NEED_CALL_SOCKINIT in favor of the + more generic INITIALIZE_SOCKET_SUBSYSTEM. Note that the code assumes + that if INITIALIZE_SOCKET_SUBSYSTEM() returns, socket subsystem + initialization has been successful. + +Sat Dec 9 22:01:41 1995 Dan O'Connor + + * commit.c (check_fileproc): pass RUN_REALLY flag to run_exec, + because it's okay to examine the file with noexec set. + +Sat Dec 9 20:28:01 1995 Karl Fogel + + * client.c (update_entries): new var, `bin, init to 0. + Use it in determining whether to convert the file. + (send_modified): same as above. + +Fri Dec 8 17:47:39 1995 Karl Fogel + + * server.c (downcase_string): removed. + (check_repository_password): don't deal with case-insensitivity + anymore. + + * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): deleted this. No + need for it anymore. + +Thu Dec 7 21:08:39 1995 Karl Fogel + + * server.c (check_repository_password): when checking for false + prefix-matches, look for ':', not '@'. Duh. + +Thu Dec 7 18:44:51 1995 Karl Fogel + + * options.h.in (CVS_PASSWORDS_CASE_SENSITIVE): replaces + CVS_PASSWORDS_CASE_INSENSITIVE; passwords are now insensitive by + default. Expanded explanatory comment. + + * login.c (get_cvs_password): Use memset(), not bzero(). I + botched this change earlier. + + * server.c (check_repository_password): no need to check + xmalloc()'s return value. + (check_repository_password): check for false prefix-matches (for + example, username is "theo" and linebuf contains user + "theocracy"). + +Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com) + + * filesubr.c (isaccessible): Rename from isaccessable. + Update callers. + * cvs.h: Update prototype. + * main.c (main): Update callers. + * server.c (main): Update callers. + +Thu Dec 7 12:50:20 1995 Adam Glass + + * cvs.h: "isaccessible" is the correct spelling. + Also add "const" to second arg to make prototype match + declaration. + +Thu Dec 7 11:06:51 1995 Karl Fogel + + * client.c, login.c: memset() instead of bzero(). + +Thu Dec 7 00:08:53 1995 Karl Fogel + + * server.c (authenticate_connection): document server's side of + the Authentication Protocol too. + + * client.c (connect_to_pserver): when printing out "unrecognized + response", also print out the offending response. + + * server.c (check_password): take `repository' arg too now. + Call check_repository_password() before checking /etc/passwd. + (check_repository_password): new func. + + * options.h.in (CVS_PASSWORDS_CASE_INSENSITIVE): new define, unset + by default. + +Wed Dec 6 18:51:16 1995 Karl Fogel + + * server.c (check_password): If user has a null password, then + return 1 if arg is also null. + Reverse sense of return value. Caller changed. + +Wed Dec 6 14:42:57 1995 Karl Fogel + + * server.c (check_password): new func. + (authenticate_connection): call above new func. + + * login.c (login): use construct_cvspass_filename(). + If CVSroot is not "fully-qualified", then insist the user qualify + it before going on. + (get_cvs_password): fleshed out. Now reads from ~/.cvspass, or + prompts if no appropriate password found. + (construct_cvspass_filename): new func. + + * server.c (authenticate_connection): send ACK or NACK to client. + + * client.c (connect_to_pserver): check for ACK vs NACK response + from server after sending authorization request. + + * login.c (get_cvs_password): new func. + + * client.c (connect_to_pserver): use new func get_cvs_password(). + Prototype it at top of file. Hmmm. + +Wed Dec 6 13:29:22 1995 Karl Fogel + + * server.c: same as below (AUTH_SERVER_SUPPORT). + + * main.c: same as below (AUTH_SERVER_SUPPORT where appropriate). + + * login.c: same same as below. + + * cvs.h: same as below. + + * client.c: use AUTH_CLIENT_SUPPORT, not CVS_LOGIN. + + * options.h.in (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): these + replace CVS_LOGIN. + +Wed Dec 6 00:04:58 1995 Karl Fogel + + * server.c (authenticate_connection): expanded comment. + +Tue Dec 5 23:37:39 1995 Karl Fogel + + * client.c (connect_to_pserver): read password from prompt for + now. + + * server.c (authenticate_connection): if the password passes + muster, then don't abort. + +Tue Dec 5 22:46:37 1995 Karl Fogel + + * subr.c (strip_trailing_newlines): new func. + + * client.c (connect_to_pserver): took out print statements. + + * server.c (authenticate_connection): removed print statments. + Use new func strip_trailing_newlines() to purify `repository', + `username', and `password'. + Run a primitive password check, just for testing. + + * client.c (connect_to_pserver): use CVS_AUTH_PORT. + Take tofdp, fromfdp, and log args. Caller changed. + (get_responses_and_close): either kerberos and CVS_LOGIN might + have one fd for both directions, so adjust #ifdef accordingly. + + * cvs.h (CVS_AUTH_PORT): new define, default to 2401. + Prototype strip_trailing_newlines(). + +Tue Dec 5 16:53:35 1995 Karl Fogel + + * server.c (authenticate_connection): new func. + + * client.c (init_sockaddr): func moved here from login.c. + (connect_to_pserver): same as above. Take no args, now. + Include , , , if CVS_LOGIN. + + * cvs.h: Declare use_authenticating_server, as extern int. + Declare connect_to_pserver(). + + * main.c (main): call authenticate_connection(). Removed testing + code. + Add 'a' to the short-option string in the getopt() call. + + * login.c (connect_to_pserver): moved to client.c. + +Tue Dec 5 16:01:42 1995 Peter Chubb + (patch applied by Karl Fogel ) + + * update.c (join_file): if vers->vn_user is "0", file has been + removed on the current branch, so print an error and return. + +Mon Dec 4 14:27:42 1995 Jim Kingdon + + * Version 1.6.3. + +Mon Dec 4 16:28:25 1995 Norbert Kiesel + + * release.c (release): add return (0) as last line + + * cvs.h: declare program_path + + * main.c define program_path + (main): set program_path + + * release.c (release): use program_path for update_cmd + +Mon Dec 4 11:22:42 1995 Jim Kingdon + + * Version 1.6.2. + +Sun Dec 3 20:02:29 1995 Jim Kingdon + + * rcs.h (struct rcsnode), rcs.c (freercsnode): Add expand field. + * rcs.h (RCSEXPAND): New #define. + * rcs.c (RCS_reparsercsfile): Record keyword expansion in expand + field of struct rcsnode. + * update.c (checkout_file): Set keyword expansion in Entries file + from rcs file if there is nowhere else to set it from. + * client.c (send_modified, update_entries) [LINES_CRLF_TERMINATED]: + If -kb is in effect, don't convert. + + * update.c (update_file_proc), commit.c (check_fileproc), + rcscmds.c (RCS_merge): Direct stdout to DEVNULL rather than + passing -s option to grep. This avoids trouble with respect to + finding a grep which support -s and whether we should use the (GNU + grep) -q option if it exists. + * options.h.in: Change "@ggrep_path@" to "grep". + +Fri Dec 1 11:53:19 1995 Norbert Kiesel + + * rcs.c (RCS_gettag): new parameter return_both force return both + tags: the symbolic and the numeric one. + (RCS_getversion): new parameter return_both is forwarded to + RCS_gettag. + + * rtag.c, tag.c, commit.c, patch.c, update.c: pass 0 as additional + last parameter to RCS_getversion and RCS_gettag + + * rcs.h (RCS_gettag): new parameter return_both. + (RCS_getversion): new parameter return_both. + + * cvs.h (struct vers_ts): add vn_tag slot for symbolic tag name + + * vers_ts.c (Version_TS): call RCS_getversion with 1 for + return_both and split output into vn_rcs and vn_tag + (freevers_ts): free vn_tag + + * update.c (checkout_file): use vn_tag instead of vn_rcs when + calling 'rcs co' to allow rcs expansion of :$Name : + +Thu Nov 30 20:44:30 1995 Karl Fogel + + * client.c (get_responses_and_close): undo previous change + regarding waitpid(). The problem has been solved by modifying + os2/waitpid.c instead of its callers. + +Thu Nov 30 16:37:10 1995 Karl Fogel + + * client.c: All these changes are for OS/2, which will no longer have + a separate client.c: + (start_kerberos_server): new func, contains code that + used to be in start_server(). + (start_server): moved kerberos code to above function, reorganized + the rest. Added authentication clause. + (call_in_directory): test errno against EACCESS, if EACCESS is + defined (this is for OS/2's oddball mkdir). + (change_mode): don't set execute permission on anything if + EXECUTE_PERMISSION_LOSES is defined. + (get_responses_and_close): if START_RSH_WITH_POPEN_RW, then use + pclose() instead of fclose(). + If waitpid errors with ECHILD, don't die. This is okay. + (start_rsh_server): alternate definition if + START_RSH_WITH_POPEN_RW. + + * main.c: [all these changes conditional on CVS_LOGIN: ] + Don't prototype connect_to_pserver, don't enter it in cmds[] + (actually, it was never in there, I don't know why my previous + change said it was). + (use_authenticating_server): new global var. + (main): if "-a", then set above new var to TRUE. + (usg): document "-a" option. + +Wed Nov 29 12:55:10 1995 Karl Fogel + + * main.c: Prototype connect_to_pserver(), and enter it in cmds[]. + (main): test some extremely primitive authentication. + + * login.c: Include + (connect_to_pserver): new func. + (init_sockaddr): new func. + +Mon Nov 20 14:07:41 1995 Jim Kingdon + + * Makefile.in (TAGFILES): Separate out from DISTFILES, for C code. + (TAGS,tags): Use TAGFILES not DISTFILES. + +Sun Nov 19 11:22:43 1995 Jim Kingdon + + * recurse.c (do_recursion): Don't call server_pause_check if there + are writelocks around. Revise comment to reflect fact we are no + longer relying on a writelock'd operations being "unable" to + generate enough data to pause. + +Sun Nov 19 10:04:50 1995 Peter Wemm + + * server.c, server.h, options.h.in: Implement hooks for doing + simple flow control on the server to prevent VM exhaustion on a + slow network with a fast server. + * recurse.c: Call the flow control check at a convenient location + while no locks are active. This is a convenience tradeoff against + accurate flow control - if you have a large directory it will all + be queued up, bypassing the flow control check until the next + directory is processed. + +Sat Nov 18 16:22:06 1995 Karl Fogel + + * client.c, update.c, vers_ts.c, server.c, rcs.c, lock.c, + ignore.c, entries.c, diff.c, commit.c, checkin.c: + Use new macro `existence_error', instead of comparing errno to + ENOENT directly. + +Fri Nov 17 14:56:12 1995 Karl Fogel + + * client.c (start_server): removed alternate version of this func, + since os2/client.c will now be used under OS/2. + +Thu Nov 16 22:57:12 1995 Karl Fogel + + * client.c (start_server): ifdef HAVE_POPEN_RW, use a different + version of start_server(). This is maybe not the cleanest cut to + make, but it's better than mucking around with yet more #ifdefs in + the middle of the old start_server() function. Once things are + up, I may reposition this code. + +Wed Nov 15 15:33:37 1995 Karl Fogel + + * main.c (main): ifdef NEED_CALL_SOCKINIT, then call SockInit(). + Only OS/2 needs this initialization. + +Tue Nov 14 18:54:01 1995 Greg A. Woods + + * patch.c: + - fix orientation of test for result of getline() call + - use fputs() not printf() when just copying file out + + * cvsbug.sh: + - add space after #! + - new rcs id + - allow version to be edited by Makefile. + + * Makefile.in: + - make Makefile a dependent of all (this might not be perfect, but + it at least gives you a chance to catch up on the second + go-around). + - filter cvsbug.sh in a manner similar to cvsinit.sh to get the + version number set from version.c + +Tue Nov 14 13:28:17 1995 Jim Kingdon + + * sanity.sh: Call old log file check.plog, not check.olog. + + * sanity.sh: Convert remaining tests from old-style ('***' on fail + and nothing on pass), to new-style (FAIL on fail and PASS on pass). + + * sanity.sh: Fix ability to run only some of the tests (always run + tests 1-4.75 to set up repository, document better how it works). + + * sanity.sh: Change "completed successfully" to "completed" in + message--many tests, but not all, exit if they fail. + +Tue Nov 14 15:10:00 1995 Greg A. Woods + + * sanity.sh: test 63 doesn't work and probably can't + +Tue Nov 14 12:22:00 1995 Greg A. Woods + + * sanity.sh: many minor tweaks: + - make the optional arguments almost work + - use a function 'directory_cmp' instead of 'diff -r' + - fix up a few more tests that weren't working.... + +Mon Nov 13 07:33:55 1995 Karl Fogel + + * cvs.h: ifdef USE_OWN_POPEN, #include "popen.h". Only OS/2 has + its own popen()/pclose() right now. + +Mon Nov 13 04:06:10 1995 Karl Fogel + + * cvs.h: conform to 80 column standard (yes, I'm a pedant). + +Sat Nov 11 13:45:13 1995 Karl Fogel + + * client.c (process_prune_candidates): use unlink_file_dir() to + remove the directory, instead of invoking "rm" via run_exec(). + +Fri Nov 10 14:38:56 1995 Karl Fogel + + * main.c (main): removed "#define KF_GETOPT_LONG 1", since that + change is no longer in testing. + +Thu Nov 9 20:32:12 1995 Karl Fogel + + * release.c (release): Use Popen(), not popen(). + +Wed Nov 8 10:20:20 1995 Jim Meyering (meyering@comco.com) + + * entries.c (ParseTag): Remove dcl of unused local. + + * patch.c: Include getline.h. + +Wed Nov 8 11:57:31 1995 Norbert Kiesel + + * options.h.in: add configuration option STEXID_SUPPORT (default + is off i.e. old semantics) + + * filesubr.c (isaccessable): new function. Checks access-rights + for files like access(), but is getxid-safe. Falls back to + access() if SETXID_SUPPORT is not enabled. + (isfile): replace stat() by isaccessable(file, F_OK) + (isreadable): replace access() by isaccessable() + (iswritable): ditto + (make_directory): rename local variable buf to sb + + * cvs.h: add prototype for new function isaccessable. + + * server.c (serve_root): replace access() by isaccessable() + + * cvsrc.c (read_cvsrc): replace access() by isreadable() + + * main.c (main): replace access() by isaccessable() + +Wed Nov 8 10:22:41 1995 Greg A. Woods + + * entries.c (fgetentent): change definition to static to match the + declaration at the top of the file + +Tue Nov 7 16:59:25 1995 J.T. Conklin + + * rcs.c (RCS_getbranch, RCS_getdate, RCS_getrevtime, RCS_gettag, + RCS_getversion, RCS_head): Use assert() instead of attempting to + "do the right thing" with a bogus RCSNode argument. + +Mon Nov 6 14:24:34 1995 Jim Kingdon + + * vers_ts.c: Remove ctime define. It is just asking for trouble. + +Mon Nov 6 11:58:26 1995 Karl Fogel + + * vers_ts.c: ifdef ctime, undef it before redefining it. It is a + macro on some systems. + + * lock.c: don't prototype ctime() here. (See note below about + fgetentent() in entries.c.) + +Sun Nov 5 16:06:01 1995 Karl Fogel + + * entries.c (fgetentent): don't prototype ctime here; we include + cvs.h, which includes system.h, which includes + unconditionally (either as or ). Anyway, IBM + C/C++ chokes on mid-function, or even mid-file, prototypes. Sigh. + +Thu Nov 2 21:51:04 1995 Dan Wilder + + * rtag.c (rtag): Fix typo ("-T" -> "-F"). + +Tue Oct 31 19:09:11 1995 Dan Wilder + + * diff.c (diff_dirproc): just return R_SKIP_ALL if dir not exist. + (diff_file_nodiff): don't complain if file doesn't exist, just + ignore. + +Tue Oct 31 09:25:10 1995 Norbert Kiesel + + * sanity.sh: Use absolute pathname for mkmodules. + +Sat Oct 28 01:01:41 1995 Jim Meyering (meyering@comco.com) + + * entries.c (ParseTag): Use getline instead of fgets. + +Fri Oct 27 13:44:20 1995 Karl Fogel + + * cvs.h: do nothing about alloca ifdef ALLOCA_IN_STDLIB. I am + rather suspicious of this solution, and will not be surprised to + find out that there's a Right Way to handle this situation ("this + situation" being that OS/2 simply declares alloca in ). + Suggestions are welcome; see src/cvs.h and lib/system.h to see why + I was getting a conflict in the first place. + +Wed Oct 25 16:03:20 1995 J.T. Conklin + + * cvs.h (struct entnode): Add user field. + * entries.c (fputentent): New function, write entries line. + (write_ent_proc): Call fputentent to write entries line. + (Entnode_Create): New function, construct new Entnode. + (Entnode_Destroy): New function, destruct old Entnode. + (AddEntryNode): Changed to take an Entnode argument instead of + separate user, version, timestamp, etc. arguments. + (fgetentent): Changed to return Entnode. + (struct entent, free_entent): Removed. + +Wed Oct 25 12:44:32 1995 Jim Kingdon + + * admin.c (admin): Don't rely on ANSI C string concatenation; + SunOS 4.1.3 /bin/cc doesn't support it. + +Tue Oct 24 22:34:22 1995 Anthony J. Lill + + * import.c (expand_at_signs): Check errno as well as return value + from putc. Some systems bogusly return EOF when successfully + writing 0xff. + +Tue Oct 24 14:32:45 1995 Norbert Kiesel + + * admin.c (admin): use getcaller() instead of getpwuid + + * subr.c (getcaller): prefer getlogin() to $USER and $LOGNAME + (especially useful for NT where getuid always returns 0) + +Tue Oct 24 06:22:08 1995 Jim Meyering (meyering@comco.com) + + * cvsrc.c (read_cvsrc): Use getline instead of fgets. + * patch.c (patch_fileproc): Use getline instead of fgets. + + * entries.c (fgetentent): Use getline instead of fgets. + Use xmalloc to allocate space for each returned entry. + Since LINE is no longer static, save it in struct entent. + (struct entent): New member, line. + (free_entent): New function. + (Entries_Open): Call it after each call to fgetentent. + +Tue Oct 24 11:13:15 1995 Norbert Kiesel + + * cvs.h: Declare valloc again, but this time with the right + signature (also changed in libs/valloc.c) + +Mon Oct 23 12:17:03 1995 Jim Kingdon + + * logmsg.c (do_editor): Check for errors from stdio calls. + +Mon Oct 23 12:37:06 1995 Jim Kingdon + + * cvs.h: Don't declare valloc. Some systems (e.g. linux) declare + it in stdlib.h in a conflicting way. + +Mon Oct 23 08:41:25 1995 Jim Meyering (meyering@comco.com) + + * commit.c (commit_filesdoneproc): Use getline instead of fgets. + + * logmsg.c (do_editor): Use getline instead of fgets. + (rcsinfo_proc): Likewise. + + * logmsg.c (do_editor): Lose if fclose of temp file output + stream fails. + +Mon Oct 23 11:59:41 1995 Norbert Kiesel + + * cvs.h: add valloc declaration + + * server.h: add server_cleanup prototype + + * server.c: remove server_cleanup prototype + + * mkmodules.c (server_cleanup): fix parameter type + + * server.c: encapsulate wait_sig in #ifdef sun (it's only used in + code which is also encapsulated in #ifdef sun) + + * rcscmds.c (RCS_deltag, RCS_lock): add definition of noerr + parameter + + * error.c: include cvs.h instead of config.h, add USE(rcsid) + + * error.c (error): fix parameter type + + * update.c (join_file): encapsulate recent changes from garyo + within #ifdef SERVER_SUPPORT + +Sun Oct 22 13:47:53 1995 J.T. Conklin + + * client.c (update_entries): Fix memory leak; free mode_string and + file_timestamp. + (send_fileproc): Fix memory leak; call freevers_ts before exiting. + + * module.c (do_module): Partially fix memory leak; added + variable so that the address of memory allocated by line2argv + is retained, but comment out the call to free_names. Freeing + the vector at that point loses because some of the elements + may be used later in the function. + (cat_module): fix memory leak. + + * recurse.c (start_recursion): Fix memory leak; free return + value of Name_Repository after it has been used. + +Sat Oct 21 23:24:26 1995 Jim Meyering (meyering@comco.com) + + * client.c (send_modified) [LINES_CRLF_TERMINATED]: Comment text + after #endif. + +Fri Oct 20 14:41:49 1995 Jim Kingdon + + * sanity.sh: Add test 87a, to test for bug fixed by garyo in + change below. + +Fri Oct 20 10:59:58 1995 Gary Oberbrunner + + * update.c (join_file): send file back to client even if no + conflicts were detected, by calling Register(). + +Fri Oct 20 10:46:45 1995 Norbert Kiesel + + * lock.c: Add prototype for Check_Owner + +Thu Oct 19 16:38:14 1995 Jim Meyering (meyering@comco.com) + + * lock.c (Check_Owner): Declare function `static int'. + +Thu Oct 19 14:58:40 1995 Jim Kingdon + + * expand_path.c (expand_variable): Fix typo ('*'->'('). + +Thu Oct 19 14:58:40 1995 Jim Kingdon + + * commit.c (commit_filesdoneproc): Check for errors from fopen, + fgets, and fclose. + + * rcscmds.c (RCS_merge): Remove comment about rcsmerge -E. + Hacking CVS was never a very good solution; the situation is fixed + in RCS 5.7, and is documented in ../INSTALL. + +Thu Oct 19 15:06:15 1995 Jim Meyering (meyering@comco.com) + + * filesubr.c (xchmod): Parenthesize arithmetic in operand of | + to placate gcc -Wall. + + * expand_path.c (expand_path): Parenthesize assignments used as + truth values to placate gcc -Wall. + + * commit.c (checkaddfile): Remove dcls of unused variables. + * lock.c (unlock): Remove dcl of unused variable. + +Thu Oct 19 14:58:40 1995 Jim Kingdon + + * root.c (Create_Root): If noexec, don't create CVS/Root. + +Wed Oct 18 11:19:40 1995 J.T. Conklin + + * lock.c (unlock): Change order of comparison so that Check_Owner + is called only if other conditions are true. This performance + enhancement was broken when the AFS support was added. + +Wed Oct 18 12:51:33 1995 Karl Fogel + + * main.c (main): check if argv[0] is "pserver" with else-if, not + if, since we've already asked if it's "kserver". + +Tue Oct 17 18:09:23 1995 Warren Jones + and Jim Kingdon + + * sanity.sh: Deal with supplying a relative cvs filename, or + with a cvs filename which doesn't have basename "cvs". + +Mon Oct 16 15:58:31 1995 Vince Demarco + + * parseinfo.c (Parse_Info): if the Keyword isn't ALL the current + version doesn't use the expanded variable, It should. + +Mon Oct 16 15:58:31 1995 Gary Oberbrunner + and Jim Kingdon + + * server.c (server_register): Don't pass NULL to printf if tag, + date, or conflict is NULL. + +Thu Oct 12 12:13:42 1995 Karl Fogel + + * main.c (main): begin to handle "pserver"; support not complete + yet, however. + +Thu Oct 12 02:52:13 1995 Roland McGrath + + * expand_path.c: Don't #include , since cvs.h already does, + and not all systems' s are protected from multiple inclusion. + * login.c: Likewise. + +Wed Oct 11 15:23:24 1995 Karl Fogel + + * login.c (login): handle everything correctly now. + +Wed Oct 11 12:02:48 1995 Norbert Kiesel + + * rcs.c (RCS_gettag): support RCS keyword Name + +Tue Oct 10 19:11:16 1995 Karl Fogel + + * options.h.in (CVS_LOGIN): discuss, but leave commented out. + The "cvs login" command is still under construction; however, the + repository was changing so fast that instead of creating a branch + and dealing with the attendant hair, I'm just developing on the + trunk, making sure that everything is surrounded by "#ifdef + CVS_LOGIN ... #endif" so I don't get in anyone's way. + + * login.c: include cvs.h before checking CVS_LOGIN, so it has a + chance to get defined before we ask if it's defined. + (login): oops, use semi not comma in `for' loop init. + + * Makefile.in (SOURCES, OBJECTS): include login.c, login.o. + + * main.c: added protoype for login(). + Added "login" entry to cmds[]. + (usg): added line about "login". + + * login.c: new file. + +Tue Oct 10 18:33:47 1995 Karl Fogel + + * Makefile.in (COMMON_OBJECTS): added error.o. + (OBJECTS): took error.o out; it's in COMMON_OBJECTS now. + +Tue Oct 10 12:02:37 1995 Thorsten Lockert + + * cvsbug.sh: Cater to lame versions of sh (4.4BSD ash) by using + ${foo-bar} instead of `if....`. + +Tue Oct 10 12:02:37 1995 Jim Kingdon + + * remove.c (remove_fileproc): If noexec, don't remove file. Check + for error when removing file. + +Sun Oct 8 12:32:15 1995 Peter Wemm + + * run.c: detect/use POSIX/BSD style reliable signals for critical + section masking etc. Helps prevent stray locks on interruption. + +Sat Oct 7 23:26:54 1995 Norbert Kiesel + + * admin.c (admin): If group CVS_ADMIN_GROUP exists, allow only + users in that group to use "cvs admin". + * options.h.in: Default CVS_ADMIN_GROUP to "cvsadmin". + +Sat Oct 7 23:05:24 1995 Norbert Kiesel + + * add.c, checkout.c, commit.c, cvs.h, filesubr.c, import.c, + lock.c, main.c, modules.c, options.h.in: New variable cvsumask + which is used to set mode of files in repository (regardless of + umask in effect when cvs is run). + +Sat Oct 7 22:40:17 1995 Stephen Bailey + + * lock.c: Include AFSCVS ifdefs to deal with AFS's lack of + correspondance between userid's from stat and from geteuid. + +Sat Oct 7 22:28:49 1995 Scott Carson + + * add.c (add): Pass -ko, not -k -ko, to set keyword expansion options. + + * admin.c (admin): Don't skip first argument when sending to server. + +Fri Oct 6 21:45:03 1995 Jim Kingdon + + * version.c: Version 1.6.1. + +Fri Oct 6 21:31:28 1995 Jeff Johnson + + * cvs.h, admin.c, client.c, commit.c, log.c, modules.c, + parseinfo.c, patch.c, recurse.c, rtag.c, status.c, tag.c: + Prototype when dealing in pointers to functions. + +Fri Oct 6 21:07:22 1995 Mark H. Wilkinson + + * cvsrc.c (read_cvsrc): fix look up of command names in cvsrc file + to use full name from command table rather than possible nickname + in argv. Fixes errors with things like `cvs di' when cvsrc has + `diff -u5' in it. + +Thu Aug 3 01:03:52 1995 Vince DeMarco + + * parseinfo.c (Parse_Info): Add code to call expand_path function + instead of using built in code. + + * wrapper.c (wrap_add): Add code to call expand_path function to + expand all built in variables. + + * expand_path.c (New file): expand things that look like + environmental variables (only expand local CVS environmental + variables) and user names like ~/. + * cvs.h: Declare expand_path. + + * Makefile.in (SOURCES, OBJECTS): Added expand_path.c, + expand_path.o. + +Fri Oct 6 14:03:09 1995 Jim Kingdon + + * ignore.c (ign_setup): Don't try to look for a file in CVSroot if + client. (The recent tightening of the error checking detects this). + + * commit.c (checkaddfile): Don't try to pass options if it is "". + +Thu Oct 5 18:04:46 1995 Karl Fogel + + * sanity.sh: unset CVSREAD, since it causes the script to bomb. + +Thu Oct 5 18:29:17 1995 Jim Kingdon + + * remove.c, add.c, commit.c, cvs.h: Remove CVSEXT_OPT stuff; it + has been broken for ages and the options are already stored in the + Entries file. + +Thu Oct 5 18:20:13 1995 Norbert Kiesel + + * commit.c (checkaddfile): New argument options; pass it to RCS. + (commit_fileproc): Pass it. + Tue Oct 3 09:26:00 1995 Karl Fogel * version.c: upped to 1.6. @@ -40,11 +1647,11 @@ Fri Sep 29 13:22:44 1995 Jim Blandy * diff.c (diff): Doc fix. Fri Sep 29 14:32:36 1995 Norbert Kiesel - + * repos.c (Short_Repository): chop superfluous "/". - + * tag.c (pretag_proc): correct user-visible string. - + * rtag.c (pretag_proc): correct user-visible string. Fri Sep 29 13:45:36 1995 Karl Fogel @@ -53,9 +1660,9 @@ Fri Sep 29 13:45:36 1995 Karl Fogel nothing. Thu Sep 28 13:37:05 1995 Larry Jones - + * server.c: ifdef ISC, include . - + Fri Sep 29 07:54:22 1995 Mike Sutton * filesubr.c (last_component): Don't use ANSI style declaration. @@ -134,7 +1741,7 @@ Thu Sep 7 19:18:00 1995 Jim Blandy Thu Sep 7 14:38:06 1995 Karl Fogel * ALL FILES: add semicolon, as indicated below. - + * cvs.h (USE): don't provide semicolon in the expansion of the USE macro; we'd rather the callers provided it themselves because that way etags doesn't get fooled. diff --git a/gnu/usr.bin/cvs/src/Makefile.in b/gnu/usr.bin/cvs/src/Makefile.in index 73478a8e619..436d1ef6cef 100644 --- a/gnu/usr.bin/cvs/src/Makefile.in +++ b/gnu/usr.bin/cvs/src/Makefile.in @@ -44,30 +44,34 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ LIBS = @LIBS@ SOURCES = add.c admin.c checkin.c checkout.c classify.c client.c commit.c \ -create_adm.c cvsrc.c diff.c entries.c find_names.c hash.c history.c ignore.c \ -import.c lock.c log.c logmsg.c main.c modules.c myndbm.c no_diff.c \ +create_adm.c cvsrc.c diff.c edit.c entries.c error.c expand_path.c \ +fileattr.c find_names.c hash.c history.c ignore.c import.c \ +lock.c log.c login.c logmsg.c main.c modules.c myndbm.c no_diff.c \ parseinfo.c patch.c rcs.c rcscmds.c recurse.c release.c remove.c repos.c \ -root.c rtag.c server.c status.c subr.c filesubr.c run.c tag.c update.c \ -wrapper.c vers_ts.c version.c +root.c rtag.c scramble.c server.c status.c subr.c filesubr.c run.c \ +tag.c update.c watch.c wrapper.c vers_ts.c version.c MSOURCES = mkmodules.c -OBJECTS = add.o admin.o checkin.o checkout.o classify.o commit.o \ -create_adm.o cvsrc.o diff.o entries.o find_names.o hash.o history.o \ -ignore.o import.o lock.o log.o logmsg.o main.o modules.o myndbm.o no_diff.o \ +OBJECTS = add.o admin.o checkin.o checkout.o classify.o client.o commit.o \ +create_adm.o cvsrc.o diff.o edit.o entries.o expand_path.o \ +fileattr.o find_names.o hash.o history.o ignore.o import.o \ +lock.o log.o login.o logmsg.o main.o modules.o myndbm.o no_diff.o \ parseinfo.o patch.o rcs.o rcscmds.o recurse.o release.o remove.o repos.o \ -root.o rtag.o status.o tag.o update.o wrapper.o vers_ts.o server.o client.o +root.o rtag.o scramble.o server.o status.o tag.o update.o \ +watch.o wrapper.o vers_ts.o MOBJECTS = hash.o mkmodules.o myndbm.o -COMMON_OBJECTS = subr.o filesubr.o run.o version.o +COMMON_OBJECTS = subr.o filesubr.o run.o version.o error.o -HEADERS = cvs.h rcs.h hash.h myndbm.h patchlevel.h \ - update.h server.h client.h +HEADERS = cvs.h rcs.h hash.h myndbm.h \ + update.h server.h client.h error.h fileattr.h edit.h watch.h + +TAGFILES = $(HEADERS) options.h.in $(SOURCES) $(MSOURCES) DISTFILES = .cvsignore Makefile.in ChangeLog ChangeLog.fsf \ NOTES README-rm-add \ - sanity.sh cvsbug.sh \ - $(HEADERS) options.h.in $(SOURCES) $(MSOURCES) + sanity.sh cvsbug.sh $(TAGFILES) PROGS = cvs mkmodules cvsbug @@ -82,7 +86,7 @@ INCLUDES = -I. -I.. -I$(srcdir) -I$(top_srcdir)/lib .c.o: $(CC) $(CPPFLAGS) $(INCLUDES) $(DEFS) $(CFLAGS) -c $< -all: $(PROGS) +all: Makefile $(PROGS) .PHONY: all saber_cvs: @@ -121,11 +125,11 @@ remotecheck: all $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs .PHONY: remotecheck -tags: $(DISTFILES) - ctags $(DISTFILES) +tags: $(TAGFILES) + ctags $(TAGFILES) -TAGS: $(DISTFILES) - etags `for i in $(DISTFILES); do echo $(srcdir)/$$i; done` +TAGS: $(TAGFILES) + etags `for i in $(TAGFILES); do echo $(srcdir)/$$i; done` ls: @echo $(DISTFILES) @@ -172,7 +176,16 @@ mkmodules: $(MOBJECTS) $(COMMON_OBJECTS) $(CC) $(LDFLAGS) -o $@ $(MOBJECTS) $(COMMON_OBJECTS) ../lib/libcvs.a $(LIBS) $(LIBIBERTY) cvsbug: cvsbug.sh - cp $(srcdir)/cvsbug.sh cvsbug + echo > .fname \ + cvs-`sed < $(srcdir)/version.c \ + -e '/version_string/!d' \ + -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \ + -e q` + sed -e 's,xLIBDIRx,$(libdir)/cvs,g' \ + -e "s,xVERSIONx,`cat .fname`,g" $(srcdir)/$@.sh > $@-t + rm -f .fname + mv $@-t $@ + chmod a+x $@ # Compilation rules. diff --git a/gnu/usr.bin/cvs/src/add.c b/gnu/usr.bin/cvs/src/add.c index d5224f16e08..fd800763254 100644 --- a/gnu/usr.bin/cvs/src/add.c +++ b/gnu/usr.bin/cvs/src/add.c @@ -101,7 +101,7 @@ add (argc, argv) int i; start_server (); ign_setup (); - option_with_arg ("-k", options); + if (options) send_arg(options); option_with_arg ("-m", message); for (i = 0; i < argc; ++i) /* FIXME: Does this erroneously call Create_Admin in error @@ -128,9 +128,9 @@ add (argc, argv) free (date); free (rcsdir); } + send_file_names (argc, argv); send_files (argc, argv, 0, 0); - if (fprintf (to_server, "add\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("add\012", 0); return get_responses_and_close (); } #endif @@ -438,7 +438,7 @@ add_directory (repository, dir) } #endif - omask = umask ((mode_t) 2); + omask = umask (cvsumask); if (CVS_MKDIR (rcsdir, 0777) < 0) { error (0, errno, "cannot mkdir %s", rcsdir); @@ -517,16 +517,7 @@ build_entry (repository, user, options, message, entries, tag) return (0); /* - * The options for the "add" command are store in the file CVS/user,p - * XXX - no they are not! - */ - (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_OPT); - fp = open_file (fname, "w+"); - if (fclose (fp) == EOF) - error(1, errno, "cannot close %s", fname); - - /* - * And the requested log is read directly from the user and stored in the + * The requested log is read directly from the user and stored in the * file user,t. If the "message" argument is set, use it as the * initial creation log (which typically describes the file). */ @@ -539,8 +530,8 @@ build_entry (repository, user, options, message, entries, tag) /* * Create the entry now, since this allows the user to interrupt us above - * without needing to clean anything up (well, we could clean up the ,p - * and ,t files, but who cares). + * without needing to clean anything up (well, we could clean up the + * ,t file, but who cares). */ (void) sprintf (line, "Initial %s", user); Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0); diff --git a/gnu/usr.bin/cvs/src/admin.c b/gnu/usr.bin/cvs/src/admin.c index b85df3622a9..ebbda9a122c 100644 --- a/gnu/usr.bin/cvs/src/admin.c +++ b/gnu/usr.bin/cvs/src/admin.c @@ -12,6 +12,9 @@ */ #include "cvs.h" +#ifdef CVS_ADMIN_GROUP +#include +#endif #ifndef lint static const char rcsid[] = "$CVSid: @(#)admin.c 1.20 94/09/30 $"; @@ -38,10 +41,37 @@ admin (argc, argv) char **argv; { int err; - +#ifdef CVS_ADMIN_GROUP + struct group *grp; +#endif if (argc <= 1) usage (admin_usage); +#ifdef CVS_ADMIN_GROUP + grp = getgrnam(CVS_ADMIN_GROUP); + /* skip usage right check if group CVS_ADMIN_GROUP does not exist */ + if (grp != NULL) + { + char *me = getcaller(); + char **grnam = grp->gr_mem; + int denied = 1; + + while (*grnam) + { + if (strcmp(*grnam, me) == 0) + { + denied = 0; + break; + } + grnam++; + } + + if (denied) + error (1, 0, "usage is restricted to members of the group %s", + CVS_ADMIN_GROUP); + } +#endif + wrap_setup (); /* skip all optional arguments to see if we have any file names */ @@ -65,26 +95,22 @@ admin (argc, argv) ign_setup (); - for (i = 1; i <= ac; ++i) + for (i = 0; i <= ac; ++i) /* XXX send -ko too with i = 0 */ send_arg (av[i]); -#if 0 + send_file_names (argc, argv); /* 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_file_names (argc, argv); -#else send_files (argc, argv, 0, 0); -#endif - if (fprintf (to_server, "admin\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("admin\012", 0); return get_responses_and_close (); } #endif /* CLIENT_SUPPORT */ /* start the recursion processor */ - err = start_recursion (admin_fileproc, (int (*) ()) NULL, admin_dirproc, - (int (*) ()) NULL, argc, argv, 0, + err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc, + (DIRLEAVEPROC) NULL, argc, argv, 0, W_LOCAL, 0, 1, (char *) NULL, 1, 0); return (err); } @@ -106,17 +132,18 @@ admin_fileproc (file, update_dir, repository, entries, srcfiles) char **argv; int argc; int retcode = 0; + int status = 0; vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, file, 0, 0, entries, srcfiles); version = vers->vn_user; if (version == NULL) - return (0); + goto exitfunc; else if (strcmp (version, "0") == 0) { error (0, 0, "cannot admin newly added file `%s'", file); - return (0); + goto exitfunc; } run_setup ("%s%s", Rcsbin, RCS); @@ -128,9 +155,12 @@ admin_fileproc (file, update_dir, repository, entries, srcfiles) if (!quiet) error (0, retcode == -1 ? errno : 0, "%s failed for `%s'", RCS, file); - return (1); + status = 1; + goto exitfunc; } - return (0); + exitfunc: + freevers_ts (&vers); + return status; } /* diff --git a/gnu/usr.bin/cvs/src/checkin.c b/gnu/usr.bin/cvs/src/checkin.c index 09a81f764ff..6a75b4cd736 100644 --- a/gnu/usr.bin/cvs/src/checkin.c +++ b/gnu/usr.bin/cvs/src/checkin.c @@ -16,6 +16,8 @@ */ #include "cvs.h" +#include "fileattr.h" +#include "edit.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)checkin.c 1.48 94/10/07 $"; @@ -66,7 +68,7 @@ Checkin (type, file, update_dir, repository, { copy_file (tocvsPath, fname); if (unlink_file_dir (file) < 0) - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "cannot remove %s", file); copy_file (tocvsPath, file); } @@ -121,7 +123,7 @@ Checkin (type, file, update_dir, repository, * If we want read-only files, muck the permissions here, before * getting the file time-stamp. */ - if (cvswrite == FALSE) + if (cvswrite == FALSE || fileattr_get (file, "_watched")) xchmod (file, 0); #ifndef DEATH_SUPPORT @@ -198,7 +200,9 @@ Checkin (type, file, update_dir, repository, else server_checked_in (file, update_dir, repository); } + else #endif + mark_up_to_date (file); return (0); } diff --git a/gnu/usr.bin/cvs/src/checkout.c b/gnu/usr.bin/cvs/src/checkout.c index 422cfeeb75f..b78eb97388e 100644 --- a/gnu/usr.bin/cvs/src/checkout.c +++ b/gnu/usr.bin/cvs/src/checkout.c @@ -89,6 +89,7 @@ static int pipeout; static int aflag; static char *options = NULL; static char *tag = NULL; +static int tag_validated = 0; static char *date = NULL; static char *join_rev1 = NULL; static char *join_rev2 = NULL; @@ -324,15 +325,13 @@ checkout (argc, argv) client_nonexpanded_setup (); } - if (fprintf - (to_server, - strcmp (command_name, "export") == 0 ? "export\n" : "co\n") - < 0) - error (1, errno, "writing to server"); + send_to_server (strcmp (command_name, "export") == 0 ? + "export\012" : "co\012", + 0); return get_responses_and_close (); } -#endif +#endif /* CLIENT_SUPPORT */ if (cat || status) { @@ -360,7 +359,12 @@ checkout (argc, argv) (void) sprintf (repository, "%s/%s/%s", CVSroot, CVSROOTADM, CVSNULLREPOS); if (!isfile (repository)) + { + mode_t omask; + omask = umask (cvsumask); (void) CVS_MKDIR (repository, 0777); + (void) umask (omask); + } /* I'm not sure whether this check is redundant. */ if (!isdir (repository)) @@ -719,13 +723,29 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten, return (1); } which = W_REPOS; + if (tag != NULL && !tag_validated) + { + tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, NULL); + tag_validated = 1; + } } else + { which = W_LOCAL | W_REPOS; + if (tag != NULL && !tag_validated) + { + tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, + repository); + tag_validated = 1; + } + } if (tag != NULL || date != NULL) which |= W_ATTIC; + /* FIXME: We don't call tag_check_valid on join_rev1 and join_rev2 + yet (make sure to handle ':' correctly if we do, though). */ + /* * if we are going to be recursive (building dirs), go ahead and call the * update recursion processor. We will be recursive unless either local @@ -755,7 +775,7 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten, entries = Entries_Open (0); for (i = 1; i < *pargc; i++) { - char line[MAXLINELEN]; + char *line; char *user; Vers_TS *vers; @@ -764,10 +784,12 @@ checkout_proc (pargc, argv, where, mwhere, mfile, shorten, force_tag_match, 0, entries, (List *) NULL); if (vers->ts_user == NULL) { + line = xmalloc (strlen (user) + 15); (void) sprintf (line, "Initial %s", user); Register (entries, user, vers->vn_rcs ? vers->vn_rcs : "0", line, vers->options, vers->tag, vers->date, (char *) 0); + free (line); } freevers_ts (&vers); } diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c index 5f34c5dcd7b..0fa3299e4d9 100644 --- a/gnu/usr.bin/cvs/src/client.c +++ b/gnu/usr.bin/cvs/src/client.c @@ -1,25 +1,33 @@ /* CVS client-related stuff. */ #include "cvs.h" +#include "getline.h" #ifdef CLIENT_SUPPORT -#include "update.h" /* Things shared with update.c */ #include "md5.h" -#if HAVE_KERBEROS -#define CVS_PORT 1999 - +#if defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS #include #include #include +#endif /* defined(AUTH_CLIENT_SUPPORT) || HAVE_KERBEROS */ + +#ifdef AUTH_CLIENT_SUPPORT +char *get_cvs_password PROTO((char *user, char *host, char *cvsrooot)); +#endif /* AUTH_CLIENT_SUPPORT */ + +#if HAVE_KERBEROS +#define CVS_PORT 1999 + #include extern char *krb_realmofhost (); #ifndef HAVE_KRB_GET_ERR_TEXT #define krb_get_err_text(status) krb_err_txt[status] -#endif -#endif +#endif /* HAVE_KRB_GET_ERR_TEXT */ +#endif /* HAVE_KERBEROS */ + static void add_prune_candidate PROTO((char *)); @@ -62,6 +70,7 @@ static void handle_set_update_prog PROTO((char *, int)); static void handle_module_expansion PROTO((char *, int)); static void handle_m PROTO((char *, int)); static void handle_e PROTO((char *, int)); +static void handle_notified PROTO((char *, int)); #endif /* CLIENT_SUPPORT */ @@ -76,10 +85,10 @@ static void handle_e PROTO((char *, int)); char * #ifdef __STDC__ mode_to_string (mode_t mode) -#else +#else /* ! __STDC__ */ mode_to_string (mode) mode_t mode; -#endif +#endif /* __STDC__ */ { char buf[18], u[4], g[4], o[4]; int i; @@ -115,6 +124,40 @@ change_mode (filename, mode_string) char *filename; char *mode_string; { +#ifdef CHMOD_BROKEN + char *p; + int writeable = 0; + + /* We can only distinguish between + 1) readable + 2) writeable + 3) Picasso's "Blue Period" + We handle the first two. */ + p = mode_string; + while (*p != '\0') + { + if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') + { + char *q = p + 2; + while (*q != ',' && *q != '\0') + { + if (*q == 'w') + writeable = 1; + ++q; + } + } + /* Skip to the next field. */ + while (*p != ',' && *p != '\0') + ++p; + if (*p == ',') + ++p; + } + + xchmod (filename, writeable); + return 0; + +#else /* ! CHMOD_BROKEN */ + char *p; mode_t mode = 0; @@ -169,9 +212,11 @@ change_mode (filename, mode_string) if (*p == ',') ++p; } + if (chmod (filename, mode) < 0) return errno; return 0; +#endif /* ! CHMOD_BROKEN */ } #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ @@ -189,20 +234,68 @@ int client_active; int client_prune_dirs; +static int cvsroot_parsed = 0; + +static List *ignlist = (List *) NULL; + /* Set server_host and server_cvsroot. */ static void parse_cvsroot () { char *p; +#ifdef AUTH_CLIENT_SUPPORT + static char *access_method; +#endif /* AUTH_CLIENT_SUPPORT */ + + /* Don't go through the trouble twice. */ + if (cvsroot_parsed) + return; server_host = xstrdup (CVSroot); + +#ifdef AUTH_CLIENT_SUPPORT + if ((server_host[0] == ':')) + { + /* Access method specified, as in + * "cvs -d :pserver:user@host:/path". + * We need to get past that part of CVSroot before parsing the + * rest of it. + */ + access_method = p = &(server_host[1]); + + if (! *access_method) + error (1, 0, "bad CVSroot: %s", CVSroot); + + if (! *(p = strchr (access_method, ':'))) + error (1, 0, "bad CVSroot: %s", CVSroot); + + *p = '\0'; + p++; + + server_host = p; + + if (! *server_host) + error (1, 0, "bad CVSroot: %s", CVSroot); + + if (strcmp (access_method, "pserver") == 0) + use_authenticating_server = 1; + else + error (1, 0, "unknown access method: %s", access_method); + } +#endif /* AUTH_CLIENT_SUPPORT */ + + /* First get just the pathname. */ server_cvsroot = strchr (server_host, ':'); *server_cvsroot = '\0'; ++server_cvsroot; - - if ( (p = strchr (server_host, '@')) == NULL) { + + /* Then deal with host and possible user. */ + if ( (p = strchr (server_host, '@')) == NULL) + { server_user = NULL; - } else { + } + else + { server_user = server_host; server_host = p; ++server_host; @@ -210,20 +303,36 @@ parse_cvsroot () } client_active = 1; + cvsroot_parsed = 1; } +#ifdef NO_SOCKET_TO_FD +/* Under certain circumstances, we must communicate with the server + via a socket using send() and recv(). This is because under some + operating systems (OS/2 and Windows 95 come to mind), a socket + cannot be converted to a file descriptor -- it must be treated as a + socket and nothing else. */ +static int use_socket_style = 0; +static int server_sock; +#endif /* NO_SOCKET_TO_FD */ + /* Stream to write to the server. */ -FILE *to_server; +static FILE *to_server; /* Stream to read from the server. */ -FILE *from_server; +static FILE *from_server; + +/* We might want to log client/server traffic. */ +static FILE *from_server_logfile; +static FILE *to_server_logfile; #if ! RSH_NOT_TRANSPARENT /* Process ID of rsh subprocess. */ static int rsh_pid = -1; -#endif +#endif /* ! RSH_NOT_TRANSPARENT */ + /* - * Read a line from the server. + * Read a line from the server. Result does not include the terminating \n. * * Space for the result is malloc'd and should be freed by the caller. * @@ -237,21 +346,46 @@ read_line (resultp, eof_ok) { int c; char *result; - int input_index = 0; - int result_size = 80; + size_t input_index = 0; + size_t result_size = 80; + +#ifdef NO_SOCKET_TO_FD + if (! use_socket_style) +#endif /* NO_SOCKET_TO_FD */ + fflush (to_server); - fflush (to_server); result = (char *) xmalloc (result_size); while (1) { - c = getc (from_server); + +#ifdef NO_SOCKET_TO_FD + if (use_socket_style) + { + char ch; + /* Yes, this sucks performance-wise. Short of implementing + our own buffering, I'm not sure how to effect a big + improvement. We could at least avoid calling + read_from_server() for each character if we were willing + to duplicate a lot of its code, but I'm not sure that's + worth it. */ + read_from_server (&ch, 1); + c = ch; + } + else +#endif /* NO_SOCKET_TO_FD */ + c = getc (from_server); if (c == EOF) { free (result); - if (ferror (from_server)) - error (1, errno, "reading from server"); + +#ifdef NO_SOCKET_TO_FD + if (! use_socket_style) +#endif /* NO_SOCKET_TO_FD */ + if (ferror (from_server)) + error (1, errno, "reading from server"); + /* It's end of file. */ if (eof_ok) return 0; @@ -276,12 +410,31 @@ read_line (resultp, eof_ok) /* Terminate it just for kicks, but we *can* deal with embedded NULs. */ result[input_index] = '\0'; +#ifdef NO_SOCKET_TO_FD + if (! use_socket_style) +#endif /* NO_SOCKET_TO_FD */ + { + /* + * If we're using socket style, then everything has already + * been logged because read_from_server() was used to get the + * individual chars, and read_from_server() logs already. + */ + if (from_server_logfile) + { + if (fwrite (result, 1, input_index, from_server_logfile) + < input_index) + error (0, errno, "writing to from-server logfile"); + putc ('\n', from_server_logfile); + } + } + if (resultp == NULL) free (result); return input_index; } #endif /* CLIENT_SUPPORT */ + #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) @@ -306,7 +459,7 @@ int filter_through_gunzip (fd, dir, pidp) int fd, dir; pid_t *pidp; { - static char *gunzip_argv[2] = { "gunzip" }; + static char *gunzip_argv[3] = { "gunzip", "-d" }; return filter_stream_through_program (fd, dir, &gunzip_argv[0], pidp); } @@ -392,8 +545,9 @@ handle_valid_requests (args, len) * Server wants to know if we have this, to enable the * feature. */ - if (fprintf(to_server, "%s\n", rq->name) < 0) - error (1, errno, "writing to server"); + send_to_server (rq->name, 0); + send_to_server ("\012", 0); + if (!strcmp("UseUnchanged",rq->name)) use_unchanged = 1; } @@ -443,7 +597,7 @@ get_short_pathname (name) * SHORT_PATHNAME. When we call FUNC, the curent directory points to * the directory portion of SHORT_PATHNAME. */ -static char *last_dirname; +static char *last_dir_name; static void call_in_directory (pathname, func, data) @@ -454,7 +608,7 @@ call_in_directory (pathname, func, data) { static List *last_entries; - char *dirname; + char *dir_name; char *filename; /* Just the part of pathname relative to toplevel_repos. */ char *short_pathname = get_short_pathname (pathname); @@ -515,17 +669,17 @@ call_in_directory (pathname, func, data) else *p = '\0'; - dirname = xstrdup (short_pathname); - p = strrchr (dirname, '/'); + dir_name = xstrdup (short_pathname); + p = strrchr (dir_name, '/'); if (p == NULL) { - dirname = xrealloc (dirname, 2); - dirname[0] = '.'; dirname[1] = '\0'; + dir_name = xrealloc (dir_name, 2); + dir_name[0] = '.'; dir_name[1] = '\0'; } else *p = '\0'; if (client_prune_dirs) - add_prune_candidate (dirname); + add_prune_candidate (dir_name); filename = strrchr (short_repos, '/'); if (filename == NULL) @@ -542,12 +696,12 @@ call_in_directory (pathname, func, data) strcat (short_pathname, filename); } - if (last_dirname == NULL - || strcmp (last_dirname, dirname) != 0) + if (last_dir_name == NULL + || strcmp (last_dir_name, dir_name) != 0) { - if (last_dirname) - free (last_dirname); - last_dirname = dirname; + if (last_dir_name) + free (last_dir_name); + last_dir_name = dir_name; if (toplevel_wd[0] == '\0') if (getwd (toplevel_wd) == NULL) @@ -556,17 +710,17 @@ call_in_directory (pathname, func, data) if (chdir (toplevel_wd) < 0) error (1, errno, "could not chdir to %s", toplevel_wd); - if (chdir (dirname) < 0) + if (chdir (dir_name) < 0) { char *dir; char *dirp; - if (errno != ENOENT) - error (1, errno, "could not chdir to %s", dirname); + if (! existence_error (errno)) + error (1, errno, "could not chdir to %s", dir_name); /* Directory does not exist, we need to create it. */ - dir = xmalloc (strlen (dirname) + 1); - dirp = dirname; + dir = xmalloc (strlen (dir_name) + 1); + dirp = dir_name; rdirp = reposdirname; /* This algorithm makes nested directories one at a time @@ -578,11 +732,11 @@ call_in_directory (pathname, func, data) 2) .. foo/bar .. /foo/bar 3) .. foo/bar/baz .. /foo/bar/baz - As you can see, we're just stepping along DIRNAME (with + As you can see, we're just stepping along DIR_NAME (with DIRP) and REPOSDIRNAME (with RDIRP) respectively. We need to be careful when we are checking out a - module, however, since DIRNAME and REPOSDIRNAME are not + module, however, since DIR_NAME and REPOSDIRNAME are not going to be the same. Since modules will not have any slashes in their names, we should watch the output of STRCHR to decide whether or not we should use STRCHR on @@ -594,8 +748,8 @@ call_in_directory (pathname, func, data) dirp = strchr (dirp, '/'); if (dirp) { - strncpy (dir, dirname, dirp - dirname); - dir[dirp - dirname] = '\0'; + strncpy (dir, dir_name, dirp - dir_name); + dir[dirp - dir_name] = '\0'; /* Skip the slash. */ ++dirp; if (rdirp == NULL) @@ -622,15 +776,36 @@ call_in_directory (pathname, func, data) STRCHR call here). */ rdirp = NULL; - strcpy (dir, dirname); + strcpy (dir, dir_name); } if (CVS_MKDIR (dir, 0777) < 0) { - if (errno != EEXIST) - error (1, errno, "cannot make directory %s", dir); - - /* It already existed, fine. Just keep going. */ + /* Now, let me get this straight. In IBM C/C++ + * under OS/2, the error string for EEXIST is: + * + * "The file already exists", + * + * and the error string for EACCESS is: + * + * "The file or directory specified is read-only". + * + * Nonetheless, mkdir() will set EACCESS if the + * directory *exists*, according both to the + * documentation and its actual behavior. + * + * I'm sure that this made sense, to someone, + * somewhere, sometime. Just not me, here, now. + */ +#ifdef EACCESS + if ((errno != EACCESS) && (errno != EEXIST)) + error (1, errno, "cannot make directory %s", dir); +#else /* ! defined(EACCESS) */ + if ((errno != EEXIST)) + error (1, errno, "cannot make directory %s", dir); +#endif /* defined(EACCESS) */ + + /* It already existed, fine. Just keep going. */ } else if (strcmp (command_name, "export") == 0) /* Don't create CVSADM directories if this is export. */ @@ -680,8 +855,8 @@ call_in_directory (pathname, func, data) } while (dirp != NULL); free (dir); /* Now it better work. */ - if (chdir (dirname) < 0) - error (1, errno, "could not chdir to %s", dirname); + if (chdir (dir_name) < 0) + error (1, errno, "could not chdir to %s", dir_name); } if (strcmp (command_name, "export") != 0) @@ -692,7 +867,7 @@ call_in_directory (pathname, func, data) } } else - free (dirname); + free (dir_name); free (reposdirname); (*func) (data, last_entries, short_pathname, filename); if (reposname != NULL) @@ -718,8 +893,8 @@ copy_a_file (data, ent_list, short_pathname, filename) static void handle_copy_file (args, len) - char *args; - int len; + char *args; + int len; { call_in_directory (args, copy_a_file, (char *)NULL); } @@ -735,8 +910,8 @@ static unsigned char stored_checksum[16]; static void handle_checksum (args, len) - char *args; - int len; + char *args; + int len; { char *s; char buf[3]; @@ -764,6 +939,24 @@ handle_checksum (args, len) stored_checksum_valid = 1; } +static int stored_mode_valid; +static char *stored_mode; + +static void handle_mode PROTO ((char *, int)); + +static void +handle_mode (args, len) + char *args; + int len; +{ + if (stored_mode_valid) + error (1, 0, "protocol error: duplicate Mode"); + if (stored_mode != NULL) + free (stored_mode); + stored_mode = xstrdup (args); + stored_mode_valid = 1; +} + /* * If we receive a patch, but the patch program fails to apply it, we * want to request the original file. We keep a list of files whose @@ -808,19 +1001,68 @@ update_entries (data_arg, ent_list, short_pathname, filename) char *entries_line; struct update_entries_data *data = (struct update_entries_data *)data_arg; + char *cp; + char *user; + char *vn; + /* Timestamp field. Always empty according to the protocol. */ + char *ts; + char *options; + char *tag; + char *date; + char *tag_or_date; + char *scratch_entries; + int bin; + read_line (&entries_line, 0); + /* + * Parse the entries line. + */ + if (strcmp (command_name, "export") != 0) + { + scratch_entries = xstrdup (entries_line); + + if (scratch_entries[0] != '/') + error (1, 0, "bad entries line `%s' from server", entries_line); + user = scratch_entries + 1; + if ((cp = strchr (user, '/')) == NULL) + error (1, 0, "bad entries line `%s' from server", entries_line); + *cp++ = '\0'; + vn = cp; + if ((cp = strchr (vn, '/')) == NULL) + error (1, 0, "bad entries line `%s' from server", entries_line); + *cp++ = '\0'; + + ts = cp; + if ((cp = strchr (ts, '/')) == NULL) + error (1, 0, "bad entries line `%s' from server", entries_line); + *cp++ = '\0'; + options = cp; + if ((cp = strchr (options, '/')) == NULL) + error (1, 0, "bad entries line `%s' from server", entries_line); + *cp++ = '\0'; + tag_or_date = cp; + + /* If a slash ends the tag_or_date, ignore everything after it. */ + cp = strchr (tag_or_date, '/'); + if (cp != NULL) + *cp = '\0'; + tag = (char *) NULL; + date = (char *) NULL; + if (*tag_or_date == 'T') + tag = tag_or_date + 1; + else if (*tag_or_date == 'D') + date = tag_or_date + 1; + } + if (data->contents == UPDATE_ENTRIES_UPDATE || data->contents == UPDATE_ENTRIES_PATCH) { char *size_string; char *mode_string; int size; - int size_read; - int size_left; int fd; char *buf; - char *buf2; char *temp_filename; int use_gzip, gzip_status; pid_t gzip_pid = 0; @@ -843,11 +1085,29 @@ update_entries (data_arg, ent_list, short_pathname, filename) temp_filename = xmalloc (strlen (filename) + 80); #ifdef _POSIX_NO_TRUNC sprintf (temp_filename, ".new.%.9s", filename); -#else +#else /* _POSIX_NO_TRUNC */ sprintf (temp_filename, ".new.%s", filename); -#endif +#endif /* _POSIX_NO_TRUNC */ buf = xmalloc (size); - fd = open (temp_filename, O_WRONLY | O_CREAT | O_TRUNC, 0777); + + /* Some systems, like OS/2 and Windows NT, end lines with CRLF + instead of just LF. Format translation is done in the C + library I/O funtions. Here we tell them whether or not to + convert -- if this file is marked "binary" with the RCS -kb + 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; + + fd = open (temp_filename, + O_WRONLY | O_CREAT | O_TRUNC | (bin ? OPEN_BINARY : 0), + 0777); + if (fd < 0) error (1, errno, "writing %s", short_pathname); @@ -856,26 +1116,12 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (size > 0) { - buf2 = buf; - size_left = size; - while ((size_read = fread (buf2, 1, size_left, from_server)) != size_left) - { - if (feof (from_server)) - /* FIXME: Should delete temp_filename. */ - error (1, 0, "unexpected end of file from server"); - else if (ferror (from_server)) - /* FIXME: Should delete temp_filename. */ - error (1, errno, "reading from server"); - else - { - /* short reads are ok if we keep trying */ - buf2 += size_read; - size_left -= size_read; - } - } - if (write (fd, buf, size) != size) - error (1, errno, "writing %s", short_pathname); + read_from_server (buf, size); + + if (write (fd, buf, size) != size) + error (1, errno, "writing %s", short_pathname); } + if (close (fd) < 0) error (1, errno, "writing %s", short_pathname); if (gzip_pid > 0) @@ -897,19 +1143,24 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (data->contents == UPDATE_ENTRIES_UPDATE) { #ifdef LINES_CRLF_TERMINATED - if (use_gzip) + + /* `bin' is non-zero iff `options' contains "-kb", meaning + treat this file as binary. */ + + if (use_gzip && (! bin)) { convert_file (temp_filename, O_RDONLY | OPEN_BINARY, filename, O_WRONLY | O_CREAT | O_TRUNC); if (unlink (temp_filename) < 0) - error (0, errno, "warning: couldn't delete %s", temp_filename); + error (0, errno, "warning: couldn't delete %s", + temp_filename); } else rename_file (temp_filename, filename); -#else +#else /* ! LINES_CRLF_TERMINATED */ rename_file (temp_filename, filename); -#endif +#endif /* LINES_CRLF_TERMINATED */ } else { @@ -948,7 +1199,7 @@ update_entries (data_arg, ent_list, short_pathname, filename) rename_file (backup, filename); /* Get rid of the patch reject file. */ - path_tmp = xmalloc (strlen (filename + 10)); + path_tmp = xmalloc (strlen (filename) + 10); strcpy (path_tmp, filename); strcat (path_tmp, ".rej"); /* FIXME: should we really be silently ignoring errors? */ @@ -1037,64 +1288,29 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (status != 0) error (0, status, "cannot change mode of %s", short_pathname); } + + free (mode_string); free (buf); } + if (stored_mode_valid) + change_mode (filename, stored_mode); + stored_mode_valid = 0; + /* * Process the entries line. Do this after we've written the file, * since we need the timestamp. */ if (strcmp (command_name, "export") != 0) { - char *cp; - char *user; - char *vn; - /* Timestamp field. Always empty according to the protocol. */ - char *ts; - char *options; - char *tag; - char *date; - char *tag_or_date; char *local_timestamp; char *file_timestamp; - char *scratch_entries = xstrdup (entries_line); - - if (scratch_entries[0] != '/') - error (1, 0, "bad entries line `%s' from server", entries_line); - user = scratch_entries + 1; - if ((cp = strchr (user, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - vn = cp; - if ((cp = strchr (vn, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - - ts = cp; - if ((cp = strchr (ts, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - options = cp; - if ((cp = strchr (options, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - tag_or_date = cp; - - /* If a slash ends the tag_or_date, ignore everything after it. */ - cp = strchr (tag_or_date, '/'); - if (cp != NULL) - *cp = '\0'; - tag = (char *) NULL; - date = (char *) NULL; - if (*tag_or_date == 'T') - tag = tag_or_date + 1; - else if (*tag_or_date == 'D') - date = tag_or_date + 1; - local_timestamp = data->timestamp; if (local_timestamp == NULL || ts[0] == '+') file_timestamp = time_stamp (filename); + else + file_timestamp = NULL; /* * These special version numbers signify that it is not up to @@ -1104,10 +1320,17 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (vn[0] == '\0' || vn[0] == '0' || vn[0] == '-') local_timestamp = "dummy timestamp"; else if (local_timestamp == NULL) + { local_timestamp = file_timestamp; + mark_up_to_date (filename); + } Register (ent_list, filename, vn, local_timestamp, options, tag, date, ts[0] == '+' ? file_timestamp : NULL); + + if (file_timestamp) + free (file_timestamp); + free (scratch_entries); } free (entries_line); @@ -1269,7 +1492,7 @@ clear_static (data, ent_list, short_pathname, filename) char *short_pathname; char *filename; { - if (unlink_file (CVSADM_ENTSTAT) < 0 && errno != ENOENT) + if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); } @@ -1352,7 +1575,7 @@ clear_sticky (data, ent_list, short_pathname, filename) char *short_pathname; char *filename; { - if (unlink_file (CVSADM_TAG) < 0 && errno != ENOENT) + if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno)) error (1, errno, "cannot remove %s", CVSADM_TAG); } @@ -1484,7 +1707,7 @@ client_isemptydir (dir) if ((dirp = opendir (dir)) == NULL) { - if (errno != ENOENT) + if (! existence_error (errno)) error (0, errno, "cannot open directory %s for empty check", dir); return (0); } @@ -1546,9 +1769,7 @@ process_prune_candidates () { if (client_isemptydir (p->dir)) { - run_setup ("%s -fr", RM); - run_arg (p->dir); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); + unlink_file_dir (p->dir); } free (p->dir); q = p->next; @@ -1593,19 +1814,17 @@ send_repository (dir, repos, update_dir) if (use_directory) { - if (fprintf (to_server, "Directory ") < 0) - error (1, errno, "writing to server"); - if (fprintf (to_server, "%s", update_dir) < 0) - error (1, errno, "writing to server"); - - if (fprintf (to_server, "\n%s\n", repos) - < 0) - error (1, errno, "writing to server"); + send_to_server ("Directory ", 0); + send_to_server (update_dir, 0); + send_to_server ("\012", 1); + send_to_server (repos, 0); + send_to_server ("\012", 1); } else { - if (fprintf (to_server, "Repository %s\n", repos) < 0) - error (1, errno, "writing to server"); + send_to_server ("Repository ", 0); + send_to_server (repos, 0); + send_to_server ("\012", 1); } if (supported_request ("Static-directory")) { @@ -1618,8 +1837,7 @@ send_repository (dir, repos, update_dir) strcat (adm_name, CVSADM_ENTSTAT); if (isreadable (adm_name)) { - if (fprintf (to_server, "Static-directory\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Static-directory\012", 0); } } if (supported_request ("Sticky")) @@ -1633,26 +1851,23 @@ send_repository (dir, repos, update_dir) f = fopen (adm_name, "r"); if (f == NULL) { - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "reading %s", adm_name); } else { char line[80]; char *nl; - if (fprintf (to_server, "Sticky ") < 0) - error (1, errno, "writing to server"); + send_to_server ("Sticky ", 0); while (fgets (line, sizeof (line), f) != NULL) { - if (fprintf (to_server, "%s", line) < 0) - error (1, errno, "writing to server"); + send_to_server (line, 0); nl = strchr (line, '\n'); if (nl != NULL) break; } if (nl == NULL) - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("\012", 1); if (fclose (f) == EOF) error (0, errno, "closing %s", adm_name); } @@ -1668,26 +1883,26 @@ send_repository (dir, repos, update_dir) f = fopen (adm_name, "r"); if (f == NULL) { - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "reading %s", adm_name); } else { char line[80]; char *nl; - if (fprintf (to_server, "Checkin-prog ") < 0) - error (1, errno, "writing to server"); + + send_to_server ("Checkin-prog ", 0); + while (fgets (line, sizeof (line), f) != NULL) { - if (fprintf (to_server, "%s", line) < 0) - error (1, errno, "writing to server"); + send_to_server (line, 0); + nl = strchr (line, '\n'); if (nl != NULL) break; } if (nl == NULL) - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("\012", 1); if (fclose (f) == EOF) error (0, errno, "closing %s", adm_name); } @@ -1703,26 +1918,26 @@ send_repository (dir, repos, update_dir) f = fopen (adm_name, "r"); if (f == NULL) { - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "reading %s", adm_name); } else { char line[80]; char *nl; - if (fprintf (to_server, "Update-prog ") < 0) - error (1, errno, "writing to server"); + + send_to_server ("Update-prog ", 0); + while (fgets (line, sizeof (line), f) != NULL) { - if (fprintf (to_server, "%s", line) < 0) - error (1, errno, "writing to server"); + send_to_server (line, 0); + nl = strchr (line, '\n'); if (nl != NULL) break; } if (nl == NULL) - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("\012", 1); if (fclose (f) == EOF) error (0, errno, "closing %s", adm_name); } @@ -1815,6 +2030,7 @@ send_a_repository (dir, repository, update_dir) send_repository (dir, repository, update_dir); } +/* The "expanded" modules. */ static int modules_count; static int modules_allocated; static char **modules_vector; @@ -1842,6 +2058,10 @@ handle_module_expansion (args, len) ++modules_count; } +/* Original, not "expanded" modules. */ +static int module_argc; +static char **module_argv; + void client_expand_modules (argc, argv, local) int argc; @@ -1851,11 +2071,18 @@ client_expand_modules (argc, argv, local) int errs; int i; + module_argc = argc; + module_argv = (char **) xmalloc ((argc + 1) * sizeof (module_argv[0])); + for (i = 0; i < argc; ++i) + module_argv[i] = xstrdup (argv[i]); + module_argv[argc] = NULL; + for (i = 0; i < argc; ++i) send_arg (argv[i]); send_a_repository ("", server_cvsroot, ""); - if (fprintf (to_server, "expand-modules\n") < 0) - error (1, errno, "writing to server"); + + send_to_server ("expand-modules\012", 0); + errs = get_server_responses (); if (last_repos != NULL) free (last_repos); @@ -1864,7 +2091,7 @@ client_expand_modules (argc, argv, local) free (last_update_dir); last_update_dir = NULL; if (errs) - error (errs, 0, ""); + error (errs, 0, "cannot expand modules"); } void @@ -1873,13 +2100,20 @@ client_send_expansions (local) { int i; char *argv[1]; + + /* Send the original module names. The "expanded" module name might + not be suitable as an argument to a co request (e.g. it might be + the result of a -d argument in the modules file). It might be + 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); + for (i = 0; i < modules_count; ++i) { argv[0] = modules_vector[i]; if (isfile (argv[0])) send_files (1, argv, local, 0); - else - send_file_names (1, argv); } send_a_repository ("", server_cvsroot, ""); } @@ -1916,9 +2150,9 @@ struct response responses[] = { #ifdef CLIENT_SUPPORT #define RSP_LINE(n, f, t, s) {n, f, t, s} -#else +#else /* ! CLIENT_SUPPORT */ #define RSP_LINE(n, f, t, s) {n, s} -#endif +#endif /* CLIENT_SUPPORT */ RSP_LINE("ok", handle_ok, response_type_ok, rs_essential), RSP_LINE("error", handle_error, response_type_error, rs_essential), @@ -1932,6 +2166,7 @@ struct response responses[] = RSP_LINE("Updated", handle_updated, response_type_normal, rs_essential), RSP_LINE("Merged", handle_merged, response_type_normal, rs_essential), RSP_LINE("Patched", handle_patched, response_type_normal, rs_optional), + RSP_LINE("Mode", handle_mode, response_type_normal, rs_optional), RSP_LINE("Removed", handle_removed, response_type_normal, rs_essential), RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal, rs_optional), @@ -1949,6 +2184,7 @@ struct response responses[] = rs_optional), RSP_LINE("Set-update-prog", handle_set_update_prog, response_type_normal, rs_optional), + RSP_LINE("Notified", handle_notified, response_type_normal, rs_optional), RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal, rs_optional), RSP_LINE("M", handle_m, response_type_normal, rs_essential), @@ -1962,10 +2198,117 @@ struct response responses[] = #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ #ifdef CLIENT_SUPPORT +/* + * If LEN is 0, then send_to_server() computes string's length itself. + * + * Therefore, pass the real length when transmitting data that might + * contain 0's. + */ +void +send_to_server (str, len) + char *str; + size_t len; +{ + if (len == 0) + len = strlen (str); + +#ifdef NO_SOCKET_TO_FD + if (use_socket_style) + { + int just_wrtn = 0; + int wrtn = 0; + + while (wrtn < len) + { + just_wrtn = send (server_sock, str + wrtn, len - wrtn, 0); + + if (just_wrtn == -1) + error (1, errno, "reading from server socket"); + + wrtn += just_wrtn; + if (wrtn == len) + break; + } + } + else +#endif /* NO_SOCKET_TO_FD */ + { + size_t wrtn = 0; + + while (wrtn < len) + { + wrtn += fwrite (str + wrtn, 1, len - wrtn, to_server); + + if (wrtn == len) + break; + + if (ferror (to_server)) + error (1, errno, "writing to server"); + if (feof (to_server)) + error (1, 0, "premature end-of-file on server"); + } + } + + if (to_server_logfile) + if (fwrite (str, 1, len, to_server_logfile) < len) + error (0, errno, "writing to to-server logfile"); +} + /* - * Get some server responses and process them. Returns nonzero for - * error, 0 for success. + * Read LEN bytes from the server or die trying. */ +void +read_from_server (buf, len) + char *buf; + size_t len; +{ +#ifdef NO_SOCKET_TO_FD + if (use_socket_style) + { + int just_red = 0; + int red = 0; + + while (red < len) + { + just_red = recv (server_sock, buf + red, len - red, 0); + + if (just_red == -1) + error (1, errno, "reading from server"); + + red += just_red; + if (red == len) + break; + } + } + else +#endif /* NO_SOCKET_TO_FD */ + { + 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, "premature end-of-file from server"); + } + } + + /* 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. */ int get_server_responses () { @@ -2007,6 +2350,16 @@ get_server_responses () /* Get the responses and then close the connection. */ int server_fd = -1; +/* + * Flag var; we'll set it in start_server() and not one of its + * callees, such as start_rsh_server(). This means that there might + * be a small window between the starting of the server and the + * setting of this var, but all the code in that window shouldn't care + * because it's busy checking return values to see if the server got + * started successfully anyway. + */ +int server_started = 0; + int get_responses_and_close () { @@ -2017,51 +2370,72 @@ get_responses_and_close () if (client_prune_dirs) process_prune_candidates (); -#ifdef HAVE_KERBEROS - if (server_fd != -1) - { - if (shutdown (server_fd, 1) < 0) - error (1, errno, "shutting down connection to %s", server_host); - /* - * In this case, both sides of the net connection will use the - * same fd. - */ - if (fileno (from_server) != fileno (to_server)) - { - if (fclose (to_server) != 0) - error (1, errno, "closing down connection to %s", server_host); - } - } +#ifdef NO_SOCKET_TO_FD + if (use_socket_style) + { + if (shutdown (server_sock, 2) < 0) + error (1, errno, "shutting down server socket"); + } else -#endif +#endif /* NO_SOCKET_TO_FD */ + { +#if defined(HAVE_KERBEROS) || defined(AUTH_CLIENT_SUPPORT) + if (server_fd != -1) + { + if (shutdown (server_fd, 1) < 0) + error (1, errno, "shutting down connection to %s", server_host); + /* + * This test will always be true because we dup the descriptor + */ + if (fileno (from_server) != fileno (to_server)) + { + if (fclose (to_server) != 0) + error (1, errno, + "closing down connection to %s", + server_host); + } + } + else +#endif /* HAVE_KERBEROS || AUTH_CLIENT_SUPPORT */ + #ifdef SHUTDOWN_SERVER - SHUTDOWN_SERVER (fileno (to_server)); -#else - { - if (fclose (to_server) == EOF) - error (1, errno, "closing connection to %s", server_host); - } - - if (getc (from_server) != EOF) - error (0, 0, "dying gasps from %s unexpected", server_host); - else if (ferror (from_server)) - error (0, errno, "reading from %s", server_host); - - fclose (from_server); -#endif - -#if !RSH_NOT_TRANSPARENT + SHUTDOWN_SERVER (fileno (to_server)); +#else /* ! SHUTDOWN_SERVER */ + { + +#ifdef START_RSH_WITH_POPEN_RW + if (pclose (to_server) == EOF) +#else /* ! START_RSH_WITH_POPEN_RW */ + if (fclose (to_server) == EOF) +#endif /* START_RSH_WITH_POPEN_RW */ + { + error (1, errno, "closing connection to %s", server_host); + } + } + + if (getc (from_server) != EOF) + error (0, 0, "dying gasps from %s unexpected", server_host); + else if (ferror (from_server)) + error (0, errno, "reading from %s", server_host); + + fclose (from_server); +#endif /* SHUTDOWN_SERVER */ + } + +#if ! RSH_NOT_TRANSPARENT if (rsh_pid != -1 && waitpid (rsh_pid, (int *) 0, 0) == -1) - error (1, errno, "waiting for process %d", rsh_pid); -#endif + error (1, errno, "waiting for process %d", rsh_pid); +#endif /* ! RSH_NOT_TRANSPARENT */ + + server_started = 0; return errs; } #ifndef RSH_NOT_TRANSPARENT static void start_rsh_server PROTO((int *, int *)); -#endif +#endif /* RSH_NOT_TRANSPARENT */ int supported_request (name) @@ -2073,194 +2447,434 @@ supported_request (name) if (!strcmp (rq->name, name)) return rq->status == rq_supported; error (1, 0, "internal error: testing support for unknown option?"); + /* NOTREACHED */ + return 0; } -/* Contact the server. */ - + +#ifdef AUTH_CLIENT_SUPPORT void -start_server () +init_sockaddr (name, hostname, port) + struct sockaddr_in *name; + const char *hostname; + unsigned short int port; { - int tofd, fromfd; - char *log = getenv ("CVS_CLIENT_LOG"); - -#if HAVE_KERBEROS + 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 *hp; - char *hname; - const char *realm; - const char *portenv; - int port; - struct sockaddr_in sin; - int s; - KTEXT_ST ticket; - int status; - - /* - * We look up the host to give a better error message if it - * does not exist. However, we then pass server_host to - * krb_sendauth, rather than the canonical name, because - * krb_sendauth is going to do its own canonicalization anyhow - * and that lets us not worry about the static storage used by - * gethostbyname. - */ - hp = gethostbyname (server_host); - if (hp == NULL) - error (1, 0, "%s: unknown host", server_host); - hname = xmalloc (strlen (hp->h_name) + 1); - strcpy (hname, hp->h_name); + fprintf (stderr, "Unknown host %s.\n", hostname); + exit (EXIT_FAILURE); + } + name->sin_addr = *(struct in_addr *) hostinfo->h_addr; +} - realm = krb_realmofhost (hname); - portenv = getenv ("CVS_CLIENT_PORT"); - if (portenv != NULL) +int +auth_server_port_number () +{ + return CVS_AUTH_PORT; +} + + +/* + * Connect to the authenticating server. + * + * If VERIFY_ONLY is non-zero, then just verify that the password is + * correct and then shutdown the connection. In this case, the return + * values is 1 if the password was correct, 0 if not. + * + * If VERIFY_ONLY is 0, then really connect to the server. In this + * case the return value is 1 on succees, but is probably ignored. If + * fail to connect, then die with error. + */ +int +connect_to_pserver (tofdp, fromfdp, verify_only) + int *tofdp, *fromfdp; + int verify_only; +{ + int sock; + int tofd, fromfd; + int port_number; + struct hostent *host; + struct sockaddr_in client_sai; + + /* Does nothing if already called before now. */ + parse_cvsroot (); + + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock == -1) + { + fprintf (stderr, "socket() failed\n"); + exit (1); + } + port_number = auth_server_port_number (); + init_sockaddr (&client_sai, server_host, port_number); + if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)) + < 0) + error (1, errno, "connect to %s:%d failed", server_host, + CVS_AUTH_PORT); + + /* Run the authorization mini-protocol before anything else. */ + { + int i; + char ch, read_buf[PATH_MAX]; + char *begin = NULL; + char *repository = server_cvsroot; + char *username = server_user; + char *password = NULL; + char *end = NULL; + + if (verify_only) { - port = atoi (portenv); - if (port <= 0) - goto try_rsh_no_message; - port = htons (port); + begin = "BEGIN VERIFICATION REQUEST\n"; + end = "END VERIFICATION REQUEST\n"; } else { - struct servent *sp; - - sp = getservbyname ("cvs", "tcp"); - if (sp == NULL) - port = htons (CVS_PORT); - else - port = sp->s_port; + begin = "BEGIN AUTH REQUEST\n"; + end = "END AUTH REQUEST\n"; } - s = socket (AF_INET, SOCK_STREAM, 0); - if (s < 0) - error (1, errno, "socket"); - - memset (&sin, 0, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = 0; - - if (bind (s, (struct sockaddr *) &sin, sizeof sin) < 0) - error (1, errno, "bind"); - - memcpy (&sin.sin_addr, hp->h_addr, hp->h_length); - sin.sin_port = port; - - tofd = -1; - if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0) + /* Get the password, probably from ~/.cvspass. */ + password = get_cvs_password (server_user, server_host, server_cvsroot); + + /* Announce that we're starting the authorization protocol. */ + send (sock, begin, strlen (begin), 0); + + /* Send the data the server needs. */ + send (sock, repository, strlen (repository), 0); + send (sock, "\n", 1, 0); + send (sock, username, strlen (username), 0); + send (sock, "\n", 1, 0); + send (sock, password, strlen (password), 0); + send (sock, "\n", 1, 0); + + /* Announce that we're ending the authorization protocol. */ + send (sock, end, strlen (end), 0); + + /* Paranoia. */ + memset (password, 0, strlen (password)); + + /* Get ACK or NACK from the server. + * + * We could avoid this careful read-char loop by having the ACK + * and NACK cookies be of the same length, so we'd simply read + * that length and see what we got. But then there'd be Yet + * Another Protocol Requirement floating around, and someday + * someone would make a change that breaks it and spend a hellish + * day tracking it down. Therefore, we use "\n" to mark off the + * end of both ACK and NACK, and we loop, reading until "\n". + */ + ch = 0; + memset (read_buf, 0, PATH_MAX); + for (i = 0; (i < (PATH_MAX - 1)) && (ch != '\n'); i++) { - error (0, errno, "connect"); - close (s); + if (recv (sock, &ch, 1, 0) < 0) + error (1, errno, "recv() from server %s", server_host); + + read_buf[i] = ch; } - else + + if (strcmp (read_buf, "I HATE YOU\n") == 0) { - struct sockaddr_in laddr; - int laddrlen; - MSG_DAT msg_data; - CREDENTIALS cred; - Key_schedule sched; - - laddrlen = sizeof (laddr); - if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0) - error (1, errno, "getsockname"); - - /* We don't care about the checksum, and pass it as zero. */ - status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd", - hname, realm, (unsigned long) 0, &msg_data, - &cred, sched, &laddr, &sin, "KCVSV1.0"); - if (status != KSUCCESS) + /* Authorization not granted. */ + if (shutdown (sock, 2) < 0) { - error (0, 0, "kerberos: %s", krb_get_err_text(status)); - close (s); + error (0, 0, + "authorization failed: server %s rejected access", + server_host); + error (1, errno, + "shutdown() failed (server %s)", server_host); } + + if (verify_only) + return 0; else + error (1, 0, + "authorization failed: server %s rejected access", + server_host); + } + else if (strcmp (read_buf, "I LOVE YOU\n") != 0) + { + /* Unrecognized response from server. */ + if (shutdown (sock, 2) < 0) { - server_fd = s; - close_on_exec (server_fd); - /* - * If we do any filtering, TOFD and FROMFD will be - * closed. So make sure they're copies of SERVER_FD, - * and not the same fd number. - */ - if (log) - { - tofd = dup (s); - fromfd = dup (s); - } - else - tofd = fromfd = s; + error (0, 0, + "unrecognized auth response from %s: %s", + server_host, read_buf); + error (1, errno, "shutdown() failed, server %s", server_host); } + error (1, 0, + "unrecognized auth response from %s: %s", + server_host, read_buf); } + } - if (tofd == -1) - { - error (0, 0, "trying to start server using rsh"); - try_rsh_no_message: - server_fd = -1; + if (verify_only) + { + if (shutdown (sock, 2) < 0) + error (0, errno, "shutdown() failed, server %s", server_host); + return 1; + } + else + { +#ifdef NO_SOCKET_TO_FD + use_socket_style = 1; + server_sock = sock; + /* Try to break mistaken callers: */ + *tofdp = 0; + *fromfdp = 0; +#else /* ! NO_SOCKET_TO_FD */ + server_fd = sock; + close_on_exec (server_fd); + tofd = fromfd = sock; + /* Hand them back to the caller. */ + *tofdp = tofd; + *fromfdp = fromfd; +#endif /* NO_SOCKET_TO_FD */ + } + + return 1; +} +#endif /* AUTH_CLIENT_SUPPORT */ + + +#if HAVE_KERBEROS + +/* + * FIXME: this function has not been changed to deal with + * NO_SOCKET_TO_FD (i.e., systems on which sockets cannot be converted + * to file descriptors. The first person to try building a kerberos + * client on such a system (OS/2, Windows 95, and maybe others) will + * have to make take care of this. + */ +void +start_kerberos_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; + KTEXT_ST ticket; + int status; + + /* + * We look up the host to give a better error message if it + * does not exist. However, we then pass server_host to + * krb_sendauth, rather than the canonical name, because + * krb_sendauth is going to do its own canonicalization anyhow + * and that lets us not worry about the static storage used by + * gethostbyname. + */ + hp = gethostbyname (server_host); + if (hp == NULL) + error (1, 0, "%s: unknown host", server_host); + hname = xmalloc (strlen (hp->h_name) + 1); + strcpy (hname, hp->h_name); + + realm = krb_realmofhost (hname); + + portenv = getenv ("CVS_CLIENT_PORT"); + if (portenv != NULL) + { + port = atoi (portenv); + if (port <= 0) + goto try_rsh_no_message; + port = htons (port); + } + else + { + struct servent *sp; + + sp = getservbyname ("cvs", "tcp"); + if (sp == NULL) + port = htons (CVS_PORT); + else + port = sp->s_port; + } + + s = socket (AF_INET, SOCK_STREAM, 0); + if (s < 0) + error (1, errno, "socket"); + + memset (&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = 0; + + if (bind (s, (struct sockaddr *) &sin, sizeof sin) < 0) + error (1, errno, "bind"); + + memcpy (&sin.sin_addr, hp->h_addr, hp->h_length); + sin.sin_port = port; + + tofd = -1; + if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0) + { + error (0, errno, "kerberos connect"); + close (s); + } + else + { + struct sockaddr_in laddr; + int laddrlen; + MSG_DAT msg_data; + CREDENTIALS cred; + Key_schedule sched; + + laddrlen = sizeof (laddr); + if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0) + error (1, errno, "getsockname"); + + /* We don't care about the checksum, and pass it as zero. */ + status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd", + hname, realm, (unsigned long) 0, &msg_data, + &cred, sched, &laddr, &sin, "KCVSV1.0"); + if (status != KSUCCESS) + { + error (0, 0, "kerberos: %s", krb_get_err_text(status)); + close (s); + } + else + { + server_fd = s; + close_on_exec (server_fd); + tofd = fromfd = s; + } + } + + if (tofd == -1) + { + error (0, 0, "trying to start server using rsh"); + try_rsh_no_message: + server_fd = -1; #if ! RSH_NOT_TRANSPARENT - start_rsh_server (&tofd, &fromfd); -#else + start_rsh_server (&tofd, &fromfd); +#else /* RSH_NOT_TRANSPARENT */ #if defined (START_SERVER) - START_SERVER (&tofd, &fromfd, getcaller (), - server_user, server_host, server_cvsroot); -#endif /* START_SERVER */ -#endif /* RSH_NOT_TRANSPARENT */ - } - free (hname); + START_SERVER (&tofd, &fromfd, getcaller (), + server_user, server_host, server_cvsroot); +#endif /* defined (START_SERVER) */ +#endif /* ! RSH_NOT_TRANSPARENT */ } + free (hname); + /* Give caller the values it wants. */ + *tofdp = tofd; + *fromfdp = fromfd; +} + +#endif /* HAVE_KERBEROS */ + +/* Contact the server. */ +void +start_server () +{ + int tofd, fromfd; + char *log = getenv ("CVS_CLIENT_LOG"); + + /* Init these to NULL. They will be set later if logging is on. */ + from_server_logfile = (FILE *) NULL; + to_server_logfile = (FILE *) NULL; + +#ifdef AUTH_CLIENT_SUPPORT + if (use_authenticating_server) + { + /* Toss the return value. It will die with error if anything + goes wrong anyway. */ + connect_to_pserver (&tofd, &fromfd, 0); + } + else +#endif /* AUTH_CLIENT_SUPPORT */ + { +#if HAVE_KERBEROS + start_kerberos_server (&tofd, &fromfd); #else /* ! HAVE_KERBEROS */ + #if ! RSH_NOT_TRANSPARENT - start_rsh_server (&tofd, &fromfd); -#else + start_rsh_server (&tofd, &fromfd); +#else /* RSH_NOT_TRANSPARENT */ + #if defined(START_SERVER) - /* This is all a real mess. We now have three ways of connecting - to the server, and there's a fourth on the horizon. We should - clean this all up before adding the fourth. */ - START_SERVER (&tofd, &fromfd, getcaller (), - server_user, server_host, server_cvsroot); -#endif /* START_SERVER */ -#endif /* RSH_NOT_TRANSPARENT */ -#endif /* ! HAVE_KERBEROS */ + START_SERVER (&tofd, &fromfd, getcaller (), + server_user, server_host, server_cvsroot); +#endif /* defined(START_SERVER) */ - close_on_exec (tofd); - close_on_exec (fromfd); +#endif /* ! RSH_NOT_TRANSPARENT */ +#endif /* HAVE_KERBEROS */ + } + /* "Hi, I'm Darlene and I'll be your server tonight..." */ + server_started = 1; + + /* Set up logfiles, if any. */ if (log) { int len = strlen (log); - char *buf = xmalloc (5 + len); + char *buf = xmalloc (len + 5); char *p; - static char *teeprog[3] = { "tee" }; - teeprog[1] = buf; strcpy (buf, log); p = buf + len; strcpy (p, ".in"); - tofd = filter_stream_through_program (tofd, 0, teeprog, 0); + to_server_logfile = open_file (buf, "w"); + if (to_server_logfile == NULL) + error (0, errno, "opening to-server logfile %s", buf); strcpy (p, ".out"); - fromfd = filter_stream_through_program (fromfd, 1, teeprog, 0); + from_server_logfile = open_file (buf, "w"); + if (from_server_logfile == NULL) + error (0, errno, "opening from-server logfile %s", buf); free (buf); } - /* Should be using binary mode on systems which have it. */ - to_server = fdopen (tofd, FOPEN_BINARY_WRITE); - if (to_server == NULL) - error (1, errno, "cannot fdopen %d for write", tofd); - /* Should be using binary mode on systems which have it. */ - from_server = fdopen (fromfd, FOPEN_BINARY_READ); - if (from_server == NULL) - error (1, errno, "cannot fdopen %d for read", fromfd); +#ifdef NO_SOCKET_TO_FD + if (! use_socket_style) +#endif /* NO_SOCKET_TO_FD */ + { + /* todo: some OS's don't need these calls... */ + close_on_exec (tofd); + close_on_exec (fromfd); + + /* SCO 3 and AIX have a nasty bug in the I/O libraries which precludes + fdopening the same file descriptor twice, so dup it if it is the + same. */ + if (tofd == fromfd) + { + fromfd = dup (tofd); + if (fromfd < 0) + error (1, errno, "cannot dup net connection"); + } + + /* These will use binary mode on systems which have it. */ + to_server = fdopen (tofd, FOPEN_BINARY_WRITE); + if (to_server == NULL) + error (1, errno, "cannot fdopen %d for write", tofd); + from_server = fdopen (fromfd, FOPEN_BINARY_READ); + if (from_server == NULL) + error (1, errno, "cannot fdopen %d for read", fromfd); + } /* Clear static variables. */ if (toplevel_repos != NULL) free (toplevel_repos); toplevel_repos = NULL; - if (last_dirname != NULL) - free (last_dirname); - last_dirname = NULL; + if (last_dir_name != NULL) + free (last_dir_name); + last_dir_name = NULL; if (last_repos != NULL) free (last_repos); last_repos = NULL; @@ -2268,23 +2882,26 @@ start_server () free (last_update_dir); last_update_dir = NULL; 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 (fprintf (to_server, "Root %s\n", server_cvsroot) < 0) - error (1, errno, "writing to server"); { struct response *rs; - if (fprintf (to_server, "Valid-responses") < 0) - error (1, errno, "writing to server"); + + send_to_server ("Valid-responses", 0); + for (rs = responses; rs->name != NULL; ++rs) { - if (fprintf (to_server, " %s", rs->name) < 0) - error (1, errno, "writing to server"); + send_to_server (" ", 0); + send_to_server (rs->name, 0); } - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("\012", 1); } - if (fprintf (to_server, "valid-requests\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("valid-requests\012", 0); + if (get_server_responses ()) exit (1); @@ -2309,8 +2926,7 @@ start_server () { if (have_global) { - if (fprintf (to_server, "Global_option -n\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Global_option -n\012", 0); } else error (1, 0, @@ -2320,8 +2936,7 @@ start_server () { if (have_global) { - if (fprintf (to_server, "Global_option -q\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Global_option -q\012", 0); } else error (1, 0, @@ -2331,8 +2946,7 @@ start_server () { if (have_global) { - if (fprintf (to_server, "Global_option -Q\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Global_option -Q\012", 0); } else error (1, 0, @@ -2342,8 +2956,7 @@ start_server () { if (have_global) { - if (fprintf (to_server, "Global_option -r\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Global_option -r\012", 0); } else error (1, 0, @@ -2353,8 +2966,7 @@ start_server () { if (have_global) { - if (fprintf (to_server, "Global_option -t\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Global_option -t\012", 0); } else error (1, 0, @@ -2364,8 +2976,7 @@ start_server () { if (have_global) { - if (fprintf (to_server, "Global_option -l\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Global_option -l\012", 0); } else error (1, 0, @@ -2376,8 +2987,12 @@ start_server () { if (supported_request ("gzip-file-contents")) { - if (fprintf (to_server, "gzip-file-contents %d\n", gzip_level) < 0) - error (1, 0, "writing to server"); + char gzip_level_buf[5]; + send_to_server ("gzip-file-contents ", 0); + sprintf (gzip_level_buf, "%d", gzip_level); + send_to_server (gzip_level_buf, 0); + + send_to_server ("\012", 1); } else { @@ -2390,6 +3005,88 @@ start_server () #ifndef RSH_NOT_TRANSPARENT /* Contact the server by starting it with rsh. */ +/* Right now, we have two different definitions for this function, + depending on whether we start the rsh server using popenRW or not. + This isn't ideal, and the best thing would probably be to change + the OS/2 port to be more like the regular Unix client (i.e., by + implementing piped_child)... but I'm doing something else at the + moment, and wish to make only one change at a time. -Karl */ + +#ifdef START_RSH_WITH_POPEN_RW + +/* This is actually a crock -- it's OS/2-specific, for no one else + uses it. If I get time, I want to make piped_child and all the + other stuff in os2/run.c work right. In the meantime, this gets us + up and running, and that's most important. */ + +static void +start_rsh_server (tofdp, fromfdp) + int *tofdp, *fromfdp; +{ + int pipes[2]; + + /* If you're working through firewalls, you can set the + CVS_RSH environment variable to a script which uses rsh to + invoke another rsh on a proxy machine. */ + char *cvs_rsh = getenv ("CVS_RSH"); + char *cvs_server = getenv ("CVS_SERVER"); + char command[PATH_MAX]; + int i = 0; + /* This needs to fit "rsh", "-b", "-l", "USER", "host", + "cmd (w/ args)", and NULL. We leave some room to grow. */ + char *rsh_argv[10]; + + if (!cvs_rsh) + cvs_rsh = "rsh"; + if (!cvs_server) + cvs_server = "cvs"; + + /* If you are running a very old (Nov 3, 1994, before 1.5) + * version of the server, you need to make sure that your .bashrc + * on the server machine does not set CVSROOT to something + * containing a colon (or better yet, upgrade the server). */ + + /* The command line starts out with rsh. */ + rsh_argv[i++] = cvs_rsh; + +#ifdef RSH_NEEDS_BINARY_FLAG + /* "-b" for binary, under OS/2. */ + rsh_argv[i++] = "-b"; +#endif /* RSH_NEEDS_BINARY_FLAG */ + + /* Then we strcat more things on the end one by one. */ + if (server_user != NULL) + { + rsh_argv[i++] = "-l"; + rsh_argv[i++] = server_user; + } + + rsh_argv[i++] = server_host; + rsh_argv[i++] = cvs_server; + rsh_argv[i++] = "server"; + + /* Mark the end of the arg list. */ + rsh_argv[i] = (char *) NULL; + + if (trace) + { + fprintf (stderr, " -> Starting server: "); + fprintf (stderr, "%s", command); + putc ('\n', stderr); + } + + /* Do the deed. */ + rsh_pid = popenRW (rsh_argv, pipes); + if (rsh_pid < 0) + error (1, errno, "cannot start server via rsh"); + + /* Give caller the file descriptors. */ + *tofdp = pipes[0]; + *fromfdp = pipes[1]; +} + +#else /* ! START_RSH_WITH_POPEN_RW */ + static void start_rsh_server (tofdp, fromfdp) int *tofdp; @@ -2455,7 +3152,10 @@ start_rsh_server (tofdp, fromfdp) error (1, errno, "cannot start server via rsh"); } } -#endif + +#endif /* START_RSH_WITH_POPEN_RW */ +#endif /* ! RSH_NOT_TRANSPARENT */ + /* Send an argument STRING. */ @@ -2463,28 +3163,34 @@ void send_arg (string) char *string; { + char buf[1]; char *p = string; - if (fprintf (to_server, "Argument ") < 0) - error (1, errno, "writing to server"); + + send_to_server ("Argument ", 0); + while (*p) { if (*p == '\n') { - if (fprintf (to_server, "\nArgumentx ") < 0) - error (1, errno, "writing to server"); + send_to_server ("\012Argumentx ", 0); } - else if (putc (*p, to_server) == EOF) - error (1, errno, "writing to server"); + else + { + buf[0] = *p; + send_to_server (buf, 1); + } ++p; } - if (putc ('\n', to_server) == EOF) - error (1, errno, "writing to server"); + send_to_server ("\012", 1); } -void -send_modified (file, short_pathname) +static void send_modified PROTO ((char *, char *, Vers_TS *)); + +static void +send_modified (file, short_pathname, vers) char *file; char *short_pathname; + Vers_TS *vers; { /* File was modified, send it. */ struct stat sb; @@ -2492,6 +3198,7 @@ send_modified (file, short_pathname) char *buf; char *mode_string; int bufsize; + int bin; /* Don't think we can assume fstat exists. */ if (stat (file, &sb) < 0) @@ -2507,7 +3214,16 @@ send_modified (file, short_pathname) bufsize = sb.st_size; buf = xmalloc (bufsize); - fd = open (file, O_RDONLY); + /* Is the file marked as containing binary data by the "-kb" flag? + If so, make sure to open it in binary mode: */ + + if (vers && vers->options) + bin = !(strcmp (vers->options, "-kb")); + else + bin = 0; + + fd = open (file, O_RDONLY | (bin ? OPEN_BINARY : 0)); + if (fd < 0) error (1, errno, "reading %s", short_pathname); @@ -2519,37 +3235,52 @@ send_modified (file, short_pathname) int readsize = 8192; #ifdef LINES_CRLF_TERMINATED char tempfile[L_tmpnam]; -#endif + int converting; +#endif /* LINES_CRLF_TERMINATED */ #ifdef LINES_CRLF_TERMINATED - /* gzip reads and writes files without munging CRLF sequences, as it - should, but files should be transmitted in LF form. Convert CRLF - to LF before gzipping, on systems where this is necessary. - - If Windows NT supported fork, we could do this by pushing another - filter on in front of gzip. But it doesn't. I'd have to write a - trivial little program to do the conversion and have CVS spawn it - off. But little executables like that always get lost. - - Alternatively, this cruft could go away if we switched to a gzip - library instead of a subprocess; then we could tell gzip to open - the file with CRLF translation enabled. */ - if (close (fd) < 0) - error (0, errno, "warning: can't close %s", short_pathname); - - tmpnam (tempfile); - convert_file (file, O_RDONLY, - tempfile, O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY); + /* Assume everything in a "cvs import" is text. */ + if (vers == NULL) + converting = 1; + else + /* Otherwise, we convert things unless they're binary. */ + converting = (! bin); - /* This OPEN_BINARY doesn't make any difference, I think, because - gzip will deal with the inherited handle as it pleases. But I - do remember something obscure in the manuals about propagating - the translation mode to created processes via environment - variables, ick. */ - fd = open (tempfile, O_RDONLY | OPEN_BINARY); - if (fd < 0) - error (1, errno, "reading %s", short_pathname); -#endif + if (converting) + { + /* gzip reads and writes files without munging CRLF + sequences, as it should, but files should be + transmitted in LF form. Convert CRLF to LF before + gzipping, on systems where this is necessary. + + If Windows NT supported fork, we could do this by + pushing another filter on in front of gzip. But it + doesn't. I'd have to write a trivial little program to + do the conversion and have CVS spawn it off. But + little executables like that always get lost. + + Alternatively, this cruft could go away if we switched + to a gzip library instead of a subprocess; then we + could tell gzip to open the file with CRLF translation + enabled. */ + if (close (fd) < 0) + error (0, errno, "warning: can't close %s", short_pathname); + + tmpnam (tempfile); + convert_file (file, O_RDONLY, + tempfile, + O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY); + + /* This OPEN_BINARY doesn't make any difference, I think, because + gzip will deal with the inherited handle as it pleases. But I + do remember something obscure in the manuals about propagating + the translation mode to created processes via environment + variables, ick. */ + fd = open (tempfile, O_RDONLY | OPEN_BINARY); + if (fd < 0) + error (1, errno, "reading %s", short_pathname); + } +#endif /* LINES_CRLF_TERMINATED */ fd = filter_through_gzip (fd, 1, gzip_level, &gzip_pid); while (1) @@ -2584,15 +3315,27 @@ send_modified (file, short_pathname) error (1, errno, "gzip exited %d", gzip_status); #if LINES_CRLF_TERMINATED - if (unlink (tempfile) < 0) - error (0, errno, "warning: can't remove temp file %s", tempfile); -#endif LINES_CRLF_TERMINATED + if (converting) + { + if (unlink (tempfile) < 0) + error (0, errno, + "warning: can't remove temp file %s", tempfile); + } +#endif /* LINES_CRLF_TERMINATED */ - fprintf (to_server, "Modified %s\n%s\nz%lu\n", file, mode_string, - (unsigned long) newsize); - fwrite (buf, newsize, 1, to_server); - if (feof (to_server) || ferror (to_server)) - error (1, errno, "writing to server"); + { + char tmp[80]; + + send_to_server ("Modified ", 0); + send_to_server (file, 0); + send_to_server ("\012", 1); + send_to_server (mode_string, 0); + send_to_server ("\012z", 2); + sprintf (tmp, "%lu\n", (unsigned long) newsize); + send_to_server (tmp, 0); + + send_to_server (buf, newsize); + } } else { @@ -2613,22 +3356,31 @@ send_modified (file, short_pathname) if (close (fd) < 0) error (0, errno, "warning: can't close %s", short_pathname); - if (fprintf (to_server, "Modified %s\n%s\n%lu\n", file, - mode_string, (unsigned long) newsize) < 0) - error (1, errno, "writing to server"); + { + char tmp[80]; + + send_to_server ("Modified ", 0); + send_to_server (file, 0); + send_to_server ("\012", 1); + send_to_server (mode_string, 0); + send_to_server ("\012", 1); + sprintf (tmp, "%lu\012", (unsigned long) newsize); + send_to_server (tmp, 0); + } /* * Note that this only ends with a newline if the file ended with * one. */ if (newsize > 0) - if (fwrite (buf, newsize, 1, to_server) != 1) - error (1, errno, "writing to server"); + send_to_server (buf, newsize); } free (buf); free (mode_string); } +static int send_fileproc PROTO ((char *, char *, char *, List *, List *)); + /* Deal with one file. */ static int send_fileproc (file, update_dir, repository, entries, srcfiles) @@ -2654,27 +3406,35 @@ send_fileproc (file, update_dir, repository, entries, srcfiles) if (vers->vn_user != NULL) { + char *tmp; + + tmp = xmalloc (strlen (file) + strlen (vers->vn_user) + + strlen (vers->options) + 200); + sprintf (tmp, "Entry /%s/%s/%s%s/%s/", + file, vers->vn_user, + vers->ts_conflict == NULL ? "" : "+", + (vers->ts_conflict == NULL ? "" + : (vers->ts_user != NULL && + strcmp (vers->ts_conflict, vers->ts_user) == 0 + ? "=" + : "modified")), + vers->options); + /* The Entries request. */ /* Not sure about whether this deals with -k and stuff right. */ - if (fprintf (to_server, "Entry /%s/%s/%s%s/%s/", file, vers->vn_user, - vers->ts_conflict == NULL ? "" : "+", - (vers->ts_conflict == NULL ? "" - : (vers->ts_user != NULL && - strcmp (vers->ts_conflict, vers->ts_user) == 0 - ? "=" - : "modified")), - vers->options) < 0) - error (1, errno, "writing to server"); + send_to_server (tmp, 0); + free (tmp); if (vers->entdata != NULL && vers->entdata->tag) { - if (fprintf (to_server, "T%s", vers->entdata->tag) < 0) - error (1, errno, "writing to server"); + send_to_server ("T", 0); + send_to_server (vers->entdata->tag, 0); } else if (vers->entdata != NULL && vers->entdata->date) - if (fprintf (to_server, "D%s", vers->entdata->date) < 0) - error (1, errno, "writing to server"); - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); + { + send_to_server ("D", 0); + send_to_server (vers->entdata->date, 0); + } + send_to_server ("\012", 1); } if (vers->ts_user == NULL) @@ -2687,8 +3447,9 @@ send_fileproc (file, update_dir, repository, entries, srcfiles) if (!use_unchanged) { /* if the server is old, use the old request... */ - if (fprintf (to_server, "Lost %s\n", file) < 0) - error (1, errno, "writing to server"); + send_to_server ("Lost ", 0); + send_to_server (file, 0); + send_to_server ("\012", 1); /* * Otherwise, don't do anything for missing files, * they just happen. @@ -2698,14 +3459,17 @@ send_fileproc (file, update_dir, repository, entries, srcfiles) else if (vers->ts_rcs == NULL || strcmp (vers->ts_user, vers->ts_rcs) != 0) { - send_modified (file, short_pathname); + send_modified (file, short_pathname, vers); } else { /* Only use this request if the server supports it... */ if (use_unchanged) - if (fprintf (to_server, "Unchanged %s\n", file) < 0) - error (1, errno, "writing to server"); + { + send_to_server ("Unchanged ", 0); + send_to_server (file, 0); + send_to_server ("\012", 1); + } } /* if this directory has an ignore list, add this file to it */ @@ -2719,10 +3483,53 @@ send_fileproc (file, update_dir, repository, entries, srcfiles) (void) addnode (ignlist, p); } + freevers_ts (&vers); free (short_pathname); return 0; } +static void send_ignproc PROTO ((char *, char *)); + +static void +send_ignproc (file, dir) + char *file; + char *dir; +{ + if (ign_inhibit_server || !supported_request ("Questionable")) + { + if (dir[0] != '\0') + (void) printf ("? %s/%s\n", dir, file); + else + (void) printf ("? %s\n", file); + } + else + { + send_to_server ("Questionable ", 0); + send_to_server (file, 0); + send_to_server ("\012", 1); + } +} + +static int send_filesdoneproc PROTO ((int, char *, char *)); + +static int +send_filesdoneproc (err, repository, update_dir) + int err; + char *repository; + char *update_dir; +{ + /* if this directory has an ignore list, process it then free it */ + if (ignlist) + { + ignore_files (ignlist, update_dir, send_ignproc); + dellist (&ignlist); + } + + return (err); +} + +static Dtype send_dirent_proc PROTO ((char *, char *, char *)); + /* * send_dirent_proc () is called back by the recursion processor before a * sub-directory is processed for update. @@ -2849,8 +3656,12 @@ send_file_names (argc, argv) { if (supported_request ("Max-dotdot")) { - if (fprintf (to_server, "Max-dotdot %d\n", max_level) < 0) - error (1, errno, "writing to server"); + char buf[10]; + sprintf (buf, "%d", max_level); + + send_to_server ("Max-dotdot ", 0); + send_to_server (buf, 0); + send_to_server ("\012", 1); } else /* @@ -2883,16 +3694,14 @@ send_files (argc, argv, local, aflag) { int err; - send_file_names (argc, argv); - /* * aflag controls whether the tag/date is copied into the vers_ts. * But we don't actually use it, so I don't think it matters what we pass * for aflag here. */ err = start_recursion - (send_fileproc, update_filesdone_proc, - send_dirent_proc, (int (*) ())NULL, + (send_fileproc, send_filesdoneproc, + send_dirent_proc, (DIRLEAVEPROC)NULL, argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0, 0); if (err) exit (1); @@ -2949,7 +3758,7 @@ client_process_import_file (message, vfile, vtag, targc, targv, repository) { send_a_repository ("", repository, short_pathname); } - send_modified (vfile, short_pathname); + send_modified (vfile, short_pathname, NULL); return 0; } @@ -2970,6 +3779,137 @@ client_import_done () send_repository ("", toplevel_repos, "."); } +static void +notified_a_file (data, ent_list, short_pathname, filename) + char *data; + List *ent_list; + char *short_pathname; + char *filename; +{ + FILE *fp; + FILE *newf; + size_t line_len = 8192; + char *line = xmalloc (line_len); + char *cp; + int nread; + int nwritten; + char *p; + + fp = open_file (CVSADM_NOTIFY, "r"); + if (getline (&line, &line_len, fp) < 0) + { + error (0, errno, "cannot read %s", CVSADM_NOTIFY); + goto error_exit; + } + cp = strchr (line, '\t'); + if (cp == NULL) + { + error (0, 0, "malformed %s file", CVSADM_NOTIFY); + goto error_exit; + } + *cp = '\0'; + if (strcmp (filename, line + 1) != 0) + { + error (0, 0, "protocol error: notified %s, expected %s", filename, + line + 1); + } + + if (getline (&line, &line_len, fp) < 0) + { + if (feof (fp)) + { + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", CVSADM_NOTIFY); + if (unlink (CVSADM_NOTIFY) < 0) + error (0, errno, "cannot remove %s", CVSADM_NOTIFY); + return; + } + else + { + error (0, errno, "cannot read %s", CVSADM_NOTIFY); + goto error_exit; + } + } + newf = open_file (CVSADM_NOTIFYTMP, "w"); + if (fputs (line, newf) < 0) + { + error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP); + goto error2; + } + while ((nread = fread (line, 1, line_len, fp)) > 0) + { + p = line; + while ((nwritten = fwrite (p, 1, nread, newf)) > 0) + { + nread -= nwritten; + p += nwritten; + } + if (ferror (newf)) + { + error (0, errno, "cannot write %s", CVSADM_NOTIFYTMP); + goto error2; + } + } + if (ferror (fp)) + { + error (0, errno, "cannot read %s", CVSADM_NOTIFY); + goto error2; + } + if (fclose (newf) < 0) + { + error (0, errno, "cannot close %s", CVSADM_NOTIFYTMP); + goto error_exit; + } + if (fclose (fp) < 0) + { + error (0, errno, "cannot close %s", CVSADM_NOTIFY); + return; + } + + { + /* In this case, we want rename_file() to ignore noexec. */ + int saved_noexec = noexec; + noexec = 0; + rename_file (CVSADM_NOTIFYTMP, CVSADM_NOTIFY); + noexec = saved_noexec; + } + + return; + error2: + (void) fclose (newf); + error_exit: + (void) fclose (fp); +} + +static void +handle_notified (args, len) + char *args; + int len; +{ + call_in_directory (args, notified_a_file, NULL); +} + +void +client_notify (repository, update_dir, filename, notif_type, val) + char *repository; + char *update_dir; + char *filename; + int notif_type; + char *val; +{ + char buf[2]; + + send_a_repository ("", repository, update_dir); + send_to_server ("Notify ", 0); + send_to_server (filename, 0); + send_to_server ("\012", 1); + buf[0] = notif_type; + buf[1] = '\0'; + send_to_server (buf, 1); + send_to_server ("\t", 1); + send_to_server (val, 0); +} + /* * Send an option with an argument, dealing correctly with newlines in * the argument. If ARG is NULL, forget the whole thing. @@ -2981,8 +3921,11 @@ option_with_arg (option, arg) { if (arg == NULL) return; - if (fprintf (to_server, "Argument %s\n", option) < 0) - error (1, errno, "writing to server"); + + send_to_server ("Argument ", 0); + send_to_server (option, 0); + send_to_server ("\012", 1); + send_arg (arg); } @@ -3010,7 +3953,7 @@ client_senddate (date) #ifndef HAVE_RCS5 /* We need to fix the timezone in this case; see Make_Date. */ abort (); -#endif +#endif /* HAVE_RCS5 */ sprintf (buf, "%d/%d/%d %d:%d:%d GMT", month, day, year, hour, minute, second); @@ -3187,4 +4130,59 @@ client_release (argc, argv) return release (argc, argv); /* Call real code */ } +int +client_watch (argc, argv) + int argc; + char **argv; +{ + + parse_cvsroot (); + + return watch (argc, argv); /* Call real code */ +} + +int +client_watchers (argc, argv) + int argc; + char **argv; +{ + + parse_cvsroot (); + + return watchers (argc, argv); /* Call real code */ +} + +int +client_editors (argc, argv) + int argc; + char **argv; +{ + + parse_cvsroot (); + + return editors (argc, argv); /* Call real code */ +} + +int +client_edit (argc, argv) + int argc; + char **argv; +{ + + parse_cvsroot (); + + return edit (argc, argv); /* Call real code */ +} + +int +client_unedit (argc, argv) + int argc; + char **argv; +{ + + parse_cvsroot (); + + return unedit (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 0602900aaf5..53043857527 100644 --- a/gnu/usr.bin/cvs/src/client.h +++ b/gnu/usr.bin/cvs/src/client.h @@ -30,6 +30,11 @@ extern int client_admin PROTO((int argc, char **argv)); extern int client_export PROTO((int argc, char **argv)); extern int client_history PROTO((int argc, char **argv)); extern int client_release PROTO((int argc, char **argv)); +extern int client_watch PROTO((int argc, char **argv)); +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)); /* * Flag variable for seeing whether common code is running as a client @@ -37,13 +42,26 @@ extern int client_release PROTO((int argc, char **argv)); */ extern int client_active; +/* + * Flag variable for seeing whether the server has been started yet. + * As of this writing, only edit.c:notify_check() uses it. + */ +extern int server_started; + /* Is the -P option to checkout or update specified? */ extern int client_prune_dirs; -/* Stream to write to the server. */ -extern FILE *to_server; -/* Stream to read from the server. */ -extern FILE *from_server; +#ifdef AUTH_CLIENT_SUPPORT +extern int use_authenticating_server; +int connect_to_pserver PROTO((int *tofdp, int* fromfdp, int verify_only)); +# ifndef CVS_AUTH_PORT +# define CVS_AUTH_PORT 2401 +# endif /* CVS_AUTH_PORT */ +#endif /* AUTH_CLIENT_SUPPORT */ + +/* Talking to the server. */ +void send_to_server PROTO((char *str, size_t len)); +void read_from_server PROTO((char *buf, size_t len)); /* Internal functions that handle client communication to server, etc. */ int supported_request PROTO ((char *)); @@ -65,9 +83,7 @@ send_file_names PROTO((int argc, char **argv)); /* * Send Repository, Modified and Entry. argc and argv contain only * the files to operate on (or empty for everything), not options. - * local is nonzero if we should not recurse (-l option). Also sends - * Argument lines for argc and argv, so should be called after options - * are sent. + * local is nonzero if we should not recurse (-l option). */ void send_files PROTO((int argc, char **argv, int local, int aflag)); @@ -159,5 +175,5 @@ extern int client_process_import_file PROTO((char *message, char *vfile, char *vtag, int targc, char *targv[], char *repository)); extern void client_import_done PROTO((void)); - +extern void client_notify PROTO((char *, char *, char *, int, char *)); #endif /* CLIENT_SUPPORT */ diff --git a/gnu/usr.bin/cvs/src/cvsbug.sh b/gnu/usr.bin/cvs/src/cvsbug.sh index b47597f93cd..bee910f990d 100644 --- a/gnu/usr.bin/cvs/src/cvsbug.sh +++ b/gnu/usr.bin/cvs/src/cvsbug.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#! /bin/sh # Submit a problem report to a GNATS site. # Copyright (C) 1993 Free Software Foundation, Inc. # Contributed by Brendan Kehoe (brendan@cygnus.com), based on a @@ -6,8 +6,8 @@ # # This file is part of GNU GNATS. # Modified by Berliner for CVS. -# Modified by Jim Blandy for CVS 1.5. -# $CVSid: @(#)cvsbug.sh 1.2 94/10/22 $ +# +#ident "@(#)cvs/src:$Name: $:$Id: cvsbug.sh,v 1.1.1.2 1996/01/30 00:17:47 tholo Exp $" # # GNU GNATS is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -43,7 +43,7 @@ GNATS_ADDR=bug-cvs@prep.ai.mit.edu ## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}.. # The default release for this host. -DEFAULT_RELEASE="post-cvs-1.5" +DEFAULT_RELEASE="xVERSIONx" # The default organization. DEFAULT_ORGANIZATION="net" @@ -337,24 +337,14 @@ X-send-pr-version: $VERSION >Submitter-Id: $SUBMITTER >Originator: $ORIGINATOR >Organization: -` - if [ -n "$ORGANIZATION" ]; then - echo "$ORGANIZATION" - else - echo " $ORGANIZATION_C" ; - fi ; -` +${ORGANIZATION-$ORGANIZATION_C} >Confidential: $CONFIDENTIAL_C >Synopsis: $SYNOPSIS_C >Severity: $SEVERITY_C >Priority: $PRIORITY_C >Category: $CATEGORY_C >Class: $CLASS_C ->Release: `if [ -n "$DEFAULT_RELEASE" ]; then - echo "$DEFAULT_RELEASE" - else - echo " $RELEASE_C" - fi; ` +>Release: ${DEFAULT_RELEASE-$RELEASE_C} >Environment: $ENVIRONMENT_C `[ -n "$SYSTEM" ] && echo System: $SYSTEM` diff --git a/gnu/usr.bin/cvs/src/cvsrc.c b/gnu/usr.bin/cvs/src/cvsrc.c index ec594eb5456..5882afceb26 100644 --- a/gnu/usr.bin/cvs/src/cvsrc.c +++ b/gnu/usr.bin/cvs/src/cvsrc.c @@ -10,6 +10,7 @@ #include "cvs.h" +#include "getline.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)cvsrc.c 1.9 94/09/30 $"; @@ -36,10 +37,13 @@ read_cvsrc (argc, argv) char *homeinit; FILE *cvsrcfile; - char linebuf [MAXLINELEN]; - + char *line; + int line_length; + size_t line_chars_allocated; + char *optstart; + int command_len; int found = 0; int i; @@ -72,7 +76,7 @@ read_cvsrc (argc, argv) /* if it can't be read, there's no point to continuing */ - if (access (homeinit, R_OK) != 0) + if (!isreadable (homeinit)) { free (homeinit); return; @@ -80,15 +84,20 @@ read_cvsrc (argc, argv) /* now scan the file until we find the line for the command in question */ + line = NULL; + line_chars_allocated = 0; + command_len = strlen (command_name); cvsrcfile = open_file (homeinit, "r"); - while (fgets (linebuf, MAXLINELEN, cvsrcfile)) + while ((line_length = getline (&line, &line_chars_allocated, cvsrcfile)) + >= 0) { /* skip over comment lines */ - if (linebuf[0] == '#') + if (line[0] == '#') continue; /* stop if we match the current command */ - if (!strncmp (linebuf, (*argv)[0], strlen ((*argv)[0]))) + if (!strncmp (line, command_name, command_len) + && isspace (*(line + command_len))) { found = 1; break; @@ -100,8 +109,8 @@ read_cvsrc (argc, argv) if (found) { /* skip over command in the options line */ - optstart = strtok(linebuf+strlen((*argv)[0]), "\t \n"); - + optstart = strtok (line + command_len, "\t \n"); + do { new_argv [new_argc] = xstrdup (optstart); @@ -123,6 +132,9 @@ read_cvsrc (argc, argv) while ((optstart = strtok (NULL, "\t \n")) != NULL); } + if (line != NULL) + free (line); + /* now copy the remaining arguments */ for (i=1; i < *argc; i++) diff --git a/gnu/usr.bin/cvs/src/diff.c b/gnu/usr.bin/cvs/src/diff.c index b7a41697082..f798f7ae567 100644 --- a/gnu/usr.bin/cvs/src/diff.c +++ b/gnu/usr.bin/cvs/src/diff.c @@ -183,36 +183,29 @@ diff (argc, argv) if (diff_date2) client_senddate (diff_date2); + send_file_names (argc, argv); #if 0 -/* FIXME: We shouldn't have to send current files to diff two revs, but it - doesn't work yet and I haven't debugged it. So send the files -- - it's slower but it works. gnu@cygnus.com Apr94 */ - -/* Idea: often times the changed region of a file is relatively small. - It would be cool if the client could just divide the file into 4k - blocks or whatever and send hash values for the blocks. Send hash - values for blocks aligned with the beginning of the file and the - end of the file. Then the server can tell how much of the head and - tail of the file is unchanged. Well, hash collisions will screw - things up, but MD5 has 128 bits of hash value... */ - + /* FIXME: We shouldn't have to send current files to diff two + revs, but it doesn't work yet and I haven't debugged it. + So send the files -- it's slower but it works. + gnu@cygnus.com Apr94 */ /* Send the current files unless diffing two revs from the archive */ if (diff_rev2 == NULL && diff_date2 == NULL) - send_files (argc, argv, local); - else - send_file_names (argc, argv); -#else - send_files (argc, argv, local, 0); #endif + send_files (argc, argv, local, 0); - if (fprintf (to_server, "diff\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("diff\012", 0); err = get_responses_and_close (); free (options); return (err); } #endif + if (diff_rev1 != NULL) + tag_check_valid (diff_rev1, argc, argv, local, 0, ""); + if (diff_rev2 != NULL) + tag_check_valid (diff_rev2, argc, argv, local, 0, ""); + which = W_LOCAL; if (diff_rev2 != NULL || diff_date2 != NULL) which |= W_REPOS | W_ATTIC; @@ -350,7 +343,7 @@ diff_fileproc (file, update_dir, repository, entries, srcfiles) /* Backup the current version of the file to CVS/,,filename */ sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, file); if (unlink_file_dir (fname) < 0) - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "cannot remove %s", file); rename_file (file, fname); /* Copy the wrapped file to the current directory then go to work */ @@ -420,7 +413,7 @@ diff_fileproc (file, update_dir, repository, entries, srcfiles) if (tocvsPath) { if (unlink_file_dir (file) < 0) - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "cannot remove %s", file); rename_file (fname,file); @@ -450,6 +443,8 @@ diff_mark_errors (err) /* * Print a warm fuzzy message when we enter a dir + * + * Don't try to diff directories that don't exist! -- DW */ /* ARGSUSED */ static Dtype @@ -459,6 +454,11 @@ diff_dirproc (dir, pos_repos, update_dir) char *update_dir; { /* XXX - check for dirs we don't want to process??? */ + + /* YES ... for instance dirs that don't exist!!! -- DW */ + if (!isdir (dir) ) + return (R_SKIP_ALL); + if (!quiet) error (0, 0, "Diffing %s", update_dir); return (R_PROCESS); @@ -522,8 +522,11 @@ diff_file_nodiff (file, repository, entries, srcfiles, vers) diff_date1, file, 1, 0, entries, srcfiles); if (xvers->vn_rcs == NULL) { - if (diff_rev1) - error (0, 0, "tag %s is not in file %s", diff_rev1, file); + /* Don't gripe if it doesn't exist, just ignore! */ + if (! isfile (file)) + /* null statement */ ; + else if (diff_rev1) + error (0, 0, "tag %s is not in file %s", diff_rev1, file); else error (0, 0, "no revision for date %s in file %s", diff_date1, file); @@ -544,7 +547,10 @@ diff_file_nodiff (file, repository, entries, srcfiles, vers) diff_date2, file, 1, 0, entries, srcfiles); if (xvers->vn_rcs == NULL) { - if (diff_rev1) + /* Don't gripe if it doesn't exist, just ignore! */ + if (! isfile (file)) + /* null statement */ ; + else if (diff_rev1) error (0, 0, "tag %s is not in file %s", diff_rev2, file); else error (0, 0, "no revision for date %s in file %s", diff --git a/gnu/usr.bin/cvs/src/edit.c b/gnu/usr.bin/cvs/src/edit.c new file mode 100644 index 00000000000..8eeecb51e45 --- /dev/null +++ b/gnu/usr.bin/cvs/src/edit.c @@ -0,0 +1,1032 @@ +/* Implementation for "cvs edit", "cvs watch on", and related commands + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "cvs.h" +#include "getline.h" +#include "watch.h" +#include "edit.h" +#include "fileattr.h" + +static int watch_onoff PROTO ((int, char **)); + +static int setting_default; +static int turning_on; + +static int setting_tedit; +static int setting_tunedit; +static int setting_tcommit; + +static int onoff_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +onoff_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + fileattr_set (file, "_watched", turning_on ? "" : NULL); + return 0; +} + +static int onoff_filesdoneproc PROTO ((int, char *, char *)); + +static int +onoff_filesdoneproc (err, repository, update_dir) + int err; + char *repository; + char *update_dir; +{ + if (setting_default) + fileattr_set (NULL, "_watched", turning_on ? "" : NULL); + return err; +} + +static int +watch_onoff (argc, argv) + int argc; + char **argv; +{ + int c; + int local = 0; + int err; + + optind = 1; + while ((c = getopt (argc, argv, "l")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case '?': + default: + usage (watch_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); + /* 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 (turning_on ? "watch-on\012" : "watch-off\012", 0); + return get_responses_and_close (); + } +#endif /* CLIENT_SUPPORT */ + + setting_default = (argc <= 0); + + lock_tree_for_write (argc, argv, local, 0); + + err = start_recursion (onoff_fileproc, onoff_filesdoneproc, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, + 0, 0); + + lock_tree_cleanup (); + return err; +} + +int +watch_on (argc, argv) + int argc; + char **argv; +{ + turning_on = 1; + return watch_onoff (argc, argv); +} + +int +watch_off (argc, argv) + int argc; + char **argv; +{ + turning_on = 0; + return watch_onoff (argc, argv); +} + +static int dummy_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +dummy_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + /* This is a pretty hideous hack, but the gist of it is that recurse.c + won't call notify_check unless there is a fileproc, so we can't just + pass NULL for fileproc. */ + return 0; +} + +static int ncheck_fileproc PROTO ((char *file, char *update_dir, + char *repository, + List * entries, List * srcfiles)); + +/* Check for and process notifications. Local only. I think that doing + this as a fileproc is the only way to catch all the + cases (e.g. foo/bar.c), even though that means checking over and over + for the same CVSADM_NOTIFY file which we removed the first time we + processed the directory. */ + +static int +ncheck_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + int notif_type; + char *filename; + char *val; + char *cp; + char *watches; + + FILE *fp; + char *line = NULL; + size_t line_len = 0; + + /* We send notifications even if noexec. I'm not sure which behavior + is most sensible. */ + + fp = fopen (CVSADM_NOTIFY, "r"); + if (fp == NULL) + { + if (!existence_error (errno)) + error (0, errno, "cannot open %s", CVSADM_NOTIFY); + return 0; + } + while (getline (&line, &line_len, fp) > 0) + { + notif_type = line[0]; + if (notif_type == '\0') + continue; + filename = line + 1; + cp = strchr (filename, '\t'); + if (cp == NULL) + continue; + *cp++ = '\0'; + val = cp; + cp = strchr (val, '\t'); + if (cp == NULL) + continue; + *cp++ = '+'; + cp = strchr (cp, '\t'); + if (cp == NULL) + continue; + *cp++ = '+'; + cp = strchr (cp, '\t'); + if (cp == NULL) + continue; + *cp++ = '\0'; + watches = cp; + cp = strchr (cp, '\n'); + if (cp == NULL) + continue; + *cp = '\0'; + + notify_do (notif_type, filename, getcaller (), val, watches, + repository); + } + + if (ferror (fp)) + error (0, errno, "cannot read %s", CVSADM_NOTIFY); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", CVSADM_NOTIFY); + + if (unlink (CVSADM_NOTIFY) < 0) + error (0, errno, "cannot remove %s", CVSADM_NOTIFY); + + return 0; +} + +static int send_notifications PROTO ((int, char **, int)); + +/* Look through the CVSADM_NOTIFY file and process each item there + accordingly. */ +static int +send_notifications (argc, argv, local) + int argc; + char **argv; + int local; +{ + int err = 0; + +#ifdef CLIENT_SUPPORT + /* OK, we've done everything which needs to happen on the client side. + Now we can try to contact the server; if we fail, then the + notifications stay in CVSADM_NOTIFY to be sent next time. */ + if (client_active) + { + if (strcmp (command_name, "release") != 0) + { + start_server (); + ign_setup (); + } + + err += start_recursion (dummy_fileproc, (FILESDONEPROC) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, + 0, 0); + + send_to_server ("noop\012", 0); + if (strcmp (command_name, "release") == 0) + err += get_server_responses (); + else + err += get_responses_and_close (); + } + else +#endif + { + /* Local. */ + + lock_tree_for_write (argc, argv, local, 0); + err += start_recursion (ncheck_fileproc, (FILESDONEPROC) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, + 0, 0); + lock_tree_cleanup (); + } + return err; +} + +static int edit_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +edit_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + FILE *fp; + time_t now; + char *ascnow; + char *basefilename; + + if (noexec) + return 0; + + fp = open_file (CVSADM_NOTIFY, "a"); + + (void) time (&now); + ascnow = asctime (gmtime (&now)); + ascnow[24] = '\0'; + fprintf (fp, "E%s\t%s GMT\t%s\t%s\t", file, + ascnow, hostname, CurDir); + if (setting_tedit) + fprintf (fp, "E"); + if (setting_tunedit) + fprintf (fp, "U"); + if (setting_tcommit) + fprintf (fp, "C"); + fprintf (fp, "\n"); + + if (fclose (fp) < 0) + { + if (update_dir[0] == '\0') + error (0, errno, "cannot close %s", file); + else + error (0, errno, "cannot close %s/%s", update_dir, file); + } + + xchmod (file, 1); + + /* Now stash the file away in CVSADM so that unedit can revert even if + it can't communicate with the server. We stash away a writable + copy so that if the user removes the working file, then restores it + with "cvs update" (which clears _editors but does not update + CVSADM_BASE), then a future "cvs edit" can still win. */ + /* Could save a system call by only calling mkdir if trying to create + the output file fails. But copy_file isn't set up to facilitate + that. */ + if (CVS_MKDIR (CVSADM_BASE, 0777) < 0) + { + if (errno != EEXIST +#ifdef EACCESS + /* OS/2; see longer comment in client.c. */ + && errno != EACCESS +#endif + ) + error (1, errno, "cannot mkdir %s", CVSADM_BASE); + } + basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (file)); + strcpy (basefilename, CVSADM_BASE); + strcat (basefilename, "/"); + strcat (basefilename, file); + copy_file (file, basefilename); + free (basefilename); + + return 0; +} + +static const char *const edit_usage[] = +{ + "Usage: %s %s [-l] [files...]\n", + "-l: Local directory only, not recursive\n", + "-a: Specify what actions for temporary watch, one of\n", + " edit,unedit,commit.all,none\n", + NULL +}; + +int +edit (argc, argv) + int argc; + char **argv; +{ + int local = 0; + int c; + int err; + int a_omitted; + + if (argc == -1) + usage (edit_usage); + + a_omitted = 1; + setting_tedit = 0; + setting_tunedit = 0; + setting_tcommit = 0; + optind = 1; + while ((c = getopt (argc, argv, "la:")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case 'a': + a_omitted = 0; + if (strcmp (optarg, "edit") == 0) + setting_tedit = 1; + else if (strcmp (optarg, "unedit") == 0) + setting_tunedit = 1; + else if (strcmp (optarg, "commit") == 0) + setting_tcommit = 1; + else if (strcmp (optarg, "all") == 0) + { + setting_tedit = 1; + setting_tunedit = 1; + setting_tcommit = 1; + } + else if (strcmp (optarg, "none") == 0) + { + setting_tedit = 0; + setting_tunedit = 0; + setting_tcommit = 0; + } + else + usage (edit_usage); + break; + case '?': + default: + usage (edit_usage); + break; + } + } + argc -= optind; + argv += optind; + + if (a_omitted) + { + setting_tedit = 1; + setting_tunedit = 1; + setting_tcommit = 1; + } + + /* No need to readlock since we aren't doing anything to the + repository. */ + err = start_recursion (edit_fileproc, (FILESDONEPROC) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, + 0, 0); + + err += send_notifications (argc, argv, local); + + return err; +} + +static int unedit_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +unedit_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + FILE *fp; + time_t now; + char *ascnow; + char *basefilename; + + if (noexec) + return 0; + + basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (file)); + strcpy (basefilename, CVSADM_BASE); + strcat (basefilename, "/"); + strcat (basefilename, file); + if (!isfile (basefilename)) + { + /* This file apparently was never cvs edit'd (e.g. we are uneditting + a directory where only some of the files were cvs edit'd. */ + free (basefilename); + return 0; + } + + if (xcmp (file, basefilename) != 0) + { + if (update_dir[0] != '\0') + printf ("%s/", update_dir); + printf ("%s has been modified; revert changes? ", file); + if (!yesno ()) + { + /* "no". */ + free (basefilename); + return 0; + } + } + rename_file (basefilename, file); + free (basefilename); + + fp = open_file (CVSADM_NOTIFY, "a"); + + (void) time (&now); + ascnow = asctime (gmtime (&now)); + ascnow[24] = '\0'; + fprintf (fp, "U%s\t%s GMT\t%s\t%s\t\n", file, + ascnow, hostname, CurDir); + + if (fclose (fp) < 0) + { + if (update_dir[0] == '\0') + error (0, errno, "cannot close %s", file); + else + error (0, errno, "cannot close %s/%s", update_dir, file); + } + + xchmod (file, 0); + return 0; +} + +int +unedit (argc, argv) + int argc; + char **argv; +{ + int local = 0; + int c; + int err; + + if (argc == -1) + usage (edit_usage); + + optind = 1; + while ((c = getopt (argc, argv, "l")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case '?': + default: + usage (edit_usage); + break; + } + } + argc -= optind; + argv += optind; + + /* No need to readlock since we aren't doing anything to the + repository. */ + err = start_recursion (unedit_fileproc, (FILESDONEPROC) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, + 0, 0); + + err += send_notifications (argc, argv, local); + + return err; +} + +void +mark_up_to_date (file) + char *file; +{ + char *base; + + /* The file is up to date, so we better get rid of an out of + date file in CVSADM_BASE. */ + base = xmalloc (strlen (file) + 80); + strcpy (base, CVSADM_BASE); + strcat (base, "/"); + strcat (base, file); + if (unlink_file (base) < 0 && ! existence_error (errno)) + error (0, errno, "cannot remove %s", file); + free (base); +} + + +void +editor_set (filename, editor, val) + char *filename; + char *editor; + char *val; +{ + char *edlist; + char *newlist; + + edlist = fileattr_get0 (filename, "_editors"); + newlist = fileattr_modify (edlist, editor, val, '>', ','); + if (edlist != NULL) + free (edlist); + /* If the attributes is unchanged, don't rewrite the attribute file. */ + if (!((edlist == NULL && newlist == NULL) + || (edlist != NULL + && newlist != NULL + && strcmp (edlist, newlist) == 0))) + fileattr_set (filename, "_editors", newlist); + if (newlist != NULL) + free (newlist); +} + +struct notify_proc_args { + /* What kind of notification, "edit", "tedit", etc. */ + char *type; + /* User who is running the command which causes notification. */ + char *who; + /* User to be notified. */ + char *notifyee; + /* File. */ + char *file; +}; + +/* Pass as a static until we get around to fixing Parse_Info to pass along + a void * where we can stash it. */ +static struct notify_proc_args *notify_args; + +static int notify_proc PROTO ((char *repository, char *filter)); + +static int +notify_proc (repository, filter) + char *repository; + char *filter; +{ + FILE *pipefp; + char *prog; + char *p; + char *q; + char *srepos; + struct notify_proc_args *args = notify_args; + + srepos = Short_Repository (repository); + prog = xmalloc (strlen (filter) + strlen (args->notifyee) + 1); + /* Copy FILTER to PROG, replacing the first occurrence of %s with + the notifyee. We only allocated enough memory for one %s, and I doubt + there is a need for more. */ + for (p = filter, q = prog; *p != '\0'; ++p) + { + if (p[0] == '%') + { + if (p[1] == 's') + { + strcpy (q, args->notifyee); + q += strlen (q); + strcpy (q, p + 2); + q += strlen (q); + break; + } + else + continue; + } + *q++ = *p; + } + *q = '\0'; + + pipefp = Popen (prog, "w"); + if (pipefp == NULL) + { + error (0, errno, "cannot write entry to notify filter: %s", prog); + free (prog); + return 1; + } + + fprintf (pipefp, "%s %s\n---\n", srepos, args->file); + fprintf (pipefp, "Triggered %s watch on %s\n", args->type, repository); + fprintf (pipefp, "By %s\n", args->who); + + /* Lots more potentially useful information we could add here; see + logfile_write for inspiration. */ + + free (prog); + return (pclose (pipefp)); +} + +void +notify_do (type, filename, who, val, watches, repository) + int type; + char *filename; + char *who; + char *val; + char *watches; + char *repository; +{ + static struct addremove_args blank; + struct addremove_args args; + char *watchers; + char *p; + char *endp; + char *nextp; + + /* Initialize fields to 0, NULL, or 0.0. */ + args = blank; + switch (type) + { + case 'E': + editor_set (filename, who, val); + break; + case 'U': + case 'C': + editor_set (filename, who, NULL); + break; + default: + return; + } + + watchers = fileattr_get0 (filename, "_watchers"); + p = watchers; + while (p != NULL) + { + char *q; + char *endq; + char *nextq; + char *notif; + + endp = strchr (p, '>'); + if (endp == NULL) + break; + nextp = strchr (p, ','); + + if ((size_t)(endp - p) == strlen (who) && strncmp (who, p, endp - p) == 0) + { + /* Don't notify user of their own changes. Would perhaps + be better to check whether it is the same working + directory, not the same user, but that is hairy. */ + p = nextp == NULL ? nextp : nextp + 1; + continue; + } + + /* Now we point q at a string which looks like + "edit+unedit+commit,"... and walk down it. */ + q = endp + 1; + notif = NULL; + while (q != NULL) + { + endq = strchr (q, '+'); + if (endq == NULL || (nextp != NULL && endq > nextp)) + { + if (nextp == NULL) + endq = q + strlen (q); + else + endq = nextp; + nextq = NULL; + } + else + nextq = endq + 1; + + /* If there is a temporary and a regular watch, send a single + notification, for the regular watch. */ + if (type == 'E' && endq - q == 4 && strncmp ("edit", q, 4) == 0) + { + notif = "edit"; + } + else if (type == 'U' + && endq - q == 6 && strncmp ("unedit", q, 6) == 0) + { + notif = "unedit"; + } + else if (type == 'C' + && endq - q == 6 && strncmp ("commit", q, 6) == 0) + { + notif = "commit"; + } + else if (type == 'E' + && endq - q == 5 && strncmp ("tedit", q, 5) == 0) + { + if (notif == NULL) + notif = "temporary edit"; + } + else if (type == 'U' + && endq - q == 7 && strncmp ("tunedit", q, 7) == 0) + { + if (notif == NULL) + notif = "temporary unedit"; + } + else if (type == 'C' + && endq - q == 7 && strncmp ("tcommit", q, 7) == 0) + { + if (notif == NULL) + notif = "temporary commit"; + } + q = nextq; + } + if (nextp != NULL) + ++nextp; + + if (notif != NULL) + { + struct notify_proc_args args; + size_t len = endp - p; + FILE *fp; + char *usersname; + char *line = NULL; + size_t line_len = 0; + + args.notifyee = NULL; + usersname = xmalloc (strlen (CVSroot) + + sizeof CVSROOTADM + + sizeof CVSROOTADM_USERS + + 20); + strcpy (usersname, CVSroot); + strcat (usersname, "/"); + strcat (usersname, CVSROOTADM); + strcat (usersname, "/"); + strcat (usersname, CVSROOTADM_USERS); + fp = fopen (usersname, "r"); + if (fp == NULL && !existence_error (errno)) + error (0, errno, "cannot read %s", usersname); + if (fp != NULL) + { + while (getline (&line, &line_len, fp) >= 0) + { + if (strncmp (line, p, len) == 0 + && line[len] == ':') + { + char *cp; + args.notifyee = xstrdup (line + len + 1); + cp = strchr (args.notifyee, ':'); + if (cp != NULL) + *cp = '\0'; + break; + } + } + if (ferror (fp)) + error (0, errno, "cannot read %s", usersname); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", usersname); + } + free (usersname); + free (line); + + if (args.notifyee == NULL) + { + args.notifyee = xmalloc (endp - p + 1); + strncpy (args.notifyee, p, endp - p); + args.notifyee[endp - p] = '\0'; + } + + notify_args = &args; + args.type = notif; + args.who = who; + args.file = filename; + + (void) Parse_Info (CVSROOTADM_NOTIFY, repository, notify_proc, 1); + free (args.notifyee); + } + + p = nextp; + } + if (watchers != NULL) + free (watchers); + + switch (type) + { + case 'E': + if (*watches == 'E') + { + args.add_tedit = 1; + ++watches; + } + if (*watches == 'U') + { + args.add_tunedit = 1; + ++watches; + } + if (*watches == 'C') + { + args.add_tcommit = 1; + } + watch_modify_watchers (filename, &args); + break; + case 'U': + case 'C': + args.remove_temp = 1; + watch_modify_watchers (filename, &args); + break; + } +} + +/* Check and send notifications. This is only for the client. */ +void +notify_check (repository, update_dir) + char *repository; + char *update_dir; +{ + FILE *fp; + char *line = NULL; + size_t line_len = 0; + + if (! server_started) + /* We are in the midst of a command which is not to talk to + the server (e.g. the first phase of a cvs edit). Just chill + out, we'll catch the notifications on the flip side. */ + return; + + /* We send notifications even if noexec. I'm not sure which behavior + is most sensible. */ + + fp = fopen (CVSADM_NOTIFY, "r"); + if (fp == NULL) + { + if (!existence_error (errno)) + error (0, errno, "cannot open %s", CVSADM_NOTIFY); + return; + } + while (getline (&line, &line_len, fp) > 0) + { + int notif_type; + char *filename; + char *val; + char *cp; + + notif_type = line[0]; + if (notif_type == '\0') + continue; + filename = line + 1; + cp = strchr (filename, '\t'); + if (cp == NULL) + continue; + *cp++ = '\0'; + val = cp; + + client_notify (repository, update_dir, filename, notif_type, val); + } + + if (ferror (fp)) + error (0, errno, "cannot read %s", CVSADM_NOTIFY); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", CVSADM_NOTIFY); + + /* Leave the CVSADM_NOTIFY file there, until the server tells us it + has dealt with it. */ +} + +static const char *const editors_usage[] = +{ + "Usage: %s %s [files...]\n", + NULL +}; + +static int editors_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +editors_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + char *them; + char *p; + + them = fileattr_get0 (file, "_editors"); + if (them == NULL) + return 0; + + if (update_dir[0] == '\0') + printf ("%s", file); + else + printf ("%s/%s", update_dir, file); + + p = them; + while (1) + { + putc ('\t', stdout); + while (*p != '>' && *p != '\0') + putc (*p++, stdout); + if (*p == '\0') + { + /* Only happens if attribute is misformed. */ + putc ('\n', stdout); + break; + } + ++p; + putc ('\t', stdout); + while (1) + { + while (*p != '+' && *p != ',' && *p != '\0') + putc (*p++, stdout); + if (*p == '\0') + { + putc ('\n', stdout); + goto out; + } + if (*p == ',') + { + ++p; + break; + } + ++p; + putc ('\t', stdout); + } + putc ('\n', stdout); + } + out:; + return 0; +} + +int +editors (argc, argv) + int argc; + char **argv; +{ + int local = 0; + int c; + + if (argc == -1) + usage (editors_usage); + + optind = 1; + while ((c = getopt (argc, argv, "l")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case '?': + default: + usage (editors_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); + /* 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 ("editors\012", 0); + return get_responses_and_close (); + } +#endif /* CLIENT_SUPPORT */ + + return start_recursion (editors_fileproc, (FILESDONEPROC) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 1, (char *)NULL, + 0, 0); +} diff --git a/gnu/usr.bin/cvs/src/edit.h b/gnu/usr.bin/cvs/src/edit.h new file mode 100644 index 00000000000..416ba79c24c --- /dev/null +++ b/gnu/usr.bin/cvs/src/edit.h @@ -0,0 +1,40 @@ +/* Interface to "cvs edit", "cvs watch on", and related features + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern int watch_on PROTO ((int argc, char **argv)); +extern int watch_off PROTO ((int argc, char **argv)); + +/* Check to see if any notifications are sitting around in need of being + sent. These are the notifications stored in CVSADM_NOTIFY (edit,unedit); + commit calls notify_do directly. */ +extern void notify_check PROTO ((char *repository, char *update_dir)); + +/* Issue a notification for file FILENAME. TYPE is 'E' for edit, 'U' + for unedit, and 'C' for commit. WHO is the user currently running. + For TYPE 'E', VAL is the time+host+directory data which goes in + _editors, and WATCHES is zero or more of E,U,C, in that order, to specify + what kinds of temporary watches to set. */ +extern void notify_do PROTO ((int type, char *filename, char *who, + char *val, char *watches, char *repository)); + +/* Set attributes to reflect the fact that EDITOR is editing FILENAME. + VAL is time+host+directory, or NULL if we are to say that EDITOR is + *not* editing FILENAME. */ +extern void editor_set PROTO ((char *filename, char *editor, char *val)); + +/* Take note of the fact that FILE is up to date (this munges CVS/Base; + processing of CVS/Entries is done separately). */ +extern void mark_up_to_date PROTO ((char *file)); diff --git a/gnu/usr.bin/cvs/src/entries.c b/gnu/usr.bin/cvs/src/entries.c index f5b40121632..19890f2f098 100644 --- a/gnu/usr.bin/cvs/src/entries.c +++ b/gnu/usr.bin/cvs/src/entries.c @@ -12,19 +12,69 @@ */ #include "cvs.h" +#include "getline.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)entries.c 1.44 94/10/07 $"; USE(rcsid); #endif -static Node *AddEntryNode PROTO((List * list, char *name, char *version, - char *timestamp, char *options, char *tag, - char *date, char *conflict)); +static Node *AddEntryNode PROTO((List * list, Entnode *entnode)); + +static Entnode *fgetentent PROTO((FILE *)); +static int fputentent PROTO((FILE *, Entnode *)); static FILE *entfile; static char *entfilename; /* for error messages */ +/* + * Construct an Entnode + */ +Entnode * +Entnode_Create(user, vn, ts, options, tag, date, ts_conflict) + const char *user; + const char *vn; + const char *ts; + const char *options; + const char *tag; + const char *date; + const char *ts_conflict; +{ + Entnode *ent; + + /* Note that timestamp and options must be non-NULL */ + ent = (Entnode *) xmalloc (sizeof (Entnode)); + ent->user = xstrdup (user); + ent->version = xstrdup (vn); + ent->timestamp = xstrdup (ts ? ts : ""); + ent->options = xstrdup (options ? options : ""); + ent->tag = xstrdup (tag); + ent->date = xstrdup (date); + ent->conflict = xstrdup (ts_conflict); + + return ent; +} + +/* + * Destruct an Entnode + */ +void +Entnode_Destroy (ent) + Entnode *ent; +{ + free (ent->user); + free (ent->version); + free (ent->timestamp); + free (ent->options); + if (ent->tag) + free (ent->tag); + if (ent->date) + free (ent->date); + if (ent->conflict) + free (ent->conflict); + free (ent); +} + /* * Write out the line associated with a node of an entries file */ @@ -34,32 +84,9 @@ write_ent_proc (node, closure) Node *node; void *closure; { - Entnode *p; - - p = (Entnode *) node->data; - if (fprintf (entfile, "/%s/%s/%s", node->key, p->version, - p->timestamp) == EOF) - error (1, errno, "cannot write %s", entfilename); - if (p->conflict) - { - if (fprintf (entfile, "+%s", p->conflict) < 0) - error (1, errno, "cannot write %s", entfilename); - } - if (fprintf (entfile, "/%s/", p->options) < 0) + if (fputentent(entfile, (Entnode *) node->data)) error (1, errno, "cannot write %s", entfilename); - if (p->tag) - { - if (fprintf (entfile, "T%s\n", p->tag) < 0) - error (1, errno, "cannot write %s", entfilename); - } - else if (p->date) - { - if (fprintf (entfile, "D%s\n", p->date) < 0) - error (1, errno, "cannot write %s", entfilename); - } - else if (fprintf (entfile, "\n") < 0) - error (1, errno, "cannot write %s", entfilename); return (0); } @@ -131,6 +158,7 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict) char *date; char *ts_conflict; { + Entnode *entnode; Node *node; #ifdef SERVER_SUPPORT @@ -156,7 +184,8 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict) #endif } - node = AddEntryNode (list, fname, vn, ts, options, tag, date, ts_conflict); + entnode = Entnode_Create(fname, vn, ts, options, tag, date, ts_conflict); + node = AddEntryNode (list, entnode); if (!noexec) { @@ -188,27 +217,22 @@ freesdt (p) free ((char *) sdtp); } -struct entent { - char *user; - char *vn; - char *ts; - char *options; - char *tag; - char *date; - char *ts_conflict; -}; - -struct entent * +static Entnode * fgetentent(fpin) FILE *fpin; { - static struct entent ent; - static char line[MAXLINELEN]; + Entnode *ent; + char *line; + size_t line_chars_allocated; register char *cp; char *user, *vn, *ts, *options; char *tag_or_date, *tag, *date, *ts_conflict; - while (fgets (line, sizeof (line), fpin) != NULL) + line = NULL; + line_chars_allocated = 0; + + ent = NULL; + while (getline (&line, &line_chars_allocated, fpin) > 0) { if (line[0] != '/') continue; @@ -257,7 +281,6 @@ fgetentent(fpin) struct stat sb; if (strlen (ts) > 30 && stat (user, &sb) == 0) { - extern char *ctime (); char *c = ctime (&sb.st_mtime); if (!strncmp (ts + 25, c, 24)) @@ -270,18 +293,46 @@ fgetentent(fpin) } } - ent.user = user; - ent.vn = vn; - ent.ts = ts; - ent.options = options; - ent.tag = tag; - ent.date = date; - ent.ts_conflict = ts_conflict; + ent = Entnode_Create(user, vn, ts, options, tag, date, ts_conflict); + break; + } + + free (line); + return ent; +} + +static int +fputentent(fp, p) + FILE *fp; + Entnode *p; +{ + if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0) + return 1; + if (p->conflict) + { + if (fprintf (fp, "+%s", p->conflict) < 0) + return 1; + } + if (fprintf (fp, "/%s/", p->options) < 0) + return 1; - return &ent; + if (p->tag) + { + if (fprintf (fp, "T%s\n", p->tag) < 0) + return 1; + } + else if (p->date) + { + if (fprintf (fp, "D%s\n", p->date) < 0) + return 1; + } + else + { + if (fprintf (fp, "\n") < 0) + return 1; } - return NULL; + return 0; } @@ -293,7 +344,7 @@ Entries_Open (aflag) int aflag; { List *entries; - struct entent *ent; + Entnode *ent; char *dirtag, *dirdate; int do_rewrite = 0; FILE *fpin; @@ -328,31 +379,18 @@ Entries_Open (aflag) { while ((ent = fgetentent (fpin)) != NULL) { - (void) AddEntryNode (entries, - ent->user, - ent->vn, - ent->ts, - ent->options, - ent->tag, - ent->date, - ent->ts_conflict); + (void) AddEntryNode (entries, ent); } fclose (fpin); } fpin = fopen (CVSADM_ENTLOG, "r"); - if (fpin != NULL) { + if (fpin != NULL) + { while ((ent = fgetentent (fpin)) != NULL) { - (void) AddEntryNode (entries, - ent->user, - ent->vn, - ent->ts, - ent->options, - ent->tag, - ent->date, - ent->ts_conflict); + (void) AddEntryNode (entries, ent); } do_rewrite = 1; fclose (fpin); @@ -362,8 +400,6 @@ Entries_Open (aflag) write_entries (entries); /* clean up and return */ - if (fpin) - (void) fclose (fpin); if (dirtag) free (dirtag); if (dirdate) @@ -398,16 +434,7 @@ Entries_delproc (node) Entnode *p; p = (Entnode *) node->data; - free (p->version); - free (p->timestamp); - free (p->options); - if (p->tag) - free (p->tag); - if (p->date) - free (p->date); - if (p->conflict) - free (p->conflict); - free ((char *) p); + Entnode_Destroy(p); } /* @@ -415,21 +442,14 @@ Entries_delproc (node) * list */ static Node * -AddEntryNode (list, name, version, timestamp, options, tag, date, conflict) +AddEntryNode (list, entdata) List *list; - char *name; - char *version; - char *timestamp; - char *options; - char *tag; - char *date; - char *conflict; + Entnode *entdata; { Node *p; - Entnode *entdata; /* was it already there? */ - if ((p = findnode (list, name)) != NULL) + if ((p = findnode (list, entdata->user)) != NULL) { /* take it out */ delnode (p); @@ -441,21 +461,11 @@ AddEntryNode (list, name, version, timestamp, options, tag, date, conflict) p->delproc = Entries_delproc; /* this one gets a key of the name for hashing */ - p->key = xstrdup (name); - - /* malloc the data parts and fill them in */ - p->data = xmalloc (sizeof (Entnode)); - entdata = (Entnode *) p->data; - entdata->version = xstrdup (version); - entdata->timestamp = xstrdup (timestamp); - if (entdata->timestamp == NULL) - entdata->timestamp = xstrdup ("");/* must be non-NULL */ - entdata->options = xstrdup (options); - if (entdata->options == NULL) - entdata->options = xstrdup ("");/* must be non-NULL */ - entdata->conflict = xstrdup (conflict); - entdata->tag = xstrdup (tag); - entdata->date = xstrdup (date); + /* FIXME This results in duplicated data --- the hash package shouldn't + assume that the key is dynamically allocated. The user's free proc + should be responsible for freeing the key. */ + p->key = xstrdup (entdata->user); + p->data = (char *) entdata; /* put the node into the list */ addnode (list, p); @@ -499,7 +509,7 @@ WriteTag (dir, tag, date) error (1, errno, "cannot close %s", tmp); } else - if (unlink_file (tmp) < 0 && errno != ENOENT) + if (unlink_file (tmp) < 0 && ! existence_error (errno)) error (1, errno, "cannot remove %s", tmp); } @@ -512,8 +522,6 @@ ParseTag (tagp, datep) char **datep; { FILE *fp; - char line[MAXLINELEN]; - char *cp; if (tagp) *tagp = (char *) NULL; @@ -522,15 +530,24 @@ ParseTag (tagp, datep) fp = fopen (CVSADM_TAG, "r"); if (fp) { - if (fgets (line, sizeof (line), fp) != NULL) + char *line; + int line_length; + size_t line_chars_allocated; + + line = NULL; + line_chars_allocated = 0; + + if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0) { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; + /* Remove any trailing newline. */ + if (line[line_length - 1] == '\n') + line[--line_length] = '\0'; if (*line == 'T' && tagp) *tagp = xstrdup (line + 1); else if (*line == 'D' && datep) *datep = xstrdup (line + 1); } (void) fclose (fp); + free (line); } } diff --git a/gnu/usr.bin/cvs/src/error.c b/gnu/usr.bin/cvs/src/error.c new file mode 100644 index 00000000000..beee0633090 --- /dev/null +++ b/gnu/usr.bin/cvs/src/error.c @@ -0,0 +1,188 @@ +/* error.c -- error handler for noninteractive utilities + Copyright (C) 1990-1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* David MacKenzie */ +/* Brian Berliner added support for CVS */ + +#include "cvs.h" + +#ifndef lint +static const char rcsid[] = "$CVSid: @(#)error.c 1.13 94/09/30 $"; +USE(rcsid); +#endif /* not lint */ + +#include + +/* If non-zero, error will use the CVS protocol to stdout to report error + messages. This will only be set in the CVS server parent process; + most other code is run via do_cvs_command, which forks off a child + process and packages up its stderr in the protocol. */ +int error_use_protocol; + +#ifdef HAVE_VPRINTF + +#if __STDC__ +#include +#define VA_START(args, lastarg) va_start(args, lastarg) +#else /* ! __STDC__ */ +#include +#define VA_START(args, lastarg) va_start(args) +#endif /* __STDC__ */ + +#else /* ! HAVE_VPRINTF */ + +#ifdef HAVE_DOPRNT +#define va_alist args +#define va_dcl int args; +#else /* ! HAVE_DOPRNT */ +#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 +#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; +#endif /* HAVE_DOPRNT */ + +#endif /* HAVE_VPRINTF */ + +#if STDC_HEADERS +#include +#include +#else /* ! STDC_HEADERS */ +#if __STDC__ +void exit(int status); +#else /* ! __STDC__ */ +void exit (); +#endif /* __STDC__ */ +#endif /* STDC_HEADERS */ + +extern char *strerror (); + +typedef void (*fn_returning_void) PROTO((void)); + +/* Function to call before exiting. */ +static fn_returning_void cleanup_fn; + +fn_returning_void +error_set_cleanup (arg) + fn_returning_void arg; +{ + fn_returning_void retval = cleanup_fn; + cleanup_fn = arg; + return retval; +} + +/* 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. */ +/* VARARGS */ +void +#if defined (HAVE_VPRINTF) && __STDC__ +error (int status, int errnum, const char *message, ...) +#else +error (status, errnum, message, va_alist) + int status; + int errnum; + const char *message; + va_dcl +#endif +{ + FILE *out = stderr; + extern char *program_name; + extern char *command_name; +#ifdef HAVE_VPRINTF + va_list args; +#endif + + if (error_use_protocol) + { + out = stdout; + printf ("E "); + } + + if (command_name && *command_name) + if (status) + fprintf (out, "%s [%s aborted]: ", program_name, command_name); + else + fprintf (out, "%s %s: ", program_name, command_name); + else + fprintf (out, "%s: ", program_name); +#ifdef HAVE_VPRINTF + VA_START (args, message); + vfprintf (out, message, args); + va_end (args); +#else +#ifdef HAVE_DOPRNT + _doprnt (message, &args, out); +#else + fprintf (out, message, a1, a2, a3, a4, a5, a6, a7, a8); +#endif +#endif + if (errnum) + fprintf (out, ": %s", strerror (errnum)); + putc ('\n', out); + fflush (out); + if (status) + { + if (cleanup_fn) + (*cleanup_fn) (); + exit (status); + } +} + +/* 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. */ +/* VARARGS */ +void +#if defined (HAVE_VPRINTF) && __STDC__ +fperror (FILE *fp, int status, int errnum, char *message, ...) +#else +fperror (fp, status, errnum, message, va_alist) + FILE *fp; + int status; + int errnum; + char *message; + va_dcl +#endif +{ + extern char *program_name; +#ifdef HAVE_VPRINTF + va_list args; +#endif + + fprintf (fp, "%s: ", program_name); +#ifdef HAVE_VPRINTF + VA_START (args, message); + vfprintf (fp, message, args); + va_end (args); +#else +#ifdef HAVE_DOPRNT + _doprnt (message, &args, fp); +#else + fprintf (fp, message, a1, a2, a3, a4, a5, a6, a7, a8); +#endif +#endif + if (errnum) + fprintf (fp, ": %s", strerror (errnum)); + putc ('\n', fp); + fflush (fp); + if (status) + { + if (cleanup_fn) + (*cleanup_fn) (); + exit (status); + } +} diff --git a/gnu/usr.bin/cvs/src/error.h b/gnu/usr.bin/cvs/src/error.h new file mode 100644 index 00000000000..7d4f5353797 --- /dev/null +++ b/gnu/usr.bin/cvs/src/error.h @@ -0,0 +1,47 @@ +/* error.h -- declaration for error-reporting function + Copyright (C) 1995 Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _error_h_ +#define _error_h_ + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#if __STDC__ +void error (int, int, const char *, ...) \ + __attribute__ ((__format__ (__printf__, 3, 4))); +#else +void error (); +#endif + +/* If non-zero, error will use the CVS protocol to report error + messages. This will only be set in the CVS server parent process; + most other code is run via do_cvs_command, which forks off a child + process and packages up its stderr in the protocol. */ +extern int error_use_protocol; + +#endif /* _error_h_ */ diff --git a/gnu/usr.bin/cvs/src/expand_path.c b/gnu/usr.bin/cvs/src/expand_path.c new file mode 100644 index 00000000000..f63ddff0035 --- /dev/null +++ b/gnu/usr.bin/cvs/src/expand_path.c @@ -0,0 +1,134 @@ +/* expand_path.c -- expand environmental variables in passed in string + * + * The main routine is expand_path(), it is the routine that handles + * the '~' character in four forms: + * ~name + * ~name/ + * ~/ + * ~ + * and handles environment variables contained within the pathname + * which are defined by: + * ${var_name} (var_name is the name of the environ variable) + * $var_name (var_name ends w/ non-alphanumeric char other than '_') + */ + +#include "cvs.h" +#include + +static char *expand_variable PROTO((char *env)); +extern char *xmalloc (); +extern void free (); + +/* char *expand_pathname(char *name) + * + * This routine will expand the pathname to account for ~ + * and $ characters as described above. If an error occurs, NULL + * is returned. + * Will only expand Built in CVS variables all others are ignored. + */ +char * +expand_path (name) + char *name; +{ + char *s; + char *d; + char mybuf[PATH_MAX]; + char buf[PATH_MAX]; + char *result; + s = name; + d = mybuf; + while ((*d++ = *s)) + if (*s++ == '$') + { + char *p = d; + char *e; + int flag = (*s == '{'); + + for (; (*d++ = *s); s++) + if (flag ? *s =='}' : + isalnum (*s) == 0 && *s!='_' ) + break; + *--d = 0; + e = expand_variable (&p[flag]); + + if (e) + { + for (d = &p[-1]; (*d++ = *e++);) + ; + --d; + if (flag && *s) + s++; + } + else + return NULL; /* no env variable */ + } + *d = 0; + s = mybuf; + d = buf; + /* If you don't want ~username ~/ to be expanded simply remove + * This entire if statement including the else portion + */ + if (*s++ == '~') + { + char *t; + char *p=s; + if (*s=='/' || *s==0) + t = getenv ("HOME"); + else + { + struct passwd *ps; + for (; *p!='/' && *p; p++) + ; + *p = 0; + ps = getpwnam (s); + if (ps == 0) + return NULL; /* no such user */ + t = ps->pw_dir; + } + while ((*d++ = *t++)) + ; + --d; + if (*p == 0) + *p = '/'; /* always add / */ + s=p; + } + else + --s; + /* Kill up to here */ + while ((*d++ = *s++)) + ; + *d=0; + result = xmalloc (sizeof(char) * strlen(buf)+1); + strcpy (result, buf); + return result; +} +static char * +expand_variable (name) + char *name; +{ + /* There is nothing expanding this function to allow it + * to read a file in the $CVSROOT/CVSROOT directory that + * says which environmental variables could be expanded + * or just say everything is fair game to be expanded + */ + if ( strcmp (name, CVSROOT_ENV) == 0 ) + return CVSroot; + else + if ( strcmp (name, RCSBIN_ENV) == 0 ) + return Rcsbin; + else + if ( strcmp (name, EDITOR1_ENV) == 0 ) + return Editor; + else + if ( strcmp (name, EDITOR2_ENV) == 0 ) + return Editor; + else + if ( strcmp (name, EDITOR3_ENV) == 0 ) + return Editor; + else + return NULL; + /* The code here could also just + * return whatever getenv would + * return. + */ +} diff --git a/gnu/usr.bin/cvs/src/fileattr.c b/gnu/usr.bin/cvs/src/fileattr.c new file mode 100644 index 00000000000..44987006bc8 --- /dev/null +++ b/gnu/usr.bin/cvs/src/fileattr.c @@ -0,0 +1,508 @@ +/* Implementation for file attribute munging features. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "cvs.h" +#include "getline.h" +#include "fileattr.h" +#include + +static void fileattr_read PROTO ((void)); +static int writeattr_proc PROTO ((Node *, void *)); + +/* Where to look for CVSREP_FILEATTR. */ +static char *fileattr_stored_repos; + +/* The in-memory attributes. */ +static List *attrlist; +static char *fileattr_default_attrs; +/* We have already tried to read attributes and failed in this directory + (for example, there is no CVSREP_FILEATTR file). */ +static int attr_read_attempted; + +/* Have the in-memory attributes been modified since we read them? */ +static int attrs_modified; + +/* Note that if noone calls fileattr_get, this is very cheap. No stat(), + no open(), no nothing. */ +void +fileattr_startdir (repos) + char *repos; +{ + assert (fileattr_stored_repos == NULL); + fileattr_stored_repos = xstrdup (repos); + assert (attrlist == NULL); + attr_read_attempted = 0; +} + +static void +fileattr_delproc (node) + Node *node; +{ + free (node->data); +} + +/* Read all the attributes for the current directory into memory. */ +static void +fileattr_read () +{ + char *fname; + FILE *fp; + char *line = NULL; + size_t line_len = 0; + + /* If there are no attributes, don't waste time repeatedly looking + for the CVSREP_FILEATTR file. */ + if (attr_read_attempted) + return; + + /* If NULL was passed to fileattr_startdir, then it isn't kosher to look + at attributes. */ + assert (fileattr_stored_repos != NULL); + + fname = xmalloc (strlen (fileattr_stored_repos) + + 1 + + sizeof (CVSREP_FILEATTR) + + 1); + + strcpy (fname, fileattr_stored_repos); + strcat (fname, "/"); + strcat (fname, CVSREP_FILEATTR); + + attr_read_attempted = 1; + fp = fopen (fname, "r"); + if (fp == NULL) + { + if (!existence_error (errno)) + error (0, errno, "cannot read %s", fname); + free (fname); + return; + } + attrlist = getlist (); + while (1) { + int nread; + nread = getline (&line, &line_len, fp); + if (nread < 0) + break; + /* Remove trailing newline. */ + line[nread - 1] = '\0'; + if (line[0] == 'F') + { + char *p; + Node *newnode; + + p = strchr (line, '\t'); + *p++ = '\0'; + newnode = getnode (); + newnode->type = FILEATTR; + newnode->delproc = fileattr_delproc; + newnode->key = xstrdup (line + 1); + newnode->data = xstrdup (p); + addnode (attrlist, newnode); + } + else if (line[0] == 'D') + { + char *p; + /* Currently nothing to skip here, but for future expansion, + ignore anything located here. */ + p = strchr (line, '\t'); + ++p; + fileattr_default_attrs = xstrdup (p); + } + /* else just ignore the line, for future expansion. */ + } + if (ferror (fp)) + error (0, errno, "cannot read %s", fname); + if (line != NULL) + free (line); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", fname); + attrs_modified = 0; + free (fname); +} + +char * +fileattr_get (filename, attrname) + char *filename; + char *attrname; +{ + Node *node; + size_t attrname_len = strlen (attrname); + char *p; + + if (attrlist == NULL) + fileattr_read (); + if (attrlist == NULL) + /* Either nothing has any attributes, or fileattr_read already printed + an error message. */ + return NULL; + + node = findnode (attrlist, filename); + if (node == NULL) + /* A file not mentioned has no attributes. */ + return NULL; + p = node->data; + while (1) { + if (strncmp (attrname, p, attrname_len) == 0 + && p[attrname_len] == '=') + { + /* Found it. */ + return p + attrname_len + 1; + } + p = strchr (p, ';'); + if (p == NULL) + break; + ++p; + } + /* The file doesn't have this attribute. */ + return NULL; +} + +char * +fileattr_get0 (filename, attrname) + char *filename; + char *attrname; +{ + char *cp; + char *cpend; + char *retval; + + cp = fileattr_get (filename, attrname); + if (cp == NULL) + return NULL; + cpend = strchr (cp, ';'); + if (cpend == NULL) + cpend = cp + strlen (cp); + retval = xmalloc (cpend - cp + 1); + strncpy (retval, cp, cpend - cp); + retval[cpend - cp] = '\0'; + return retval; +} + +char * +fileattr_modify (list, attrname, attrval, namevalsep, entsep) + char *list; + char *attrname; + char *attrval; + int namevalsep; + int entsep; +{ + char *retval; + char *rp; + size_t attrname_len = strlen (attrname); + + /* Portion of list before the attribute to be replaced. */ + char *pre; + char *preend; + /* Portion of list after the attribute to be replaced. */ + char *post; + + char *p; + char *p2; + + p = list; + pre = list; + preend = NULL; + /* post is NULL unless set otherwise. */ + post = NULL; + p2 = NULL; + if (list != NULL) + { + while (1) { + p2 = strchr (p, entsep); + if (p2 == NULL) + { + p2 = p + strlen (p); + if (preend == NULL) + preend = p2; + } + else + ++p2; + if (strncmp (attrname, p, attrname_len) == 0 + && p[attrname_len] == namevalsep) + { + /* Found it. */ + preend = p; + if (preend > list) + /* Don't include the preceding entsep. */ + --preend; + + post = p2; + } + if (p2[0] == '\0') + break; + p = p2; + } + } + if (post == NULL) + post = p2; + + if (preend == pre && attrval == NULL && post == p2) + return NULL; + + retval = xmalloc ((preend - pre) + + 1 + + (attrval == NULL ? 0 : (attrname_len + 1 + + strlen (attrval))) + + 1 + + (p2 - post) + + 1); + if (preend != pre) + { + strncpy (retval, pre, preend - pre); + rp = retval + (preend - pre); + if (attrval != NULL) + *rp++ = entsep; + *rp = '\0'; + } + else + retval[0] = '\0'; + if (attrval != NULL) + { + strcat (retval, attrname); + rp = retval + strlen (retval); + *rp++ = namevalsep; + strcpy (rp, attrval); + } + if (post != p2) + { + rp = retval + strlen (retval); + if (preend != pre || attrval != NULL) + *rp++ = entsep; + strncpy (rp, post, p2 - post); + rp += p2 - post; + *rp = '\0'; + } + return retval; +} + +void +fileattr_set (filename, attrname, attrval) + char *filename; + char *attrname; + char *attrval; +{ + Node *node; + char *p; + + attrs_modified = 1; + + if (filename == NULL) + { + p = fileattr_modify (fileattr_default_attrs, attrname, attrval, + '=', ';'); + if (fileattr_default_attrs != NULL) + free (fileattr_default_attrs); + fileattr_default_attrs = p; + return; + } + if (attrlist == NULL) + fileattr_read (); + if (attrlist == NULL) + { + /* Not sure this is a graceful way to handle things + in the case where fileattr_read was unable to read the file. */ + /* No attributes existed previously. */ + attrlist = getlist (); + } + + node = findnode (attrlist, filename); + if (node == NULL) + { + if (attrval == NULL) + /* Attempt to remove an attribute which wasn't there. */ + return; + + /* First attribute for this file. */ + node = getnode (); + node->type = FILEATTR; + node->delproc = fileattr_delproc; + node->key = xstrdup (filename); + node->data = xmalloc (strlen (attrname) + 1 + strlen (attrval) + 1); + strcpy (node->data, attrname); + strcat (node->data, "="); + strcat (node->data, attrval); + addnode (attrlist, node); + } + + p = fileattr_modify (node->data, attrname, attrval, '=', ';'); + free (node->data); + if (p == NULL) + delnode (node); + else + node->data = p; +} + +void +fileattr_newfile (filename) + char *filename; +{ + Node *node; + + if (attrlist == NULL) + fileattr_read (); + + if (fileattr_default_attrs == NULL) + return; + + if (attrlist == NULL) + { + /* Not sure this is a graceful way to handle things + in the case where fileattr_read was unable to read the file. */ + /* No attributes existed previously. */ + attrlist = getlist (); + } + + node = getnode (); + node->type = FILEATTR; + node->delproc = fileattr_delproc; + node->key = xstrdup (filename); + node->data = xstrdup (fileattr_default_attrs); + addnode (attrlist, node); + attrs_modified = 1; +} + +static int +writeattr_proc (node, data) + Node *node; + void *data; +{ + FILE *fp = (FILE *)data; + fputs ("F", fp); + fputs (node->key, fp); + fputs ("\t", fp); + fputs (node->data, fp); + fputs ("\n", fp); + return 0; +} + +void +fileattr_write () +{ + FILE *fp; + char *fname; + mode_t omask; + + if (!attrs_modified) + return; + + if (noexec) + return; + + /* If NULL was passed to fileattr_startdir, then it isn't kosher to set + attributes. */ + assert (fileattr_stored_repos != NULL); + + fname = xmalloc (strlen (fileattr_stored_repos) + + 1 + + sizeof (CVSREP_FILEATTR) + + 1); + + strcpy (fname, fileattr_stored_repos); + strcat (fname, "/"); + strcat (fname, CVSREP_FILEATTR); + + if (list_isempty (attrlist) && fileattr_default_attrs == NULL) + { + /* There are no attributes. */ + if (unlink_file (fname) < 0) + { + if (!existence_error (errno)) + { + error (0, errno, "cannot remove %s", fname); + } + } + + /* Now remove CVSREP directory, if empty. The main reason we bother + is that CVS 1.6 and earlier will choke if a CVSREP directory + exists, so provide the user a graceful way to remove it. */ + strcpy (fname, fileattr_stored_repos); + strcat (fname, "/"); + strcat (fname, CVSREP); + if (rmdir (fname) < 0) + { + if (errno != ENOTEMPTY + + /* Don't know why we would be here if there is no CVSREP + directory, but it seemed to be happening anyway, so + check for it. */ + && !existence_error (errno)) + error (0, errno, "cannot remove %s", fname); + } + + free (fname); + return; + } + + omask = umask (cvsumask); + fp = fopen (fname, "w"); + if (fp == NULL) + { + if (existence_error (errno)) + { + /* Maybe the CVSREP directory doesn't exist. Try creating it. */ + char *repname; + + repname = xmalloc (strlen (fileattr_stored_repos) + + 1 + + sizeof (CVSREP) + + 1); + strcpy (repname, fileattr_stored_repos); + strcat (repname, "/"); + strcat (repname, CVSREP); + + if (CVS_MKDIR (repname, 0777) < 0 && errno != EEXIST) + { + error (0, errno, "cannot make directory %s", repname); + (void) umask (omask); + free (repname); + return; + } + free (repname); + + fp = fopen (fname, "w"); + } + if (fp == NULL) + { + error (0, errno, "cannot write %s", fname); + (void) umask (omask); + return; + } + } + (void) umask (omask); + walklist (attrlist, writeattr_proc, fp); + if (fileattr_default_attrs != NULL) + { + fputs ("D\t", fp); + fputs (fileattr_default_attrs, fp); + fputs ("\n", fp); + } + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", fname); + attrs_modified = 0; + free (fname); +} + +void +fileattr_free () +{ + dellist (&attrlist); + if (fileattr_stored_repos != NULL) + free (fileattr_stored_repos); + fileattr_stored_repos = NULL; + if (fileattr_default_attrs != NULL) + free (fileattr_default_attrs); + fileattr_default_attrs = NULL; +} diff --git a/gnu/usr.bin/cvs/src/fileattr.h b/gnu/usr.bin/cvs/src/fileattr.h new file mode 100644 index 00000000000..1a83ab43de5 --- /dev/null +++ b/gnu/usr.bin/cvs/src/fileattr.h @@ -0,0 +1,123 @@ +/* Declarations for file attribute munging features. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef FILEATTR_H + +/* File containing per-file attributes. Format is a series of entries: + + ENT-TYPE FILENAME ATTRNAME = ATTRVAL + {; ATTRNAME = ATTRVAL} + + ENT-TYPE is 'F' for a file, in which case the entry specifies the + attributes for that file. + + ENT-TYPE is 'D', and FILENAME empty, to specify default attributes + to be used for newly added files. + + There is currently no way of quoting tabs or linefeeds in the + filename, '=' in ATTRNAME, ';' in ATTRVAL, etc. I'm not sure + whether I think we need one. Note: the current implementation also + doesn't handle '\0' in any of the fields. + + By convention, ATTRNAME starting with '_' is for an attribute given + special meaning by CVS; other ATTRNAMEs are for user-defined attributes + (or will be, once we add commands to manipulate user-defined attributes). + + Builtin attributes: + + _watched: Present means the file is watched and should be checked out + read-only. + + _watchers: Users with watches for this file. Value is + WATCHER > TYPE { , WATCHER > TYPE } + where WATCHER is a username, and TYPE is edit,unedit,commit separated by + + (or nothing if none; there is no "none" or "all" keyword). + + _editors: Users editing this file. Value is + EDITOR > VAL { , EDITOR > VAL } + where EDITOR is a username, and VAL is TIME+HOSTNAME+PATHNAME, where + TIME is when the "cvs edit" command happened, + and HOSTNAME and PATHNAME are for the working directory. */ + +#define CVSREP_FILEATTR "CVS/fileattr" + +/* Prepare for a new directory with repository REPOS. If REPOS is NULL, + then prepare for a "non-directory"; the caller can call fileattr_write + and fileattr_free, but must not call fileattr_get or fileattr_set. */ +extern void fileattr_startdir PROTO ((char *repos)); + +/* Get the attribute ATTRNAME for file FILENAME. The return value + points into memory managed by the fileattr_* routines, should not + be altered by the caller, and is only good until the next call to + fileattr_clear or fileattr_set. It points to the value, terminated + by '\0' or ';'. Return NULL if said file lacks said attribute. */ +extern char *fileattr_get PROTO ((char *filename, char *attrname)); + +/* Like fileattr_get, but return a pointer to a newly malloc'd string + terminated by '\0' (or NULL if said file lacks said attribute). */ +extern char *fileattr_get0 PROTO ((char *filename, char *attrname)); + +/* This is just a string manipulation function; it does not manipulate + file attributes as such. + + LIST is in the format + + ATTRNAME NAMEVALSEP ATTRVAL {ENTSEP ATTRNAME NAMEVALSEP ATTRVAL} + + And we want to put in an attribute with name NAME and value VAL, + replacing the already-present attribute with name NAME if there is + one. Or if VAL is NULL remove attribute NAME. Return a new + malloc'd list; don't muck with the one passed in. If we are removing + the last attribute return NULL. LIST can be NULL to mean that we + started out without any attributes. + + Examples: + + fileattr_modify ("abc=def", "xxx", "val", '=', ';')) => "abc=def;xxx=val" + fileattr_modify ("abc=def", "abc", "val", '=', ';')) => "abc=val" + fileattr_modify ("abc=v1;def=v2", "abc", "val", '=', ';')) + => "abc=val;def=v2" + fileattr_modify ("abc=v1;def=v2", "def", "val", '=', ';')) + => "abc=v1;def=val" + fileattr_modify ("abc=v1;def=v2", "xxx", "val")) + => "abc=v1;def=v2;xxx=val" + fileattr_modify ("abc=v1;def=v2;ghi=v3", "def", "val", '=', ';')) + => "abc=v1;def=val;ghi=v3" +*/ + +extern char *fileattr_modify PROTO ((char *list, char *attrname, + char *attrval, int namevalsep, + int entsep)); + +/* Set attribute ATTRNAME for file FILENAME to ATTRVAL. If ATTRVAL is NULL, + the attribute is removed. Changes are not written to disk until the + next call to fileattr_write. If FILENAME is NULL, set attributes for + files created in the future. If ATTRVAL is NULL, remove that attribute. */ +extern void fileattr_set PROTO ((char *filename, char *attrname, + char *attrval)); + +/* Set the attributes for file FILENAME in whatever manner is appropriate + for a newly created file. */ +extern void fileattr_newfile PROTO ((char *filename)); + +/* Write out all modified attributes. */ +extern void fileattr_write PROTO ((void)); + +/* Free all memory allocated by fileattr_*. */ +extern void fileattr_free PROTO ((void)); + +#define FILEATTR_H 1 +#endif /* fileattr.h */ diff --git a/gnu/usr.bin/cvs/src/filesubr.c b/gnu/usr.bin/cvs/src/filesubr.c index c2fb5a4304d..41bbfc89846 100644 --- a/gnu/usr.bin/cvs/src/filesubr.c +++ b/gnu/usr.bin/cvs/src/filesubr.c @@ -151,33 +151,88 @@ int isfile (file) const char *file; { - struct stat sb; - - if (stat (file, &sb) < 0) - return (0); - return (1); + return isaccessible(file, F_OK); } /* * Returns non-zero if the argument file is readable. - * XXX - must be careful if "cvs" is ever made setuid! */ int isreadable (file) const char *file; { - return (access (file, R_OK) != -1); + return isaccessible(file, R_OK); } /* - * Returns non-zero if the argument file is writable - * XXX - muct be careful if "cvs" is ever made setuid! + * Returns non-zero if the argument file is writable. */ int iswritable (file) const char *file; { - return (access (file, W_OK) != -1); + return isaccessible(file, W_OK); +} + +/* + * Returns non-zero if the argument file is accessable according to + * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid + * bits set. + */ +int +isaccessible (file, mode) + const char *file; + const int mode; +{ +#ifdef SETXID_SUPPORT + struct stat sb; + int umask = 0; + int gmask = 0; + int omask = 0; + int uid; + + if (stat(file, &sb) == -1) + return 0; + if (mode == F_OK) + return 1; + + uid = geteuid(); + if (uid == 0) /* superuser */ + { + if (mode & X_OK) + return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH); + else + return 1; + } + + if (mode & R_OK) + { + umask |= S_IRUSR; + gmask |= S_IRGRP; + omask |= S_IROTH; + } + if (mode & W_OK) + { + umask |= S_IWUSR; + gmask |= S_IWGRP; + omask |= S_IWOTH; + } + if (mode & X_OK) + { + umask |= S_IXUSR; + gmask |= S_IXGRP; + omask |= S_IXOTH; + } + + if (sb.st_uid == uid) + return (sb.st_mode & umask) == umask; + else if (sb.st_gid == getegid()) + return (sb.st_mode & gmask) == gmask; + else + return (sb.st_mode & omask) == omask; +#else + return access(file, mode) == 0; +#endif } /* @@ -202,9 +257,9 @@ void make_directory (name) const char *name; { - struct stat buf; + struct stat sb; - if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode))) + if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) error (0, 0, "%s already exists but is not a directory", name); if (!noexec && mkdir (name, 0777) < 0) error (1, errno, "cannot make directory %s", name); @@ -225,7 +280,7 @@ make_directories (name) if (mkdir (name, 0777) == 0 || errno == EEXIST) return; - if (errno != ENOENT) + if (! existence_error (errno)) { error (0, errno, "cannot make path to %s", name); return; @@ -242,8 +297,7 @@ make_directories (name) /* * Change the mode of a file, either adding write permissions, or removing - * all write permissions. Adding write permissions honors the current umask - * setting. + * all write permissions. Either change honors the current umask setting. */ void xchmod (fname, writable) @@ -259,17 +313,18 @@ xchmod (fname, writable) error (0, errno, "cannot stat %s", fname); return; } + oumask = umask (0); + (void) umask (oumask); if (writable) { - oumask = umask (0); - (void) umask (oumask); - mode = sb.st_mode | ~oumask & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) | - ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) | - ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)); + mode = sb.st_mode | (~oumask + & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) + | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) + | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0))); } else { - mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH); + mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask; } if (trace) @@ -309,7 +364,9 @@ rename_file (from, to) } /* - * link a file, if possible. + * link a file, if possible. Warning: the Windows NT version of this + * function just copies the file, so only use this function in ways + * that can deal with either a link or a copy. */ int link_file (from, to) @@ -401,7 +458,7 @@ deep_remove_dir (path) struct dirent *dp; char buf[PATH_MAX]; - if ( rmdir (path) != 0 && errno == ENOTEMPTY ) + if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST)) { if ((dirp = opendir (path)) == NULL) /* If unable to open the directory return @@ -439,7 +496,8 @@ deep_remove_dir (path) } closedir (dirp); return rmdir (path); - } + } + /* Was able to remove the directory return 0 */ return 0; } diff --git a/gnu/usr.bin/cvs/src/find_names.c b/gnu/usr.bin/cvs/src/find_names.c index 82959b5754b..b7bf42bc070 100644 --- a/gnu/usr.bin/cvs/src/find_names.c +++ b/gnu/usr.bin/cvs/src/find_names.c @@ -219,7 +219,8 @@ find_dirs (dir, list, checkadm) if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0 || strcmp (dp->d_name, CVSATTIC) == 0 || - strcmp (dp->d_name, CVSLCK) == 0) + strcmp (dp->d_name, CVSLCK) == 0 || + strcmp (dp->d_name, CVSREP) == 0) continue; #ifdef DT_DIR diff --git a/gnu/usr.bin/cvs/src/hash.c b/gnu/usr.bin/cvs/src/hash.c index 8ac93237c38..084fdf2c0e4 100644 --- a/gnu/usr.bin/cvs/src/hash.c +++ b/gnu/usr.bin/cvs/src/hash.c @@ -30,7 +30,9 @@ hashp (key) while (*key != 0) { - h = (h << 4) + *key++; + unsigned int c = *key++; + /* The FOLD_FN_CHAR is so that findnode_fn works. */ + h = (h << 4) + FOLD_FN_CHAR (c); if ((g = h & 0xf0000000) != 0) h = (h ^ (g >> 24)) ^ g; } @@ -271,6 +273,29 @@ findnode (list, key) return ((Node *) NULL); } +/* + * Like findnode, but for a filename. + */ +Node * +findnode_fn (list, key) + List *list; + const char *key; +{ + Node *head, *p; + + if (list == (List *) NULL) + return ((Node *) NULL); + + head = list->hasharray[hashp (key)]; + if (head == (Node *) NULL) + return ((Node *) NULL); + + for (p = head->hashnext; p != head; p = p->hashnext) + if (fncmp (p->key, key) == 0) + return (p); + return ((Node *) NULL); +} + /* * walk a list with a specific proc */ @@ -292,6 +317,13 @@ walklist (list, proc, closure) return (err); } +int +list_isempty (list) + List *list; +{ + return list == NULL || list->list->next == list->list; +} + /* * sort the elements of a list (in place) */ @@ -358,6 +390,7 @@ nodetypestring (type) case UPDATE: return("UPDATE"); case LOCK: return("LOCK"); case NDBMNODE: return("NDBMNODE"); + case FILEATTR: return("FILEATTR"); } return(""); diff --git a/gnu/usr.bin/cvs/src/hash.h b/gnu/usr.bin/cvs/src/hash.h index e30511a2701..5dcc4f6d6f1 100644 --- a/gnu/usr.bin/cvs/src/hash.h +++ b/gnu/usr.bin/cvs/src/hash.h @@ -19,7 +19,7 @@ enum ntype { UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE, - RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE + RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE, FILEATTR }; typedef enum ntype Ntype; @@ -46,9 +46,11 @@ typedef struct list List; List *getlist PROTO((void)); Node *findnode PROTO((List * list, const char *key)); +Node *findnode_fn PROTO((List * list, const char *key)); Node *getnode PROTO((void)); int addnode PROTO((List * list, Node * p)); int walklist PROTO((List * list, int (*)(Node *n, void *closure), void *closure)); +int list_isempty PROTO ((List *list)); void dellist PROTO((List ** listp)); void delnode PROTO((Node * p)); void freenode PROTO((Node * p)); diff --git a/gnu/usr.bin/cvs/src/history.c b/gnu/usr.bin/cvs/src/history.c index 7a40b7bd8bd..47310a91654 100644 --- a/gnu/usr.bin/cvs/src/history.c +++ b/gnu/usr.bin/cvs/src/history.c @@ -579,8 +579,7 @@ history (argc, argv) option_with_arg ("-x", rec_types); option_with_arg ("-z", tz_name); - if (fprintf (to_server, "history\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("history\012", 0); return get_responses_and_close (); } #endif @@ -944,6 +943,7 @@ fill_hrec (line, hr) int c; int off; static int idx = 0; + unsigned long date; memset ((char *) hr, 0, sizeof (*hr)); while (isspace (*line)) @@ -953,7 +953,8 @@ fill_hrec (line, hr) *rtn++ = '\0'; hr->type = line++; - (void) sscanf (line, "%x", &hr->date); + (void) sscanf (line, "%lx", &date); + hr->date = date; while (*line && strchr ("0123456789abcdefABCDEF", *line)) line++; if (*line == '\0') diff --git a/gnu/usr.bin/cvs/src/ignore.c b/gnu/usr.bin/cvs/src/ignore.c index c4bf510ecd1..fc2a425a3fe 100644 --- a/gnu/usr.bin/cvs/src/ignore.c +++ b/gnu/usr.bin/cvs/src/ignore.c @@ -27,11 +27,15 @@ static int ign_size; /* This many slots available (plus static int ign_hold; /* Index where first "temporary" item * is held */ -const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state .nse_depinfo #* .#* cvslog.* ,* CVS* .del-* *.a *.o *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej"; +const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.o *.obj *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej"; #define IGN_GROW 16 /* grow the list by 16 elements at a * time */ +/* Nonzero if we have encountered an -I ! directive, which means one should + no longer ask the server about what is in CVSROOTADM_IGNORE. */ +int ign_inhibit_server; + /* * To the "ignore list", add the hard-coded default ignored wildcards above, * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in @@ -45,14 +49,26 @@ ign_setup () char file[PATH_MAX]; char *tmp; + ign_inhibit_server = 0; + /* Start with default list and special case */ tmp = xstrdup (ign_default); ign_add (tmp, 0); free (tmp); - /* Then add entries found in repository, if it exists */ - (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_IGNORE); - ign_add_file (file, 0); +#ifdef CLIENT_SUPPORT + /* The client handles another way, by (after it does its own ignore file + processing, and only if !ign_inhibit_server), letting the server + know about the files and letting it decide whether to ignore + them based on CVSROOOTADM_IGNORE. */ + if (!client_active) +#endif + { + /* Then add entries found in repository, if it exists */ + (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, + CVSROOTADM_IGNORE); + ign_add_file (file, 0); + } /* Then add entries found in home dir, (if user has one) and file exists */ if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir) @@ -118,7 +134,7 @@ ign_add_file (file, hold) fp = fopen (file, "r"); if (fp == NULL) { - if (errno != ENOENT) + if (! existence_error (errno)) error (0, errno, "cannot open %s", file); return; } @@ -165,7 +181,10 @@ ign_add (ign, hold) /* if we are doing a '!', continue; otherwise add the '*' */ if (*ign == '!') + { + ign_inhibit_server = 1; continue; + } } else if (*ign == '!') { @@ -273,3 +292,81 @@ int ignore_directory (name) return 0; } + +/* + * Process the current directory, looking for files not in ILIST and not on + * the global ignore list for this directory. If we find one, call PROC + * passing it the name of the file and the update dir. + */ +void +ignore_files (ilist, update_dir, proc) + List *ilist; + char *update_dir; + Ignore_proc proc; +{ + DIR *dirp; + struct dirent *dp; + struct stat sb; + char *file; + char *xdir; + + /* we get called with update_dir set to "." sometimes... strip it */ + if (strcmp (update_dir, ".") == 0) + xdir = ""; + else + xdir = update_dir; + + dirp = opendir ("."); + if (dirp == NULL) + return; + + ign_add_file (CVSDOTIGNORE, 1); + wrap_add_file (CVSDOTWRAPPER, 1); + + while ((dp = readdir (dirp)) != NULL) + { + file = dp->d_name; + if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0) + continue; + if (findnode_fn (ilist, file) != NULL) + continue; + + if ( +#ifdef DT_DIR + dp->d_type != DT_UNKNOWN || +#endif + lstat(file, &sb) != -1) + { + + if ( +#ifdef DT_DIR + dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN && +#endif + S_ISDIR(sb.st_mode)) + { + char temp[PATH_MAX]; + + (void) sprintf (temp, "%s/%s", file, CVSADM); + if (isdir (temp)) + continue; + } +#ifdef S_ISLNK + else if ( +#ifdef DT_DIR + dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && +#endif + S_ISLNK(sb.st_mode)) + { + continue; + } +#endif + } + + /* We could be ignoring FIFOs and other files which are neither + regular files nor directories here. */ + if (ign_name (file)) + continue; + (*proc) (file, xdir); + } + (void) closedir (dirp); +} diff --git a/gnu/usr.bin/cvs/src/import.c b/gnu/usr.bin/cvs/src/import.c index 95d3c4338d0..9fdf5a11be3 100644 --- a/gnu/usr.bin/cvs/src/import.c +++ b/gnu/usr.bin/cvs/src/import.c @@ -207,8 +207,6 @@ import (argc, argv) { int err; - ign_setup (); - if (use_file_modtime) send_arg("-d"); @@ -218,6 +216,14 @@ import (argc, argv) option_with_arg ("-m", message); if (keyword_opt != NULL) option_with_arg ("-k", keyword_opt); + /* The only ignore processing which takes place on the server side + is the CVSROOT/cvsignore file. But if the user specified -I !, + the documented behavior is to not process said file. */ + if (ign_inhibit_server) + { + send_arg ("-I"); + send_arg ("!"); + } { int i; @@ -229,8 +235,7 @@ import (argc, argv) client_import_setup (repository); err = import_descend (message, argv[1], argc - 2, argv + 2); client_import_done (); - if (fprintf (to_server, "import\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("import\012", 0); err += get_responses_and_close (); return err; } @@ -240,7 +245,7 @@ import (argc, argv) * Make all newly created directories writable. Should really use a more * sophisticated security mechanism here. */ - (void) umask (2); + (void) umask (cvsumask); make_directories (repository); /* Create the logfile that will be logged upon completion */ @@ -333,16 +338,15 @@ import_descend (message, vtag, targc, targv) { if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) continue; - if (ign_name (dp->d_name)) - { #ifdef SERVER_SUPPORT - /* CVS directories are created by server.c because it doesn't - special-case import. So don't print a message about them. - Do print a message about other ignored files (although - most of these will get ignored on the client side). */ - if (server_active && strcmp (dp->d_name, CVSADM) == 0) - continue; + /* CVS directories are created in the temp directory by + server.c because it doesn't special-case import. So + don't print a message about them, regardless of -I!. */ + if (server_active && strcmp (dp->d_name, CVSADM) == 0) + continue; #endif + if (ign_name (dp->d_name)) + { add_log ('I', dp->d_name); continue; } @@ -572,7 +576,6 @@ add_rev (message, rcs, vfile, vers) { int locked, status, ierrno; char *tocvsPath; - struct stat vfile_stat; if (noexec) return (0); @@ -591,20 +594,29 @@ add_rev (message, rcs, vfile, vers) locked = 1; } tocvsPath = wrap_tocvs_process_file (vfile); + if (tocvsPath == NULL) + { + /* We play with hard links rather than passing -u to ci to avoid + expanding RCS keywords (see test 106.5 in sanity.sh). */ + if (link_file (vfile, FILE_HOLDER) < 0) + { + if (errno == EEXIST) + { + (void) unlink_file (FILE_HOLDER); + (void) link_file (vfile, FILE_HOLDER); + } + else + { + ierrno = errno; + fperror (logfp, 0, ierrno, + "ERROR: cannot create link to %s", vfile); + error (0, ierrno, "ERROR: cannot create link to %s", vfile); + return (1); + } + } + } - /* We used to deposit the revision with -r; RCS would delete the - working file, but we'd keep a hard link to it, and rename it - back after running RCS (ooh, atomicity). However, that - strategy doesn't work on operating systems without hard links - (like Windows NT). Instead, let's deposit it using -u, and - restore its permission bits afterwards. This also means the - file always exists under its own name. */ - if (! tocvsPath) - stat (vfile, &vfile_stat); - - run_setup ("%s%s -q -f %s%s", Rcsbin, RCS_CI, - (tocvsPath ? "-r" : "-u"), - vbranch); + run_setup ("%s%s -q -f -r%s", Rcsbin, RCS_CI, vbranch); run_args ("-m%s", make_message_rcslegal (message)); if (use_file_modtime) run_arg ("-d"); @@ -613,9 +625,11 @@ add_rev (message, rcs, vfile, vers) status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); ierrno = errno; - /* Restore the permissions on vfile. */ - if (! tocvsPath) - chmod (vfile, vfile_stat.st_mode); + if (tocvsPath == NULL) + rename_file (FILE_HOLDER, vfile); + else + if (unlink_file_dir (tocvsPath) < 0) + error (0, errno, "cannot remove %s", tocvsPath); if (status) { @@ -989,11 +1003,16 @@ add_rcs_file (message, rcs, user, vtag, targc, targv) (void) fclose (fpuser); /* - * Fix the modes on the RCS files. They must maintain the same modes as - * the original user file, except that all write permissions must be + * Fix the modes on the RCS files. The user modes of the original + * user file are propagated to the group and other modes as allowed + * by the repository umask, except that all write permissions are * turned off. */ - mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH); + mode = (sb.st_mode | + (sb.st_mode & S_IRWXU) >> 3 | + (sb.st_mode & S_IRWXU) >> 6) & + ~cvsumask & + ~(S_IWRITE | S_IWGRP | S_IWOTH); if (chmod (rcs, mode) < 0) { ierrno = errno; @@ -1041,14 +1060,15 @@ expand_at_signs (buf, size, fp) { char *cp, *end; + errno = 0; for (cp = buf, end = buf + size; cp < end; cp++) { if (*cp == '@') { - if (putc ('@', fp) == EOF) + if (putc ('@', fp) == EOF && errno != 0) return EOF; } - if (putc (*cp, fp) == EOF) + if (putc (*cp, fp) == EOF && errno != 0) return (EOF); } return (1); diff --git a/gnu/usr.bin/cvs/src/log.c b/gnu/usr.bin/cvs/src/log.c index d11757166b6..cbe24fc4801 100644 --- a/gnu/usr.bin/cvs/src/log.c +++ b/gnu/usr.bin/cvs/src/log.c @@ -67,17 +67,13 @@ cvslog (argc, argv) for (i = 1; i < argc && argv[i][0] == '-'; i++) send_arg (argv[i]); -#if 0 + send_file_names (argc - i, argv + i); /* FIXME: We shouldn't have to send current files to get log entries, but it doesn't work yet and I haven't debugged it. So send the files -- it's slower but it works. gnu@cygnus.com Apr94 */ - send_file_names (argc - i, argv + i); -#else send_files (argc - i, argv + i, local, 0); -#endif - if (fprintf (to_server, "log\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("log\012", 0); err = get_responses_and_close (); return err; } @@ -86,8 +82,8 @@ cvslog (argc, argv) av = argv; #endif - err = start_recursion (log_fileproc, (int (*) ()) NULL, log_dirproc, - (int (*) ()) NULL, argc - i, argv + i, local, + err = start_recursion (log_fileproc, (FILESDONEPROC) NULL, log_dirproc, + (DIRLEAVEPROC) NULL, argc - i, argv + i, local, W_LOCAL | W_REPOS | W_ATTIC, 0, 1, (char *) NULL, 1, 0); return (err); diff --git a/gnu/usr.bin/cvs/src/login.c b/gnu/usr.bin/cvs/src/login.c new file mode 100644 index 00000000000..c6001514ff7 --- /dev/null +++ b/gnu/usr.bin/cvs/src/login.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA + * + * You may distribute under the terms of the GNU General Public License as + * specified in the README file that comes with CVS. + * + * Allow user to log in for an authenticating server. + */ + +#include "cvs.h" + +#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */ + +#include +#include +#include + +#ifndef lint +static const char rcsid[] = "$CVSid: @(#)login.c 1.1 95/10/01 $"; +USE(rcsid); +#endif + +#ifndef CVS_PASSWORD_FILE +#define CVS_PASSWORD_FILE ".cvspass" +#endif + +/* If non-NULL, get_cvs_password() will just return this. */ +static char *cvs_password = NULL; + +/* The return value will need to be freed. */ +char * +construct_cvspass_filename () +{ + char *homedir; + char *passfile; + + /* Environment should override file. */ + if ((passfile = getenv ("CVS_PASSFILE")) != NULL) + return xstrdup (passfile); + + /* Construct absolute pathname to user's password file. */ + /* todo: does this work under Win-NT and OS/2 ? */ + homedir = getenv ("HOME"); + if (! homedir) + { + error (1, errno, "could not find out home directory"); + return (char *) NULL; + } + + passfile = + (char *) xmalloc (strlen (homedir) + strlen (CVS_PASSWORD_FILE) + 3); + strcpy (passfile, homedir); + strcat (passfile, "/"); + strcat (passfile, CVS_PASSWORD_FILE); + + /* Safety first and last, Scouts. */ + if (isfile (passfile)) + /* xchmod() is too polite. */ + chmod (passfile, 0600); + + return passfile; +} + + +/* Prompt for a password, and store it in the file "CVS/.cvspass". + * + * Because the user might be accessing multiple repositories, with + * different passwords for each one, the format of ~/.cvspass is: + * + * user@host:/path Acleartext_password + * user@host:/path Acleartext_password + * ... + * + * Of course, the "user@" might be left off -- it's just based on the + * value of CVSroot. + * + * The "A" before "cleartext_password" is a literal capital A. It's a + * version number indicating which form of scrambling we're doing on + * the password -- someday we might provide something more secure than + * the trivial encoding we do now, and when that day comes, it would + * be nice to remain backward-compatible. + * + * Like .netrc, the file's permissions are the only thing preventing + * it from being read by others. Unlike .netrc, we will not be + * fascist about it, at most issuing a warning, and never refusing to + * work. + */ +int +login (argc, argv) + int argc; + char **argv; +{ + char *username; + int i; + char *passfile; + FILE *fp; + char *typed_password, *found_password; + char *linebuf = (char *) NULL; + size_t linebuf_len; + int root_len, already_entered = 0; + + /* Make this a "fully-qualified" CVSroot if necessary. */ + if (! strchr (CVSroot, '@')) + { + /* We need to prepend "user@host:". */ + char *tmp; + + printf ("Repository \"%s\" not fully-qualified.\n", CVSroot); + printf ("Please enter \"user@host:/path\": "); + fflush (stdout); + getline (&linebuf, &linebuf_len, stdin); + + tmp = xmalloc (strlen (linebuf) + 1); + + /* Give it some permanent storage. */ + strcpy (tmp, linebuf); + tmp[strlen (linebuf) - 1] = '\0'; + CVSroot = tmp; + + /* Reset. */ + free (linebuf); + linebuf = (char *) NULL; + } + + if (CVSroot[0] != ':') + { + /* Then we need to prepend ":pserver:". */ + char *tmp; + + tmp = xmalloc (strlen (":pserver:") + strlen (CVSroot) + 1); + strcpy (tmp, ":pserver:"); + strcat (tmp, CVSroot); + CVSroot = tmp; + } + + /* Check to make sure it's fully-qualified before going on. + * Fully qualified in this context means it has both a user and a + * host:repos portion. + */ + { + char *r; + + /* After confirming that CVSroot is non-NULL, we skip past the + initial ":pserver:" to test the rest of it. */ + + if (! CVSroot) + error (1, 0, "CVSroot is NULL"); + else if (! strchr ((r = (CVSroot + strlen (":pserver:"))), '@')) + goto not_fqrn; + else if (! strchr (r, ':')) + goto not_fqrn; + + if (0) /* Lovely. */ + { + not_fqrn: + error (0, 0, "CVSroot not fully-qualified: %s", CVSroot); + error (1, 0, "should be format user@host:/path/to/repository"); + } + } + + passfile = construct_cvspass_filename (); + typed_password = getpass ("CVS password: "); + typed_password = scramble (typed_password); + + /* Force get_cvs_password() to use this one (when the client + * confirms the new password with the server), instead of consulting + * the file. We make a new copy because cvs_password will get + * zeroed by connect_to_server(). + */ + cvs_password = xstrdup (typed_password); + + if (connect_to_pserver (NULL, NULL, 1) == 0) + { + /* The password is wrong, according to the server. */ + error (1, 0, "incorrect password"); + } + + /* IF we have a password for this "[user@]host:/path" already + * THEN + * IF it's the same as the password we read from the prompt + * THEN + * do nothing + * ELSE + * replace the old password with the new one + * ELSE + * append new entry to the end of the file. + */ + + root_len = strlen (CVSroot); + + /* Yes, the method below reads the user's password file twice. It's + inefficient, but we're not talking about a gig of data here. */ + + fp = fopen (passfile, "r"); + if (fp != NULL) + { + /* Check each line to see if we have this entry already. */ + while (getline (&linebuf, &linebuf_len, fp) >= 0) + { + if (strncmp (CVSroot, linebuf, root_len) == 0) + { + already_entered = 1; + break; + } + else + { + free (linebuf); + linebuf = (char *) NULL; + } + } + } + fclose (fp); + + + if (already_entered) + { + /* This user/host has a password in the file already. */ + + strtok (linebuf, " "); + found_password = strtok (NULL, "\n"); + if (strcmp (found_password, typed_password)) + { + /* typed_password and found_password don't match, so we'll + * have to update passfile. We replace the old password + * with the new one by writing a tmp file whose contents are + * exactly the same as passfile except that this one entry + * gets typed_password instead of found_password. Then we + * rename the tmp file on top of passfile. + */ + char *tmp_name; + FILE *tmp_fp; + + tmp_name = tmpnam (NULL); + if ((tmp_fp = fopen (tmp_name, "w")) == NULL) + { + error (1, errno, "unable to open temp file %s", tmp_name); + return 1; + } + chmod (tmp_name, 0600); + + fp = fopen (passfile, "r"); + if (fp == NULL) + { + error (1, errno, "unable to open %s", passfile); + return 1; + } + /* I'm not paranoid, they really ARE out to get me: */ + chmod (passfile, 0600); + + free (linebuf); + linebuf = (char *) NULL; + while (getline (&linebuf, &linebuf_len, fp) >= 0) + { + if (strncmp (CVSroot, linebuf, root_len)) + fprintf (tmp_fp, "%s", linebuf); + else + fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password); + + free (linebuf); + linebuf = (char *) NULL; + } + fclose (tmp_fp); + fclose (fp); + rename_file (tmp_name, passfile); + chmod (passfile, 0600); + } + } + else + { + if ((fp = fopen (passfile, "a")) == NULL) + { + error (1, errno, "could not open %s", passfile); + free (passfile); + return 1; + } + + fprintf (fp, "%s %s\n", CVSroot, typed_password); + fclose (fp); + } + + /* Utter, total, raving paranoia, I know. */ + chmod (passfile, 0600); + memset (typed_password, 0, strlen (typed_password)); + free (typed_password); + + free (passfile); + free (cvs_password); + cvs_password = NULL; + return 0; +} + +/* todo: "cvs logout" could erase an entry from the file. + * But to what purpose? + */ + +/* Returns the _scrambled_ password. The server must descramble + before hashing and comparing. */ +char * +get_cvs_password () +{ + int found_it = 0; + int root_len; + char *password; + char *linebuf = (char *) NULL; + size_t linebuf_len; + FILE *fp; + char *passfile; + + /* If someone (i.e., login()) is calling connect_to_pserver() out of + context, then assume they have supplied the correct, scrambled + password. */ + if (cvs_password) + return cvs_password; + + /* Environment should override file. */ + if ((password = getenv ("CVS_PASSWORD")) != NULL) + { + char *p; + p = xstrdup (password); + /* If we got it from the environment, then it wasn't properly + scrambled. Since unscrambling is done on the server side, we + need to transmit it scrambled. */ + p = scramble (p); + return p; + } + + /* Else get it from the file. */ + passfile = construct_cvspass_filename (); + fp = fopen (passfile, "r"); + if (fp == NULL) + { + error (0, errno, "could not open %s", passfile); + free (passfile); + error (1, 0, "use \"cvs login\" to log in first"); + } + + root_len = strlen (CVSroot); + + /* Check each line to see if we have this entry already. */ + while (getline (&linebuf, &linebuf_len, fp) >= 0) + { + if (strncmp (CVSroot, linebuf, root_len) == 0) + { + /* This is it! So break out and deal with linebuf. */ + found_it = 1; + break; + } + else + { + free (linebuf); + linebuf = (char *) NULL; + } + } + + if (found_it) + { + /* linebuf now contains the line with the password. */ + char *tmp; + + strtok (linebuf, " "); + password = strtok (NULL, "\n"); + + /* Give it permanent storage. */ + tmp = xmalloc (strlen (password) + 1); + strcpy (tmp, password); + tmp[strlen (password)] = '\0'; + memset (password, 0, strlen (password)); + return tmp; + } + else + { + error (0, 0, "cannot find password"); + error (0, 0, "use \"cvs login\" to log in first"); + error (1, 0, "or set the CVS_PASSWORD environment variable"); + } + free (linebuf); +} + +#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */ + diff --git a/gnu/usr.bin/cvs/src/logmsg.c b/gnu/usr.bin/cvs/src/logmsg.c index f39dd31e888..7686a3680a6 100644 --- a/gnu/usr.bin/cvs/src/logmsg.c +++ b/gnu/usr.bin/cvs/src/logmsg.c @@ -7,6 +7,7 @@ */ #include "cvs.h" +#include "getline.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)logmsg.c 1.48 94/09/29 $"; @@ -129,9 +130,13 @@ do_editor (dir, messagep, repository, changes) List *changes; { static int reuse_log_message = 0; - char line[MAXLINELEN], fname[L_tmpnam+1]; + char *line; + int line_length; + size_t line_chars_allocated; + char fname[L_tmpnam+1]; struct stat pre_stbuf, post_stbuf; int retcode = 0; + char *p; if (noexec || reuse_log_message) return; @@ -172,7 +177,8 @@ do_editor (dir, messagep, repository, changes) CVSEDITPREFIX); /* finish off the temp file */ - (void) fclose (fp); + if (fclose (fp) == EOF) + error (1, errno, "%s", fname); if (stat (fname, &pre_stbuf) == -1) pre_stbuf.st_mtime = 0; @@ -209,19 +215,30 @@ do_editor (dir, messagep, repository, changes) *messagep[0] = '\0'; } -/* !!! XXX FIXME: fgets is broken. This should not have any line - length limits. */ + line = NULL; + line_chars_allocated = 0; if (*messagep) { - while (fgets (line, sizeof (line), fp) != NULL) + p = *messagep; + while (1) { + line_length = getline (&line, &line_chars_allocated, fp); + if (line_length == -1) + { + if (ferror (fp)) + error (0, errno, "warning: cannot read %s", fname); + break; + } if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0) continue; - (void) strcat (*messagep, line); + (void) strcpy (p, line); + p += line_length; } } - (void) fclose (fp); + if (fclose (fp) < 0) + error (0, errno, "warning: cannot close %s", fname); + if (pre_stbuf.st_mtime == post_stbuf.st_mtime || *messagep == NULL || strcmp (*messagep, "\n") == 0) @@ -232,9 +249,9 @@ do_editor (dir, messagep, repository, changes) (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n"); (void) printf ("Action: (continue) "); (void) fflush (stdout); - *line = '\0'; - (void) fgets (line, sizeof (line), stdin); - if (*line == '\0' || *line == '\n' || *line == 'c' || *line == 'C') + line_length = getline (&line, &line_chars_allocated, stdin); + if (line_length <= 0 + || *line == '\n' || *line == 'c' || *line == 'C') break; if (*line == 'a' || *line == 'A') error (1, 0, "aborted by user"); @@ -248,7 +265,10 @@ do_editor (dir, messagep, repository, changes) (void) printf ("Unknown input\n"); } } - (void) unlink_file (fname); + if (line) + free (line); + if (unlink_file (fname) < 0) + error (0, errno, "warning: cannot remove temp file %s", fname); } /* @@ -264,7 +284,6 @@ rcsinfo_proc (repository, template) { static char *last_template; FILE *tfp; - char line[MAXLINELEN]; /* nothing to do if the last one included is the same as this one */ if (last_template && strcmp (last_template, template) == 0) @@ -275,14 +294,22 @@ rcsinfo_proc (repository, template) if ((tfp = fopen (template, "r")) != NULL) { - while (fgets (line, sizeof (line), tfp) != NULL) + char *line = NULL; + size_t line_chars_allocated = 0; + + while (getline (&line, &line_chars_allocated, tfp) >= 0) (void) fputs (line, fp); - (void) fclose (tfp); + if (ferror (tfp)) + error (0, errno, "warning: cannot read %s", template); + if (fclose (tfp) < 0) + error (0, errno, "warning: cannot close %s", template); + if (line) + free (line); return (0); } else { - error (0, 0, "Couldn't open rcsinfo template file %s", template); + error (0, errno, "Couldn't open rcsinfo template file %s", template); return (1); } } diff --git a/gnu/usr.bin/cvs/src/mkmodules.c b/gnu/usr.bin/cvs/src/mkmodules.c index c4453588921..999833e95d4 100644 --- a/gnu/usr.bin/cvs/src/mkmodules.c +++ b/gnu/usr.bin/cvs/src/mkmodules.c @@ -72,6 +72,8 @@ main (argc, argv) "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}}; /* @@ -422,7 +424,8 @@ Lock_Cleanup () int server_active = 0; void -server_cleanup () +server_cleanup (sig) + int sig; { } diff --git a/gnu/usr.bin/cvs/src/modules.c b/gnu/usr.bin/cvs/src/modules.c index 9dcce131473..2f1a6155deb 100644 --- a/gnu/usr.bin/cvs/src/modules.c +++ b/gnu/usr.bin/cvs/src/modules.c @@ -84,7 +84,7 @@ do_module (db, mname, m_type, msg, callback_proc, where, char *mname; enum mtype m_type; char *msg; - int (*callback_proc) (); + CALLBACKPROC callback_proc; char *where; int shorten; int local_specified; @@ -97,16 +97,18 @@ do_module (db, mname, m_type, msg, callback_proc, where, char *tag_prog = NULL; char *update_prog = NULL; struct saved_cwd cwd; - char line[MAXLINELEN]; - char *xmodargv[MAXFILEPERDIR]; + char *line; + int modargc; + int xmodargc; char **modargv; + char *xmodargv[MAXFILEPERDIR]; char *value; char *zvalue; char *mwhere = NULL; char *mfile = NULL; char *spec_opt = NULL; char xvalue[PATH_MAX]; - int modargc, alias = 0; + int alias = 0; datum key, val; char *cp; int c, err = 0; @@ -114,10 +116,11 @@ do_module (db, mname, m_type, msg, callback_proc, where, #ifdef SERVER_SUPPORT if (trace) { - fprintf (stderr, "%c-> do_module (%s, %s, %s, %s)\n", + fprintf (stderr, "%s%c-> do_module (%s, %s, %s, %s)\n", + error_use_protocol ? "E " : "", (server_active) ? 'S' : ' ', - mname, msg, where ? where : "", - extra_arg ? extra_arg : ""); + mname, msg, where ? where : "", + extra_arg ? extra_arg : ""); } #endif @@ -348,7 +351,12 @@ do_module (db, mname, m_type, msg, callback_proc, where, (void) sprintf (nullrepos, "%s/%s/%s", CVSroot, CVSROOTADM, CVSNULLREPOS); if (!isfile (nullrepos)) + { + mode_t omask; + omask = umask (cvsumask); (void) CVS_MKDIR (nullrepos, 0777); + (void) umask (omask); + } if (!isdir (nullrepos)) error (1, 0, "there is no repository %s", nullrepos); @@ -386,10 +394,13 @@ do_module (db, mname, m_type, msg, callback_proc, where, */ /* Put the value on a line with XXX prepended for getopt to eat */ + line = xmalloc (strlen (value) + 10); (void) sprintf (line, "%s %s", "XXX", value); /* turn the line into an argv[] array */ - line2argv (&modargc, xmodargv, line); + line2argv (&xmodargc, xmodargv, line); + free (line); + modargc = xmodargc; modargv = xmodargv; /* parse the args */ @@ -471,8 +482,12 @@ do_module (db, mname, m_type, msg, callback_proc, where, err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten, local_specified, mname, msg); - /* clean up */ - free_names (&modargc, modargv); +#if 0 + /* FIXME: I've fixed this so that the correct arguments are called, + but now this fails because there is code below this point that + uses optarg values extracted from the arg vector. */ + free_names (&xmodargc, xmodargv); +#endif /* if there were special include args, process them now */ @@ -749,7 +764,8 @@ cat_module (status) int moduleargc; struct sortrec *s_h; char *cp, *cp2, **argv; - char line[MAXLINELEN], *moduleargv[MAXFILEPERDIR]; + char *line; + char *moduleargv[MAXFILEPERDIR]; #ifdef sun #ifdef TIOCGSIZE @@ -801,8 +817,10 @@ cat_module (status) } /* Parse module file entry as command line and print options */ + line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 10); (void) sprintf (line, "%s %s", s_h->modname, s_h->rest); line2argv (&moduleargc, moduleargv, line); + free (line); argc = moduleargc; argv = moduleargv; @@ -866,5 +884,7 @@ cat_module (status) *cp++ = '\0'; (void) printf ("%s\n", cp2); } + + free_names(&moduleargc, moduleargv); } } diff --git a/gnu/usr.bin/cvs/src/myndbm.c b/gnu/usr.bin/cvs/src/myndbm.c index fef326576bd..f5d8f4f4dea 100644 --- a/gnu/usr.bin/cvs/src/myndbm.c +++ b/gnu/usr.bin/cvs/src/myndbm.c @@ -13,7 +13,9 @@ * size, and this code works fine. */ +#include #include "cvs.h" +#include "getline.h" #ifdef MY_NDBM @@ -34,21 +36,54 @@ mydbm_open (file, flags, mode) FILE *fp; DBM *db; - if ((fp = fopen (file, "r")) == NULL) + fp = fopen (file, "r"); + if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT))) return ((DBM *) 0); db = (DBM *) xmalloc (sizeof (*db)); db->dbm_list = getlist (); + db->modified = 0; + db->name = xstrdup (file); - mydbm_load_file (fp, db->dbm_list); - (void) fclose (fp); + if (fp != NULL) + { + mydbm_load_file (fp, db->dbm_list); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", file); + } return (db); } +static int write_item PROTO ((Node *, void *)); + +static int +write_item (node, data) + Node *node; + void *data; +{ + FILE *fp = (FILE *)data; + fputs (node->key, fp); + fputs (" ", fp); + fputs (node->data, fp); + fputs ("\n", fp); + return 0; +} + void mydbm_close (db) DBM *db; { + if (db->modified) + { + FILE *fp; + fp = fopen (db->name, "w"); + if (fp == NULL) + error (1, errno, "cannot write %s", db->name); + walklist (db->dbm_list, write_item, (void *)fp); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", db->name); + } + free (db->name); dellist (&db->dbm_list); free ((char *) db); } @@ -128,16 +163,53 @@ mydbm_nextkey (db) return (key); } +/* Note: only updates the in-memory copy, which is written out at + mydbm_close time. Note: Also differs from DBM in that on duplication, + it gives a warning, rather than either DBM_INSERT or DBM_REPLACE + behavior. */ +int +mydbm_store (db, key, value, flags) + DBM *db; + datum key; + datum value; + int flags; +{ + Node *node; + + node = getnode (); + node->type = NDBMNODE; + + node->key = xmalloc (key.dsize + 1); + strncpy (node->key, key.dptr, key.dsize); + node->key[key.dsize] = '\0'; + + node->data = xmalloc (value.dsize + 1); + strncpy (node->data, value.dptr, value.dsize); + node->data[value.dsize] = '\0'; + + db->modified = 1; + if (addnode (db->dbm_list, node) == -1) + { + error (0, 0, "attempt to insert duplicate key `%s'", node->key); + freenode (node); + return 0; + } + return 0; +} + static void mydbm_load_file (fp, list) FILE *fp; List *list; { - char line[MAXLINELEN], value[MAXLINELEN]; + char *line = NULL; + size_t line_len; + /* FIXME: arbitrary limit. */ + char value[MAXLINELEN]; char *cp, *vp; int len, cont; - for (cont = 0; fgets (line, sizeof (line), fp) != NULL;) + for (cont = 0; getline (&line, &line_len, fp) >= 0;) { if ((cp = strrchr (line, '\n')) != NULL) *cp = '\0'; /* strip the newline */ @@ -208,6 +280,7 @@ mydbm_load_file (fp, list) } } } + free (line); } #endif /* MY_NDBM */ diff --git a/gnu/usr.bin/cvs/src/myndbm.h b/gnu/usr.bin/cvs/src/myndbm.h index 3af31305506..0431e15d4d6 100644 --- a/gnu/usr.bin/cvs/src/myndbm.h +++ b/gnu/usr.bin/cvs/src/myndbm.h @@ -8,6 +8,13 @@ typedef struct { List *dbm_list; /* cached database */ Node *dbm_next; /* next key to return for nextkey() */ + + /* Name of the file to write to if modified is set. malloc'd. */ + char *name; + + /* Nonzero if the database has been modified and dbm_close needs to + write it out to disk. */ + int modified; } DBM; typedef struct @@ -26,11 +33,15 @@ typedef struct #define dbm_fetch mydbm_fetch #define dbm_firstkey mydbm_firstkey #define dbm_nextkey mydbm_nextkey +#define dbm_store mydbm_store +#define DBM_INSERT 0 +#define DBM_REPLACE 1 DBM *mydbm_open PROTO((char *file, int flags, int mode)); void mydbm_close PROTO((DBM * db)); datum mydbm_fetch PROTO((DBM * db, datum key)); datum mydbm_firstkey PROTO((DBM * db)); datum mydbm_nextkey PROTO((DBM * db)); +extern int mydbm_store PROTO ((DBM *, datum, datum, int)); #endif /* MY_NDBM */ diff --git a/gnu/usr.bin/cvs/src/options.h.in b/gnu/usr.bin/cvs/src/options.h.in index de55040ea72..d7166a9affd 100644 --- a/gnu/usr.bin/cvs/src/options.h.in +++ b/gnu/usr.bin/cvs/src/options.h.in @@ -54,9 +54,9 @@ /* * The "diff" program to execute when creating patch output. This "diff" * must support the "-c" option for context diffing. Specify a full - * pathname if your site wants to use a particular diff. If you are - * using the GNU version of diff (version 1.15 or later), this should - * be "diff -a". + * pathname if your site wants to use a particular diff. Note that unlike + * the diff used with RCS, you *must not* supply -a here (doing so will cause + * the server to generate patches which patch cannot handle in some cases). * * NOTE: this program is only used for the ``patch'' sub-command (and * for ``update'' if you are using the server). The other commands @@ -65,18 +65,18 @@ */ #ifndef DIFF -#define DIFF "@gdiff_path@" +#define DIFF "diff" #endif /* * The "grep" program to execute when checking to see if a merged file had - * any conflicts. This "grep" must support the "-s" option and a standard + * any conflicts. This "grep" must support a standard basic * regular expression as an argument. Specify a full pathname if your site * wants to use a particular grep. */ #ifndef GREP -#define GREP "@ggrep_path@" +#define GREP "grep" #endif /* @@ -114,9 +114,20 @@ * unless the user overrides the default with the RCSBIN environment variable * or the "-b" option to CVS. * + * If you're compiling the authenticating server (see + * AUTH_SERVER_SUPPORT farther down), then you probably want to set + * RCSBIN_DFLT. The authenticating server starts out running as root, + * and then switches to run as the appropriate user once + * authentication is complete. No shell is ever started by that user, + * so the PATH environment variable may not contain the directory with + * the RCS binaries, even though if that user logged in normally, PATH + * would include the directory. An alternative to setting RCSBIN_DFLT + * is to make sure that root has the right directory in its path + * already. Another, probably better alternative is to specify -b in + * /etc/inetd.conf. + * * This define should be either the empty string ("") or a full pathname to the - * directory containing all the installed programs from the RCS distribution. - */ + * directory containing all the installed programs from the RCS distribution. */ #ifndef RCSBIN_DFLT #define RCSBIN_DFLT "" #endif @@ -132,6 +143,30 @@ #define EDITOR_DFLT "vi" #endif +/* + * The default umask to use when creating or otherwise setting file or + * directory permissions in the repository. Must be a value in the + * range of 0 through 0777. For example, a value of 002 allows group + * rwx access and world rx access; a value of 007 allows group rwx + * access but no world access. This value is overridden by the value + * of the CVSUMASK environment variable, which is interpreted as an + * octal number. + */ +#ifndef UMASK_DFLT +#define UMASK_DFLT 002 +#endif + +/* + * The cvs admin command is restricted to the members of the group + * CVS_ADMIN_GROUP. If this group does not exist, all users are + * allowed to run cvs admin. To disable the cvs admin for all users, + * create an empty group CVS_ADMIN_GROUP. To disable access control for + * cvs admin, comment out the define below. + */ +#ifndef CVS_ADMIN_GROUP +#define CVS_ADMIN_GROUP "cvsadmin" +#endif + /* * The Repository file holds the path to the directory within the source * repository that contains the RCS ,v files for each CVS working directory. @@ -187,19 +222,6 @@ #define CVS_BADROOT #endif -/* - * The "cvs admin" command allows people to get around most of the logging - * and info procedures within CVS. For exmaple, "cvs tag tagname filename" - * will perform some validity checks on the tag, while "cvs admin -Ntagname" - * will not perform those checks. For this reason, some sites may wish to - * disable the admin function completely. - * - * To disable the admin function, uncomment the lines below. - */ -#ifndef CVS_NOADMIN -/* #define CVS_NOADMIN */ -#endif - /* * The "cvs diff" command accepts all the single-character options that GNU * diff (1.15) accepts. Except -D. GNU diff uses -D as a way to put @@ -212,6 +234,40 @@ #define CVS_DIFFDATE #endif +/* + * define this to enable the SETXID support (see FAQ 4D.13) + */ +#ifndef SETXID_SUPPORT +/* #define SETXID_SUPPORT */ +#endif + +/* + * The client and server will not perform password-authentication + * unless you explicitly ask for it. You can build a binary that only + * serves or only clients (sure it's a verb), or one that does both. + */ +/* #define AUTH_CLIENT_SUPPORT 1 */ +/* #define AUTH_SERVER_SUPPORT 1 */ + +/* + * If you are working with a large remote repository and a 'cvs checkout' is + * swamping your network and memory, define these to enable flow control. + * You will end up with even less guarantees of a consistant checkout, + * but that may be better than no checkout at all. The master server process + * will monitor how far it is getting behind, if it reaches the high water + * mark, it will signal the child process to stop generating data when + * convenient (ie: no locks are held, currently at the beginning of a + * new directory). Once the buffer has drained sufficiently to reach the + * low water mark, it will be signalled to start again. + * -- EXPERIMENTAL! -- A better solution may be in the works. + * You may override the default hi/low watermarks here too. + */ +#ifndef SERVER_FLOWCONTROL +/* #define SERVER_FLOWCONTROL */ +/* #define SERVER_HI_WATER (2 * 1024 * 1024) */ +/* #define SERVER_LO_WATER (1 * 1024 * 1024) */ +#endif + /* End of CVS configuration section */ /* diff --git a/gnu/usr.bin/cvs/src/parseinfo.c b/gnu/usr.bin/cvs/src/parseinfo.c index d19e774f294..6d59884db9a 100644 --- a/gnu/usr.bin/cvs/src/parseinfo.c +++ b/gnu/usr.bin/cvs/src/parseinfo.c @@ -24,7 +24,7 @@ int Parse_Info (infofile, repository, callproc, all) char *infofile; char *repository; - int (*callproc) (); + CALLPROC callproc; int all; { int err = 0; @@ -32,6 +32,7 @@ Parse_Info (infofile, repository, callproc, all) char infopath[PATH_MAX]; char line[MAXLINELEN]; char *default_value = NULL; + char *expanded_value= NULL; int callback_done, line_number; char *cp, *exp, *value, *srepos; const char *regex_err; @@ -97,42 +98,14 @@ Parse_Info (infofile, repository, callproc, all) if ((cp = strrchr (value, '\n')) != NULL) *cp = '\0'; - /* FIXME: probably should allow multiple occurrences of CVSROOT. */ - /* FIXME-maybe: perhaps should allow CVSREAD and other cvs - settings (if there is a need for them, which isn't clear). */ - /* FIXME-maybe: Should there be a way to substitute arbitrary - environment variables? Probably not, because then what gets - substituted would depend on who runs cvs. A better feature might - be to allow a file in CVSROOT to specify variables to be - substituted. */ + expanded_value = expand_path (value); + if (!expanded_value) { - char *p, envname[128]; - - strcpy(envname, "$"); - /* FIXME: I'm not at all sure this should be CVSROOT_ENV as opposed - to literal CVSROOT. The value we subsitute is the cvs root - in use which is not the same thing as the environment variable - CVSROOT_ENV. */ - strcat(envname, CVSROOT_ENV); - - cp = xstrdup(value); - if ((p = strstr(cp, envname))) { - if (strlen(line) + strlen(CVSroot) + 1 > MAXLINELEN) { - /* FIXME: there is no reason for this arbitrary limit. */ - error(0, 0, - "line %d in %s too long to expand $CVSROOT, ignored", - line_number, infofile); - continue; - } - if (p > cp) { - strncpy(value, cp, p - cp); - value[p - cp] = '\0'; - strcat(value, CVSroot); - } else - strcpy(value, CVSroot); - strcat(value, p + strlen(envname)); - } - free(cp); + error (0, 0, + "Invalid environmental variable at line %d in file %s", + line_number, infofile); + continue; + } /* @@ -145,7 +118,7 @@ Parse_Info (infofile, repository, callproc, all) /* save the default value so we have it later if we need it */ if (strcmp (exp, "DEFAULT") == 0) { - default_value = xstrdup (value); + default_value = xstrdup (expanded_value); continue; } @@ -157,7 +130,7 @@ Parse_Info (infofile, repository, callproc, all) if (strcmp (exp, "ALL") == 0) { if (all) - err += callproc (repository, value); + err += callproc (repository, expanded_value); else error(0, 0, "Keyword `ALL' is ignored at line %d in %s file", line_number, infofile); @@ -179,7 +152,7 @@ Parse_Info (infofile, repository, callproc, all) continue; /* no match */ /* it did, so do the callback and note that we did one */ - err += callproc (repository, value); + err += callproc (repository, expanded_value); callback_done = 1; } (void) fclose (fp_info); @@ -191,6 +164,8 @@ Parse_Info (infofile, repository, callproc, all) /* free up space if necessary */ if (default_value != NULL) free (default_value); + if (expanded_value != NULL) + free (expanded_value); return (err); } diff --git a/gnu/usr.bin/cvs/src/patch.c b/gnu/usr.bin/cvs/src/patch.c index f9e9f3a9f1b..2170d98636b 100644 --- a/gnu/usr.bin/cvs/src/patch.c +++ b/gnu/usr.bin/cvs/src/patch.c @@ -13,6 +13,7 @@ */ #include "cvs.h" +#include "getline.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)patch.c 1.57 94/09/30 $"; @@ -33,7 +34,9 @@ static int toptwo_diffs = 0; static int local = 0; static char *options = NULL; static char *rev1 = NULL; +static int rev1_validated = 1; static char *rev2 = NULL; +static int rev2_validated = 1; static char *date1 = NULL; static char *date2 = NULL; static char tmpfile1[L_tmpnam+1], tmpfile2[L_tmpnam+1], tmpfile3[L_tmpnam+1]; @@ -202,8 +205,7 @@ patch (argc, argv) send_arg (argv[i]); } - if (fprintf (to_server, "rdiff\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("rdiff\012", 0); return get_responses_and_close (); } #endif @@ -310,9 +312,20 @@ patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, else which = W_REPOS; + if (rev1 != NULL && !rev1_validated) + { + tag_check_valid (rev1, *pargc - 1, argv + 1, local, 0, NULL); + rev1_validated = 1; + } + if (rev2 != NULL && !rev2_validated) + { + tag_check_valid (rev2, *pargc - 1, argv + 1, local, 0, NULL); + rev2_validated = 1; + } + /* start the recursion processor */ - err = start_recursion (patch_fileproc, (int (*) ()) NULL, patch_dirproc, - (int (*) ()) NULL, *pargc - 1, argv + 1, local, + err = start_recursion (patch_fileproc, (FILESDONEPROC) NULL, patch_dirproc, + (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local, which, 0, 1, where, 1, 1); return (err); @@ -342,7 +355,9 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles) int isattic = 0; int retcode = 0; char file1[PATH_MAX], file2[PATH_MAX], strippath[PATH_MAX]; - char line1[MAXLINELEN], line2[MAXLINELEN]; + char *line1, *line2; + size_t line1_chars_allocated; + size_t line2_chars_allocated; char *cp1, *cp2, *commap; FILE *fp; @@ -360,7 +375,7 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles) if (isattic && rev2 == NULL && date2 == NULL) vers_head = NULL; else - vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match); + vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, 0); if (toptwo_diffs) { @@ -378,7 +393,7 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles) return (1); } } - vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match); + vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, 0); if (vers_tag == NULL && (vers_head == NULL || isattic)) return (0); /* nothing known about specified revs */ @@ -465,6 +480,12 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles) run_setup ("%s -%c", DIFF, unidiff ? 'u' : 'c'); run_arg (tmpfile1); run_arg (tmpfile2); + + line1 = NULL; + line1_chars_allocated = 0; + line2 = NULL; + line2_chars_allocated = 0; + switch (run_exec (RUN_TTY, tmpfile3, RUN_TTY, RUN_NORMAL)) { case -1: /* fork/wait failure */ @@ -488,8 +509,8 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles) (void) fflush (stdout); fp = open_file (tmpfile3, "r"); - if (fgets (line1, sizeof (line1), fp) == NULL || - fgets (line2, sizeof (line2), fp) == NULL) + if (getline (&line1, &line1_chars_allocated, fp) < 0 || + getline (&line2, &line2_chars_allocated, fp) < 0) { error (0, errno, "failed to read diff file header %s for %s", tmpfile3, rcs); @@ -557,14 +578,19 @@ patch_fileproc (file, update_dir, repository, entries, srcfiles) if (update_dir[0] != '\0') (void) printf ("%s/", update_dir); (void) printf ("%s%s", rcs, cp2); - while (fgets (line1, sizeof (line1), fp) != NULL) - (void) printf ("%s", line1); + /* spew the rest of the diff out */ + while (getline (&line1, &line1_chars_allocated, fp) >= 0) + (void) fputs (line1, stdout); (void) fclose (fp); break; default: error (0, 0, "diff failed for %s", rcs); } out: + if (line1) + free (line1); + if (line2) + free (line2); (void) unlink_file (tmpfile1); (void) unlink_file (tmpfile2); (void) unlink_file (tmpfile3); diff --git a/gnu/usr.bin/cvs/src/rcs.c b/gnu/usr.bin/cvs/src/rcs.c index 9722b338bfb..43282a668ff 100644 --- a/gnu/usr.bin/cvs/src/rcs.c +++ b/gnu/usr.bin/cvs/src/rcs.c @@ -152,7 +152,7 @@ RCS_parse (file, repos) fclose (fp); return (rcs); } - else if (errno != ENOENT) + else if (! existence_error (errno)) { error (0, errno, "cannot open %s", rcsfile); return NULL; @@ -177,7 +177,7 @@ RCS_parse (file, repos) fclose (fp); return (rcs); } - else if (errno != ENOENT) + else if (! existence_error (errno)) { error (0, errno, "cannot open %s", rcsfile); return NULL; @@ -347,6 +347,12 @@ RCS_reparsercsfile (rdata) } } + if (strcmp (RCSEXPAND, key) == 0) + { + rdata->expand = xstrdup (value); + continue; + } + /* * check key for '.''s and digits (probably a rev) if it is a * revision, we are done with the headers and are down to the @@ -494,6 +500,8 @@ freercsnode (rnodep) dellist (&(*rnodep)->symbols); if ((*rnodep)->symbols_data != (char *) NULL) free ((*rnodep)->symbols_data); + if ((*rnodep)->expand != NULL) + free ((*rnodep)->expand); if ((*rnodep)->head != (char *) NULL) free ((*rnodep)->head); if ((*rnodep)->branch != (char *) NULL) @@ -827,15 +835,15 @@ do_branches (list, val) * The result is returned; null-string if error. */ char * -RCS_getversion (rcs, tag, date, force_tag_match) +RCS_getversion (rcs, tag, date, force_tag_match, return_both) RCSNode *rcs; char *tag; char *date; int force_tag_match; + int return_both; { /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) NULL); + assert (rcs != NULL); if (tag && date) { @@ -845,7 +853,7 @@ RCS_getversion (rcs, tag, date, force_tag_match) * first lookup the tag; if that works, turn the revision into * a branch and lookup the date. */ - tagrev = RCS_gettag (rcs, tag, force_tag_match); + tagrev = RCS_gettag (rcs, tag, force_tag_match, 0); if (tagrev == NULL) return ((char *) NULL); @@ -856,7 +864,7 @@ RCS_getversion (rcs, tag, date, force_tag_match) return (rev); } else if (tag) - return (RCS_gettag (rcs, tag, force_tag_match)); + return (RCS_gettag (rcs, tag, force_tag_match, return_both)); else if (date) return (RCS_getdate (rcs, date, force_tag_match)); else @@ -873,16 +881,17 @@ RCS_getversion (rcs, tag, date, force_tag_match) * If the matched tag is a branch tag, find the head of the branch. */ char * -RCS_gettag (rcs, tag, force_tag_match) +RCS_gettag (rcs, symtag, force_tag_match, return_both) RCSNode *rcs; - char *tag; + char *symtag; int force_tag_match; + int return_both; { Node *p; + char *tag = symtag; /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) NULL); + assert (rcs != NULL); /* XXX this is probably not necessary, --jtc */ if (rcs->flags & PARTIAL) @@ -982,7 +991,25 @@ RCS_gettag (rcs, tag, force_tag_match) else p = findnode (rcs->versions, tag); if (p != NULL) - return (xstrdup (tag)); + { + /* + * we have found a numeric revision for the revision tag. + * To support expanding the RCS keyword Name, return both + * the numeric tag and the supplied tag (which might be + * symbolic). They are separated with a ':' which is not + * a valid tag char. The variable return_both is only set + * if this function is called through Version_TS -> + * RCS_getversion. + */ + if (return_both) + { + char *both = xmalloc(strlen(tag) + 2 + strlen(symtag)); + sprintf(both, "%s:%s", tag, symtag); + return both; + } + else + return (xstrdup (tag)); + } else { /* The revision wasn't there, so return the head or NULL */ @@ -1211,8 +1238,7 @@ RCS_getbranch (rcs, tag, force_tag_match) char *cp; /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) NULL); + assert (rcs != NULL); if (rcs->flags & PARTIAL) RCS_reparsercsfile (rcs); @@ -1323,16 +1349,14 @@ RCS_head (rcs) RCSNode *rcs; { /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) NULL); - - if (rcs->branch) - return (RCS_getbranch (rcs, rcs->branch, 1)); + assert (rcs != NULL); /* * NOTE: we call getbranch with force_tag_match set to avoid any * possibility of recursion */ + if (rcs->branch) + return (RCS_getbranch (rcs, rcs->branch, 1)); else return (xstrdup (rcs->head)); } @@ -1353,8 +1377,7 @@ RCS_getdate (rcs, date, force_tag_match) RCSVers *vers = NULL; /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) NULL); + assert (rcs != NULL); if (rcs->flags & PARTIAL) RCS_reparsercsfile (rcs); @@ -1526,8 +1549,7 @@ RCS_getrevtime (rcs, rev, date, fudge) RCSVers *vers; /* make sure we have something to look at... */ - if (rcs == NULL) - return (revdate); + assert (rcs != NULL); if (rcs->flags & PARTIAL) RCS_reparsercsfile (rcs); diff --git a/gnu/usr.bin/cvs/src/rcs.h b/gnu/usr.bin/cvs/src/rcs.h index d5ac5989c29..f64501d71e6 100644 --- a/gnu/usr.bin/cvs/src/rcs.h +++ b/gnu/usr.bin/cvs/src/rcs.h @@ -25,7 +25,13 @@ #define RCSSYMBOLS "symbols" #define RCSDATE "date" #define RCSDESC "desc" +#define RCSEXPAND "expand" + +/* Used by the version of death support which results if you define + DEATH_SUPPORT and not DEATH_STATE. Requires a hacked up RCS. Considered + obsolete. */ #define RCSDEAD "dead" + #define DATEFORM "%02d.%02d.%02d.%02d.%02d.%02d" #define SDATEFORM "%d.%d.%d.%d.%d.%d" @@ -44,6 +50,7 @@ struct rcsnode char *head; char *branch; char *symbols_data; + char *expand; List *symbols; List *versions; List *dates; @@ -78,9 +85,10 @@ RCSNode *RCS_parse PROTO((const char *file, const char *repos)); RCSNode *RCS_parsercsfile PROTO((char *rcsfile)); char *RCS_check_kflag PROTO((const char *arg)); char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match)); -char *RCS_gettag PROTO((RCSNode * rcs, char *tag, int force_tag_match)); +char *RCS_gettag PROTO((RCSNode * rcs, char *symtag, int force_tag_match, + int return_both)); char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date, - int force_tag_match)); + 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)); diff --git a/gnu/usr.bin/cvs/src/rcscmds.c b/gnu/usr.bin/cvs/src/rcscmds.c index 593cf5c0bba..af32cea1d6d 100644 --- a/gnu/usr.bin/cvs/src/rcscmds.c +++ b/gnu/usr.bin/cvs/src/rcscmds.c @@ -28,6 +28,7 @@ int RCS_deltag(path, tag, noerr) const char *path; const char *tag; + int noerr; { run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag); run_arg (path); @@ -64,6 +65,7 @@ int RCS_unlock(path, rev, noerr) const char *path; const char *rev; + int noerr; { run_setup ("%s%s -q -u%s", Rcsbin, RCS, rev ? rev : ""); run_arg (path); @@ -80,10 +82,6 @@ RCS_merge(path, options, rev1, rev2) { int status; - /* We pass -E to rcsmerge so that it will not indicate a conflict if - both things we are merging are modified the same way. - - Well, okay, but my rcsmerge doesn't take a -E option. --JimB */ /* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */ run_setup ("%s%s %s -r%s -r%s %s", Rcsbin, RCS_RCSMERGE, @@ -93,10 +91,10 @@ RCS_merge(path, options, rev1, rev2) if (status == 0) { /* Run GREP to see if there appear to be conflicts in the file */ - run_setup ("%s -s", GREP); + run_setup ("%s", GREP); run_arg (RCS_MERGE_PAT); run_arg (path); - status = (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) == 0); + status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0); } #endif diff --git a/gnu/usr.bin/cvs/src/recurse.c b/gnu/usr.bin/cvs/src/recurse.c index fdf972f5a9f..d11bdf4a499 100644 --- a/gnu/usr.bin/cvs/src/recurse.c +++ b/gnu/usr.bin/cvs/src/recurse.c @@ -10,6 +10,8 @@ #include "cvs.h" #include "save-cwd.h" +#include "fileattr.h" +#include "edit.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)recurse.c 1.31 94/09/30 $"; @@ -26,10 +28,10 @@ static void addfile PROTO((List **listp, char *dir, char *file)); /* * Local static versions eliminates the need for globals */ -static int (*fileproc) (); -static int (*filesdoneproc) (); -static Dtype (*direntproc) (); -static int (*dirleaveproc) (); +static FILEPROC fileproc; +static FILESDONEPROC filesdoneproc; +static DIRENTPROC direntproc; +static DIRLEAVEPROC dirleaveproc; static int which; static Dtype flags; static int aflag; @@ -44,10 +46,10 @@ static List *filelist = NULL; /* holds list of files on which to operate */ static List *dirlist = NULL; /* holds list of directories on which to operate */ struct recursion_frame { - int (*fileproc)(); - int (*filesdoneproc) (); - Dtype (*direntproc) (); - int (*dirleaveproc) (); + FILEPROC fileproc; + FILESDONEPROC filesdoneproc; + DIRENTPROC direntproc; + DIRLEAVEPROC dirleaveproc; Dtype flags; int which; int aflag; @@ -68,10 +70,10 @@ int start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, argc, argv, local, which, aflag, readlock, update_preload, dosrcs, wd_is_repos) - int (*fileproc) (); - int (*filesdoneproc) (); - Dtype (*direntproc) (); - int (*dirleaveproc) (); + FILEPROC fileproc; + FILESDONEPROC filesdoneproc; + DIRENTPROC direntproc; + DIRLEAVEPROC dirleaveproc; int argc; char **argv; int local; @@ -213,6 +215,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, /* look for it in the repository. */ repos = Name_Repository (dir, update_dir); (void) sprintf (tmp, "%s/%s", repos, comp); + free (repos); if (!wrap_name_has (comp, WRAP_TOCVS) && isdir(tmp)) addlist (&dirlist, argv[i]); @@ -266,10 +269,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, int do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, xflags, xwhich, xaflag, xreadlock, xdosrcs) - int (*xfileproc) (); - int (*xfilesdoneproc) (); - Dtype (*xdirentproc) (); - int (*xdirleaveproc) (); + FILEPROC xfileproc; + FILESDONEPROC xfilesdoneproc; + DIRENTPROC xdirentproc; + DIRLEAVEPROC xdirleaveproc; Dtype xflags; int xwhich; int xaflag; @@ -295,6 +298,18 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, readlock = noexec ? 0 : xreadlock; dosrcs = xdosrcs; +#if defined(SERVER_SUPPORT) && defined(SERVER_FLOWCONTROL) + /* + * Now would be a good time to check to see if we need to stop + * generating data, to give the buffers a chance to drain to the + * remote client. We should not have locks active at this point. + */ + if (server_active + /* If there are writelocks around, we cannot pause here. */ + && (readlock || noexec)) + server_pause_check(); +#endif + /* * Fill in repository with the current repository */ @@ -312,6 +327,8 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, } srepository = repository; /* remember what to free */ + fileattr_startdir (repository); + /* * The filesdoneproc needs to be called for each directory where files * processed, or each directory that is processed by a call where no @@ -365,6 +382,15 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, if (readlock && repository && Reader_Lock (repository) != 0) error (1, 0, "read lock failed - giving up"); +#ifdef CLIENT_SUPPORT + /* For the server, we handle notifications in a completely different + place (server_notify). For local, we can't do them here--we don't + have writelocks in place, and there is no way to get writelocks + here. */ + if (client_active) + notify_check (repository, update_dir); +#endif + /* pre-parse the source files */ if (dosrcs && repository) srcfiles = RCS_parsefiles (filelist, repository); @@ -389,6 +415,9 @@ do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, if (dodoneproc && filesdoneproc != NULL) err = filesdoneproc (err, repository, update_dir[0] ? update_dir : "."); + fileattr_write (); + fileattr_free (); + /* process the directories (if necessary) */ if (dirlist != NULL) err += walklist (dirlist, do_dir_proc, NULL); diff --git a/gnu/usr.bin/cvs/src/release.c b/gnu/usr.bin/cvs/src/release.c index 987edd0d301..c7cd55c9410 100644 --- a/gnu/usr.bin/cvs/src/release.c +++ b/gnu/usr.bin/cvs/src/release.c @@ -27,6 +27,21 @@ static const char *const release_usage[] = static short delete; +/* FIXME: This implementation is cheezy in quite a few ways: + + 1. The whole "cvs update" junk could be checked locally with a + fairly simple start_recursion/classify_file loop--a win for + portability, performance, and cleanliness. + + 2. Should be like edit/unedit in terms of working well if disconnected + from the network, and then sending a delayed notification. + + 3. Way too many network turnarounds. More than one for each argument. + Puh-leeze. + + 4. Oh, and as a purely stylistic nit, break this out into separate + functions for client/local and for server. Those #ifdefs are a mess. */ + int release (argc, argv) int argc; @@ -38,6 +53,7 @@ release (argc, argv) char line[PATH_MAX], update_cmd[PATH_MAX]; char *thisarg; int arg_start_idx; + int err = 0; #ifdef SERVER_SUPPORT if (!server_active) @@ -82,7 +98,7 @@ release (argc, argv) */ /* Construct the update command. */ sprintf (update_cmd, "%s -n -q -d %s update", - program_name, CVSroot); + program_path, CVSroot); #ifdef CLIENT_SUPPORT /* Start the server; we'll close it after looping. */ @@ -100,8 +116,8 @@ release (argc, argv) if (server_active) arg_start_idx = 1; else - arg_start_idx = 0; #endif /* SERVER_SUPPORT */ + arg_start_idx = 0; for (i = arg_start_idx; i < argc; i++) { @@ -157,11 +173,8 @@ release (argc, argv) * the user, telling her how many files have been * modified, and asking if she still wants to do the * release. - * - * This is "popen()" instead of "Popen()" since we - * wouldn't want the `noexec' flag to stop it. */ - fp = popen (update_cmd, "r"); + fp = Popen (update_cmd, "r"); c = 0; while (fgets (line, sizeof (line), fp)) @@ -196,13 +209,33 @@ release (argc, argv) } } + if (1 +#ifdef SERVER_SUPPORT + && !server_active +#endif +#ifdef CLIENT_SUPPORT + && !(client_active + && (!supported_request ("noop") + || !supported_request ("Notify"))) +#endif + ) + { + /* We are chdir'ed into the directory in question. + So don't pass args to unedit. */ + int argc = 1; + char *argv[3]; + argv[0] = "dummy"; + argv[1] = NULL; + err += unedit (argc, argv); + } + #ifdef CLIENT_SUPPORT if (client_active) { - if (fprintf (to_server, "Argument %s\n", thisarg) < 0) - error (1, errno, "writing to server"); - if (fprintf (to_server, "release\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("Argument ", 0); + send_to_server (thisarg, 0); + send_to_server ("\012", 1); + send_to_server ("release\012", 0); } else { @@ -226,6 +259,7 @@ release (argc, argv) } /* else server not active */ #endif /* SERVER_SUPPORT */ } /* `for' loop */ + return err; } @@ -237,7 +271,6 @@ release_delete (dir) { struct stat st; ino_t ino; - int retcode = 0; (void) stat (".", &st); ino = st.st_ino; @@ -253,9 +286,6 @@ release_delete (dir) * XXX - shouldn't this just delete the CVS-controlled files and, perhaps, * the files that would normally be ignored and leave everything else? */ - run_setup ("%s -fr", RM); - run_arg (dir); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) - error (0, retcode == -1 ? errno : 0, - "deletion of module %s failed.", dir); + if (unlink_file_dir (dir) < 0) + error (0, errno, "deletion of directory %s failed", dir); } diff --git a/gnu/usr.bin/cvs/src/remove.c b/gnu/usr.bin/cvs/src/remove.c index 95140d66ea0..ee3d81f5fda 100644 --- a/gnu/usr.bin/cvs/src/remove.c +++ b/gnu/usr.bin/cvs/src/remove.c @@ -82,17 +82,17 @@ cvsremove (argc, argv) ign_setup (); if (local) send_arg("-l"); + send_file_names (argc, argv); send_files (argc, argv, local, 0); - if (fprintf (to_server, "remove\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("remove\012", 0); return get_responses_and_close (); } #endif /* start the recursion processor */ - err = start_recursion (remove_fileproc, (int (*) ()) NULL, remove_dirproc, - (int (*) ()) NULL, argc, argv, local, - W_LOCAL, 0, 1, (char *) NULL, 1, 0); + err = start_recursion (remove_fileproc, (FILESDONEPROC) NULL, + remove_dirproc, (DIRLEAVEPROC) NULL, argc, argv, + local, W_LOCAL, 0, 1, (char *) NULL, 1, 0); if (removed_files) error (0, 0, "use '%s commit' to remove %s permanently", program_name, @@ -123,12 +123,22 @@ remove_fileproc (file, update_dir, repository, entries, srcfiles) char fname[PATH_MAX]; Vers_TS *vers; - /* - * If unlinking the file works, good. If not, the "unremoved" - * error will indicate problems. - */ if (force) - (void) unlink (file); + { + if (!noexec) + { + if (unlink (file) < 0 && ! existence_error (errno)) + { + if (update_dir[0] == '\0') + error (0, errno, "unable to remove %s", file); + else + error (0, errno, "unable to remove %s/%s", update_dir, + file); + } + } + /* else FIXME should probably act as if the file doesn't exist + in doing the following checks. */ + } vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, file, 0, 0, entries, srcfiles); @@ -148,12 +158,9 @@ remove_fileproc (file, update_dir, repository, entries, srcfiles) { /* * It's a file that has been added, but not commited yet. So, - * remove the ,p and ,t file for it and scratch it from the - * entries file. - */ + * remove the ,t file for it and scratch it from the + * entries file. */ Scratch_Entry (entries, file); - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT); - (void) unlink_file (fname); (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG); (void) unlink_file (fname); if (!quiet) diff --git a/gnu/usr.bin/cvs/src/root.c b/gnu/usr.bin/cvs/src/root.c index 8b7c83807cb..3129c3b6610 100644 --- a/gnu/usr.bin/cvs/src/root.c +++ b/gnu/usr.bin/cvs/src/root.c @@ -50,7 +50,7 @@ Name_Root(dir, update_dir) * Do not bother looking for a readable file if there is no cvsadm * directory present. * - * It is possiible that not all repositories will have a CVS/Root + * It is possible that not all repositories will have a CVS/Root * file. This is ok, but the user will need to specify -d * /path/name or have the environment variable CVSROOT set in * order to continue. @@ -92,9 +92,9 @@ Name_Root(dir, update_dir) /* It must specify a server via remote CVS or be an absolute pathname. */ if ((strchr (root, ':') == NULL) && ! isabsolute (root)) -#else +#else /* ! CLIENT_SUPPORT */ if (root[0] != '/') -#endif +#endif /* CLIENT_SUPPORT */ { error (0, 0, "in directory %s:", xupdate_dir); error (0, 0, @@ -105,9 +105,9 @@ Name_Root(dir, update_dir) #ifdef CLIENT_SUPPORT if ((strchr (root, ':') == NULL) && !isdir (root)) -#else +#else /* ! CLIENT_SUPPORT */ if (!isdir (root)) -#endif +#endif /* CLIENT_SUPPORT */ { error (0, 0, "in directory %s:", xupdate_dir); error (0, 0, @@ -162,6 +162,9 @@ Create_Root (dir, rootdir) FILE *fout; char tmp[PATH_MAX]; + if (noexec) + return; + /* record the current cvs root */ if (rootdir != NULL) diff --git a/gnu/usr.bin/cvs/src/rtag.c b/gnu/usr.bin/cvs/src/rtag.c index 238ff7db595..bf476297c51 100644 --- a/gnu/usr.bin/cvs/src/rtag.c +++ b/gnu/usr.bin/cvs/src/rtag.c @@ -55,6 +55,7 @@ static List *tlist; static char *symtag; static char *numtag; +static int numtag_validated = 0; static int delete; /* adding a tag by default */ static int attic_too; /* remove tag from Attic files */ static int branch_mode; /* make an automagic "branch" tag */ @@ -175,7 +176,7 @@ rtag (argc, argv) if (branch_mode) send_arg("-b"); if (force_tag_move) - send_arg("-T"); + send_arg("-F"); if (run_module_prog) send_arg("-n"); if (attic_too) @@ -194,8 +195,7 @@ rtag (argc, argv) send_arg (argv[i]); } - if (fprintf (to_server, "rtag\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("rtag\012", 0); return get_responses_and_close (); } #endif @@ -289,12 +289,18 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, else which = W_REPOS; + if (numtag != NULL && !numtag_validated) + { + tag_check_valid (numtag, *pargc - 1, argv + 1, local, 0, NULL); + numtag_validated = 1; + } + /* check to make sure they are authorized to tag all the specified files in the repository */ mtlist = getlist(); err = start_recursion (check_fileproc, check_filesdoneproc, - (Dtype (*) ()) NULL, (int (*) ()) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local, which, 0, 1, where, 1, 1); @@ -304,8 +310,8 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, } /* start the recursion processor */ - err = start_recursion (rtag_fileproc, (int (*) ()) NULL, rtag_dirproc, - (int (*) ()) NULL, *pargc - 1, argv + 1, local, + err = start_recursion (rtag_fileproc, (FILESDONEPROC) NULL, rtag_dirproc, + (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local, which, 0, 1, where, 1, 1); dellist(&mtlist); @@ -358,13 +364,13 @@ check_fileproc(file, update_dir, repository, entries, srcfiles) p->delproc = tag_delproc; vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, file, 0, 0, entries, srcfiles); - p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match); + p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0); if (p->data != NULL) { int addit = 1; char *oversion; - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1); + oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); if (oversion == NULL) { if (delete) @@ -541,7 +547,7 @@ rtag_fileproc (file, update_dir, repository, entries, srcfiles) return (rtag_delete (rcsfile)); } - version = RCS_getversion (rcsfile, numtag, date, force_tag_match); + version = RCS_getversion (rcsfile, numtag, date, force_tag_match, 0); if (version == NULL) { /* If -a specified, clean up any old tags */ @@ -584,7 +590,7 @@ rtag_fileproc (file, update_dir, repository, entries, srcfiles) * typical tagging operation. */ rev = branch_mode ? RCS_magicrev (rcsfile, version) : version; - oversion = RCS_getversion (rcsfile, symtag, (char *) 0, 1); + oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0); if (oversion != NULL) { int isbranch = RCS_isbranch (file, symtag, srcfiles); @@ -651,13 +657,13 @@ rtag_delete (rcsfile) if (numtag) { - version = RCS_getversion (rcsfile, numtag, (char *) 0, 1); + version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1, 0); if (version == NULL) return (0); free (version); } - version = RCS_getversion (rcsfile, symtag, (char *) 0, 1); + version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0); if (version == NULL) return (0); free (version); diff --git a/gnu/usr.bin/cvs/src/run.c b/gnu/usr.bin/cvs/src/run.c index ebc26ae42d8..0909878267a 100644 --- a/gnu/usr.bin/cvs/src/run.c +++ b/gnu/usr.bin/cvs/src/run.c @@ -18,10 +18,6 @@ #include "cvs.h" -#ifdef _MINIX -#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */ -#endif - #ifdef HAVE_VPRINTF #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) #include @@ -179,7 +175,7 @@ run_exec (stin, stout, sterr, flags) int rerrno = 0; int pid, w; -#ifdef POSIX +#ifdef POSIX_SIGNALS sigset_t sigset_mask, sigset_omask; struct sigaction act, iact, qact; @@ -286,7 +282,7 @@ run_exec (stin, stout, sterr, flags) } /* the parent. Ignore some signals for now */ -#ifdef POSIX +#ifdef POSIX_SIGNALS if (flags & RUN_SIGIGNORE) { act.sa_handler = SIG_IGN; @@ -320,7 +316,7 @@ run_exec (stin, stout, sterr, flags) #endif /* wait for our process to die and munge return status */ -#ifdef POSIX +#ifdef POSIX_SIGNALS while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) ; #else @@ -347,7 +343,7 @@ run_exec (stin, stout, sterr, flags) rc = 1; /* restore the signals */ -#ifdef POSIX +#ifdef POSIX_SIGNALS if (flags & RUN_SIGIGNORE) { (void) sigaction (SIGINT, &iact, (struct sigaction *) NULL); @@ -477,6 +473,9 @@ close_on_exec (fd) /* * dir = 0 : main proc writes to new proc, which writes to oldfd * dir = 1 : main proc reads from new proc, which reads from oldfd + * + * Returns: a file descriptor. On failure (i.e., the exec fails), + * then filter_stream_through_program() complains and dies. */ int diff --git a/gnu/usr.bin/cvs/src/sanity.sh b/gnu/usr.bin/cvs/src/sanity.sh index 1d6ea42ed3d..a47632de71a 100644 --- a/gnu/usr.bin/cvs/src/sanity.sh +++ b/gnu/usr.bin/cvs/src/sanity.sh @@ -1,76 +1,271 @@ -#!/bin/sh -# a quick sanity test for cvs. +#! /bin/sh +: +# sanity.sh -- a growing sanity test for cvs. +# +#ident "$CVSid$" # # Copyright (C) 1992, 1993 Cygnus Support # # Original Author: K. Richard Pixley -# usage: sanity.sh [-r] @var{cvs-to-test} +# usage: sanity.sh [-r] @var{cvs-to-test} @var{tests-to-run} # -r means to test remote instead of local cvs. +# @var{tests-to-run} are the names of the tests to run; if omitted run all +# tests. # See TODO list at end of file. +# required to make this script work properly. +unset CVSREAD + TESTDIR=/tmp/cvs-sanity # "debugger" #set -x -echo This test should produce no other output than this line, and "Ok." - -# clean any old remnants -rm -rf ${TESTDIR} +echo 'This test should produce no other output than this line, and a final "OK".' if test x"$1" = x"-r"; then - shift - remote=yes + shift + remote=yes else - remote=no + remote=no fi -testcvs=$1; shift +# Use full path for CVS executable, so that CVS_SERVER gets set properly +# for remote. +case $1 in +/*) + testcvs=$1 + ;; +*) + testcvs=`pwd`/$1 + ;; +esac -# Remaining arguments are the names of tests to run. -if test x"$*" = x; then - tests="basic0 basic1 basic2 basic3 rtags death import new conflicts modules mflag errmsg1" -else - tests="$*" -fi +shift + +# Use full path for mkmodules, so that the right one will be invoked +# +testmkmodules=`pwd`/mkmodules -# fixme: try things (what things? checkins?) without -m. +# FIXME: try things (what things? checkins?) without -m. +# # Some of these tests are written to expect -Q. But testing with # -Q is kind of bogus, it is not the way users actually use CVS (usually). # So new tests probably should invoke ${testcvs} directly, rather than ${CVS}. -CVS="${testcvs} -Q" +# and then they've obviously got to do something with the output.... +# +CVS="${testcvs} -Q -f" LOGFILE=`pwd`/check.log -if test -f check.log; then mv check.log check.plog; fi +# Save the previous log in case the person running the tests decides +# they want to look at it. The extension ".plog" is chosen for consistency +# with dejagnu. +if test -f check.log; then + mv check.log check.plog +fi + +# That we should have to do this is total bogosity, but GNU expr +# version 1.9.4 uses the emacs definition of "$" instead of the unix +# (e.g. SunOS 4.1.3 expr) one. IMHO, this is a GNU expr bug, but I +# don't have a copy of POSIX.2 handy to check. +ENDANCHOR="$" +if expr 'abc +def' : 'abc$' >/dev/null; then + ENDANCHOR='\'\' +fi + +# Work around another GNU expr (version 1.10) bug/incompatibility. +# "." doesn't appear to match a newline (it does with SunOS 4.1.3 expr). +# Note that the workaround is not a complete equivalent of .* because +# the first parenthesized expression in the regexp must match something +# in order for expr to return a successful exit status. +DOTSTAR='.*' +if expr 'abc +def' : "a${DOTSTAR}f" >/dev/null; then + : good, it works +else + DOTSTAR='\(.\| +\)*' +fi + +# Cause NextStep 3.3 users to lose in a more graceful fashion. +if expr 'abc +def' : 'abc +def' >/dev/null; then + : good, it works +else + echo 'Running these tests requires an "expr" program that can handle' + echo 'multi-line patterns. Make sure that such an expr (GNU, or many but' + echo 'not all vendor-supplied versions) is in your path.' + exit 1 +fi + +pass () +{ + echo "PASS: $1" >>${LOGFILE} +} + +fail () +{ + echo "FAIL: $1" | tee -a ${LOGFILE} + # This way the tester can go and see what remnants were left + 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 () +{ + 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 + 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 + else + if expr "`cat ${TESTDIR}/dotest.tmp`" : \ + "$3"${ENDANCHOR} >/dev/null; then + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} + pass "$1" + else + if test x"$4" != x; then + if expr "`cat ${TESTDIR}/dotest.tmp`" : \ + "$4"${ENDANCHOR} >/dev/null; then + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} + pass "$1" + else + echo "** expected: " >>${LOGFILE} + echo "$3" >>${LOGFILE} + echo "** or: " >>${LOGFILE} + echo "$4" >>${LOGFILE} + echo "** got: " >>${LOGFILE} + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} + fail "$1" + fi + else + echo "** expected: " >>${LOGFILE} + echo "$3" >>${LOGFILE} + echo "** got: " >>${LOGFILE} + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} + fail "$1" + fi + fi + 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). +dotest_fail () +{ + if $2 >${TESTDIR}/dotest.tmp 2>&1; then + status=$? + cat ${TESTDIR}/dotest.tmp >>${LOGFILE} + echo "exit status was $status" >>${LOGFILE} + fail "$1" + 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 + 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 + fi +} + +# clean any old remnants +rm -rf ${TESTDIR} mkdir ${TESTDIR} cd ${TESTDIR} -# so far so good. Let's try something harder. +# Remaining arguments are the names of tests to run. +# +# FIXME: not all combinations are possible; rtags depends on files set +# up by basic2, for example. This should be changed. The goal is +# that tests can be run in manageably-sized chunks, so that one can +# quickly get a result from a cvs or testsuite change, and to +# facilitate understanding the tests. + +if test x"$*" = x; then + tests="basica basic0 basic1 basic2 rtags death import new conflicts modules mflag errmsg1 devcom ignore binfiles" +else + tests="$*" +fi # this should die if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ; then - echo "FAIL: test 1" | tee -a ${LOGFILE}; exit 1 + echo "FAIL: test 1" | tee -a ${LOGFILE} + exit 1 else - echo "PASS: test 1" >>${LOGFILE} + echo "PASS: test 1" >>${LOGFILE} fi # this should still die mkdir cvsroot if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ; then - echo "FAIL: test 2" | tee -a ${LOGFILE}; exit 1 + echo "FAIL: test 2" | tee -a ${LOGFILE} + exit 1 else - echo "PASS: test 2" >>${LOGFILE} + echo "PASS: test 2" >>${LOGFILE} fi # this should still die mkdir cvsroot/CVSROOT if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ; then - echo "FAIL: test 3" | tee -a ${LOGFILE}; exit 1 + echo "FAIL: test 3" | tee -a ${LOGFILE} + exit 1 else - echo "PASS: test 3" >>${LOGFILE} + echo "PASS: test 3" >>${LOGFILE} fi # This one should work, although it should spit a warning. @@ -78,44 +273,139 @@ mkdir tmp ; cd tmp ${CVS} -d `pwd`/../cvsroot co CVSROOT 2>> ${LOGFILE} cd .. ; rm -rf tmp +# set up a minimal modules file... +echo "CVSROOT -i ${testmkmodules} CVSROOT" > cvsroot/CVSROOT/modules +# The following line stolen from cvsinit.sh. FIXME: create our +# repository via cvsinit.sh; that way we test it too. +(cd cvsroot/CVSROOT; ci -q -u -t/dev/null \ + -m'initial checkin of modules' modules) + # This one should succeed. No warnings. -echo 'CVSROOT -i mkmodules CVSROOT' > cvsroot/CVSROOT/modules mkdir tmp ; cd tmp if ${CVS} -d `pwd`/../cvsroot co CVSROOT ; then - echo "PASS: test 4" >>${LOGFILE} + echo "PASS: test 4" >>${LOGFILE} else - echo "FAIL: test 4" | tee -a ${LOGFILE}; exit 1 + echo "FAIL: test 4" | tee -a ${LOGFILE} + exit 1 fi -cd .. ; rm -rf tmp +if echo "yes" | ${CVS} -d `pwd`/../cvsroot release -d CVSROOT ; then + echo "PASS: test 4.5" >>${LOGFILE} +else + echo "FAIL: test 4.5" | tee -a ${LOGFILE} + exit 1 +fi +# this had better be empty +cd ..; rmdir tmp +dotest_fail 4.75 "test -d tmp" '' + +# a simple function to compare directory contents +# +# BTW, I don't care any more -- if you don't have a /bin/sh that handles +# shell functions, well get one. +# +# Returns: ISDIFF := true|false +# +directory_cmp () +{ + OLDPWD=`pwd` + DIR_1=$1 + DIR_2=$2 + ISDIFF=false + + cd $DIR_1 + find . -print | fgrep -v /CVS | sort > /tmp/dc$$d1 + + # go back where we were to avoid symlink hell... + cd $OLDPWD + cd $DIR_2 + find . -print | fgrep -v /CVS | sort > /tmp/dc$$d2 + + if diff /tmp/dc$$d1 /tmp/dc$$d2 >/dev/null 2>&1 + then + : + else + ISDIFF=true + return + fi + cd $OLDPWD + while read a + do + if [ -f $DIR_1/"$a" ] ; then + cmp -s $DIR_1/"$a" $DIR_2/"$a" + if [ $? -ne 0 ] ; then + ISDIFF=true + fi + fi + done < /tmp/dc$$d1 +### FIXME: +### rm -f /tmp/dc$$* +} + +# so much for the setup. Let's try something harder. # Try setting CVSROOT so we don't have to worry about it anymore. (now that # we've tested -d cvsroot.) -CVSROOT_FILENAME=`pwd`/cvsroot -CVSROOT=${CVSROOT_FILENAME} ; export CVSROOT +CVSROOT_DIRNAME=${TESTDIR}/cvsroot +CVSROOT=${CVSROOT_DIRNAME} ; export CVSROOT if test "x$remote" = xyes; then - CVSROOT=`hostname`:${CVSROOT_FILENAME} ; export CVSROOT - # Use rsh so we can test it without having to muck with inetd or anything - # like that. Also needed to get CVS_SERVER to work. - CVS_CLIENT_PORT=-1; export CVS_CLIENT_PORT - CVS_SERVER=${testcvs}; export CVS_SERVER -fi - -mkdir tmp ; cd tmp -if ${CVS} -d `pwd`/../cvsroot co CVSROOT ; then - echo "PASS: test 5" >>${LOGFILE} -else - echo "FAIL: test 5" | tee -a ${LOGFILE}; exit 1 + CVSROOT=`hostname`:${CVSROOT_DIRNAME} ; export CVSROOT + # Use rsh so we can test it without having to muck with inetd or anything + # like that. Also needed to get CVS_SERVER to work. + CVS_CLIENT_PORT=-1; export CVS_CLIENT_PORT + CVS_SERVER=${testcvs}; export CVS_SERVER fi -cd .. ; rm -rf tmp - # start keeping history -touch ${CVSROOT_FILENAME}/CVSROOT/history +touch ${CVSROOT_DIRNAME}/CVSROOT/history ### The big loop for what in $tests; do case $what in + basica) + # Similar in spirit to some of the basic0, basic1, and basic2 + # tests, but hopefully a lot faster. Also tests operating on + # files two directories down *without* operating on the parent dirs. + mkdir ${CVSROOT_DIRNAME}/first-dir + dotest basica-1 "${testcvs} -q co first-dir" '' + cd first-dir + mkdir sdir + dotest basica-2 "${testcvs} add sdir" \ +'Directory /tmp/cvs-sanity/cvsroot/first-dir/sdir added to the repository' + cd sdir + mkdir ssdir + dotest basica-3 "${testcvs} add ssdir" \ +'Directory /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir added to the repository' + cd ssdir + echo ssfile >ssfile + dotest basica-4 "${testcvs} add ssfile" \ +'cvs [a-z]*: scheduling file `ssfile'\'' for addition +cvs [a-z]*: use '\''cvs commit'\'' to add this file permanently' + cd ../.. + dotest basica-5 "${testcvs} -q ci -m add-it" \ +'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v +done +Checking in sdir/ssdir/ssfile; +/tmp/cvs-sanity/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile +initial revision: 1.1 +done' + dotest basica-6 "${testcvs} -q update" '' + echo "ssfile line 2" >>sdir/ssdir/ssfile + 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 +new revision: 1.2; previous revision: 1.1 +done' + dotest_fail basica-nonexist "${testcvs} -q ci nonexist" \ +'cvs [a-z]*: nothing known about `nonexist'\'' +cvs \[[a-z]* aborted\]: correct above errors first!' + dotest basica-8 "${testcvs} -q update" '' + cd .. + + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -r first-dir + ;; + basic0) # Now, let's build something. # mkdir first-dir # this doesn't yet work, though I think maybe it should. xoxorich. @@ -123,13 +413,17 @@ for what in $tests; do # true # else # echo cvs does not yet add top level directories cleanly. - mkdir ${CVSROOT_FILENAME}/first-dir + mkdir ${CVSROOT_DIRNAME}/first-dir # fi # rm -rf first-dir # check out an empty directory if ${CVS} co first-dir ; then - echo "PASS: test 6" >>${LOGFILE} + if [ -r first-dir/CVS/Entries ] ; then + echo "PASS: test 6" >>${LOGFILE} + else + echo "FAIL: test 6" | tee -a ${LOGFILE}; exit 1 + fi else echo "FAIL: test 6" | tee -a ${LOGFILE}; exit 1 fi @@ -185,9 +479,9 @@ for what in $tests; do ;; basic1) # first dive - add a files, first singly, then in a group. - rm -rf ${CVSROOT_FILENAME}/first-dir + rm -rf ${CVSROOT_DIRNAME}/first-dir rm -rf first-dir - mkdir ${CVSROOT_FILENAME}/first-dir + mkdir ${CVSROOT_DIRNAME}/first-dir # check out an empty directory if ${CVS} co first-dir ; then echo "PASS: test 13a" >>${LOGFILE} @@ -232,7 +526,7 @@ for what in $tests; do echo "FAIL: test 17-${do}-$j" | tee -a ${LOGFILE}; exit 1 fi - # fixme: this one doesn't work yet for added files. + # FIXME: this one doesn't work yet for added files. # log all. if ${CVS} log >> ${LOGFILE}; then echo "PASS: test 18-${do}-$j" >>${LOGFILE} @@ -267,7 +561,7 @@ for what in $tests; do fi # log all. - # fixme: doesn't work right for added files. + # FIXME: doesn't work right for added files. if ${CVS} log first-dir >> ${LOGFILE}; then echo "PASS: test 22-${do}-$j" >>${LOGFILE} else @@ -283,34 +577,36 @@ for what in $tests; do # update all. if ${CVS} update first-dir ; then - true + echo "PASS: test 24-${do}-$j" >>${LOGFILE} else - echo '***' failed test 24-${do}-$j. ; exit 1 + 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 - true + echo "PASS: test 25-${do}-$j" >>${LOGFILE} else # diff all if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then - true + echo "PASS: test 25-${do}-$j" >>${LOGFILE} else - echo '***' failed test 25-${do}-$j. # FIXME; exit 1 + echo "FAIL: test 25-${do}-$j" | tee -a ${LOGFILE} + # FIXME; exit 1 fi # diff all if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then - true + echo "PASS: test 26-${do}-$j" >>${LOGFILE} else - echo '***' failed test 26-${do}-$j. # FIXME; exit 1 + echo "FAIL: test 26-${do}-$j" | tee -a ${LOGFILE} + # FIXME; exit 1 fi fi # update all. if ${CVS} co first-dir ; then - true + echo "PASS: test 27-${do}-$j" >>${LOGFILE} else - echo '***' failed test 27-${do}-$j. ; exit 1 + echo "FAIL: test 27-${do}-$j" | tee -a ${LOGFILE} ; exit 1 fi cd first-dir @@ -321,21 +617,27 @@ for what in $tests; do files="file2 file3 file4 file5" done if ${CVS} tag first-dive ; then - true + echo "PASS: test 28" >>${LOGFILE} else - echo '***' failed test 28. ; exit 1 + echo "FAIL: test 28" | tee -a ${LOGFILE} ; exit 1 fi cd .. + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -rf first-dir ;; - basic2) # second dive - add bunch o' files in bunch o' added directories + basic2) + # second dive - add bunch o' files in bunch o' added + # directories + mkdir ${CVSROOT_DIRNAME}/first-dir + dotest basic2-1 "${testcvs} -q co first-dir" '' for i in first-dir dir1 dir2 dir3 dir4 ; do if [ ! -d $i ] ; then mkdir $i if ${CVS} add $i >> ${LOGFILE}; then - true + echo "PASS: test 29-$i" >>${LOGFILE} else - echo '***' failed test 29-$i. ; exit 1 + echo "FAIL: test 29-$i" | tee -a ${LOGFILE} ; exit 1 fi fi @@ -346,51 +648,52 @@ for what in $tests; do done if ${CVS} add file6 file7 file8 file9 file10 file11 file12 file13 2>> ${LOGFILE}; then - true + echo "PASS: test 30-$i-$j" >>${LOGFILE} else - echo '***' failed test 30-$i-$j. ; exit 1 + echo "FAIL: test 30-$i-$j" | tee -a ${LOGFILE} ; exit 1 fi done cd ../../../../.. if ${CVS} update first-dir ; then - true + echo "PASS: test 31" >>${LOGFILE} else - echo '***' failed test 31. ; exit 1 + echo "FAIL: test 31" | tee -a ${LOGFILE} ; exit 1 fi # fixme: doesn't work right for added files. if ${CVS} log first-dir >> ${LOGFILE}; then - true + echo "PASS: test 32" >>${LOGFILE} else - echo '***' failed test 32. # ; exit 1 + echo "FAIL: test 32" | tee -a ${LOGFILE} # ; exit 1 fi if ${CVS} status first-dir >> ${LOGFILE}; then - true + echo "PASS: test 33" >>${LOGFILE} else - echo '***' failed test 33. ; exit 1 + echo "FAIL: test 33" | tee -a ${LOGFILE} ; exit 1 fi # if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then -# true +# echo "PASS: test 34" >>${LOGFILE} # else -# echo '***' failed test 34. # ; exit 1 +# echo "FAIL: test 34" | tee -a ${LOGFILE} # ; exit 1 # fi if ${CVS} ci -m "second dive" first-dir >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 35" >>${LOGFILE} else - echo '***' failed test 35. ; exit 1 + echo "FAIL: test 35" | tee -a ${LOGFILE} ; exit 1 fi if ${CVS} tag second-dive first-dir ; then - true + echo "PASS: test 36" >>${LOGFILE} else - echo '***' failed test 36. ; exit 1 + echo "FAIL: test 36" | tee -a ${LOGFILE} ; exit 1 fi - ;; - basic3) # third dive - in bunch o' directories, add bunch o' files, delete some, change some. + # third dive - in bunch o' directories, add bunch o' files, + # delete some, change some. + for i in first-dir dir1 dir2 dir3 dir4 ; do cd $i @@ -403,9 +706,9 @@ for what in $tests; do rm file7 file9 file11 file13 if ${CVS} rm file7 file9 file11 file13 2>> ${LOGFILE}; then - true + echo "PASS: test 37-$i" >>${LOGFILE} else - echo '***' failed test 37-$i. ; exit 1 + echo "FAIL: test 37-$i" | tee -a ${LOGFILE} ; exit 1 fi # and add some new ones @@ -414,336 +717,403 @@ for what in $tests; do done if ${CVS} add file14 file15 file16 file17 2>> ${LOGFILE}; then - true + echo "PASS: test 38-$i" >>${LOGFILE} else - echo '***' failed test 38-$i. ; exit 1 + echo "FAIL: test 38-$i" | tee -a ${LOGFILE} ; exit 1 fi done cd ../../../../.. if ${CVS} update first-dir ; then - true + echo "PASS: test 39" >>${LOGFILE} else - echo '***' failed test 39. ; exit 1 + echo "FAIL: test 39" | tee -a ${LOGFILE} ; exit 1 fi # fixme: doesn't work right for added files if ${CVS} log first-dir >> ${LOGFILE}; then - true + echo "PASS: test 40" >>${LOGFILE} else - echo '***' failed test 40. # ; exit 1 + echo "FAIL: test 40" | tee -a ${LOGFILE} # ; exit 1 fi if ${CVS} status first-dir >> ${LOGFILE}; then - true + echo "PASS: test 41" >>${LOGFILE} else - echo '***' failed test 41. ; exit 1 + echo "FAIL: test 41" | tee -a ${LOGFILE} ; exit 1 fi # if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then -# true +# echo "PASS: test 42" >>${LOGFILE} # else -# echo '***' failed test 42. # ; exit 1 +# echo "FAIL: test 42" | tee -a ${LOGFILE} # ; exit 1 # fi if ${CVS} ci -m "third dive" first-dir >>${LOGFILE} 2>&1; then - true + echo "PASS: test 43" >>${LOGFILE} else - echo '***' failed test 43. ; exit 1 + echo "FAIL: test 43" | tee -a ${LOGFILE} ; exit 1 fi + dotest 43.5 "${testcvs} -q update first-dir" '' if ${CVS} tag third-dive first-dir ; then - true + echo "PASS: test 44" >>${LOGFILE} else - echo '***' failed test 44. ; exit 1 + echo "FAIL: test 44" | tee -a ${LOGFILE} ; exit 1 fi - # Hmm... fixme. -# if ${CVS} release first-dir ; then -# true -# else -# echo '***' failed test 45. # ; exit 1 -# fi + if echo "yes" | ${CVS} release -d first-dir ; then + echo "PASS: test 45" >>${LOGFILE} + else + echo "FAIL: test 45" | tee -a ${LOGFILE} ; exit 1 + fi # end of third dive - rm -rf first-dir + if [ -d first-dir ] ; then + echo "FAIL: test 45.5" | tee -a ${LOGFILE} ; exit 1 + else + echo "PASS: test 45.5" >>${LOGFILE} + fi + ;; rtags) # now try some rtags # rtag HEADS if ${CVS} rtag rtagged-by-head first-dir ; then - true + echo "PASS: test 46" >>${LOGFILE} else - echo '***' failed test 46. ; exit 1 + echo "FAIL: test 46" | tee -a ${LOGFILE} ; exit 1 fi # tag by tag if ${CVS} rtag -r rtagged-by-head rtagged-by-tag first-dir ; then - true + echo "PASS: test 47" >>${LOGFILE} else - echo '***' failed test 47. ; exit 1 + echo "FAIL: test 47" | tee -a ${LOGFILE} ; exit 1 fi # tag by revision if ${CVS} rtag -r1.1 rtagged-by-revision first-dir ; then - true + echo "PASS: test 48" >>${LOGFILE} else - echo '***' failed test 48. ; exit 1 + echo "FAIL: test 48" | tee -a ${LOGFILE} ; exit 1 fi # rdiff by revision if ${CVS} rdiff -r1.1 -rrtagged-by-head first-dir >> ${LOGFILE} || [ $? = 1 ] ; then - true + echo "PASS: test 49" >>${LOGFILE} else - echo '***' failed test 49. ; exit 1 + echo "FAIL: test 49" | tee -a ${LOGFILE} ; exit 1 fi # now export by rtagged-by-head and rtagged-by-tag and compare. rm -rf first-dir if ${CVS} export -r rtagged-by-head first-dir ; then - true + echo "PASS: test 50" >>${LOGFILE} else - echo '***' failed test 50. ; exit 1 + echo "FAIL: test 50" | tee -a ${LOGFILE} ; exit 1 fi mv first-dir 1dir if ${CVS} export -r rtagged-by-tag first-dir ; then - true + echo "PASS: test 51" >>${LOGFILE} else - echo '***' failed test 51. ; exit 1 + echo "FAIL: test 51" | tee -a ${LOGFILE} ; exit 1 fi - if diff -c -r 1dir first-dir ; then - true + directory_cmp 1dir first-dir + + if $ISDIFF ; then + echo "FAIL: test 52" | tee -a ${LOGFILE} ; exit 1 else - echo '***' failed test 52. ; exit 1 + echo "PASS: test 52" >>${LOGFILE} fi rm -rf 1dir first-dir - # For some reason, this command has stopped working and hence much of this sequence is currently off. - # export by revision vs checkout by rtagged-by-revision and compare. -# if ${CVS} export -r1.1 first-dir ; then -# true -# else -# echo '***' failed test 53. # ; exit 1 -# fi - # note sidestep below - #mv first-dir 1dir + # checkout by revision vs export by rtagged-by-revision and compare. + if ${CVS} export -rrtagged-by-revision -d export-dir first-dir ; then + echo "PASS: test 53" >>${LOGFILE} + else + echo "FAIL: test 53" | tee -a ${LOGFILE} ; exit 1 + fi - if ${CVS} co -rrtagged-by-revision first-dir ; then - true + if ${CVS} co -r1.1 first-dir ; then + echo "PASS: test 54" >>${LOGFILE} else - echo '***' failed test 54. ; exit 1 + echo "FAIL: test 54" | tee -a ${LOGFILE} ; exit 1 fi - # fixme: this is here temporarily to sidestep test 53. - ln -s first-dir 1dir # directory copies are done in an oblique way in order to avoid a bug in sun's tmp filesystem. mkdir first-dir.cpy ; (cd first-dir ; tar cf - * | (cd ../first-dir.cpy ; tar xf -)) - if diff --exclude=CVS -c -r 1dir first-dir ; then - true + directory_cmp first-dir export-dir + + if $ISDIFF ; then + echo "FAIL: test 55" | tee -a ${LOGFILE} ; exit 1 else - echo '***' failed test 55. ; exit 1 + echo "PASS: test 55" >>${LOGFILE} fi # interrupt, while we've got a clean 1.1 here, let's import it into another tree. - cd 1dir + cd export-dir if ${CVS} import -m "first-import" second-dir first-immigration immigration1 immigration1_0 ; then - true + echo "PASS: test 56" >>${LOGFILE} else - echo '***' failed test 56. ; exit 1 + echo "FAIL: test 56" | tee -a ${LOGFILE} ; exit 1 fi cd .. if ${CVS} export -r HEAD second-dir ; then - true + echo "PASS: test 57" >>${LOGFILE} else - echo '***' failed test 57. ; exit 1 + echo "FAIL: test 57" | tee -a ${LOGFILE} ; exit 1 fi - if diff --exclude=CVS -c -r first-dir second-dir ; then - true + directory_cmp first-dir second-dir + + if $ISDIFF ; then + echo "FAIL: test 58" | tee -a ${LOGFILE} ; exit 1 else - echo '***' failed test 58. ; exit 1 + echo "PASS: test 58" >>${LOGFILE} fi - rm -rf 1dir first-dir + rm -rf second-dir + rm -rf export-dir first-dir mkdir first-dir (cd first-dir.cpy ; tar cf - * | (cd ../first-dir ; tar xf -)) # update the top, cancelling sticky tags, retag, update other copy, compare. cd first-dir if ${CVS} update -A -l *file* 2>> ${LOGFILE}; then - true + echo "PASS: test 59" >>${LOGFILE} else - echo '***' failed test 59. ; exit 1 + echo "FAIL: test 59" | tee -a ${LOGFILE} ; exit 1 fi # If we don't delete the tag first, cvs won't retag it. # This would appear to be a feature. if ${CVS} tag -l -d rtagged-by-revision ; then - true + echo "PASS: test 60a" >>${LOGFILE} else - echo '***' failed test 60a. ; exit 1 + echo "FAIL: test 60a" | tee -a ${LOGFILE} ; exit 1 fi if ${CVS} tag -l rtagged-by-revision ; then - true + echo "PASS: test 60b" >>${LOGFILE} else - echo '***' failed test 60b. ; exit 1 + echo "FAIL: test 60b" | tee -a ${LOGFILE} ; exit 1 fi - cd .. ; mv first-dir 1dir - mv first-dir.cpy first-dir ; cd first-dir + cd .. + mv first-dir 1dir + mv first-dir.cpy first-dir + cd first-dir + if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then - true + echo "PASS: test 61" >>${LOGFILE} else - echo '***' failed test 61. ; exit 1 + echo "FAIL: test 61" | tee -a ${LOGFILE} ; exit 1 fi if ${CVS} update ; then - true + echo "PASS: test 62" >>${LOGFILE} else - echo '***' failed test 62. ; exit 1 + echo "FAIL: test 62" | tee -a ${LOGFILE} ; exit 1 fi cd .. -# Haven't investigated why this is failing. -# if diff --exclude=CVS -c -r 1dir first-dir ; then -# true + #### FIXME: is this expected to work??? Need to investigate + #### and fix or remove the test. +# directory_cmp 1dir first-dir +# +# if $ISDIFF ; then +# echo "FAIL: test 63" | tee -a ${LOGFILE} # ; exit 1 # else -# echo '***' failed test 63. # ; exit 1 +# echo "PASS: test 63" >>${LOGFILE} # fi rm -rf 1dir first-dir if ${CVS} his -e -a >> ${LOGFILE}; then - true + echo "PASS: test 64" >>${LOGFILE} else - echo '***' failed test 64. ; exit 1 + echo "FAIL: test 64" | tee -a ${LOGFILE} ; exit 1 fi + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -rf ${CVSROOT_DIRNAME}/second-dir ;; death) # next dive. test death support. - rm -rf ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir + mkdir ${CVSROOT_DIRNAME}/first-dir if ${CVS} co first-dir ; then - true + echo "PASS: test 65" >>${LOGFILE} else - echo '***' failed test 65 ; exit 1 + echo "FAIL: test 65" | tee -a ${LOGFILE} ; exit 1 fi cd first-dir + # Create a directory with only dead files, to make sure CVS + # doesn't get confused by it. + mkdir subdir + dotest 65a0 "${testcvs} add subdir" \ +'Directory /tmp/cvs-sanity/cvsroot/first-dir/subdir added to the repository' + cd subdir + echo file in subdir >sfile + dotest 65a1 "${testcvs} add sfile" \ +'cvs [a-z]*: scheduling file `sfile'\'' for addition +cvs [a-z]*: use '\''cvs commit'\'' to add this file permanently' + dotest 65a2 "${testcvs} -q ci -m add-it" \ +'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/subdir/sfile,v +done +Checking in sfile; +/tmp/cvs-sanity/cvsroot/first-dir/subdir/sfile,v <-- sfile +initial revision: 1.1 +done' + rm sfile + dotest 65a3 "${testcvs} rm sfile" \ +'cvs [a-z]*: scheduling `sfile'\'' for removal +cvs [a-z]*: use '\''cvs commit'\'' to remove this file permanently' + dotest 65a4 "${testcvs} -q ci -m remove-it" \ +'Removing sfile; +/tmp/cvs-sanity/cvsroot/first-dir/subdir/sfile,v <-- sfile +new revision: delete; previous revision: 1.1 +done' + cd .. + dotest 65a5 "${testcvs} -q update -P" '' + dotest_fail 65a6 "test -d subdir" '' + # add a file. touch file1 if ${CVS} add file1 2>> ${LOGFILE}; then - true + echo "PASS: test 66" >>${LOGFILE} else - echo '***' failed test 66 ; exit 1 + echo "FAIL: test 66" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 67" >>${LOGFILE} else - echo '***' failed test 67 ; exit 1 + echo "FAIL: test 67" | tee -a ${LOGFILE} ; exit 1 fi # remove rm file1 if ${CVS} rm file1 2>> ${LOGFILE}; then - true + echo "PASS: test 68" >>${LOGFILE} else - echo '***' failed test 68 ; exit 1 + echo "FAIL: test 68" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >>${LOGFILE} ; then - true + echo "PASS: test 69" >>${LOGFILE} else - echo '***' failed test 69 ; exit 1 + echo "FAIL: test 69" | tee -a ${LOGFILE} ; exit 1 fi # add again and create second file touch file1 file2 if ${CVS} add file1 file2 2>> ${LOGFILE}; then - true + echo "PASS: test 70" >>${LOGFILE} else - echo '***' failed test 70 ; exit 1 + echo "FAIL: test 70" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 71" >>${LOGFILE} else - echo '***' failed test 71 ; exit 1 + echo "FAIL: test 71" | tee -a ${LOGFILE} ; exit 1 fi # log if ${CVS} log file1 >> ${LOGFILE}; then - true + echo "PASS: test 72" >>${LOGFILE} else - echo '***' failed test 72 ; exit 1 + echo "FAIL: test 72" | tee -a ${LOGFILE} ; exit 1 fi + # file4 will be dead at the time of branching and stay dead. + echo file4 > file4 + dotest death-file4-add "${testcvs} add file4" \ +'cvs [a-z]*: scheduling file `file4'\'' for addition +cvs [a-z]*: use '\''cvs commit'\'' to add this file permanently' + dotest death-file4-ciadd "${testcvs} -q ci -m add file4" \ +'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' + rm file4 + dotest death-file4-rm "${testcvs} remove file4" \ +'cvs [a-z]*: scheduling `file4'\'' for removal +cvs [a-z]*: use '\''cvs commit'\'' to remove this file permanently' + dotest death-file4-cirm "${testcvs} -q ci -m remove file4" \ +'Removing file4; +/tmp/cvs-sanity/cvsroot/first-dir/file4,v <-- file4 +new revision: delete; previous revision: 1.1 +done' # branch1 if ${CVS} tag -b branch1 ; then - true + echo "PASS: test 73" >>${LOGFILE} else - echo '***' failed test 73 ; exit 1 + echo "FAIL: test 73" | tee -a ${LOGFILE} ; exit 1 fi # and move to the branch. if ${CVS} update -r branch1 ; then - true + echo "PASS: test 74" >>${LOGFILE} else - echo '***' failed test 74 ; exit 1 + echo "FAIL: test 74" | tee -a ${LOGFILE} ; exit 1 fi + dotest_fail death-file4-3 "test -f file4" '' + # add a file in the branch echo line1 from branch1 >> file3 if ${CVS} add file3 2>> ${LOGFILE}; then - true + echo "PASS: test 75" >>${LOGFILE} else - echo '***' failed test 75 ; exit 1 + echo "FAIL: test 75" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 76" >>${LOGFILE} else - echo '***' failed test 76 ; exit 1 + echo "FAIL: test 76" | tee -a ${LOGFILE} ; exit 1 fi # remove rm file3 if ${CVS} rm file3 2>> ${LOGFILE}; then - true + echo "PASS: test 77" >>${LOGFILE} else - echo '***' failed test 77 ; exit 1 + echo "FAIL: test 77" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >>${LOGFILE} ; then - true + echo "PASS: test 78" >>${LOGFILE} else - echo '***' failed test 78 ; exit 1 + echo "FAIL: test 78" | tee -a ${LOGFILE} ; exit 1 fi # add again echo line1 from branch1 >> file3 if ${CVS} add file3 2>> ${LOGFILE}; then - true + echo "PASS: test 79" >>${LOGFILE} else - echo '***' failed test 79 ; exit 1 + echo "FAIL: test 79" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 80" >>${LOGFILE} else - echo '***' failed test 80 ; exit 1 + echo "FAIL: test 80" | tee -a ${LOGFILE} ; exit 1 fi # change the first file @@ -751,108 +1121,139 @@ for what in $tests; do # commit if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 81" >>${LOGFILE} else - echo '***' failed test 81 ; exit 1 + echo "FAIL: test 81" | tee -a ${LOGFILE} ; exit 1 fi # remove the second rm file2 if ${CVS} rm file2 2>> ${LOGFILE}; then - true + echo "PASS: test 82" >>${LOGFILE} else - echo '***' failed test 82 ; exit 1 + echo "FAIL: test 82" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >>${LOGFILE}; then - true + echo "PASS: test 83" >>${LOGFILE} else - echo '***' failed test 83 ; exit 1 + echo "FAIL: test 83" | tee -a ${LOGFILE} ; exit 1 fi # back to the trunk. if ${CVS} update -A 2>> ${LOGFILE}; then - true + echo "PASS: test 84" >>${LOGFILE} else - echo '***' failed test 84 ; exit 1 + echo "FAIL: test 84" | tee -a ${LOGFILE} ; exit 1 fi + dotest_fail death-file4-4 "test -f file4" '' + if [ -f file3 ] ; then - echo '***' failed test 85 ; exit 1 + echo "FAIL: test 85" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 85" >>${LOGFILE} fi # join if ${CVS} update -j branch1 >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 86" >>${LOGFILE} else - echo '***' failed test 86 ; exit 1 + echo "FAIL: test 86" | tee -a ${LOGFILE} ; exit 1 fi + dotest_fail death-file4-5 "test -f file4" '' + if [ -f file3 ] ; then - true + echo "PASS: test 87" >>${LOGFILE} else - echo '***' failed test 87 ; exit 1 + echo "FAIL: test 87" | tee -a ${LOGFILE} ; exit 1 + fi + + # Make sure that we joined the correct change to file1 + if echo line2 from branch1 | cmp - file1 >/dev/null; then + echo 'PASS: test 87a' >>${LOGFILE} + else + echo 'FAIL: test 87a' | tee -a ${LOGFILE} + exit 1 fi # update if ${CVS} update ; then - true + echo "PASS: test 88" >>${LOGFILE} else - echo '***' failed test 88 ; exit 1 + echo "FAIL: test 88" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >>${LOGFILE} 2>&1; then - true + echo "PASS: test 89" >>${LOGFILE} else - echo '***' failed test 89 ; exit 1 + echo "FAIL: test 89" | tee -a ${LOGFILE} ; exit 1 fi # remove first file. rm file1 if ${CVS} rm file1 2>> ${LOGFILE}; then - true + echo "PASS: test 90" >>${LOGFILE} else - echo '***' failed test 90 ; exit 1 + echo "FAIL: test 90" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m test >>${LOGFILE}; then - true + echo "PASS: test 91" >>${LOGFILE} else - echo '***' failed test 91 ; exit 1 + echo "FAIL: test 91" | tee -a ${LOGFILE} ; exit 1 fi if [ -f file1 ] ; then - echo '***' failed test 92 ; exit 1 + echo "FAIL: test 92" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 92" >>${LOGFILE} + fi + + # typo; try to get to the branch and fail + dotest_fail 92.1a "${testcvs} update -r brnach1" \ + 'cvs \[[a-z]* aborted\]: no such tag brnach1' + # Make sure we are still on the trunk + if test -f file1 ; then + echo "FAIL: 92.1b" | tee -a ${LOGFILE} ; exit 1 + else + echo "PASS: 92.1b" >>${LOGFILE} + fi + if test -f file2 ; then + echo "PASS: 92.1c" >>${LOGFILE} + else + echo "FAIL: 92.1c" | tee -a ${LOGFILE} ; exit 1 fi # back to branch1 if ${CVS} update -r branch1 2>> ${LOGFILE}; then - true + echo "PASS: test 93" >>${LOGFILE} else - echo '***' failed test 93 ; exit 1 + echo "FAIL: test 93" | tee -a ${LOGFILE} ; exit 1 fi + dotest_fail death-file4-6 "test -f file4" '' + if [ -f file1 ] ; then - true + echo "PASS: test 94" >>${LOGFILE} else - echo '***' failed test 94 ; exit 1 + echo "FAIL: test 94" | tee -a ${LOGFILE} ; exit 1 fi # and join if ${CVS} update -j HEAD >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 95" >>${LOGFILE} else - echo '***' failed test 95 ; exit 1 + echo "FAIL: test 95" | tee -a ${LOGFILE} ; exit 1 fi - cd .. ; rm -rf first-dir ${CVSROOT_FILENAME}/first-dir + dotest_fail death-file4-7 "test -f file4" '' + + cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir ;; import) # test death after import @@ -863,35 +1264,54 @@ for what in $tests; do echo imported file"$i" > imported-file"$i" done + # This directory should be on the default ignore list, + # so it shouldn't get imported. + mkdir RCS + echo ignore.me >RCS/ignore.me + + echo 'import should not expand $''Id$' >>imported-file2 + cp imported-file2 ../imported-file2-orig.tmp + if ${CVS} import -m first-import first-dir vendor-branch junk-1_0 ; then - true + echo "PASS: test 96" >>${LOGFILE} else - echo '***' failed test 96 ; exit 1 + echo "FAIL: test 96" | tee -a ${LOGFILE} ; exit 1 + fi + + if cmp ../imported-file2-orig.tmp imported-file2; then + pass 96.5 + else + fail 96.5 fi cd .. # co if ${CVS} co first-dir ; then - true + echo "PASS: test 97" >>${LOGFILE} else - echo '***' failed test 97 ; exit 1 + echo "FAIL: test 97" | tee -a ${LOGFILE} ; exit 1 fi cd first-dir for i in 1 2 3 4 ; do if [ -f imported-file"$i" ] ; then - true + echo "PASS: test 98-$i" >>${LOGFILE} else - echo '***' failed test 98-$i ; exit 1 + echo "FAIL: test 98-$i" | tee -a ${LOGFILE} ; exit 1 fi done + if test -d RCS; then + echo "FAIL: test 98.5" | tee -a ${LOGFILE} ; exit 1 + else + echo "PASS: test 98.5" >>${LOGFILE} + fi # remove rm imported-file1 if ${CVS} rm imported-file1 2>> ${LOGFILE}; then - true + echo "PASS: test 99" >>${LOGFILE} else - echo '***' failed test 99 ; exit 1 + echo "FAIL: test 99" | tee -a ${LOGFILE} ; exit 1 fi # change @@ -902,46 +1322,46 @@ for what in $tests; do # commit if ${CVS} ci -m local-changes >> ${LOGFILE} 2>&1; then - true + echo "PASS: test 100" >>${LOGFILE} else - echo '***' failed test 100 ; exit 1 + echo "FAIL: test 100" | tee -a ${LOGFILE} ; exit 1 fi # log if ${CVS} log imported-file1 | grep '1.1.1.2 (dead)' ; then - echo '***' failed test 101 ; exit 1 + echo "FAIL: test 101" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 101" >>${LOGFILE} fi # update into the vendor branch. if ${CVS} update -rvendor-branch ; then - true + echo "PASS: test 102" >>${LOGFILE} else - echo '***' failed test 102 ; exit 1 + echo "FAIL: test 102" | tee -a ${LOGFILE} ; exit 1 fi # remove file4 on the vendor branch rm imported-file4 if ${CVS} rm imported-file4 2>> ${LOGFILE}; then - true + echo "PASS: test 103" >>${LOGFILE} else - echo '***' failed test 103 ; exit 1 + echo "FAIL: test 103" | tee -a ${LOGFILE} ; exit 1 fi # commit if ${CVS} ci -m vendor-removed imported-file4 >>${LOGFILE}; then - true + echo "PASS: test 104" >>${LOGFILE} else - echo '***' failed test 104 ; exit 1 + echo "FAIL: test 104" | tee -a ${LOGFILE} ; exit 1 fi # update to main line if ${CVS} update -A 2>> ${LOGFILE}; then - true + echo "PASS: test 105" >>${LOGFILE} else - echo '***' failed test 105 ; exit 1 + echo "FAIL: test 105" | tee -a ${LOGFILE} ; exit 1 fi # second import - file4 deliberately unchanged @@ -949,146 +1369,152 @@ for what in $tests; do for i in 1 2 3 ; do echo rev 2 of file $i >> imported-file"$i" done + cp imported-file2 ../imported-file2-orig.tmp if ${CVS} import -m second-import first-dir vendor-branch junk-2_0 ; then - true + echo "PASS: test 106" >>${LOGFILE} + else + echo "FAIL: test 106" | tee -a ${LOGFILE} ; exit 1 + fi + if cmp ../imported-file2-orig.tmp imported-file2; then + pass 106.5 else - echo '***' failed test 106 ; exit 1 + fail 106.5 fi cd .. # co if ${CVS} co first-dir ; then - true + echo "PASS: test 107" >>${LOGFILE} else - echo '***' failed test 107 ; exit 1 + echo "FAIL: test 107" | tee -a ${LOGFILE} ; exit 1 fi cd first-dir if [ -f imported-file1 ] ; then - echo '***' failed test 108 ; exit 1 + echo "FAIL: test 108" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 108" >>${LOGFILE} fi for i in 2 3 ; do if [ -f imported-file"$i" ] ; then - true + echo "PASS: test 109-$i" >>${LOGFILE} else - echo '***' failed test 109-$i ; exit 1 + echo "FAIL: test 109-$i" | tee -a ${LOGFILE} ; exit 1 fi done # check vendor branch for file4 if ${CVS} update -rvendor-branch ; then - true + echo "PASS: test 110" >>${LOGFILE} else - echo '***' failed test 110 ; exit 1 + echo "FAIL: test 110" | tee -a ${LOGFILE} ; exit 1 fi if [ -f imported-file4 ] ; then - true + echo "PASS: test 111" >>${LOGFILE} else - echo '***' failed test 111 ; exit 1 + echo "FAIL: test 111" | tee -a ${LOGFILE} ; exit 1 fi # update to main line if ${CVS} update -A 2>> ${LOGFILE}; then - true + echo "PASS: test 112" >>${LOGFILE} else - echo '***' failed test 112 ; exit 1 + echo "FAIL: test 112" | tee -a ${LOGFILE} ; exit 1 fi cd .. if ${CVS} co -jjunk-1_0 -jjunk-2_0 first-dir >>${LOGFILE} 2>&1; then - true + echo "PASS: test 113" >>${LOGFILE} else - echo '***' failed test 113 ; exit 1 + echo "FAIL: test 113" | tee -a ${LOGFILE} ; exit 1 fi cd first-dir if [ -f imported-file1 ] ; then - echo '***' failed test 114 ; exit 1 + echo "FAIL: test 114" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 114" >>${LOGFILE} fi for i in 2 3 ; do if [ -f imported-file"$i" ] ; then - true + echo "PASS: test 115-$i" >>${LOGFILE} else - echo '***' failed test 115-$i ; exit 1 + echo "FAIL: test 115-$i" | tee -a ${LOGFILE} ; exit 1 fi done if cat imported-file2 | grep '====' >> ${LOGFILE}; then - true + echo "PASS: test 116" >>${LOGFILE} else - echo '***' failed test 116 ; exit 1 + echo "FAIL: test 116" | tee -a ${LOGFILE} ; exit 1 fi - cd .. ; rm -rf first-dir ${CVSROOT_FILENAME}/first-dir + cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir + rm -rf import-dir ;; new) # look for stray "no longer pertinent" messages. - rm -rf first-dir ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir + mkdir ${CVSROOT_DIRNAME}/first-dir if ${CVS} co first-dir ; then - true + echo "PASS: test 117" >>${LOGFILE} else - echo '***' failed test 117 ; exit 1 + echo "FAIL: test 117" | tee -a ${LOGFILE} ; exit 1 fi cd first-dir touch a if ${CVS} add a 2>>${LOGFILE}; then - true + echo "PASS: test 118" >>${LOGFILE} else - echo '***' failed test 118 ; exit 1 + echo "FAIL: test 118" | tee -a ${LOGFILE} ; exit 1 fi if ${CVS} ci -m added >>${LOGFILE} 2>&1; then - true + echo "PASS: test 119" >>${LOGFILE} else - echo '***' failed test 119 ; exit 1 + echo "FAIL: test 119" | tee -a ${LOGFILE} ; exit 1 fi rm a if ${CVS} rm a 2>>${LOGFILE}; then - true + echo "PASS: test 120" >>${LOGFILE} else - echo '***' failed test 120 ; exit 1 + echo "FAIL: test 120" | tee -a ${LOGFILE} ; exit 1 fi if ${CVS} ci -m removed >>${LOGFILE} ; then - true + echo "PASS: test 121" >>${LOGFILE} else - echo '***' failed test 121 ; exit 1 + echo "FAIL: test 121" | tee -a ${LOGFILE} ; exit 1 fi if ${CVS} update -A 2>&1 | grep longer ; then - echo '***' failed test 122 ; exit 1 + echo "FAIL: test 122" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 122" >>${LOGFILE} fi if ${CVS} update -rHEAD 2>&1 | grep longer ; then - echo '***' failed test 123 ; exit 1 + echo "FAIL: test 123" | tee -a ${LOGFILE} ; exit 1 else - true + echo "PASS: test 123" >>${LOGFILE} fi - cd .. ; rm -rf first-dir ; rm -rf ${CVSROOT_FILENAME}/first-dir + cd .. ; rm -rf first-dir ; rm -rf ${CVSROOT_DIRNAME}/first-dir ;; conflicts) - rm -rf first-dir ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir + rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir + mkdir ${CVSROOT_DIRNAME}/first-dir mkdir 1 cd 1 @@ -1249,16 +1675,11 @@ for what in $tests; do fi cd ../.. - rm -rf 1 2 3 ; rm -rf ${CVSROOT_FILENAME}/first-dir + rm -rf 1 2 3 ; rm -rf ${CVSROOT_DIRNAME}/first-dir ;; modules) - # The following line stolen from cvsinit.sh. FIXME: create our - # repository via cvsinit.sh; that way we test it too. - (cd ${CVSROOT_FILENAME}/CVSROOT; ci -q -u -t/dev/null \ - -m'initial checkin of modules' modules) - - rm -rf first-dir ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir + rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir + mkdir ${CVSROOT_DIRNAME}/first-dir mkdir 1 cd 1 @@ -1267,6 +1688,7 @@ for what in $tests; do echo 'PASS: test 143' >>${LOGFILE} else echo 'FAIL: test 143' | tee -a ${LOGFILE} + exit 1 fi cd first-dir @@ -1274,18 +1696,20 @@ for what in $tests; do ${testcvs} add subdir >>${LOGFILE} cd subdir - touch a + touch a b - if ${testcvs} add a 2>>${LOGFILE} ; then + if ${testcvs} add a b 2>>${LOGFILE} ; then echo 'PASS: test 144' >>${LOGFILE} else echo 'FAIL: test 144' | tee -a ${LOGFILE} + exit 1 fi if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then echo 'PASS: test 145' >>${LOGFILE} else echo 'FAIL: test 145' | tee -a ${LOGFILE} + exit 1 fi cd .. @@ -1293,6 +1717,7 @@ for what in $tests; do echo 'PASS: test 146' >>${LOGFILE} else echo 'FAIL: test 146' | tee -a ${LOGFILE} + exit 1 fi # Here we test that CVS can deal with CVSROOT (whose repository @@ -1303,34 +1728,131 @@ for what in $tests; do echo 'PASS: test 147' >>${LOGFILE} else echo 'FAIL: test 147' | tee -a ${LOGFILE} + exit 1 fi echo realmodule first-dir/subdir a >>CVSROOT/modules + 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 if ${testcvs} ci -m 'add modules' CVSROOT/modules \ >>${LOGFILE} 2>&1; then echo 'PASS: test 148' >>${LOGFILE} else echo 'FAIL: test 148' | tee -a ${LOGFILE} + exit 1 fi cd .. + + # Test that real modules check out to realmodule/a, not subdir/a. if ${testcvs} co realmodule >>${LOGFILE}; then - echo 'PASS: test 149' >>${LOGFILE} + echo 'PASS: test 149a1' >>${LOGFILE} else - echo 'FAIL: test 149' | tee -a ${LOGFILE} + echo 'FAIL: test 149a1' | tee -a ${LOGFILE} + exit 1 fi if test -d realmodule && test -f realmodule/a; then - echo 'PASS: test 150' >>${LOGFILE} + echo 'PASS: test 149a2' >>${LOGFILE} + else + echo 'FAIL: test 149a2' | tee -a ${LOGFILE} + exit 1 + fi + if test -f realmodule/b; then + echo 'FAIL: test 149a3' | tee -a ${LOGFILE} + exit 1 else - echo 'FAIL: test 150' | tee -a ${LOGFILE} + echo 'PASS: test 149a3' >>${LOGFILE} fi + if ${testcvs} -q co realmodule; then + echo 'PASS: test 149a4' >>${LOGFILE} + else + echo 'FAIL: test 149a4' | tee -a ${LOGFILE} + exit 1 + fi + if echo "yes" | ${testcvs} release -d realmodule >>${LOGFILE} ; then + echo 'PASS: test 149a5' >>${LOGFILE} + else + echo 'FAIL: test 149a5' | tee -a ${LOGFILE} + exit 1 + fi + + # Now test the ability to check out a single file from a directory + if ${testcvs} co dirmodule/a >>${LOGFILE}; then + echo 'PASS: test 150c' >>${LOGFILE} + else + echo 'FAIL: test 150c' | tee -a ${LOGFILE} + exit 1 + fi + if test -d dirmodule && test -f dirmodule/a; then + echo 'PASS: test 150d' >>${LOGFILE} + else + echo 'FAIL: test 150d' | tee -a ${LOGFILE} + exit 1 + fi + if test -f dirmodule/b; then + echo 'FAIL: test 150e' | tee -a ${LOGFILE} + exit 1 + else + echo 'PASS: test 150e' >>${LOGFILE} + fi + if echo "yes" | ${testcvs} release -d dirmodule >>${LOGFILE} ; then + echo 'PASS: test 150f' >>${LOGFILE} + else + echo 'FAIL: test 150f' | tee -a ${LOGFILE} + exit 1 + fi + # Now test the ability to correctly reject a non-existent filename. + # For maximum studliness we would check that an error message is + # being output. + if ${testcvs} co dirmodule/nonexist >>${LOGFILE} 2>&1; then + # We accept a zero exit status because it is what CVS does + # (Dec 95). Probably the exit status should be nonzero, + # however. + echo 'PASS: test 150g1' >>${LOGFILE} + else + echo 'PASS: test 150g1' >>${LOGFILE} + fi + # We tolerate the creation of the dirmodule directory, since that + # is what CVS does, not because we view that as preferable to not + # creating it. + if test -f dirmodule/a || test -f dirmodule/b; then + echo 'FAIL: test 150g2' | tee -a ${LOGFILE} + exit 1 + else + echo 'PASS: test 150g2' >>${LOGFILE} + fi + rm -rf dirmodule + + # Now test that a module using -d checks out to the specified + # directory. + dotest 150h1 "${testcvs} -q co namedmodule" 'U nameddir/a +U nameddir/b' + if test -f nameddir/a && test -f nameddir/b; then + pass 150h2 + else + fail 150h2 + fi + echo add line >>nameddir/a + dotest 150h3 "${testcvs} -q co namedmodule" 'M nameddir/a' + rm nameddir/a + dotest 150h4 "${testcvs} -q co namedmodule" 'U nameddir/a' + if echo "yes" | ${testcvs} release -d nameddir >>${LOGFILE} ; then + pass 150h99 + else + fail 150h99 + fi + + # Now test that alias modules check out to subdir/a, not + # aliasmodule/a. if ${testcvs} co aliasmodule >>${LOGFILE}; then echo 'PASS: test 151' >>${LOGFILE} else echo 'FAIL: test 151' | tee -a ${LOGFILE} + exit 1 fi if test -d aliasmodule; then echo 'FAIL: test 152' | tee -a ${LOGFILE} + exit 1 else echo 'PASS: test 152' >>${LOGFILE} fi @@ -1340,20 +1862,17 @@ for what in $tests; do echo 'PASS: test 153' >>${LOGFILE} else echo 'FAIL: test 153' | tee -a ${LOGFILE} + exit 1 fi echo 'M first-dir/subdir/a' >ans153.tmp if cmp test153.tmp ans153.tmp; then echo 'PASS: test 154' >>${LOGFILE} else echo 'FAIL: test 154' | tee -a ${LOGFILE} - fi - if ${testcvs} -q co realmodule; then - echo 'PASS: test 155' >>${LOGFILE} - else - echo 'FAIL: test 155' | tee -a ${LOGFILE} + exit 1 fi cd .. - rm -rf 1 ; rm -rf ${CVSROOT_FILENAME}/first-dir + rm -rf 1 ; rm -rf ${CVSROOT_DIRNAME}/first-dir ;; mflag) for message in '' ' ' ' @@ -1366,6 +1885,7 @@ for what in $tests; do echo 'PASS: test 156' >>${LOGFILE} else echo 'FAIL: test 156' | tee -a ${LOGFILE} + exit 1 fi # Must import twice since the first time uses inline code that # avoids RCS call. @@ -1374,6 +1894,7 @@ for what in $tests; do echo 'PASS: test 157' >>${LOGFILE} else echo 'FAIL: test 157' | tee -a ${LOGFILE} + exit 1 fi # Test handling of -m during ci cd ..; rm -rf a-dir; @@ -1381,6 +1902,7 @@ for what in $tests; do echo 'PASS: test 158' >>${LOGFILE} else echo 'FAIL: test 158' | tee -a ${LOGFILE} + exit 1 fi cd a-dir echo testc >>test @@ -1388,6 +1910,7 @@ for what in $tests; do echo 'PASS: test 159' >>${LOGFILE} else echo 'FAIL: test 159' | tee -a ${LOGFILE} + exit 1 fi # Test handling of -m during rm/ci rm test; @@ -1395,24 +1918,27 @@ for what in $tests; do echo 'PASS: test 160' >>${LOGFILE} else echo 'FAIL: test 160' | tee -a ${LOGFILE} + exit 1 fi if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then echo 'PASS: test 161' >>${LOGFILE} else echo 'FAIL: test 161' | tee -a ${LOGFILE} + exit 1 fi # Clean up - cd ..; rm -rf a-dir ${CVSROOT_FILENAME}/a-dir + cd ..; rm -rf a-dir ${CVSROOT_DIRNAME}/a-dir done ;; errmsg1) - mkdir ${CVSROOT_FILENAME}/1dir + mkdir ${CVSROOT_DIRNAME}/1dir mkdir 1 cd 1 if ${testcvs} -q co 1dir; then echo 'PASS: test 162' >>${LOGFILE} else echo 'FAIL: test 162' | tee -a ${LOGFILE} + exit 1 fi cd 1dir touch foo @@ -1420,11 +1946,13 @@ for what in $tests; do echo 'PASS: test 163' >>${LOGFILE} else echo 'FAIL: test 163' | tee -a ${LOGFILE} + exit 1 fi if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then echo 'PASS: test 164' >>${LOGFILE} else echo 'FAIL: test 164' | tee -a ${LOGFILE} + exit 1 fi cd ../.. mkdir 2 @@ -1433,6 +1961,7 @@ for what in $tests; do echo 'PASS: test 165' >>${LOGFILE} else echo 'FAIL: test 165' | tee -a ${LOGFILE} + exit 1 fi chmod a-w 1dir cd ../1/1dir @@ -1441,37 +1970,339 @@ for what in $tests; do echo 'PASS: test 166' >>${LOGFILE} else echo 'FAIL: test 166' | tee -a ${LOGFILE} + exit 1 fi if ${testcvs} ci -m removed >>${LOGFILE} 2>&1; then echo 'PASS: test 167' >>${LOGFILE} else echo 'FAIL: test 167' | tee -a ${LOGFILE} + exit 1 fi cd ../../2/1dir ${testcvs} -q update 2>../tst167.err + CVSBASE=`basename $testcvs` # Get basename of CVS executable. cat <../tst167.ans -cvs server: warning: foo is not (any longer) pertinent -cvs update: unable to remove ./foo: Permission denied +$CVSBASE server: warning: foo is not (any longer) pertinent +$CVSBASE update: unable to remove ./foo: Permission denied EOF if cmp ../tst167.ans ../tst167.err >/dev/null || - ( echo 'cvs [update aborted]: cannot rename file foo to CVS/,,foo: Permission denied' | cmp - ../tst167.err >/dev/null ) + ( echo "$CVSBASE [update aborted]: cannot rename file foo to CVS/,,foo: Permission denied" | cmp - ../tst167.err >/dev/null ) then echo 'PASS: test 168' >>${LOGFILE} else echo 'FAIL: test 168' | tee -a ${LOGFILE} + exit 1 fi cd .. chmod u+w 1dir cd .. - rm -rf 1 2 ${CVSROOT_FILENAME}/1dir + rm -rf 1 2 ${CVSROOT_DIRNAME}/1dir ;; - *) echo $what is not the name of a test -- ignored ;; + devcom) + mkdir ${CVSROOT_DIRNAME}/first-dir + mkdir 1 + cd 1 + if ${testcvs} -q co first-dir >>${LOGFILE} ; then + echo 'PASS: test 169' >>${LOGFILE} + else + echo 'FAIL: test 169' | tee -a ${LOGFILE} + exit 1 + fi + + cd first-dir + echo abb >abb + if ${testcvs} add abb 2>>${LOGFILE}; then + echo 'PASS: test 170' >>${LOGFILE} + else + echo 'FAIL: test 170' | tee -a ${LOGFILE} + exit 1 + fi + if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then + echo 'PASS: test 171' >>${LOGFILE} + else + echo 'FAIL: test 171' | tee -a ${LOGFILE} + exit 1 + fi + if ${testcvs} watch on; then + echo 'PASS: test 172' >>${LOGFILE} + else + echo 'FAIL: test 172' | tee -a ${LOGFILE} + fi + echo abc >abc + if ${testcvs} add abc 2>>${LOGFILE}; then + echo 'PASS: test 173' >>${LOGFILE} + else + echo 'FAIL: test 173' | tee -a ${LOGFILE} + fi + if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then + echo 'PASS: test 174' >>${LOGFILE} + else + echo 'FAIL: test 174' | tee -a ${LOGFILE} + fi + + cd ../.. + mkdir 2 + cd 2 + + if ${testcvs} -q co first-dir >>${LOGFILE}; then + echo 'PASS: test 175' >>${LOGFILE} + else + echo 'FAIL: test 175' | tee -a ${LOGFILE} + fi + cd first-dir + if test -w abb; then + echo 'FAIL: test 176' | tee -a ${LOGFILE} + else + echo 'PASS: test 176' >>${LOGFILE} + fi + if test -w abc; then + echo 'FAIL: test 177' | tee -a ${LOGFILE} + else + echo 'PASS: test 177' >>${LOGFILE} + fi + + if ${testcvs} editors >../ans178.tmp; then + echo 'PASS: test 178' >>${LOGFILE} + else + echo 'FAIL: test 178' | tee -a ${LOGFILE} + fi + cat ../ans178.tmp >>${LOGFILE} + if test -s ../ans178.tmp; then + echo 'FAIL: test 178a' | tee -a ${LOGFILE} + else + echo 'PASS: test 178a' >>${LOGFILE} + fi + + if ${testcvs} edit abb; then + echo 'PASS: test 179' >>${LOGFILE} + else + echo 'FAIL: test 179' | tee -a ${LOGFILE} + exit 1 + fi + + if ${testcvs} editors >../ans180.tmp; then + echo 'PASS: test 180' >>${LOGFILE} + else + echo 'FAIL: test 180' | tee -a ${LOGFILE} + exit 1 + fi + cat ../ans180.tmp >>${LOGFILE} + if test -s ../ans180.tmp; then + echo 'PASS: test 181' >>${LOGFILE} + else + echo 'FAIL: test 181' | tee -a ${LOGFILE} + fi + + echo aaaa >>abb + if ${testcvs} ci -m modify abb >>${LOGFILE} 2>&1; then + echo 'PASS: test 182' >>${LOGFILE} + else + echo 'FAIL: test 182' | tee -a ${LOGFILE} + fi + # Unedit of a file not being edited should be a noop. + dotest 182.5 "${testcvs} unedit abb" '' + + if ${testcvs} editors >../ans183.tmp; then + echo 'PASS: test 183' >>${LOGFILE} + else + echo 'FAIL: test 183' | tee -a ${LOGFILE} + fi + cat ../ans183.tmp >>${LOGFILE} + if test -s ../ans183.tmp; then + echo 'FAIL: test 184' | tee -a ${LOGFILE} + else + echo 'PASS: test 184' >>${LOGFILE} + fi + + if test -w abb; then + echo 'FAIL: test 185' | tee -a ${LOGFILE} + else + echo 'PASS: test 185' >>${LOGFILE} + fi + + if ${testcvs} edit abc; then + echo 'PASS: test 186a1' >>${LOGFILE} + else + echo 'FAIL: test 186a1' | tee -a ${LOGFILE} + fi + # Unedit of an unmodified file. + if ${testcvs} unedit abc; then + echo 'PASS: test 186a2' >>${LOGFILE} + else + echo 'FAIL: test 186a2' | tee -a ${LOGFILE} + fi + if ${testcvs} edit abc; then + echo 'PASS: test 186a3' >>${LOGFILE} + else + echo 'FAIL: test 186a3' | tee -a ${LOGFILE} + fi + echo changedabc >abc + # Try to unedit a modified file; cvs should ask for confirmation + if (echo no | ${testcvs} unedit abc) >>${LOGFILE}; then + echo 'PASS: test 186a4' >>${LOGFILE} + else + echo 'FAIL: test 186a4' | tee -a ${LOGFILE} + fi + if echo changedabc | cmp - abc; then + echo 'PASS: test 186a5' >>${LOGFILE} + else + echo 'FAIL: test 186a5' | tee -a ${LOGFILE} + fi + # OK, now confirm the unedit + if (echo yes | ${testcvs} unedit abc) >>${LOGFILE}; then + echo 'PASS: test 186a6' >>${LOGFILE} + else + echo 'FAIL: test 186a6' | tee -a ${LOGFILE} + fi + if echo abc | cmp - abc; then + echo 'PASS: test 186a7' >>${LOGFILE} + else + echo 'FAIL: test 186a7' | tee -a ${LOGFILE} + fi + + cd ../.. + rm -rf 1 2 ${CVSROOT_DIRNAME}/first-dir + ;; + + ignore) + mkdir home + HOME=${TESTDIR}/home; export HOME + dotest 187a1 "${testcvs} -q co CVSROOT" 'U CVSROOT/modules' + cd CVSROOT + echo rootig.c >cvsignore + dotest 187a2 "${testcvs} add cvsignore" 'cvs [a-z]*: scheduling file `cvsignore'"'"' for addition +cvs [a-z]*: use '"'"'cvs commit'"'"' to add this file permanently' + + # As of Jan 96, local CVS prints "Examining ." and remote doesn't. + # Accept either. + dotest 187a3 " ${testcvs} ci -m added" \ +"${DOTSTAR}"'CS file: /tmp/cvs-sanity/cvsroot/CVSROOT/cvsignore,v +done +Checking in cvsignore; +/tmp/cvs-sanity/cvsroot/CVSROOT/cvsignore,v <-- cvsignore +initial revision: 1.1 +done +cvs [a-z]*: Executing '"'"''"'"'.*mkmodules'"'"' '"'"'/tmp/cvs-sanity/cvsroot/CVSROOT'"'"''"'"'' + + cd .. + if echo "yes" | ${testcvs} release -d CVSROOT >>${LOGFILE} ; then + echo 'PASS: test 187a4' >>${LOGFILE} + else + echo 'FAIL: test 187a4' | tee -a ${LOGFILE} + exit 1 + fi + + # CVS looks at the home dir from getpwuid, not HOME (is that correct + # behavior?), so this is hard to test and we won't try. + # echo foobar.c >${HOME}/.cvsignore + CVSIGNORE=envig.c; export CVSIGNORE + mkdir dir-to-import + cd dir-to-import + touch foobar.c bar.c rootig.c defig.o envig.c optig.c + # We really should allow the files to be listed in any order. + # But we (kludgily) just list the orders which have been observed. + dotest 188a "${testcvs} import -m m -I optig.c first-dir tag1 tag2" \ + 'N first-dir/foobar.c +N first-dir/bar.c +I first-dir/rootig.c +I first-dir/defig.o +I first-dir/envig.c +I first-dir/optig.c + +No conflicts created by this import' 'I first-dir/defig.o +I first-dir/envig.c +I first-dir/optig.c +N first-dir/foobar.c +N first-dir/bar.c +I first-dir/rootig.c + +No conflicts created by this import' + dotest 188b "${testcvs} import -m m -I ! second-dir tag3 tag4" \ + 'N second-dir/foobar.c +N second-dir/bar.c +N second-dir/rootig.c +N second-dir/defig.o +N second-dir/envig.c +N second-dir/optig.c + +No conflicts created by this import' + cd .. + rm -rf dir-to-import + + dotest 189a "${testcvs} -q co second-dir" \ +'U second-dir/bar.c +U second-dir/defig.o +U second-dir/envig.c +U second-dir/foobar.c +U second-dir/optig.c +U second-dir/rootig.c' + rm -rf second-dir + dotest 189b "${testcvs} -q co first-dir" 'U first-dir/bar.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' + # 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' + cd .. + rm -rf first-dir + + rm -rf ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/second-dir + ;; + + binfiles) + # Test cvs's ability to handle binary files. + mkdir ${CVSROOT_DIRNAME}/first-dir + mkdir 1; cd 1 + dotest binfiles-1 "${testcvs} -q co first-dir" '' + awk 'BEGIN { printf "%c%c%c%c%c%c", 2, 10, 137, 0, 13, 10 }' \ + binfile.dat + cat binfile.dat binfile.dat >binfile2.dat + cd first-dir + cp ../binfile.dat binfile + dotest binfiles-2 "${testcvs} add -kb binfile" \ +'cvs [a-z]*: scheduling file `binfile'\'' for addition +cvs [a-z]*: use '\''cvs commit'\'' to add this file permanently' + dotest binfiles-3 "${testcvs} -q ci -m add-it" \ +'RCS file: /tmp/cvs-sanity/cvsroot/first-dir/binfile,v +done +Checking in binfile; +/tmp/cvs-sanity/cvsroot/first-dir/binfile,v <-- binfile +initial revision: 1.1 +done' + cd ../.. + mkdir 2; cd 2 + dotest binfiles-4 "${testcvs} -q co first-dir" 'U first-dir/binfile' + cd first-dir + dotest binfiles-5 "cmp ../../1/binfile.dat binfile" '' + cp ../../1/binfile2.dat binfile + dotest binfiles-6 "${testcvs} -q ci -m modify-it" \ +'Checking in binfile; +/tmp/cvs-sanity/cvsroot/first-dir/binfile,v <-- binfile +new revision: 1.2; previous revision: 1.1 +done' + cd ../../1/first-dir + dotest binfiles-7 "${testcvs} -q update" '[UP] binfile' + dotest binfiles-8 "cmp ../binfile2.dat binfile" '' + + cd ../.. + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -r 1 2 + ;; + *) + echo $what is not the name of a test -- ignored + ;; esac done -echo Ok. +echo "OK, all tests completed." # TODO: # * Test `cvs admin'. @@ -1479,7 +2310,6 @@ echo Ok. # * Test `cvs update foo bar' (where foo and bar are both from the same # repository). Suppose one is a branch--make sure that both directories # get updated with the respective correct thing. -# * Zero length files (check in, check out). # * `cvs update ../foo'. Also ../../foo ./../foo foo/../../bar /foo/bar # foo/.././../bar foo/../bar etc. # * Test all flags in modules file. @@ -1497,6 +2327,11 @@ echo Ok. # gives an appropriate error (e.g. # Cannot access /tmp/cvs-sanity/non-existent/CVSROOT # No such file or directory). +# * Test "cvs watch add", "cvs watch remove", "cvs watchers", that +# notify script gets called where appropriate. +# * Test "cvs unedit" and that it really reverts a change. +# * Test that remote edit and/or unedit works when disconnected from +# server (e.g. set CVS_SERVER to "foobar"). # End of TODO list. # Remove the test directory, but first change out of it. diff --git a/gnu/usr.bin/cvs/src/scramble.c b/gnu/usr.bin/cvs/src/scramble.c new file mode 100644 index 00000000000..4bf92447366 --- /dev/null +++ b/gnu/usr.bin/cvs/src/scramble.c @@ -0,0 +1,245 @@ +/* + * Trivially encode strings to protect them from innocent eyes (i.e., + * inadvertent password compromises, like a network administrator + * who's watching packets for legitimate reasons and accidentally sees + * the password protocol go by). + * + * This is NOT secure encryption. + * + * It would be tempting to encode the password according to username + * and repository, so that the same password would encode to a + * different string when used with different usernames and/or + * repositories. However, then users would not be able to cut and + * paste passwords around. They're not supposed to anyway, but we all + * know they will, and there's no reason to make it harder for them if + * we're not trying to provide real security anyway. + */ + +/* Set this to test as a standalone program. */ +/* #define DIAGNOSTIC */ + +#ifndef DIAGNOSTIC +#include "cvs.h" +#else /* ! DIAGNOSTIC */ +/* cvs.h won't define this for us */ +#define AUTH_CLIENT_SUPPORT +#define xmalloc malloc +/* Use "gcc -fwritable-strings". */ +#include +#include +#include +#endif /* ! DIAGNOSTIC */ + +#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT) + +/* Map characters to each other randomly and symmetrically, A <--> B. + * + * We divide the ASCII character set into 3 domains: control chars (0 + * thru 31), printing chars (32 through 126), and "meta"-chars (127 + * through 255). The control chars map _to_ themselves, the printing + * chars map _among_ themselves, and the meta chars map _among_ + * themselves. Why is this thus? + * + * No character in any of these domains maps to a character in another + * domain, because I'm not sure what characters are legal in + * passwords, or what tools people are likely to use to cut and paste + * them. It seems prudent not to introduce control or meta chars, + * unless the user introduced them first. And having the control + * chars all map to themselves insures that newline and + * carriage-return are safely handled. + */ + +static char +shifts[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, +17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 114, 120, +53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, 111, 52, +75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, 41, 57, +83, 43, 46, 102, 40, 89, 38, 103, 45, 50, 42, 123, 91, 35, 125, 55, +54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, 36, 121, +117, 104, 101, 100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 58, 113, +32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223, 225, 216, +187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, +199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203, +226, 193, 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238, +161, 179, 160, 212, 207, 221, 254, 173, 202, 146, 224, 151, 140, 196, +205, 130, 135, 133, 143, 246, 192, 159, 244, 239, 185, 168, 215, 144, +139, 165, 180, 157, 147, 186, 214, 176, 227, 231, 219, 169, 175, 156, +206, 198, 129, 164, 150, 210, 154, 177, 134, 127, 182, 128, 158, 208, +162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195, 243, 233, +253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152 }; + + +/* SCRAMBLE and DESCRAMBLE work like this: + * + * scramble(STR) returns SCRM, a scrambled copy of STR. SCRM[0] is a + * single letter indicating the scrambling method. As of this + * writing, the only legal method is 'A', but check the code for more + * up-to-date information. The copy will have been allocated with + * malloc(). + * + * descramble(SCRM) returns STR, again in its own malloc'd space. + * descramble() uses SCRM[0] to determine which method of unscrambling + * to use. If it does not recognize the method, it dies with error. + */ + +/* Return a malloc'd, scrambled version of STR. */ +char * +scramble (str) + char *str; +{ + int i; + char *s; + + /* +2 to hold the 'A' prefix that indicates which version of + * scrambling this is (the first, obviously, since we only do one + * kind of scrambling so far), and then the '\0' of course. + */ + s = xmalloc (strlen (str) + 2); + + s[0] = 'A'; /* Scramble (TM) version prefix. */ + strcpy (s + 1, str); + + for (i = 1; s[i]; i++) + s[i] = shifts[(s[i])]; + + return s; +} + +/* Decode the string in place. */ +char * +descramble (str) + char *str; +{ + char *s, *ret; + + /* For now we can only handle one kind of scrambling. In the future + * there may be other kinds, and this `if' will become a `switch'. + */ + if (str[0] != 'A') +#ifndef DIAGNOSTIC + error (1, 0, "descramble: unknown scrambling method"); +#else /* DIAGNOSTIC */ + { + fprintf (stderr, "descramble: unknown scrambling method\n", str); + fflush (stderr); + exit (1); + } +#endif /* DIAGNOSTIC */ + + /* Method `A' is symmetrical, so scramble again to decrypt. */ + s = scramble (str + 1); + + /* Make sure the string we return can be free()'d! */ + ret = xmalloc (strlen (s)); + strcpy (ret, s + 1); /* scoot past the 'A' */ + free (s); + + return ret; +} + +#endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */ + +#ifdef DIAGNOSTIC +int +main () +{ + int i; + char *e, *m, biggie[256]; + + char *cleartexts[5]; + cleartexts[0] = "first"; + cleartexts[1] = "the second"; + cleartexts[2] = "this is the third"; + cleartexts[3] = "$#% !!\\3"; + cleartexts[4] = biggie; + + /* Set up the most important test string: */ + /* Can't have a real ASCII zero in the string, because we want to + use printf, so we substitute the character zero. */ + biggie[0] = '0'; + /* The rest of the string gets straight ascending ASCII. */ + for (i = 1; i < 256; i++) + biggie[i] = i; + + /* Test all the strings. */ + for (i = 0; i < 5; i++) + { + printf ("clear%d: %s\n", i, cleartexts[i]); + e = scramble (cleartexts[i]); + printf ("scram%d: %s\n", i, e); + m = descramble (e); + free (e); + printf ("clear%d: %s\n\n", i, m); + free (m); + } + + fflush (stdout); + return 0; +} +#endif /* DIAGNOSTIC */ + +/* + * ;;; The Emacs Lisp that did the dirty work ;;; + * (progn + * + * ;; Helper func. + * (defun random-elt (lst) + * (let* ((len (length lst)) + * (rnd (random len))) + * (nth rnd lst))) + * + * ;; A list of all characters under 127, each appearing once. + * (setq non-meta-chars + * (let ((i 0) + * (l nil)) + * (while (< i 127) + * (setq l (cons i l) + * i (1+ i))) + * l)) + * + * ;; A list of all characters 127 and above, each appearing once. + * (setq meta-chars + * (let ((i 127) + * (l nil)) + * (while (< i 256) + * (setq l (cons i l) + * i (1+ i))) + * l)) + * + * ;; A vector that will hold the chars in a random order. + * (setq scrambled-chars (make-vector 256 0)) + * + * ;; These characters should map to themselves. + * (let ((i 0)) + * (while (< i 32) + * (aset scrambled-chars i i) + * (setq non-meta-chars (delete i non-meta-chars) + * i (1+ i)))) + * + * ;; Assign random (but unique) values, within the non-meta chars. + * (let ((i 32)) + * (while (< i 127) + * (let ((ch (random-elt non-meta-chars))) + * (if (= 0 (aref scrambled-chars i)) + * (progn + * (aset scrambled-chars i ch) + * (aset scrambled-chars ch i) + * (setq non-meta-chars (delete ch non-meta-chars) + * non-meta-chars (delete i non-meta-chars)))) + * (setq i (1+ i))))) + * + * ;; Assign random (but unique) values, within the non-meta chars. + * (let ((i 127)) + * (while (< i 256) + * (let ((ch (random-elt meta-chars))) + * (if (= 0 (aref scrambled-chars i)) + * (progn + * (aset scrambled-chars i ch) + * (aset scrambled-chars ch i) + * (setq meta-chars (delete ch meta-chars) + * meta-chars (delete i meta-chars)))) + * (setq i (1+ i))))) + * + * ;; Now use the `scrambled-chars' vector to get your C array. + * ) + */ diff --git a/gnu/usr.bin/cvs/src/server.h b/gnu/usr.bin/cvs/src/server.h index d0560be7661..cb49267e991 100644 --- a/gnu/usr.bin/cvs/src/server.h +++ b/gnu/usr.bin/cvs/src/server.h @@ -79,6 +79,12 @@ extern void server_update_entries enum progs {PROG_CHECKIN, PROG_UPDATE}; extern void server_prog PROTO((char *, char *, enum progs)); +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)); +#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 d987a91ac8c..eb12fe9f7a4 100644 --- a/gnu/usr.bin/cvs/src/status.c +++ b/gnu/usr.bin/cvs/src/status.c @@ -82,12 +82,12 @@ status (argc, argv) if (local) send_arg("-l"); + send_file_names (argc, argv); /* XXX This should only need to send file info; the file contents themselves will not be examined. */ send_files (argc, argv, local, 0); - if (fprintf (to_server, "status\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("status\012", 0); err = get_responses_and_close (); return err; @@ -95,8 +95,8 @@ status (argc, argv) #endif /* start the recursion processor */ - err = start_recursion (status_fileproc, (int (*) ()) NULL, status_dirproc, - (int (*) ()) NULL, argc, argv, local, + err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, status_dirproc, + (DIRLEAVEPROC) NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, 1, 0); return (err); diff --git a/gnu/usr.bin/cvs/src/subr.c b/gnu/usr.bin/cvs/src/subr.c index b94fc8abfa5..228581c5b1e 100644 --- a/gnu/usr.bin/cvs/src/subr.c +++ b/gnu/usr.bin/cvs/src/subr.c @@ -76,6 +76,18 @@ xstrdup (str) return (s); } +/* Remove trailing newlines from STRING, destructively. */ +void +strip_trailing_newlines (str) + char *str; +{ + int len; + len = strlen (str) - 1; + + while (str[len] == '\n') + str[len--] = '\0'; +} + /* * Recover the space allocated by Find_Names() and line2argv() */ @@ -148,8 +160,8 @@ getcaller () if (uid == (uid_t) 0) { /* super-user; try getlogin() to distinguish */ - if (((name = getenv("LOGNAME")) || (name = getenv("USER")) || - (name = getlogin ())) && *name) + if (((name = getlogin ()) || (name = getenv("LOGNAME")) || + (name = getenv("USER"))) && *name) return (name); } if ((pw = (struct passwd *) getpwuid (uid)) == NULL) diff --git a/gnu/usr.bin/cvs/src/tag.c b/gnu/usr.bin/cvs/src/tag.c index a2544afd8d5..21da5f4d733 100644 --- a/gnu/usr.bin/cvs/src/tag.c +++ b/gnu/usr.bin/cvs/src/tag.c @@ -12,6 +12,7 @@ */ #include "cvs.h" +#include "save-cwd.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)tag.c 1.60 94/09/30 $"; @@ -59,7 +60,7 @@ static List *tlist; static const char *const tag_usage[] = { - "Usage: %s %s [-lRF] [-b] [-d] tag [files...]\n", + "Usage: %s %s [-lRF] [-b] [-d] [-r tag|-D date] tag [files...]\n", "\t-l\tLocal directory only, not recursive.\n", "\t-R\tProcess directories recursively.\n", "\t-d\tDelete the given Tag.\n", @@ -138,6 +139,8 @@ tag (argc, argv) argc--; argv++; + if (date && numtag) + error (1, 0, "-r and -D options are mutually exclusive"); if (delete && branch_mode) error (0, 0, "warning: -b ignored with -d options"); RCS_check_tag (symtag); @@ -159,28 +162,32 @@ tag (argc, argv) if (force_tag_move) send_arg("-F"); + if (numtag) + option_with_arg ("-r", numtag); + if (date) + client_senddate (date); + send_arg (symtag); -#if 0 + send_file_names (argc, argv); /* 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_file_names (argc, argv); -#else send_files (argc, argv, local, 0); -#endif - if (fprintf (to_server, "tag\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("tag\012", 0); return get_responses_and_close (); } #endif + if (numtag != NULL) + tag_check_valid (numtag, argc, argv, local, 0, ""); + /* check to make sure they are authorized to tag all the specified files in the repository */ mtlist = getlist(); err = start_recursion (check_fileproc, check_filesdoneproc, - (Dtype (*) ()) NULL, (int (*) ()) NULL, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, 1, 0); @@ -190,8 +197,8 @@ tag (argc, argv) } /* start the recursion processor */ - err = start_recursion (tag_fileproc, (int (*) ()) NULL, tag_dirproc, - (int (*) ()) NULL, argc, argv, local, + err = start_recursion (tag_fileproc, (FILESDONEPROC) NULL, tag_dirproc, + (DIRLEAVEPROC) NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, 1, 0); dellist(&mtlist); return (err); @@ -242,13 +249,13 @@ check_fileproc(file, update_dir, repository, entries, srcfiles) p->delproc = tag_delproc; vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, file, 0, 0, entries, srcfiles); - p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match); + p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, 0); if (p->data != NULL) { int addit = 1; char *oversion; - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1); + oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); if (oversion == NULL) { if (delete) @@ -409,7 +416,7 @@ tag_fileproc (file, update_dir, repository, entries, srcfiles) nversion = RCS_getversion(vers->srcfile, numtag, date, - force_tag_match); + force_tag_match, 0); if (nversion == NULL) { freevers_ts (&vers); @@ -428,7 +435,7 @@ tag_fileproc (file, update_dir, repository, entries, srcfiles) * "rcs" to remove the tag... trust me. */ - version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1); + version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); if (version == NULL || vers->srcfile == NULL) { freevers_ts (&vers); @@ -507,7 +514,7 @@ tag_fileproc (file, update_dir, repository, entries, srcfiles) * module -- which I have found to be a typical tagging operation. */ rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version; - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1); + oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); if (oversion != NULL) { int isbranch = RCS_isbranch (file, symtag, srcfiles); @@ -580,3 +587,215 @@ tag_dirproc (dir, repos, update_dir) error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir); return (R_PROCESS); } + +/* Code relating to the val-tags file. Note that this file has no way + of knowing when a tag has been deleted. The problem is that there + is no way of knowing whether a tag still exists somewhere, when we + delete it some places. Using per-directory val-tags files (in + CVSREP) might be better, but that might slow down the process of + verifying that a tag is correct (maybe not, for the likely cases, + if carefully done), and/or be harder to implement correctly. */ + +struct val_args { + char *name; + int found; +}; + +/* Pass as a static until we get around to fixing start_recursion to pass along + a void * where we can stash it. */ +static struct val_args *val_args_static; + +static int val_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +val_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + RCSNode *rcsdata; + Node *node; + struct val_args *args = val_args_static; + + node = findnode (srcfiles, file); + if (node == NULL) + /* Not sure this can happen, after all we passed only + W_REPOS | W_ATTIC. */ + return 0; + rcsdata = (RCSNode *) node->data; + if (RCS_gettag (rcsdata, args->name, 1, 0) != NULL) + { + /* FIXME: should find out a way to stop the search at this point. */ + args->found = 1; + } + return 0; +} + +static Dtype val_direntproc PROTO ((char *, char *, char *)); + +static Dtype +val_direntproc (dir, repository, update_dir) + char *dir; + char *repository; + char *update_dir; +{ + /* This is not quite right--it doesn't get right the case of "cvs + update -d -r foobar" where foobar is a tag which exists only in + files in a directory which does not exist yet, but which is + about to be created. */ + if (isdir (dir)) + return 0; + return R_SKIP_ALL; +} + +/* Check to see whether NAME is a valid tag. If so, return. If not + print an error message and exit. ARGC, ARGV, LOCAL, and AFLAG specify + which files we will be operating on. + + REPOSITORY is the repository if we need to cd into it, or NULL if + we are already there, or "" if we should do a W_LOCAL recursion. + Sorry for three cases, but the "" case is needed in case the + working directories come from diverse parts of the repository, the + NULL case avoids an unneccesary chdir, and the non-NULL, non-"" + case is needed for checkout, where we don't want to chdir if the + tag is found in CVSROOTADM_VALTAGS, but there is not (yet) any + local directory. */ +void +tag_check_valid (name, argc, argv, local, aflag, repository) + char *name; + int argc; + char **argv; + int local; + int aflag; + char *repository; +{ + DBM *db; + char *valtags_filename; + int err; + datum mytag; + struct val_args the_val_args; + struct saved_cwd cwd; + int which; + + /* Numeric tags require only a syntactic check. */ + if (isdigit (name[0])) + { + char *p; + for (p = name; *p != '\0'; ++p) + { + if (!(isdigit (*p) || *p == '.')) + error (1, 0, "\ +Numeric tag %s contains characters other than digits and '.'", name); + } + return; + } + + mytag.dptr = name; + mytag.dsize = strlen (name); + + valtags_filename = xmalloc (strlen (CVSroot) + sizeof CVSROOTADM + + sizeof CVSROOTADM_HISTORY + 20); + strcpy (valtags_filename, CVSroot); + strcat (valtags_filename, "/"); + strcat (valtags_filename, CVSROOTADM); + strcat (valtags_filename, "/"); + strcat (valtags_filename, CVSROOTADM_VALTAGS); + db = dbm_open (valtags_filename, O_RDWR, 0666); + if (db == NULL) + { + if (!existence_error (errno)) + error (1, errno, "cannot read %s", valtags_filename); + + /* If the file merely fails to exist, we just keep going and create + it later if need be. */ + } + else + { + datum val; + + val = dbm_fetch (db, mytag); + if (val.dptr != NULL) + { + /* Found. The tag is valid. */ + dbm_close (db); + free (valtags_filename); + return; + } + /* FIXME: should check errors somehow (add dbm_error to myndbm.c?). */ + } + + /* We didn't find the tag in val-tags, so look through all the RCS files + to see whether it exists there. Yes, this is expensive, but there + is no other way to cope with a tag which might have been created + by an old version of CVS, from before val-tags was invented. */ + + the_val_args.name = name; + the_val_args.found = 0; + val_args_static = &the_val_args; + + which = W_REPOS | W_ATTIC; + + if (repository != NULL) + { + if (repository[0] == '\0') + which |= W_LOCAL; + else + { + if (save_cwd (&cwd)) + exit (1); + if (chdir (repository) < 0) + error (1, errno, "cannot change to %s directory", repository); + } + } + + err = start_recursion (val_fileproc, (FILESDONEPROC) NULL, + val_direntproc, (DIRLEAVEPROC) NULL, + argc, argv, local, which, aflag, + 1, NULL, 1, 0); + if (repository != NULL && repository[0] != '\0') + { + if (restore_cwd (&cwd, NULL)) + exit (1); + free_cwd (&cwd); + } + + if (!the_val_args.found) + error (1, 0, "no such tag %s", name); + else + { + /* The tags is valid but not mentioned in val-tags. Add it. */ + datum value; + + if (noexec) + { + if (db != NULL) + dbm_close (db); + free (valtags_filename); + return; + } + + if (db == NULL) + { + mode_t omask; + omask = umask (cvsumask); + db = dbm_open (valtags_filename, O_RDWR | O_CREAT | O_TRUNC, 0666); + (void) umask (omask); + + if (db == NULL) + { + error (0, errno, "cannot create %s", valtags_filename); + free (valtags_filename); + return; + } + } + value.dptr = "y"; + value.dsize = 1; + if (dbm_store (db, mytag, value, DBM_REPLACE) < 0) + error (0, errno, "cannot store %s into %s", name, + valtags_filename); + dbm_close (db); + } + free (valtags_filename); +} diff --git a/gnu/usr.bin/cvs/src/update.c b/gnu/usr.bin/cvs/src/update.c index 0e01faeda74..cae9cb32690 100644 --- a/gnu/usr.bin/cvs/src/update.c +++ b/gnu/usr.bin/cvs/src/update.c @@ -34,12 +34,12 @@ */ #include "cvs.h" -#ifdef CLIENT_SUPPORT -#include "update.h" -#endif #ifdef SERVER_SUPPORT #include "md5.h" #endif +#include "watch.h" +#include "fileattr.h" +#include "edit.h" #ifndef lint static const char rcsid[] = "$CVSid: @(#)update.c 1.95 94/10/22 $"; @@ -63,11 +63,9 @@ static Dtype update_dirent_proc PROTO((char *dir, char *repository, char *update static int update_dirleave_proc PROTO((char *dir, int err, char *update_dir)); static int update_file_proc PROTO((char *file, char *update_dir, char *repository, List * entries, List * srcfiles)); -#ifndef CLIENT_SUPPORT -static int update_filesdone_proc PROTO((int err, char *repository, char *update_dir)); -#endif +static int update_filesdone_proc PROTO((int err, char *repository, + char *update_dir)); static int write_letter PROTO((char *file, int letter, char *update_dir)); -static void ignore_files PROTO((List * ilist, char *update_dir)); #ifdef SERVER_SUPPORT static void join_file PROTO((char *file, List *srcfiles, Vers_TS *vers_ts, char *update_dir, List *entries, char *repository)); @@ -89,11 +87,7 @@ static int pipeout = 0; #ifdef SERVER_SUPPORT static int patches = 0; #endif -#ifdef CLIENT_SUPPORT -List *ignlist = (List *) NULL; -#else static List *ignlist = (List *) NULL; -#endif static time_t last_register_time; static const char *const update_usage[] = { @@ -226,8 +220,6 @@ update (argc, argv) start_server (); - ign_setup (); - if (local) send_arg("-l"); if (update_build_dirs) @@ -270,7 +262,10 @@ update (argc, argv) } if (failed_patches == NULL) + { + send_file_names (argc, argv); send_files (argc, argv, local, aflag); + } else { int i; @@ -286,6 +281,7 @@ update (argc, argv) for (i = 0; i < failed_patches_count; i++) (void) unlink_file (failed_patches[i]); + send_file_names (failed_patches_count, failed_patches); send_files (failed_patches_count, failed_patches, local, aflag); } @@ -293,8 +289,7 @@ update (argc, argv) failed_patches = NULL; failed_patches_count = 0; - if (fprintf (to_server, "update\n") < 0) - error (1, errno, "writing to server"); + send_to_server ("update\012", 0); status = get_responses_and_close (); if (status != 0) @@ -306,6 +301,11 @@ update (argc, argv) } #endif + if (tag != NULL) + tag_check_valid (tag, argc, argv, local, aflag, ""); + /* FIXME: We don't call tag_check_valid on join_rev1 and join_rev2 + yet (make sure to handle ':' correctly if we do, though). */ + /* * If we are updating the entire directory (for real) and building dirs * as we go, we make sure there is no static entries file and write the @@ -315,7 +315,7 @@ update (argc, argv) { if (update_build_dirs) { - if (unlink_file (CVSADM_ENTSTAT) < 0 && errno != ENOENT) + if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); #ifdef SERVER_SUPPORT if (server_active) @@ -552,10 +552,10 @@ update_file_proc (file, update_dir, repository, entries, srcfiles) * If the timestamps differ, look for Conflict * indicators to see if 'C' anyway. */ - run_setup ("%s -s", GREP); + run_setup ("%s", GREP); run_arg (RCS_MERGE_PAT); run_arg (file); - retcode = run_exec (RUN_TTY, RUN_TTY, + retcode = run_exec (RUN_TTY, DEVNULL, RUN_TTY,RUN_NORMAL); if (retcode == -1) { @@ -668,16 +668,18 @@ update_file_proc (file, update_dir, repository, entries, srcfiles) return (retval); } -/* - * update_filesdone_proc () is used - */ +static void update_ignproc PROTO ((char *, char *)); + +static void +update_ignproc (file, dir) + char *file; + char *dir; +{ + (void) write_letter (file, '?', dir); +} + /* ARGSUSED */ -#ifdef CLIENT_SUPPORT -/* Also used by client.c */ -int -#else static int -#endif update_filesdone_proc (err, repository, update_dir) int err; char *repository; @@ -686,19 +688,12 @@ update_filesdone_proc (err, repository, update_dir) /* if this directory has an ignore list, process it then free it */ if (ignlist) { - ignore_files (ignlist, update_dir); + ignore_files (ignlist, update_dir, update_ignproc); dellist (&ignlist); } /* Clean up CVS admin dirs if we are export */ -#ifdef CLIENT_SUPPORT - /* In the client, we need to clean these up after we create them. Doing - it here might would clean up the user's previous contents even on - SIGINT which probably is bad. */ - if (!client_active && strcmp (command_name, "export") == 0) -#else if (strcmp (command_name, "export") == 0) -#endif { run_setup ("%s -fr", RM); run_arg (CVSADM); @@ -712,14 +707,7 @@ update_filesdone_proc (err, repository, update_dir) #endif /* SERVER_SUPPORT */ { /* If there is no CVS/Root file, add one */ -#ifdef CLIENT_SUPPORT - if (!isfile (CVSADM_ROOT) - /* but only if we want it */ - && ! (getenv ("CVS_IGNORE_REMOTE_ROOT") && strchr (CVSroot, ':')) - ) -#else /* No CLIENT_SUPPORT */ if (!isfile (CVSADM_ROOT)) -#endif /* No CLIENT_SUPPORT */ Create_Root( (char *) NULL, CVSroot ); } #endif /* CVSADM_ROOT */ @@ -780,7 +768,7 @@ update_dirent_proc (dir, repository, update_dir) char tmp[PATH_MAX]; (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT); - if (unlink_file (tmp) < 0 && errno != ENOENT) + if (unlink_file (tmp) < 0 && ! existence_error (errno)) error (1, errno, "cannot remove file %s", tmp); #ifdef SERVER_SUPPORT if (server_active) @@ -846,6 +834,7 @@ update_dirleave_proc (dir, err, update_dir) free (repository); } + /* FIXME: chdir ("..") loses with symlinks. */ /* Prune empty dirs on the way out - if necessary */ (void) chdir (".."); if (update_prune_dirs && isemptydir (dir)) @@ -938,7 +927,7 @@ checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir) if (!file_is_dead) { #endif - run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_rcs, + run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_tag, vers_ts->options); /* @@ -985,31 +974,65 @@ checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir) if (file_is_dead && joining()) { - /* when joining, we need to get dead files checked - out. Try harder. */ - run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_rcs, - vers_ts->options); - - run_arg ("-f"); - run_arg (vers_ts->srcfile->path); - run_arg (file); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) + if (RCS_getversion (vers_ts->srcfile, join_rev1, + date_rev1, 1, 0) + || (join_rev2 != NULL && + RCS_getversion (vers_ts->srcfile, join_rev2, + date_rev2, 1, 0))) { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not check out %s", file); - (void) unlink_file (backup); - return (retcode); + /* when joining, we need to get dead files checked + out. Try harder. */ + run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, + vers_ts->vn_rcs, + vers_ts->options); + + run_arg ("-f"); + run_arg (vers_ts->srcfile->path); + run_arg (file); + retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); + if (retcode != 0) + { + error (retcode == -1 ? 1 : 0, + retcode == -1 ? errno : 0, + "could not check out %s", file); + (void) unlink_file (backup); + return (retcode); + } + file_is_dead = 0; + resurrecting = 1; + } + else + { + /* If the file is dead and does not contain either of + the join revisions, then we don't want to check it + out. */ + return 0; } - file_is_dead = 0; - resurrecting = 1; } +#endif /* DEATH_SUPPORT */ - if (cvswrite == TRUE && !file_is_dead) - xchmod (file, 1); -#else /* No DEATH_SUPPORT */ - if (cvswrite == TRUE) + if (cvswrite == TRUE +#ifdef DEATH_SUPPORT + && !file_is_dead +#endif + && !fileattr_get (file, "_watched")) xchmod (file, 1); -#endif /* No DEATH_SUPPORT */ + + { + /* A newly checked out file is never under the spell + of "cvs edit". If we think we were editing it + from a previous life, clean up. Would be better to + check for same the working directory instead of + same user, but that is hairy. */ + + struct addremove_args args; + + editor_set (file, getcaller (), NULL); + + memset (&args, 0, sizeof args); + args.remove_temp = 1; + watch_modify_watchers (file, &args); + } /* set the time from the RCS file iff it was unknown before */ if (vers_ts->vn_user == NULL || @@ -1026,6 +1049,20 @@ checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir) force_tag_match, set_time, entries, srcfiles); if (strcmp (xvers_ts->options, "-V4") == 0) xvers_ts->options[0] = '\0'; + /* If no keyword expansion was specified on command line, + use whatever was in the file. This is how we tell the client + whether a file is binary. */ + if (xvers_ts->options[0] == '\0') + { + if (vers_ts->srcfile->expand != NULL) + { + free (xvers_ts->options); + xvers_ts->options = + xmalloc (strlen (vers_ts->srcfile->expand) + 3); + strcpy (xvers_ts->options, "-k"); + strcat (xvers_ts->options, vers_ts->srcfile->expand); + } + } (void) time (&last_register_time); @@ -1044,7 +1081,7 @@ checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir) update_dir, file); } Scratch_Entry (entries, file); - if (unlink_file (file) < 0 && errno != ENOENT) + if (unlink_file (file) < 0 && ! existence_error (errno)) { if (update_dir[0] == '\0') error (0, errno, "cannot remove %s", file); @@ -1203,7 +1240,8 @@ patch_file (file, repository, entries, srcfiles, vers_ts, update_dir, else { rename_file (file, file2); - if (cvswrite == TRUE) + if (cvswrite == TRUE + && !fileattr_get (file, "_watched")) xchmod (file2, 1); e = fopen (file2, "r"); if (e == NULL) @@ -1544,9 +1582,20 @@ join_file (file, srcfiles, vers, update_dir, entries) return; } + /* Fix for bug CVS/193: + * Used to dump core if the file had been removed on the current branch. + */ + if (strcmp(vers->vn_user, "0") == 0) + { + error(0, 0, + "file %s has been deleted", + file); + return; + } + /* convert the second rev spec, walking branches and dates. */ - rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1); + rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, 0); if (rev2 == NULL) { if (!quiet) @@ -1598,7 +1647,7 @@ join_file (file, srcfiles, vers, update_dir, entries) abort(); } - tst = RCS_gettag (vers->srcfile, rev2, 1); + tst = RCS_gettag (vers->srcfile, rev2, 1, 0); if (tst == NULL) { /* this should not be possible. */ @@ -1621,7 +1670,7 @@ join_file (file, srcfiles, vers, update_dir, entries) /* otherwise, convert the first rev spec, walking branches and dates. */ - rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1); + rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, 0); if (rev1 == NULL) { if (!quiet) { @@ -1645,7 +1694,7 @@ join_file (file, srcfiles, vers, update_dir, entries) /* special handling when two revisions are specified */ if (join_rev1 && join_rev2) { - rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1); + rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1, 0); if (rev == NULL) { if (!quiet && date_rev2 == NULL) @@ -1654,7 +1703,7 @@ join_file (file, srcfiles, vers, update_dir, entries) return; } - baserev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1); + baserev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0); if (baserev == NULL) { if (!quiet && date_rev1 == NULL) @@ -1682,7 +1731,7 @@ join_file (file, srcfiles, vers, update_dir, entries) } else { - rev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1); + rev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0); if (rev == NULL) return; if (strcmp (rev, vers->vn_user) == 0) /* no merge necessary */ @@ -1769,7 +1818,17 @@ join_file (file, srcfiles, vers, update_dir, entries) free (rev1); free (rev2); +#ifdef SERVER_SUPPORT + /* + * If we're in server mode, then we need to re-register the file + * even if there were no conflicts (status == 0). + * This tells server_updated() to send the modified file back to + * the client. + */ + if (status == 1 || (status == 0 && server_active)) +#else if (status == 1) +#endif { char *cp = 0; @@ -1791,80 +1850,6 @@ join_file (file, srcfiles, vers, update_dir, entries) #endif } -/* - * Process the current directory, looking for files not in ILIST and not on - * the global ignore list for this directory. - */ -static void -ignore_files (ilist, update_dir) - List *ilist; - char *update_dir; -{ - DIR *dirp; - struct dirent *dp; - struct stat sb; - char *file; - char *xdir; - - /* we get called with update_dir set to "." sometimes... strip it */ - if (strcmp (update_dir, ".") == 0) - xdir = ""; - else - xdir = update_dir; - - dirp = opendir ("."); - if (dirp == NULL) - return; - - ign_add_file (CVSDOTIGNORE, 1); - wrap_add_file (CVSDOTWRAPPER, 1); - - while ((dp = readdir (dirp)) != NULL) - { - file = dp->d_name; - if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0) - continue; - if (findnode (ilist, file) != NULL) - continue; - - if ( -#ifdef DT_DIR - dp->d_type != DT_UNKNOWN || -#endif - lstat(file, &sb) != -1) - { - - if ( -#ifdef DT_DIR - dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN && -#endif - S_ISDIR(sb.st_mode)) - { - char temp[PATH_MAX]; - - (void) sprintf (temp, "%s/%s", file, CVSADM); - if (isdir (temp)) - continue; - } -#ifdef S_ISLNK - else if ( -#ifdef DT_DIR - dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && -#endif - S_ISLNK(sb.st_mode)) - { - continue; - } -#endif - } - - if (ign_name (file)) - continue; - (void) write_letter (file, '?', xdir); - } - (void) closedir (dirp); -} - int joining () { diff --git a/gnu/usr.bin/cvs/src/update.h b/gnu/usr.bin/cvs/src/update.h index 68c91d55ab9..bad6562fb02 100644 --- a/gnu/usr.bin/cvs/src/update.h +++ b/gnu/usr.bin/cvs/src/update.h @@ -1,9 +1,21 @@ -/* Definitions of routines shared between local and client/server - "update" code. */ +/* Declarations for update.c. -/* List of files that we have either processed or are willing to - ignore. Any file not on this list gets a question mark printed. */ -extern List *ignlist; + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. -extern int -update_filesdone_proc PROTO((int err, char *repository, char *update_dir)); + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +int do_update PROTO((int argc, char *argv[], char *xoptions, char *xtag, + char *xdate, int xforce, int local, int xbuild, + int xaflag, int xprune, int xpipeout, int which, + char *xjoin_rev1, char *xjoin_rev2, char *preload_update_dir)); +int joining PROTO((void)); diff --git a/gnu/usr.bin/cvs/src/vers_ts.c b/gnu/usr.bin/cvs/src/vers_ts.c index 2fc912521df..ebb7ca8d305 100644 --- a/gnu/usr.bin/cvs/src/vers_ts.c +++ b/gnu/usr.bin/cvs/src/vers_ts.c @@ -13,8 +13,6 @@ static const char rcsid[] = "$CVSid: @(#)vers_ts.c 1.45 94/10/07 $"; USE(rcsid); #endif -#define ctime(X) do not use ctime, please - #ifdef SERVER_SUPPORT static void time_stamp_server PROTO((char *, Vers_TS *)); #endif @@ -148,10 +146,28 @@ Version_TS (repository, options, tag, date, user, force_tag_match, { #endif if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0) + { vers_ts->vn_rcs = xstrdup (vers_ts->vn_user); + vers_ts->vn_tag = xstrdup (vers_ts->vn_user); + } else + { vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag, - vers_ts->date, force_tag_match); + vers_ts->date, force_tag_match, 1); + if (vers_ts->vn_rcs == NULL) + vers_ts->vn_tag = NULL; + else + { + char *colon = strchr (vers_ts->vn_rcs, ':'); + if (colon) + { + vers_ts->vn_tag = xstrdup (colon+1); + *colon = '\0'; + } + else + vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs); + } + } #ifndef DEATH_SUPPORT } #endif @@ -205,7 +221,7 @@ time_stamp_server (file, vers_ts) if (stat (file, &sb) < 0) { - if (errno != ENOENT) + if (! existence_error (errno)) error (1, errno, "cannot stat temp file"); if (use_unchanged) { @@ -291,6 +307,8 @@ freevers_ts (versp) free ((*versp)->vn_user); if ((*versp)->vn_rcs) free ((*versp)->vn_rcs); + if ((*versp)->vn_tag) + free ((*versp)->vn_tag); if ((*versp)->ts_user) free ((*versp)->ts_user); if ((*versp)->ts_rcs) diff --git a/gnu/usr.bin/cvs/src/version.c b/gnu/usr.bin/cvs/src/version.c index e01fb7aef50..e2ddd0fa331 100644 --- a/gnu/usr.bin/cvs/src/version.c +++ b/gnu/usr.bin/cvs/src/version.c @@ -17,7 +17,7 @@ static const char rcsid[] = "$CVSid: @(#)version.c 1.15 94/10/03 $"; USE(rcsid); #endif -char *version_string = "\nConcurrent Versions System (CVS) 1.6"; +char *version_string = "\nConcurrent Versions System (CVS) 1.7.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 new file mode 100644 index 00000000000..b84926fb429 --- /dev/null +++ b/gnu/usr.bin/cvs/src/watch.c @@ -0,0 +1,530 @@ +/* Implementation for "cvs watch add", "cvs watchers", and related commands + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "cvs.h" +#include "edit.h" +#include "fileattr.h" +#include "watch.h" + +const char *const watch_usage[] = +{ + "Usage: %s %s [on|off|add|remove] [-l] [-a action] [files...]\n", + "on/off: turn on/off read-only checkouts of files\n", + "add/remove: add or remove notification on actions\n", + "-l (on/off/add/remove): Local directory only, not recursive\n", + "-a (add/remove): Specify what actions, one of\n", + " edit,unedit,commit,all,none\n", + NULL +}; + +static struct addremove_args the_args; + +void +watch_modify_watchers (file, what) + char *file; + struct addremove_args *what; +{ + char *curattr = fileattr_get0 (file, "_watchers"); + char *p; + char *pend; + char *nextp; + char *who; + int who_len; + char *mycurattr; + char *mynewattr; + size_t mynewattr_size; + + int add_edit_pending; + int add_unedit_pending; + int add_commit_pending; + int remove_edit_pending; + int remove_unedit_pending; + int remove_commit_pending; + int add_tedit_pending; + int add_tunedit_pending; + int add_tcommit_pending; + + who = getcaller (); + who_len = strlen (who); + + /* Look for current watcher types for this user. */ + mycurattr = NULL; + if (curattr != NULL) + { + p = curattr; + while (1) { + if (strncmp (who, p, who_len) == 0 + && p[who_len] == '>') + { + /* Found this user. */ + mycurattr = p + who_len + 1; + } + p = strchr (p, ','); + if (p == NULL) + break; + ++p; + } + } + if (mycurattr != NULL) + { + mycurattr = xstrdup (mycurattr); + p = strchr (mycurattr, ','); + if (p != NULL) + *p = '\0'; + } + + /* Now copy mycurattr to mynewattr, making the requisite modifications. + Note that we add a dummy '+' to the start of mynewattr, to reduce + special cases (but then we strip it off when we are done). */ + + mynewattr_size = sizeof "+edit+unedit+commit+tedit+tunedit+tcommit"; + if (mycurattr != NULL) + mynewattr_size += strlen (mycurattr); + mynewattr = xmalloc (mynewattr_size); + mynewattr[0] = '\0'; + + add_edit_pending = what->adding && what->edit; + add_unedit_pending = what->adding && what->unedit; + add_commit_pending = what->adding && what->commit; + remove_edit_pending = !what->adding && what->edit; + remove_unedit_pending = !what->adding && what->unedit; + remove_commit_pending = !what->adding && what->commit; + add_tedit_pending = what->add_tedit; + add_tunedit_pending = what->add_tunedit; + add_tcommit_pending = what->add_tcommit; + + /* Copy over existing watch types, except those to be removed. */ + p = mycurattr; + while (p != NULL) + { + pend = strchr (p, '+'); + if (pend == NULL) + { + pend = p + strlen (p); + nextp = NULL; + } + else + nextp = pend + 1; + + /* Process this item. */ + if (pend - p == 4 && strncmp ("edit", p, 4) == 0) + { + if (!remove_edit_pending) + strcat (mynewattr, "+edit"); + add_edit_pending = 0; + } + else if (pend - p == 6 && strncmp ("unedit", p, 6) == 0) + { + if (!remove_unedit_pending) + strcat (mynewattr, "+unedit"); + add_unedit_pending = 0; + } + else if (pend - p == 6 && strncmp ("commit", p, 6) == 0) + { + if (!remove_commit_pending) + strcat (mynewattr, "+commit"); + add_commit_pending = 0; + } + else if (pend - p == 5 && strncmp ("tedit", p, 5) == 0) + { + if (!what->remove_temp) + strcat (mynewattr, "+tedit"); + add_tedit_pending = 0; + } + else if (pend - p == 7 && strncmp ("tunedit", p, 7) == 0) + { + if (!what->remove_temp) + strcat (mynewattr, "+tunedit"); + add_tunedit_pending = 0; + } + else if (pend - p == 7 && strncmp ("tcommit", p, 7) == 0) + { + if (!what->remove_temp) + strcat (mynewattr, "+tcommit"); + add_tcommit_pending = 0; + } + else + { + char *mp; + + /* Copy over any unrecognized watch types, for future + expansion. */ + mp = mynewattr + strlen (mynewattr); + *mp++ = '+'; + strncpy (mp, p, pend - p); + *(mp + (pend - p)) = '\0'; + } + + /* Set up for next item. */ + p = nextp; + } + + /* Add in new watch types. */ + if (add_edit_pending) + strcat (mynewattr, "+edit"); + if (add_unedit_pending) + strcat (mynewattr, "+unedit"); + if (add_commit_pending) + strcat (mynewattr, "+commit"); + if (add_tedit_pending) + strcat (mynewattr, "+tedit"); + if (add_tunedit_pending) + strcat (mynewattr, "+tunedit"); + if (add_tcommit_pending) + strcat (mynewattr, "+tcommit"); + + { + char *curattr_new; + + curattr_new = + fileattr_modify (curattr, + who, + mynewattr[0] == '\0' ? NULL : mynewattr + 1, + '>', + ','); + /* If the attribute is unchanged, don't rewrite the attribute file. */ + if (!((curattr_new == NULL && curattr == NULL) + || (curattr_new != NULL + && curattr != NULL + && strcmp (curattr_new, curattr) == 0))) + fileattr_set (file, + "_watchers", + curattr_new); + if (curattr_new != NULL) + free (curattr_new); + } + + if (curattr != NULL) + free (curattr); + if (mycurattr != NULL) + free (mycurattr); +} + +static int addremove_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +addremove_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + watch_modify_watchers (file, &the_args); + return 0; +} + +static int addremove_filesdoneproc PROTO ((int, char *, char *)); + +static int +addremove_filesdoneproc (err, repository, update_dir) + int err; + char *repository; + char *update_dir; +{ + if (the_args.setting_default) + watch_modify_watchers (NULL, &the_args); + return err; +} + +static int watch_addremove PROTO ((int argc, char **argv)); + +static int +watch_addremove (argc, argv) + int argc; + char **argv; +{ + int c; + int local = 0; + int err; + int a_omitted; + + a_omitted = 1; + the_args.commit = 0; + the_args.edit = 0; + the_args.unedit = 0; + optind = 1; + while ((c = getopt (argc, argv, "la:")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case 'a': + a_omitted = 0; + if (strcmp (optarg, "edit") == 0) + the_args.edit = 1; + else if (strcmp (optarg, "unedit") == 0) + the_args.unedit = 1; + else if (strcmp (optarg, "commit") == 0) + the_args.commit = 1; + else if (strcmp (optarg, "all") == 0) + { + the_args.edit = 1; + the_args.unedit = 1; + the_args.commit = 1; + } + else if (strcmp (optarg, "none") == 0) + { + the_args.edit = 0; + the_args.unedit = 0; + the_args.commit = 0; + } + else + usage (watch_usage); + break; + case '?': + default: + usage (watch_usage); + break; + } + } + argc -= optind; + argv += optind; + + if (a_omitted) + { + the_args.edit = 1; + the_args.unedit = 1; + the_args.commit = 1; + } + +#ifdef CLIENT_SUPPORT + if (client_active) + { + start_server (); + ign_setup (); + + if (local) + send_arg ("-l"); + /* FIXME: copes poorly with "all" if server is extended to have + new watch types and client is still running an old version. */ + if (the_args.edit) + { + send_arg ("-a"); + send_arg ("edit"); + } + if (the_args.unedit) + { + send_arg ("-a"); + send_arg ("unedit"); + } + if (the_args.commit) + { + send_arg ("-a"); + send_arg ("commit"); + } + if (!the_args.edit && !the_args.unedit && !the_args.commit) + { + send_arg ("-a"); + send_arg ("none"); + } + send_file_names (argc, argv); + /* 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 (the_args.adding ? + "watch-add\012" : "watch-remove\012", + 0); + return get_responses_and_close (); + } +#endif /* CLIENT_SUPPORT */ + + the_args.setting_default = (argc <= 0); + + lock_tree_for_write (argc, argv, local, 0); + + err = start_recursion (addremove_fileproc, addremove_filesdoneproc, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, + argc, argv, local, W_LOCAL, 0, 0, (char *)NULL, + 1, 0); + + lock_tree_cleanup (); + return err; +} + +int +watch_add (argc, argv) + int argc; + char **argv; +{ + the_args.adding = 1; + return watch_addremove (argc, argv); +} + +int +watch_remove (argc, argv) + int argc; + char **argv; +{ + the_args.adding = 0; + return watch_addremove (argc, argv); +} + +int +watch (argc, argv) + int argc; + char **argv; +{ + if (argc == -1) + usage (watch_usage); + if (strcmp (argv[1], "on") == 0) + { + --argc; + ++argv; + return watch_on (argc, argv); + } + else if (strcmp (argv[1], "off") == 0) + { + --argc; + ++argv; + return watch_off (argc, argv); + } + else if (strcmp (argv[1], "add") == 0) + { + --argc; + ++argv; + return watch_add (argc, argv); + } + else if (strcmp (argv[1], "remove") == 0) + { + --argc; + ++argv; + return watch_remove (argc, argv); + } + else + usage (watch_usage); + return 0; +} + +static const char *const watchers_usage[] = +{ + "Usage: %s %s [files...]\n", + NULL +}; + +static int watchers_fileproc PROTO ((char *, char *, char *, List *, List *)); + +static int +watchers_fileproc (file, update_dir, repository, entries, srcfiles) + char *file; + char *update_dir; + char *repository; + List *entries; + List *srcfiles; +{ + char *them; + char *p; + + them = fileattr_get0 (file, "_watchers"); + if (them == NULL) + return 0; + + if (update_dir[0] == '\0') + printf ("%s", file); + else + printf ("%s/%s", update_dir, file); + + p = them; + while (1) + { + putc ('\t', stdout); + while (*p != '>' && *p != '\0') + putc (*p++, stdout); + if (*p == '\0') + { + /* Only happens if attribute is misformed. */ + putc ('\n', stdout); + break; + } + ++p; + putc ('\t', stdout); + while (1) + { + while (*p != '+' && *p != ',' && *p != '\0') + putc (*p++, stdout); + if (*p == '\0') + { + putc ('\n', stdout); + goto out; + } + if (*p == ',') + { + ++p; + break; + } + ++p; + putc ('\t', stdout); + } + putc ('\n', stdout); + } + out:; + return 0; +} + +int +watchers (argc, argv) + int argc; + char **argv; +{ + int local = 0; + int c; + + if (argc == -1) + usage (watchers_usage); + + optind = 1; + while ((c = getopt (argc, argv, "l")) != -1) + { + switch (c) + { + case 'l': + local = 1; + break; + case '?': + default: + usage (watchers_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); + /* 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 ("watchers\012", 0); + return get_responses_and_close (); + } +#endif /* CLIENT_SUPPORT */ + + return start_recursion (watchers_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/watch.h b/gnu/usr.bin/cvs/src/watch.h new file mode 100644 index 00000000000..d279c7126b5 --- /dev/null +++ b/gnu/usr.bin/cvs/src/watch.h @@ -0,0 +1,56 @@ +/* Interface to "cvs watch add", "cvs watchers", and related features + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern const char *const watch_usage[]; + +/* Flags to pass between the various functions making up the + add/remove code. All in a single structure in case there is some + need to make the code reentrant some day. */ + +struct addremove_args { + /* A flag for each watcher type. */ + int edit; + int unedit; + int commit; + + /* Are we adding or removing (non-temporary) edit,unedit,and/or commit + watches? */ + int adding; + + /* Should we add a temporary edit watch? */ + int add_tedit; + /* Should we add a temporary unedit watch? */ + int add_tunedit; + /* Should we add a temporary commit watch? */ + int add_tcommit; + + /* Should we remove all temporary watches? */ + int remove_temp; + + /* Should we set the default? This is here for passing among various + routines in watch.c (a good place for it if there is ever any reason + to make the stuff reentrant), not for watch_modify_watchers. */ + int setting_default; +}; + +/* Modify the watchers for FILE. *WHAT tells what to do to them. + If FILE is NULL, modify default args (WHAT->SETTING_DEFAULT is + not used). */ +extern void watch_modify_watchers PROTO ((char *file, + struct addremove_args *what)); + +extern int watch_add PROTO ((int argc, char **argv)); +extern int watch_remove PROTO ((int argc, char **argv)); diff --git a/gnu/usr.bin/cvs/src/wrapper.c b/gnu/usr.bin/cvs/src/wrapper.c index 2aafb2f69ca..ec5f43e8dcf 100644 --- a/gnu/usr.bin/cvs/src/wrapper.c +++ b/gnu/usr.bin/cvs/src/wrapper.c @@ -217,17 +217,26 @@ wrap_add (line, isTemp) case 'f': if(e.fromcvsFilter) free(e.fromcvsFilter); - e.fromcvsFilter=xstrdup(temp); + e.fromcvsFilter=expand_path (temp); + if (!e.fromcvsFilter) + error (1, 0, + "Invalid environmental variable string '%s'",temp); break; case 't': if(e.tocvsFilter) free(e.tocvsFilter); - e.tocvsFilter=xstrdup(temp); + e.tocvsFilter=expand_path (temp); + if (!e.tocvsFilter) + error (1, 0, + "Invalid environmental variable string '%s'",temp); break; case 'c': if(e.conflictHook) free(e.conflictHook); - e.conflictHook=xstrdup(temp); + e.conflictHook=expand_path (temp); + if (!e.conflictHook) + error (1, 0, + "Invalid environmental variable string '%s'",temp); break; case 'm': if(*temp=='C' || *temp=='c') diff --git a/gnu/usr.bin/cvs/windows-NT/.cvsignore b/gnu/usr.bin/cvs/windows-NT/.cvsignore new file mode 100644 index 00000000000..f3c7a7c5da6 --- /dev/null +++ b/gnu/usr.bin/cvs/windows-NT/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/gnu/usr.bin/cvs/windows-NT/ChangeLog b/gnu/usr.bin/cvs/windows-NT/ChangeLog index fd36d33417c..a2db29a381e 100644 --- a/gnu/usr.bin/cvs/windows-NT/ChangeLog +++ b/gnu/usr.bin/cvs/windows-NT/ChangeLog @@ -1,3 +1,123 @@ +Thu Jan 11 16:01:27 1996 Jim Kingdon + + * README: Update with information for Visual C++ 4.0, some + warnings that weren't mentioned, etc. + +Thu Jan 11 12:04:42 1996 Norbert Kiesel + + * options.h: remove CVS_NOADMIN + +Wed Jan 3 16:17:19 1996 Jon Dart + and Jim Kingdon + + * run.c (filter_stream_through_program): If pidp is NULL, don't + store to *pidp. + * ndir.h: Change MAXNAMLEN to 255. + * run.c (build_command): Deal with it if there are no arguments at + all. + +Mon Jan 1 23:40:01 1996 Jim Kingdon + + * filesubr.c (link_file): New function. + + * README: Mention CRLF vs. LF in cvsnt.mak. Other minor revisions. + +Fri Dec 22 12:00:00 1995 Jim Kingdon + + * run.c (filter_stream_through_program): On error, error() rather + than returning -1. + +Thu Dec 21 16:00:00 1995 Jim Kingdon + + * options.h: Don't define NO_SOCKET_TO_FD. + +Mon Dec 18 09:57:29 1995 Jim Kingdon + + * options.h: Explain NO_SOCKET_TO_FD some more. + +Sun Dec 17 21:19:18 1995 Karl Fogel + + * options.h (NO_SOCKET_TO_FD): define to 1. + +Tue Dec 12 19:18:00 1995 Karl Fogel + + * options.h (AUTH_CLIENT_SUPPORT, AUTH_SERVER_SUPPORT): these + replace CVS_LOGIN. + (RCSBIN_DFLT): expand comment. + +Mon Dec 11 12:43:35 1995 adamg + + * config.h: Add INITIALIZE_SOCKET_SUBSYSTEM macro to ensure that + winsock is initialized early enough for the gethostname() in + main.c to succeed. + * rcmd.c: Remove from init_winsock(), and rcmd() code that + initialized winsock on demand. + +Thu Dec 7 14:49:16 1995 Jim Meyering (meyering@comco.com) + + * filesubr.c (isaccessible): Rename from isaccessable. + Update callers. + +Mon Dec 4 10:46:31 1995 Jim Kingdon + + * The following change was copied from src/filesubr.c. This is + because we need filesubr.c to compile, not because we are trying + to make set*id work on NT (if it even has set*id). + * filesubr.c (isaccessable): new function. Checks access-rights + for files like access(), but is getxid-safe. Falls back to + access() if SETXID_SUPPORT is not enabled. + (isfile): replace stat() by isaccessable(file, F_OK) + (isreadable): replace access() by isaccessable() + (iswritable): ditto + (make_directory): rename local variable buf to sb + +Fri Nov 24 11:17:16 EST 1995 Boleslaw Ciesielski + + * filesubr.c (convert_file): Pass S_IWRITE to open when creating + file (fixes problem with deleting temporary files). + +Fri Nov 24 11:12:47 1995 Boleslaw Ciesielski + + * run.c (build_command): Move len++ inside loop, to make room for + spaces between arguments. + +Thu Oct 26 10:12:51 1995 Jim Kingdon + + * README: Say that patch is required, not optional. + +Wed Oct 25 07:40:17 1995 Noel Cragg + + * startserver.c (wnt_start_server): removed NTOHS call; since the + resulting number was passed as the port number to rcmd which + called NTOHS again, we did a complicated NOOP. + +Tue Oct 24 10:59:03 1995 Norbert Kiesel + + * Makefile.in: insert autoconf variables. This allows e.g. make + dist to work when configure was called from within a subdir. + + * Makefile.in (dist): replace by rule which honors $(srcdir) + +Mon Oct 23 18:51:49 1995 Karl Fogel + + * Makefile.in (clean): new rule, does nothing but satisfy + top-level Makefile's beliefs about what its children can do. + +Fri Oct 20 11:09:55 1995 Norbert Kiesel + + * config.h: use same layout and comments as current ../config.h.in + + * options.h: as above for ../src/options.h.in + +Tue Oct 10 16:04:18 1995 Jim Kingdon + + * README: Update to remove obsolete information (e.g. ftp + distributions). + +Thu Oct 5 17:28:52 1995 Kevin Layer + + * filesubr.c: Add semicolon after USE. + Thu Sep 7 19:18:00 1995 Jim Blandy * config.h (CVS_SUPPORT): #define this. diff --git a/gnu/usr.bin/cvs/windows-NT/Makefile.in b/gnu/usr.bin/cvs/windows-NT/Makefile.in index 6a2158c9fdf..8697f8efaaa 100644 --- a/gnu/usr.bin/cvs/windows-NT/Makefile.in +++ b/gnu/usr.bin/cvs/windows-NT/Makefile.in @@ -2,6 +2,17 @@ #### this makefile. However, we need this file in order for 'make #### dist' to work properly on Unix machines. +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +cvs_srcdir = @top_srcdir@/src +VPATH = @srcdir@ + +SHELL = /bin/sh + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + + HEADERS = \ alloca.h \ config.h \ @@ -45,4 +56,13 @@ lint: .PHONY: dist-dir dist-dir: mkdir ${DISTDIR} - ln ${DISTFILES} ${DISTDIR} + for i in ${DISTFILES}; do \ + ln $(srcdir)/$${i} ${DISTDIR}; \ + done + +clean: + @echo make clean does nothing in windows-NT subdir + +subdir = windows-NT +Makefile: ../config.status Makefile.in + cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status diff --git a/gnu/usr.bin/cvs/windows-NT/README b/gnu/usr.bin/cvs/windows-NT/README index ef74d25c562..03416bbd07d 100644 --- a/gnu/usr.bin/cvs/windows-NT/README +++ b/gnu/usr.bin/cvs/windows-NT/README @@ -1,77 +1,53 @@ - Concurrent Versions System (CVS) Version 1.5 + Concurrent Versions System (CVS) ported to Microsoft Windows NT Cyclic Software -Cyclic Software has ported the client side of CVS 1.5 to Windows NT. -The port implements the full set of CVS commands, but cannot access -repositories located on the local machine. The repository must live -on another machine (a Unix box, say) which runs a complete port of -CVS. +Check the ../INSTALL file for information on the most recent version +of CVS which has been known to be tested with NT. -Source code for the port is available from Cyclic Software as: +The port implements the full set of CVS commands, but is client only, +not server or local ("local" meaning accessing repositories on a +filesystem mounted on the local machine). The repository must live on +another machine (a Unix box, say) which runs a complete port of CVS. - ftp://ftp.cyclic.com/pub/cvs/windows-nt/cvs-1.5nt.tar.gz - -That includes documentation, in Texinfo and PostScript. It's all -distributed as a gzipped tar file instead of a .ZIP file because, as -far as I can tell, PKZIP insists on munging long file names, which -would confuse the makefile for Visual C++. +We don't distribute a .ZIP source distribution partly because, as far +as I can tell, PKZIP insists on munging long file names, which would +confuse the makefile for Visual C++. To compile, use Microsoft Visual C++ on the file cvsnt.mak in the -distribution's top directory. We haven't tested it under any other -development environments. If you're curious, see below about the -warnings you may encounter. - -We've put a Windows NT 80x86 executable for CVS in the same directory -as the source distribution, called cvs.exe. Full documentation is -present in PostScript format in the source distribution. Generally, -we'd like to avoid spending much time on binary distributions. - -Please send bug reports to bug-cvs@prep.ai.mit.edu. I can't promise -to fix them --- paying work must come first --- but the reports will -not be tossed, and I'll see what I can do. - -This port passes the test in src/sanity.sh. (We ran the checks by -hand, since we couldn't find a port of the Bourne shell good enough to -execute the script). Sanity.sh provides pretty minimal feature -coverage, but still gives me some confidence it isn't totally broken. - -For best results, you will also need GNU patch and GZIP installed on -your system, although CVS can be used without them. The Congruent -ports of these packages to Windows NT, binary and source, are -available in: +distribution's top directory. At least with the tar port I'm using, +the sources get extracted without carriage returns and you must add +carriage returns to the end of every line in cvsnt.mak. It doesn't +seem to be necessary to add them to any other file. This has been +tested with Visual C++ 2.1. Visual C++ 4.0 apparently requires one to +remove some quotation marks from cvsnt.mak (around save-cwd.c, +save-cwd.sbr, and save-cwd.obj). + +Send bug reports to bug-cvs@prep.ai.mit.edu. + +As of August 20, 1995, this port passed the test in src/sanity.sh. +(We ran the checks by hand, since we couldn't find a port of the +Bourne shell good enough to execute the script). Sanity.sh provides +pretty minimal feature coverage, but still gives me some confidence it +isn't totally broken. + +You will also need GNU patch installed on your system. GZIP is useful +but not required. The Congruent ports of these packages to Windows +NT, binary and source, are available in: ftp://microlib.cc.utexas.edu/microlib/nt/gnu -At the moment, this port isn't integrated into our mainline CVS -sources, but I expect that to be straightforward. I'll get around to -it soon, but as I said, paying work... - -Now, strictly speaking, I don't *know* that this port won't correctly -access repositories on the local machine. I haven't tried it. I -have put calls to abort in places I'm pretty sure are wrong. If you'd -like to finish it off and post patches, Morten Hindsholm's port of CVS -1.4A2 to Windows NT might be helpful; it is available as +If you'd like to finish off the port of local CVS, Morten Hindsholm's +port of CVS 1.4A2 to Windows NT might be helpful; it is available as ftp://ftp.digex.net/pub/access/schueman/cvs/cvsnt14b.zip +The following harmless warnings are known: -I get the following warnings when compiling this port of CVS 1.5 under -Microsoft Visual C++. They are all harmless. - -- main.c: This is a very weird warning message! If you understand - what it's trying to say, let me know: - 'void (__cdecl *)(void)' differs in parameter lists from - 'void (__cdecl *)(void )' - Okay, whatever, man. -- sighandle.c: These are harmless conflicts in the arguments of - pointed-to functions. You're welcome to submit patches for them. - regex.c: These are signed/unsigned comparison conflicts. I am not going to *touch* this code. :-) I got my fill of it when I was hacking GNU Emacs. - - - -Jim Blandy -Sunday, August 20, 1995 +.\lib\getdate.c(760) : warning C4013: 'getdate_yyparse' undefined; assuming extern returning int +.\lib\getdate.c(1612) : warning C4102: 'yyerrlab' : unreferenced label +.\lib\getdate.c(1612) : warning C4102: 'yynewstate' : unreferenced label diff --git a/gnu/usr.bin/cvs/windows-NT/filesubr.c b/gnu/usr.bin/cvs/windows-NT/filesubr.c index ce4a126ae08..c9b4c17e06a 100644 --- a/gnu/usr.bin/cvs/windows-NT/filesubr.c +++ b/gnu/usr.bin/cvs/windows-NT/filesubr.c @@ -27,7 +27,7 @@ #ifndef lint static const char rcsid[] = "$CVSid:$"; -USE(rcsid) +USE(rcsid); #endif /* @@ -110,6 +110,20 @@ copy_file (from, to) (void) utime (to, &t); } +/* + * link a file, if possible. Warning: the Windows NT version of this + * function just copies the file, so only use this function in ways + * that can deal with either a link or a copy. + */ +int +link_file (from, to) + const char *from; + const char *to; +{ + copy_file (from, to); + return 0; +} + /* FIXME-krp: these functions would benefit from caching the char * & stat buf. */ @@ -153,33 +167,88 @@ int isfile (file) const char *file; { - struct stat sb; - - if (stat (file, &sb) < 0) - return (0); - return (1); + return isaccessible(file, F_OK); } /* * Returns non-zero if the argument file is readable. - * XXX - must be careful if "cvs" is ever made setuid! */ int isreadable (file) const char *file; { - return (access (file, R_OK) != -1); + return isaccessible(file, R_OK); } /* - * Returns non-zero if the argument file is writable - * XXX - muct be careful if "cvs" is ever made setuid! + * Returns non-zero if the argument file is writable. */ int iswritable (file) const char *file; { - return (access (file, W_OK) != -1); + return isaccessible(file, W_OK); +} + +/* + * Returns non-zero if the argument file is accessable according to + * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid + * bits set. + */ +int +isaccessible (file, mode) + const char *file; + const int mode; +{ +#ifdef SETXID_SUPPORT + struct stat sb; + int umask = 0; + int gmask = 0; + int omask = 0; + int uid; + + if (stat(file, &sb) == -1) + return 0; + if (mode == F_OK) + return 1; + + uid = geteuid(); + if (uid == 0) /* superuser */ + { + if (mode & X_OK) + return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH); + else + return 1; + } + + if (mode & R_OK) + { + umask |= S_IRUSR; + gmask |= S_IRGRP; + omask |= S_IROTH; + } + if (mode & W_OK) + { + umask |= S_IWUSR; + gmask |= S_IWGRP; + omask |= S_IWOTH; + } + if (mode & X_OK) + { + umask |= S_IXUSR; + gmask |= S_IXGRP; + omask |= S_IXOTH; + } + + if (sb.st_uid == uid) + return (sb.st_mode & umask) == umask; + else if (sb.st_gid == getegid()) + return (sb.st_mode & gmask) == gmask; + else + return (sb.st_mode & omask) == omask; +#else + return access(file, mode) == 0; +#endif } /* @@ -204,9 +273,9 @@ void make_directory (name) const char *name; { - struct stat buf; + struct stat sb; - if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode))) + if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) error (0, 0, "%s already exists but is not a directory", name); if (!noexec && mkdir (name) < 0) error (1, errno, "cannot make directory %s", name); @@ -707,7 +776,7 @@ convert_file (char *infile, int inflags, if ((infd = open (infile, inflags)) < 0) error (1, errno, "couldn't read %s", infile); - if ((outfd = open (outfile, outflags)) < 0) + if ((outfd = open (outfile, outflags, S_IWRITE)) < 0) error (1, errno, "couldn't write %s", outfile); while ((len = read (infd, buf, sizeof (buf))) > 0) diff --git a/gnu/usr.bin/cvs/windows-NT/ndir.h b/gnu/usr.bin/cvs/windows-NT/ndir.h index 5160a1a28a6..f5be88634c2 100644 --- a/gnu/usr.bin/cvs/windows-NT/ndir.h +++ b/gnu/usr.bin/cvs/windows-NT/ndir.h @@ -15,7 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Header: /home/cvs/src/gnu/usr.bin/cvs/windows-NT/ndir.h,v 1.1.1.1 1995/12/19 09:21:43 deraadt Exp $ + $Header: /home/cvs/src/gnu/usr.bin/cvs/windows-NT/ndir.h,v 1.1.1.2 1996/01/30 00:19:27 tholo Exp $ */ /* Everything non trivial in this code is taken from: @(#)msd_dir.c 1.4 @@ -27,7 +27,10 @@ #define rewinddir(dirp) seekdir(dirp, 0L) -#define MAXNAMLEN 12 +/* 255 is said to be big enough for Windows NT. The more elegant + solution would be declaring d_name as one byte long and allocating + it to the actual size needed. */ +#define MAXNAMLEN 255 struct direct { diff --git a/gnu/usr.bin/cvs/windows-NT/options.h b/gnu/usr.bin/cvs/windows-NT/options.h index 6f6d341a621..479f67335bb 100644 --- a/gnu/usr.bin/cvs/windows-NT/options.h +++ b/gnu/usr.bin/cvs/windows-NT/options.h @@ -53,12 +53,14 @@ /* * The "diff" program to execute when creating patch output. This "diff" - * must support the "-c" option for context diffing. Specify a full pathname - * if your site wants to use a particular diff. If you are using the GNU - * version of diff (version 1.15 or later), this should be "diff -a". + * must support the "-c" option for context diffing. Specify a full + * pathname if your site wants to use a particular diff. If you are + * using the GNU version of diff (version 1.15 or later), this should + * be "diff -a". * - * NOTE: this program is only used for the ``patch'' sub-command. The other - * commands use rcsdiff which will use whatever version of diff was specified + * NOTE: this program is only used for the ``patch'' sub-command (and + * for ``update'' if you are using the server). The other commands + * use rcsdiff which will use whatever version of diff was specified * when rcsdiff was built on your system. */ @@ -112,6 +114,17 @@ * unless the user overrides the default with the RCSBIN environment variable * or the "-b" option to CVS. * + * If you're compiling the authenticating server (see + * AUTH_SERVER_SUPPORT farther down), then you probably want to set + * RCSBIN_DFLT. The authenticating server starts out running as root, + * and then switches to run as the appropriate user once + * authentication is complete. No shell is ever started by that user, + * so the PATH environment variable may not contain the directory with + * the RCS binaries, even though if that user logged in normally, PATH + * would include the directory. An alternative to setting RCSBIN_DFLT + * is to make sure that root has the right directory in its path + * already. + * * This define should be either the empty string ("") or a full pathname to the * directory containing all the installed programs from the RCS distribution. */ @@ -132,6 +145,33 @@ #define EDITOR_DFLT "notepad" #endif +/* + * The default umask to use when creating or otherwise setting file or + * directory permissions in the repository. Must be a value in the + * range of 0 through 0777. For example, a value of 002 allows group + * rwx access and world rx access; a value of 007 allows group rwx + * access but no world access. This value is overridden by the value + * of the CVSUMASK environment variable, which is interpreted as an + * octal number. + */ +#ifndef UMASK_DFLT +#define UMASK_DFLT 002 +#endif + +/* + * The cvs admin command is restricted to the members of the group + * CVS_ADMIN_GROUP. If this group does not exist, all users are + * allowed to run cvs admin. To disable the cvs admin for all users, + * create an empty group CVS_ADMIN_GROUP. To disable access control for + * cvs admin, comment out the define below. + * + * Under Windows NT, this must not be used because it tries to include + * + */ +#ifdef CVS_ADMIN_GROUP +/* #define CVS_ADMIN_GROUP "cvsadmin" */ +#endif + /* * The Repository file holds the path to the directory within the source * repository that contains the RCS ,v files for each CVS working directory. @@ -187,8 +227,7 @@ * so the case in which someone has logged in as root does not occur. * Thus, there is no need for this hack. */ -#undef CVS_BADROOT - +#undef CVS_BADROOT /* * The "cvs diff" command accepts all the single-character options that GNU @@ -202,6 +241,23 @@ #define CVS_DIFFDATE #endif +/* + * The authenticated client/server is under construction -- it is not + * known to work with Windows NT. + */ +/* #define AUTH_CLIENT_SUPPORT 1 */ +/* #define AUTH_SERVER_SUPPORT 1 */ + +/* + * This tells the client that it must use send()/recv() to talk to the + * server if it is connected to the server via a socket; Win95 is said to + * need it because _open_osfhandle doesn't work. This is only + * implemented for pserver, not rsh. Furthermore, NT doesn't seem to have send() + * and recv(), or maybe one has to link against a different library or something, + * I don't know. So this is commented out. + */ +/* #define NO_SOCKET_TO_FD 1 */ + /* End of CVS configuration section */ /* diff --git a/gnu/usr.bin/cvs/windows-NT/rcmd.c b/gnu/usr.bin/cvs/windows-NT/rcmd.c index dbc17770124..7e5ed3d8254 100644 --- a/gnu/usr.bin/cvs/windows-NT/rcmd.c +++ b/gnu/usr.bin/cvs/windows-NT/rcmd.c @@ -6,34 +6,30 @@ #include #include #include +#include #include #include "rcmd.h" -static int +void init_winsock () { - static char initialized = 0; WSADATA data; - - if (initialized) - return 0; + int optionValue = SO_SYNCHRONOUS_NONALERT; if (WSAStartup (MAKEWORD (1, 1), &data)) - return -1; - { - int optionValue = SO_SYNCHRONOUS_NONALERT; - - if (setsockopt(INVALID_SOCKET, SOL_SOCKET, - SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)) - == SOCKET_ERROR) - return -1; + fprintf (stderr, "cvs: unable to initialize winsock\n"); + exit (1); } - initialized = 1; - - return 0; + if (setsockopt(INVALID_SOCKET, SOL_SOCKET, + SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)) + == SOCKET_ERROR) + { + fprintf (stderr, "cvs: unable to setup winsock\n"); + exit (1); + } } static int @@ -190,9 +186,6 @@ rcmd (const char **ahost, assert (fd2p == 0); - if (init_winsock () < 0) - return -1; - if (resolve_address (ahost, &sai) < 0) return -1; diff --git a/gnu/usr.bin/cvs/windows-NT/run.c b/gnu/usr.bin/cvs/windows-NT/run.c index 8f1105b0725..6364bd3c8d0 100644 --- a/gnu/usr.bin/cvs/windows-NT/run.c +++ b/gnu/usr.bin/cvs/windows-NT/run.c @@ -578,12 +578,13 @@ build_command (char **argv) else len++; } + len++; /* for the space or the '\0' */ } - len++; /* for the space or the '\0' */ } { - char *command = (char *) malloc (len); + /* The + 10 is in case len is 0. */ + char *command = (char *) malloc (len + 10); int i; char *p; @@ -594,6 +595,7 @@ build_command (char **argv) } p = command; + *p = '\0'; /* copy each element of argv to command, putting each command in double quotes, and backslashing any quotes that appear within an argument. */ @@ -611,7 +613,8 @@ build_command (char **argv) *p++ = '"'; *p++ = ' '; } - p[-1] = '\0'; + if (p > command) + p[-1] = '\0'; return command; } @@ -664,6 +667,9 @@ piped_child (char **argv, int *to, int *from) /* * dir = 0 : main proc writes to new proc, which writes to oldfd * dir = 1 : main proc reads from new proc, which reads from oldfd + * + * Returns: a file descriptor. On failure (e.g., the exec fails), + * then filter_stream_through_program() complains and dies. */ int @@ -681,19 +687,19 @@ filter_stream_through_program (oldfd, dir, prog, pidp) /* Get the OS handle associated with oldfd, to be passed to the child. */ if ((oldfd_handle = (HANDLE) _get_osfhandle (oldfd)) < 0) - return -1; + error (1, errno, "cannot _get_osfhandle"); if (dir) { /* insert child before parent, pipe goes child->parent. */ if (my_pipe (pipe, inherit_writing) == -1) - return -1; + error (1, errno, "cannot my_pipe"); if ((command = build_command (prog)) == NULL) - return -1; + error (1, errno, "cannot build_command"); child = start_child (command, oldfd_handle, pipe[1]); free (command); if (child == (int) INVALID_HANDLE_VALUE) - return -1; + error (1, errno, "cannot start_child"); close (oldfd); CloseHandle (pipe[1]); newfd_handle = pipe[0]; @@ -702,22 +708,23 @@ filter_stream_through_program (oldfd, dir, prog, pidp) { /* insert child after parent, pipe goes parent->child. */ if (my_pipe (pipe, inherit_reading) == -1) - return -1; + error (1, errno, "cannot my_pipe"); if ((command = build_command (prog)) == NULL) - return -1; + error (1, errno, "cannot build_command"); child = start_child (command, pipe[0], oldfd_handle); free (command); if (child == (int) INVALID_HANDLE_VALUE) - return -1; + error (1, errno, "cannot start_child"); close (oldfd); CloseHandle (pipe[0]); newfd_handle = pipe[1]; } if ((newfd = _open_osfhandle ((long) newfd_handle, _O_BINARY)) == -1) - return -1; + error (1, errno, "cannot _open_osfhandle"); - *pidp = child; + if (pidp) + *pidp = child; return newfd; } diff --git a/gnu/usr.bin/cvs/windows-NT/startserver.c b/gnu/usr.bin/cvs/windows-NT/startserver.c index cc77a6c7a65..9df9289b7e1 100644 --- a/gnu/usr.bin/cvs/windows-NT/startserver.c +++ b/gnu/usr.bin/cvs/windows-NT/startserver.c @@ -47,7 +47,7 @@ wnt_start_server (int *tofd, int *fromfd, if ((s = getservbyname("shell", "tcp")) == NULL) port = IPPORT_CMDSERVER; else - port = ntohs (s->s_port); + port = s->s_port; read_fd = rcmd (&server_host, port,