diff options
154 files changed, 126 insertions, 76725 deletions
diff --git a/gnu/usr.bin/cvs/BUGS b/gnu/usr.bin/cvs/BUGS deleted file mode 100644 index 3ad13a8..0000000 --- a/gnu/usr.bin/cvs/BUGS +++ /dev/null @@ -1,248 +0,0 @@ -* `cvs checkout -d nested/dir/path <module>' just doesn't work. The - simpler version -- `cvs checkout -d single-dir <module>' works, - however. - - -* CVS leaves .#mumble files around when a conflict occurs. (Note: - this is intentional and is documented in doc/cvs.texinfo. Of course - whether it is a good idea is a separate question). - - -* pcl-cvs doesn't like it when you try to check in a file which isn't - up-to-date. The messages produced by the server perhaps don't match - what pcl-cvs is looking for. - - -* From: Roland McGrath <roland@gnu.ai.mit.edu> - To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com> - Subject: weird bug - Date: Sat, 25 Mar 1995 16:41:41 -0500 - X-Windows: Even your dog won't like it. - - I just noticed some droppings on my disk from what must be a pretty weird - bug in remote CVS. - - In my home directory on a repository machine I use, I find: - - drwxr-xr-x 4 roland staff 512 Mar 7 14:08 cvs-serv28962 - drwxr-xr-x 4 roland staff 512 Mar 7 14:11 cvs-serv28978 - drwxr-xr-x 4 roland staff 512 Mar 7 15:13 cvs-serv29141 - - OK, so these are leftover cruft from some cvs run that got aborted. - Well, it should clean up after itself, but so what. - - The last one is pretty dull; the real weirdness is the contents of the - first two directories. - - duality 77 # ls -RF cvs-serv28978/ - CVS/ cvs-serv28978/ - - cvs-serv28978/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978: - arpa/ - - cvs-serv28978/cvs-serv28978/arpa: - CVS/ cvs-serv28978/ - - cvs-serv28978/cvs-serv28978/arpa/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978: - assert/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert: - CVS/ cvs-serv28978/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978: - bare/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare: - CVS/ cvs-serv28978/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978: - conf/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf: - CVS/ cvs-serv28978/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978: - crypt/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt: - CVS/ cvs-serv28978/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978: - csu/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu: - CVS/ cvs-serv28978/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/CVS: - Entries Repository - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978: - ctype/ - - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype: - CVS/ cvs-serv28978/ - - [...] - - ls: cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978/socket: File name too long - cvs-serv28978/cvs-serv28978/arpa/cvs-serv28978/assert/cvs-serv28978/bare/cvs-serv28978/conf/cvs-serv28978/crypt/cvs-serv28978/csu/cvs-serv28978/ctype/cvs-serv28978/dirent/cvs-serv28978/elf/cvs-serv28978/gnu/cvs-serv28978/gnulib/cvs-serv28978/grp/cvs-serv28978/hurd/cvs-serv28978/hurd/hurd/cvs-serv28978/inet/cvs-serv28978/inet/arpa/cvs-serv28978/inet/netinet[...]/cvs-serv28978/posix/glob/cvs-serv28978/posix/gnu/cvs-serv28978/posix/sys/cvs-serv28978/protocols/cvs-serv28978/pwd/cvs-serv28978/resolv/cvs-serv28978/resolv/arpa/cvs-serv28978/resolv/sys/cvs-serv28978/resource/cvs-serv28978/resource/sys/cvs-serv28978/rpc/cvs-serv28978/setjmp/cvs-serv28978/signal/cvs-serv28978/signal/sys/cvs-serv28978/socket/cvs-serv28978: - - -* From: billr@mpd.tandem.com (Bill Robertson) - Subject: Problem with rtag and the -D option - Date: Fri, 17 Mar 1995 10:53:29 -0600 (CST) - - I have been trying to use the -D option to specify a date for tagging, but - rtag does not recognize the -D option. It is documented to do so and I've - tested the use of -D with cvs update and cvs diff and it works fine there. - - -* We need some version numbers really badly. Are there some - (and Charles Hannum is just not including them in his reports), or do - we simply have no reliable way to distinguish between the various - versions of rCVS people on the list are running? - - Now that I think of it, version numbers present a problem when - people can update their sources anytime and rebuild. I think the - solution is to increment a minor version number *every* time a bug is - fixed, so we can identify uniquely what someone is running when they - submit a report. This implies recording the version increments in the - ChangeLog; that way we can just look to see where a particular version - lies in relation to the flow of changing code. - - Should we be doing same with Guppy? I guess not -- it's only - important when you have people who are updating directly from your - development tree, which is the case with the remote-cvs folks. - - Thoughts? - - -* (Charles Hannum <mycroft@ai.mit.edu>) has these bugs: - - I just tossed remote CVS at a fairly large source tree that I already - had, and noticed a few problems: - - 1) server.c assumes that /usr/tmp is a valid default for the place to - store files uploaded from the client. There are a number of systems - that now use /var/tmp. These should probably be detected by autoconf. - - 2) The server deals rather ungracefully with the tmp directory - becoming full. - - 3) There's some oddness with relative paths in Repository files that - causes the directory prefix to be added twice; e.g. if I have CVSROOT - set to `machine:/this/dir', and I try to update in a directory whose - Repository file says `src/bin', the server looks in - `/this/dir/machine:/this/dir/src/bin'. - -* From: "Charles M. Hannum" <mycroft@ai.mit.edu> - To: jimb@duality.gnu.ai.mit.edu, roland@duality.gnu.ai.mit.edu - Subject: Serious flaw in remote CVS - Date: Wed, 22 Feb 1995 20:54:36 -0500 - - I just found a major flaw in the current implementation. Because the - sockets are not changed to non-blocking mode, write(2)s can hang. In - some cases, this happens on both sides at the same time, with the - socket buffers full in both directions. This causes a deadlock, - because both processes are stuck in I/O wait and thus never drain - their input queues. - - Until this is fixed, I can't use it. I'll look at the problem myself - at some point, but I don't know when. - - - From: "Charles M. Hannum" <mycroft@ai.mit.edu> - To: remote-cvs@cyclic.com - Cc: jimb@totoro.bio.indiana.edu - Subject: Re: forwarded message from Charles M. Hannum - Date: Wed, 22 Feb 1995 22:07:07 -0500 - - FYI, this happened because the tmp directory on the server became - full. Somehow the server started interpreting the files the client - was sending as commands, and started spewing tons of errors. - Apparently the errors are sent with blocking I/O, or something, and - thus allowed the deadlock to happen. - - -* From: "Charles M. Hannum" <mycroft@ai.mit.edu> - To: remote-cvs@cyclic.com - Subject: Regarding that relative path problem - Date: Thu, 23 Feb 1995 02:41:51 -0500 - - This is actually more serious. If you have `bar.com:/foo' as your CVS - root directory, then: - - 1) When you check things out, the Repository files will contain - `/foo/...' (i.e. without the machine name), which makes little sense. - - 2) If you instead have a relative path, when the Repository file is - read, `bar.com:/foo' is prepended. This is sent to the server, but - confuses it, because it's not expecting the machine name to be - prepended. - - A slightly klugy fix would be to have the client prepend the machine - name when writing a new Repository file, and strip it off before - sending one to the server. This would be backward-compatible with the - current arrangement. - - -* From: "Charles M. Hannum" <mycroft@ai.mit.edu> - To: remote-cvs@cyclic.com - Subject: Still one more bug - Date: Sat, 25 Feb 1995 17:01:15 -0500 - - mycroft@duality [1]; cd /usr/src/lib/libc - mycroft@duality [1]; cvs diff -c2 '-D1 day ago' -Dnow - cvs server: Diffing . - cvs server: Diffing DB - cvs [server aborted]: could not chdir to DB: No such file or directory - mycroft@duality [1]; - - `DB' is an old directory, which no longer has files in it, and is - removed automatically when I use the `-P' option to checkout. - - This error doesn't occur when run locally. - - P.S. Is anyone working on fixing these bugs? - - -* From: Roland McGrath <roland@gnu.ai.mit.edu> - To: Cyclic CVS Hackers <cyclic-cvs@cyclic.com> - Subject: bizarre failure mode - Date: Tue, 7 Mar 95 14:17:28 -0500 - - This is pretty weird: - - CVS_SERVER='TMPDIR=. /usr/local/bin/cvs' ../cvs-build/src/cvs update -q - cvs [server aborted]: could not get working directory: Result too large - [Exit 1] - asylum 29 % grep 'Result too large' /usr/include/sys/errno.h - #define ERANGE 34 /* Result too large */ - - Now, getcwd fails with ERANGE when the buffer is too small. But I don't - know why that would be the case; I don't think there are exceptionally long - directory names involved. It would be robust to notice ERANGE and use a - bigger buffer. But I suspect something weirder is going on. - - The repository in question in duality.gnu.ai.mit.edu:/gd4/gnu/cvsroot/libc. - - Send me a PGP-signed message if you want the password to use the machine - where the problem showed up. diff --git a/gnu/usr.bin/cvs/FAQ b/gnu/usr.bin/cvs/FAQ deleted file mode 100644 index 84d4a3a..0000000 --- a/gnu/usr.bin/cvs/FAQ +++ /dev/null @@ -1,10006 +0,0 @@ - -Archive-name: cvs-faq -Hand Revision: 3.5 <<== Include this in your comments -Last Updated: 1995/03/09 -$Revision: 1.4 $ -$Date: 1995/10/02 23:13:07 $ - -=========================================================================== -== 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 <dgg@world.std.com> - - - 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: <Your Internet address> - 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 <tag>".] - [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 <prog>" 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 <prog>" appears in the - modules file for the checked-out module.] - - ./CVS/<file>,p - ./CVS/<file>,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 <rev/tag>" or "-D <date>". 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 <rev> -j <rev>". (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 <branch_tag> {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 <rev> -j <rev> {optional files}" command merges - the difference between two specified revisions into files in - your working directory. The two revisions <rev> 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 <where you have some space to work> - 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 <module>, all tags are named <tag> (branch tags are - named <branch_tag>) and all files are named <file>. - - The checkout command will take a relative path name in place - of a module name. If you use a relative pathname in place of - <module>, you should use the same relative path every place - you see <module> 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 <module> 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 <module>. Then type: - - cvs checkout <module> - cd <module> - emacs <file> # Isn't Emacs a synonym for edit? - cvs commit <file> - - 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 <module> in the example above. - - To work on a single file, you'll have to change "cd <module>" to - "cd `dirname <module>`". - - - 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 <module> directory that "checkout" created? - - Change your directory to be the same as when you executed the - "checkout" command that created <module>. - - If you want to get rid of the CVS control information, but leave - the files and directories, type: - - cvs release <module> - - If you want to obliterate the entire directory, type: - - cvs release -d <module> - - ("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 <module>" 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. - - ? <file> - - To add <file> to the Repository, type: - - cvs add <file> - cvs commit <file> - - 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: - - ? <file> - - 2. If neither you nor anyone else has committed changes to <file>, - 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 <file> - - 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 <file> - - 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/<file> - retrieving revision 1.X - retrieving revision 1.Y - Merging differences between 1.X and 1.Y into <file> - M <file> - - 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/<file> - retrieving revision 1.X - retrieving revision 1.Y - Merging differences between 1.X and 1.Y into <file> - rcsmerge warning: overlaps during merge - cvs update: conflicts found in <file> - C <file> - - 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 <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 <tag> <module> - - - 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 <tag>" option. - - 2. By date, via the "-D <date>" option. - - 3. By branch tag (a type of tag with a magic format), via the - "-r <branch_tag>" option. - - 4. By date within a branch, via the "-r <branch_tag>:<date>" - option. - - 5. By an explicit branch revision number ("-r <rev>"), 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 <rev>" Though this works, it - is almost useless for more than one file. - - - You type: - - cvs checkout <option-specified-above> <module> - cd <module> - - - 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 <dir> - cvs add <dir> - - It will respond: - - Directory /Repos/<dir> added to the repository - - and will create both a matching directory in the Repository and a - ./CVS administrative directory within the local <dir> 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 <file> - cvs remove <file> - - CVS registers the file for removal. To complete the removal, you - must type: - - cvs commit <file> - - 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/<odir>/<ofile>,v $CVSROOT/<ndir>/<nfile>,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 <tag/rev>" or "-D <date>" options to - "checkout" and "update". - - 2. Remove the old file using CVS. - - cd <working-dir>/<odir> - rm <ofile> - cvs remove <ofile> - cvs commit <ofile> - - This will move the <ofile> to the Attic associated with - <odir>. - - 3. Retrieve <nfile> 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 <working-dir>/<ndir> - cvs update <nfile> - cvs log <nfile> # Save the list of Tags - cvs tag -d <tag1> <nfile> - cvs tag -d <tag2> <nfile> - . . . - - - 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 <working-dir> to know about the name change. - - Warning: Stripping the old tags from the copied file will allow - "-r <tag>" to do the right thing, but you will still have problems - with "-D <date>" 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 <branch_tag> - - 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 <branch_tag> - - and commit a file in the normal way: - - cvs commit <file> - - then a branch will be created in the underlying <file>,v file and - the new revision of <file> 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 <fileA>, which already in the Repository, - into three pieces, <fileA>, <fileB> and <fileC>. - - 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/<path>/<fileA>,v $CVSROOT/<path>/<fileB>,v - cp $CVSROOT/<path>/<fileA>,v $CVSROOT/<path>/<fileC>,v - cvs update <fileB> <fileC> - - 2. Then remove all the <tags> from the new files by using: - - cvs log <fileB> <fileC> # Save the list of <tag?> - cvs tag -d <tag1> <fileB> <fileC> - cvs tag -d <tag2> <fileB> <fileC> - . . . - - 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 <fileA> <fileB> <fileC> - cvs commit <fileA> <fileB> <fileC> - - - 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 .#<file>.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 <tag>", CVS remembers the <tag>. 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 <tag>" on the command line. - - It is most useful for a <branch_tag>, which is a sticky tag - indicating what branch you are working on. - - A revision number ("-r <rev-number>") or date ("-D <date>") 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 <tag/rev>" 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 <tag/rev> 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 <file> 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 `<file>' - - You must merge your coworker's changes into your working file by - typing: - - cvs update <file> - - 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 <file>. 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 .#<file>.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 <file>. - You both make changes -- different changes. B commits first, so - <file>,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 ".#<file>.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 <original file> - <original file with only my work added>", which can be done in the - example above by the Unix shell command: - - cvs update -p -r 1.3 <file> | diff - .#<file>.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 <branch_tag>" - option (to place you on a branch tagged with <branch_tag>). To - add <file> to the branch you are on, you type: - - cvs add <file> - cvs commit <file> - - 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 <branch_tag>" option creates it), the file will be added - to the branch named (i.e. tagged with) <branch_tag>. - - 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 <file> - cvs commit <file> - cvs tag -b <branch_tag> <file> - - [<branch_tag> 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 <branch_tag> <file> - - 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 <branch_tag> - - - 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 <file> - - 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 <file> <file>.hold - cvs remove <file> - mv <file>.hold <file> - - - 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 <file> - - Commit the file normally. The sticky -ko option will be used. - - cvs commit <file> - - 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 <file> - - 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 <branch_tag>" 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 <file>" 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 "<boss's name>_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 <file> 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 <file>,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 <file> - - 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 <tag>, not just the one on <file>. 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 <tag>. 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 <tag> pointed to without using the "tag" - command. For example, if revision 1.3 has <tag> attached to it - and you "outdate" the 1.3 revision, <tag> 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 <tag> 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 <prog>") 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 `<file>' - 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 <tag/rev>" 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 `<file>' - - 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 - <previous-rev>" 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 <tag/rev>" argument - handed to the "checkout" or "update" commands. The <tag/rev> 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 <branch_tag> by: - - cvs update -r <branch_tag> {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 <oldtag> <newtag> <module> - - (It was not a big mistake. Branch-point tags can be useful. - But the <newtag> must have a different name.) - - If you don't know the <module> name or don't use "modules", - you can also use "tag" this way: - - cvs update -r <oldtag> - cvs tag -b <newtag> . - - Then, to put your working directory onto the branch, you type: - - cvs update -r <newtag> - - - You can't delete <oldtag> before adding <newtag>, and I would - not advise deleting the <oldtag> 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 <oldtag> <module> - or - cvs tag -d <oldtag> . - - - 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 - <oldtag> 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 <oldtag> <branch_point_tag> <module> - cvs rtag -d <oldtag> <module> - cvs rtag -b -r <branch_point_tag> <oldtag> <module> - - Then, if you really must, delete the <branch_point_tag>: - - cvs rtag -d <branch_point_tag> <module> - - - - Note: The unwieldy mixture of "tag" and "rtag" is mostly - because you can't specify a revision (-r <tag>) to the - "tag" command. - - See 4C.3 for more info on creating a branch. - - - 3D.7 Why does "commit -r <tag/rev>" put newly added files in the Attic? - - If you specify "-r <rev>" (where <rev> is a dotted numeric number - like 2.4), it correctly sets the initial revision to <rev>, but it - also attaches the numeric <rev> 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 <tag>" to commit a newly added file, the <tag> - is treated like a <branch_tag>, 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 <file>. 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 <file> - - 2. To display the difference between a working file and a - committed revision of the same file: - - cvs diff -r <tag/rev> <file> - - 3. To display the difference between two committed revisions of - the same file: - - cvs diff -r <tag1/rev1> -r <tag2/rev2> <file> - - You can specify any number of <file> arguments. Without any - <file> arguments, it compares the whole directory. - - In the examples above, "-D <date>" may be substituted wherever - "-r <tag/rev>" appears. The revision a <date> 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 <file> - - - 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 <file> - - - 3E.4 How do I display the difference between my working file and what - I checked in last Thursday? - - cvs diff -D "last Thursday" <file> - - 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 <tag/rev>" and - "cvs history -t <tag>"? - 3G.8 Why does "cvs history -c -t <tag>" 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 <tag/rev>" and - "cvs history -t <tag>"? - - The '-t' option looks for a Tag record stored by "rtag" in the - history file and limits the search to dates after the last <tag> - of the given name was added. - - The '-r' option was intended to search all files looking for the - <tag> in the RCS files. It takes forever and needs to be - rewritten. - - - 3G.8 Why does "cvs history -c -t <tag>" 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 <same for all users> - - cvs history -o -w What working directories have I created - and what modules are in them? - cvs history -a -o -w <same for every user> - - 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 <tag> - * Modified files since TAG on files: -c -r <tag> - * 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 <file>: Permission denied - 3H.15 Where does the -m <message> 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" <repos> <Vendor-Tag> <Release-Tag> - - where <repos> 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 <your source tree> - 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 <file> - rm <file> - cvs update <file> - - 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 <new source> - cvs import -I ! -m "Message" <repos> <VendorTag> <ReleaseTag> - - - 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. - - <repos> is a relative path to a directory within the - Repository. The directory <new source> must be at - the same relative level within the new sources as - the <repos> you give is within the Repository. (I - realize this is not obvious. Experiment first.) - - <VendorTag> is a Tag used to identify the Vendor who sent you - the files you are importing. All "imports" into - the same <repos> *must* use the same VendorTag. - You can find it later by using the "log" command. - - <ReleaseTag> 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 <repos> 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 <PreviousReleaseTag> -j <ReleaseTag> - or - cvs update -j <VendorTag:yesterday> -j <VendorTag> - - 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 <PreviousReleaseTag> <ReleaseTag>", - 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 <pre-import-tag> <post-commit-tag>". - 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 <file>: 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 <message> go when the file doesn't change? - - The <message> 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 <ReleaseTag> 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 <head-of-vendor-tree> - 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 <head-of-vendor-tree> - 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 <rev1> and <rev2> 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<rev1>:<rev2> <file> - - If you want all the revisions on the branch from <rev1> to the end - of the branch <rev1> is on, you can use: - - cvs log -r<rev1>: <file> - - (If <rev1> 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 <rev2> is on up to revision <rev2>, you can use: - - cvs log -r:<rev2> <file> - - - Note: Depending on whether <rev1> and <rev2> 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<rev> <file> - - where <rev> 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<branch_tag> <file> - - 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 <rev/tag> -r <rev/tag> <file1> . . . - - 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 <date>" 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 <oldtag>", files with <oldtag> - 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 <tag1> <tag2>" actually put the tag on? - 3M.4 What happens if the tags are the same in "rtag -r <tag> <tag>"? - 3M.5 Why doesn't "rtag -b -r <branch_tag1> <branch_tag2>" 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 <tag1> <tag2>" 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 <tag/rev>" option. - - Depending on whether <tag1> is a <branch_tag>, or a non-branch - <tag> and on whether you use the '-b' option to "rtag", you get - four different results: - - 1. rtag -r <tag1> <tag2> - - Adds the non-branch tag <tag2> to the same revision that the - non-branch tag <tag1> is attached to. - - Example: - <tag1> --> TT1 - <tag2> --> TT2 - <file> --> Symbols: TT1:1.4 - After --> Symbols: TT1:1.4,TT2:1.4 - - - 2. rtag -r <branch_tag1> <tag2> - - Adds the non-branch tag <tag2> to the HEAD of (the highest - revision number on) the branch labelled with tag <branch_tag1>. - - Example: - <branch_tag1> --> BR1 - <tag2> --> TT2 - <file> --> 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 <branch_tag1> has not been created, - then the tag shows up on the branch point revision: - - Example: - <branch_tag1> --> BR1 - <tag2> --> TT2 - <file> --> 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 <tag1> <branch_tag2> - - Adds the magic branch tag <branch_tag2> to the revision that - the non-branch tag <tag1> is attached to, preparing it to be a - branch point. - - Example: - <tag1> --> TT1 - <branch_tag2> --> BR2 - <file> --> Symbol: TT1:1.4 - After --> Symbol: TT1:1.4, BR2:1.4.0.2 - - - 4. rtag -b -r <branch_tag1> <branch_tag2> - - Adds the magic branch tag <branch_tag2> to the revision at the - HEAD of (the highest revision number on) the branch labelled - with <branch_tag1>, preparing it to be a branch point. - - Example: - <branch_tag1> --> BR1 - <branch_tag2> --> BR2 - <file> --> 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 <branch_tag1> has not been created, - then the tag shows up as a second branch off the same - branch point revision: - - Example: - <branch_tag1> --> BR1 - <tag2> --> TT2 - <file> --> 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 <tag2> already exists on the file, you - get an error unless you specify the '-F' option. - - In all four cases, if <tag1> does not exist on the file, <tag2> is - not added unless you specify the '-f' option. - - - 3M.4 What happens if the tags are the same in "rtag -r <tag> <tag>"? - - Again, there are four cases depending on whether <tag> is a - branch tag, or a non-branch tag and on whether you use the - '-b' option to "rtag": - - 1. rtag -r <tag> <tag> - - Is a no-op. It does nothing even with '-F' specified. - - If you add the '-f' option ("rtag -f -r <tag> <tag>"), then - <tag> is attached to the latest revision on the Main Branch if - the file does *not* already have <tag> on some revision. - - If the <tag> is already on the file, using "rtag -f" is still - a no-op. - - - 2. rtag -r <branch_tag> <branch_tag> - - Produces an error, since the <branch_tag> is already on some - revision of the file. - - But, "rtag -F -r <branch_tag> <branch_tag>" 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 <tag> <tag> - - Produces an error, since the <tag> is already on the file. - - But, "rtag -F -b -r <tag> <tag>" 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 <branch_tag> <branch_tag> - - Produces an error, since the <branch_tag> is already on the - file. - - But, "rtag -F -b -r <branch_tag> <branch_tag>" 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 <branch_tag1> <branch_tag2>" 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 <tag>" in my working directory, why doesn't "checkout - -r <tag>" 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 <tag>? - - - **** 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 <tag>, 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 <oldtag>" option to retag an - existing tag. The "tag" command does not. - - 4. How it is logged. - - Currently "rtag" records the <tag> 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 <tag> 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* <-*- <tag> - 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 <tag> 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 <tag> 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 <tag>" in my working directory, why doesn't "checkout - -r <tag>" somewhere else produce copies of my current files? - - The only reason this would fail, other than misspelling the <tag> - 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 <tag>? - - For a procedure to rename a branch tag, See section 4D.5 - The following covers only non-branch tags. - - First, pick a <newtag> 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 <newtag> only on revisions attached to - <oldtag> in the whole Repository, then delete the old one. - - cvs rtag -r <oldtag> <newtag> world - cvs rtag -d <oldtag> world. - - - You can also checkout or update your working directory to the - <oldtag> and "tag" rather than "rtag" the result. But that - will take longer and it has the chance of producing conflicts. - - cvs update -r <oldtag> - cvs tag <newtag> - cvs tag -d <oldtag> - cvs update -A (or cvs update -r <previous_tag>) - - ----------------- --- 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 <branch_tag> {optional files} - - If you want to grab the changes made between two tags or - revisions, you type: - - cvs update -j <tag1> -j <tag2> {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 <branch_tag> {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 <branch_tag>. You may specify any revision or <tag> - with '-r' and get the specified revision or the tagged - revision: - - cvs update -r <tag/rev> {optional files} - - Or you may specify any date with '-D': - - cvs update -D <date> {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 <tag> or <date> 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 <tag>" or "-D <date>" 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 <file> 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: - - <<<<<<< <file> The working <file> in question. - 7777 Change made to the working <file>. - ======= - 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 <tag>" some time ago, then - removed <tag> from the Repository files. "update -r <tag>" will - delete a file that doesn't contain <tag>. - - 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 <the_tag_you_want> - - Another way to make a file disappear is to execute "update -D - <date>" where <date> 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 <command> 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 - <command>. If <command> exits with a non-zero - status, the commit is blocked. - - A <command> associated with a pathname of - "DEFAULT" is executed if nothing else matches. - Every <command> 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 <command> 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 <command> is expected to read a log message - from its standard input. The <command> 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 <dir> - - - 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 <tag>" 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 <tag>" produces the correct files. - - - The duplicated revision history can be slightly misleading. - - - A plain (i.e. without the "-r <tag>") "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 <tag>" 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 <tag> - onto the new, more sophisticated, revision of the Makefile. - (Yes, this changes the "released" file if <tag> 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 <tag> or <date>. - - - 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.<pid>") - - 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 <tag>"? - 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 <branch_tag>" 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 <branch_point_tag> module - 2. cvs rtag -b -r <branch_point_tag> <branch_tag> <module> - 3. cvs checkout -r <branch_tag> 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 <branch_point_tag> - 2. cvs rtag -b -r <branch_point_tag> <branch_tag> <module> - 3. cvs update -r <branch_tag> - - - 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 <oldtag> <newtag>" applies <newtag> to the - same revision that <oldtag> 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 - <branch_tag>" instead of the "rtag" command. - - 2. The <module> can be a relative path to a directory - from which your working directory was checked out. - - If you have trouble figuring out what <module> 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 <branch_tag> 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 <tag> is a unique string and you don't use the '-f' - option to "rtag -r", "rtag" will only add a <tag> to files in - which it actually *finds* the earlier <tag>. - - In each procedure above, Step #3 may occur any time after step 2. - Unless you explicitly remove them with "tag -d", a <tag> is - permanent. - - - The <branch_tag> 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 <branch_point_tag> and - <branch_tag> names. But keep in mind that the <branch_tag> 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 <branch_point_tag> is some modification of - the <branch_tag>.) - - <branch_point_tag> Matching <branch_tag> - - 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_<branch_point_tag>". (You can substitute what - ever you like for "latest_", as long as your <branch_tag> is some - modification of the <branch_point_tag>.) - - <branch_point_tag> Matching <branch_tag> - - 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 <branch_point_tag> -r <branch_tag> - - For Style 1, this is: - - cvs diff -r bp_<branch_tag> -r <branch_tag> - - For Style 2, this is: - - cvs diff -r <branch_point_tag> -r latest_<branch_point_tag> - - - Notes on "being on a branch": - - - "update -r <tag>" 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" <tag> (including a <branch_tag>) causes most CVS - commands to act as if "-r <tag>" were on the command line. - - - A "sticky" <branch_tag> 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 <branch_tag> <module> - cd <module> - - If you already have a working directory: - - cd <working_directory> - cvs update <== Optional, to bring it up to date. - cvs update -j <branch_tag> - - 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 <branch_tag> {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 <branch_tag> 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 <tags> using - two "-j" options on "update" or "checkout". - - Identify the two tags on the branch you want to merge from. - - cvs update -j <tag1> -j <tag2> {optional files} - - This step assumes you were careful about tagging milestones. - You can use this technique for any two <tags> 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 <tags>, you can use a <branch_tag> 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 <branch_tag> {optional files} - cvs commit - cvs tag -F -b <same_branch_tag> {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 - <branch_tag>:<date> 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_tag> 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_tag> branch. - - The other choice, which I would suggest, is to re-tag the file - with <branch_tag>, restoring a normal-looking magic branch tag - to the file: - - cvs tag -F -b <branch_tag> <file> - - - After you have done the above, you can run "update -A" or "update - -r <branch_tag>" 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 <branch_tag> - - - 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 <branch_tag> 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 <tag>" 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 <module> - cd <module> - cvs tag -b <branch_tag> - cvs update -r <branch_tag> - >>> 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 <branch_tag> - >>> 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 <branch_tag> <module> - cd <module> - - - B. The paranoid way is more difficult, but it can catch all sorts - of problems. You created the branch this way: - - cvs checkout <module> - cd <module> - cvs tag <branch_point_tag> - cvs tag -b <branch_tag> - cvs update -r <branch_tag> - >>> 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 <latest_on_branch_tag> - cvs update -A - *1* cvs diff -r <branch_point_tag> -r <latest_on_branch_tag> - >>> *1* shows all the changes on the branch. - *2* cvs diff -r <branch_point_tag> -r HEAD - >>> *2* shows the changes on the trunk since branching. - cvs tag <premerge_tag> - cvs update -j <branch_tag> - >>> Edit the 'C' files and remove the overlaps. - *3* cvs diff - >>> Verify that *3* matches *1*, except for line numbers. - cvs commit - cvs tag <just_merge_changes_tag> - >>> Edit some more to make it all compile and work. - cvs commit - cvs tag <after_merge_cleanup_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 <rev>" 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 <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 <non-branch-tag>" - - Doing this overrides the sticky <branch_tag> 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 <branch_tag>". - - 2. Use the "update -r <branch_tag>:<date>" trick. - - This is almost like using the '-D' option, but it looks for - revisions extant on <date> 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 <tag>" where <tag> - 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 <branch_tag> <<== To tag the current files. - cvs update -r <branch_tab> <<== To move onto the branch. - - B. You can do it "externally" and create a new working directory: - - cvs rtag -b -r <tag> <branch_tag> <module> - cvs checkout -r <branch_tag> <module> - - <module> can be a relative path within the Repository. - - <tag> in the above is the non-branch tag you placed earlier - that caused the error in your question. Be warned that - if <tag> 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 <tag>"? - - If "update -r <tag>" always retrieves the latest files on a - branch, then <tag> is really a <branch_tag>. 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 - <branch_tag> 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 <branch_tag> $i > $i - end - - 3. Commit all the working files onto the Main Branch. - - cvs commit -m 'Moved branch <branch_tag> 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<tag> <file> - - 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 <file>. - - a. Use "update" to grab the revision you want, then - execute a normal "tag" command to Tag that revision: - - cvs update -r <rev> <file> - cvs tag <tag> <file> - - b. Use "admin" to set the tag to a specific revision: - - cvs admin -N<tag>:<rev> <file> - - - 4D.5 How do I move or rename a magic branch tag? - - (To rename a non-branch <tag> 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 <branch_tag> is an artificial tag attached to a - non-existent revision on a non-existent branch number zero. It - looks like this: - - TAG1:<X>.0.Y - - <X> 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 <X>. The - first "update -r TAG1 <file>" after applying TAG1 will produce - a copy of revision <X> with a sticky tag of TAG1. The first - "commit" to that file will cause CVS to construct an RCS branch - named <X>.Y and check in revision <X>.Y.1 on the new branch. - - Note: TAG1 is *not* considered to be attached to <X> by RCS, - which explains why you can't refer directly to the branch point - revision for some CVS commands. - - - B. Moving a magic <branch_tag> is the act of reapplying the same - tag to different revisions in the file: - - TAG1:<X>.0.Y - to - TAG1:<X>.0.Z or TAG1:<A>.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 <branch_tag>. - - cvs update -r <tag/rev> (or '-A' for the Main Branch) - cvs tag -F -b <branch_tag> - - 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 (<X>), the "tag" command above will create the tag: - - TAG1:<X>.0.Z - - Where Z is 2 greater than the highest magic branch already on - revision <X>. The TAG1 branch will still have the same branch - point (i.e. revision <X>), but the first commit to the new TAG1 - branch will create a different RCS branch number (<X>.Z instead - of <X>.Y). - - - C. Renaming a magic <branch_tag> is the act of changing - - TAG1:<X>.0.Y - to - TAG2:<X>.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 - <other_tag>" 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 <old_branch_tag> <new_branch_tag> - - 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<new_branch_tag>:<old_branch_tag> . - cvs tag -d <old_branch_tag> - - 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 <old_branch_tag>" would interpret - <old_branch_tag> 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 <branch_tag> 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 <command> - - - 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 <command>". The - visually similar command "cvs <command> -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: <X> is not (any longer) pertinent - 4E.6 Why did a Repository file change from <file>,v to ,<file>,? - - - **** 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: <X> is not (any longer) pertinent - - This message occurs in three instances: - - 1. When there is an entry in the ./CVS/Entries for file <X> 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 `<module/path>' - 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 <file>,v to ,<file>,? - - This is an RCS problem, since the ,<file>, syntax for file names - is used by RCS and not CVS. - - RCS constructs a new <file>,v in a temporary file named ,<file>, - (which doubles as a lock file) then renames it to <file>,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 <file>,v; ln ,<file>, <file>,v; rm ,<file>, - - 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>, 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 ,<file>, exists, rename it to <file>,v. - - - If both ,<file>, and <file>,v exist and are linked, remove the - ,<file>, file. - - - If both ,<file>, and <file>,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 - <grdodson@lexmark.com>, 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 <file> - - #!/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. ./<file> 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 <file> 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, <Bob_Vadnais@pdh.com> 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 <linstee@dutecaj.et.tudelft.nl> 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 #!/<some shell> 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 <berliner@sun.com> converted a collection of - scripts written by Dick Grune <dick@cs.vu.nl> into a C program, - then added all sorts of features. He continues to maintain CVS. - - Jeff Polk <polk@bsdi.com> wrote much of the code added between - revisions 1.2 and 1.3. Many others were involved at some level. - - david d zuhn <zoo@armadillo.com> 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 <berliner@sun.com>, CVS maintainer. - Paul Eggert <eggert@twinsun.com>, RCS maintainer. - - Gray Watson <gray@antaire.com> - Per Cederqvist <ceder@signum.se> - Pete Clark <pclark@is.com> - - 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 <amanda@iesd.auc.dk> - Donald Amby <amby@mixcom.mixcom.com> - Mark D Baushke <mdb@cisco.com> - Jim Blandy <jimb@cyclic.com> - Tom Cunningham <tomc@bouwsma,sps.mot.com> - Graydon Dodson <grdodson@lexmark.com> - Joe Drumgoole <joed@splatter.demon.co.uk> - Don Dwiggins <dwig@markv.com> - Bryant Eastham <bryant@ced.utah.edu> - Dan Franklin <dan@diamond.bbn.com> - Michael Ganzberger <ganzbergermd@ES.net> - Steve Harris <vsh%etnibsd@uunet.uu.net> - Erik van Linstee <linstee@dutecaj.et.tudelft.nl> - Jeffrey M Loomis <jml@world.std.com> - Barry Margolin <barmar@near.net> - Mark K. Mellis <mkm@ncd.com> - Chris Moore <Chris.Moore@src.bae.co.uk> - Gary Oberbrunner <garyo@avs.com> - Steve Turner <stevet@carrier.sps.mot.com> - Dave Wolfe <dwolfe@pffft.sps.mot.com> - Dale Woolridge <dwoolridge@cid.aes.doe.ca> - - - - 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 <date>", 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 <date>" 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 <date>", 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 <date>: - - 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 <tag>, or even "-r HEAD" than to use a - date spec. - - If you must use "-D <date>", 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 <date>" 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 <branch_tag>:<date>" 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 <Paul_Kunz@slac.stanford.edu> 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: <info@cyclic.com> - 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 <module> 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 .#<file>.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 `<file>' - 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 <tag/rev>" 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 <tag/rev>" and - "cvs history -t <tag>"? - 3G.8 Why does "cvs history -c -t <tag>" 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 <file>: Permission denied - 3H.15 Where does the -m <message> 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 <tag1> <tag2>" actually put the tag on? - 3M.4 What happens if the tags are the same in "rtag -r <tag> <tag>"? - 3M.5 Why doesn't "rtag -b -r <branch_tag1> <branch_tag2>" 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 <tag>" in my working directory, why doesn't "checkout - -r <tag>" 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 <tag>? - ----------------- --- 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 <tag>"? - 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: <X> is not (any longer) pertinent - 4E.6 Why did a Repository file change from <file>,v to ,<file>,? - ----------------- --- 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 <date>", 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 <date>" 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: diff --git a/gnu/usr.bin/cvs/INSTALL b/gnu/usr.bin/cvs/INSTALL deleted file mode 100644 index 898af66..0000000 --- a/gnu/usr.bin/cvs/INSTALL +++ /dev/null @@ -1,356 +0,0 @@ -#ident "$CVSid$" - -First, read the README file. If you're still happy... - -CVS has been tested on the following platforms. The most recent -version of CVS reported to have been tested is indicated, but more -recent versions of CVS probably will work too. Please send updates to -this list to info-cvs@prep.ai.mit.edu. - -Alpha: - DEC Alpha running OSF/1 version 1.3 using cc (about 1.4A2) - DEC Alpha running OSF/1 version 2.0 (1.4.90) - DEC Alpha running OSF/1 version 2.1 (about 1.4A2) - 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 (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) -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.6.2 client-only) - FreeBSD 2.0.5, i486, gcc (1.5.95) - NextSTEP 3.3 (1.4.92, a few tweaks needed) - SCO Unix 3.2.4.2 (1.4.93) (footnote 4) - SCO OpenServer 5.0.0, "CC='cc -b elf' configure" -m68k: - Sun 3 running SunOS 4.1.1_U1 w/ bundled K&R /usr/5bin/cc (1.6) - NextSTEP 3.3 (1.4.92, a few tweaks needed) -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) - 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 4.1 using gcc and cc (about 1.4A2) (footnote 1) -SPARC: - Sun SPARC running SunOS 4.1.4 w/ bundled K&R /usr/5bin/cc (1.6) - 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 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) - Sun SPARC running Solaris 2.5 (2.5 beta?) (1.6.2) - NextSTEP 3.3 (1.4.92, a few tweaks needed) - -(footnote 1) - AIX 4.1 systems fail to run "configure" due to bugs in their - "/bin/sh" implementation. You might want to try feeding the - configure script to "bash" ported to AIX 4.1. (about 1.4A2). - -(footnote 2) - Some Irix 4.0 systems may core dump in malloc while running - CVS. We believe this is a bug in the Irix malloc. You can - workaround this bug by linking with "-lmalloc" if necessary. - (about 1.4A2). - -(footnote 3) - There are some warnings about pointer casts which can safely be - ignored. (about 1.4.90). - -(footnote 4) Comment out the include of sys/time.h in src/server.c. (1.4.93) - You also may have to make sure TIME_WITH_SYS_TIME is undef'ed. - -(footnote 5) Change /usr/tmp to /var/tmp in src/server.c (2 places) (1.4.93). - -(footnote 6) Build in ucb universe with COFF compiler tools. Put - /usr/local/bin first in PATH while doing a configure, make - and install of GNU diffutils-2.7, rcs-5.7, then cvs-1.5. - -(footnote 7) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports - success with this configure command: - CC=cc CFLAGS='-O2 -Olimit 2000 -std1' ./configure --verbose alpha-dec-osf - -(footnote 8) Manoj Srivastava <srivasta@pilgrim.umass.edu> reports - success with this configure command: - CC=cc CFLAGS='+O2 -Aa -D_HPUX_SOURCE' ./configure --verbose hppa1.1-hp-hpux - -------------------------------------------------------------------------------- - -Installation under Unix: - -1) Run "configure": - - $ ./configure - - You can specify an alternate destination to override the default with - the --prefix option: - - $ ./configure --prefix=/usr/local/gnu - - or some path that is more appropriate for your site. The default prefix - value is "/usr/local", with binaries in sub-directory "bin", manual - pages in sub-directory "man", and libraries in sub-directory "lib". - - 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.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 - - Configure will also try to find a version of grep that supports the - '-s' option, and tries to find the GNU Grep version first. You can - similarly tell it where to find GNU Grep: - - $ ./configure --with-gnugrep - $ ./configure --with-gnugrep=/usr/gnu/bin/grep - - 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). Configure does not yet check to see if you've got this, so - be careful! - - 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. - - 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 - CVS to work in a heterogeneous environment. However, if you have - a very large modules database, this may not work well. You will - need to edit src/options.h to turn off the MY_NDBM #define and - re-run configure. If you do this, the following comments apply. - If not, you may safely skip these comments. - - If you configure CVS to use the real ndbm(3) libraries and - you do not have them installed in a "normal" place, you will - probably want to get the GNU version of ndbm (gdbm) and install - that before running the CVS configure script. Be aware that the - GDBM 1.5 release does NOT install the <ndbm.h> header file included - with the release automatically. You may have to install it by hand. - - If you configure CVS to use the ndbm(3) libraries, you cannot - compile CVS with GNU cc (gcc) on Sun-4 SPARC systems. However, gcc - 2.0 may have fixed this limitation if -fpcc-struct-return is - defined. When using gcc on other systems to compile CVS, you *may* - need to specify the -fpcc-struct-return option to gcc (you will - *know* you have to if "cvs checkout" core dumps in some ndbm - function). You can do this as follows: - - $ CC='gcc -fpcc-struct-return' ./configure - - for sh, bash, and ksh users and: - - % setenv CC 'gcc -fpcc-struct-return' - % ./configure - - for csh and tcsh users. - - END OF NOTE FOR NDBM GUNK. - -2) Edit src/options.h. Appropriate things to look at may be the - invocation locations of programs like DIFF, GREP, RM, and SORT. - Also glance at the default values for the environment variables - that CVS uses, in particular, the RCSBIN variable, which holds the - path to where the RCS programs live on your system. The - likelihood is that you don't have to change anything here, except - perhaps adding the -a option to DIFF if you are using GNU diff. - -3) Try to build it: - - $ make - - This will (hopefully) make the needed CVS binaries within the "src" - directory. If something fails for your system, using the "cvsbug" - script submit your "config.status" file together with your host - type, operating system and compiler information, make output, and - anything else you think will be helpful. - - 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, - using the "cvsbug" script please submit your "config.status" file, - together with your host type, operating system and compiler - information, the contents of /tmp/cvs-sanity/check.log, and any - "make check" output. - -4) Install the binaries/documentation: - - $ make install - - Depending on your installation's configuration, you may need to be - root to do this. - -5) Take a look at the CVS documentation. - - $ man cvs - - and - - $ info cvs - - See what it can do for you, and if it fits your environment (or can - possibly be made to fit your environment). If things look good, - continue on... - -6) Setup the master source repository. Choose a directory with ample disk - space available for source files. This is where the RCS ",v" files - will be stored. Note that this should be some shared directory for your - site. It should probably be auto-mounted, if you're running NFS. - - Say you choose "/src/master" as the root of your source repository. - Run the "cvsinit" script to help you set it up. It will ask you to - enter the path to your CVSROOT area. You would enter /src/master in - this example. - - $ ./cvsinit - - The cvsinit script will setup a reasonable CVSROOT area to start with. - It is also valuable to folks who already have a CVSROOT area setup from - using earlier releases of CVS. It assumes that you have installed CVS - already (step 4) and that the RCS programs (co and ci) are in your - 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 file; or in the - site-wide /etc/profile: - - CVSROOT=/src/master; export CVSROOT - - for sh/bash/ksh users, or place the following commands in the user's - ~/.cshrc, ~/.login, or /etc/chsrc file: - - setenv CVSROOT /src/master - - for csh/tcsh users. If these environment variables are not already set - in your current shell, set them now (or source the login script you - just edited). You will need to have the CVSROOT environment variable - set to continue on to the next step. - -8) It might be a good idea to jump right in and put the CVS distribution - directly under CVS control. From within the top-level directory of the - CVS distribution (the one that contains this README file) do the - following commands: - - $ make distclean - $ 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: - - $ cd - $ cvs checkout cvs - - This will make the directory "cvs" in your current directory and - populate it with the appropriate CVS files and directories. - -10) Remember to edit the modules file manually when sources are checked in - with "cvs import" or "cvs add". A copy of the modules file for editing - can usually be retrieved with the "cvs checkout modules" command, and - definitely with the "cvs checkout CVSROOT" command. See cvs(5). - -11) Read the NEWS file to see what's new. - -12) Hack away. - -------------------------------------------------------------------------------- - -Detailed information about your interaction with "configure": - -The "configure" script and its interaction with its options and the -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 - various pieces of CVS (/usr/local). - --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. - --with-gnugrep[=PATH] Assume use of GNU grep 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 - "./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. - YACC If not set, tries to determine if "bison" - is available, choosing "yacc" if it doesn't - appear to be. - -------------------------------------------------------------------------------- -Installation under Windows NT: - -You may find interesting information in windows-NT/README. - -1) Using Microsoft Visual C++ version 2.1, open the project `cvsnt.mak', - in the top directory of the CVS distribution. -2) Choose "Build cvs.exe" from the "Project" menu. -3) MSVC will place the executable file cvs.exe in WinDebug, or whatever - your target directory is. -------------------------------------------------------------------------------- diff --git a/gnu/usr.bin/cvs/MINOR-BUGS b/gnu/usr.bin/cvs/MINOR-BUGS deleted file mode 100644 index 7b85719..0000000 --- a/gnu/usr.bin/cvs/MINOR-BUGS +++ /dev/null @@ -1,60 +0,0 @@ -Low-priority bugs go here. We don't have many yet -- everything is -high-priority at the moment. :-) - - -* From: Jeff Johnson <jbj@brewster.JBJ.ORG> - To: cyclic-cvs@cyclic.com - Subject: Named_Root assumes . on server - Date: Wed, 17 May 1995 11:04:53 -0400 (EDT) - - Problem: - On server, Name_Root() attempts (aggressively) to set CVSADM_Root. - If ~/CVS/Root exists (wrto rsh login), then CVSADM_Root will be - initialized from that file. The sanity check between the root - repository and the invocation will fail if the two values are not - coincidentally the same. - - Workaround: - There's a zillion ways to fix this bugture/featurelet. My current - workaround is to remove ~/CVS/Root on the server. I shall attempt - a better fix as soon as I can determine what appears politically - correct. IMHO, the CVS/Root stuff (and getenv("CVSROOT") also) is - a bit fragile and tedious in an rcmd() driven CCVS environment. - - -* (Jeff Johnson <jbj@jbj.org>) - I tried a "cvs status -v" and received the following: - - ? CVS - ? programs/CVS - ? tests/CVS - cvs server: Examining . - =================================================================== - File: Install.dec Status: Up-to-date - ... - - I claim that CVS dirs should be ignored. - - -* I sometimes get this message: - - Could not look up address for your host. Permission denied. - cvs [update aborted]: premature end of file from server - - The client's response should be cleaned up. - -* In the gb-grep module, update-ChangeLog (and therefore, I assume, - rcs2log) truncates file names --- I get entries for things called - ring/lenstring.h instead of lenstring/lenstring.h. - -* On remote checkout, files don't have the right time/date stamps in - the CVS/Entries files. Doesn't look like the C/S protocol has any - way to send this information along (according to cvsclient.texi). - Perhaps we can spiff it up a bit by using the conflict field for the - stamp on the checkout/update command. Please note that this really - doesn't do very much for us even if we get it done. - -* Does the function that lists the available modules in the repository - belong under the "checkout" function? Perhaps it is more logically - grouped with the "history" function or we should create a new "info" - function? diff --git a/gnu/usr.bin/cvs/Makefile b/gnu/usr.bin/cvs/Makefile index a9b43ae..a15127d 100644 --- a/gnu/usr.bin/cvs/Makefile +++ b/gnu/usr.bin/cvs/Makefile @@ -1,5 +1,5 @@ -# $Id: Makefile,v 1.6 1995/04/14 15:15:27 nate Exp $ +# $Id: Makefile,v 1.7 1995/12/10 22:58:29 peter Exp $ -SUBDIR = lib cvs mkmodules contrib cvsbug cvsinit doc examples +SUBDIR = lib cvs contrib cvsbug doc tools .include <bsd.subdir.mk> diff --git a/gnu/usr.bin/cvs/Makefile.inc b/gnu/usr.bin/cvs/Makefile.inc index c153243..daeb274 100644 --- a/gnu/usr.bin/cvs/Makefile.inc +++ b/gnu/usr.bin/cvs/Makefile.inc @@ -1,3 +1,7 @@ +.if !defined(CVSDIR) + +CVSDIR= $(.CURDIR)/../../../../contrib/cvs + .if exists(${.OBJDIR}/../lib) LIBDESTDIR= ${.OBJDIR}/../lib .else @@ -6,3 +10,9 @@ LIBDESTDIR= ${.CURDIR}/../lib LDDESTDIR= -L${LIBDESTDIR} LIBCVS= ${LIBDESTDIR}/libcvs.a + +.if exists(${.CURDIR}/../../Makefile.inc) +.include "${.CURDIR}/../../Makefile.inc" +.endif + +.endif diff --git a/gnu/usr.bin/cvs/NEWS b/gnu/usr.bin/cvs/NEWS deleted file mode 100644 index 8965819..0000000 --- a/gnu/usr.bin/cvs/NEWS +++ /dev/null @@ -1,863 +0,0 @@ -Changes since 1.6: - -* RCS keyword "Name" supported for "cvs update -r <tag>" and "cvs -checkout -r <tag>". - -* 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". - -* 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 name .cvsrc now matches 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'"). - -Changes from 1.5 to 1.6: - -* Del updated the man page to include all of the new features -of CVS 1.6. - -* "cvs tag" now supports a "-r | -D" option for tagging an already -tagged revision / specific revision of a file. - -* There is a "taginfo" file in CVSROOT that supports filtering and -recording of tag operations. - -* Long options support added, including --help and --version options. - -* "cvs release" no longer cares whether or not the directory being -released has an entry in the `modules' file. - -* The modules file now takes a -e option which is used instead of -o -for "cvs export". If your modules file has a -o option which you want -to be used for "cvs export", change it to specify -e as well as -o. - -* "cvs export" now takes a -k option to set RCS keyword expansion. -This way you can export binary files. If you want the old behavior, -you need to specify -kv. - -* "cvs update", "cvs rdiff", "cvs checkout", "cvs import", "cvs -release", "cvs rtag", and "cvs tag" used to take -q and -Q options -after the command name (e.g. "cvs update -q"). This was confusing -because other commands, such as "cvs ci", did not. So the options -after the command name have been removed and you must now specify, for -example, "cvs -q update", which has been supported since CVS 1.3. - -* New "wrappers" feature. This allows you to set a hook which -transforms files on their way in and out of cvs (apparently on the -NeXT there is some particular usefulness in tarring things up in the -repository). It also allows you to declare files as merge-by-copy -which means that instead of trying to merge the file, CVS will merely -copy the new version. There is a CVSROOT/cvswrappers file and an -optionsl ~/.cvswrappers file to support this feature. - -* You can set CVSROOT to user@host:dir, not just host:dir, if your -username on the server host is different than on the client host. - -* VISUAL is accepted as well as EDITOR. - -* $CVSROOT is expanded in *info files. - -Changes from 1.4A2 to 1.5: - -* Remote implementation. This is very helpful when collaborating on a -project with someone across a wide-area network. This release can -also be used locally, like other CVS versions, if you have no need for -remote access. - -Here are some of the features of the remote implementation: -- It uses reliable transport protocols (TCP/IP) for remote repository - access, not NFS. NFS is unusable over long distances (and sometimes - over short distances) -- It transfers only those files that have changed in the repository or - the working directory. To save transmission time, it will transfer - patches when appropriate, and can compress data for transmission. -- The server never holds CVS locks while waiting for a reply from the client; - this makes the system robust when used over flaky networks. - -The remote features are documented in doc/cvsclient.texi in the CVS -distribution, but the main doc file, cvs.texinfo, has not yet been -updated to include the remote features. - -* Death support. See src/README-rm-add for more information on this. - -* Many speedups, especially from jtc@cygnus.com. - -* CVS 1.2 compatibility code has been removed as a speedup. If you -have working directories checked out by CVS 1.2, CVS 1.3 or 1.4A2 will -try to convert them, but CVS 1.5 and later will not (if the working -directory is up to date and contains no extraneous files, you can just -remove it, and then check out a new working directory). Likewise if -your repository contains a CVSROOT.adm directory instead of a CVSROOT -directory, you need to rename it. - -Fri Oct 21 20:58:54 1994 Brian Berliner <berliner@sun.com> - - * Changes between CVS 1.3 and CVS 1.4 Alpha-2 - - * A new program, "cvsbug", is provided to let you send bug reports - directly to the CVS maintainers. Please use it instead of sending - mail to the info-cvs mailing list. If your build fails, you may - have to invoke "cvsbug" directly from the "src" directory as - "src/cvsbug.sh". - - * A new User's Guide and Tutorial, written by Per Cederqvist - <ceder@signum.se> of Signum Support. See the "doc" directory. A - PostScript version is included as "doc/cvs.ps". - - * The Frequesntly Asked Questions file, FAQ, has been added to the - release. Unfortunately, its contents are likely out-of-date. - - * The "cvsinit" shell script is now installed in the $prefix/bin - directory like the other programs. You can now create new - CVS repositories with great ease. - - * Index: lines are now printed on output from 'diff' and 'rdiff', - in order to facilitate application of patches to multiple subdirs. - - * Support for a ~/.cvsrc file, which allows you to specify options - that are always supposed to be given to a specific command. This - feature shows the non-orthogonality of the option set, since while - there may be an option to turn something on, the option to turn - that same thing off may not exist. - - * You can now list subdirectories that you wish to ignore in a - modules listing, such as: - - gcc -a gnu/gcc, !gnu/gcc/testsuites - - which will check out everything underneath gnu/gcc, except - everything underneath gnu/gcc/testsuites. - - * It is now much harder to accidentally overwrite an existing tag - name, since attempting to move a tag name will result in a error, - unless the -F (force) flag is given to the tag subcommands. - - * Better error checking on matching of the repository used to - check code out from against the repository the current cvs - commnands would use. (Thanks to Mark Baushke <mdb@cisco.com>) - - * Better support for sites with multiple CVSROOT repositories has - been contributed. The file "CVS/Root" in your working directory - is created to hold the full path to the CVS repository and a - simple check is made against your current CVSROOT setting. - - * You can now specify an RCS keyword substitution value when you - import files into the repository. - - * Uses a much newer version of Autoconf, and conforms to the GNU - coding standards much more closely. No, it still doesn't have - long option names. - - * Code cleanup. Many passes through gcc -Wall helped to identify - a number of questionable constructs. Most arbitrary length limits - were removed. - - * Profiling to determine bottlenecks helped to identify the best - places to spend time speeding up the code, which was then done. A - number of performance enhancements in filename matching have sped - up checkouts. - - * Many more contributions have been added to the "contrib" - directory. See the README file in that directory for more - information. - - * "cvs commit" will try harder to not change the file's - modification time after the commit. If the file does not change - as a result of the commit operation, CVS will preserve the - original modification time, thus speeding up future make-type - builds. - - * "cvs commit" now includes any removed files in the (optional) - pre-commit checking program that may be invoked. Previously, only - added and modified files were included. - - * It is now possible to commit a file directly onto the trunk at a - specific revision level by doing "cvs commit -r3.0 file.c", where - "3.0" specifies the revision you wish to create. The file must be - up-to-date with the current head of the trunk for this to succeed. - - * "cvs commit" will now function with a pre-commit program that - has arguments specified in the "commitinfo" file. - - * The "mkmodules" program will now look within the - $CVSROOT/CVSROOT/checkoutlist" file for any additional files that - should be automatically checked out within CVSROOT; mkmodules also - tries harder to preserve any execute bits the files may have - originally had. - - * "cvs diff" is much more accurate about its exit status now. It - now returns the maximum exit status of any invoked diff. - - * The "-I !" option is now supported for the import and update - commands correctly. It will properly clear the ignore list now. - - * Some problems with "cvs import" handling of .cvsignore have been - fixed; as well, some rampant recursion problems with import have - also been fixed. - - * "cvs rdiff" (aka "cvs patch") now tries to set the modify time - of any temporary files it uses to match those specified for the - particular revision. This allows a more accurate patch image to - be created. - - * "cvs status" has improved revision descriptions. "Working - revision" is used for the revision of the working file that you - edit directly; "Repository revision" is the revision of the file - with the $CVSROOT source repository. Also, the output is clearer - with regard to sticky and branch revisions. - - * CVS no longer dumps core when given a mixture of directories and - files in sub-directories (as in "cvs ci file1 dir1/file2"). - Instead, arguments are now clumped into their respective directory - and operated on in chunks, together. - - * If the CVSEDITOR environment variable is set, that editor is - used for log messages instead of the EDITOR environment variable. - This makes it easy to substitute intelligent programs to make more - elaborate log messages. Contributed by Mark D Baushke - (mdb@cisco.com). - - * Command argument changes: - cvs: The "-f" option has been added to ignore - the ~/.cvsrc file. - commit: Renamed the "-f logfile" option to the - "-F logfile" option. Added the "-f" - option to force a commit of the specified - files (this disables recursion). - history: Added "-t timezone" option to force any - date-specific output into the specified - timezone. - import: Added "-d" option to use the file's - modification time as the time of the - import. Added "-k sub" option to set the - default RCS keyword substitution mode for - newly-created files. - remove: Added "-f" option to force the file's - automatic removal if it still exists in - the working directory (use with caution). - rtag: Added "-F" option to move the tag if it - already exists -- new default is to NOT - move tags automatically. - tag: Added "-F" option to move the tag if it - already exists -- new default is to NOT - move tags automatically. - -Tue Apr 7 15:55:25 1992 Brian Berliner (berliner at sun.com) - - * Changes between CVS 1.3 Beta-3 and official CVS 1.3! - - * A new shell script is provided, "./cvsinit", which can be run at - install time to help setup your $CVSROOT area. This can greatly - ease your entry into CVS usage. - - * The INSTALL file has been updated to include the machines on - which CVS has compiled successfully. I think CVS 1.3 is finally - portable. Thanks to all the Beta testers! - - * Support for the "editinfo" file was contributed. This file - (located in $CVSROOT/CVSROOT) can be used to specify a special - "editor" to run on a per-directory basis within the repository, - instead of the usual user's editor. As such, it can verify that - the log message entered by the user is of the appropriate form - (contains a bugid and test validation, for example). - - * The manual pages cvs(1) and cvs(5) have been updated. - - * The "mkmodules" command now informs you when your modules file - has duplicate entries. - - * The "add" command now preserves any per-directory sticky tag when - you add a new directory to your checked-out sources. - - * The "admin" command is now a fully recursive interface to the - "rcs" program which operates on your checked-out sources. It no - longer requires you to specify the full path to the RCS file. - - * The per-file sticky tags can now be effectively removed with - "cvs update -A file", even if you had checked out the whole - directory with a per-directory sticky tag. This allows a great - deal of flexibility in managing the revisions that your checked-out - sources are based upon (both per-directory and per-file sticky - tags). - - * The "cvs -n commit" command now works, to show which files are - out-of-date and will cause the real commit to fail, or which files - will fail any pre-commit checks. Also, the "cvs -n import ..." - command will now show you what it would've done without actually - doing it. - - * Doing "cvs commit modules" to checkin the modules file will no - properly run the "mkmodules" program (assuming you have setup your - $CVSROOT/CVSROOT/modules file to do so). - - * The -t option in the modules file (which specifies a program to - run when you do a "cvs rtag" operation on a module) now gets the - symbolic tag as the second argument when invoked. - - * When the source repository is locked by another user, that user's - login name will be displayed as the holder of the lock. - - * Doing "cvs checkout module/file.c" now works even if - module/file.c is in the Attic (has been removed from main-line - development). - - * Doing "cvs commit */Makefile" now works as one would expect. - Rather than trying to commit everything recursively, it will now - commit just the files specified. - - * The "cvs remove" command is now fully recursive. To schedule a - file for removal, all you have to do is "rm file" and "cvs rm". - With no arguments, "cvs rm" will schedule all files that have been - physically removed for removal from the source repository at the - next "cvs commit". - - * The "cvs tag" command now prints "T file" for each file that was - tagged by this invocation and "D file" for each file that had the - tag removed (as with "cvs tag -d"). - - * The -a option has been added to "cvs rtag" to force it to clean - up any old, matching tags for files that have been removed (in the - Attic) that may not have been touched by this tag operation. This - can help keep a consistent view with your tag, even if you re-use - it frequently. - -Sat Feb 29 16:02:05 1992 Brian Berliner (berliner at sun.com) - - * Changes between CVS 1.3 Beta-2 and CVS 1.3 Beta-3 - - * Many portability fixes, thanks to all the Beta testers! With any - luck, this Beta release will compile correctly on most anything. - Hey, what are we without our dreams. - - * CVS finally has support for doing isolated development on a - branch off the current (or previous!) revisions. This is also - extremely nice for generating patches for previously released - software while development is progressing on the next release. - Here's an example of creating a branch to fix a patch with the 2.0 - version of the "foo" module, even though we are already well into - the 3.0 release. Do: - - % cvs rtag -b -rFOO_2_0 FOO_2_0_Patch foo - % cvs checkout -rFOO_2_0_Patch foo - % cd foo - [[ hack away ]] - % cvs commit - - A physical branch will be created in the RCS file only when you - actually commit the change. As such, forking development at some - random point in time is extremely light-weight -- requiring just a - symbolic tag in each file until a commit is done. To fork - development at the currently checked out sources, do: - - % cvs tag -b Personal_Hack - % cvs update -rPersonal_Hack - [[ hack away ]] - % cvs commit - - Now, if you decide you want the changes made in the Personal_Hack - branch to be merged in with other changes made in the main-line - development, you could do: - - % cvs commit # to make Personal_Hack complete - % cvs update -A # to update sources to main-line - % cvs update -jPersonal_Hack # to merge Personal_Hack - - to update your checked-out sources, or: - - % cvs checkout -jPersonal_Hack module - - to checkout a fresh copy. - - To support this notion of forked development, CVS reserves - all even-numbered branches for its own use. In addition, CVS - reserves the ".0" and ".1" branches. So, if you intend to do your - own branches by hand with RCS, you should use odd-numbered branches - starting with ".3", as in "1.1.3", "1.1.5", 1.2.9", .... - - * The "cvs commit" command now supports a fully functional -r - option, allowing you to commit your changes to a specific numeric - revision or symbolic tag with full consistency checks. Numeric - tags are useful for bringing your sources all up to some revision - level: - - % cvs commit -r2.0 - - For symbolic tags, you can only commit to a tag that references a - branch in the RCS file. One created by "cvs rtag -b" or from - "cvs tag -b" is appropriate (see below). - - * Roland Pesch <pesch@cygnus.com> and K. Richard Pixley - <rich@cygnus.com> were kind enough to contribute two new manual - pages for CVS: cvs(1) and cvs(5). Most of the new CVS 1.3 features - are now documented, with the exception of the new branch support - added to commit/rtag/tag/checkout/update. - - * The -j options of checkout/update have been added. The "cvs join" - command has been removed. - - With one -j option, CVS will 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, CVS will merge all changes made in - that branch into your working file). - - With two -j options, CVS will merge in the changes between the two - respective revisions. This can be used to "remove" a certain delta - from your working file. E.g., If the file foo.c is based on - revision 1.6 and I want to remove the changes made between 1.3 and - 1.5, I might do: - - % cvs update -j1.5 -j1.3 foo.c # note the order... - - In addition, each -j option can contain on 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, as in: - - -jSymbolic_Tag:Date_Specifier - - An example might be what "cvs import" tells you to do when you have - just imported sources that have conflicts with local changes: - - % cvs checkout -jTAG:yesterday -jTAG module - - which tells CVS to merge in the changes made to the branch - specified by TAG in the last 24 hours. If this is not what is - intended, substitute "yesterday" for whatever format of date that - is appropriate, like: - - % cvs checkout -jTAG:'1 week ago' -jTAG module - - * "cvs diff" now supports the special tags "BASE" and "HEAD". So, - the command: - - % cvs diff -u -rBASE -rHEAD - - will effectively show the changes made by others (in unidiff - format) that will be merged into your working sources with your - next "cvs update" command. "-rBASE" resolves to the revision that - your working file is based on. "-rHEAD" resolves to the current - head of the branch or trunk that you are working on. - - * The -P option of "cvs checkout" now means to Prune empty - directories, as with "update". The default is to not remove empty - directories. However, if you do "checkout" with any -r options, -P - will be implied. I.e., checking out with a tag will cause empty - directories to be pruned automatically. - - * The new file INSTALL describes how to install CVS, including - detailed descriptions of interfaces to "configure". - - * The example loginfo file in examples/loginfo has been updated to - use the perl script included in contrib/log.pl. The nice thing - about this log program is that it records the revision numbers of - your change in the log message. - - Example files for commitinfo and rcsinfo are now included in the - examples directory. - - * All "#if defined(__STDC__) && __STDC__ == 1" lines have been - changed to be "#if __STDC__" to fix some problems with the former. - - * The lib/regex.[ch] files have been updated to the 1.3 release of - the GNU regex package. - - * The ndbm emulation routines included with CVS 1.3 Beta-2 in the - src/ndbm.[ch] files has been moved into the src/myndbm.[ch] files - to avoid any conflict with the system <ndbm.h> header file. If - you had a previous CVS 1.3 Beta release, you will want to "cvs - remove ndbm.[ch]" form your copy of CVS as well. - - * "cvs add" and "cvs remove" are a bit more verbose, telling you - what to do to add/remove your file permanently. - - * We no longer mess with /dev/tty in "commit" and "add". - - * More things are quiet with the -Q option set. - - * New src/config.h option: If CVS_BADROOT is set, CVS will not - allow people really logged in as "root" to commit changes. - - * "cvs diff" exits with a status of 0 if there were no diffs, 1 if - there were diffs, and 2 if there were errors. - - * "cvs -n diff" is now supported so that you can still run diffs - even while in the middle of committing files. - - * Handling of the CVS/Entries file is now much more robust. - - * The default file ignore list now includes "*.so". - - * "cvs import" did not expand '@' in the log message correctly. It - does now. Also, import now uses the ignore file facility - correctly. - - Import will now tell you whether there were conflicts that need to - be resolved, and how to resolve them. - - * "cvs log" has been changed so that you can "log" things that are - not a part of the current release (in the Attic). - - * If you don't change the editor message on commit, CVS now prompts - you with the choice: - - !)reuse this message unchanged for remaining dirs - - which allows you to tell CVS that you have no intention of changing - the log message for the remainder of the commit. - - * It is no longer necessary to have CVSROOT set if you are using - the -H option to get Usage information on the commands. - - * Command argument changes: - checkout: -P handling changed as described above. - New -j option (up to 2 can be specified) - for doing rcsmerge kind of things on - checkout. - commit: -r option now supports committing to a - numeric or symbolic tags, with some - restrictions. Full consistency checks will - be done. - Added "-f logfile" option, which tells - commit to glean the log message from the - specified file, rather than invoking the - editor. - rtag: Added -b option to create a branch tag, - useful for creating a patch for a previous - release, or for forking development. - tag: Added -b option to create a branch tag, - useful for creating a patch for a previous - release, or for forking development. - update: New -j option (up to 2 can be specified) - for doing rcsmerge kind of things on - update. - -Thu Jan 9 10:51:35 MST 1992 Jeff Polk (polk at BSDI.COM) - - * Changes between CVS 1.3 Beta-1 and CVS 1.3 Beta-2 - - * Thanks to K. Richard Pixley at Cygnus we now have function - prototypes in all the files - - * Some small changes to configure for portability. There have - been other portability problems submitted that have not been fixed - (Brian will be working on those). Additionally all __STDC__ - tests have been modified to check __STDC__ against the constant 1 - (this is what the Second edition of K&R says must be true). - - * Lots of additional error checking for forked processes (run_exec) - (thanks again to K. Richard Pixley) - - * Lots of miscellaneous bug fixes - including but certainly not - limited to: - various commit core dumps - various update core dumps - bogus results from status with numeric sticky tags - commitprog used freed memory - Entries file corruption caused by No_Difference - commit to revision broken (now works if branch exists) - ignore file processing broken for * and ! - ignore processing didn't handle memory reasonably - miscellaneous bugs in the recursion processor - file descriptor leak in ParseInfo - CVSROOT.adm->CVSROOT rename bug - lots of lint fixes - - * Reformatted all the code in src (with GNU indent) and then - went back and fixed prototypes, etc since indent gets confused. The - rationale is that it is better to do it sooner than later and now - everything is consistent and will hopefully stay that way. - The basic options to indent were: "-bad -bbb -bap -cdb -d0 -bl -bli0 - -nce -pcs -cs -cli4 -di1 -nbc -psl -lp -i4 -ip4 -c41" and then - miscellaneous formatting fixes were applied. Note also that the - "-nfc1" or "-nfca" may be appropriate in files where comments have - been carefully formatted (e.g, modules.c). - -Sat Dec 14 20:35:22 1991 Brian Berliner (berliner at sun.com) - - * Changes between CVS 1.2 and CVS 1.3 Beta are described here. - - * Lots of portability work. CVS now uses the GNU "configure" - script to dynamically determine the features provided by your - system. It probably is not foolproof, but it is better than - nothing. Please let me know of any portability problems. Some - file names were changed to fit within 14-characters. - - * CVS has a new RCS parser that is much more flexible and - extensible. It should read all known RCS ",v" format files. - - * Most of the commands now are fully recursive, rather than just - operating on the current directory alone. This includes "commit", - which makes it real easy to do an "atomic" commit of all the - changes made to a CVS hierarchy of sources. Most of the commands - also correctly handle file names that are in directories other than - ".", including absolute path names. Commands now accept the "-R" - option to force recursion on (though it is always the default now) - and the "-l" option to force recursion off, doing just "." and not - any sub-directories. - - * CVS supports many of the features provided with the RCS 5.x - distribution - including the new "-k" keyword expansion options. I - recommend using RCS 5.x (5.6 is the current official RCS version) - and GNU diff 1.15 (or later) distributions with CVS. - - * Checking out files with symbolic tags/dates is now "sticky", in - that CVS remembers the tag/date used for each file (and directory) - and will use that tag/date automatically on the next "update" call. - This stickyness also holds for files checked out with the the new - RCS 5.x "-k" options. - - * The "cvs diff" command now recognizes all of the rcsdiff 5.x - options. Unidiff format is available by installing the GNU - diff 1.15 distribution. - - * The old "CVS.adm" directories created on checkout are now called - "CVS" directories, to look more like "RCS" and "SCCS". Old CVS.adm - directories are automagically converted to CVS directories. The - old "CVSROOT.adm" directory within the source repository is - automagically changed into a "CVSROOT" directory as well. - - * Symbolic links in the source repository are fully supported ONLY - if you use RCS 5.6 or later and (of course) your system supports - symlinks. - - * A history database has been contributed which maintains the - history of certain CVS operations, as well as providing a wide array - of querying options. - - * The "cvs" program has a "-n" option which can be used with the - "update" command to show what would be updated without actually - doing the update, like: "cvs -n update". All usage statements - have been cleaned up and made more verbose. - - * The module database parsing has been rewritten. The new format - is compatible with the old format, but with much more - functionality. It allows modules to be created that grab pieces or - whole directories from various different parts of your source - repository. Module-relative specifications are also correctly - recognized now, like "cvs checkout module/file.c". - - * A configurable template can be specified such that on a "commit", - certain directories can supply a template that the user must fill - before completing the commit operation. - - * A configurable pre-commit checking program can be specified which - will run to verify that a "commit" can happen. This feature can be - used to restrict certain users from changing certain pieces of the - source repository, or denying commits to the entire source - repository. - - * The new "cvs export" command is much like "checkout", but - establishes defaults suitable for exporting code to others (expands - out keywords, forces the use of a symbolic tag, and does not create - "CVS" directories within the checked out sources. - - * The new "cvs import" command replaces the deprecated "checkin" - shell script and is used to import sources into CVS control. It is - also much faster for the first-time import. Some algorithmic - improvements have also been made to reduce the number of - conflicting files on next-time imports. - - * The new "cvs admin" command is basically an interface to the - "rcs" program. (Not yet implemented very well). - - * Signal handling (on systems with BSD or POSIX signals) is much - improved. Interrupting CVS now works with a single interrupt! - - * CVS now invokes RCS commands by direct fork/exec rather than - calling system(3). This improves performance by removing a call to - the shell to parse the arguments. - - * Support for the .cvsignore file has been contributed. CVS will - now show "unknown" files as "? filename" as the result of an "update" - command. The .cvsignore file can be used to add files to the - current list of ignored files so that they won't show up as unknown. - - * Command argument changes: - cvs: Added -l to turn off history logging. - Added -n to show what would be done without actually - doing anything. - Added -q/-Q for quiet and really quiet settings. - Added -t to show debugging trace. - add: Added -k to allow RCS 5.x -k options to be specified. - admin: New command; an interface to rcs(1). - checkout: Added -A to reset sticky tags/date/options. - Added -N to not shorten module paths. - Added -R option to force recursion. - Changed -p (prune empty directories) to -P option. - Changed -f option; forcing tags match is now default. - Added -p option to checkout module to standard output. - Added -s option to cat the modules db with status. - Added -d option to checkout in the specified directory. - Added -k option to use RCS 5.x -k support. - commit: Removed -a option; use -l instead. - Removed -f option. - Added -l option to disable recursion. - Added -R option to force recursion. - If no files specified, commit is recursive. - diff: Now recognizes all RCS 5.x rcsdiff options. - Added -l option to disable recursion. - Added -R option to force recursion. - history: New command; displays info about CVS usage. - import: Replaces "checkin" shell script; imports sources - under CVS control. Ignores files on the ignore - list (see -I option or .cvsignore description above). - export: New command; like "checkout", but w/special options - turned on by default to facilitate exporting sources. - join: Added -B option to join from base of the branch; - join now defaults to only joining with the top two - revisions on the branch. - Added -k option for RCS 5.x -k support. - log: Supports all RCS 5.x options. - Added -l option to disable recursion. - Added -R option to force recursion. - patch: Changed -f option; forcing tags match is now default. - Added -c option to force context-style diffs. - Added -u option to support unidiff-style diffs. - Added -V option to support RCS specific-version - keyword expansion formats. - Added -R option to force recursion. - remove: No option changes. It's a bit more verbose. - rtag: Equivalent to the old "cvs tag" command. - No option changes. It's a lot faster for re-tag. - status: New output formats with more information. - Added -l option to disable recursion. - Added -R option to force recursion. - Added -v option to show symbolic tags for files. - tag: Functionality changed to tag checked out files - rather than modules; use "rtag" command to get the - old "cvs tag" behaviour. - update: Added -A to reset sticky tags/date/options. - Changed -p (prune empty directories) to -P option. - Changed -f option; forcing tags match is now default. - Added -p option to checkout module to standard output. - Added -I option to add files to the ignore list. - Added -R option to force recursion. - - Major Contributors: - - * Jeff Polk <polk@bsdi.com> rewrote most of the grody code of CVS - 1.2. He made just about everything dynamic (by using malloc), - added a generic hashed list manager, re-wrote the modules database - parsing in a compatible - but extended way, generalized directory - hierarchy recursion for virtually all the commands (including - commit!), generalized the loginfo file to be used for pre-commit - checks and commit templates, wrote a new and flexible RCS parser, - fixed an uncountable number of bugs, and helped in the design of - future CVS features. If there's anything gross left in CVS, it's - probably my fault! - - * David G. Grubbs <dgg@odi.com> contributed the CVS "history" and - "release" commands. As well as the ever-so-useful "-n" option of - CVS which tells CVS to show what it would do, without actually - doing it. He also contributed support for the .cvsignore file. - - * Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and - contributed the code in lib/sighandle.c. I added support for - POSIX, BSD, and non-POSIX/non-BSD systems. - - * Free Software Foundation contributed the "configure" script and - other compatibility support in the "lib" directory, which will help - make CVS much more portable. - - * Many others have contributed bug reports and enhancement requests. - Some have even submitted actual code which I have not had time yet - to integrate into CVS. Maybe for the next release. - - * Thanks to you all! - -Wed Feb 6 10:10:58 1991 Brian Berliner (berliner at sun.com) - - * Changes from CVS 1.0 Patchlevel 1 to CVS 1.0 Patchlevel 2; also - known as "Changes from CVS 1.1 to CVS 1.2". - - * Major new support with this release is the ability to use the - recently-posted RCS 5.5 distribution with CVS 1.2. See below for - other assorted bug-fixes that have been thrown in. - - * ChangeLog (new): Added Emacs-style change-log file to CVS 1.2 - release. Chronological description of changes between release. - - * README: Small fixes to installation instructions. My email - address is now "berliner@sun.com". - - * src/Makefile: Removed "rcstime.h". Removed "depend" rule. - - * src/partime.c: Updated to RCS 5.5 version with hooks for CVS. - * src/maketime.c: Updated to RCS 5.5 version with hooks for CVS. - * src/rcstime.h: Removed from the CVS 1.2 distribution. - Thanks to Paul Eggert <eggert@twinsun.com> for these changes. - - * src/checkin.csh: Support for RCS 5.5 parsing. - Thanks to Paul Eggert <eggert@twinsun.com> for this change. - - * src/collect_sets.c (Collect_Sets): Be quieter if "-f" option is - specified. When checking out files on-top-of other files that CVS - doesn't know about, run a diff in the hopes that they are really - the same file before aborting. - - * src/commit.c (branch_number): Fix for RCS 5.5 parsing. - Thanks to Paul Eggert <eggert@twinsun.com> for this change. - - * src/commit.c (do_editor): Bug fix - fprintf missing argument - which sometimes caused core dumps. - - * src/modules.c (process_module): Properly NULL-terminate - update_dir[] in all cases. - - * src/no_difference.c (No_Difference): The wrong RCS revision was - being registered in certain (strange) cases. - - * src/patch.c (get_rcsdate): New algorithm. No need to call - maketime() any longer. - Thanks to Paul Eggert <eggert@twinsun.com> for this change. - - * src/patchlevel.h: Increased patch level to "2". - - * src/subr.c (isdir, islink): Changed to compare stat mode bits - correctly. - - * src/tag.c (tag_file): Added support for following symbolic links - that are in the master source repository when tagging. Made tag - somewhat quieter in certain cases. - - * src/update.c (update_process_lists): Unlink the user's file if it - was put on the Wlist, meaning that the user's file is not modified - and its RCS file has been removed by someone else. - - * src/update.c (update): Support for "cvs update dir" to correctly - just update the argument directory "dir". - - * src/cvs.h: Fixes for RCS 5.5 parsing. - * src/version_number.c (Version_Number): Fixes for parsing RCS 5.5 - and older RCS-format files. - Thanks to Paul Eggert <eggert@twinsun.com> for these changes. - - * src/version_number.c (Version_Number): Bug fixes for "-f" option. - Bug fixes for parsing with certain branch numbers. RCS - revision/symbol parsing is much more solid now. - -Wed Feb 14 10:01:33 1990 Brian Berliner (berliner at sun.com) - - * Changes from CVS 1.0 Patchlevel 0 to CVS 1.0 Patchlevel 1; also - known as "Changes from CVS 1.0 to CVS 1.1". - - * src/patch.c (get_rcsdate): Portability fix. Replaced call to - timelocal() with call to maketime(). - -Mon Nov 19 23:15:11 1990 Brian Berliner (berliner at prisma.com) - - * Sent CVS 1.0 release to comp.sources.unix moderator and FSF. - - * Special thanks to Dick Grune <dick@cs.vu.nl> for his work on the - 1986 version of CVS and making it available to the world. Dick's - version is available on uunet.uu.net in the - comp.sources.unix/volume6/cvs directory. - -$CVSid: @(#)ChangeLog 1.35 94/10/22 $ diff --git a/gnu/usr.bin/cvs/PROJECTS b/gnu/usr.bin/cvs/PROJECTS deleted file mode 100644 index de76576..0000000 --- a/gnu/usr.bin/cvs/PROJECTS +++ /dev/null @@ -1,59 +0,0 @@ -This is a list of projects for CVS. In general, unlike the things in -the TODO file, these need more analysis to determine if and how -worthwhile each task is. - -I haven't gone through TODO, but it's likely that it has entries that -are actually more appropriate for this list. - -0. Improved Efficency - -* CVS uses a single doubly linked list/hash table data structure for - all of its lists. Since the back links are only used for deleting - list nodes it might be beneficial to use singly linked lists or a - tree structure. Most likely, a single list implementation will not - be appropriate for all uses. - - One easy change would be to remove the "type" field out of the list - and node structures. I have found it to be of very little use when - debugging, and each instance eats up a word of memory. This can add - up and be a problem on memory-starved machines. - - Profiles have shown that on fast machines like the Alpha, fsortcmp() - is one of the hot spots. - -* Dynamically allocated character strings are created, copied, and - destroyed throughout CVS. The overhead of malloc()/strcpy()/free() - needs to be measured. If significant, it could be minimized by using a - reference counted string "class". - -* File modification time is stored as a character string. It might be - worthwile to use a time_t internally if the time to convert a time_t - (from struct stat) to a string is greater that the time to convert a - ctime style string (from the entries file) to a time_t. time_t is - an machine-dependant type (although it's pretty standard on UN*X - systems), so we would have to have different conversion routines. - Profiles show that both operations are called about the same number - of times. - -* stat() is one of the largest performance bottlenecks on systems - without the 4.4BSD filesystem. By spliting information out of - the filesystem (perhaps the "rename database") we should be - able to improve performance. - -* Parsing RCS files is very expensive. This might be unnecessary if - RCS files are only used as containers for revisions, and tag, - revision, and date information was available in easy to read - (and modify) indexes. This becomes very apparent with files - with several hundred revisions. - -* A RCS "library", so CVS could operate on RCS files directly. - - CVS parses RCS files in order to determine if work needs to be done, - and then RCS parses the files again when it is performing the work. - This would be much faster if CVS could do whatever is necessary - by itself. - -1. Improved testsuite/sanity check script - -* Need to use a code coverage tool to determine how much the sanity - script tests, and fill in the holes. diff --git a/gnu/usr.bin/cvs/README b/gnu/usr.bin/cvs/README deleted file mode 100644 index b257f89..0000000 --- a/gnu/usr.bin/cvs/README +++ /dev/null @@ -1,207 +0,0 @@ -$CVSid: @(#)README 1.32 94/10/22 $ - - CVS Kit - - Copyright (c) 1993-1994 Brian Berliner - Copyright (c) 1992 Brian Berliner and Jeff Polk - Copyright (c) 1989-1992, Brian Berliner - All Rights Reserved - - 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. - -------------------------------------------------------------------------------- - -Welcome to CVS! - -Bug reports are accepted, however note that someone may or may not -feel like taking care of your bug report. Support contracts are -available from Cyclic Software (http://www.cyclic.com). - -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". - -Please consult the INSTALL file for information on tested -configurations. If you have a comment about an already tested -configuration, or have tried CVS on a new configuration, please write -to the above address and let us know! Free software only works if we -all help out. - -Finally, we cannot guarantee that this release will not completely wipe out -all of your work from your system. We do some simple testing before each -release, but you are completely on your own. We recommend testing this -release on a source repository that is not critical to your work. THIS -SOFTWARE IS SUPPLIED COMPLETELY "AS IS". NO WARRANTY.... - -Thanks for your support! - - -The CVS Team, and the Cyclic CVS Hackers - -------------------------------------------------------------------------------- - -CVS is a freely available collection of programs that provide for software -release and revision control functions in a UNIX environment. It is -designed to work on top of the RCS distribution, V4 and later. CVS does -understand how to parse older RCS formats, but cannot do any of the fancier -features (like vendor branch support) without RCS branch support. - -Short blurb from the manual page (larger blurb is included there): - cvs is a front end to the rcs(1) revision control system - which extends the notion of revision control from a collec- - tion of files in a single directory to a hierarchical col- - lection of directories consisting of revision controlled - files. These directories and files can be combined together - to form a software release. cvs provides the functions - necessary to manage these software releases and to control - the concurrent editing of source files among multiple - software developers. - -And a whole lot more. See the man/cvs.1 file for more information. - -------------------------------------------------------------------------------- - -Special note to current CVS 1.3 users: - ---> You can skip this section and go straight to "Installation" if you <-- ---> have not been running any previous releases of CVS. <-- - -See the NEWS file for a description of features new in this version. - -Some files have been renamed from the CVS 1.3 distribution. If you're -not careful, this can cause your CVS build to fail in strange ways. -In particular, be sure to remove the src/config.h file (which is now -src/options.h), as the correct config.h file is generated -automatically by the "configure" stage of installation (and installed -in this directory). - -------------------------------------------------------------------------------- - -Installation: - -Please read the INSTALL file for installation instructions. Brief summary: - - $ ./configure - $ make - $ make check # optional, long-running, step - $ make install - $ cvsinit - -------------------------------------------------------------------------------- - -* 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.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. - -[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 - address.] - -------------------------------------------------------------------------------- - -Credits: - -The conflict-resolution algorithms and much of the administrative file -definitions of CVS were based on the original package written by Dick Grune -at Vrije Universiteit in Amsterdam <dick@cs.vu.nl>, and posted to -comp.sources.unix in the volume 6 release sometime in 1986. This original -version was a collection of shell scripts. I am thankful that Dick made -his work available. - -Brian Berliner from Prisma, Inc. (now at Sun Microsystems, Inc.) -<berliner@sun.com> converted the original CVS shell scripts into reasonably -fast C and added many, many features to support software release control -functions. See the manual page in the "man" directory. A copy of the -USENIX article presented at the Winter 1990 USENIX Conference, Washington -D.C., is included in the "doc" directory. - -Jeff Polk from BSDI <polk@bsdi.com> converted the CVS 1.2 -sources into much more readable and maintainable C code. He also added a -whole lot of functionality and modularity to the code in the process. -See the ChangeLog file. - -david d `zoo' zuhn <zoo@armadillo.com> contributed the working base code -for CVS 1.4 Alpha. His work carries on from work done by K. Richard Pixley -and others at Cygnus Support. The CVS 1.4 upgrade is due in large part to -Zoo's efforts. - -David G. Grubbs <dgg@odi.com> contributed the CVS "history" and "release" -commands. As well as the ever-so-useful "-n" option of CVS which tells CVS -to show what it would do, without actually doing it. He also contributed -support for the .cvsignore file. - -The Free Software Foundation (GNU) contributed most of the portability -framework that CVS now uses. This can be found in the "configure" script, -the Makefile's, and basically most of the "lib" directory. - -K. Richard Pixley, Cygnus Support <rich@cygnus.com> contributed many bug -fixes/enhancement as well as completing early reviews of the CVS 1.3 manual -pages. - -Roland Pesch, then of Cygnus Support <roland@wrs.com> contributed brand new -cvs(1) and cvs(5) manual pages. We should all thank him for saving us from -my poor use of our language! - -Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> wrote and -contributed the code in lib/sighandle.c. I added support for POSIX, BSD, -and non-POSIX/non-BSD systems. - -Jim Kingdon and others at Cygnus Support <info@cygnus.com> wrote the -remote repository access code. - -In addition to the above contributors, the following Beta testers deserve -special mention for their support. If I have left off your name, I -apologize. Just write to me and let me know! - - Mark D. Baushke <mdb@cisco.com> - Per Cederqvist <ceder@signum.se> - J.T. Conklin (jtc@cygnus.com> - Vince DeMarco <vdemarco@fdcsrvr.cs.mci.com> - Paul Eggert <eggert@twinsun.com> - Lal George <george@research.att.com> - Dean E. Hardi <Dean.E.Hardi@ccmail.jpl.nasa.gov> - Mike Heath <mike@pencom.com> - Jim Kingdon <kingdon@cygnus.com> - Bernd Leibing <bernd.leibing@rz.uni-ulm.de> - Benedict Lofstedt <benedict@tusc.com.au> - Dave Love <d.love@dl.ac.uk> - Robert Lupton the Good <rhl@astro.princeton.edu> - Tom McAliney <tom@hilco.com> - Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de> - Jim Meyering <meyering@comco.com> - Thomas Mohr <mohr@lts.sel.alcatel.de> - Thomas Nilsson <thoni@softlab.se> - Raye Raskin <raye.raskin@lia.com> - Harlan Stenn <harlan@landmark.com> - Gunnar Tornblom <gunnar.tornblom@senet.abb.se> - Greg A. Woods <woods@kuma.web.net> - -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 -contributed GNU Emacs CVS-mode in contrib/pcl-cvs. - -------------------------------------------------------------------------------- - - Cyclic Software <info@cyclic.com> diff --git a/gnu/usr.bin/cvs/TODO b/gnu/usr.bin/cvs/TODO deleted file mode 100644 index 1b8cb60..0000000 --- a/gnu/usr.bin/cvs/TODO +++ /dev/null @@ -1,474 +0,0 @@ -$CVSid: @(#)TODO 1.26 94/09/21 $ - -14. Pathname stripper, for checkout, as well as for writing the - Repository file. - [[ I have a simple one, but need to make sure to call it at all the - 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. - (This should be configurable via commitinfo or some new config file - -kingdon, Jun 1995). - -30. Add "patch" program option to the modules database. - -31. Think hard about ^C recovery. - -35. Add "admin" command as an interface to "rcs". - [[ a cheesy version is there, but it should be re-done ]] - -38. Think hard about using RCS state information to allow one to checkin - a new vendor release without having it be accessed until it has been - integrated into the local changes. - -39. Think about allowing parallel source trees that can easily track - each other. - [[ sort of solved with the automagic branch support, but I want more ]] - -45. Consider enhancing the "patch" and "tag" command support in the module - database -- they seem hard to use since these commands deal directly - with the RCS ,v files. - -46. Perhaps checkout/checkin/tag/patch commands should be imbedded in the - file system directly, using special known command names? - -49. cvs xxx commands should be able to deal with files in other - directories. I want to do a cvs add foo/bar.c. - [[ 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 - a project directory without mucking about with groups. Is there any - plan to provide a similar functionality to CVS? Our site (and, I'd - imagine, many other sites with large user bases) has decided against - having the user-groups feature of unix available to the users, due to - perceived administrative, technical and performance headaches. A tool - 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. - -63. The "import" and vendor support commands (co -j) need to be documented - better. - -64. Need to greatly increase the performance of an initial checkout. - [[ 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. - -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 - them out. - -69. Consider enhacing import to add a module automatically to the module - database. Perhaps with a new option, or perhaps with an editor. - -72. Consider re-design of the module -o, -i, -t options to use the file - system more intuitively. - -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. - -79. Might be nice to have some sort of interface to TFS and tagged - revisions. - -82. Maybe the import stuff should allow an arbitrary revision to be - specified. - -84. Improve the documentation about administration of the repository and - how to add/remove files and the use of symbolic links. - -85. Add revision controlled symbolic links to CVS using one of the tag - fields in the RCS file. - -91. Better document the format of the source repository and how one might - convert their current SCCS or RCS files into CVS format. - -92. Look into this: - After a bit of soul searching via dbx, I realized my sin was that I'd - specified "echo" as the program to call from loginfo. The commit - procedure worked fine till it hit my echo, then silently aborted - leaving the lockfiles intact. Since I needn't use the loginfo - facility, I simply removed those commands and it all works. - -93. Need to think hard about release and development environments. Think - about execsets as well. - -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. - -100. Checked out files should have revision control support. Maybe. - -102. Perhaps directory modes should be propagated on all import check-ins. - Not necessarily uid/gid changes. - -103. setuid/setgid on files is suspect. - -104. cvs should recover nicely on unreadable files/directories. - -105. cvs should have administrative tools to allow for changing permissions - and modes and what not. In particular, this would make cvs a - more attractive alternative to rdist. - -107. It should be possible to specify a list of symbolic revisions to - checkout such that the list is processed in reverse order looking for - matches within the RCS file for the symbolic revision. If there is - not a match, the next symbolic rev on the list is checked, and so on, - until all symbolic revs are exhausted. This would allow one to, say, - checkout "4.0" + "4.0.3" + "4.0.3Patch1" + "4.0.3Patch2" to get the - most recent 4.x stuff. This is usually handled by just specifying the - right release_tag, but most people forget to do this. - -108. If someone creates a whole new directory (i.e. adds it to the cvs - repository) and you happen to have a directory in your source farm by - the same name, when you do your cvs update -d it SILENTLY does - *nothing* to that directory. At least, I think it was silent; - certainly, it did *not* abort my cvs update, as it would have if the - same thing had happened with a file instead of a directory. - -109. I had gotten pieces of the sys directory in the past but not a - complete tree. I just did something like: - - cvs get * - - Where sys was in * and got the message - - cvs get: Executing 'sys/tools/make_links sys' - sh: sys/tools/make_links: not found - - I suspect this is because I didn't have the file in question, - but I do not understand how I could fool it into getting an - error. I think a later cvs get sys seemed to work so perhaps - something is amiss in handling multiple arguments to cvs get? - -113. The "cvs update" command should tee its output to a log file in ".". - (why? What is wrong with piping stdout to "tee"? -kingdon, Jun 1995) - -115. I still think "cvs modules" is a good idea. - Since everything else is inside cvs, "mkmodules" should be in there too: - - Add a "modules" (synonym "mod") command directly in cvs. - ("checkout -c" is not really intuitive. I'd move it into "mod -s".) - - "mod" Print database as typed. (line count as record id?) - "mod -s" Print the sorted database (as "checkout -c" does now) - "mod -m" Internal replacement for "mkmodules" command. - "mod module ..." Print the raw dbm record for the named modules - "mod -p module ..." Print relative filenames contained in modules.(no ",v") - "mod -l module ..." Prints more info about relative filenames ("ls -l"?) - "mod -f file ..." Tells you what module(s) the filenames are in. - -119. Consider an option to have import checkout the RCS or SCCS files - if necessary. - -122. If Name_Repository fails, it currently causes CVS to die completely. It - should instead return NULL and have the caller do something reasonable. - -123. Add a flag to import to not build vendor branches for local code. - -124. Anyway, I thought you might want to add something like the following - to the cvs and mkmodules man pages: - - BUGS - The sum of the sizes of a module key and its contents are - limited. See ndbm(3). - -126. Do an analysis to see if CVS is forgetting to close file descriptors. - Especially when committing many files (more than the open file limit - for the particular UNIX). - -127. Look at *info files; they should all be quiet if the files are not - there. Should be able to point at a RCS directory and go. - -128. When I tag a file, the message tells me that I'm tagging a directory. - -129. Something strange seems to have happened here. When I check this out, - the update lines (U CFTS/...) seem to report a bogus leading CFTS - (e.g. U CFTS/Medusa_TS/...) when the later files are checked out. - - The directory structure doesn't seem to be botched, just the - messages. I don't recall seeing this before. - -130. cvs diff with no -r arguments does not need to look up the current RCS - version number since it only cares about what's in the Entries file. - This should make it much faster. - - It should ParseEntries itself and access the entries list much like - Version_TS does (sticky tags and sticky options may need to be - supported here as well). Then it should only diff the things that - have the wrong time stamp (the ones that look modified). - -134. Make a statement about using hard NFS mounts to your source - repository. Look into checking NULL fgets() returns with ferror() to - see if an error had occurred. - -135. The email CVS sends with each checkin, should include the version - number of each file it is checking in. - [[ Sort of solved by contrib/log.pl, which does a good job of this ]] - -137. Some sites might want CVS to fsync() the RCS ,v file to protect - against nasty hardware errors. There is a slight performance hit with - doing so, though, so it should be configurable in the .cvsrc file. - Also, along with this, we should look at the places where CVS itself - could be a little more synchronous so as not to lose data. - [[ I've done some of this, but it could use much more ]] - -138. Some people have suggested that CVS use a VPATH-like environment - variable to limit the amount of sources that need to be duplicated for - sites with giant source trees and no disk space. - -141. Import should accept modules as its directory argument. - -143. Update the documentation to show that the source repository is - something far away from the files that you work on. - -144. Have cvs checkout look for the environment variable CVSPREFIX - (or CVSMODPREFIX or some such). If it's set, then when looking - up an alias in the modules database, first look it up with the - value of CVSPREFIX attached, and then look for the alias itself. - This would be useful when you have several projects in a single - repository. You could have aliases abc_src and xyz_src and - tell people working on project abc to put "setenv CVSPREFIX abc_" - in their .cshrc file (or equivalent for other shells). - Then they could do "cvs co src" to get a copy of their src - directory, not xyz's. (This should create a directory called - src, not abc_src.) - -145. After you create revision 1.1.1.1 in the previous scenario, if - you do "cvs update -r1 filename" you get revision 1.1, not - 1.1.1.1. It would be nice to get the later revision. Again, - this restriction comes from RCS and is probably hard to - change in CVS. Sigh. - - |"cvs update -r1 filename" does not tell RCS to follow any branches. CVS - |tries to be consistent with RCS in this fashion, so I would not change - |this. Within CVS we do have the flexibility of extending things, like - |making a revision of the form "-r1HEAD" find the most recent revision - |(branch or not) with a "1." prefix in the RCS file. This would get what - |you want maybe. - - This would be very useful. Though I would prefer an option - such as "-v1" rather than "-r1HEAD". This option might be - used quite often. - -146. The merging of files should be controlled via a hook so that programs - other than "rcsmerge" can be used, like Sun's filemerge or emacs's - emerge.el. (but be careful in making this work client/server--it means - doing the interactive merging at the end after the server is done). - -149. On Sun, 2 Feb 92 22:01:38 EST, rouilj@dl5000.bc.edu (John P. Rouillard) - said: - Maybe there should be an option to cvs admin that allows a user to - change the Repository file with some degree of error checking? - Something like "cvs admin reposmv /old/path /new/pretty/path". Before - it does the replace it check to see that the files - /new/pretty/path/<dir>/<files> exist. - -150. I have a customer request for a way to specify log message per - file, non-interactively before the commit, such that a single, fully - recursive commit prompts for one commit message, and concatenates the - per file messages for each file. In short, one commit, one editor - session, log messages allowed to vary across files within the commit. - Also, the per file messages should be allowed to be written when the - files are changed, which may predate the commit considerably. - - A new command seems appropriate for this. The state can be saved in the - CVS directory. I.e., - - % cvs msg foo.c - Enter log message for foo.c - >> fixed an uninitialized variable - >> ^D - - The text is saved as CVS/foo.c,m (or some such name) and commit is - modified to append (prepend?) the text (if found) to the log message - specified at commit time. Easy enough. - -151. Also, is there a flag I am missing that allows replacing Ulrtx_Build - by Ultrix_build? I.E. I would like a tag replacement to be a one step - operation rather than a two step "cvs rtag -r Ulrtx_Build Ultrix_Build" - followed by "cvs trag -d Ulrtx_Build" - -152. The "cvs -n" option does not work as one would expect for all the - commands. In particular, for "commit" and "import", where one would - also like to see what it would do, without actually doing anything. - -153. There should be some command (maybe I just haven't figured - out which one...) to import a source directory which is already - RCS-administered without losing all prior RCS gathered data. Thus, it - would have to examine the RCS files and choose a starting version and - branch higher than previous ones used. - -154. When committing the modules file, a pre-commit check should be done to - verify the validity of the new modules file before allowing it to be - committed. This could easily be done by adding an option to mkmodules - to perform the verification. - -155. The options for "cvs history" are mutually exclusive, even though - useful queries can be done if they are not, as in specifying both a - module and a tag. A workaround is to specify the module, then run the - output through grep to only display lines that begin with T, which are - tag lines. - -156. Also, how hard would it be to allow continuation lines in the - {commit,rcs,log}info files? It would probably be useful with all of - the various flags that are now available, or if somebody has a lot of - files to put into a module. - -157. The "cvs release" command does not understand about module names with - the same flexibility that the "checkout" and "rdiff" commands do. - It should, though, since it's confusing right now. - -158. If I do a recursive commit and find that the same RCS file is checked - out (and modified!) in two different places within my checked-out - files (but within the realm of a single "commit"), CVS will commit the - first change, then overwrite that change with the second change. We - should catch this (typically unusual) case and issue an appropriate - diagnostic and die. - -159. On "update", when a merge is done, CVS should remember that your file - was merged into and should keep reminding you of this fact until you - actually look at the file (change its access time). Once you do this, - it should go back to being a normal, unmodified file. This way, after - a big update, you can run update again to see which files just got - merged and may need attention. - -160. The checks that the commit command does should be extended to make - sure that the revision that we will lock is not already locked by - someone else. Maybe it should also lock the new revision if the old - revision was already locked by the user as well, thus moving the lock - forward after the commit. - -161. The date parser included with CVS (lib/getdate.y) does not support - such RCS-supported dates as "1992/03/07". It probably should. - -163. The rtag/tag commands should have an option that removes the specified - tag from any file that is in the attic. This allows one to re-use a - tag (like "Mon", "Tue", ...) all the time and still have it tag the - real main-line code. - -164. The *info files should allow multiple ocurrences of $CVSROOT and/or - other cvs variables. They probably should *not* expand environment - variables, as their behavior probably should not depend on who is - running CVS. - -165. The "import" command will create RCS files automatically, but will - screw-up when trying to create long file names on short file name - file systems. Perhaps import should be a bit more cautious. - -166. There really needs to be a "Getting Started" document which describes - some of the new CVS philosophies. Folks coming straight from SCCS or - RCS might be confused by "cvs import". Also need to explain: - - How one might setup their $CVSROOT - - What all the tags mean in an "import" command - - Tags are important; revision numbers are not - -167. "cvs log" doesn't understand about CVS magic branch numbers. As such, - the command: - - cvs log -r1.63.2 - cvs log -rC2 - - where "C2" is a magic branch that resolves to 1.63.2 do not print the - same things. Sigh. - -169. We are using CVS as the configuration control for a software reuse library. - What we do is do system calls passing the needed arguments. In the next - release, it would be nice to see an option to put cvs .o files into a - archive library with an API. This enhancement would go nicely with the - notion of being able to integrate tools into a large software engineering - environment. - -170. Is there an "info" file that can be invoked when a file is checked out, or - updated ? What I want to do is to advise users, particularly novices, of - the state of their working source whenever they check something out, as - a sanity check. - - For example, I've written a perl script which tells you what branch you're - on, if any. Hopefully this will help guard against mistaken checkins to - the trunk, or to the wrong branch. I suppose I can do this in - "commitinfo", but it'd be nice to advise people before they edit their - files. - - It would also be nice if there was some sort of "verboseness" switch to - the checkout and update commands that could turn this invocation of the - script off, for mature users. - -173. We have a tagged branch in CVS. How do we get the version of that branch - (for an entire directory) that corresponds to the files on that branch on a - certain day? I'd like to specify BOTH -r and -D to 'cvs checkout', but I - can't. It looks like I can only specify the date for the main line (as - opposed to any branches). True? Any workarounds to get what I need? - -174. I would like to see "cvs release" modified so that it only removes files - which are known to CVS - all the files in the repository, plus those which - are listed in .cvsignore. This way, if you do leave something valuable in - a source tree you can "cvs release -d" the tree and your non-CVS goodies - are still there. If a user is going to leave non-CVS files in their source - trees, they really should have to clean them up by hand. - -175. And, in the feature request department, I'd dearly love a command-line - interface to adding a new module to the CVSROOT/modules file. - -176. If you use the -i flag in the modules file, you can control access - to source code; this is a Good Thing under certain circumstances. I - just had a nasty thought, and on experiment discovered that the - filter specified by -i is _not_ run before a cvs admin command; as - this allows a user to go behind cvs's back and delete information - (cvs admin -o1.4 file) this seems like a serious problem. - -177. We've got some external vendor source that sits under a source code - hierarchy, and when we do a cvs update, it gets wiped out because - its tag is different from the "main" distribution. I've tried to - use "-I" to ignore the directory, as well as .cvsignore, but this - doesn't work. - -179. "cvs admin" does not log its actions with loginfo, nor does it check - whether the action is allowed with commitinfo. It should. diff --git a/gnu/usr.bin/cvs/contrib/Makefile b/gnu/usr.bin/cvs/contrib/Makefile index 3e21c04..80a4cf5 100644 --- a/gnu/usr.bin/cvs/contrib/Makefile +++ b/gnu/usr.bin/cvs/contrib/Makefile @@ -1,10 +1,14 @@ -# $Id: Makefile,v 1.3 1995/12/11 01:23:42 peter Exp $ +# $Id: Makefile,v 1.4 1995/12/11 01:58:47 peter Exp $ -SUBDIR= pcl-cvs +.include "${.CURDIR}/../Makefile.inc" -SCRIPTS= ccvs-rsh rcs2log clmerge cln_hist commit_prep cvs_acls cvscheck \ +.PATH: ${CVSDIR}/contrib +.PATH: ${CVSDIR}/man + +SCRIPTS= rcs2log clmerge cln_hist commit_prep cvs_acls cvscheck \ log log_accum mfpipe rcs-to-cvs rcs2log rcslock sccs2rcs \ - easy-import + +# easy-import FILES= README cvscheck.man cvshelp.man descend.man intro.doc @@ -27,11 +31,14 @@ all: ${SCRIPTS} beforeinstall: +.for file in ${SCRIPTS} ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ - ${SCRIPTS} ${DESTDIR}${EXAMPDIR}/contrib + ${file} ${DESTDIR}${EXAMPDIR}/contrib +.endfor +.for file in ${FILES} cd ${.CURDIR} ; \ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 \ - ${FILES} ${DESTDIR}${EXAMPDIR}/contrib + ${CVSDIR}/contrib/${file} ${DESTDIR}${EXAMPDIR}/contrib +.endfor -.include "../../Makefile.inc" .include <bsd.prog.mk> diff --git a/gnu/usr.bin/cvs/contrib/README b/gnu/usr.bin/cvs/contrib/README deleted file mode 100644 index a999aed..0000000 --- a/gnu/usr.bin/cvs/contrib/README +++ /dev/null @@ -1,91 +0,0 @@ -$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 README file will be kept -up-to-date from release to release. BUT, I must point out that these -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. - -Contents of this directory: - - README This file. - log A perl script suitable for including in your - $CVSROOT/CVSROOT/loginfo file for logging commit - changes. Includes the RCS revision of the change - as part of the log. - Contributed by Kevin Samborn <samborn@sunrise.com>. - pcl-cvs A directory that contains GNU Emacs lisp code which - implements a CVS-mode for emacs. - Contributed by Per Cederqvist <ceder@lysator.liu.se>. - commit_prep A perl script, to be combined with log_accum.pl, to - 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. - 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 <hampton@cisco.com>. - mfpipe Another perl script for logging. Allows you to - pipe the log message to a file and/or send mail - to some alias. - Contributed by John Clyne <clyne@niwot.scd.ucar.edu>. - rcs-to-cvs Script to import sources that may have been under - RCS control already. - Contributed by Per Cederqvist <ceder@lysator.liu.se>. - cvscheck Identifies files added, changed, or removed in a - cvscheck.man checked out CVS tree; also notices unknown files. - Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net> - cvshelp.man An introductory manual page written by Lowell Skoog - <fluke!lowell@uunet.uu.net>. It is most likely - out-of-date relative to CVS 1.3, but still may be - useful. - dirfns A shar file which contains some code that might - help your system support opendir/readdir/closedir, - if it does not already. - Copied from the C-News distribution. - rcslock A perl script that can be added to your commitinfo - file that tries to determine if your RCS file is - currently locked by someone else, as might be the - case for a binary file. - Contributed by John Rouillard <rouilj@cs.umb.edu>. - ccvs-rsh A Perl script which allows "rsh pipelines" to - be built in order to use Cyclic CVS from - behind some varieties of firewall. - cvs_acls A perl script that implements Access Control Lists - by using the "commitinfo" hook provided with the - "cvs commit" command. - Contributed by David G. Grubbs <dgg@ksr.com>. - descend A shell script that can be used to recursively - descend.man descend through a directory. In CVS 1.2, this was - very useful, since many of the commands were not - recursive. In CVS 1.3 (and later), however, most of - the commands are recursive. However, this may still - come in handy. - Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net> - cln_hist A perl script to compress your - $CVSROOT/CVSROOT/history file, as it can grow quite - large after extended use. - Contributed by David G. Grubbs <dgg@ksr.com> - sccs2rcs A C-shell script that can convert (some) SCCS files - into RCS files, retaining the info contained in the - SCCS file (like dates, author, and log message). - Contributed by Ken Cox <kenstir@viewlogic.com>. - intro.doc A user's view of what you need to know to get - started with CVS. - Contributed by <Steven.Pemberton@cwi.nl>. - rcs2sccs A shell script to convert simple RCS files into - SCCS files, originally gleaned off the network - somewhere (originally by "kenc") and modified by - Jerry Jelinek <jerry@rmtc.Central.Sun.COM> and - Brian Berliner <berliner@sun.com> to increase - robustness and add support for one-level of branches. - rcs2log A shell script to create a ChangeLog-format file - given only a set of RCS files. - Contributed by Paul Eggert <eggert@twinsun.com>. - clmerge A perl script to handle merge conflicts in GNU - style ChangeLog files . - Contributed by Tom Tromey <tromey@busco.lanl.gov>. - checklog.pl extract your commits from commitlogs archive diff --git a/gnu/usr.bin/cvs/contrib/ccvs-rsh.pl b/gnu/usr.bin/cvs/contrib/ccvs-rsh.pl deleted file mode 100644 index f01c66a..0000000 --- a/gnu/usr.bin/cvs/contrib/ccvs-rsh.pl +++ /dev/null @@ -1,97 +0,0 @@ -#! xPERL_PATHx - -# The version of the remote shell program on some Linuxes, at least, -# misuses GNU getopt in such a way that it plucks arguments to rsh -# that look like command-line switches from anywhere in rsh's -# arguments. This is the Wrong Thing to do, and causes older versions -# of CCVS to break. - -# In addition, if we live behind a firewall and have to construct a -# "pipeline" of rshes through different machines in order to get to -# the outside world, each rshd along the way undoes the hard work CCVS -# does to put the command to be executed at the far end into a single -# argument. Sigh. - -# This script is a very minimal wrapper to rsh which makes sure that -# the commands to be executed remotely are packed into a single -# argument before we call exec(). It works on the idea of a "proxy -# chain", which is a set of machines you go through to get to the CCVS -# server machine. - -# Each host you go through before you reach the CCVS server machine -# should have a copy of this script somewhere (preferably accessible -# directly from your PATH envariable). In addition, each host you go -# through before you reach the firewall should have the CVS_PROXY_HOST -# envariable set to the next machine in the chain, and CVS_PROXY_USER -# set if necessary. - -# This really isn't as complex as it sounds. Honest. - -# Bryan O'Sullivan <bos@serpentine.com> April 1995 - -$usage = "usage: ccvs-rsh hostname [-l username] command [...]\n"; - -if ($#ARGV < 1) { - print STDERR $usage; - exit 1; -} - -# Try to pick a sane version of the remote shell command to run. This -# only understands BSD and Linux machines; if your remote shell is -# called "remsh" under some System V (e.g. HP-SUX), you should edit -# the line manually to suit yourself. - -$rsh = (-x "/usr/ucb/rsh") ? "/usr/ucb/rsh" : "/usr/bin/rsh"; - -# If you are not rshing directly to the CCVS server machine, make the -# following variable point at ccvs-rsh on the next machine in the -# proxy chain. If it's accessible through the PATH envariable, you -# can just set this to "ccvs-rsh". - -$ccvs_rsh = "ccvs-rsh"; - -# There shouldn't be any user-serviceable parts beyond this point. - -$host = $ARGV[0]; - -if ($ARGV[1] eq "-l") { - if ($#ARGV < 3) { - print STDERR $usage; - exit 1; - } - $user = $ARGV[2]; - $cbase = 3; -} else { - $cbase = 1; -} - -# You might think you shoul be able to do something like -# $command = join(' ', $ARGV[$cbase..$#ARGV]); -# to achieve the effect of the following block of code, but it doesn't -# work under Perl 4 on Linux, at least. Sigh. - -$command = $ARGV[$cbase]; -for ($cbase++; $cbase <= $#ARGV; $cbase++) { - $command .= " " . $ARGV[$cbase]; -} - -if (defined $ENV{"CVS_PROXY_HOST"}) { - $command = (defined $user) - ? "$ccvs_rsh $host -l $user $command" - : "$ccvs_rsh $host $command"; - - if (defined $ENV{"CVS_PROXY_USER"}) { - exec ($rsh, $ENV{"CVS_PROXY_HOST"}, "-l", $ENV{"CVS_PROXY_USER"}, - $command); - } else { - exec ($rsh, $ENV{"CVS_PROXY_HOST"}, $command); - } -} elsif (defined $user) { - exec ($rsh, $host, "-l", $user, $command); -} else { - if (defined $ENV{"CVS_PROXY_USER"}) { - exec ($rsh, $host, "-l", $ENV{"CVS_PROXY_USER"}, $command); - } else { - exec ($rsh, $host, $command); - } -} diff --git a/gnu/usr.bin/cvs/contrib/checklog.pl b/gnu/usr.bin/cvs/contrib/checklog.pl deleted file mode 100644 index fab1c8f..0000000 --- a/gnu/usr.bin/cvs/contrib/checklog.pl +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/perl -# Copyright (c) Wolfram Schneider <wosch@freebsd.org>. June 1996, Berlin. -# -# checklog - extract your commits from commitlogs archive -# -# checklog username /a/cvs/CVSROOT/commitlogs/*[a-y] -# zcat /a/cvs/CVSROOT/commitlogs/*.gz | checklog [username] -# -# $Id: checklog.pl,v 1.2 1996/06/27 12:54:25 wosch Exp $ - -# your name or first argument -if ($ARGV[0]) { - $name = $ARGV[0]; shift @ARGV; - warn "Is this really a username: `$name' ?\n" - unless $name =~ /^[a-z0-9]+$/; -} else { - $name = `whoami`; chop $name; -} - -# date string 96/02/18 10:44:59 -$date = '[0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]'; - -$flag = 0; -while(<>) { - if (/^[a-z]/) { # start of a commit - if (m%^$name\s+$date$%o) { # it's *your* commit - $flag = 1; - } else { - $flag = 0; - } - } - - print if $flag; -} diff --git a/gnu/usr.bin/cvs/contrib/clmerge.pl b/gnu/usr.bin/cvs/contrib/clmerge.pl deleted file mode 100644 index ac81371..0000000 --- a/gnu/usr.bin/cvs/contrib/clmerge.pl +++ /dev/null @@ -1,152 +0,0 @@ -#! xPERL_PATHx - -# Merge conflicted ChangeLogs -# tromey Mon Aug 15 1994 - -# Usage is: -# -# cl-merge [-i] file ... -# -# With -i, it works in place (backups put in a ~ file). Otherwise the -# merged ChangeLog is printed to stdout. - -# Please report any bugs to me. I wrote this yesterday, so there are no -# guarantees about its performance. I recommend checking its output -# carefully. If you do send a bug report, please include the failing -# ChangeLog, so I can include it in my test suite. -# -# Tom -# --- -# tromey@busco.lanl.gov Member, League for Programming Freedom -# Sadism and farce are always inexplicably linked. -# -- Alexander Theroux - - -# Month->number mapping. Used for sorting. -%months = ('Jan', 0, - 'Feb', 1, - 'Mar', 2, - 'Apr', 3, - 'May', 4, - 'Jun', 5, - 'Jul', 6, - 'Aug', 7, - 'Sep', 8, - 'Oct', 9, - 'Nov', 10, - 'Dec', 11); - -# If '-i' is given, do it in-place. -if ($ARGV[0] eq '-i') { - shift (@ARGV); - $^I = '~'; -} - -$lastkey = ''; -$lastval = ''; -$conf = 0; -%conflist = (); - -$tjd = 0; - -# Simple state machine. The states: -# -# 0 Not in conflict. Just copy input to output. -# 1 Beginning an entry. Next non-blank line is key. -# 2 In entry. Entry beginner transitions to state 1. -while (<>) { - if (/^<<<</ || /^====/) { - # Start of a conflict. - - # Copy last key into array. - if ($lastkey ne '') { - $conflist{$lastkey} = $lastval; - - $lastkey = ''; - $lastval = ''; - } - - $conf = 1; - } elsif (/^>>>>/) { - # End of conflict. Output. - - # Copy last key into array. - if ($lastkey ne '') { - $conflist{$lastkey} = $lastval; - - $lastkey = ''; - $lastval = ''; - } - - foreach (reverse sort clcmp keys %conflist) { - print STDERR "doing $_" if $tjd; - print $_; - print $conflist{$_}; - } - - $lastkey = ''; - $lastval = ''; - $conf = 0; - %conflist = (); - } elsif ($conf == 1) { - # Beginning an entry. Skip empty lines. Error if not a real - # beginner. - if (/^$/) { - # Empty line; just skip at this point. - } elsif (/^[MTWFS]/) { - # Looks like the name of a day; assume opener and move to - # "in entry" state. - $lastkey = $_; - $conf = 2; - print STDERR "found $_" if $tjd; - } else { - die ("conflict crosses entry boundaries: $_"); - } - } elsif ($conf == 2) { - # In entry. Copy into variable until we see beginner line. - if (/^[MTWFS]/) { - # Entry beginner line. - - # Copy last key into array. - if ($lastkey ne '') { - $conflist{$lastkey} = $lastval; - - $lastkey = ''; - $lastval = ''; - } - - $lastkey = $_; - print STDERR "found $_" if $tjd; - $lastval = ''; - } else { - $lastval .= $_; - } - } else { - # Just copy. - print; - } -} - -# Compare ChangeLog time strings like <=>. -# -# 0 1 2 3 -# Thu Aug 11 13:22:42 1994 Tom Tromey (tromey@creche.colorado.edu) -# 0123456789012345678901234567890 -# -sub clcmp { - # First check year. - $r = substr ($a, 20, 4) <=> substr ($b, 20, 4); - - # Now check month. - $r = $months{substr ($a, 4, 3)} <=> $months{substr ($b, 4, 3)} if !$r; - - # Now check day. - $r = substr ($a, 8, 2) <=> substr ($b, 8, 2) if !$r; - - # Now check time (3 parts). - $r = substr ($a, 11, 2) <=> substr ($b, 11, 2) if !$r; - $r = substr ($a, 14, 2) <=> substr ($b, 14, 2) if !$r; - $r = substr ($a, 17, 2) <=> substr ($b, 17, 2) if !$r; - - $r; -} diff --git a/gnu/usr.bin/cvs/contrib/cln_hist.pl b/gnu/usr.bin/cvs/contrib/cln_hist.pl deleted file mode 100644 index ff49d0a..0000000 --- a/gnu/usr.bin/cvs/contrib/cln_hist.pl +++ /dev/null @@ -1,92 +0,0 @@ -#! xPERL_PATHx -# -*-Perl-*- -# -# $Id: cln_hist.pl,v 1.2 1995/07/10 02:01:26 kfogel Exp $ -# Contributed by David G. Grubbs <dgg@ksr.com> -# -# Clean up the history file. 10 Record types: MAR OFT WUCG -# -# WUCG records are thrown out. -# MAR records are retained. -# T records: retain only last tag with same combined tag/module. -# -# Two passes: Walk through the first time and remember the -# 1. Last Tag record with same "tag" and "module" names. -# 2. Last O record with unique user/module/directory, unless followed -# by a matching F record. -# - -$r = $ENV{"CVSROOT"}; -$c = "$r/CVSROOT"; -$h = "$c/history"; - -eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';" - while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV)); -exit 255 if $die; # process any variable=value switches - -%tags = (); -%outs = (); - -# -# Move history file to safe place and re-initialize a new one. -# -rename($h, "$h.bak"); -open(XX, ">$h"); -close(XX); - -# -# Pass1 -- remember last tag and checkout. -# -open(HIST, "$h.bak"); -while (<HIST>) { - next if /^[MARWUCG]/; - - # Save whole line keyed by tag|module - if (/^T/) { - @tmp = split(/\|/, $_); - $tags{$tmp[4] . '|' . $tmp[5]} = $_; - } - # Save whole line - if (/^[OF]/) { - @tmp = split(/\|/, $_); - $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} = $_; - } -} - -# -# Pass2 -- print out what we want to save. -# -open(SAVE, ">$h.work"); -open(HIST, "$h.bak"); -while (<HIST>) { - next if /^[FWUCG]/; - - # If whole line matches saved (i.e. "last") one, print it. - if (/^T/) { - @tmp = split(/\|/, $_); - next if $tags{$tmp[4] . '|' . $tmp[5]} ne $_; - } - # Save whole line - if (/^O/) { - @tmp = split(/\|/, $_); - next if $outs{$tmp[1] . '|' . $tmp[2] . '|' . $tmp[5]} ne $_; - } - - print SAVE $_; -} - -# -# Put back the saved stuff -# -system "cat $h >> $h.work"; - -if (-s $h) { - rename ($h, "$h.interim"); - print "history.interim has non-zero size.\n"; -} else { - unlink($h); -} - -rename ("$h.work", $h); - -exit(0); diff --git a/gnu/usr.bin/cvs/contrib/commit_prep.pl b/gnu/usr.bin/cvs/contrib/commit_prep.pl deleted file mode 100644 index 5272c04..0000000 --- a/gnu/usr.bin/cvs/contrib/commit_prep.pl +++ /dev/null @@ -1,216 +0,0 @@ -#! xPERL_PATHx -# -*-Perl-*- -# -#ident "@(#)cvs/contrib:$Name: $:$Id: commit_prep.pl,v 1.2 1995/07/10 02:01:29 kfogel Exp $" -# -# Perl filter to handle pre-commit checking of files. This program -# records the last directory where commits will be taking place for -# use by the log_accum.pl script. For new files, it forces the -# existence of a RCS "Id" keyword in the first ten lines of the file. -# For existing files, it checks version number in the "Id" line to -# prevent losing changes because an old version of a file was copied -# into the direcory. -# -# Possible future enhancements: -# -# Check for cruft left by unresolved conflicts. Search for -# "^<<<<<<<$", "^-------$", and "^>>>>>>>$". -# -# Look for a copyright and automagically update it to the -# current year. [[ bad idea! -- woods ]] -# -# -# Contributed by David Hampton <hampton@cisco.com> -# -# Hacked on lots by Greg A. Woods <woods@web.net> - -# -# Configurable options -# - -# Constants (remember to protect strings from RCS keyword substitution) -# -$LAST_FILE = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl -$ENTRIES = "CVS/Entries"; - -# Patterns to find $Log keywords in files -# -$LogString1 = "\\\$\\Log: .* \\\$"; -$LogString2 = "\\\$\\Log\\\$"; -$NoLog = "%s - contains an RCS \$Log keyword. It must not!\n"; - -# pattern to match an RCS Id keyword line with an existing ID -# -$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\""; -$NoId = " -%s - Does not contain a properly formatted line with the keyword \"Id:\". - I.e. no lines match \"" . $IDstring . "\". - Please see the template files for an example.\n"; - -# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded) -# -$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\""; - -$NoName = " -%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\" - for a newly created file.\n"; - -$BadName = " -%s - The file name '%s' in the ID line does not match - the actual filename.\n"; - -$BadVersion = " -%s - How dare you!!! You replaced your copy of the file '%s', - which was based upon version %s, with an %s version based - upon %s. Please move your '%s' out of the way, perform an - update to get the current version, and them merge your changes - into that file, then try the commit again.\n"; - -# -# Subroutines -# - -sub write_line { - local($filename, $line) = @_; - open(FILE, ">$filename") || die("Cannot open $filename, stopped"); - print(FILE $line, "\n"); - close(FILE); -} - -sub check_version { - local($i, $id, $rname, $version); - local($filename, $cvsversion) = @_; - - open(FILE, "<$filename") || return(0); - - @all_lines = (); - $idpos = -1; - $newidpos = -1; - for ($i = 0; <FILE>; $i++) { - chop; - push(@all_lines, $_); - if ($_ =~ /$IDstring/) { - $idpos = $i; - } - if ($_ =~ /$NewId/) { - $newidpos = $i; - } - } - - if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) { - print STDERR sprintf($NoLog, $filename); - return(1); - } - - if ($debug != 0) { - print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename}); - } - - if ($cvsversion{$filename} == 0) { - if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) { - print STDERR sprintf($NoName, $filename); - return(1); - } - return(0); - } - - if ($idpos == -1) { - print STDERR sprintf($NoId, $filename); - return(1); - } - - $line = $all_lines[$idpos]; - $pos = index($line, "Id: "); - if ($debug != 0) { - print STDERR sprintf("%d in '%s'.\n", $pos, $line); - } - ($id, $rname, $version) = split(' ', substr($line, $pos)); - if ($rname ne "$filename,v") { - print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2)); - return(1); - } - if ($cvsversion{$filename} < $version) { - print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename}, - "newer", $version, $filename); - return(1); - } - if ($cvsversion{$filename} > $version) { - print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename}, - "older", $version, $filename); - return(1); - } - return(0); -} - -# -# Main Body -# - -$id = getpgrp(); # You *must* use a shell that does setpgrp()! - -# Check each file (except dot files) for an RCS "Id" keyword. -# -$check_id = 0; - -# Record the directory for later use by the log_accumulate stript. -# -$record_directory = 0; - -# parse command line arguments -# -while (@ARGV) { - $arg = shift @ARGV; - - if ($arg eq '-d') { - $debug = 1; - print STDERR "Debug turned on...\n"; - } elsif ($arg eq '-c') { - $check_id = 1; - } elsif ($arg eq '-r') { - $record_directory = 1; - } else { - push(@files, $arg); - } -} - -$directory = shift @files; - -if ($debug != 0) { - print STDERR "dir - ", $directory, "\n"; - print STDERR "files - ", join(":", @files), "\n"; - print STDERR "id - ", $id, "\n"; -} - -# Suck in the CVS/Entries file -# -open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n"); -while (<ENTRIES>) { - local($filename, $version) = split('/', substr($_, 1)); - $cvsversion{$filename} = $version; -} - -# Now check each file name passed in, except for dot files. Dot files -# are considered to be administrative files by this script. -# -if ($check_id != 0) { - $failed = 0; - foreach $arg (@files) { - if (index($arg, ".") == 0) { - next; - } - $failed += &check_version($arg); - } - if ($failed) { - print STDERR "\n"; - exit(1); - } -} - -# Record this directory as the last one checked. This will be used -# by the log_accumulate script to determine when it is processing -# the final directory of a multi-directory commit. -# -if ($record_directory != 0) { - &write_line("$LAST_FILE.$id", $directory); -} -exit(0); diff --git a/gnu/usr.bin/cvs/contrib/cvs-format.el b/gnu/usr.bin/cvs/contrib/cvs-format.el deleted file mode 100644 index cdbd842..0000000 --- a/gnu/usr.bin/cvs/contrib/cvs-format.el +++ /dev/null @@ -1,81 +0,0 @@ -;; -*- lisp-interaction -*- -;; -*- emacs-lisp -*- -;; -;; -;; originally from... -;; Rich's personal .emacs file. feel free to copy. -;; -;; Last Mod Wed Feb 5 16:11:47 PST 1992, by rich@cygnus.com -;; - -;; -;; -;; This section sets constants used by c-mode for formating -;; -;; - -;; If `c-auto-newline' is non-`nil', newlines are inserted both -;;before and after braces that you insert, and after colons and semicolons. -;;Correct C indentation is done on all the lines that are made this way. - -(setq c-auto-newline nil) - - -;;*Non-nil means TAB in C mode should always reindent the current line, -;;regardless of where in the line point is when the TAB command is used. -;;It might be desirable to set this to nil for CVS, since unlike GNU -;; CVS often uses comments over to the right separated by TABs. -;; Depends some on whether you're in the habit of using TAB to -;; reindent. -;(setq c-tab-always-indent nil) - -;;; It seems to me that -;;; `M-x set-c-style BSD RET' -;;; or -;;; (set-c-style "BSD") -;;; takes care of the indentation parameters correctly. - - -;; C does not have anything analogous to particular function names for which -;;special forms of indentation are desirable. However, it has a different -;;need for customization facilities: many different styles of C indentation -;;are in common use. -;; -;; There are six variables you can set to control the style that Emacs C -;;mode will use. -;; -;;`c-indent-level' -;; Indentation of C statements within surrounding block. The surrounding -;; block's indentation is the indentation of the line on which the -;; open-brace appears. - -(setq c-indent-level 4) - -;;`c-continued-statement-offset' -;; Extra indentation given to a substatement, such as the then-clause of -;; an if or body of a while. - -(setq c-continued-statement-offset 4) - -;;`c-brace-offset' -;; Extra indentation for line if it starts with an open brace. - -(setq c-brace-offset -4) - -;;`c-brace-imaginary-offset' -;; An open brace following other text is treated as if it were this far -;; to the right of the start of its line. - -(setq c-brace-imaginary-offset 0) - -;;`c-argdecl-indent' -;; Indentation level of declarations of C function arguments. - -(setq c-argdecl-indent 4) - -;;`c-label-offset' -;; Extra indentation for line that is a label, or case or default. - -(setq c-label-offset -4) - -;;;; eof diff --git a/gnu/usr.bin/cvs/contrib/cvs_acls.pl b/gnu/usr.bin/cvs/contrib/cvs_acls.pl deleted file mode 100644 index bcb544d..0000000 --- a/gnu/usr.bin/cvs/contrib/cvs_acls.pl +++ /dev/null @@ -1,143 +0,0 @@ -#! xPERL_PATHx -# -*-Perl-*- -# -# $Id: cvs_acls.pl,v 1.2 1995/07/10 02:01:33 kfogel Exp $ -# -# Access control lists for CVS. dgg@ksr.com (David G. Grubbs) -# -# CVS "commitinfo" for matching repository names, running the program it finds -# on the same line. More information is available in the CVS man pages. -# -# ==== INSTALLATION: -# -# To use this program as I intended, do the following four things: -# -# 0. Install PERL. :-) -# -# 1. Put one line, as the *only* non-comment line, in your commitinfo file: -# -# DEFAULT /usr/local/bin/cvs_acls -# -# 2. Install this file as /usr/local/bin/cvs_acls and make it executable. -# -# 3. Create a file named $CVSROOT/CVSROOT/avail. -# -# ==== FORMAT OF THE avail FILE: -# -# The avail file determines whether you may commit files. It contains lines -# read from top to bottom, keeping track of a single "bit". The "bit" -# defaults to "on". It can be turned "off" by "unavail" lines and "on" by -# "avail" lines. ==> Last one counts. -# -# Any line not beginning with "avail" or "unavail" is ignored. -# -# Lines beginning with "avail" or "unavail" are assumed to be '|'-separated -# triples: (All spaces and tabs are ignored in a line.) -# -# {avail.*,unavail.*} [| user,user,... [| repos,repos,...]] -# -# 1. String starting with "avail" or "unavail". -# 2. Optional, comma-separated list of usernames. -# 3. Optional, comma-separated list of repository pathnames. -# These are pathnames relative to $CVSROOT. They can be directories or -# filenames. A directory name allows access to all files and -# directories below it. -# -# Example: (Text from the ';;' rightward may not appear in the file.) -# -# unavail ;; Make whole repository unavailable. -# avail|dgg ;; Except for user "dgg". -# avail|fred, john|bin/ls ;; Except when "fred" or "john" commit to -# ;; the module whose repository is "bin/ls" -# -# PROGRAM LOGIC: -# -# CVS passes to @ARGV an absolute directory pathname (the repository -# appended to your $CVSROOT variable), followed by a list of filenames -# within that directory. -# -# We walk through the avail file looking for a line that matches both -# the username and repository. -# -# A username match is simply the user's name appearing in the second -# column of the avail line in a space-or-comma separate list. -# -# A repository match is either: -# - One element of the third column matches $ARGV[0], or some -# parent directory of $ARGV[0]. -# - Otherwise *all* file arguments ($ARGV[1..$#ARGV]) must be -# in the file list in one avail line. -# - In other words, using directory names in the third column of -# the avail file allows committing of any file (or group of -# files in a single commit) in the tree below that directory. -# - If individual file names are used in the third column of -# the avail file, then files must be committed individually or -# all files specified in a single commit must all appear in -# third column of a single avail line. -# - -$debug = 0; -$cvsroot = $ENV{'CVSROOT'}; -$availfile = $cvsroot . "/CVSROOT/avail"; -$myname = $ENV{"USER"} if !($myname = $ENV{"LOGNAME"}); - -eval "print STDERR \$die='Unknown parameter $1\n' if !defined \$$1; \$$1=\$';" - while ($ARGV[0] =~ /^(\w+)=/ && shift(@ARGV)); -exit 255 if $die; # process any variable=value switches - -die "Must set CVSROOT\n" if !$cvsroot; -($repos = shift) =~ s:^$cvsroot/::; -grep($_ = $repos . '/' . $_, @ARGV); - -print "$$ Repos: $repos\n","$$ ==== ",join("\n$$ ==== ",@ARGV),"\n" if $debug; - -$exit_val = 0; # Good Exit value - -$universal_off = 0; -open (AVAIL, $availfile) || exit(0); # It is ok for avail file not to exist -while (<AVAIL>) { - chop; - next if /^\s*\#/; - next if /^\s*$/; - ($flagstr, $u, $m) = split(/[\s,]*\|[\s,]*/, $_); - - # Skip anything not starting with "avail" or "unavail" and complain. - (print "Bad avail line: $_\n"), next - if ($flagstr !~ /^avail/ && $flagstr !~ /^unavail/); - - # Set which bit we are playing with. ('0' is OK == Available). - $flag = (($& eq "avail") ? 0 : 1); - - # If we find a "universal off" flag (i.e. a simple "unavail") remember it - $universal_off = 1 if ($flag && !$u && !$m); - - # $myname considered "in user list" if actually in list or is NULL - $in_user = (!$u || grep ($_ eq $myname, split(/[\s,]+/,$u))); - print "$$ \$myname($myname) in user list: $_\n" if $debug && $in_user; - - # Module matches if it is a NULL module list in the avail line. If module - # list is not null, we check every argument combination. - if (!($in_repo = !$m)) { - @tmp = split(/[\s,]+/,$m); - for $j (@tmp) { - # If the repos from avail is a parent(or equal) dir of $repos, OK - $in_repo = 1, last if ($repos eq $j || $repos =~ /^$j\//); - } - if (!$in_repo) { - $in_repo = 1; - for $j (@ARGV) { - last if !($in_repo = grep ($_ eq $j, @tmp)); - } - } - } - print "$$ \$repos($repos) in repository list: $_\n" if $debug && $in_repo; - - $exit_val = $flag if ($in_user && $in_repo); - print "$$ ==== \$exit_val = $exit_val\n$$ ==== \$flag = $flag\n" if $debug; -} -close(AVAIL); -print "$$ ==== \$exit_val = $exit_val\n" if $debug; -print "**** Access denied: Insufficient Karma ($myname|$repos)\n" if $exit_val; -print "**** Access allowed: Personal Karma exceeds Environmental Karma.\n" - if $universal_off && !$exit_val; -exit($exit_val); diff --git a/gnu/usr.bin/cvs/contrib/cvscheck.man b/gnu/usr.bin/cvs/contrib/cvscheck.man deleted file mode 100644 index 61a064a..0000000 --- a/gnu/usr.bin/cvs/contrib/cvscheck.man +++ /dev/null @@ -1,53 +0,0 @@ -.\" $Id: cvscheck.man,v 1.1.1.3 1995/08/28 16:20:24 jimb Exp $ -.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net> -.TH CVSCHECK LOCAL "4 March 1991" FLUKE -.SH NAME -cvscheck \- identify files added, changed, or removed in a CVS working -directory -.SH SYNOPSIS -.B cvscheck -.SH DESCRIPTION -This command is a housekeeping aid. It should be run in a working -directory that has been checked out using CVS. It identifies files -that have been added, changed, or removed in the working directory, but -not CVS -.BR commit ted. -It also determines whether the files have been CVS -.BR add ed -or CVS -.BR remove d. -For directories, this command determines only whether they have been -.BR add ed. -It operates in the current directory only. -.LP -This command provides information that is available using CVS -.B status -and CVS -.BR diff . -The advantage of -.B cvscheck -is that its output is very concise. It saves you the strain (and -potential error) of interpreting the output of CVS -.B status -and -.BR diff . -.LP -See -.BR cvs (local) -or -.BR cvshelp (local) -for instructions on how to add or remove a file or directory in a -CVS-controlled package. -.SH DIAGNOSTICS -The exit status is 0 if no files have been added, changed, or removed -from the current directory. Otherwise, the command returns a count of -the adds, changes, and deletes. -.SH SEE ALSO -.BR cvs (local), -.BR cvshelp (local) -.SH AUTHOR -Lowell Skoog -.br -Software Technology Group -.br -Technical Computing diff --git a/gnu/usr.bin/cvs/contrib/cvscheck.sh b/gnu/usr.bin/cvs/contrib/cvscheck.sh deleted file mode 100644 index 96dba6e..0000000 --- a/gnu/usr.bin/cvs/contrib/cvscheck.sh +++ /dev/null @@ -1,84 +0,0 @@ -#! /bin/sh -# $Id: cvscheck.sh,v 1.1 1995/07/10 02:26:29 kfogel Exp $ -# -# cvscheck - identify files added, changed, or removed -# in CVS working directory -# -# Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net> -# -# This program should be run in a working directory that has been -# checked out using CVS. It identifies files that have been added, -# changed, or removed in the working directory, but not "cvs -# committed". It also determines whether the files have been "cvs -# added" or "cvs removed". For directories, it is only practical to -# determine whether they have been added. - -name=cvscheck -changes=0 - -# If we can't run CVS commands in this directory -cvs status . > /dev/null 2>&1 -if [ $? != 0 ] ; then - - # Bail out - echo "$name: there is no version here; bailing out" 1>&2 - exit 1 -fi - -# Identify files added to working directory -for file in .* * ; do - - # Skip '.' and '..' - if [ $file = '.' -o $file = '..' ] ; then - continue - fi - - # If a regular file - if [ -f $file ] ; then - if cvs status $file | grep -s '^From:[ ]*New file' ; then - echo "file added: $file - not CVS committed" - changes=`expr $changes + 1` - elif cvs status $file | grep -s '^From:[ ]*no entry for' ; then - echo "file added: $file - not CVS added, not CVS committed" - changes=`expr $changes + 1` - fi - - # Else if a directory - elif [ -d $file -a $file != CVS.adm ] ; then - - # Move into it - cd $file - - # If CVS commands don't work inside - cvs status . > /dev/null 2>&1 - if [ $? != 0 ] ; then - echo "directory added: $file - not CVS added" - changes=`expr $changes + 1` - fi - - # Move back up - cd .. - fi -done - -# Identify changed files -changedfiles=`cvs diff | egrep '^diff' | awk '{print $3}'` -for file in $changedfiles ; do - echo "file changed: $file - not CVS committed" - changes=`expr $changes + 1` -done - -# Identify files removed from working directory -removedfiles=`cvs status | egrep '^File:[ ]*no file' | awk '{print $4}'` - -# Determine whether each file has been cvs removed -for file in $removedfiles ; do - if cvs status $file | grep -s '^From:[ ]*-' ; then - echo "file removed: $file - not CVS committed" - else - echo "file removed: $file - not CVS removed, not CVS committed" - fi - changes=`expr $changes + 1` -done - -exit $changes diff --git a/gnu/usr.bin/cvs/contrib/cvshelp.man b/gnu/usr.bin/cvs/contrib/cvshelp.man deleted file mode 100644 index 2cfae1f..0000000 --- a/gnu/usr.bin/cvs/contrib/cvshelp.man +++ /dev/null @@ -1,562 +0,0 @@ -.\" $Id: cvshelp.man,v 1.1.1.3 1995/08/28 16:20:28 jimb Exp $ -.\" Contributed by Lowell Skoog <fluke!lowell@uunet.uu.net> -.\" Full space in nroff; half space in troff -.de SP -.if n .sp -.if t .sp .5 -.. -.\" Start a command example -.de XS -.SP -.in +.5i -.ft B -.nf -.. -.\" End a command example -.de XE -.fi -.ft P -.in -.5i -.SP -.. -.TH CVSHELP LOCAL "17 March 1991" FLUKE -.SH NAME -cvshelp \- advice on using the Concurrent Versions System -.SH DESCRIPTION -This man page is based on experience using CVS. -It is bound to change as we gain more experience. -If you come up with better advice than is found here, -contact the Software Technology -Group and we will add it to this page. -.SS "Getting Started" -Use the following steps to prepare to use CVS: -.TP -\(bu -Take a look at the CVS manual page to see what it can do for you, and -if it fits your environment (or can possibly be made to fit your -environment). -.XS -man cvs -.XE -If things look good, continue on... -.TP -\(bu -Setup the master source repository. Choose a directory with -ample disk space available for source files. This is where the RCS -`,v' files will be stored. Say you choose -.B /src/master -as the root -of your source repository. Make the -.SB CVSROOT.adm -directory in the root of the source repository: -.XS -mkdir /src/master/CVSROOT.adm -.XE -.TP -\(bu -Populate this directory with the -.I loginfo -and -.I modules -files from the -.B "/usr/doc/local/cvs" -directory. Edit these files to reflect your local source repository -environment \- they may be quite small initially, but will grow as -sources are added to your source repository. Turn these files into -RCS controlled files: -.XS -cd /src/master/CVSROOT.adm -ci \-m'Initial loginfo file' loginfo -ci \-m'Initial modules file' modules -.XE -.TP -\(bu -Run the command: -.XS -mkmodules /src/master/CVSROOT.adm -.XE -This will build the -.BR ndbm (3) -file for the modules database. -.TP -\(bu -Remember to edit the -.I modules -file manually when sources are checked -in with -.B checkin -or CVS -.BR add . -A copy of the -.I modules -file for editing can be retrieved with the command: -.XS -cvs checkout CVSROOT.adm -.XE -.TP -\(bu -Have all users of the CVS system set the -.SM 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 a -.I .login -or -.I .profile -file: -.XS -setenv CVSROOT /src/master -.XE -for csh users, and -.XS -CVSROOT=/src/master; export CVSROOT -.XE -for sh users. -.SS "Placing Locally Written Sources Under CVS Control" -Say you want to place the `whizbang' sources under -CVS control. Say further that the sources have never -been under revision control before. -.TP -\(bu -Move the source hierarchy (lock, stock, and barrel) -into the master source repository: -.XS -mv ~/whizbang $CVSROOT -.XE -.TP -\(bu -Clean out unwanted object files: -.XS -cd $CVSROOT/whizbang -make clean -.XE -.TP -\(bu -Turn every file in the hierarchy into an RCS controlled file: -.XS -descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-nV\fR\fIx\fR\fB_\fR\fIy\fR\fB *' -.XE -In this example, the initial release tag is \fBV\fIx\fB_\fIy\fR, -representing version \fIx\fR.\fIy\fR. -.LP -You can use CVS on sources that are already under RCS control. -The following example shows how. -In this example, the source package is called `skunkworks'. -.TP -\(bu -Move the source hierarchy into the master source -repository: -.XS -mv ~/skunkworks $CVSROOT -.XE -.TP -\(bu -Clean out unwanted object files: -.XS -cd $CVSROOT/skunkworks -make clean -.XE -.TP -\(bu -Clean out unwanted working files, leaving only the RCS `,v' files: -.XS -descend \-r rcsclean -.XE -Note: If any working files have been checked out and changed, -.B rcsclean -will fail. Check in the modified working files -and run the command again. -.TP -\(bu -Get rid of -.SB RCS -subdirectories. CVS does not use them. -.XS -descend \-r \-f 'mv RCS/*,v .' -descend \-r \-f 'rmdir RCS' -.XE -.TP -\(bu -Delete any unwanted files that remain in the source hierarchy. Then -make sure all files are under RCS control: -.XS -descend \-f 'ci \-t/dev/null \-m"Placed under CVS control" \-n\fR\fItag\fR\fB *' -.XE -.I tag -is the latest symbolic revision tag that you applied to your package -(if any). Note: This command will probably generate lots of error -messages (for directories and existing RCS files) that you can -ignore. -.SS "Placing a Third-Party Source Distribution Under CVS Control" -The -.B checkin -command checks third-party sources into CVS. The -difference between third-party sources and locally -written sources is that third-party sources must be checked into a -separate branch (called the -.IR "vendor branch" ) -of the RCS tree. This makes it possible to merge local changes to -the sources with later releases from the vendor. -.TP -\(bu -Save the original distribution kit somewhere. For example, if the -master source repository is -.B /src/master -the distribution kit could be saved in -.BR /src/dist . -Organize the distribution directory so that each release -is clearly identifiable. -.TP -\(bu -Unpack the package in a scratch directory, for example -.BR ~/scratch . -.TP -\(bu -Create a repository for the package. -In this example, the package is called `Bugs-R-Us 4.3'. -.XS -mkdir $CVSROOT/bugs -.XE -.TP -\(bu -Check in the unpacked files: -.XS -cd ~/scratch -checkin \-m 'Bugs-R-Us 4.3 distribution' bugs VENDOR V4_3 -.XE -There is nothing magic about the tag `VENDOR', which is applied to -the vendor branch. You can use whatever tag you want. `VENDOR' is a -useful convention. -.TP -\(bu -Never modify vendor files before checking them in. -Check in the files -.I exactly -as you unpacked them. -If you check in locally modified files, future vendor releases may -wipe out your local changes. -.SS "Working With CVS-Controlled Sources" -To use or edit the sources, you must check out a private copy. -For the following examples, the master files are assumed to reside in -.BR "$CVSROOT/behemoth" . -The working directory is -.BR "~/work" . -See -.BR cvs (local) -for more details on the commands mentioned below. -.TP -.I "To Check Out Working Files -Use CVS -.BR checkout : -.XS -cd ~/work -cvs checkout behemoth -.XE -There is nothing magic about the working directory. CVS will check -out sources anywhere you like. Once you have a working copy of the -sources, you can compile or edit them as desired. -.TP -.I "To Display Changes You Have Made" -Use CVS -.BR diff -to display detailed changes, equivalent to -.BR rcsdiff (local). -You can also use -.BR cvscheck (local) -to list files added, changed, and removed in -the directory, but not yet -.BR commit ted. -You must be in a directory containing working files. -.TP -.I "To Display Revision Information" -Use CVS -.BR log , -which is equivalent to -.BR rlog (local). -You must be in a directory containing working files. -.TP -.I "To Update Working Files" -Use CVS -.BR update -in a directory containing working files. -This command brings your working files up -to date with changes checked into the -master repository since you last checked out or updated -your files. -.TP -.I "To Check In Your Changes" -Use CVS -.BR commit -in a directory containing working files. -This command checks your changes into the master repository. -You can specify files by name or use -.XS -cvs commit \-a -.XE -to -.B commit -all the files you have changed. -.TP -.I "To Add a File" -Add the file to the working directory. -Use CVS -.B add -to mark the file as added. -Use CVS -.B commit -to add the file to the master repository. -.TP -.I "To Remove a File" -Remove the file from the working directory. -Use CVS -.B remove -to mark the file as removed. -Use CVS -.B commit -to move the file from its current location in the master repository -to the CVS -.IR Attic -directory. -.TP -.I "To Add a Directory" -Add the directory to the working directory. -Use CVS -.B add -to add the directory to the master repository. -.TP -.I "To Remove a Directory" -.br -You shouldn't remove directories under CVS. You should instead remove -their contents and then prune them (using the -.B \-f -and -.B \-p -options) when you -.B checkout -or -.B update -your working files. -.TP -.I "To Tag a Release" -Use CVS -.B tag -to apply a symbolic tag to the latest revision of each file in the -master repository. For example: -.XS -cvs tag V2_1 behemoth -.XE -.TP -.I "To Retrieve an Exact Copy of a Previous Release" -During a CVS -.B checkout -or -.BR update , -use the -.B \-r -option to retrieve revisions associated with a symbolic tag. -Use the -.B \-f -option to ignore all RCS files that do not contain the -tag. -Use the -.B \-p -option to prune directories that wind up empty because none -of their files matched the tag. Example: -.XS -cd ~/work -cvs checkout \-r V2_1 \-f \-p behemoth -.XE -.SS "Logging Changes" -It is a good idea to keep a change log together with the -sources. As a minimum, the change log should name and describe each -tagged release. The change log should also be under CVS control and -should be tagged along with the sources. -.LP -.BR cvslog (local) -can help. This command logs -changes reported during CVS -.B commit -operations. It automatically -updates a change log file in your working directory. When you are -finished making changes, you (optionally) edit the change log file and -then commit it to the master repository. -.LP -Note: You must edit the change log to describe a new release -and -.B commit -it to the master repository -.I before -.BR tag ging -the release using CVS. Otherwise, the release description will not be -included in the tagged package. -.LP -See -.BR cvslog (local) -for more information. -.SS "Merging a Subsequent Third-Party Distribution" -The initial steps in this process are identical to placing a -third-party distribution under CVS for the first time: save the -distribution kit and unpack the package in a scratch directory. From -that point the steps diverge. -The following example considers release 5.0 of the -Bugs-R-Us package. -.TP -\(bu -Check in the sources after unpacking them: -.XS -cd ~/scratch -checkin \-m 'Bugs-R-Us 5.0 distribution' bugs VENDOR V5_0 \\ - | tee ~/WARNINGS -.XE -It is important to save the output of -.B checkin -in a file -because it lists the sources that have been locally modified. -It is best to save the file in a different directory (for example, -your home directory). Otherwise, -.B checkin -will try to check it into the master repository. -.TP -\(bu -In your usual working directory, check out a fresh copy of the -distribution that you just checked in. -.XS -cd ~/work -cvs checkout \-r VENDOR bugs -.XE -The -.B checkout -command shown above retrieves the latest revision on the vendor branch. -.TP -\(bu -See the `WARNINGS' file for a list of all locally modified -sources. -For each locally modified source, -look at the differences between -the new distribution and the latest local revision: -.XS -cvs diff \-r \fR\fILocalRev file\fR\fB -.XE -In this command, -.I LocalRev -is the latest -numeric or symbolic revision -on the RCS trunk of -.IR file . -You can use CVS -.B log -to get the revision history. -.TP -\(bu -If your local modifications to a file have been incorporated into -the vendor's distribution, then you should reset the default RCS -branch for that file to the vendor branch. CVS doesn't provide a -mechanism to do this. You have to do it by hand in the master -repository: -.XS -rcs \-bVENDOR \fR\fIfile\fR\fB,v -.XE -.TP -\(bu -If your local modifications need to be merged with the -new distribution, use CVS -.B join -to do it: -.XS -cvs join \-r VENDOR \fR\fIfile\fR\fB -.XE -The resulting file will be placed in your working directory. -Edit it to resolve any overlaps. -.TP -\(bu -Test the merged package. -.TP -\(bu -Commit all modified files to the repository: -.XS -cvs commit \-a -.XE -.TP -\(bu -Tag the repository with a new local tag. -.SS "Applying Patches to Third-Party Sources" -Patches are handled in a manner very similar to complete -third-party distributions. This example considers patches applied to -Bugs-R-Us release 5.0. -.TP -\(bu -Save the patch files together with the distribution kit -to which they apply. -The patch file names should clearly indicate the patch -level. -.TP -\(bu -In a scratch directory, check out the last `clean' vendor copy \- the -highest revision on the vendor branch with -.IR "no local changes" : -.XS -cd ~/scratch -cvs checkout \-r VENDOR bugs -.XE -.TP -\(bu -Use -.BR patch (local) -to apply the patches. You should now have an image of the -vendor's software just as though you had received a complete, -new release. -.TP -\(bu -Proceed with the steps described for merging a subsequent third-party -distribution. -.TP -\(bu -Note: When you get to the step that requires you -to check out the new distribution after you have -checked it into the vendor branch, you should move to a different -directory. Do not attempt to -.B checkout -files in the directory in -which you applied the patches. If you do, CVS will try to merge the -changes that you made during patching with the version being checked -out and things will get very confusing. Instead, -go to a different directory (like your working directory) and -check out the files there. -.SS "Advice to Third-Party Source Hackers" -As you can see from the preceding sections, merging local changes -into third-party distributions remains difficult, and probably -always will. This fact suggests some guidelines: -.TP -\(bu -Minimize local changes. -.I Never -make stylistic changes. -Change makefiles only as much as needed for installation. Avoid -overhauling anything. Pray that the vendor does the same. -.TP -\(bu -Avoid renaming files or moving them around. -.TP -\(bu -Put independent, locally written files like help documents, local -tools, or man pages in a sub-directory called `local-additions'. -Locally written files that are linked into an existing executable -should be added right in with the vendor's sources (not in a -`local-additions' directory). -If, in the future, -the vendor distributes something -equivalent to your locally written files -you can CVS -.B remove -the files from the `local-additions' directory at that time. -.SH SEE ALSO -.BR cvs (local), -.BR checkin (local), -.BR cvslog (local), -.BR cvscheck (local) -.SH AUTHOR -Lowell Skoog -.br -Software Technology Group -.br -Technical Computing diff --git a/gnu/usr.bin/cvs/contrib/descend.man b/gnu/usr.bin/cvs/contrib/descend.man deleted file mode 100644 index 5ac46f4..0000000 --- a/gnu/usr.bin/cvs/contrib/descend.man +++ /dev/null @@ -1,115 +0,0 @@ -.\" $Id: descend.man,v 1.1.1.3 1995/08/28 16:20:31 jimb Exp $ -.TH DESCEND 1 "31 March 1992" -.SH NAME -descend \- walk directory tree and execute a command at each node -.SH SYNOPSIS -.B descend -[ -.B \-afqrv -] -.I command -[ -.I directory -\&.\|.\|. -] -.SH DESCRIPTION -.B descend -walks down a directory tree and executes a command at each node. It -is not as versatile as -.BR find (1), -but it has a simpler syntax. If no -.I directory -is specified, -.B descend -starts at the current one. -.LP -Unlike -.BR find , -.B descend -can be told to skip the special directories associated with RCS, -CVS, and SCCS. This makes -.B descend -especially handy for use with these packages. It can be used with -other commands too, of course. -.LP -.B descend -is a poor man's way to make any command recursive. Note: -.B descend -does not follow symbolic links to directories unless they are -specified on the command line. -.SH OPTIONS -.TP 15 -.B \-a -.I All. -Descend into directories that begin with '.'. -.TP -.B \-f -.I Force. -Ignore errors during descent. Normally, -.B descend -quits when an error occurs. -.TP -.B \-q -.I Quiet. -Suppress the message `In directory -.IR directory ' -that is normally printed during the descent. -.TP -.B \-r -.I Restricted. -Don't descend into the special directories -.SB RCS, -.SB CVS, -.SB CVS.adm, -and -.SB SCCS. -.TP -.B \-v -.I Verbose. -Print -.I command -before executing it. -.SH EXAMPLES -.TP 15 -.B "descend ls" -Cheap substitute for `ls -R'. -.TP 15 -.B "descend -f 'rm *' tree" -Strip `tree' of its leaves. This command descends the `tree' -directory, removing all regular files. Since -.BR rm (1) -does not remove directories, this command leaves the directory -structure of `tree' intact, but denuded. The -.B \-f -option is required to keep -.B descend -from quitting. You could use `rm \-f' instead. -.TP -.B "descend -r 'co RCS/*'" /project/src/ -Check out every RCS file under the directory -.BR "/project/src" . -.TP -.B "descend -r 'cvs diff'" -Perform CVS `diff' operation on every directory below (and including) -the current one. -.SH DIAGNOSTICS -Returns 1 if errors occur (and the -.B \-f -option is not used). Otherwise returns 0. -.SH SEE ALSO -.BR find (1), -.BR rcsintro (1), -.BR cvs (1), -.BR sccs (1) -.SH AUTHOR -Lowell Skoog -.br -Software Technology Group -.br -John Fluke Mfg. Co., Inc. -.SH BUGS -Shell metacharacters in -.I command -may have bizarre effects. In particular, compound commands -(containing ';', '[', and ']' characters) will not work. It is best -to enclose complicated commands in single quotes \(aa\ \(aa. diff --git a/gnu/usr.bin/cvs/contrib/descend.sh b/gnu/usr.bin/cvs/contrib/descend.sh deleted file mode 100644 index e6a7880..0000000 --- a/gnu/usr.bin/cvs/contrib/descend.sh +++ /dev/null @@ -1,116 +0,0 @@ -#! /bin/sh -# $Id: descend.sh,v 1.1 1995/07/10 02:26:32 kfogel Exp $ -# -# descend - walk down a directory tree and execute a command at each node - -fullname=$0 -name=descend -usage="Usage: $name [-afqrv] command [directory ...]\n -\040\040-a\040\040All: descend into directories starting with '.'\n -\040\040-f\040\040Force: ignore errors during descent\n -\040\040-q\040\040Quiet: don't print directory names\n -\040\040-r\040\040Restricted: don't descend into RCS, CVS.adm, SCCS directories\n -\040\040-v\040\040Verbose: print command before executing it" - -# Scan for options -while getopts afqrv option; do - case $option in - a) - alldirs=$option - options=$options" "-$option - ;; - f) - force=$option - options=$options" "-$option - ;; - q) - verbose= - quiet=$option - options=$options" "-$option - ;; - r) - restricted=$option - options=$options" "-$option - ;; - v) - verbose=$option - quiet= - options=$options" "-$option - ;; - \?) - /usr/5bin/echo $usage 1>&2 - exit 1 - ;; - esac -done -shift `expr $OPTIND - 1` - -# Get command to execute -if [ $# -lt 1 ] ; then - /usr/5bin/echo $usage 1>&2 - exit 1 -else - command=$1 - shift -fi - -# If no directory specified, use '.' -if [ $# -lt 1 ] ; then - default_dir=. -fi - -# For each directory specified -for dir in $default_dir "$@" ; do - - # Spawn sub-shell so we return to starting directory afterward - (cd $dir - - # Execute specified command - if [ -z "$quiet" ] ; then - echo In directory `hostname`:`pwd` - fi - if [ -n "$verbose" ] ; then - echo $command - fi - eval "$command" || if [ -z "$force" ] ; then exit 1; fi - - # Collect dot file names if necessary - if [ -n "$alldirs" ] ; then - dotfiles=.* - else - dotfiles= - fi - - # For each file in current directory - for file in $dotfiles * ; do - - # Skip '.' and '..' - if [ "$file" = "." -o "$file" = ".." ] ; then - continue - fi - - # If a directory but not a symbolic link - if [ -d "$file" -a ! -h "$file" ] ; then - - # If not skipping this type of directory - if [ \( "$file" != "RCS" -a \ - "$file" != "SCCS" -a \ - "$file" != "CVS" -a \ - "$file" != "CVS.adm" \) \ - -o -z "$restricted" ] ; then - - # Recursively descend into it - $fullname $options "$command" "$file" \ - || if [ -z "$force" ] ; then exit 1; fi - fi - - # Else if a directory AND a symbolic link - elif [ -d "$file" -a -h "$file" ] ; then - - if [ -z "$quiet" ] ; then - echo In directory `hostname`:`pwd`/$file: symbolic link: skipping - fi - fi - done - ) || if [ -z "$force" ] ; then exit 1; fi -done diff --git a/gnu/usr.bin/cvs/contrib/dirfns.shar b/gnu/usr.bin/cvs/contrib/dirfns.shar deleted file mode 100644 index 8324c41..0000000 --- a/gnu/usr.bin/cvs/contrib/dirfns.shar +++ /dev/null @@ -1,481 +0,0 @@ -echo 'directory.3': -sed 's/^X//' >'directory.3' <<'!' -X.TH DIRECTORY 3 imported -X.DA 9 Oct 1985 -X.SH NAME -Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations -X.SH SYNOPSIS -X.B #include <sys/types.h> -X.br -X.B #include <ndir.h> -X.PP -X.SM -X.B DIR -X.B *opendir(filename) -X.br -X.B char *filename; -X.PP -X.SM -X.B struct direct -X.B *readdir(dirp) -X.br -X.B DIR *dirp; -X.PP -X.SM -X.B long -X.B telldir(dirp) -X.br -X.B DIR *dirp; -X.PP -X.SM -X.B seekdir(dirp, loc) -X.br -X.B DIR *dirp; -X.br -X.B long loc; -X.PP -X.SM -X.B rewinddir(dirp) -X.br -X.B DIR *dirp; -X.PP -X.SM -X.B closedir(dirp) -X.br -X.B DIR *dirp; -X.SH DESCRIPTION -XThis library provides high-level primitives for directory scanning, -Xsimilar to those available for 4.2BSD's (very different) directory system. -X.\"The purpose of this library is to simulate -X.\"the new flexible length directory names of 4.2bsd UNIX -X.\"on top of the old directory structure of v7. -XIt incidentally provides easy portability to and from 4.2BSD (insofar -Xas such portability is not compromised by other 4.2/VAX dependencies). -X.\"It allows programs to be converted immediately -X.\"to the new directory access interface, -X.\"so that they need only be relinked -X.\"when moved to 4.2bsd. -X.\"It is obtained with the loader option -X.\".BR \-lndir . -X.PP -X.I Opendir -Xopens the directory named by -X.I filename -Xand associates a -X.I directory stream -Xwith it. -X.I Opendir -Xreturns a pointer to be used to identify the -X.I directory stream -Xin subsequent operations. -XThe pointer -X.SM -X.B NULL -Xis returned if -X.I filename -Xcannot be accessed or is not a directory. -X.PP -X.I Readdir -Xreturns a pointer to the next directory entry. -XIt returns -X.B NULL -Xupon reaching the end of the directory or detecting -Xan invalid -X.I seekdir -Xoperation. -X.PP -X.I Telldir -Xreturns the current location associated with the named -X.I directory stream. -X.PP -X.I Seekdir -Xsets the position of the next -X.I readdir -Xoperation on the -X.I directory stream. -XThe new position reverts to the one associated with the -X.I directory stream -Xwhen the -X.I telldir -Xoperation was performed. -XValues returned by -X.I telldir -Xare good only for the lifetime of the DIR pointer from -Xwhich they are derived. -XIf the directory is closed and then reopened, -Xthe -X.I telldir -Xvalue may be invalidated -Xdue to undetected directory compaction in 4.2BSD. -XIt is safe to use a previous -X.I telldir -Xvalue immediately after a call to -X.I opendir -Xand before any calls to -X.I readdir. -X.PP -X.I Rewinddir -Xresets the position of the named -X.I directory stream -Xto the beginning of the directory. -X.PP -X.I Closedir -Xcauses the named -X.I directory stream -Xto be closed, -Xand the structure associated with the DIR pointer to be freed. -X.PP -XA -X.I direct -Xstructure is as follows: -X.PP -X.RS -X.nf -Xstruct direct { -X /* unsigned */ long d_ino; /* inode number of entry */ -X unsigned short d_reclen; /* length of this record */ -X unsigned short d_namlen; /* length of string in d_name */ -X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ -X}; -X.fi -X.RE -X.PP -XThe -X.I d_reclen -Xfield is meaningless in non-4.2BSD systems and should be ignored. -XThe use of a -X.I long -Xfor -X.I d_ino -Xis also a 4.2BSDism; -X.I ino_t -X(see -X.IR types (5)) -Xshould be used elsewhere. -XThe macro -X.I DIRSIZ(dp) -Xgives the minimum memory size needed to hold the -X.I direct -Xvalue pointed to by -X.IR dp , -Xwith the minimum necessary allocation for -X.IR d_name . -X.PP -XThe preferred way to search the current directory for entry ``name'' is: -X.PP -X.RS -X.nf -X len = strlen(name); -X dirp = opendir("."); -X if (dirp == NULL) { -X fprintf(stderr, "%s: can't read directory .\\n", argv[0]); -X return NOT_FOUND; -X } -X while ((dp = readdir(dirp)) != NULL) -X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) { -X closedir(dirp); -X return FOUND; -X } -X closedir(dirp); -X return NOT_FOUND; -X.RE -X.\".SH LINKING -X.\"This library is accessed by specifying ``-lndir'' as the -X.\"last argument to the compile line, e.g.: -X.\".PP -X.\" cc -I/usr/include/ndir -o prog prog.c -lndir -X.SH "SEE ALSO" -Xopen(2), -Xclose(2), -Xread(2), -Xlseek(2) -X.SH HISTORY -XWritten by -XKirk McKusick at Berkeley (ucbvax!mckusick). -XMiscellaneous bug fixes from elsewhere. -XThe size of the data structure has been decreased to avoid excessive -Xspace waste under V7 (where filenames are 14 characters at most). -XFor obscure historical reasons, the include file is also available -Xas -X.IR <ndir/sys/dir.h> . -XThe Berkeley version lived in a separate library (\fI\-lndir\fR), -Xwhereas ours is -Xpart of the C library, although the separate library is retained to -Xmaximize compatibility. -X.PP -XThis manual page has been substantially rewritten to be informative in -Xthe absence of a 4.2BSD manual. -X.SH BUGS -XThe -X.I DIRSIZ -Xmacro actually wastes a bit of space due to some padding requirements -Xthat are an artifact of 4.2BSD. -X.PP -XThe returned value of -X.I readdir -Xpoints to a static area that will be overwritten by subsequent calls. -X.PP -XThere are some unfortunate name conflicts with the \fIreal\fR V7 -Xdirectory structure definitions. -! -echo 'dir.h': -sed 's/^X//' >'dir.h' <<'!' -X/* dir.h 4.4 82/07/25 */ -X -X/* -X * A directory consists of some number of blocks of DIRBLKSIZ -X * bytes, where DIRBLKSIZ is chosen such that it can be transferred -X * to disk in a single atomic operation (e.g. 512 bytes on most machines). -X * -X * Each DIRBLKSIZ byte block contains some number of directory entry -X * structures, which are of variable length. Each directory entry has -X * a struct direct at the front of it, containing its inode number, -X * the length of the entry, and the length of the name contained in -X * the entry. These are followed by the name padded to a 4 byte boundary -X * with null bytes. All names are guaranteed null terminated. -X * The maximum length of a name in a directory is MAXNAMLEN. -X * -X * The macro DIRSIZ(dp) gives the amount of space required to represent -X * a directory entry. Free space in a directory is represented by -X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes -X * in a directory block are claimed by the directory entries. This -X * usually results in the last entry in a directory having a large -X * dp->d_reclen. When entries are deleted from a directory, the -X * space is returned to the previous entry in the same directory -X * block by increasing its dp->d_reclen. If the first entry of -X * a directory block is free, then its dp->d_ino is set to 0. -X * Entries other than the first in a directory do not normally have -X * dp->d_ino set to 0. -X */ -X#define DIRBLKSIZ 512 -X#ifdef VMUNIX -X#define MAXNAMLEN 255 -X#else -X#define MAXNAMLEN 14 -X#endif -X -Xstruct direct { -X /* unsigned */ long d_ino; /* inode number of entry */ -X unsigned short d_reclen; /* length of this record */ -X unsigned short d_namlen; /* length of string in d_name */ -X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ -X}; -X -X/* -X * The DIRSIZ macro gives the minimum record length which will hold -X * the directory entry. This requires the amount of space in struct direct -X * without the d_name field, plus enough space for the name with a terminating -X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. -X */ -X#undef DIRSIZ -X#define DIRSIZ(dp) \ -X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) -X -X#ifndef KERNEL -X/* -X * Definitions for library routines operating on directories. -X */ -Xtypedef struct _dirdesc { -X int dd_fd; -X long dd_loc; -X long dd_size; -X char dd_buf[DIRBLKSIZ]; -X} DIR; -X#ifndef NULL -X#define NULL 0 -X#endif -Xextern DIR *opendir(); -Xextern struct direct *readdir(); -Xextern long telldir(); -X#ifdef void -Xextern void seekdir(); -Xextern void closedir(); -X#endif -X#define rewinddir(dirp) seekdir((dirp), (long)0) -X#endif KERNEL -! -echo 'makefile': -sed 's/^X//' >'makefile' <<'!' -XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o -XCFLAGS=-O -I. -Dvoid=int -XDEST=.. -X -Xall: $(DIR) -X -Xmv: $(DIR) -X mv $(DIR) $(DEST) -X -Xcpif: dir.h -X cp dir.h /usr/include/ndir.h -X -Xclean: -X rm -f *.o -! -echo 'closedir.c': -sed 's/^X//' >'closedir.c' <<'!' -Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82"; -X -X#include <sys/types.h> -X#include <dir.h> -X -X/* -X * close a directory. -X */ -Xvoid -Xclosedir(dirp) -X register DIR *dirp; -X{ -X close(dirp->dd_fd); -X dirp->dd_fd = -1; -X dirp->dd_loc = 0; -X free((char *)dirp); -X} -! -echo 'opendir.c': -sed 's/^X//' >'opendir.c' <<'!' -X/* Copyright (c) 1982 Regents of the University of California */ -X -Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82"; -X -X#include <sys/types.h> -X#include <sys/stat.h> -X#include <dir.h> -X -X/* -X * open a directory. -X */ -XDIR * -Xopendir(name) -X char *name; -X{ -X register DIR *dirp; -X register int fd; -X struct stat statbuf; -X char *malloc(); -X -X if ((fd = open(name, 0)) == -1) -X return NULL; -X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) { -X close(fd); -X return NULL; -X } -X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { -X close (fd); -X return NULL; -X } -X dirp->dd_fd = fd; -X dirp->dd_loc = 0; -X dirp->dd_size = 0; /* so that telldir will work before readdir */ -X return dirp; -X} -! -echo 'readdir.c': -sed 's/^X//' >'readdir.c' <<'!' -X/* Copyright (c) 1982 Regents of the University of California */ -X -Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82"; -X -X#include <sys/types.h> -X#include <dir.h> -X -X/* -X * read an old stlye directory entry and present it as a new one -X */ -X#define ODIRSIZ 14 -X -Xstruct olddirect { -X ino_t od_ino; -X char od_name[ODIRSIZ]; -X}; -X -X/* -X * get next entry in a directory. -X */ -Xstruct direct * -Xreaddir(dirp) -X register DIR *dirp; -X{ -X register struct olddirect *dp; -X static struct direct dir; -X -X for (;;) { -X if (dirp->dd_loc == 0) { -X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, -X DIRBLKSIZ); -X if (dirp->dd_size <= 0) { -X dirp->dd_size = 0; -X return NULL; -X } -X } -X if (dirp->dd_loc >= dirp->dd_size) { -X dirp->dd_loc = 0; -X continue; -X } -X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); -X dirp->dd_loc += sizeof(struct olddirect); -X if (dp->od_ino == 0) -X continue; -X dir.d_ino = dp->od_ino; -X strncpy(dir.d_name, dp->od_name, ODIRSIZ); -X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ -X dir.d_namlen = strlen(dir.d_name); -X dir.d_reclen = DIRBLKSIZ; -X return (&dir); -X } -X} -! -echo 'seekdir.c': -sed 's/^X//' >'seekdir.c' <<'!' -Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83"; -X -X#include <sys/param.h> -X#include <dir.h> -X -X/* -X * seek to an entry in a directory. -X * Only values returned by "telldir" should be passed to seekdir. -X */ -Xvoid -Xseekdir(dirp, loc) -X register DIR *dirp; -X long loc; -X{ -X long curloc, base, offset; -X struct direct *dp; -X extern long lseek(); -X -X curloc = telldir(dirp); -X if (loc == curloc) -X return; -X base = loc & ~(DIRBLKSIZ - 1); -X offset = loc & (DIRBLKSIZ - 1); -X (void) lseek(dirp->dd_fd, base, 0); -X dirp->dd_size = 0; -X dirp->dd_loc = 0; -X while (dirp->dd_loc < offset) { -X dp = readdir(dirp); -X if (dp == NULL) -X return; -X } -X} -! -echo 'telldir.c': -sed 's/^X//' >'telldir.c' <<'!' -Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82"; -X -X#include <sys/types.h> -X#include <dir.h> -X -X/* -X * return a pointer into a directory -X */ -Xlong -Xtelldir(dirp) -X DIR *dirp; -X{ -X long lseek(); -X -X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); -X} -! -echo done diff --git a/gnu/usr.bin/cvs/contrib/intro.doc b/gnu/usr.bin/cvs/contrib/intro.doc deleted file mode 100644 index a6d4ec1..0000000 --- a/gnu/usr.bin/cvs/contrib/intro.doc +++ /dev/null @@ -1,112 +0,0 @@ -Date: Tue, 16 Jun 1992 17:05:23 +0200 -From: Steven.Pemberton@cwi.nl -Message-Id: <9206161505.AA06927.steven@sijs.cwi.nl> -To: berliner@Sun.COM -Subject: cvs - -INTRODUCTION TO USING CVS - - CVS is a system that lets groups of people work simultaneously on - groups of files (for instance program sources). - - It works by holding a central 'repository' of the most recent version - of the files. You may at any time create a personal copy of these - files; if at a later date newer versions of the files are put in the - repository, you can 'update' your copy. - - You may edit your copy of the files freely. If new versions of the - files have been put in the repository in the meantime, doing an update - merges the changes in the central copy into your copy. - (It can be that when you do an update, the changes in the - central copy clash with changes you have made in your own - copy. In this case cvs warns you, and you have to resolve the - clash in your copy.) - - When you are satisfied with the changes you have made in your copy of - the files, you can 'commit' them into the central repository. - (When you do a commit, if you haven't updated to the most - recent version of the files, cvs tells you this; then you have - to first update, resolve any possible clashes, and then redo - the commit.) - -USING CVS - - Suppose that a number of repositories have been stored in - /usr/src/cvs. Whenever you use cvs, the environment variable - CVSROOT must be set to this (for some reason): - - CVSROOT=/usr/src/cvs - export CVSROOT - -TO CREATE A PERSONAL COPY OF A REPOSITORY - - Suppose you want a copy of the files in repository 'views' to be - created in your directory src. Go to the place where you want your - copy of the directory, and do a 'checkout' of the directory you - want: - - cd $HOME/src - cvs checkout views - - This creates a directory called (in this case) 'views' in the src - directory, containing a copy of the files, which you may now work - on to your heart's content. - -TO UPDATE YOUR COPY - - Use the command 'cvs update'. - - This will update your copy with any changes from the central - repository, telling you which files have been updated (their names - are displayed with a U before them), and which have been modified - by you and not yet committed (preceded by an M). You will be - warned of any files that contain clashes, the clashes will be - marked in the file surrounded by lines of the form <<<< and >>>>. - -TO COMMIT YOUR CHANGES - - Use the command 'cvs commit'. - - You will be put in an editor to make a message that describes the - changes that you have made (for future reference). Your changes - will then be added to the central copy. - -ADDING AND REMOVING FILES - - It can be that the changes you want to make involve a completely - new file, or removing an existing one. The commands to use here - are: - - cvs add <filename> - cvs remove <filename> - - You still have to do a commit after these commands. You may make - any number of new files in your copy of the repository, but they - will not be committed to the central copy unless you do a 'cvs add'. - -OTHER USEFUL COMMANDS AND HINTS - - To see the commit messages for files, and who made them, use: - - cvs log [filenames] - - To see the differences between your version and the central version: - - cvs diff [filenames] - - To give a file a new name, rename it and do an add and a remove. - - To lose your changes and go back to the version from the - repository, delete the file and do an update. - - After an update where there have been clashes, your original - version of the file is saved as .#file.version. - - All the cvs commands mentioned accept a flag '-n', that doesn't do - the action, but lets you see what would happen. For instance, you - can use 'cvs -n update' to see which files would be updated. - -MORE INFORMATION - - This is necessarily a very brief introduction. See the manual page - (man cvs) for full details. diff --git a/gnu/usr.bin/cvs/contrib/log.pl b/gnu/usr.bin/cvs/contrib/log.pl deleted file mode 100644 index 5e3bf48..0000000 --- a/gnu/usr.bin/cvs/contrib/log.pl +++ /dev/null @@ -1,169 +0,0 @@ -#! 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! -# - -# Usage: log.pl [[-m user] ...] [-s] -f logfile 'dirname file ...' -# -# -m user - for each user to receive cvs log reports -# (multiple -m's permitted) -# -s - to prevent "cvs status -v" messages -# -f logfile - for the logfile to append to (mandatory, -# but only one logfile can be specified). - -# here is what the output looks like: -# -# From: woods@kuma.domain.top -# Subject: CVS update: testmodule -# -# Date: Wednesday November 23, 1994 @ 14:15 -# Author: woods -# -# Update of /local/src-CVS/testmodule -# In directory kuma:/home/kuma/woods/work.d/testmodule -# -# Modified Files: -# test3 -# Added Files: -# test6 -# Removed Files: -# test4 -# Log Message: -# - wow, what a test -# -# (and for each file the "cvs status -v" output is appended unless -s is used) -# -# ================================================================== -# File: test3 Status: Up-to-date -# -# Working revision: 1.41 Wed Nov 23 14:15:59 1994 -# Repository revision: 1.41 /local/src-CVS/cvs/testmodule/test3,v -# Sticky Options: -ko -# -# Existing Tags: -# local-v2 (revision: 1.7) -# local-v1 (revision: 1.1.1.2) -# CVS-1_4A2 (revision: 1.1.1.2) -# local-v0 (revision: 1.2) -# CVS-1_4A1 (revision: 1.1.1.1) -# CVS (branch: 1.1.1) - -$cvsroot = $ENV{'CVSROOT'}; - -# turn off setgid -# -$) = $(; - -$dostatus = 1; - -# parse command line arguments -# -while (@ARGV) { - $arg = shift @ARGV; - - if ($arg eq '-m') { - $users = "$users " . shift @ARGV; - } elsif ($arg eq '-f') { - ($logfile) && die "Too many '-f' args"; - $logfile = shift @ARGV; - } elsif ($arg eq '-s') { - $dostatus = 0; - } else { - ($donefiles) && die "Too many arguments!\n"; - $donefiles = 1; - @files = split(/ /, $arg); - } -} - -# the first argument is the module location relative to $CVSROOT -# -$modulepath = shift @files; - -$mailcmd = "| Mail -s 'CVS update: $modulepath'"; - -# Initialise some date and time arrays -# -@mos = (January,February,March,April,May,June,July,August,September, - October,November,December); -@days = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday); - -($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime; - -# get a login name for the guy doing the commit.... -# -$login = getlogin || (getpwuid($<))[0] || "nobody"; - -# open log file for appending -# -open(OUT, ">>" . $logfile) || die "Could not open(" . $logfile . "): $!\n"; - -# send mail, if there's anyone to send to! -# -if ($users) { - $mailcmd = "$mailcmd $users"; - open(MAIL, $mailcmd) || die "Could not Exec($mailcmd): $!\n"; -} - -# print out the log Header -# -print OUT "\n"; -print OUT "****************************************\n"; -print OUT "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n"; -print OUT "Author:\t$login\n\n"; - -if (MAIL) { - print MAIL "\n"; - print MAIL "Date:\t$days[$wday] $mos[$mon] $mday, 19$year @ $hour:" . sprintf("%02d", $min) . "\n"; - print MAIL "Author:\t$login\n\n"; -} - -# print the stuff from logmsg that comes in on stdin to the logfile -# -open(IN, "-"); -while (<IN>) { - print OUT $_; - if (MAIL) { - print MAIL $_; - } -} -close(IN); - -print OUT "\n"; - -# after log information, do an 'cvs -Qq status -v' on each file in the arguments. -# -if ($dostatus != 0) { - while (@files) { - $file = shift @files; - if ($file eq "-") { - print OUT "[input file was '-']\n"; - if (MAIL) { - print MAIL "[input file was '-']\n"; - } - last; - } - open(RCS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $file; - while (<RCS>) { - print OUT; - if (MAIL) { - print MAIL; - } - } - close(RCS); - } -} - -close(OUT); -die "Write to $logfile failed" if $?; - -close(MAIL); -die "Pipe to $mailcmd failed" if $?; - -## must exit cleanly -## -exit 0; diff --git a/gnu/usr.bin/cvs/contrib/log_accum.pl b/gnu/usr.bin/cvs/contrib/log_accum.pl deleted file mode 100644 index b47f433..0000000 --- a/gnu/usr.bin/cvs/contrib/log_accum.pl +++ /dev/null @@ -1,496 +0,0 @@ -#! xPERL_PATHx -# -*-Perl-*- -# -# Perl filter to handle the log messages from the checkin of files in -# a directory. This script will group the lists of files by log -# message, and mail a single consolidated log message at the end of -# the commit. -# -# This file assumes a pre-commit checking program that leaves the -# names of the first and last commit directories in a temporary file. -# -# Contributed by David Hampton <hampton@cisco.com> -# -# hacked greatly by Greg A. Woods <woods@planix.com> - -# Usage: log_accum.pl [-d] [-s] [-M module] [[-m mailto] ...] [-f logfile] -# -d - turn on debugging -# -m mailto - send mail to "mailto" (multiple) -# -M modulename - set module name to "modulename" -# -f logfile - write commit messages to logfile too -# -s - *don't* run "cvs status -v" for each file - -# -# Configurable options -# - -$MAILER = "Mail"; # set this to something that takes "-s" - -# -# End user configurable options. -# - -# Constants (don't change these!) -# -$STATE_NONE = 0; -$STATE_CHANGED = 1; -$STATE_ADDED = 2; -$STATE_REMOVED = 3; -$STATE_LOG = 4; - -$LAST_FILE = "/tmp/#cvs.lastdir"; - -$CHANGED_FILE = "/tmp/#cvs.files.changed"; -$ADDED_FILE = "/tmp/#cvs.files.added"; -$REMOVED_FILE = "/tmp/#cvs.files.removed"; -$LOG_FILE = "/tmp/#cvs.files.log"; - -$FILE_PREFIX = "#cvs.files"; - -# -# Subroutines -# - -sub cleanup_tmpfiles { - local($wd, @files); - - $wd = `pwd`; - chdir("/tmp") || die("Can't chdir('/tmp')\n"); - opendir(DIR, "."); - push(@files, grep(/^$FILE_PREFIX\..*\.$id$/, readdir(DIR))); - closedir(DIR); - foreach (@files) { - unlink $_; - } - unlink $LAST_FILE . "." . $id; - - chdir($wd); -} - -sub write_logfile { - local($filename, @lines) = @_; - - open(FILE, ">$filename") || die("Cannot open log file $filename.\n"); - print FILE join("\n", @lines), "\n"; - close(FILE); -} - -sub append_to_logfile { - local($filename, @lines) = @_; - - open(FILE, ">$filename") || die("Cannot open log file $filename.\n"); - print FILE join("\n", @lines), "\n"; - close(FILE); -} - -sub format_names { - local($dir, @files) = @_; - local(@lines); - - $format = "\t%-" . sprintf("%d", length($dir)) . "s%s "; - - $lines[0] = sprintf($format, $dir, ":"); - - if ($debug) { - print STDERR "format_names(): dir = ", $dir, "; files = ", join(":", @files), ".\n"; - } - foreach $file (@files) { - if (length($lines[$#lines]) + length($file) > 65) { - $lines[++$#lines] = sprintf($format, " ", " "); - } - $lines[$#lines] .= $file . " "; - } - - @lines; -} - -sub format_lists { - local(@lines) = @_; - local(@text, @files, $lastdir); - - if ($debug) { - print STDERR "format_lists(): ", join(":", @lines), "\n"; - } - @text = (); - @files = (); - $lastdir = shift @lines; # first thing is always a directory - if ($lastdir !~ /.*\/$/) { - die("Damn, $lastdir doesn't look like a directory!\n"); - } - foreach $line (@lines) { - if ($line =~ /.*\/$/) { - push(@text, &format_names($lastdir, @files)); - $lastdir = $line; - @files = (); - } else { - push(@files, $line); - } - } - push(@text, &format_names($lastdir, @files)); - - @text; -} - -sub append_names_to_file { - local($filename, $dir, @files) = @_; - - if (@files) { - open(FILE, ">>$filename") || die("Cannot open file $filename.\n"); - print FILE $dir, "\n"; - print FILE join("\n", @files), "\n"; - close(FILE); - } -} - -sub read_line { - local($line); - local($filename) = @_; - - open(FILE, "<$filename") || die("Cannot open file $filename.\n"); - $line = <FILE>; - close(FILE); - chop($line); - $line; -} - -sub read_logfile { - local(@text); - local($filename, $leader) = @_; - - open(FILE, "<$filename"); - while (<FILE>) { - chop; - push(@text, $leader.$_); - } - close(FILE); - @text; -} - -sub build_header { - local($header); - local($sec,$min,$hour,$mday,$mon,$year) = localtime(time); - $header = sprintf("CVSROOT:\t%s\nModule name:\t%s\nChanges by:\t%s@%s\t%02d/%02d/%02d %02d:%02d:%02d", - $cvsroot, - $modulename, - $login, $hostdomain, - $year%100, $mon+1, $mday, - $hour, $min, $sec); -} - -sub mail_notification { - local($name, @text) = @_; - open(MAIL, "| $MAILER -s \"CVS Update: " . $modulename . "\" " . $name); - print MAIL join("\n", @text), "\n"; - close(MAIL); -} - -sub write_commitlog { - local($logfile, @text) = @_; - - open(FILE, ">>$logfile"); - print FILE join("\n", @text), "\n"; - close(FILE); -} - -# -# Main Body -# - -# Initialize basic variables -# -$debug = 0; -$id = getpgrp(); # note, you *must* use a shell which does setpgrp() -$state = $STATE_NONE; -$login = getlogin || (getpwuid($<))[0] || "nobody"; -chop($hostname = `hostname`); -chop($domainname = `domainname`); -$hostdomain = $hostname . $domainname; -$cvsroot = $ENV{'CVSROOT'}; -$do_status = 1; -$modulename = ""; - -# parse command line arguments (file list is seen as one arg) -# -while (@ARGV) { - $arg = shift @ARGV; - - if ($arg eq '-d') { - $debug = 1; - print STDERR "Debug turned on...\n"; - } elsif ($arg eq '-m') { - $mailto = "$mailto " . shift @ARGV; - } elsif ($arg eq '-M') { - $modulename = shift @ARGV; - } elsif ($arg eq '-s') { - $do_status = 0; - } elsif ($arg eq '-f') { - ($commitlog) && die("Too many '-f' args\n"); - $commitlog = shift @ARGV; - } else { - ($donefiles) && die("Too many arguments! Check usage.\n"); - $donefiles = 1; - @files = split(/ /, $arg); - } -} -($mailto) || die("No -m mail recipient specified\n"); - -# for now, the first "file" is the repository directory being committed, -# relative to the $CVSROOT location -# -@path = split('/', $files[0]); - -# XXX there are some ugly assumptions in here about module names and -# XXX directories relative to the $CVSROOT location -- really should -# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since -# XXX we have to parse it backwards. -# -if ($modulename eq "") { - $modulename = $path[0]; # I.e. the module name == top-level dir -} -if ($#path == 0) { - $dir = "."; -} else { - $dir = join('/', @path); -} -$dir = $dir . "/"; - -if ($debug) { - print STDERR "module - ", $modulename, "\n"; - print STDERR "dir - ", $dir, "\n"; - print STDERR "path - ", join(":", @path), "\n"; - print STDERR "files - ", join(":", @files), "\n"; - print STDERR "id - ", $id, "\n"; -} - -# Check for a new directory first. This appears with files set as follows: -# -# files[0] - "path/name/newdir" -# files[1] - "-" -# files[2] - "New" -# files[3] - "directory" -# -if ($files[2] =~ /New/ && $files[3] =~ /directory/) { - local(@text); - - @text = (); - push(@text, &build_header()); - push(@text, ""); - push(@text, $files[0]); - push(@text, ""); - - while (<STDIN>) { - chop; # Drop the newline - push(@text, $_); - } - - &mail_notification($mailto, @text); - - exit 0; -} - -# Check for an import command. This appears with files set as follows: -# -# files[0] - "path/name" -# files[1] - "-" -# files[2] - "Imported" -# files[3] - "sources" -# -if ($files[2] =~ /Imported/ && $files[3] =~ /sources/) { - local(@text); - - @text = (); - push(@text, &build_header()); - push(@text, ""); - push(@text, $files[0]); - push(@text, ""); - - while (<STDIN>) { - chop; # Drop the newline - push(@text, $_); - } - - &mail_notification($mailto, @text); - - exit 0; -} - -# Iterate over the body of the message collecting information. -# -while (<STDIN>) { - chop; # Drop the newline - - if (/^In directory/) { - push(@log_lines, $_); - push(@log_lines, ""); - next; - } - - if (/^Modified Files/) { $state = $STATE_CHANGED; next; } - if (/^Added Files/) { $state = $STATE_ADDED; next; } - if (/^Removed Files/) { $state = $STATE_REMOVED; next; } - if (/^Log Message/) { $state = $STATE_LOG; next; } - - s/^[ \t\n]+//; # delete leading whitespace - s/[ \t\n]+$//; # delete trailing whitespace - - if ($state == $STATE_CHANGED) { push(@changed_files, split); } - if ($state == $STATE_ADDED) { push(@added_files, split); } - if ($state == $STATE_REMOVED) { push(@removed_files, split); } - if ($state == $STATE_LOG) { push(@log_lines, $_); } -} - -# Strip leading and trailing blank lines from the log message. Also -# compress multiple blank lines in the body of the message down to a -# single blank line. -# -while ($#log_lines > -1) { - last if ($log_lines[0] ne ""); - shift(@log_lines); -} -while ($#log_lines > -1) { - last if ($log_lines[$#log_lines] ne ""); - pop(@log_lines); -} -for ($i = $#log_lines; $i > 0; $i--) { - if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) { - splice(@log_lines, $i, 1); - } -} - -if ($debug) { - print STDERR "Searching for log file index..."; -} -# Find an index to a log file that matches this log message -# -for ($i = 0; ; $i++) { - local(@text); - - last if (! -e "$LOG_FILE.$i.$id"); # the next available one - @text = &read_logfile("$LOG_FILE.$i.$id", ""); - last if ($#text == -1); # nothing in this file, use it - last if (join(" ", @log_lines) eq join(" ", @text)); # it's the same log message as another -} -if ($debug) { - print STDERR " found log file at $i.$id, now writing tmp files.\n"; -} - -# Spit out the information gathered in this pass. -# -&append_names_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files); -&append_names_to_file("$ADDED_FILE.$i.$id", $dir, @added_files); -&append_names_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files); -&write_logfile("$LOG_FILE.$i.$id", @log_lines); - -# Check whether this is the last directory. If not, quit. -# -if ($debug) { - print STDERR "Checking current dir against last dir.\n"; -} -$_ = &read_line("$LAST_FILE.$id"); - -if ($_ ne $cvsroot . "/" . $files[0]) { - if ($debug) { - print STDERR sprintf("Current directory %s is not last directory %s.\n", $cvsroot . "/" .$files[0], $_); - } - exit 0; -} -if ($debug) { - print STDERR sprintf("Current directory %s is last directory %s -- all commits done.\n", $files[0], $_); -} - -# -# End Of Commits! -# - -# This is it. The commits are all finished. Lump everything together -# into a single message, fire a copy off to the mailing list, and drop -# it on the end of the Changes file. -# - -# -# Produce the final compilation of the log messages -# -@text = (); -@status_txt = (); -push(@text, &build_header()); -push(@text, ""); - -for ($i = 0; ; $i++) { - last if (! -e "$LOG_FILE.$i.$id"); # we're done them all! - @lines = &read_logfile("$CHANGED_FILE.$i.$id", ""); - if ($#lines >= 0) { - push(@text, "Modified files:"); - push(@text, &format_lists(@lines)); - } - @lines = &read_logfile("$ADDED_FILE.$i.$id", ""); - if ($#lines >= 0) { - push(@text, "Added files:"); - push(@text, &format_lists(@lines)); - } - @lines = &read_logfile("$REMOVED_FILE.$i.$id", ""); - if ($#lines >= 0) { - push(@text, "Removed files:"); - push(@text, &format_lists(@lines)); - } - if ($#text >= 0) { - push(@text, ""); - } - @lines = &read_logfile("$LOG_FILE.$i.$id", "\t"); - if ($#lines >= 0) { - push(@text, "Log message:"); - push(@text, @lines); - push(@text, ""); - } - if ($do_status) { - local(@changed_files); - - @changed_files = (); - push(@changed_files, &read_logfile("$CHANGED_FILE.$i.$id", "")); - push(@changed_files, &read_logfile("$ADDED_FILE.$i.$id", "")); - push(@changed_files, &read_logfile("$REMOVED_FILE.$i.$id", "")); - - if ($debug) { - print STDERR "main: pre-sort changed_files = ", join(":", @changed_files), ".\n"; - } - sort(@changed_files); - if ($debug) { - print STDERR "main: post-sort changed_files = ", join(":", @changed_files), ".\n"; - } - - foreach $dofile (@changed_files) { - if ($dofile =~ /\/$/) { - next; # ignore the silly "dir" entries - } - if ($debug) { - print STDERR "main(): doing 'cvs -nQq status -v $dofile'\n"; - } - open(STATUS, "-|") || exec 'cvs', '-nQq', 'status', '-v', $dofile; - while (<STATUS>) { - chop; - push(@status_txt, $_); - } - } - } -} - -# Write to the commitlog file -# -if ($commitlog) { - &write_commitlog($commitlog, @text); -} - -if ($#status_txt >= 0) { - push(@text, @status_txt); -} - -# Mailout the notification. -# -&mail_notification($mailto, @text); - -# cleanup -# -if (! $debug) { - &cleanup_tmpfiles(); -} - -exit 0; diff --git a/gnu/usr.bin/cvs/contrib/mfpipe.pl b/gnu/usr.bin/cvs/contrib/mfpipe.pl deleted file mode 100644 index bae7a72..0000000 --- a/gnu/usr.bin/cvs/contrib/mfpipe.pl +++ /dev/null @@ -1,88 +0,0 @@ -#! xPERL_PATHx -# -*-Perl-*- -# -# From: clyne@niwot.scd.ucar.EDU (John Clyne) -# Date: Fri, 28 Feb 92 09:54:21 MST -# -# BTW, i wrote a perl script that is similar to 'nfpipe' except that in -# addition to logging to a file it provides a command line option for mailing -# change notices to a group of users. Obviously you probably wouldn't want -# to mail every change. But there may be certain directories that are commonly -# accessed by a group of users who would benefit from an email notice. -# Especially if they regularly beat on the same directory. Anyway if you -# think anyone would be interested here it is. -# -# $Id: mfpipe.pl,v 1.2 1995/07/10 02:01:57 kfogel Exp $ -# -# -# File: mfpipe -# -# Author: John Clyne -# National Center for Atmospheric Research -# PO 3000, Boulder, Colorado -# -# Date: Wed Feb 26 18:34:53 MST 1992 -# -# Description: Tee standard input to mail a list of users and to -# a file. Used by CVS logging. -# -# Usage: mfpipe [-f file] [user@host...] -# -# Environment: CVSROOT -# Path to CVS root. -# -# Files: -# -# -# Options: -f file -# Capture output to 'file' -# - -$header = "Log Message:\n"; - -$mailcmd = "| mail -s 'CVS update notice'"; -$whoami = `whoami`; -chop $whoami; -$date = `date`; -chop $date; - -$cvsroot = $ENV{'CVSROOT'}; - -while (@ARGV) { - $arg = shift @ARGV; - - if ($arg eq '-f') { - $file = shift @ARGV; - } - else { - $users = "$users $arg"; - } -} - -if ($users) { - $mailcmd = "$mailcmd $users"; - open(MAIL, $mailcmd) || die "Execing $mail: $!\n"; -} - -if ($file) { - $logfile = "$cvsroot/LOG/$file"; - open(FILE, ">> $logfile") || die "Opening $logfile: $!\n"; -} - -print FILE "$whoami $date--------BEGIN LOG ENTRY-------------\n" if ($logfile); - -while (<>) { - print FILE $log if ($log && $logfile); - - print FILE $_ if ($logfile); - print MAIL $_ if ($users); - - $log = "log: " if ($_ eq $header); -} - -close FILE; -die "Write failed" if $?; -close MAIL; -die "Mail failed" if $?; - -exit 0; diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog b/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog deleted file mode 100644 index ac24f44..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/ChangeLog +++ /dev/null @@ -1,774 +0,0 @@ -Wed Nov 22 11:01:50 1995 Joshua Cowan <jcowan@hermit.reslife.okstate.edu> - - * 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 <kfogel@floss.cyclic.com> - - * "/bin/rmdir" as default, not "/usr/local/bin/rmdir". - -Fri Jun 16 15:24:34 1995 Jim Kingdon (kingdon@cyclic.com) - - * pcl-cvs.elc, pcl-cvs-lucid.elc: Added. - - * Makefile.in: Rename from Makefile and set srcdir. - -Thu May 18 17:10:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - Automatically guess CVS log entries from ChangeLog contents. - * pcl-cvs.el (cvs-mode-changelog-commit): New command. - (cvs-changelog-full-paragraphs): New variable. - (cvs-changelog-name, cvs-narrow-changelog, - cvs-changelog-paragraph, cvs-changelog-subparagraph, - cvs-changelog-entry, cvs-changelog-ours-p, cvs-relative-path, - cvs-changelog-entries, cvs-changelog-insert-entries, cvs-union, - cvs-insert-changelog-entries, cvs-edit-delete-common-indentation): - New functions. - (cvs-mode-map): Bind 'C' to cvs-mode-changelog-commit. - (cvs-mode): Mention cvs-mode-changelog-commit in docstring. - - Give the info files names ending in ".info". - * Makefile (INFOFILES, install_info): Change pcl-cvs to - pcl-cvs.info. - (pcl-cvs.info): Target renamed from pcl-cvs. - (DISTFILES): pcl-cvs removed; we handle the info files explicitly - in the dist-dir target. - (dist-dir): Depend on pcl-cvs.info. Distribute pcl-cvs.info*. - * pcl-cvs.texinfo: Change @setfilename appropriately. - * INSTALL: Updated. - * .cvsignore: Correctly ignore the info files. - - * README: Note that pcl-cvs has been tested under 19.28, and that - the "cookie" naming conflict was resolved in 19.11. - - * Makefile (pcl-cvs-lucid.elc): Changed this target from - pcl-cvs-lucid.el. That's a source file, for goodness' sake! - -Tue May 9 13:56:50 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Change references to "Cygnus's remote CVS" to "Cyclic CVS". - -Wed May 3 13:55:27 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * pcl-cvs.el (cvs-parse-stderr): Handle colons after both - "rcsmerge" and "warning". - -Fri Apr 28 22:38:14 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Makefile (ELFILES): Include pcl-cvs-startup.el. - (info, pcl-cvs): Call makeinfo appropriately for modern versions. - (pcl-cvs.aux): List dependency on pcl-cvs.texinfo. - (pcl-cvs.ps): New target. - (DVIPS): New variable. - (dist-dir): Renamed from dist, updated to accept DISTDIR value - passed from parent. - (DISTFILES): New varible. - (pcl-cvs.elc, pcl-cvs-lucid.elc): Add targets to elcfiles target. - -Tue Apr 25 21:33:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * pcl-cvs.el: (cvs-parse-stderr): Recognize "conflicts" as well as - "overlaps" before "during merge." - -Thu Feb 16 12:17:20 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * pcl-cvs.el (cvs-parse-stderr): Recognize "conflicts found in..." - messages attributed to "cvs server", as well as "cvs update". - -Sat Feb 4 01:47:01 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * pcl-cvs.el: Deal with the 'P' action, produced by remote CVS. - (cvs-parse-stdout): Treat 'P' like 'U' --- file is updated. - -Tue Jan 31 23:31:39 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * pcl-cvs.el (cvs-cvsroot-required): New variable. - (cvs-do-update): If cvs-cvsroot-required is not set, don't complain if - CVSROOT and cvs-cvsroot are both unset. - -Sun Jan 22 21:22:22 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * pcl-cvs.el (cvs-parse-stderr): - Some changes for Cygnus's Remote CVS. Treat - messages like "cvs server: Updating DIRECTORY" as we treat those like - "cvs update: Updating DIRECTORY". Ignore other messages starting with - "cvs server". - - * pcl-cvs.el (cvs-parse-stderr): Re-indent. - - * .cvsignore: Add ignore list for Texinfo litter. - - * Makefile (lispdir): Set appropriately for totoro. - * pcl-cvs.el (cvs-program, cvs-diff-program, cvs-rmdir-program): Same. - -Tue Jun 1 00:00:03 1993 Per Cederqvist (ceder@lysator.liu.se) - - * Release 1.05. (This release was promised before the end of May, - but I didn't quite make it. No, I didn't fake the date above). - -Mon May 31 01:32:25 1993 Per Cederqvist (ceder@lysator.liu.se) - - * Removed the elib sub-directory. Users must now get the Elib - library separately. - * pcl-cvs.texinfo: Document it. - - * pcl-cvs-lucid.el: A new version, supplied by Jamie Zawinsky, - added. - - * pcl-cvs Id 68: Transform RCS keywords - * Makefile (pcl-cvs-$(VER)): Remove the $ signs in most files in - the distribution. - - * pcl-cvs Id 76: Extra " in cvs-mode-add. - * pcl-cvs.el (cvs-mode-add): Don't add the extra level of quotes - around the log message, since it doesn't work with CVS. - - * pcl-cvs Id 56: '-d <CVSROOT>' support in pcl-cvs - * pcl-cvs.el (cvs-change-cvsroot): New function. - - * pcl-cvs Id 77: *cvs* isn't cleared properly - * pcl-cvs.el (cvs-do-update): Always erase the *cvs* buffer and - re-create the collection. - - * pcl-cvs.el (cvs-do-update): Set mode-line-process in the *cvs* - buffer. - * pcl-cvs.el (cvs-mode): Reset mode-line-process. - - * pcl-cvs Id 59: sort .cvsignore alphabetically! - * pcl-cvs.el (cvs-sort-ignore-file): New variable. - * pcl-cvs.el (cvs-mode-ignore): Use it. - * pcl-cvs.texinfo: Document it. - - * pcl-cvs Id 75: Require final newline. - * pcl-cvs.el (cvs-commit-buffer-require-final-newline): New - variable. - * pcl-cvs.el (cvs-edit-done): Use it. - * pcl-cvs.texinfo: Document it. - - * pcl-cvs Id 72: make clean deletes lucid-emacs.el - * dist-makefile (ELCFILES): Fixed a typo. - - * pcl-cvs Id 46: "cvs remove f" "touch f" "cvs update f" -> parse err. - * pcl-cvs.el (cvs-fileinfo->type): New type: REM-EXIST. - * pcl-cvs.el (cvs-shadow-entry-p): A REMOVED that follows a - REM-EXIST is a shadow. - * pcl-cvs.el (cvs-parse-stderr): Recognize the "should be removed - and is still there" message. - * pcl-cvs.el (cvs-pp): Recognize REM-EXIST. - * pcl-cvs.el (cvs-mode-undo-local-changes): Recognize and complain - about REM-EXIST. Defensive test added: complain about unknown types. - - * pcl-cvs.el (cvs-mode-add): Add an extra level of quotes around - the log message. This is apparently needed by RCVS. <This change - has been removed. --ceder>. - - * pcl-cvs.el (cvs-parse-stderr): Ignore output from RCVS. - -Tue Apr 27 00:48:40 1993 Per Cederqvist (ceder@lysator.liu.se) - - * pcl-cvs.el (cvs-startup-message): Now a defconst instead of a - defvar. - * pcl-cvs.el (cvs-mode-commit): Add a defvar for it. - - * dist-makefile (EMACS): Use $(EMACS) instead of hard-coding 'emacs'. - -Sat Apr 17 12:47:10 1993 Per Cederqvist (ceder@lysator.liu.se) - - * Release 1.04. - - * pcl-cvs.texinfo: Updated the Contributors node. - - * pcl-cvs Id 58: Lucid GNU Emacs support - * pcl-cvs-lucid.el: New file, contributed by the people at Lucid. - * pcl-cvs.el: Autoload pcl-cvs-lucid if running in an Lucid GNU - Emacs. - * compile-all.el: (files-to-compile): Add pcl-cvs-lucid. - * dist-makefile (ELFILES, ELCFILES): Dito. - - * pcl-cvs Id 55: cvs-diff-backup swaps old and new version. - * pcl-cvs.el (cvs-diff-backup-extractor): Old version should be - first. - * pcl-cvs.el (cvs-mode-diff-backup): Call cvs-backup-diffable - correctly. - - * pcl-cvs Id 64: elib substitute - * dist-makefile (install): Warn about Elib. - * pcl-cvs.texinfo: Talk about Elib. - - * pcl-cvs Id 50: Committing the *commit* buffer twice. - * pcl-cvs.el (cvs-edit-done): Report an error if cvs-commit-list - is empty, and empty it when the commit is done. - - * pcl-cvs Id 56: '-d <CVSROOT>' support. - * pcl-cvs.el (cvs-cvsroot): New variable. - * pcl-cvs.el (cvs-do-update, all callers of cvs-execute-list): Use - it everywhere CVS is called, to override CVSROOT. - * pcl-cvs.texinfo (Customization): Document it. - -Thu Apr 1 00:34:55 1993 Per Cederqvist (ceder@lysator.liu.se) - - * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Exit status nil - from call-process means everything was successful in some Emacs - versions. - - * pcl-cvs.el (cvs-mode-map): Bind "q" to bury-buffer. - * pcl-cvs.texinfo: Document it. - -Thu Mar 11 00:05:03 1993 Per Cederqvist (ceder@lysator.liu.se) - - * Release 1.03-Emerge (not released). - - * Makefile (pcl-cvs-$(VER)): Don't includ elib-dll-debug.el in the - distribution. (It's included as elib/dll-debug.el). - - * pcl-cvs.el (cvs-mode): Document the "e" key (cvs-mode-emerge). - -Tue Mar 9 00:02:57 1993 Per Cederqvist (ceder@lysator.liu.se) - - * pcl-cvs.texinfo (Emerge): New node. - - * pcl-cvs.el (cvs-kill-buffer-visiting): New function. - - * pcl-cvs.el (cvs-mode-emerge): Handle Conflict and Merged files. - - * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): Handle any revision. - - * pcl-cvs.el (cvs-fileinfo-*): Store base-revision instead of - backup-file. - - * pcl-cvs.el (cvs-backup-diffable): The file is only diffable if - the backup file is readable. - - * pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-emerge instead - of cvs-mode-find-file (which is anyhow bound to "f"). - -Mon Mar 8 23:06:52 1993 Per Cederqvist (ceder@lysator.liu.se) - - * pcl-cvs.el (cvs-mode-emerge): New function. Currently only - handles emerge of Modified files. - - * pcl-cvs.el (cvs-retrieve-revision-to-tmpfile): New function. - -Sun Jan 24 20:07:18 1993 Per Cederqvist (ceder@lysator.liu.se) - - * elib-dll-debug.el: Moved to elib. - -Mon Jan 18 00:35:59 1993 Per Cederqvist (ceder@mauritz) - - * pcl-cvs.el (cvs-do-update): Added a probably unnecessary sit-for. - - * Release 1.03-Elib-0.05.1 (not released). - - * Elib 0.05 compatibility: - * elib-dll-debug.el, pcl-cvs-buffer.el, test-dll.el: Fix the - require strings. - * pcl-cvs.el (cvs-pp): Insert the string. - - * Release 1.03-Elib-0.05 (not released). - - * elib: New directory, containing the parts of elib that are - required for pcl-cvs. Changes to the files in that directory - that are present in Elib are documented in the ChangeLog of - Elib, not here. - * Makefile (pcl-cvs-$(VER)): Copy the new dir to the distribution. - * dist-makefile (ELFILES, ELCFILES): Don't include the Elib files. - -Fri Jan 8 02:43:49 1993 Per Cederqvist (ceder@konrad) - - * pcl-cvs.el (cvs-mode-map): Bind "e" to cvs-mode-find-file, like - in dired. - -Sun Jan 3 23:25:13 1993 Per Cederqvist (ceder@konrad) - - * elib-dll.el, elib-node.el, cookie.el: Moved to the elib package. - Pcl-cvs now requires elib. - -Tue Dec 29 22:06:57 1992 Per Cederqvist (ceder@konrad) - - * pcl-cvs.el: Tracked the latest (last?) rename of all functions - in cookie.el. - -Thu Sep 24 00:29:16 1992 Per Cederqvist (ceder@robert) - - * pcl-cvs.texinfo (Archives): This version is not distributed with - CVS 1.3, so don't claim that it is. - -Fri Aug 21 15:17:08 1992 Per Cederqvist (ceder@maskros) - - * pcl-cvs.el (cvs-parse-stderr): Fixed two "(set head" that should - be "(setq head". - -Thu Aug 20 05:53:58 1992 Per Cederqvist (ceder@robin) - - * cookie.el: Changes to this file is documented in the ChangeLog - of elib in the future. - -Tue Aug 18 03:30:28 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el: Don't use cookie-last-tin (which no longer exists). - - * cookie.el: Use prefix cookie:: for internal functions. - - * cookie.el: (cookie:enter-after, cookie:enter-before, - cookie:nth-cookie): Implemented. - * cookie.el: No longer define (impl). - - * cookie.el: More renames: - cookie:next-cookie -> cookie:goto-next-tin - cookie:previous-cookie -> cookie:goto-previous-tin - tin-next -> cookie:next-tin - tin-previous -> cookie:previous-tin - tin-nth -> cookie:nth-tin - tin-delete -> cookie:delete-tin - cookie:collect -> cookie:collect-cookies - cookie:tin-collect -> cookie:collect-tins - (new) -> cookie:tin-collect-cookies - (new) -> cookie:tin-collect-tins - cookie:refresh -> cookie:refresh-all - tin-invalidate-tins -> cookie:invalidate-tins - -Mon Aug 17 01:39:49 1992 Per Cederqvist (ceder@robin) - - * cookie.el (cookie:set-buffer-bind-dll-let*): New macro. Used in - many places instead of cookie:set-buffer-bind-dll. - * cookie.el (cookie:set-buffer-bind-dll): Renamed the macro - cookie:set-buffer to this. - - * pcl-cvs.el (cvs-use-temp-buffer): Set default-directory. - -Sun Aug 16 20:51:30 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-add-sub): Fixed call to cvs-add-file-update-buffer. - -Sat Aug 8 20:28:21 1992 Per Cederqvist (ceder@robin) - - * Release 1.03-Cookie-II (not released). - - * pcl-cvs.el (cvs-mode-diff-cvs): Don't care about the exit status - from ``cvs diff''. - - * pcl-cvs.el (cvs-mode): Document cvs-mode-undo-local-changes. - * pcl-cvs.el (cvs-diffable): New function. - - * pcl-cvs.el: Use the new cookie package. - * pcl-cvs.el (cvs-cookie-handle): New variable. - * pcl-cvs.el (cvs-do-update): User the new cookie:create - interface, and cookie:clear if the buffer already existed. Make - the buffer read-only. - * pcl-cvs.el (cvs-mode-next-line, cvs-mode-previous-line): New - functions (used instead of cookie:next-cookie and - cookie:previous-cookie). - - * cookie.el: Major redesign. The handle that is passed to all - cookie functions is now a new datatype, and not the buffer that - the cookies resides in. This way it is possible to have more than - one set of cookies in a buffer. Things that used to be - buffer-local variables are now fields in the handle data type. - cookie-last-tin is no longer available. - * cookie.el (cookie:create): The buffer is not cleared, nor set to - be read-only. - * cookie.el (cookie:next-cookie, cookie:previous-cookie): Since - the first argument is now a handle and not a buffer, these can no - longer be called interactively. You have to write a small wrapper - about them. - * cookie.el (cookie:buffer): New function. - -Tue Aug 4 03:02:25 1992 Per Cederqvist (ceder@robert) - - * pcl-cvs.texinfo (Bugs): Renamed "Reporting bugs and ideas" to - "Bugs" and added a table of known bugs/FAQ:s. - -Mon Aug 3 00:19:39 1992 Per Cederqvist (ceder@robert) - - * pcl-cvs.el, pcl-cvs.texinfo: Big Renaming Time! - The commands that operate in the *cvs* buffer: - cvs-add-change-log-entry-other-window -> cvs-mode-add-change-log-entry-other-window - cvs-mark-all-files -> cvs-mode-mark-all-files - cvs-revert-updated-buffers -> cvs-mode-revert-updated-buffers - cvs-undo-local-changes -> cvs-mode-undo-local-changes - cvs-unmark-up -> cvs-mode-unmark-up - cvs-acknowledge -> cvs-mode-acknowledge - cvs-unmark-all-files -> cvs-mode-unmark-all-files - cvs-add -> cvs-mode-add - cvs-diff-backup -> cvs-mode-diff-backup - cvs-commit -> cvs-mode-commit - cvs-diff-cvs -> cvs-mode-diff-cvs - cvs-find-file -> cvs-mode-find-file - cvs-update-no-prompt -> cvs-mode-update-no-prompt - cvs-ignore -> cvs-mode-ignore - cvs-log -> cvs-mode-log - cvs-mark -> cvs-mode-mark - cvs-find-file-other-window -> cvs-mode-find-file-other-window - cvs-remove-file -> cvs-mode-remove-file - cvs-status -> cvs-mode-status - cvs-remove-handled -> cvs-mode-remove-handled - cvs-unmark -> cvs-mode-unmark - - * pcl-cvs.el (cvs-cvs-diff-flags): Variable deleted. - * pcl-cvs.el (cvs-diff-cvs): Use cvs-diff-flags instead. - * pcl-cvs.texinfo (Customization): Update the doc. - - * pcl-cvs.el (cvs-diff-cvs): Handle exit status 0 (no diffs), 1 - (diffs) and other (error). - * pcl-cvs.el (cvs-execute-list): Add support for this kind of - thing. - - * Revert buffers for committed files: - * pcl-cvs.el (cvs-auto-revert-after-commit): New variable. - * pcl-cvs.texinfo (Committing changes, Customization): Document - it. - * pcl-cvs.el (cvs-after-commit-function): New function. - - * pcl-cvs.el (cvs-execute-list): Return the exit status or nil. - * pcl-cvs.el (cvs-edit-done, cvs-diff-cvs, cvs-remove-file, - cvs-undo-local-changes, cvs-add, cvs-status, cvs-log): Use the - exit status to generate an error message. - - - * pcl-cvs.el (cvs-do-update): It should be "cvs -n update -l", not - "cvs -l update -n". Put the -n and/or -l in the message that is - displayed in the *cvs* buffer during the update. - -Sat Aug 1 00:55:49 1992 Per Cederqvist (ceder@robert) - - * cookie.el (cookie-sort): New function. - - * cookie.el (cookie-clear): Rewritten. No longer clears all local - variables. - -Tue Jul 28 17:21:17 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-parse-stderr): Try to handle the output from RCS - when it is compiled without DIFF3_BIN and a conflict occurs. - - * pcl-cvs.texinfo (Getting Started): Fixed typo. - - * pcl-cvs-startup.el (cvs-update-other-window): Make the autoload - be interactive. - -Mon Jul 27 19:36:40 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-revert-updated-buffers, cvs-revert-fileinfo): - New functions. - * pcl-cvs.texinfo (Reverting your buffers): Document it. - - * pcl-cvs.el (cvs-fileinfo->full-path): New function. - * pcl-cvs.el (cvs-full-path): Use it. - - * cookie.el (cookie-map, cookie-map-reverse): Better doc- - string. Removed the unused local variable 'result'. - - * compile-all.el: Renamed elib-files to files-to-compare. - * compile-all.el (compile-pcl-cvs): Bind load-path in a let - statement instead of globally. - -Thu Jul 23 19:02:41 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-do-update): Check that CVSROOT is set. - * pcl-cvs.el (cvs-diff-cvs): Check that cvs-cvs-diff-flags is a - list. - * pcl-cvs.el (cvs-diff-backup): Check that cvs-diff-flags is a - list. - -Tue Jul 21 11:27:39 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-parse-error): Make the *cvs* buffer writeable - before trying to write the email message. Require sendmail before - trying to switch to mail-mode. - - * pcl-cvs.el (cvs-do-update): Check that cvs-program exists. - - * pcl-cvs.el (cvs-skip-line): Fixed bracketing error. - -Mon Jul 20 10:31:51 1992 Per Cederqvist (ceder@robin) - - * Release 1.03. - - * pcl-cvs.el, cookie.el: Indentation fixes. - - * Makefile (pcl-cvs-$(VER)): Include NEWS in the distribution. - - * pcl-cvs.el (cvs-rm-program): Deleted. - * pcl-cvs.el (cvs-rmdir-program, cvs-lock-file): New variables. - - * Handle lock files in a nicer way: - * pcl-cvs.el (cvs-update-filter, cvs-delete-lock, - cvs-lock-file-p): New functions. - * pcl-cvs.el (cvs-do-update, cvs-sentinel): Redirect stdout to the - temporary file, not stderr. Use cvs-update-filter. - * pcl-cvs.el (cvs-parse-update): New arguments. - * pcl-cvs.el (cvs-parse-buffer): Renamed to cvs-parse-update. - * pcl-cvs.el (cvs-stderr-file): Renamed to cvs-stdout-file. - * pcl-cvs.texinfo (Miscellaneous commands, Updating the - directory): Document cvs-delete-lock. - - * pcl-cvs.el (cvs-mode): Don't reset buffer-read-only. - - * pcl-cvs.el (cvs-find-file-other-window): Don't save-some-buffers. - -Thu Jul 16 00:19:58 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el, test-cookie-el: Use the new names from cookie.el. - - * cookie.el: Big Renaming Time! - External functions: - cookie-next -> tin-next - cookie-previous -> tin-previous - cookie-nth -> tin-nth - cookie-delete -> tin-delete - cookie-filter-tins -> tin-filter - cookie-get-selection -> tin-get-selection - cookie-start-marker -> tin-start-marker - cookie-end-marker -> tin-end-marker - cookie-invalidate-tins -> tin-invalidate-tins - cookie-collect-tins -> tin-collect - cookie-collect-cookies -> cookie-collect - Internal functions: - cookie-create-tin -> cookie-create-wrapper - cookie-tin-start-marker -> cookie-wrapper-start-marker - cookie-tin-cookie-safe -> cookie-wrapper-cookie-safe - cookie-tin-cookie -> cookie-wrapper-cookie - set-cookie-tin-start-marker -> cookie-wrapper-set-start-marker - set-cookie-tin-cookie -> cookie-wrapper-set-cookie - cookie-tin-p -> cookie-wrapper-p - cookie-create-tin-and-insert -> cookie-create-wrapper-and-insert - - * pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Signal - an appropriate error message if the *cvs* buffer is empty. - - * cookie.el (cookie-create): Make the buffer read-only. - * cookie.el (cookie-create-tin-and-insert, cookie-refresh, - cookie-delete-tin-internal, cookie-refresh-tin): Bind - buffer-read-only to nil while changing the contents of - the buffer. - - * pcl-cvs.el (cvs-byte-compile-files): New function. - * pcl-cvs.texinfo (Miscellaneous commands): Document it. - - * pcl-cvs.el (cvs-diff-ignore-marks): New variable. - * pcl-cvs.el (cvs-diff-cvs, cvs-diff-backup): Don't consider - marked files to be selected if a prefix argument is given XOR the - variable cvs-diff-ignore-marks is non-nil. - * pcl-cvs.el (cvs-get-marked): New optional argument `ignore-marks'. - * pcl-cvs.texinfo (Customization, Viewing differences): Document - this behaviour. - - * pcl-cvs.el (cvs-undo-local-changes): New function. - * pcl-cvs.texinfo (Undoing changes): Document - cvs-undo-local-changes. - * pcl-cvs.el (cvs-mode-map): cvs-unmark-all-files moved from "U" - to "ESC DEL". cvs-undo-local-changes bound to "U". - * pcl-cvs.texinfo (Marking files): Document ESC DEL. - - * pcl-cvs.el (cvs-skip-line): New arguments. All callers updated. - Now calls cvs-parse-error if a parse error occurs. - * pcl-cvs.el (cvs-parse-error): New function that creates a bug - report. - * pcl-cvs.el (cvs-parse-stderr, cvs-parse-stdout): New arguments. - The only caller (cvs-parse-buffer) updated. Call cvs-parse-error - in case of parse error. - - * pcl-cvs.el (pcl-cvs-version): New variable. - - * cookie.el (cookie-create): Kill all local variables in the buffer. - -Fri Jul 10 11:17:40 1992 Per Cederqvist (ceder@robin) - - * Release 1.03beta1. - -Thu Jul 9 03:12:00 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-update-running): New variable. - * pcl-cvs.el (cvs-do-update): Use it instead of the previous local - variable cvs-process (that no longer exists). Make sure that only - one `cvs update' runs at any given moment. - * pcl-cvs.el (cvs-sentinel): Reset cvs-update-running when the - update process exits. - - * pcl-cvs.el (cvs-update): Switch to the *cvs* buffer. - * pcl-cvs.el (cvs-update-other-window): New function. - * pcl-cvs-startup.el (cvs-update-other-window): Added a autoload - for it. - * pcl-cvs.el (cvs-do-update): Don't pop up any buffer in a window - - let cvs-update or cvs-update-other-window handle that. Also - don't kill the *cvs* buffer, but rather insert a "Running cvs..." - message into it. - * pcl-cvs.el (cvs-parse-buffer): Don't change the window - configuration. - - * pcl-cvs.el (cvs-create-fileinfo, cvs-pp, cvs-fileninfo->type): - New type for a fileinfo: MESSAGE. - - * pcl-cvs.el (cvs-cvs-buffer): Deleted the variable. Use - cvs-buffer-name instead. (I no longer have any plans to allow more - than one cvs update to run at the same time - things only get - confusing). Changed all places where cvs-cvs-buffer was used. - - * pcl-cvs.el: Take care of update programs (the -u option in the - modules file): - * pcl-cvs.el (cvs-update-prog-output-skip-regexp): New variable. - * pcl-cvs.el (cvs-parse-stdout): Skip output from the update - program (using cvs-update-prog-output-skip-regexp). - * pcl-cvs.texinfo (Future enhancements): Document that the - solution is not as good as it should be. - * pcl-cvs.texinfo (Customization): Document the variable. - -Wed Jul 8 20:29:44 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-do-update): Check that this-dir really exists - and is a directory, and that this-dir/CVS exists and is a - directory. - -Tue Jul 7 01:02:24 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.texinfo (Customization): Document TMPDIR. - - * This chunk of modifications should make it possible to run - pcl-cvs on hosts that do not line-buffer stdout (such as - DECstation). They work by diverting stdout and stderr from - `cvs update' and later sorting them together. - * pcl-cvs.el (cvs-parse-stderr): Don't fail to parse conflict - data. - * pcl-cvs.el (cvs-remove-stdout-shadows, cvs-shadow-entry-p): New - functions. - * pcl-cvs.el (cvs-parse-buffer): Use it. - * pcl-cvs.el (cvs-remove-empty-directories): New function. - * pcl-cvs.el (cvs-remove-handled, cvs-parse-buffer): Use it. - * pcl-cvs.el (cvs-get-current-dir): New argument ROOT-DIR. All - calls to cvs-get-current-dir updated. - * pcl-cvs.el (cvs-do-update): Allocate a tmp file. Use cvs-shell - (typically /bin/sh) to redirect stderr from CVS to the tmp file. - * pcl-cvs.el (cvs-sentinel): Handle the tmp file. Remove it when - it is parsed. - * pcl-cvs.el (cvs-parse-buffer): New argument STDERR-BUFFER. All - calls to cvs-parse-buffer updated. Rewritten to handle the - separation of stderr and stdout. - * pcl-cvs.el (cvs-shell, cvs-stderr-file): New variables. - * pcl-cvs.el (cvs-compare-fileinfos, cvs-parse-stderr, - cvs-parse-stdout): New functions. - - * pcl-cvs.el (cvs-parse-buffer): Some modifications for output - from RCS 5.6. - -Tue Apr 7 09:11:27 1992 Per Cederqvist (ceder@leopold) - - * Release 1.02. - - * pcl-cvs.el (cvs-diff-backup, cvs-edit-done, cvs-status): Call - save-some-buffers. - - * pcl-cvs.el (cvs-diff-backup-extractor): Fixed syntax error. - - * Makefile, README, compile-all.el, dist-makefile, pcl-cvs.el, - pcl-cvs.texinfo (XXRELEASEXX): A magic string that is substituted - for the current release number when a distribution is made. - (Release 1.01 says that it is release 1.00). - - * pcl-cvs.el (cvs-find-file): Added missing pair of parenthesis. - -Mon Mar 30 14:25:26 1992 Per Cederqvist (ceder@leopold) - - * Release 1.01. - - * pcl-cvs.el (cvs-parse-buffer): The message when waiting for a - lock has been changed. - -Sun Mar 29 05:29:57 1992 Per Cederqvist (ceder@leopold) - - * Release 1.00. - - * pcl-cvs.el (cvs-do-update, cvs-sentinel, cvs-parse-buffer): - Major rewrite of buffer and window selection and handling. - The *cvs* buffer is now killed whenever a new "cvs update" is - initiated. The -update buffer is replaced with the *cvs* - buffer when the update is completed. - -Sat Mar 28 21:03:05 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-delete-unused-temporary-buffers): Fixed it. - - * pcl-cvs.el (cvs-auto-remove-handled): New variable. - * pcl-cvs.el (cvs-edit-done): Use it. - * pcl-cvs.texinfo (Customization, Removing handled entries): - Document it. - - * pcl-cvs.el (cvs-mode): Turn of the undo feature. It really - isn't useful in a cookie buffer... - - * pcl-cvs.el (cvs-edit-done): Committing a file now looks more - like diffing a file. The window handling is better. - * pcl-cvs.el (cvs-use-temp-buffer): The &optional switch is no - longer needed. - -Mon Mar 23 00:20:33 1992 Per Cederqvist (ceder@robin) - - * Release 0.97. - - * pcl-cvs.el (default-directory): Make sure it always ends in a - slash. fileinfo->dir does NOT end in a slash, and I had forgotten - to call file-name-as-directory in various places. - - * pcl-cvs.el (cvs-diff-backup-extractor): Signal an error if a - fileinfo without backup file is given. - - * pcl-cvs.el (cvs-mode): Added documentation. - - * pcl-cvs.el (cvs-execute-list): Fix the order of files in the - same directory. - - * pcl-cvs.el (cvs-log-flags, cvs-status-flags): New variables. - * pcl-cvs.el (cvs-log, cvs-status): Use them. - * pcl-cvs.texinfo (Customization): Document them. - - * pcl-cvs.el (cvs-diff-backup): Filter non-backup-diffable files - at an earlier stage, like cvs-commit does. - - * pcl-cvs.el (cvs-diff-flags): New variable. - * pcl-cvs.el (cvs-diff-backup): Use it. - * pcl-cvs.texinfo (Customization): Document it. - - * pcl-cvs.el (cvs-execute-single-file-list): Remove &rest before - last argument. No callers needed updating. - - * pcl-cvs.el (cvs-execute-list): Remove the &rest before the last - argument (constant-args). Update all callers of cvs-execute-list - to use the new calling convention. - * pcl-cvs.el (cvs-cvs-diff-flags): Now a list of strings instead - of a string. - * pcl-cvs.texinfo (Customization): Document the change to - cvs-cvs-diff-flags. - - * Release 0.96. - - * pcl-cvs.el (cvs-cvs-diff-flags): New variable. - * pcl-cvs.el (cvs-diff-cvs): Use it. - * pcl-cvs.texinfo (Customization, Viewing differences): Document it. - - * pcl-cvs.el (cvs-use-temp-buffe): Don't switch to the temporary - buffer. Use display-buffer and set-buffer instead. This way - cvs-log, cvs-status, cvs-diff-cvs and friends don't select the - temporary buffer. The cursor will remain in the *cvs* buffer. - -Sun Mar 22 21:50:18 1992 Per Cederqvist (ceder@robin) - - * pcl-cvs.el (cvs-find-file, cvs-find-file-other-window): Don't - prompt when reading in a directory in dired. - - * Makefile (pcl-cvs-$(VER)): Include pcl-cvs-startup.el in the - distribution. - - * dist-makefile (pcl-cvs.dvi): Don't fail even if texindex does - not exist. - - * pcl-cvs.texinfo (@setchapternewpage): Changed from 'off' to 'on'. - * pcl-cvs.texinfo (Variable index): Joined into function index. - * pcl-cvs.texinfo (Key index): add a description about the key. - * pcl-cvs.texinfo: Many other small changes. - -Wed Mar 18 01:58:38 1992 Per Cederqvist (ceder@leopold) - - * Use GNU General Public License version 2. - diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL b/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL deleted file mode 100644 index 7679967..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/INSTALL +++ /dev/null @@ -1,89 +0,0 @@ -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'. - - 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: - - (setq delete-exited-processes nil) - - Setting `delete-exited-processes' to `nil' works around a bug in - emacs that causes it to dump core. The bug was fixed in emacs - 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. - - 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. - - 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 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. - - 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. - - - -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. - - -How to make the on-line manual from pcl-cvs.texinfo -=================================================== - - 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). - - -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'. - - 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. - diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile b/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile deleted file mode 100644 index 7186a6b..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# $Id: Makefile,v 1.6 1995/12/11 01:27:18 peter Exp $ - -FILES= ChangeLog INSTALL NEWS README \ - compile-all.el pcl-cvs-lucid.el pcl-cvs-startup.el \ - pcl-cvs.el pcl-cvs.texinfo compile.sh - -NOOBJ= noobj - -EXAMPDIR= /usr/share/examples/cvs - -beforeinstall: - ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 \ - ${FILES} ${DESTDIR}${EXAMPDIR}/pcl-cvs - -.include "../../../Makefile.inc" -.include <bsd.prog.mk> diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS b/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS deleted file mode 100644 index 4f563ff..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/NEWS +++ /dev/null @@ -1,113 +0,0 @@ -This is the NEWS file for pcl-cvs, an Elisp front-end to CVS. - -User-visible changes in pcl-cvs from 1.04 to 1.05: - -* Elib is no longer distributed with pcl-cvs. You must get Elib - separately, for instance from ftp.lysator.liu.se in pub/emacs. - -* The Lucid Emacs support works again. - -* A new function, cvs-change-cvsroot, can be used to interactively - switch between CVS repositories. - -* The mode line in the *cvs* buffer now indicates when a "cvs update" - is running. - -* The .cvsignore file is automatically sorted alphabetically (to - reduce the risk of conflicts when two people add different files - simultaneously). This behaviour can be turned off with - cvs-sort-ignore-file. - -* A trailing newline is always added in commit log messages. This - behaviour can be turned off with - cvs-commit-buffer-require-final-newline. - -* This version of pcl-cvs should work together with RCVS. I have not - tested this myself, though. - -* Plus some bug fixes. (Note that the version of cookie.el that is - distributed with pcl-cvs 1.04 contains errors that affects pcl-cvs. - You should get Elib 0.07). - - -User-visible changes in pcl-cvs from 1.03 to 1.04: - -* Support for Emerge. Hitting "e" on a file that is Modified, Merged - or in Conflict will start Emerge, an interactive file merger written - in Emacs Lisp. This requires Emerge version 4. Emerge is not - included in this package. If you can't find it anywhere else, you - can get in from ftp.lysator.liu.se in pub/emacs. This package makes - it a lot easier to resolve conflicts. - -* Emacs will now automatically revert your buffers when the CVS - commands pcl-cvs issues causes the file to change. This automatic - revert never occurs if the buffer contents did not agree with the - file prior to the command. - -* If you are running Lucid GNU Emacs, you will get some fonts and - mouse support. This was contributed from people at Lucid. - -* The variable cvs-cvsroot can be used to select the location if the - repository. You no longer need to exit Emacs, setenv CVSROOT, and - start a new Emacs if you work with multiple repositories. - -* The "q" key can be used to hide the *cvs* buffer. - -* The name of the commands in the *cvs* have changed. If it was called - cvs-foo, it will now be called cvs-mode-foo. See the ChangeLog - entry from Tue Aug 4 03:02:25 1992 for a complete list of changes. - -* The variable cvs-cvs-diff-flags is no longer used. Instead, - cvs-diff-flags is always used. - -* Plus a lot of bug fixes. - - -User-visible changes in pcl-cvs from 1.02 to 1.03: - -* Output from CVS to stdout and stderr is separated and parsed - independently. In that way pcl-cvs should work regardless of - whether stdout is buffered or line-buffered. Pcl-cvs should now - work with CVS 1.3 without modifications on hosts such as - DECstations. - -* Pcl-cvs now fully supports RCS version 5.6 as well as 5.5. - -* New functions: - - + cvs-undo-local-changes ("U") - Undo all your modifications - to a file and get the newest - version from the repository. - + cvs-update-other-window - Similar to cvs-update. - + cvs-byte-compile-files - Byte compile the selected files. - -* cvs-update now displays the *cvs* buffer, which initially contains a - small message ("Running `cvs update' in /foo/bar/gazonk/...") until - the update is ready. The *cvs* buffer no longer pops up when the - update is ready. It often failed to pop up, due to race conditions - that are very hard to solve (and I doubt that they were at all - solvable). - -* cvs-unmark-all-files is moved from "U" to "ESC DEL" to be - "compatible" with dired. - -* cvs-diff ("d") and cvs-diff-backup ("b") can be configured to work - on only the file the cursor is positioned on, and ignore any marked - files. A prefix argument toggles this. - -* Only one `cvs update' can be run at a time. (It was previously - possible to start more than one simultaneously, but pcl-cvs could - not really handle more than one.) - -* Some rudimentary support for programs that CVS runs at update (due - to the -u switch in the modules file). - -* Pcl-cvs now automatically generates a bug report if it can't parse - the output from CVS. - -* The *cvs* buffer is read-only. - -* Pcl-cvs now creates temporary files in $TMPDIR if that environment - variable is set (otherwise it uses /tmp). - ----End of file NEWS--- diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/README b/gnu/usr.bin/cvs/contrib/pcl-cvs/README deleted file mode 100644 index a9b8106..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/README +++ /dev/null @@ -1,29 +0,0 @@ -@(#) Id: README,v 1.14 1993/05/31 22:43:36 ceder Exp - -This is the readme file for pcl-cvs, release 1.05. - -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.?. - -Pcl-cvs is a front-end to CVS version 1.3. It integrates the most -frequently used CVS commands into emacs. - -There is some configuration that needs to be done in pcl-cvs.el to get -it to work. See the instructions in file INSTALL. - -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). - -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. - -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) diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el deleted file mode 100644 index 6563277..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile-all.el +++ /dev/null @@ -1,52 +0,0 @@ -;;;; @(#) Id: compile-all.el,v 1.11 1993/05/31 18:40:25 ceder Exp -;;;; This file byte-compiles all .el files in pcl-cvs release 1.05. -;;;; -;;;; Copyright (C) 1991 Inge Wallin -;;;; -;;;; This file was once upon a time part of Elib, but have since been -;;;; modified by Per Cederqvist. -;;;; -;;;; GNU Elib 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. -;;;; -;;;; GNU Elib 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 GNU Emacs; see the file COPYING. If not, write to -;;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -;;;; - - -(setq files-to-compile '("pcl-cvs" "pcl-cvs-lucid")) - - -(defun compile-file-if-necessary (file) - "Compile FILE if necessary. - -This is done if FILE.el is newer than FILE.elc or if FILE.elc doesn't exist." - (let ((el-name (concat file ".el")) - (elc-name (concat file ".elc"))) - (if (or (not (file-exists-p elc-name)) - (file-newer-than-file-p el-name elc-name)) - (progn - (message (format "Byte-compiling %s..." el-name)) - (byte-compile-file el-name))))) - - -(defun compile-pcl-cvs () - "Byte-compile all uncompiled files of pcl-cvs." - - (interactive) - - ;; Be sure to have . in load-path since a number of files - ;; depend on other files and we always want the newer one even if - ;; a previous version of pcl-cvs exists. - (let ((load-path (append '(".") load-path))) - - (mapcar (function compile-file-if-necessary) - files-to-compile))) diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh b/gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh deleted file mode 100644 index b940370..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/compile.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -emacs -batch -l compile-all.el -f compile-pcl-cvs 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 deleted file mode 100644 index d1f69e3..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-lucid.el +++ /dev/null @@ -1,133 +0,0 @@ -;;; Mouse and font support for PCL-CVS 1.3 running in Lucid GNU Emacs -;; @(#) Id: pcl-cvs-lucid.el,v 1.2 1993/05/31 19:37:34 ceder Exp -;; Copyright (C) 1992-1993 Free Software Foundation, Inc. - -;; This file is part of GNU Emacs. - -;; GNU Emacs 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. - -;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - - -;; This simply adds a menu of the common CVS commands to the menubar and to -;; the right mouse button. Clicking right moves point, and then pops up a -;; menu from which commands can be executed. -;; -;; This could stand to be a lot more clever: for example, the "Commit Changes" -;; command should only be active on files for which there is something to -;; commit. Also, some indication of which files the command applies to -;; (especially in the presence of multiple marked files) would be nice. -;; -;; Middle-click runs find-file. - - -(require 'pcl-cvs) - -(defvar cvs-menu - '("CVS" - ["Find File" cvs-mode-find-file t] - ["Find File Other Window" cvs-mode-find-file-other-window t] - ["Interactively Merge (emerge)" cvs-mode-emerge t] - ["Diff against Repository" cvs-mode-diff-cvs t] - ["Diff against Backup Version" cvs-mode-diff-backup t] - "----" - ["Commit Changes to Repository" cvs-mode-commit t] - ["Revert File from Repository" cvs-mode-undo-local-changes t] - ["Add File to Repository" cvs-mode-add t] - ["Remove File from Repository" cvs-mode-remove-file t] - ["Ignore File" cvs-mode-ignore t] - ["Hide File" cvs-mode-acknowledge t] - ["Hide Handled Files" cvs-mode-remove-handled t] - "----" - ["Add ChangeLog Entry" cvs-mode-add-change-log-entry-other-window t] - ["Show CVS Log" cvs-mode-log t] - ["Show CVS Status" cvs-mode-status t] - "----" - ["Mark File" cvs-mode-mark t] - ["Unmark File" cvs-mode-unmark t] - ["Mark All Files" cvs-mode-mark-all-files t] - ["Unmark All Files" cvs-mode-unmark-all-files t] - "----" - ["Quit" bury-buffer t] - )) - -(defun cvs-menu (e) - (interactive "e") - (mouse-set-point e) - (beginning-of-line) - (or (looking-at "^[* ] ") (error "No CVS file line here")) - (popup-menu cvs-menu)) - -(defun cvs-mouse-find-file (e) - (interactive "e") - (mouse-set-point e) - (beginning-of-line) - (or (looking-at "^[* ] ") (error "No CVS file line here")) - (cvs-mode-find-file (point))) - -(define-key cvs-mode-map 'button3 'cvs-menu) -(define-key cvs-mode-map 'button2 'cvs-mouse-find-file) - -(make-face 'cvs-header-face) -(make-face 'cvs-filename-face) -(make-face 'cvs-status-face) - -(or (face-differs-from-default-p 'cvs-header-face) - (copy-face 'italic 'cvs-header-face)) - -(or (face-differs-from-default-p 'cvs-filename-face) - (copy-face 'bold 'cvs-filename-face)) - -(or (face-differs-from-default-p 'cvs-status-face) - (copy-face 'bold-italic 'cvs-status-face)) - - -(defun pcl-mode-motion-highlight-line (event) - (if (save-excursion - (let* ((window (event-window event)) - (buffer (and window (window-buffer window))) - (point (and buffer (event-point event)))) - (and point - (progn - (set-buffer buffer) - (goto-char point) - (beginning-of-line) - (looking-at "^[* ] "))))) - (mode-motion-highlight-line event))) - -(defconst pcl-cvs-font-lock-keywords - '(("^In directory \\(.+\\)$" 1 cvs-header-face) - ("^[* ] \\w+ +\\(ci\\)" 1 cvs-status-face) - ("^[* ] \\(Conflict\\|Merged\\)" 1 cvs-status-face) - ("^[* ] \\w+ +\\(ci +\\)?\\(.+\\)$" 2 cvs-filename-face) - ) - "Patterns to highlight in the *cvs* buffer.") - -(defun pcl-cvs-fontify () - ;; - ;; set up line highlighting - (require 'mode-motion) - (setq mode-motion-hook 'pcl-mode-motion-highlight-line) - ;; - ;; set up menubar - (if (and current-menubar (not (assoc "CVS" current-menubar))) - (progn - (set-buffer-menubar (copy-sequence current-menubar)) - (add-menu nil "CVS" (cdr cvs-menu)))) - ;; - ;; fontify mousable lines - (set (make-local-variable 'font-lock-keywords) pcl-cvs-font-lock-keywords) - (font-lock-mode 1) - ) - -(add-hook 'cvs-mode-hook 'pcl-cvs-fontify) 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 deleted file mode 100644 index f9b2de0..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs-startup.el +++ /dev/null @@ -1,14 +0,0 @@ -;;; @(#) Id: pcl-cvs-startup.el,v 1.4 1993/05/31 18:40:33 ceder 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. -If optional prefix argument LOCAL is non-nil, 'cvs update -l' is run." - t) - -(autoload 'cvs-update-other-window "pcl-cvs" - "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." - t) diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el deleted file mode 100644 index d9c15d5..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.el +++ /dev/null @@ -1,2493 +0,0 @@ -;;; @(#) 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 -;;; -;;; 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. - -;;;; 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. - -;;;; Send bug reports and improvements to ceder@lysator.liu.se or -;;;; ceder@signum.se. Talk some about Signum Support here. +++FIXME - -;;; 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. - -;;; Mail questions and bug reports to ceder@lysator.liu.se. - -(require 'cookie) -(provide 'pcl-cvs) - -;;; ------------------------------------------------------- -;;; START OF THINGS TO CHECK WHEN INSTALLING - -(defvar cvs-program "/usr/local/bin/cvs" - "*Full path to the cvs executable.") - -(defvar cvs-diff-program "/usr/local/bin/diff" - "*Full path to the diff program.") - -(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. - -(defvar cvs-shell "/bin/sh" - "*Full path to a shell that can do redirection on stdout.") - -;;; END OF THINGS TO CHECK WHEN INSTALLING -;;; -------------------------------------------------------- - -(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-cvsroot-required t - "*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 -do not set the `cvs-cvsroot' lisp variable, CVS will have no idea -where to find the repository, and refuse to run. CVS 1.4 and later -store the repository path with the working directories, so most -operations don't need to be told where the repository is. - -If you work with multiple repositories with CVS 1.4, it's probably -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-stdout-file nil - "Name of the file that holds the output that CVS sends to stdout. -This variable is buffer local.") - -(defvar cvs-lock-file nil - "Full path to a lock file that CVS is waiting for (or was waiting for).") - -(defvar cvs-bakprefix ".#" - "The prefix that CVS prepends to files when rcsmerge'ing.") - -(defvar cvs-erase-input-buffer nil - "*Non-nil if input buffers should be cleared before asking for new info.") - -(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.") - -(defvar cvs-sort-ignore-file t - "*Non-nil if cvs-mode-ignore should sort the .cvsignore automatically.") - -(defvar cvs-auto-revert-after-commit t - "*Non-nil if committed buffers should be automatically reverted.") - -(defconst cvs-cursor-column 14 - "Column to position cursor in in cvs-mode. -Column 0 is left-most column.") - -(defvar cvs-mode-map nil - "Keymap for the cvs mode.") - -(defvar cvs-edit-mode-map nil - "Keymap for the cvs edit mode (used when editing cvs log messages).") - -(defvar cvs-buffer-name "*cvs*" - "Name of the cvs buffer.") - -(defvar cvs-commit-prompt-buffer "*cvs-commit-message*" - "Name of buffer in which the user is prompted for a log message when -committing files.") - -(defvar cvs-commit-buffer-require-final-newline t - "*t says silently put a newline at the end of commit log messages. -Non-nil but not t says ask user whether to add a newline in each such case. -nil means don't add newlines.") - -(defvar cvs-temp-buffer-name "*cvs-tmp*" - "*Name of the cvs temporary buffer. -Output from cvs is placed here by synchronous commands.") - -(defvar cvs-diff-ignore-marks nil - "*Non-nil if cvs-diff and cvs-mode-diff-backup should ignore any marked files. -Normally they run diff on the files that are marked (with cvs-mode-mark), -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''.") - -(defvar cvs-log-flags nil - "*List of strings to pass to ``cvs log''.") - -(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.") - -(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. - -The default (a single $) fits programs without output.") - -;; 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.") - -(defvar cvs-cookie-handle nil - "Handle for the cookie structure that is displayed in the *cvs* buffer.") - -(defvar cvs-mode-commit nil - "Used internally by pcl-cvs.") - -;;; The cvs data structure: -;;; -;;; 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: - -(defun cvs-create-fileinfo (type - dir - file-name - full-log) - "Create a fileinfo from all parameters. -Arguments: TYPE DIR FILE-NAME FULL-LOG. -A fileinfo has the following fields: - - 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, 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. - 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." - (cons - 'CVS-FILEINFO - (vector nil nil type dir file-name nil nil nil full-log nil))) - - -;;; Selectors: - -(defun cvs-fileinfo->handled (cvs-fileinfo) - "Get the `handled' field from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 0)) - -(defun cvs-fileinfo->marked (cvs-fileinfo) - "Check if CVS-FILEINFO is marked." - (elt (cdr cvs-fileinfo) 1)) - -(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." - (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. " - (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->base-revision (cvs-fileinfo) - "Get the base revision from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 5)) - -(defun cvs-fileinfo->cvs-diff-buffer (cvs-fileinfo) - "Get cvs-diff-buffer from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 6)) - -(defun cvs-fileinfo->backup-diff-buffer (cvs-fileinfo) - "Get backup-diff-buffer from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 7)) - -(defun cvs-fileinfo->full-log (cvs-fileinfo) - "Get full-log from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 8)) - -(defun cvs-fileinfo->mod-time (cvs-fileinfo) - "Get mod-time from CVS-FILEINFO." - (elt (cdr cvs-fileinfo) 9)) - -;;; Modifiers: - -(defun cvs-set-fileinfo->handled (cvs-fileinfo newval) - "Set handled in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 0 newval)) - -(defun cvs-set-fileinfo->marked (cvs-fileinfo newval) - "Set marked in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 1 newval)) - -(defun cvs-set-fileinfo->type (cvs-fileinfo newval) - "Set type in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 2 newval)) - -(defun cvs-set-fileinfo->dir (cvs-fileinfo newval) - "Set dir in CVS-FILEINFO to NEWVAL. -The directory should now end with a slash." - (aset (cdr cvs-fileinfo) 3 newval)) - -(defun cvs-set-fileinfo->file-name (cvs-fileinfo newval) - "Set file-name in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 4 newval)) - -(defun cvs-set-fileinfo->base-revision (cvs-fileinfo newval) - "Set base-revision in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 5 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)) - -(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)) - -(defun cvs-set-fileinfo->full-log (cvs-fileinfo newval) - "Set full-log in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 8 newval)) - -(defun cvs-set-fileinfo->mod-time (cvs-fileinfo newval) - "Set full-log in CVS-FILEINFO to NEWVAL." - (aset (cdr cvs-fileinfo) 9 newval)) - - - -;;; Predicate: - -(defun cvs-fileinfo-p (object) - "Return t if OBJECT is a cvs-fileinfo." - (eq (car-safe object) 'CVS-FILEINFO)) - -;;;; 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 -be erased and writable." - - (let ((dir default-directory)) - (display-buffer (get-buffer-create cvs-temp-buffer-name)) - (set-buffer cvs-temp-buffer-name) - (setq buffer-read-only nil) - (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-update (directory &optional local) - "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 -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. -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)) - (while list - (if (apply predicate (car list) extra-args) - (setq tail (setcdr tail (list (car list))))) - (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. -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." - (save-some-buffers) - (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)) - "-update"))) - (temp-name (make-temp-name - (concat (file-name-as-directory - (or (getenv "TMPDIR") "/tmp")) - "pcl-cvs."))) - (args nil)) - - ;; Check that this-dir exists and is a directory that is under CVS contr. - - (if (not (file-directory-p this-dir)) - (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)) - - ;; Check that at most one `cvs update' is run at any time. - - (if (and cvs-update-running (process-status cvs-update-running) - (or (eq (process-status cvs-update-running) 'run) - (eq (process-status cvs-update-running) 'stop))) - (error "Can't run two `cvs update' simultaneously.")) - - ;; 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 "))) - - ;; Set up the buffer that receives the stderr output from "cvs update". - (set-buffer update-buffer) - (setq default-directory this-dir) - (make-local-variable 'cvs-stdout-file) - (setq cvs-stdout-file temp-name) - - (setq cvs-update-running - (let ((process-connection-type nil)) ; Use a pipe, not a pty. - (start-process "cvs" update-buffer cvs-shell "-c" - (concat cvs-program " " args " > " temp-name)))) - - (setq mode-line-process - (concat ": " - (symbol-name (process-status cvs-update-running)))) - (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line. - (set-process-sentinel cvs-update-running 'cvs-sentinel) - (set-process-filter cvs-update-running 'cvs-update-filter) - (set-marker (process-mark cvs-update-running) (point-min)) - - (save-excursion - (set-buffer (get-buffer-create cvs-buffer-name)) - (setq buffer-read-only nil) - (erase-buffer) - (cvs-mode)) - - (setq cvs-cookie-handle - (collection-create - cvs-buffer-name 'cvs-pp - cvs-startup-message ;Se comment above cvs-startup-message. - "---------- End -----")) - - (cookie-enter-first - cvs-cookie-handle - (cvs-create-fileinfo - 'MESSAGE nil nil (concat "\n Running `cvs " args "' in " this-dir - "...\n"))) - - (save-excursion - (set-buffer cvs-buffer-name) - (setq mode-line-process - (concat ": " - (symbol-name (process-status cvs-update-running)))) - (set-buffer-modified-p (buffer-modified-p)) ; Update the mode line. - (setq buffer-read-only t)) - - ;; Work around a bug in emacs 18.57 and earlier. - (setq cvs-buffers-to-delete - (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. - (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." - - (cond - ((null list) nil) - ((get-buffer-window (car list)) - (cons (car list) - (cvs-delete-unused-temporary-buffers (cdr list)))) - (t - (kill-buffer (car list)) - (cvs-delete-unused-temporary-buffers (cdr list))))) - - -(put 'cvs-mode 'mode-class 'special) - -(defun cvs-mode () - "\\<cvs-mode-map>Mode used for pcl-cvs, a frontend to CVS. - -To get the *cvs* buffer you should use ``\\[cvs-update]''. - -Full documentation is in the Texinfo file. These 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-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-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-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. - -Entry to this mode runs cvs-mode-hook. -This description is updated for release 1.05 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)) - (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 - (set-process-buffer proc nil)) - ((memq (process-status proc) '(signal exit)) - (let* ((obuf (current-buffer)) - (omax (point-max)) - (opoint (point))) - ;; save-excursion isn't the right thing if - ;; process-buffer is current-buffer - (unwind-protect - (progn - (set-buffer (process-buffer proc)) - (setq mode-line-process - (concat ": " - (symbol-name (process-status proc)))) - (let* ((out-file cvs-stdout-file) - (stdout-buffer (find-file-noselect out-file))) - (cvs-parse-update stdout-buffer (process-buffer proc)) - (setq cvs-buffers-to-delete - (cons (process-buffer proc) - (cons stdout-buffer - cvs-buffers-to-delete))) - (delete-file out-file))) - (set-buffer-modified-p (buffer-modified-p)) - (setq cvs-update-running nil)) - (if (equal obuf (process-buffer proc)) - nil - (set-buffer (process-buffer proc)) - (if (< opoint omax) - (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 -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." - (let ((old-buffer (current-buffer)) - (data (match-data))) - (unwind-protect - (progn - (set-buffer (process-buffer proc)) - (save-excursion - ;; Insert the text, moving the process-marker. - (goto-char (process-mark proc)) - (insert string) - (set-marker (process-mark proc) (point)) - ;; Delete any old lock message - (if (tin-nth cvs-cookie-handle 1) - (tin-delete cvs-cookie-handle - (tin-nth cvs-cookie-handle 1))) - ;; Check if CVS is waiting for a lock. - (beginning-of-line 0) ;Move to beginning of last - ;complete line. - (cond - ((looking-at - "^cvs update: \\[..:..:..\\] waiting \ -for \\(.*\\)lock in \\(.*\\)$") - (setq cvs-lock-file (buffer-substring (match-beginning 2) - (match-end 2))) - (cookie-enter-last - cvs-cookie-handle - (cvs-create-fileinfo - 'MESSAGE nil nil - (concat "\tWaiting for " - (buffer-substring (match-beginning 1) - (match-end 1)) - "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 - (concat (file-name-as-directory cvs-lock-file) "#cvs.lock")) - (cvs-filter (function cvs-lock-file-p) - (directory-files cvs-lock-file)))) - (error "No lock files found.")) - ((yes-or-no-p (concat "Really delete locks in " cvs-lock-file "? ")) - ;; Re-read the directory -- the locks might have disappeared. - (let ((locks (cvs-filter (function cvs-lock-file-p) - (directory-files cvs-lock-file)))) - (while locks - (delete-file (concat (file-name-as-directory cvs-lock-file) - (car locks))) - (setq locks (cdr locks))) - (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-skip-line (stdout stderr regexp &optional arg) - "Like forward-line, but check that the skipped line matches REGEXP. -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. - -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) - (if arg - (buffer-substring (match-beginning arg) - (match-end arg)))) - (t - (cvs-parse-error stdout stderr - (if (eq (current-buffer) stdout) 'STDOUT 'STDERR) - (point))))) - -(defun cvs-get-current-dir (root-dir dirname) - "Return current working directory, suitable for cvs-parse-update. -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) - ((and (eq (cvs-fileinfo->type b) 'DIRCHANGE) - (not (eq (cvs-fileinfo->type a) 'DIRCHANGE))) nil) - ;; 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) - "Handle a parse error when parsing the output from cvs. -Args: STDOUT-BUFFER STDERR-BUFFER ERR-BUF POS. -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 "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") - (insert "this, together with any information you think might be\n") - (insert "useful for me to fix the bug, to the address above. But\n") - (insert "please check the \"known problems\" section of the\n") - (insert "documentation first. Note that this buffer contains\n") - (insert "information that you might consider confidential. You\n") - (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 "RCS: \ndiff: \n\n") - - (let* ((stdout (save-excursion (set-buffer stdout-buffer) (buffer-string))) - (stderr (save-excursion (set-buffer stderr-buffer) (buffer-string))) - (errstr (if (eq err-buf 'STDOUT) stdout stderr)) - (errline-end (string-match "\n" errstr pos)) - (errline (substring errstr pos errline-end))) - (insert (format "Offending line (%d chars): >" (- errline-end pos))) - (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") - (insert (format "--- Contents of stdout buffer (%d chars) ---\n" - (length stdout))) - (insert stdout) - (insert "--- End of stdout buffer ---\n") - (insert (format "--- Contents of stderr buffer (%d chars) ---\n" - (length stderr))) - (insert stderr) - (insert "--- End of stderr buffer ---\n") - (insert "End 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. - -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) - (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 -be sure that the stderr entry is always first)." - (collection-filter-tins cvs-cookie-handle - (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. -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)) - (or - (and (eq (cvs-fileinfo->type prev) 'CONFLICT) - (eq (cvs-fileinfo->type curr) 'CONFLICT)) - (and (eq (cvs-fileinfo->type prev) 'MERGED) - (eq (cvs-fileinfo->type curr) 'MODIFIED)) - (and (eq (cvs-fileinfo->type prev) 'REM-EXIST) - (eq (cvs-fileinfo->type curr) 'REMOVED)))))) - - -(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 -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. -DIR is the directory the `cvs update' was run in. - -This function returns the last cons-cell in the list that is built." - - (save-window-excursion - (set-buffer stderr-buffer) - (goto-char (point-min)) - (let ((current-dir dir) - (root-dir dir)) - - (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 \\(.*\\)$") - (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))))) - (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") - (looking-at - "cvs update: \\(.*\\) is no longer in the repository")) - - (setcdr head (list (cvs-create-fileinfo - 'CVS-REMOVED current-dir - (file-name-nondirectory - (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 by you, but recreated by cvs. Ignored. - - ((looking-at "cvs update: warning: .* was lost$") - (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$") - (setcdr head (list (cvs-create-fileinfo - 'MOVE-AWAY current-dir - (file-name-nondirectory - (buffer-substring (match-beginning 1) - (match-end 1))) - (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. - - ((looking-at - "^cvs update: \\[..:..:..\\] 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$") - (setcdr head (list - (cvs-create-fileinfo - 'REM-CONFLICT current-dir - (file-name-nondirectory - (buffer-substring (match-beginning 1) (match-end 1))) - (buffer-substring (match-beginning 0) - (match-end 0))))) - (setq head (cdr head)) - (forward-line 1)) - - ((looking-at - "cvs update: 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))))) - (setq head (cdr head)) - (forward-line 1)) - - ((looking-at - "cvs update: \\(.*\\) 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))))) - (setq head (cdr head)) - (forward-line 1)) - - ((looking-at "cvs update: 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))))) - (setq head (cdr head)))) - - ;; Ignore other messages from Cyclic CVS. - ((looking-at "cvs server:") - (forward-line 1)) - - (t - - ;; 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). - - (let ((complex-start (point)) - initial-revision filename) - - (cvs-skip-line stdout-buffer stderr-buffer "^RCS file: .*$") - (setq initial-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. - - (setq - filename - (cvs-skip-line - stdout-buffer stderr-buffer - "^Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$" - 1)) - - (cond - ;; Was it a conflict? - ((looking-at - ;; 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 - "^cvs \\(update\\|server\\): conflicts found in ") - - (let ((fileinfo - (cvs-create-fileinfo - 'CONFLICT current-dir - filename - (buffer-substring complex-start (point))))) - - (cvs-set-fileinfo->base-revision fileinfo initial-revision) - - (setcdr head (list fileinfo)) - (setq head (cdr head)))) - - ;; Was it a conflict, and was RCS compiled without DIFF3_BIN? - - ((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$") - - (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)))) - - (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) - (setcdr head (list fileinfo)) - (setq head (cdr head))))))))))) - 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 -STDOUT-BUFFER is the buffer that holds the output to parse. -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. - - - ((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)))) - (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)) - (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. - (if (memq c '(?U ?P)) - (cvs-set-fileinfo->handled fileinfo t)) - - ;; Link this last on the list. - (setcdr head (list fileinfo)) - (setq head (cdr head)) - (forward-line 1))) - - ;; Executing a program because of the -u option in modules. - ((looking-at "cvs update: 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))))))) - -(defun cvs-pp (fileinfo) - "Pretty print FILEINFO. Insert a printed representation in current buffer. -For use by the cookie package." - - (let ((a (cvs-fileinfo->type fileinfo)) - (s (if (cvs-fileinfo->marked fileinfo) - "*" " ")) - (f (cvs-fileinfo->file-name fileinfo)) - (ci (if (cvs-fileinfo->handled fileinfo) - " " "ci"))) - (insert - (cond - ((eq a 'UPDATED) - (format "%s Updated %s" s f)) - ((eq a 'MODIFIED) - (format "%s Modified %s %s" s ci f)) - ((eq a 'MERGED) - (format "%s Merged %s %s" s ci f)) - ((eq a 'CONFLICT) - (format "%s Conflict %s" s f)) - ((eq a 'ADDED) - (format "%s Added %s %s" s ci f)) - ((eq a 'REMOVED) - (format "%s Removed %s %s" s ci f)) - ((eq a 'UNKNOWN) - (format "%s Unknown %s" s f)) - ((eq a 'CVS-REMOVED) - (format "%s Removed from repository: %s" s f)) - ((eq a 'REM-CONFLICT) - (format "%s Conflict: Removed from repository, changed by you: %s" s f)) - ((eq a 'MOD-CONFLICT) - (format "%s Conflict: Removed by you, changed in repository: %s" s f)) - ((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))) - ((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.")) - ((eq a 'MESSAGE) - (cvs-fileinfo->full-log fileinfo)) - (t - (format "%s Internal error! %s" s f)))))) - - -;;; 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-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 "M" 'cvs-mode-mark-all-files) - (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 "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) - (define-key cvs-mode-map "l" 'cvs-mode-log) - (define-key cvs-mode-map "m" 'cvs-mode-mark) - (define-key cvs-mode-map "n" 'cvs-mode-next-line) - (define-key cvs-mode-map "o" 'cvs-mode-find-file-other-window) - (define-key cvs-mode-map "p" 'cvs-mode-previous-line) - (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)) - - -(defun cvs-get-marked (&optional ignore-marks) - "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." - - (cond - ;; Any marked cookies? - ((and (not ignore-marks) - (collection-collect-tin cvs-cookie-handle 'cvs-fileinfo->marked))) - ;; Nope. - (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))))))) - - -(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." - (and (eq (cvs-fileinfo->type (tin-cookie cvs-cookie-handle tin)) 'DIRCHANGE) - (or (not (tin-next cvs-cookie-handle tin)) - (eq (cvs-fileinfo->type - (tin-cookie cvs-cookie-handle - (tin-next cvs-cookie-handle tin))) - 'DIRCHANGE)))) - -(defun cvs-mode-revert-updated-buffers () - "Revert any buffers that are UPDATED, 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." - (let* ((type (cvs-fileinfo->type fileinfo)) - (file (cvs-fileinfo->full-path fileinfo)) - (buffer (get-file-buffer file))) - ;; For a revert to happen... - (cond - ((and - ;; ...the type must be one that justifies a revert... - (or (eq type 'UPDATED) - (eq type 'MERGED) - (eq type 'CONFLICT)) - ;; ...and the user must be editing the file... - buffer) - (save-excursion - (set-buffer buffer) - (cond - ((buffer-modified-p) - (error "%s: edited since last cvs-update." - (buffer-file-name))) - ;; 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. - (collection-filter-cookies cvs-cookie-handle - (function - (lambda (fileinfo) (not (cvs-fileinfo->handled fileinfo))))) - ;; Pass two: remove empty 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)))))) - -(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." - - (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. - ((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. - cvs-cookie-handle - (cvs-fileinfo->dir sel))) - (t - (cvs-set-fileinfo->marked sel t) - (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)) - (or (eq type 'MODIFIED) - (eq type 'ADDED) - (eq type 'REMOVED) - (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. -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)))) - (if (null marked) - (error "Nothing to commit!") - (pop-to-buffer (get-buffer-create cvs-commit-prompt-buffer)) - (goto-char (point-min)) - - (if cvs-erase-input-buffer - (erase-buffer) - (push-mark (point-max))) - (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.")))) - - -(defun cvs-edit-done () - "Commit the files to the repository." - (interactive) - (if (null cvs-commit-list) - (error "You have already commited the files")) - (if (and (> (point-max) 1) - (/= (char-after (1- (point-max))) ?\n) - (or (eq cvs-commit-buffer-require-final-newline t) - (and cvs-commit-buffer-require-final-newline - (yes-or-no-p - (format "Buffer %s does not end in newline. Add one? " - (buffer-name)))))) - (save-excursion - (goto-char (point-max)) - (insert ?\n))) - (save-some-buffers) - (let ((cc-list cvs-commit-list) - (cc-buffer (get-buffer cvs-buffer-name)) - (msg-buffer (current-buffer)) - (msg (buffer-substring (point-min) (point-max)))) - (pop-to-buffer cc-buffer) - (bury-buffer msg-buffer) - (cvs-use-temp-buffer) - (message "Committing...") - (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." - cvs-temp-buffer-name)) - (let ((ccl cc-list)) - (while ccl - (cvs-after-commit-function (tin-cookie cvs-cookie-handle (car ccl))) - (setq ccl (cdr ccl)))) - (apply 'tin-invalidate cvs-cookie-handle cc-list) - (set-buffer msg-buffer) - (setq cvs-commit-list nil) - (set-buffer cc-buffer) - (if cvs-auto-remove-handled - (cvs-mode-remove-handled))) - - (message "Committing... Done.")) - -(defun cvs-after-commit-function (fileinfo) - "Do everything that needs to be done when FILEINFO has been commited. -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)) - (buffer (get-file-buffer file))) - ;; For a revert to happen... - (if buffer - ;; ...the user must be editing the file... - (save-excursion - (set-buffer buffer) - (if (not (buffer-modified-p)) - ;; ...but it must be unmodified. - (revert-buffer 'dont-use-auto-save-file 'dont-ask))))))) - - -(defun cvs-execute-list (tin-list program constant-args) - "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). - -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." - - (let ((exitstatus nil)) - (while tin-list - (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))))) - (setq arg-list - (cons (cvs-fileinfo->file-name - (tin-cookie cvs-cookie-handle (car tin-list))) - arg-list)) - (setq tin-list (cdr tin-list))) - - (setq arg-list (nreverse arg-list)) - - ;; Execute the command on all the files that were collected. - - (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) - (nconc (copy-sequence constant-args) - arg-list) - " "))) - (let ((res (apply 'call-process program nil t t - (nconc (copy-sequence constant-args) arg-list)))) - ;; Remember the first, or highest, exitstatus. - (if (and (not (and (integerp res) (zerop res))) - (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) - "Run PROGRAM on all elements on TIN-LIST. - -Args: TIN-LIST EXTRACTOR PROGRAM CONSTANT-ARGS - -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 -PROGRAM. The arguments given to the program will be CONSTANT-ARGS -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." - - (while tin-list - (let ((default-directory (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))))) - - ;; Execute the command unless extractor returned t. - - (if (eq arg-list t) - nil - (insert (format "=== cd %s\n" default-directory)) - (insert (format "=== %s %s\n\n" - program - (mapconcat '(lambda (foo) foo) - (nconc (copy-sequence constant-args) - arg-list) - " "))) - (apply 'call-process program nil t t - (nconc (copy-sequence constant-args) arg-list)) - (goto-char (point-max)))) - (setq tin-list (cdr tin-list)))) - - -(defun cvs-edit-mode () - "\\<cvs-edit-mode-map>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-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 - ;; other way around instead! - (let ((result nil)) - (while tins - (let ((type (cvs-fileinfo->type - (tin-cookie cvs-cookie-handle (car tins))))) - (if (or (eq type 'MODIFIED) - (eq type 'UPDATED) - (eq type 'MERGED) - (eq type 'CONFLICT) - (eq type 'REMOVED) ;+++Does this line make sense? - (eq type 'ADDED)) ;+++Does this line make sense? - (setq result (cons (car tins) result))) - (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." - - (interactive "P") - - (if (not (listp cvs-diff-flags)) - (error "cvs-diff-flags should be a list of strings")) - - (save-some-buffers) - (let ((marked (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)))) - -(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\" -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''." - - (interactive "P") - - (if (not (listp cvs-diff-flags)) - (error "cvs-diff-flags should be a list of strings.")) - - (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) - (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.")) - - -(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 - (file-name-as-directory (cvs-fileinfo->dir fileinfo)) - (cvs-fileinfo->file-name fileinfo)))) - (list (cvs-fileinfo->backup-file fileinfo) - (cvs-fileinfo->file-name fileinfo))) - -(defun cvs-mode-find-file-other-window (pos) - "Select a buffer containing the file in another window. -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)))) - (cond - ((or (eq type 'REMOVED) - (eq type 'CVS-REMOVED)) - (error "Can't visit a removed file.")) - ((eq type 'DIRCHANGE) - (let ((obuf (current-buffer)) - (odir default-directory)) - (setq default-directory - (file-name-as-directory - (cvs-fileinfo->dir - (tin-cookie cvs-cookie-handle tin)))) - (dired-other-window default-directory) - (set-buffer obuf) - (setq default-directory odir))) - (t - (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" - (interactive "d") - (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 - ((or (eq type 'REMOVED) - (eq type 'CVS-REMOVED)) - (error "Can't visit a removed file.")) - ((eq type 'DIRCHANGE) - (let ((odir default-directory)) - (setq default-directory - (file-name-as-directory (cvs-fileinfo->dir fileinfo))) - (dired default-directory) - (set-buffer cvs-buf) - (setq default-directory odir))) - (t - (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 - ((not (eq (cvs-fileinfo->type cookie) 'DIRCHANGE)) - (cvs-set-fileinfo->marked cookie t) - t)))) - cvs-cookie-handle)) - - -(defun cvs-mode-unmark (pos) - "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 - (function (lambda (f dir) - (cond - ((cvs-dir-member-p f dir) - (cvs-set-fileinfo->marked f nil) - t)))) - cvs-cookie-handle - (cvs-fileinfo->dir sel))) - (t - (cvs-set-fileinfo->marked sel nil) - (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. - -Returns a list of tins files that should be `cvs remove'd." - (cvs-use-temp-buffer) - (mapcar 'cvs-insert-full-path tins) - (cond - ((and tins (yes-or-no-p (format "Delete %d files? " (length tins)))) - (let (files-to-remove) - (while tins - (let* ((tin (car tins)) - (fileinfo (tin-cookie cvs-cookie-handle 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)))))) - (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) - nil - (cvs-use-temp-buffer) - (message "removing from repository...") - (if (cvs-execute-list files-to-remove cvs-program - (if cvs-cvsroot - (list "-d" cvs-cvsroot "remove") - '("remove"))) - (error "CVS exited with non-zero exit status.") - (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) - (mapcar 'cvs-insert-full-path tins-to-undo) - (cond - ((and tins-to-undo (yes-or-no-p (format "Undo changes to %d files? " - (length tins-to-undo)))) - (let (files-to-update) - (while tins-to-undo - (let* ((tin (car tins-to-undo)) - (fileinfo (tin-cookie cvs-cookie-handle tin)) - (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 'REMOVED)) - (if (not (eq type 'REMOVED)) - (delete-file (cvs-full-path tin))) - (setq files-to-update (cons tin files-to-update)) - (cvs-set-fileinfo->type fileinfo 'UPDATED) - (cvs-set-fileinfo->handled fileinfo t) - (tin-invalidate cvs-cookie-handle tin)) - - ((eq type 'MOD-CONFLICT) - (error "Use cvs-mode-add instead on %s." - (cvs-fileinfo->file-name fileinfo))) - - ((eq type 'REM-CONFLICT) - (error "Can't deal with a file you have removed and recreated.")) - - ((eq type 'DIRCHANGE) - (error "Undo on directories not supported (yet).")) - - ((eq type 'ADDED) - (error "There is no old revision to get for %s" - (cvs-fileinfo->file-name fileinfo))) - (t (error "cvs-mode-undo-local-changes: can't handle an %s" - type))) - - (setq tins-to-undo (cdr tins-to-undo)))) - (cvs-use-temp-buffer) - (message "Regetting files from repository...") - (if (cvs-execute-list files-to-update cvs-program - (if cvs-cvsroot - (list "-d" cvs-cvsroot "update") - '("update"))) - (error "CVS exited with non-zero exit status.") - (message "Regetting files from repository... done."))))))) - -(defun cvs-mode-acknowledge () - "Remove all marked files from the buffer." - (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 - (tin - (cvs-set-fileinfo->marked (tin-cookie cvs-cookie-handle tin) - 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." - (let ((fileinfo (tin-cookie cvs-cookie-handle tin))) - (cond - ((eq (cvs-fileinfo->type fileinfo) 'UNKNOWN) - (cvs-set-fileinfo->type fileinfo 'ADDED) - (tin-invalidate cvs-cookie-handle tin) - 'ADD) - ((eq (cvs-fileinfo->type fileinfo) 'REMOVED) - (cvs-set-fileinfo->type fileinfo 'UPDATED) - (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. -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) - (while candidates - (let ((type (cvs-add-file-update-buffer (car candidates)))) - (cond ((eq type 'ADD) - (setq add (cons (car candidates) add))) - ((eq type 'RESURRECT) - (setq resurrect (cons (car candidates) resurrect))))) - (setq candidates (cdr candidates))) - (cons add resurrect))) - -(defun cvs-mode-add () - "Add marked files to the cvs repository." - (interactive) - - (let* ((buf (current-buffer)) - (result (cvs-add-sub buf (cvs-get-marked))) - (added (car result)) - (resurrect (cdr result)) - (msg (if added (read-from-minibuffer "Enter description: ")))) - - (if (or resurrect added) - (cvs-use-temp-buffer)) - - (cond (resurrect - (message "Resurrecting files from repository...") - (if (cvs-execute-list resurrect cvs-program - (if cvs-cvsroot - (list "-d" cvs-cvsroot "add") - '("add"))) - (error "CVS exited with non-zero exit status.") - (message "Done.")))) - - (cond (added - (message "Adding new files to repository...") - (if (cvs-execute-list added cvs-program - (if cvs-cvsroot - (list "-d" cvs-cvsroot "add" "-m" msg) - (list "add" "-m" msg))) - (error "CVS exited with non-zero exit status.") - (message "Done.")))))) - -(defun cvs-mode-ignore () - "Arrange so that CVS ignores the selected files. -This command ignores files that are not 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))))) - (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)) - ".cvsignore"))) - (goto-char (point-max)) - (if (not (zerop (current-column))) - (insert "\n")) - (insert (cvs-fileinfo->file-name fileinfo) "\n") - (if cvs-sort-ignore-file - (sort-lines nil (point-min) (point-max))) - (save-buffer))) - -(defun cvs-mode-status () - "Show cvs status for all marked files." - (interactive) - - (save-some-buffers) - (let ((marked (cvs-get-marked))) - (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))) - (error "CVS exited with non-zero exit status.") - (message "Running cvs status ... Done.")))) - -(defun cvs-mode-log () - "Display the cvs log of all selected files." - (interactive) - - (let ((marked (cvs-get-marked))) - (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))) - (error "CVS exited with non-zero exit status.") - (message "Running cvs log ... Done.")))) - -(defun cvs-byte-compile-files () - "Run byte-compile-file on all selected files that end in '.el'." - (interactive) - (let ((marked (cvs-get-marked))) - (while marked - (let ((filename (cvs-full-path (car marked)))) - (if (string-match "\\.el$" filename) - (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)))) - - -(defun cvs-mode-add-change-log-entry-other-window (pos) - "Add a ChangeLog entry in the ChangeLog of the current directory. -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)) - (add-change-log-entry-other-window) - (set-buffer cvs-buf) - (setq default-directory odir))) - - -(defun print-cvs-tin (foo) - "Debug utility." - (let ((cookie (tin-cookie cvs-cookie-handle foo)) - (stream (get-buffer-create "debug"))) - (princ "==============\n" stream) - (princ (cvs-fileinfo->file-name cookie) stream) - (princ "\n" stream) - (princ (cvs-fileinfo->dir cookie) stream) - (princ "\n" stream) - (princ (cvs-fileinfo->full-log cookie) stream) - (princ "\n" stream) - (princ (cvs-fileinfo->marked cookie) stream) - (princ "\n" stream))) - -(defun cvs-mode-emerge (pos) - "Emerge appropriate revisions of the selected file. -Args: POS" - (interactive "d") - (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) - (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)))) - - ((or (eq type 'MERGED) - (eq type 'CONFLICT)) - (require 'emerge) - (let ((tmp-file - (cvs-retrieve-revision-to-tmpfile - fileinfo)) - (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 - (error "Can only emerge \"Modified\", \"Merged\" or \"Conflict\"%s" - " files")))) - (error "There is no file to emerge.")))) - -(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 - (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 - (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)) - - (if revision - (message "Retrieving revision %s... Done." revision) - (message "Retrieving latest revision... Done.")) - (find-file-noselect temp-name) - 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) - "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." - " 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))) - - -(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. - -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 behavior 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 behavior you get -when this variable is set to nil.") - -(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) - (while (and 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)))) - (or dir - (error "Can't find ChangeLog for %s" directory)) - file)) - -(defun cvs-narrow-changelog () - "Narrow to the top page of the current buffer, a ChangeLog file. -Actually, the narrowed region doesn't include the date line. -A \"page\" in a ChangeLog file is the area between two dates." - (or (eq major-mode 'change-log-mode) - (error "cvs-narrow-changelog: current buffer isn't a ChangeLog")) - - (goto-char (point-min)) - - ;; Skip date line and subsequent blank lines. - (forward-line 1) - (if (looking-at "[ \t\n]*\n") - (goto-char (match-end 0))) - - (let ((start (point))) - (forward-page 1) - (narrow-to-region start (point)) - (goto-char (point-min)))) - -(defun cvs-changelog-paragraph () - "Return the bounds of the ChangeLog paragraph containing point. -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))) - (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))))) - -(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." - (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 (point) (point))))) - -(defun cvs-changelog-entry () - "Return the bounds of the ChangeLog entry containing point. -The variable `cvs-changelog-full-paragraphs' decides whether an -\"entry\" is a paragraph or a subparagraph; see its documentation string -for more details." - (if cvs-changelog-full-paragraphs - (cvs-changelog-paragraph) - (cvs-changelog-subparagraph))) - -(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 (if (boundp 'add-log-full-name) - add-log-full-name - user-full-name)) - " <" - (regexp-quote - (if (boundp '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))) - (or (string= base (substring child 0 (length base))) - (error "cvs-relative-path: %s isn't in %s" child base)) - (substring child (length base)))) - -(defun cvs-changelog-entries (file) - "Return the ChangeLog entries for FILE, and the ChangeLog they came from. -The return value looks like this: - (LOGBUFFER (ENTRYSTART . ENTRYEND) ...) -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))))) - (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))) - (if (not (cvs-changelog-ours-p)) - (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))))))) - -(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)) - (while regions - (if (and last (< last (car (car regions)))) - (newline)) - (setq last (elt (car regions) 1)) - (apply 'insert-buffer-substring buffer (car regions)) - (setq regions (cdr regions))))) - -(defun cvs-union (set1 set2) - "Return the union of SET1 and SET2, according to `equal'." - (while set2 - (or (member (car set2) set1) - (setq set1 (cons (car set2) set1))) - (setq set2 (cdr set2))) - set1) - -(defun cvs-insert-changelog-entries (files) - "Given a list of files FILES, insert the ChangeLog entries for them." - (let ((buffer-entries nil)) - - ;; Add each buffer to buffer-entries, and associate it with the list - ;; 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)))) - (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))) - (if (and (cdr buffer-entries) (cdr (car buffer-entries))) - (newline)) - (setq buffer-entries (cdr buffer-entries))))) - -(defun cvs-edit-delete-common-indentation () - "Unindent the current buffer rigidly until at least one line is flush left." - (save-excursion - (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)) - (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 -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, -- 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 - the files we're checking in, and finally -- use those paragraphs as the log text." - - (interactive) - - (let* ((cvs-buf (current-buffer)) - (marked (cvs-filter (function cvs-committable) - (cvs-get-marked)))) - (if (null marked) - (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)) - (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.")))) diff --git a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo b/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo deleted file mode 100644 index bb0a4fe..0000000 --- a/gnu/usr.bin/cvs/contrib/pcl-cvs/pcl-cvs.texinfo +++ /dev/null @@ -1,1744 +0,0 @@ -\input texinfo @c -*-texinfo-*- - -@comment Id: pcl-cvs.texinfo,v 1.45 1993/05/31 22:38:15 ceder Exp -@comment Documentation for the GNU Emacs CVS mode. -@comment Copyright (C) 1992 Per Cederqvist - -@comment This file is part of the pcl-cvs distribution. - -@comment Pcl-cvs is free software; you can redistribute it and/or modify -@comment it under the terms of the GNU General Public License as published by -@comment the Free Software Foundation; either version 1, or (at your option) -@comment any later version. - -@comment Pcl-cvs is distributed in the hope that it will be useful, -@comment but WITHOUT ANY WARRANTY; without even the implied warranty of -@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -@comment GNU General Public License for more details. - -@comment You should have received a copy of the GNU General Public License -@comment along with pcl-cvs; see the file COPYING. If not, write to -@comment the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -@setfilename pcl-cvs.info -@settitle Pcl-cvs - The Emacs Front-End to CVS -@setchapternewpage on - -@ifinfo -Copyright @copyright{} 1992 Per Cederqvist - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -@ignore -Permission is granted to process this file through Tex and print the -results, provided the printed document carries copying permission -notice identical to this one except for the removal of this paragraph -(this paragraph not being relevant to the printed manual). - -@end ignore -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -section entitled ``GNU General Public License'' is included exactly as -in the original, and provided that the entire resulting derived work is -distributed under the terms of a permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions, -except that the section entitled ``GNU General Public License'' and -this permission notice may be included in translations approved by the -Free Software Foundation instead of in the original English. -@end ifinfo - -@synindex vr fn -@comment The titlepage section does not appear in the Info file. -@titlepage -@sp 4 -@comment The title is printed in a large font. -@center @titlefont{User's Guide} -@sp -@center @titlefont{to} -@sp -@center @titlefont{pcl-cvs - the Emacs Front-End to CVS} -@sp 2 -@center release 1.05 -@comment -release- -@sp 3 -@center Per Cederqvist -@sp 3 -@center last updated 31 May 1993 -@comment -date- - -@comment The following two commands start the copyright page -@comment for the printed manual. This will not appear in the Info file. -@page -@vskip 0pt plus 1filll -Copyright @copyright{} 1992 Per Cederqvist - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -section entitled ``GNU General Public License'' is included exactly as -in the original, and provided that the entire resulting derived work is -distributed under the terms of a permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions, -except that the section entitled ``GNU General Public License'' and -this permission notice may be included in translations approved by the -Free Software Foundation instead of in the original English. -@end titlepage - -@comment ================================================================ -@comment The real text starts here -@comment ================================================================ - -@node Top, Copying, (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. -@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. - -* Getting started:: An introduction with a walk-through example. -* Buffer contents:: An explanation of the buffer contents. -* Commands:: All commands, grouped by type. - -* Customization:: How you can tailor pcl-cvs to suit your needs. -* Future enhancements:: Future enhancements of pcl-cvs. -* Bugs:: Bugs (known and unknown). -* Function and Variable Index:: List of functions and variables. -* Concept Index:: List of concepts. -* Key Index:: List of keystrokes. - - --- The Detailed Node Listing --- - -Installation - -* Pcl-cvs installation:: How to install pcl-cvs on your system. -* On-line manual installation:: How to install the on-line manual. -* Typeset manual installation:: How to create typeset documentation - about pcl-cvs. - -About pcl-cvs - -* Contributors:: Contributors to pcl-cvs. -* Archives:: Where can I get a copy of Pcl-Cvs? - -Buffer contents - -* File status:: The meaning of the second field. -* Selected files:: How selection works. - -Commands - -* Updating the directory:: Commands to update the local directory -* Movement commands:: How to move up and down in the buffer -* Marking files:: How to mark files that other commands - will later operate on. -* Committing changes:: Checking in your modifications to the - 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 -* Undoing changes:: Undoing changes -* 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:: -* 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 - -@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 - -This section describes the installation of pcl-cvs, the GNU Emacs CVS -front-end. You should install not only the elisp files themselves, but -also the on-line documentation so that your users will know how to use -it. You can create typeset documentation from the file -@file{pcl-cvs.texinfo} as well as an on-line info file. The following -steps are also described in the file @file{INSTALL} in the source -directory. - -@menu -* Pcl-cvs installation:: How to install pcl-cvs on your system. -* On-line manual installation:: How to install the on-line manual. -* Typeset manual installation:: How to create typeset documentation - 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 -@cindex Installation of elisp files - -@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}. - -@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. - -@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 - -Setting @code{delete-exited-processes} to @code{nil} works around a bug -in emacs that causes it to dump core. The bug was fixed in emacs -18.58.@refill - -@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 -proceeding. - -@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. - -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 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. - -@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. - -@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 -@cindex Generating the on-line manual -@cindex On-line manual (how to generate) -@cindex Info-file (how to generate) - -@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 - -@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 - -@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 - -@example -* 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 -@cindex Printing a manual -@cindex TeX - generating a typeset manual -@cindex Generating a typeset manual - -If you have @TeX{} installed at your site, you can make a typeset manual -from @file{pcl-cvs.texinfo}. - -@enumerate -@item -Run @TeX{} by typing `@samp{make pcl-cvs.dvi}'. You will not get the -indices unless you have the @code{texindex} program. - -@item -Convert the resulting device independent file @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, @code{dvi2ps}, which does. There -is also a program which comes together with @TeX{}, @code{dvips}, which -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. - -@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 - -Contributions to the package are welcome. I have limited time to work -on this project, but I will gladly add any code that you contribute to -me to this package (@pxref{Bugs}). - -The following persons have made contributions to pcl-cvs. - -@itemize @bullet -@item -Brian Berliner wrote CVS, together with some other contributors. -Without his work on CVS this package would be useless@dots{} - -@item -Per Cederqvist wrote most of the otherwise unattributed functions in -pcl-cvs as well as all documentation. - -@item -Inge Wallin (@samp{inge@@lysator.liu.se}) wrote the skeleton to -@file{pcl-cvs.texinfo}, and gave useful comments on it. He also wrote -the files @file{elib-node.el} and @file{compile-all.el}. The file -@file{cookie.el} was inspired by Inge.@refill - -@item -Linus Tolke (@samp{linus@@lysator.liu.se}) contributed useful comments -on both the functionality and the documentation.@refill - -@item -Jamie Zawinski (@samp{jwz@@lucid.com}) contributed -@file{pcl-cvs-lucid.el}. - -@item -Leif Lonnblad contributed RCVS support. -@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 -@cindex Ftp-sites -@cindex Getting pcl-cvs -@cindex Email archives - -The latest 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 -pcl-cvs. - -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 - -This document assumes that you know what CVS is, and that you at least -knows the fundamental concepts of CVS. If that is not the case you -should read the man page for CVS. - -Pcl-cvs is only useful once you have checked out a module. So before -you invoke it you must have a copy of a module somewhere in the file -system. - -You invoke pcl-cvs by typing @kbd{M-x cvs-update RET}. If your emacs -responds with @samp{[No match]} your system administrator has not -installed pcl-cvs properly. Try @kbd{M-x load-library RET pcl-cvs RET}. -If that also fails - talk to your root. If it succeeds you might put -this line in your @file{.emacs} file so that you don't have to type the -@samp{load-library} command every time you wish to use pcl-cvs: - -@example -(autoload 'cvs-update "pcl-cvs" nil t) -@end example - -The function @code{cvs-update} will ask for a directory. The command -@samp{cvs update} will be run in that directory. (It should contain -files that have been checked out from a CVS archive.) The output from -@code{cvs} will be parsed and presented in a table in a buffer called -@samp{*cvs*}. It might look something like this: - -@example -PCL-CVS release 1.05. -@comment -release- - -In directory /users/ceder/FOO/test: - Updated bar - Updated file.txt - Modified ci namechange - Updated newer - -In directory /users/ceder/FOO/test/sub: - Modified ci ChangeLog ----------- End ----- -@end example - -In this example the three 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} -and @file{sub/ChangeLog}) have been modified locally, and needs to be -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 -of the "uninteresting" files that have only been @samp{Updated} (and -don't require any further action from you).@refill - -You can also easily get a @samp{diff} between your modified file and the -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 - -The display contains four columns. They contain, from left to right: - -@itemize @bullet -@item -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 -@item -A "need to be checked in"-marker (@samp{ci}). -@item -The file name. -@end itemize - -@menu -* File status:: The meaning of the second field. -* 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 Modified (file status) -@cindex Merged (file status) -@cindex Conflict (file status) -@cindex Added (file status) -@cindex Removed (file status) -@cindex Unknown (file status) -@cindex Removed from repository (file status) -@cindex Removed from repository, changed by you (file status) -@cindex Removed by you, changed in repository (file status) -@cindex Move away @var{file} - it is in the way (file status) -@cindex This repository is missing!@dots{} (file status) - -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 Modified -The file is modified in your working directory, and there was no -modification to the same file in the repository.@refill - -@item Merged -The file is modified in your working directory, and there were -modifications in the repository as well as in your copy, but they were -merged successfully, without conflict, in your working directory.@refill - -@item Conflict -A conflict was detected while trying to merge your changes to @var{file} -with changes from the source repository. @var{file} (the copy in your -working directory) is now the output of the @samp{rcsmerge} command on -the two versions; an unmodified copy of your file is also in your -working directory, with the name @file{.#@var{file}.@var{version}}, -where @var{version} is the RCS revision that your modified file started -from. @xref{Viewing differences}, for more details.@refill - -@item Added -The file has been added by you, but it still needs to be checked in to -the repository.@refill - -@item Removed -The file has been removed by you, but it needs to be checked in to the -repository. You can resurrect it by typing @kbd{a} (@pxref{Adding and -removing files}).@refill - -@item Unknown -A file that was detected in your directory, but that neither appears in -the repository, nor is present on the list of files that CVS should -ignore.@refill - -@end table - -There are also a few special cases, that rarely occur, which have longer -strings in the fields: - -@table @samp -@item Removed from repository -The file has been removed from your directory since someone has removed -it from the repository. (It is still present in the Attic directory, so -no permanent loss has occurred). This, unlike the other entries in this -table, is not an error condition.@refill - -@item Removed from repository, changed by you -You have modified a file that someone have removed from the repository. -You can correct this situation by removing the file manually (see -@pxref{Adding and removing files}).@refill - -@item Removed by you, changed in repository -You have removed a file, and before you committed the removal someone -committed a change to that file. You could use @kbd{a} to resurrect the -file (see @pxref{Adding and removing files}).@refill - -@item Move away @var{file} - it is in the way -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. -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 -@cindex File selection -@cindex Active files - -Many of the commands works on the current set of @dfn{selected} files. - -@itemize @bullet -@item -If there are any files that are marked they constitute the set of -selected files.@refill -@item -Otherwise, if the cursor points to a file, that file is the selected -file.@refill -@item -Otherwise, if the cursor points to a directory, all the files in that -directory that appears in the buffer are the selected files. -@end itemize - -This scheme might seem a little complicated, but once one get used to -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 -This chapter describes all the commands that you can use in pcl-cvs. -@end iftex -@ifinfo -The nodes in this menu contains explanations about all the commands that -you can use in pcl-cvs. They are grouped together by type. -@end ifinfo - -@menu -* Updating the directory:: Commands to update the local directory -* Movement commands:: How to move up and down in the buffer -* Marking files:: How to mark files that other commands - will later operate on. -* Committing changes:: Checking in your modifications to the - 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 -* Undoing changes:: Undoing changes -* 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:: -* 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 -@findex cvs-delete-lock -@cindex Getting the *cvs* buffer -@kindex g - Rerun @samp{cvs update} - - -@table @kbd - -@item M-x cvs-update -Run a @samp{cvs update} command. You will be asked for the directory in -which the @samp{cvs update} will be run. The output will be parsed by -pcl-cvs, and the result printed in the @samp{*cvs*} buffer (see -@pxref{Buffer contents} for a description of the contents).@refill - -By default, @samp{cvs-update} will descend recursively into -subdirectories. You can avoid that behavior by giving a prefix -argument to it (e.g., by typing @kbd{C-u M-x cvs-update RET}).@refill - -All other commands in pcl-cvs requires that you have a @samp{*cvs*} -buffer. This is the command that you use to get one.@refill - -CVS uses lock files in the repository to ensure the integrity of the -data files in the repository. They might be left behind i.e. if a -workstation crashes in the middle of a CVS operation. CVS outputs a -message when it is waiting for a lock file to go away. Pcl-cvs will -show the same message in the *cvs* buffer, together with instructions -for deleting the lock files. You should normally not have to delete -them manually --- just wait a little while and the problem should fix -itself. But if the lock files doesn't disappear you can delete them -with @kbd{M-x cvs-delete-lock RET}.@refill - -@item g -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 -@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 -@findex cookie-previous-cookie -@kindex SPC - Move down one file -@kindex C-n - Move down one file -@kindex n - Move down one file -@kindex C-p - Move up one file -@kindex p - Move up on file - -You can use most normal Emacs commands to move forward and backward in -the buffer. Some keys are rebound to functions that take advantage of -the fact that the buffer is a pcl-cvs buffer: - - -@table @kbd -@item SPC -@itemx C-n -@itemx n -These keys move the cursor one file forward, towards the end of the -buffer (@code{cookie-next-cookie}). - -@item C-p -@itemx p -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 -@kindex m - marking a file -@kindex M - marking all files -@kindex u - unmark a file -@kindex ESC DEL - unmark all files -@kindex DEL - unmark previous file -@findex cvs-mode-mark -@findex cvs-mode-unmark -@findex cvs-mode-mark-all-files -@findex cvs-mode-unmark-all-files -@findex cvs-mode-unmark-up - -Pcl-cvs works on a set of @dfn{selected files} (@pxref{Selected files}). -You can mark and unmark files with these commands: - -@table @kbd -@item m -This marks the file that the cursor is positioned on. If the cursor is -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 -directory, all files in that directory will be unmarked. -(@code{cvs-mode-unmark}).@refill - -@item M -Mark @emph{all} files in the buffer (@code{cvs-mode-mark-all-files}). - -@item @key{ESC} @key{DEL} -Unmark @emph{all} files (@code{cvs-mode-unmark-all-files}). - -@item @key{DEL} -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 -@kindex c - commit files -@vindex cvs-erase-input-buffer (variable) -@vindex cvs-auto-revert-after-commit (variable) -@cindex Commit buffer -@cindex Edit buffer -@cindex Erasing commit message -@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 -selected files (@pxref{Selected files}) (except those who lack the -"ci"-marker - they are ignored). Pressing @kbd{c} causes -@code{cvs-mode-commit} to be run.@refill - -When you press @kbd{c} you will get a buffer called -@samp{*cvs-commit-message*}. Enter the log message for the file(s) in -it. When you are ready you should press @kbd{C-c C-c} to actually -commit the files (using @code{cvs-edit-done}). - -Normally the @samp{*cvs-commit-message*} buffer will retain the log -message from the previous commit, but if the variable -@code{cvs-erase-input-buffer} is set to a non-@code{nil} value the -buffer will be erased. Point and mark will always be located around the -entire buffer so that you can easily erase it with @kbd{C-w} -(@samp{kill-region}).@refill - -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 -your buffer, or if @samp{cvs-auto-revert-after-commit} is set to -@samp{nil}.@refill -@end table - -@node Editing files, Getting info about files, Committing changes, Commands -@comment node-name, next, previous, up -@section Editing files - -@cindex Editing files -@cindex Finding files -@cindex Loading files -@cindex Dired -@cindex Invoking dired -@findex cvs-mode-find-file -@findex cvs-mode-find-file-other-window -@findex cvs-mode-add-change-log-entry-other-window -@kindex f - find file or directory -@kindex o - find file in other window -@kindex A - add ChangeLog entry - -There are currently three commands that can be used to find a file (that -is, load it into a buffer and start editing it there). These commands -work on the line that the cursor is situated at. They ignore any marked -files. - -@table @kbd -@item f -Find the file that the cursor points to. Run @samp{dired} -@ifinfo -(@pxref{Dired,,,Emacs}) -@end ifinfo -if the cursor points to a directory (@code{cvs-mode-find-file}).@refill - -@item o -Like @kbd{f}, but use another window -(@code{cvs-mode-find-file-other-window}).@refill - -@item A -Invoke @samp{add-change-log-entry-other-window} to edit a -@samp{ChangeLog} file. The @samp{ChangeLog} will be found in the -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) -@cindex Getting status -@kindex l - run @samp{cvs log} -@kindex s - run @samp{cvs status} -@findex cvs-mode-log -@findex cvs-mode-status - -Both of the following commands can be customized. -@xref{Customization}.@refill - -@table @kbd -@item l -Run @samp{cvs log} on all selected files, and show the result in a -temporary buffer (@code{cvs-mode-log}). - -@item s -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 -@cindex Resurrecting files -@cindex Deleting files -@cindex Putting files under CVS control -@kindex a - add a file -@kindex r - remove a file -@findex cvs-mode-add -@findex cvs-mode-remove-file - -The following commands are available to make it easy to add and remove -files from the CVS repository. - -@table @kbd -@item a -Add all selected files. This command can be used on @samp{Unknown} -files (see @pxref{File status}). The status of the file will change to -@samp{Added}, and you will have to use @kbd{c} (@samp{cvs-mode-commit}, see -@pxref{Committing changes}) to really add the file to the -repository.@refill - -This command can also be used on @samp{Removed} files (before you commit -them) to resurrect them. - -Selected files that are neither @samp{Unknown} nor @samp{Removed} will -be ignored by this command. - -The command that is run is @code{cvs-mode-add}. - -@item r -This command removes the selected files (after prompting for -confirmation). The files are @samp{rm}ed from your directory and -(unless the status was @samp{Unknown}; @pxref{File status}) they will -also be @samp{cvs remove}d. If the files were @samp{Unknown} they will -disappear from the buffer. Otherwise their status will change to -@samp{Removed}, and you must use @kbd{c} (@samp{cvs-mode-commit}, -@pxref{Committing changes}) to commit the removal.@refill - -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 -@kindex U - undo changes -@findex cvs-mode-undo-local-changes - -@table @kbd -@item U -If you have modified a file, and for some reason decide that you don't -want to keep the changes, you can undo them with this command. It works -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 -@cindex Getting rid of uninteresting lines -@cindex Removing uninteresting (processed) lines -@cindex Handled lines, removing them -@kindex x - remove processed entries -@kindex C-k - remove selected entries -@findex cvs-mode-remove-handled -@findex cvs-mode-acknowledge -@findex cvs-mode-ignore - -@table @kbd -@item x -This command allows you to remove all entries that you have processed. -More specifically, the lines for @samp{Updated} files (@pxref{File -status} and files that have been checked in (@pxref{Committing changes}) -are removed from the buffer. If a directory becomes empty the heading -for that directory is also removed. This makes it easier to get an -overview of what needs to be done. - -The command is called @code{cvs-mode-remove-handled}. If -@samp{cvs-auto-remove-handled} is set to non-@code{nil} this will -automatically be performed after every commit.@refill - -@item C-k -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 - -@table @kbd -@item i -Arrange so that CVS will ignore the selected files. The file names are -added to the @file{.cvsignore} file in the corresponding directory. If -the @file{.cvsignore} doesn't exist it will be created. - -The @file{.cvsignore} file should normally be added to the repository, -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 -@comment node-name, next, previous, up -@section Viewing differences -@cindex Diff -@cindex Conflicts, how to resolve them -@cindex Viewing differences -@kindex d - run @samp{cvs diff} -@kindex b - diff backup file -@findex cvs-mode-diff-cvs -@findex cvs-mode-diff-backup -@vindex cvs-diff-ignore-marks (variable) - -@table @kbd -@item d -Display a @samp{cvs diff} between the selected files and the RCS version -that they are based on. @xref{Customization} describes how you can send -flags to @samp{cvs diff}. If @var{cvs-diff-ignore-marks} is set to a -non-@code{nil} value or if a prefix argument is given (but not both) any -marked files will not be considered to be selected. -(@code{cvs-mode-diff-cvs}).@refill - -@item b -If CVS finds a conflict while merging two versions of a file (during a -@samp{cvs update}, @pxref{Updating the directory}) it will save the -original file in a file called @file{.#@var{FILE}.@var{VERSION}} where -@var{FILE} is the name of the file, and @var{VERSION} is the RCS version -number that your file was based on.@refill - -With the @kbd{b} command you can run a @samp{diff} on the files -@file{.#@var{FILE}.@var{VERSION}} and @file{@var{FILE}}. You can get a -context- or Unidiff by setting @samp{cvs-diff-flags} - -@pxref{Customization}. This command only works on files that have -status @samp{Conflict} or @samp{Merged}.@refill - -If @var{cvs-diff-ignore-marks} is set to a non-@code{nil} value or if a -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 -@comment node-name, next, previous, up -@section Running emerge -@cindex Emerge -@cindex Invoking emerge -@cindex Conflicts, resolving -@cindex Resolving conflicts -@kindex e - invoke @samp{emerge} -@findex cvs-mode-emerge - -@table @kbd -@item e -Invoke @samp{emerge} on one file. This command works slightly different -depending on the file status. - -@table @asis -@item @samp{Modified} -Run @samp{emerge-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{emerge-files-with-ancestor} 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. -@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. -@end table - -@node Reverting your buffers, Miscellaneous commands, Emerge, Commands -@comment node-name, next, previous, up -@section Reverting your buffers -@findex cvs-mode-revert-updated-buffers -@kindex R - revert buffers -@cindex Syncing buffers -@cindex Reverting buffers - -@table @kbd -@item R -If you are editing (or just viewing) a file in a buffer, and that file -is changed by CVS during a @samp{cvs-update}, all you have to do is type -@kbd{R} in the *cvs* buffer to read in the new versions of the -files.@refill - -All files that are @samp{Updated}, @samp{Merged} or in @samp{Conflict} -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 -@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 -@cindex Byte compilation -@cindex Getting rid of lock files -@cindex Lock files -@kindex q - bury the *cvs* buffer -@findex bury-buffer - -@table @kbd -@item M-x cvs-byte-compile-files -Byte compile all selected files that end in .el. - -@item M-x cvs-delete-lock -This command can be used in any buffer, and deletes the lock files that -the *cvs* buffer informs you about. You should normally never have to -use this command since CVS tries very carefully to always remove the -lock files itself. - -You can only use this command when a message in the *cvs* buffer tells -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}). - -@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) -@vindex cvs-diff-flags (variable) -@vindex cvs-diff-ignore-marks (variable) -@vindex cvs-log-flags (variable) -@vindex cvs-status-flags (variable) -@vindex cvs-auto-remove-handled (variable) -@vindex cvs-update-prog-output-skip-regexp (variable) -@vindex cvs-cvsroot (variable) -@vindex TMPDIR (environment variable) -@vindex cvs-auto-revert-after-commit (variable) -@vindex cvs-commit-buffer-require-final-newline (variable) -@vindex cvs-sort-ignore-file (variable) -@cindex Inhibiting the Copyright message. -@cindex Copyright message, getting rid of it -@cindex Getting rid of the Copyright message. -@cindex Customization -@cindex Variables, list of all -@cindex Erasing the input buffer -@cindex Context diff, how to get -@cindex Unidiff, how to get -@cindex Automatically remove handled files -@cindex -u option in modules file -@cindex Modules file (-u option) -@cindex Update program (-u option in modules file) -@cindex Reverting buffers after commit -@cindex Require final newline -@cindex Automatically inserting newline -@cindex Commit message, inserting newline -@cindex Sorting the .cvsignore file -@cindex .cvsignore file, sorting -@cindex Automatically sorting .cvsignore - -If you have an idea about any customization that would be handy but -isn't present in this list, please tell me! @xref{Bugs} for info on how -to reach me.@refill - -@table @samp -@item cvs-erase-input-buffer -If set to anything else than @code{nil} the edit buffer will be erased -before you write the log message (@pxref{Committing changes}). - -@item cvs-inhibit-copyright-message -The copyright message that is displayed on startup can be annoying after -a while. Set this variable to @samp{t} if you want to get rid of it. -(But don't set this to @samp{t} in the system defaults file - new users -should see this message at least once). - -@item cvs-diff-flags -A list of strings to pass as arguments to the @samp{cvs diff} and -@samp{diff} programs. This is used by @samp{cvs-mode-diff-cvs} and -@samp{cvs-mode-diff-backup} (key @kbd{b}, @pxref{Viewing differences}). If -you prefer the Unidiff format you could add this line to your -@file{.emacs} file:@refill - -@example -(setq cvs-diff-flags '("-u")) -@end example - -@item cvs-diff-ignore-marks -If this variable is non-@code{nil} or if a prefix argument is given (but -not both) to @samp{cvs-mode-diff-cvs} or @samp{cvs-mode-diff-backup} -marked files are not considered selected. - -@item cvs-log-flags -List of strings to send to @samp{cvs log}. Used by @samp{cvs-mode-log} -(key @kbd{l}, @pxref{Getting info about files}). - -@item cvs-status-flags -List of strings to send to @samp{cvs status}. Used by @samp{cvs-mode-status} -(key @kbd{s}, @pxref{Getting info about files}). - -@item cvs-auto-remove-handled -If this variable is set to any non-@code{nil} value -@samp{cvs-mode-remove-handled} will be called every time you check in -files, after the check-in is ready. @xref{Removing handled -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 - -@item cvs-update-prog-output-skip-regexp -The @samp{-u} flag in the @file{modules} file can be used to run a command -whenever a @samp{cvs update} is performed (see cvs(5)). This regexp -is used to search for the last line in that output. It is normally set -to @samp{"$"}. That setting is only correct if the command outputs -nothing. Note that pcl-cvs will get very confused if the command -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 -called as @samp{cvs -d @var{cvs-cvsroot}@dots{}} This can be useful if -your site has several repositories. - -@item TMPDIR -Pcl-cvs uses this @emph{environment variable} to decide where to put the -temporary files it needs. It defaults to @file{/tmp} if it is not set. - -@item cvs-commit-buffer-require-final-newline -When you enter a log message in the @samp{*cvs-commit-message*} buffer -pcl-cvs will normally automatically insert a trailing newline, unless -there already is one. This behavior can be controlled via -@samp{cvs-commit-buffer-require-final-newline}. If it is @samp{t} (the -default behavior), a newline will always be appended. If it is -@samp{nil}, newlines will never be appended. Any other value causes -pcl-cvs to ask the user whenever there is no trailing newline in the -commit message buffer. - -@item cvs-sort-ignore-file -If this variable is set to any non-@samp{nil} value the -@file{.cvsignore} will always be sorted whenever you use -@samp{cvs-mode-ignore} to add a file to it. This option is on by -default. - -@end table -@node Future enhancements, Bugs, Customization, Top -@comment node-name, next, previous, up -@chapter Future enhancements -@cindex Enhancements - -Pcl-cvs is still under development and needs a number of enhancements to -be called complete. Below is my current wish-list for future releases -of pcl-cvs. Please, let me know which of these features you want most. -They are listed below in approximately the order that I currently think -I will implement them in. - -@itemize @bullet -@item -Rewritten parser code. There are many situations where pcl-cvs will -fail to recognize the output from CVS. The situation could be greatly -increased. - -@item -@samp{cvs-status}. This will run @samp{cvs status} in a directory and -produce a buffer that looks pretty much like the current *cvs* buffer. -That buffer will include information for all version-controlled files. -(There will be a simple keystroke to remove all "uninteresting" files, -that is, files that are "Up-to-date"). In this new buffer you will be -able to update a file, commit a file, et c. The big win with this is -that you will be able to watch the differences between your current -working file and the head revision in the repository before you update -the file, and you can then choose to update it or let it wait for a -while longer. - -@item -Log mode. When this mode is finished you will be able to move around -(using @kbd{n} and @kbd{p}) between the revisions of a file, mark two of -them, and run a diff between them. You will be able to hide branches -(similar to the way you can hide sub-paragraphs in outline-mode) and do -merges between revisions. Other ideas about this are welcome. - -@item -The current model for marks in the *cvs* buffer seems to be confusing. -I am considering to use the VM model instead, where marks are normally -inactive. To activate the mark, you issue a command like -@samp{cvs-mode-next-command-uses-marks}. I might implement a flag so -that you can use either version. Feedback on this before I start coding -it is very welcome. - -@item -It should be possible to run commands such as @samp{cvs log}, @samp{cvs -status} and @samp{cvs commit} directly from a buffer containing a file, -instead of having to @samp{cvs-update}. If the directory contains many -files the @samp{cvs-update} can take quite some time, especially on a -slow machine. I planed to put these kind of commands on the prefix -@kbd{C-c C-v}, but that turned out to be used by for instance c++-mode. -If you have any suggestions for a better prefix key, please let me know. - -@item -Increased robustness. For instance, you can not currently press -@kbd{C-g} when you are entering the description of a file that you are -adding without confusing pcl-cvs. - -@item -Support for multiple active *cvs* buffers. - -@item -Dired support. I have an experimental @file{dired-cvs.el} that works -together with CVS 1.2. Unfortunately I wrote it on top of a -non-standard @file{dired.el}, so it must be rewritten.@refill - -@item -An ability to send user-supplied options to all the cvs commands. - -@item -Pcl-cvs is not at all clever about what it should do when @samp{cvs -update} runs a program (due to the @samp{-u} option in the -@file{modules} file --- see @samp{cvs(5)}). The current release uses a -regexp to search for the end. At the very least that regexp should be -configured for different modules. Tell me if you have any idea about -what is the right thing to do. In a perfect world the program should -also be allowed to print to @samp{stderr} without causing pcl-cvs to -crash. -@end itemize - - -If you miss something in this wish-list, let me know! I don't promise -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 -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. - -@node Bugs, Function and Variable Index, 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 -@cindex Author, how to reach -@cindex Email to the author -@cindex Known bugs -@cindex Bugs, known -@cindex FAQ -@cindex Problems, list of common - -If you find a bug or misfeature, don't hesitate to tell me! Send email -to @samp{ceder@@lysator.liu.se}. - -If you have ideas for improvements, or if you have written some -extensions to this package, I would like to hear from you. I hope that -you find this package useful! - -Below is a partial list of currently known problems with pcl-cvs version -1.05. - -@table @asis -@item Commit causes Emacs to hang -Emacs waits for the @samp{cvs commit} command to finish before you can -do anything. If you start a background job from the loginfo file you -must take care that it closes @samp{stdout} and @samp{stderr} if you do -not want to wait for it. (You do that with @samp{background-command &>- -2&>- &} if you are starting @samp{background-command} from a -@samp{/bin/sh} shell script). - -Your emacs will also hang if there was a lock file in the repository. -In this case you can type @kbd{C-g} to get control over your emacs -again. - -@item Name clash in Emacs 19 -This is really a bug in Elib or the Emacs 19 distribution. Both Elib and -Emacs 19.6 through at least 19.10 contains a file named -@file{cookie.el}. One of the files will have to be renamed, and we are -currently negotiating about which of the files to rename. - -@item Commands while cvs-update is running -It is possible to type commands in the *cvs* buffer while the update is -running, but error messages is all that you will get. The error -messages should be better. - -@item Unexpected output from CVS -Unexpected output from CVS confuses pcl-cvs. It will currently create a -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 -@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 - -@summarycontents -@contents -@bye diff --git a/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh b/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh deleted file mode 100644 index 3af83d7..0000000 --- a/gnu/usr.bin/cvs/contrib/rcs-to-cvs.sh +++ /dev/null @@ -1,185 +0,0 @@ -#! /bin/sh -# -# $Id: rcs-to-cvs.sh,v 1.2 1995/07/15 03:40:34 jimb Exp $ -# Based on the CVS 1.0 checkin csh script. -# Contributed by Per Cederqvist <ceder@signum.se>. -# Rewritten in sh by David MacKenzie <djm@cygnus.com>. -# -# Copyright (c) 1989, Brian Berliner -# -# You may distribute under the terms of the GNU General Public License. -# -############################################################################# -# -# Check in sources that previously were under RCS or no source control system. -# -# The repository is the directory where the sources should be deposited. -# -# Traverses the current directory, ensuring that an -# identical directory structure exists in the repository directory. It -# then checks the files in in the following manner: -# -# 1) If the file doesn't yet exist, check it in as revision 1.1 -# -# The script also is somewhat verbose in letting the user know what is -# going on. It prints a diagnostic when it creates a new file, or updates -# a file that has been modified on the trunk. -# -# Bugs: doesn't put the files in branch 1.1.1 -# doesn't put in release and vendor tags -# -############################################################################# - -usage="Usage: rcs-to-cvs [-v] [-m message] [-f message_file] repository" -vbose=0 -message="" -message_file=/usr/tmp/checkin.$$ -got_one=0 - -if [ $# -lt 1 ]; then - echo "$usage" >&2 - exit 1 -fi - -while [ $# -ne 0 ]; do - case "$1" in - -v) - vbose=1 - ;; - -m) - shift - echo $1 > $message_file - got_one=1 - ;; - -f) - shift - message_file=$1 - got_one=2 - ;; - *) - break - esac - shift -done - -if [ $# -lt 1 ]; then - echo "$usage" >&2 - exit 1 -fi - -repository=$1 -shift - -if [ -z "$CVSROOT" ]; then - echo "Please the environmental variable CVSROOT to the root" >&2 - echo " of the tree you wish to update" >&2 - exit 1 -fi - -if [ $got_one -eq 0 ]; then - echo "Please Edit this file to contain the RCS log information" >$message_file - echo "to be associated with this directory (please remove these lines)">>$message_file - ${EDITOR-/usr/ucb/vi} $message_file - got_one=1 -fi - -# Ya gotta share. -umask 0 - -update_dir=${CVSROOT}/${repository} -[ ! -d ${update_dir} ] && mkdir $update_dir - -if [ -d SCCS ]; then - echo SCCS files detected! >&2 - exit 1 -fi -if [ -d RCS ]; then - co RCS/* -fi - -for name in * .[a-zA-Z0-9]* -do - case "$name" in - RCS | *~ | \* | .\[a-zA-Z0-9\]\* ) continue ;; - esac - echo $name - if [ $vbose -ne 0 ]; then - echo "Updating ${repository}/${name}" - fi - if [ -d "$name" ]; then - if [ ! -d "${update_dir}/${name}" ]; then - echo "WARNING: Creating new directory ${repository}/${name}" - mkdir "${update_dir}/${name}" - if [ $? -ne 0 ]; then - echo "ERROR: mkdir failed - aborting" >&2 - exit 1 - fi - fi - cd "$name" - if [ $? -ne 0 ]; then - echo "ERROR: Couldn\'t cd to $name - aborting" >&2 - exit 1 - fi - if [ $vbose -ne 0 ]; then - $0 -v -f $message_file "${repository}/${name}" - else - $0 -f $message_file "${repository}/${name}" - fi - if [ $? -ne 0 ]; then - exit 1 - fi - cd .. - else # if not directory - if [ ! -f "$name" ]; then - echo "WARNING: $name is neither a regular file" - echo " nor a directory - ignored" - continue - fi - file="${update_dir}/${name},v" - comment="" - if grep -s '\$Log.*\$' "${name}"; then # If $Log keyword - myext=`echo $name | sed 's,.*\.,,'` - [ "$myext" = "$name" ] && myext= - case "$myext" in - c | csh | e | f | h | l | mac | me | mm | ms | p | r | red | s | sh | sl | cl | ml | el | tex | y | ye | yr | "" ) - ;; - - * ) - echo "For file ${file}:" - grep '\$Log.*\$' "${name}" - echo -n "Please insert a comment leader for file ${name} > " - read comment - ;; - esac - fi - if [ ! -f "$file" ]; then # If not exists in repository - if [ ! -f "${update_dir}/Attic/${name},v" ]; then - echo "WARNING: Creating new file ${repository}/${name}" - if [ -f RCS/"${name}",v ]; then - echo "MSG: Copying old rcs file." - cp RCS/"${name}",v "$file" - else - if [ -n "${comment}" ]; then - rcs -q -i -c"${comment}" -t${message_file} -m'.' "$file" - fi - ci -q -u1.1 -t${message_file} -m'.' "$file" - if [ $? -ne 0 ]; then - echo "ERROR: Initial check-in of $file failed - aborting" >&2 - exit 1 - fi - fi - else - file="${update_dir}/Attic/${name},v" - echo "WARNING: IGNORED: ${repository}/Attic/${name}" - continue - fi - else # File existed - echo "ERROR: File exists in repository: Ignored: $file" - continue - fi - fi -done - -[ $got_one -eq 1 ] && rm -f $message_file - -exit 0 diff --git a/gnu/usr.bin/cvs/contrib/rcs2log.sh b/gnu/usr.bin/cvs/contrib/rcs2log.sh deleted file mode 100644 index ccea907..0000000 --- a/gnu/usr.bin/cvs/contrib/rcs2log.sh +++ /dev/null @@ -1,592 +0,0 @@ -#! /bin/sh - -# RCS to ChangeLog generator - -# Generate a change log prefix from RCS files and the ChangeLog (if any). -# Output the new prefix to standard output. -# You can edit this prefix by hand, and then prepend it to ChangeLog. - -# Ignore log entries that start with `#'. -# Clump together log entries that start with `{topic} ', -# where `topic' contains neither white space nor `}'. - -# Author: Paul Eggert <eggert@twinsun.com> - -# $Id: rcs2log.sh,v 1.2 1995/07/28 19:48:45 eggert Exp $ - -# Copyright 1992, 1993, 1994, 1995 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; see the file COPYING. If not, write to -# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -tab=' ' -nl=' -' - -# Parse options. - -# defaults -: ${AWK=awk} -: ${TMPDIR=/tmp} -hostname= # name of local host (if empty, will deduce it later) -indent=8 # indent of log line -length=79 # suggested max width of log line -logins= # login names for people we know fullnames and mailaddrs of -loginFullnameMailaddrs= # login<tab>fullname<tab>mailaddr triplets -recursive= # t if we want recursive rlog -rlog_options= # options to pass to rlog -tabwidth=8 # width of horizontal tab - -while : -do - case $1 in - -i) indent=${2?}; shift;; - -h) hostname=${2?}; shift;; - -l) length=${2?}; shift;; - -[nu]) # -n is obsolescent; it is replaced by -u. - case $1 in - -n) case ${2?}${3?}${4?} in - *"$tab"* | *"$nl"*) - echo >&2 "$0: -n '$2' '$3' '$4': tabs, newlines not allowed" - exit 1 - esac - loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2$tab$3$tab$4 - shift; shift; shift;; - -u) - # If $2 is not tab-separated, use colon for separator. - case ${2?} in - *"$nl"*) - echo >&2 "$0: -u '$2': newlines not allowed" - exit 1;; - *"$tab"*) - t=$tab;; - *) - t=: - esac - case $2 in - *"$t"*"$t"*"$t"*) - echo >&2 "$0: -u '$2': too many fields" - exit 1;; - *"$t"*"$t"*) - ;; - *) - echo >&2 "$0: -u '$2': not enough fields" - exit 1 - esac - loginFullnameMailaddrs=$loginFullnameMailaddrs$nl$2 - shift - esac - logins=$logins$nl$login - ;; - -r) rlog_options=$rlog_options$nl${2?}; shift;; - -R) recursive=t;; - -t) tabwidth=${2?}; shift;; - -*) echo >&2 "$0: usage: $0 [options] [file ...] -Options: - [-h hostname] [-i indent] [-l length] [-R] [-r rlog_option] - [-t tabwidth] [-u 'login<TAB>fullname<TAB>mailaddr']..." - exit 1;; - *) break - esac - shift -done - -month_data=' - m[0]="Jan"; m[1]="Feb"; m[2]="Mar" - m[3]="Apr"; m[4]="May"; m[5]="Jun" - m[6]="Jul"; m[7]="Aug"; m[8]="Sep" - m[9]="Oct"; m[10]="Nov"; m[11]="Dec" - - # days in non-leap year thus far, indexed by month (0-12) - mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90 - mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212 - mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334 - mo[12]=365 -' - - -# Put rlog output into $rlogout. - -# If no rlog options are given, -# log the revisions checked in since the first ChangeLog entry. -case $rlog_options in -'') - date=1970 - if test -s ChangeLog - then - # Add 1 to seconds to avoid duplicating most recent log. - e=' - /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{ - '"$month_data"' - year = $5 - for (i=0; i<=11; i++) if (m[i] == $2) break - dd = $3 - hh = substr($0,12,2) - mm = substr($0,15,2) - ss = substr($0,18,2) - ss++ - if (ss == 60) { - ss = 0 - mm++ - if (mm == 60) { - mm = 0 - hh++ - if (hh == 24) { - hh = 0 - dd++ - monthdays = mo[i+1] - mo[i] - if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++ - if (dd == monthdays + 1) { - dd = 1 - i++ - if (i == 12) { - i = 0 - year++ - } - } - } - } - } - # Output comma instead of space to avoid CVS 1.5 bug. - printf "%d/%02d/%02d,%02d:%02d:%02d\n", year,i+1,dd,hh,mm,ss - exit - } - ' - d=`$AWK "$e" <ChangeLog` || exit - case $d in - ?*) date=$d - esac - fi - datearg="-d>$date" -esac - -# If CVS is in use, examine its repository, not the normal RCS files. -if test ! -f CVS/Repository -then - rlog=rlog - repository= -else - rlog='cvs log' - repository=`sed 1q <CVS/Repository` || exit - test ! -f CVS/Root || CVSROOT=`cat <CVS/Root` || exit - case $CVSROOT in - *:/*) - # remote repository - ;; - *) - # local repository - case $repository in - /*) ;; - *) repository=${CVSROOT?}/$repository - esac - if test ! -d "$repository" - then - echo >&2 "$0: $repository: bad repository (see CVS/Repository)" - exit 1 - fi - esac -fi - -# With no arguments, examine all files under the RCS directory. -case $# in -0) - case $repository in - '') - oldIFS=$IFS - IFS=$nl - case $recursive in - t) - RCSdirs=`find . -name RCS -type d -print` - filesFromRCSfiles='s|,v$||; s|/RCS/|/|; s|^\./||' - files=` - { - case $RCSdirs in - ?*) find $RCSdirs -type f -print - esac - find . -name '*,v' -print - } | - sort -u | - sed "$filesFromRCSfiles" - `;; - *) - files= - for file in RCS/.* RCS/* .*,v *,v - do - case $file in - RCS/. | RCS/..) continue;; - RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue - esac - files=$files$nl$file - done - case $files in - '') exit 0 - esac - esac - set x $files - shift - IFS=$oldIFS - esac -esac - -llogout=$TMPDIR/rcs2log$$l -rlogout=$TMPDIR/rcs2log$$r -trap exit 1 2 13 15 -trap "rm -f $llogout $rlogout; exit 1" 0 - -case $rlog_options in -?*) $rlog $rlog_options ${1+"$@"} >$rlogout;; -'') $rlog "$datearg" ${1+"$@"} >$rlogout -esac || exit - - -# Get the full name of each author the logs mention, and set initialize_fullname -# to awk code that initializes the `fullname' awk associative array. -# Warning: foreign authors (i.e. not known in the passwd file) are mishandled; -# you have to fix the resulting output by hand. - -initialize_fullname= -initialize_mailaddr= - -case $loginFullnameMailaddrs in -?*) - case $loginFullnameMailaddrs in - *\"* | *\\*) - sed 's/["\\]/\\&/g' >$llogout <<EOF || exit -$loginFullnameMailaddrs -EOF - loginFullnameMailaddrs=`cat $llogout` - esac - - oldIFS=$IFS - IFS=$nl - for loginFullnameMailaddr in $loginFullnameMailaddrs - do - case $loginFullnameMailaddr in - *"$tab"*) IFS=$tab;; - *) IFS=: - esac - set x $loginFullnameMailaddr - login=$2 - fullname=$3 - mailaddr=$4 - initialize_fullname="$initialize_fullname - fullname[\"$login\"] = \"$fullname\"" - initialize_mailaddr="$initialize_mailaddr - mailaddr[\"$login\"] = \"$mailaddr\"" - done - IFS=$oldIFS -esac - -case $llogout in -?*) sort -u -o $llogout <<EOF || exit -$logins -EOF -esac -output_authors='/^date: / { - if ($2 ~ /^[0-9]*[-\/][0-9][0-9][-\/][0-9][0-9]$/ && $3 ~ /^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][-+0-9:]*;$/ && $4 == "author:" && $5 ~ /^[^;]*;$/) { - print substr($5, 1, length($5)-1) - } -}' -authors=` - $AWK "$output_authors" <$rlogout | - case $llogout in - '') sort -u;; - ?*) sort -u | comm -23 - $llogout - esac -` -case $authors in -?*) - cat >$llogout <<EOF || exit -$authors -EOF - initialize_author_script='s/["\\]/\\&/g; s/.*/author[\"&\"] = 1/' - initialize_author=`sed -e "$initialize_author_script" <$llogout` - awkscript=' - BEGIN { - alphabet = "abcdefghijklmnopqrstuvwxyz" - ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - '"$initialize_author"' - } - { - if (author[$1]) { - fullname = $5 - if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) { - # Remove the junk from fullnames like "0000-Admin(0000)". - fullname = substr(fullname, index(fullname, "-") + 1) - fullname = substr(fullname, 1, index(fullname, "(") - 1) - } - if (fullname ~ /,[^ ]/) { - # Some sites put comma-separated junk after the fullname. - # Remove it, but leave "Bill Gates, Jr" alone. - fullname = substr(fullname, 1, index(fullname, ",") - 1) - } - abbr = index(fullname, "&") - if (abbr) { - a = substr($1, 1, 1) - A = a - i = index(alphabet, a) - if (i) A = substr(ALPHABET, i, 1) - fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1) - } - - # Quote quotes and backslashes properly in full names. - # Do not use gsub; traditional awk lacks it. - quoted = "" - rest = fullname - for (;;) { - p = index(rest, "\\") - q = index(rest, "\"") - if (p) { - if (q && q<p) p = q - } else { - if (!q) break - p = q - } - quoted = quoted substr(rest, 1, p-1) "\\" substr(rest, p, 1) - rest = substr(rest, p+1) - } - - printf "fullname[\"%s\"] = \"%s%s\"\n", $1, quoted, rest - author[$1] = 0 - } - } - ' - - initialize_fullname=` - (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null | - $AWK -F: "$awkscript" - `$initialize_fullname -esac - - -# Function to print a single log line. -# We don't use awk functions, to stay compatible with old awk versions. -# `Log' is the log message (with \n replaced by \r). -# `files' contains the affected files. -printlogline='{ - - # Following the GNU coding standards, rewrite - # * file: (function): comment - # to - # * file (function): comment - if (Log ~ /^\([^)]*\): /) { - i = index(Log, ")") - files = files " " substr(Log, 1, i) - Log = substr(Log, i+3) - } - - # If "label: comment" is too long, break the line after the ":". - sep = " " - if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string - - # Print the label. - printf "%s*%s:", indent_string, files - - # Print each line of the log, transliterating \r to \n. - while ((i = index(Log, CR)) != 0) { - logline = substr(Log, 1, i-1) - if (logline ~ /[^'"$tab"' ]/) { - printf "%s%s\n", sep, logline - } else { - print "" - } - sep = indent_string - Log = substr(Log, i+1) - } -}' - -case $hostname in -'') - hostname=`( - hostname || uname -n || uuname -l || cat /etc/whoami - ) 2>/dev/null` || { - echo >&2 "$0: cannot deduce hostname" - exit 1 - } -esac - - -# Process the rlog output, generating ChangeLog style entries. - -# First, reformat the rlog output so that each line contains one log entry. -# Transliterate \n to \r so that multiline entries fit on a single line. -# Discard irrelevant rlog output. -$AWK <$rlogout ' - BEGIN { repository = "'"$repository"'" } - /^RCS file:/ { - if (repository != "") { - filename = $3 - if (substr(filename, 1, length(repository) + 1) == repository "/") { - filename = substr(filename, length(repository) + 2) - } - if (filename ~ /,v$/) { - filename = substr(filename, 1, length(filename) - 2) - } - } - } - /^Working file:/ { if (repository == "") filename = $3 } - /^date: /, /^(-----------*|===========*)$/ { - if ($0 ~ /^branches: /) { next } - if ($0 ~ /^date: [0-9][- +\/0-9:]*;/) { - date = $2 - if (date ~ /-/) { - # An ISO format date. Replace all "-"s with "/"s. - newdate = "" - while ((i = index(date, "-")) != 0) { - newdate = newdate substr(date, 1, i-1) "/" - date = substr(date, i+1) - } - date = newdate date - } - # Ignore any time zone; ChangeLog has no room for it. - time = substr($3, 1, 8) - author = substr($5, 1, length($5)-1) - printf "%s %s %s %s %c", filename, date, time, author, 13 - next - } - if ($0 ~ /^(-----------*|===========*)$/) { print ""; next } - printf "%s%c", $0, 13 - } -' | - -# Now each line is of the form -# FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG -# where \r stands for a carriage return, -# and each line of the log is terminated by \r instead of \n. -# Sort the log entries, first by date+time (in reverse order), -# then by author, then by log entry, and finally by file name (just in case). -sort +1 -3r +3 +0 | - -# Finally, reformat the sorted log entries. -$AWK ' - BEGIN { - # Some awk variants do not understand "\r" or "\013", so we have to - # put a carriage return directly in the file. - CR="
" # <-- There is a single CR between the " chars here. - - # Initialize the fullname and mailaddr associative arrays. - '"$initialize_fullname"' - '"$initialize_mailaddr"' - - # Initialize indent string. - indent_string = "" - i = '"$indent"' - if (0 < '"$tabwidth"') - for (; '"$tabwidth"' <= i; i -= '"$tabwidth"') - indent_string = indent_string "\t" - while (1 <= i--) - indent_string = indent_string " " - - # Set up date conversion tables. - # RCS uses a nice, clean, sortable format, - # but ChangeLog wants the traditional, ugly ctime format. - - # January 1, 0 AD (Gregorian) was Saturday = 6 - EPOCH_WEEKDAY = 6 - # Of course, there was no 0 AD, but the algorithm works anyway. - - w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed" - w[4]="Thu"; w[5]="Fri"; w[6]="Sat" - - '"$month_data"' - } - - { - newlog = substr($0, 1 + index($0, CR)) - - # Ignore log entries prefixed by "#". - if (newlog ~ /^#/) { next } - - if (Log != newlog || date != $2 || author != $4) { - - # The previous log and this log differ. - - # Print the old log. - if (date != "") '"$printlogline"' - - # Logs that begin with "{clumpname} " should be grouped together, - # and the clumpname should be removed. - # Extract the new clumpname from the log header, - # and use it to decide whether to output a blank line. - newclumpname = "" - sep = "\n" - if (date == "") sep = "" - if (newlog ~ /^\{[^'"$tab"' }]*}['"$tab"' ]/) { - i = index(newlog, "}") - newclumpname = substr(newlog, 1, i) - while (substr(newlog, i+1) ~ /^['"$tab"' ]/) i++ - newlog = substr(newlog, i+1) - if (clumpname == newclumpname) sep = "" - } - printf sep - clumpname = newclumpname - - # Get ready for the next log. - Log = newlog - if (files != "") - for (i in filesknown) - filesknown[i] = 0 - files = "" - } - if (date != $2 || author != $4) { - # The previous date+author and this date+author differ. - # Print the new one. - date = $2 - author = $4 - - # Convert nice RCS date like "1992/01/03 00:03:44" - # into ugly ctime date like "Fri Jan 3 00:03:44 1992". - # Calculate day of week from Gregorian calendar. - i = index($2, "/") - year = substr($2, 1, i-1) + 0 - monthday = substr($2, i+1) - i = index(monthday, "/") - month = substr(monthday, 1, i-1) + 0 - day = substr(monthday, i+1) + 0 - leap = 0 - if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1 - days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1 - - # Print "date fullname (email address)". - # Get fullname and email address from associative arrays; - # default to author and author@hostname if not in arrays. - if (fullname[author]) - auth = fullname[author] - else - auth = author - printf "%s %s %2d %s %d %s ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth - if (mailaddr[author]) - printf "<%s>\n\n", mailaddr[author] - else - printf "<%s@%s>\n\n", author, "'"$hostname"'" - } - if (! filesknown[$1]) { - filesknown[$1] = 1 - if (files == "") files = " " $1 - else files = files ", " $1 - } - } - END { - # Print the last log. - if (date != "") { - '"$printlogline"' - printf "\n" - } - } -' && - - -# Exit successfully. - -exec rm -f $llogout $rlogout diff --git a/gnu/usr.bin/cvs/contrib/rcs2sccs.sh b/gnu/usr.bin/cvs/contrib/rcs2sccs.sh deleted file mode 100644 index af70138..0000000 --- a/gnu/usr.bin/cvs/contrib/rcs2sccs.sh +++ /dev/null @@ -1,143 +0,0 @@ -#! /bin/sh -# -# -# OrigId: rcs2sccs,v 1.12 90/10/04 20:52:23 kenc Exp Locker: kenc -# $Id: rcs2sccs.sh,v 1.1 1995/07/10 02:26:45 kfogel Exp $ - -############################################################ -# Error checking -# -if [ ! -d SCCS ] ; then - mkdir SCCS -fi - -logfile=/tmp/rcs2sccs_$$_log -rm -f $logfile -tmpfile=/tmp/rcs2sccs_$$_tmp -rm -f $tmpfile -emptyfile=/tmp/rcs2sccs_$$_empty -echo -n "" > $emptyfile -initialfile=/tmp/rcs2sccs_$$_init -echo "Initial revision" > $initialfile -sedfile=/tmp/rcs2sccs_$$_sed -rm -f $sedfile -revfile=/tmp/rcs2sccs_$$_rev -rm -f $revfile -commentfile=/tmp/rcs2sccs_$$_comment -rm -f $commentfile - -# create the sed script -cat > $sedfile << EOF -s,;Id;,%Z%%M% %I% %E%,g -s,;SunId;,%Z%%M% %I% %E%,g -s,;RCSfile;,%M%,g -s,;Revision;,%I%,g -s,;Date;,%E%,g -s,;Id:.*;,%Z%%M% %I% %E%,g -s,;SunId:.*;,%Z%%M% %I% %E%,g -s,;RCSfile:.*;,%M%,g -s,;Revision:.*;,%I%,g -s,;Date:.*;,%E%,g -EOF -sed -e 's/;/\\$/g' $sedfile > $tmpfile -cp $tmpfile $sedfile -############################################################ -# Loop over every RCS file in RCS dir -# -for vfile in *,v; do - # get rid of the ",v" at the end of the name - file=`echo $vfile | sed -e 's/,v$//'` - - # work on each rev of that file in ascending order - firsttime=1 - rlog $file | grep "^revision [0-9][0-9]*\." | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile - for rev in `cat $revfile`; do - if [ $? != 0 ]; then - echo ERROR - revision - exit - fi - # get file into current dir and get stats - date=`rlog -r$rev $file | grep "^date: " | awk '{print $2; exit}' | sed -e 's/^19//'` - time=`rlog -r$rev $file | grep "^date: " | awk '{print $3; exit}' | sed -e 's/;//'` - author=`rlog -r$rev $file | grep "^date: " | awk '{print $5; exit}' | sed -e 's/;//'` - date="$date $time" - echo "" - rlog -r$rev $file | sed -e '/^branches: /d' -e '1,/^date: /d' -e '/^===========/d' -e 's/$/\\/' | awk '{if ((total += length($0) + 1) < 510) print $0}' > $commentfile - echo "==> file $file, rev=$rev, date=$date, author=$author" - rm -f $file - co -r$rev $file >> $logfile 2>&1 - if [ $? != 0 ]; then - echo ERROR - co - exit - fi - echo checked out of RCS - - # add SCCS keywords in place of RCS keywords - sed -f $sedfile $file > $tmpfile - if [ $? != 0 ]; then - echo ERROR - sed - exit - fi - echo performed keyword substitutions - rm -f $file - cp $tmpfile $file - - # check file into SCCS - if [ "$firsttime" = "1" ]; then - firsttime=0 - echo about to do sccs admin - echo sccs admin -n -i$file $file < $commentfile - sccs admin -n -i$file $file < $commentfile >> $logfile 2>&1 - if [ $? != 0 ]; then - echo ERROR - sccs admin - exit - fi - echo initial rev checked into SCCS - else - case $rev in - *.*.*.*) - brev=`echo $rev | sed -e 's/\.[0-9]*$//'` - sccs admin -fb $file 2>>$logfile - echo sccs get -e -p -r$brev $file - sccs get -e -p -r$brev $file >/dev/null 2>>$logfile - ;; - *) - echo sccs get -e -p $file - sccs get -e -p $file >/dev/null 2>> $logfile - ;; - esac - if [ $? != 0 ]; then - echo ERROR - sccs get - exit - fi - sccs delta $file < $commentfile >> $logfile 2>&1 - if [ $? != 0 ]; then - echo ERROR - sccs delta -r$rev $file - exit - fi - echo checked into SCCS - fi - sed -e "s;^d D $rev ../../.. ..:..:.. [^ ][^ ]*;d D $rev $date $author;" SCCS/s.$file > $tmpfile - rm -f SCCS/s.$file - cp $tmpfile SCCS/s.$file - chmod 444 SCCS/s.$file - sccs admin -z $file - if [ $? != 0 ]; then - echo ERROR - sccs admin -z - exit - fi - done - rm -f $file -done - - -############################################################ -# Clean up -# -echo cleaning up... -rm -f $tmpfile $emptyfile $initialfile $sedfile $commentfile -echo =================================================== -echo " Conversion Completed Successfully" -echo =================================================== - -rm -f *,v diff --git a/gnu/usr.bin/cvs/contrib/rcslock.pl b/gnu/usr.bin/cvs/contrib/rcslock.pl deleted file mode 100644 index 01e349f..0000000 --- a/gnu/usr.bin/cvs/contrib/rcslock.pl +++ /dev/null @@ -1,235 +0,0 @@ -#! xPERL_PATHx -# -*-Perl-*- - -# Author: John Rouillard (rouilj@cs.umb.edu) -# Supported: Yeah right. (Well what do you expect for 2 hours work?) -# Blame-to: rouilj@cs.umb.edu -# Complaints to: Anybody except Brian Berliner, he's blameless for -# this script. -# Acknowlegements: The base code for this script has been acquired -# from the log.pl script. - -# rcslock.pl - A program to prevent commits when a file to be ckecked -# in is locked in the repository. - -# There are times when you need exclusive access to a file. This -# often occurs when binaries are checked into the repository, since -# cvs's (actually rcs's) text based merging mechanism won't work. This -# script allows you to use the rcs lock mechanism (rcs -l) to make -# sure that no changes to a repository are able to be committed if -# those changes would result in a locked file being changed. - -# WARNING: -# This script will work only if locking is set to strict. -# - -# Setup: -# Add the following line to the commitinfo file: - -# ALL /local/location/for/script/lockcheck [options] - -# Where ALL is replaced by any suitable regular expression. -# Options are -v for verbose info, or -d for debugging info. -# The %s will provide the repository directory name and the names of -# all changed files. - -# Use: -# When a developer needs exclusive access to a version of a file, s/he -# should use "rcs -l" in the repository tree to lock the version they -# are working on. CVS will automagically release the lock when the -# commit is performed. - -# Method: -# An "rlog -h" is exec'ed to give info on all about to be -# committed files. This (header) information is parsed to determine -# if any locks are outstanding and what versions of the file are -# locked. This filename, version number info is used to index an -# associative array. All of the files to be committed are checked to -# see if any locks are outstanding. If locks are outstanding, the -# version number of the current file (taken from the CVS/Entries -# subdirectory) is used in the key to determine if that version is -# locked. If the file being checked in is locked by the person doing -# the checkin, the commit is allowed, but if the lock is held on that -# version of a file by another person, the commit is not allowed. - -$ext = ",v"; # The extension on your rcs files. - -$\="\n"; # I hate having to put \n's at the end of my print statements -$,=' '; # Spaces should occur between arguments to print when printed - -# turn off setgid -# -$) = $(; - -# -# parse command line arguments -# -require 'getopts.pl'; - -&Getopts("vd"); # verbose or debugging - -# Verbose is useful when debugging -$opt_v = $opt_d if defined $opt_d; - -# $files[0] is really the name of the subdirectory. -# @files = split(/ /,$ARGV[0]); -@files = @ARGV[0..$#ARGV]; -$cvsroot = $ENV{'CVSROOT'}; - -# -# get login name -# -$login = getlogin || (getpwuid($<))[0] || "nobody"; - -# -# save the current directory since we have to return here to parse the -# CVS/Entries file if a lock is found. -# -$pwd = `/bin/pwd`; -chop $pwd; - -print "Starting directory is $pwd" if defined $opt_d ; - -# -# cd to the repository directory and check on the files. -# -print "Checking directory ", $files[0] if defined $opt_v ; - -if ( $files[0] =~ /^\// ) -{ - print "Directory path is $files[0]" if defined $opt_d ; - chdir $files[0] || die "Can't change to repository directory $files[0]" ; -} -else -{ - print "Directory path is $cvsroot/$files[0]" if defined $opt_d ; - chdir ($cvsroot . "/" . $files[0]) || - die "Can't change to repository directory $files[0] in $cvsroot" ; -} - - -# Open the rlog process and apss all of the file names to that one -# process to cut down on exec overhead. This may backfire if there -# are too many files for the system buffer to handle, but if there are -# that many files, chances are that the cvs repository is not set up -# cleanly. - -print "opening rlog -h @files[1..$#files] |" if defined $opt_d; - -open( RLOG, "rlog -h @files[1..$#files] |") || die "Can't run rlog command" ; - -# Create the locks associative array. The elements in the array are -# of two types: -# -# The name of the RCS file with a value of the total number of locks found -# for that file, -# or -# -# The name of the rcs file concatenated with the version number of the lock. -# The value of this element is the name of the locker. - -# The regular expressions used to split the rcs info may have to be changed. -# The current ones work for rcs 5.6. - -$lock = 0; - -while (<RLOG>) -{ - chop; - next if /^$/; # ditch blank lines - - if ( $_ =~ /^RCS file: (.*)$/ ) - { - $curfile = $1; - next; - } - - if ( $_ =~ /^locks: strict$/ ) - { - $lock = 1 ; - next; - } - - if ( $lock ) - { - # access list: is the line immediately following the list of locks. - if ( /^access list:/ ) - { # we are done getting lock info for this file. - $lock = 0; - } - else - { # We are accumulating lock info. - - # increment the lock count - $locks{$curfile}++; - # save the info on the version that is locked. $2 is the - # version number $1 is the name of the locker. - $locks{"$curfile" . "$2"} = $1 - if /[ ]*([a-zA-Z._]*): ([0-9.]*)$/; - - print "lock by $1 found on $curfile version $2" if defined $opt_d; - - } - } -} - -# Lets go back to the starting directory and see if any locked files -# are ones we are interested in. - -chdir $pwd; - -# fo all of the file names (remember $files[0] is the directory name -foreach $i (@files[1..$#files]) -{ - if ( defined $locks{$i . $ext} ) - { # well the file has at least one lock outstanding - - # find the base version number of our file - &parse_cvs_entry($i,*entry); - - # is our version of this file locked? - if ( defined $locks{$i . $ext . $entry{"version"}} ) - { # if so, it is by us? - if ( $login ne ($by = $locks{$i . $ext . $entry{"version"}}) ) - {# crud somebody else has it locked. - $outstanding_lock++ ; - print "$by has file $i locked for version " , $entry{"version"}; - } - else - { # yeah I have it locked. - print "You have a lock on file $i for version " , $entry{"version"} - if defined $opt_v; - } - } - } -} - -exit $outstanding_lock; - - -### End of main program - -sub parse_cvs_entry -{ # a very simple minded hack at parsing an entries file. -local ( $file, *entry ) = @_; -local ( @pp ); - - -open(ENTRIES, "< CVS/Entries") || die "Can't open entries file"; - -while (<ENTRIES>) - { - if ( $_ =~ /^\/$file\// ) - { - @pp = split('/'); - - $entry{"name"} = $pp[1]; - $entry{"version"} = $pp[2]; - $entry{"dates"} = $pp[3]; - $entry{"name"} = $pp[4]; - $entry{"name"} = $pp[5]; - $entry{"sticky"} = $pp[6]; - return; - } - } -} diff --git a/gnu/usr.bin/cvs/contrib/sccs2rcs.csh b/gnu/usr.bin/cvs/contrib/sccs2rcs.csh deleted file mode 100644 index 0f31893..0000000 --- a/gnu/usr.bin/cvs/contrib/sccs2rcs.csh +++ /dev/null @@ -1,277 +0,0 @@ -#! xCSH_PATHx -f -# -# Sccs2rcs is a script to convert an existing SCCS -# history into an RCS history without losing any of -# the information contained therein. -# It has been tested under the following OS's: -# SunOS 3.5, 4.0.3, 4.1 -# Ultrix-32 2.0, 3.1 -# -# Things to note: -# + It will NOT delete or alter your ./SCCS history under any circumstances. -# -# + Run in a directory where ./SCCS exists and where you can -# create ./RCS -# -# + /usr/local/bin is put in front of the default path. -# (SCCS under Ultrix is set-uid sccs, bad bad bad, so -# /usr/local/bin/sccs here fixes that) -# -# + Date, time, author, comments, branches, are all preserved. -# -# + If a command fails somewhere in the middle, it bombs with -# a message -- remove what it's done so far and try again. -# "rm -rf RCS; sccs unedit `sccs tell`; sccs clean" -# There is no recovery and exit is far from graceful. -# If a particular module is hanging you up, consider -# doing it separately; move it from the current area so that -# the next run will have a better chance or working. -# Also (for the brave only) you might consider hacking -# the s-file for simpler problems: I've successfully changed -# the date of a delta to be in sync, then run "sccs admin -z" -# on the thing. -# -# + After everything finishes, ./SCCS will be moved to ./old-SCCS. -# -# This file may be copied, processed, hacked, mutilated, and -# even destroyed as long as you don't tell anyone you wrote it. -# -# Ken Cox -# Viewlogic Systems, Inc. -# kenstir@viewlogic.com -# ...!harvard!cg-atla!viewlog!kenstir -# -# Various hacks made by Brian Berliner before inclusion in CVS contrib area. -# -# $Id: sccs2rcs.csh,v 1.1 1995/07/10 02:26:48 kfogel Exp $ - - -#we'll assume the user set up the path correctly -# for the Pmax, /usr/ucb/sccs is suid sccs, what a pain -# /usr/local/bin/sccs should override /usr/ucb/sccs there -set path = (/usr/local/bin $path) - - -############################################################ -# Error checking -# -if (! -w .) then - echo "Error: ./ not writeable by you." - exit 1 -endif -if (! -d SCCS) then - echo "Error: ./SCCS directory not found." - exit 1 -endif -set edits = (`sccs tell`) -if ($#edits) then - echo "Error: $#edits file(s) out for edit...clean up before converting." - exit 1 -endif -if (-d RCS) then - echo "Warning: RCS directory exists" - if (`ls -a RCS | wc -l` > 2) then - echo "Error: RCS directory not empty - exit 1 - endif -else - mkdir RCS -endif - -sccs clean - -set logfile = /tmp/sccs2rcs_$$_log -rm -f $logfile -set tmpfile = /tmp/sccs2rcs_$$_tmp -rm -f $tmpfile -set emptyfile = /tmp/sccs2rcs_$$_empty -echo -n "" > $emptyfile -set initialfile = /tmp/sccs2rcs_$$_init -echo "Initial revision" > $initialfile -set sedfile = /tmp/sccs2rcs_$$_sed -rm -f $sedfile -set revfile = /tmp/sccs2rcs_$$_rev -rm -f $revfile - -# the quotes surround the dollar signs to fool RCS when I check in this script -set sccs_keywords = (\ - '%W%[ ]*%G%'\ - '%W%[ ]*%E%'\ - '%W%'\ - '%Z%%M%[ ]*%I%[ ]*%G%'\ - '%Z%%M%[ ]*%I%[ ]*%E%'\ - '%M%[ ]*%I%[ ]*%G%'\ - '%M%[ ]*%I%[ ]*%E%'\ - '%M%'\ - '%I%'\ - '%G%'\ - '%E%'\ - '%U%') -set rcs_keywords = (\ - '$'Id'$'\ - '$'Id'$'\ - '$'Id'$'\ - '$'SunId'$'\ - '$'SunId'$'\ - '$'Id'$'\ - '$'Id'$'\ - '$'RCSfile'$'\ - '$'Revision'$'\ - '$'Date'$'\ - '$'Date'$'\ - '') - - -############################################################ -# Get some answers from user -# -echo "" -echo "Do you want to be prompted for a description of each" -echo "file as it is checked in to RCS initially?" -echo -n "(y=prompt for description, n=null description) [y] ?" -set ans = $< -if ((_$ans == _) || (_$ans == _y) || (_$ans == _Y)) then - set nodesc = 0 -else - set nodesc = 1 -endif -echo "" -echo "The default keyword substitutions are as follows and are" -echo "applied in the order specified:" -set i = 1 -while ($i <= $#sccs_keywords) -# echo ' '\"$sccs_keywords[$i]\"' ==> '\"$rcs_keywords[$i]\" - echo " $sccs_keywords[$i] ==> $rcs_keywords[$i]" - @ i = $i + 1 -end -echo "" -echo -n "Do you want to change them [n] ?" -set ans = $< -if ((_$ans != _) && (_$ans != _n) && (_$ans != _N)) then - echo "You can't always get what you want." - echo "Edit this script file and change the variables:" - echo ' $sccs_keywords' - echo ' $rcs_keywords' -else - echo "good idea." -endif - -# create the sed script -set i = 1 -while ($i <= $#sccs_keywords) - echo "s,$sccs_keywords[$i],$rcs_keywords[$i],g" >> $sedfile - @ i = $i + 1 -end - -onintr ERROR - -############################################################ -# Loop over every s-file in SCCS dir -# -foreach sfile (SCCS/s.*) - # get rid of the "s." at the beginning of the name - set file = `echo $sfile:t | sed -e "s/^..//"` - - # work on each rev of that file in ascending order - set firsttime = 1 - sccs prs $file | grep "^D " | awk '{print $2}' | sed -e 's/\./ /g' | sort -n -u +0 +1 +2 +3 +4 +5 +6 +7 +8 | sed -e 's/ /./g' > $revfile - foreach rev (`cat $revfile`) - if ($status != 0) goto ERROR - - # get file into current dir and get stats - set date = `sccs prs -r$rev $file | grep "^D " | awk '{printf("19%s %s", $3, $4); exit}'` - set author = `sccs prs -r$rev $file | grep "^D " | awk '{print $5; exit}'` - echo "" - echo "==> file $file, rev=$rev, date=$date, author=$author" - sccs edit -r$rev $file >>& $logfile - if ($status != 0) goto ERROR - echo checked out of SCCS - - # add RCS keywords in place of SCCS keywords - sed -f $sedfile $file > $tmpfile - if ($status != 0) goto ERROR - echo performed keyword substitutions - cp $tmpfile $file - - # check file into RCS - if ($firsttime) then - set firsttime = 0 - if ($nodesc) then - echo about to do ci - echo ci -f -r$rev -d"$date" -w$author -t$emptyfile $file - ci -f -r$rev -d"$date" -w$author -t$emptyfile $file < $initialfile >>& $logfile - if ($status != 0) goto ERROR - echo initial rev checked into RCS without description - else - echo "" - echo Enter a brief description of the file $file \(end w/ Ctrl-D\): - cat > $tmpfile - ci -f -r$rev -d"$date" -w$author -t$tmpfile $file < $initialfile >>& $logfile - if ($status != 0) goto ERROR - echo initial rev checked into RCS - endif - else - # get RCS lock - set lckrev = `echo $rev | sed -e 's/\.[0-9]*$//'` - if ("$lckrev" =~ [0-9]*.*) then - # need to lock the brach -- it is OK if the lock fails - rcs -l$lckrev $file >>& $logfile - else - # need to lock the trunk -- must succeed - rcs -l $file >>& $logfile - if ($status != 0) goto ERROR - endif - echo got lock - sccs prs -r$rev $file | grep "." > $tmpfile - # it's OK if grep fails here and gives status == 1 - # put the delta message in $tmpfile - ed $tmpfile >>& $logfile <<EOF -/COMMENTS -1,.d -w -q -EOF - ci -f -r$rev -d"$date" -w$author $file < $tmpfile >>& $logfile - if ($status != 0) goto ERROR - echo checked into RCS - endif - sccs unedit $file >>& $logfile - if ($status != 0) goto ERROR - end - rm -f $file -end - - -############################################################ -# Clean up -# -echo cleaning up... -mv SCCS old-SCCS -rm -f $tmpfile $emptyfile $initialfile $sedfile -echo =================================================== -echo " Conversion Completed Successfully" -echo "" -echo " SCCS history now in old-SCCS/" -echo =================================================== -set exitval = 0 -goto cleanup - -ERROR: -foreach f (`sccs tell`) - sccs unedit $f -end -echo "" -echo "" -echo Danger\! Danger\! -echo Some command exited with a non-zero exit status. -echo Log file exists in $logfile. -echo "" -echo Incomplete history in ./RCS -- remove it -echo Original unchanged history in ./SCCS -set exitval = 1 - -cleanup: -# leave log file -rm -f $tmpfile $emptyfile $initialfile $sedfile $revfile - -exit $exitval diff --git a/gnu/usr.bin/cvs/cvs/ChangeLog b/gnu/usr.bin/cvs/cvs/ChangeLog deleted file mode 100644 index 36c3906..0000000 --- a/gnu/usr.bin/cvs/cvs/ChangeLog +++ /dev/null @@ -1,3205 +0,0 @@ -Sat Dec 9 22:01:41 1995 Dan O'Connor <doconnor@tii.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * server.c (check_repository_password): when checking for false - prefix-matches, look for ':', not '@'. Duh. - -Thu Dec 7 18:44:51 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <glass@NetBSD.ORG> - - * 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 <kfogel@floss.cyclic.com> - - * client.c, login.c: memset() instead of bzero(). - -Thu Dec 7 00:08:53 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * server.c (authenticate_connection): expanded comment. - -Tue Dec 5 23:37:39 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <sys/socket.h>, <netinet/in.h>, <netdb.h>, 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 <peterc@bookworm.sw.oz.au> - (patch applied by Karl Fogel <kfogel@cyclic.com>) - - * 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 <kingdon@harvey.cyclic.com> - - * Version 1.6.3. - -Mon Dec 4 16:28:25 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * 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 <kingdon@harvey.cyclic.com> - - * Version 1.6.2. - -Sun Dec 3 20:02:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <nk@col.sw-ley.de> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * main.c: Prototype connect_to_pserver(), and enter it in cmds[]. - (main): test some extremely primitive authentication. - - * login.c: Include <sys/socket.h> - (connect_to_pserver): new func. - (init_sockaddr): new func. - -Mon Nov 20 14:07:41 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <kingdon@harvey.cyclic.com> - - * 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 <peter@haywire.DIALix.COM> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <woods@most.weird.com> - - * 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 <kingdon@harvey.cyclic.com> - - * 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 <woods@most.weird.com> - - * sanity.sh: test 63 doesn't work and probably can't - -Tue Nov 14 12:22:00 1995 Greg A. Woods <woods@most.weird.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * cvs.h: conform to 80 column standard (yes, I'm a pedant). - -Sat Nov 11 13:45:13 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <nk@col.sw-ley.de> - - * 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 <woods@most.weird.com> - - * 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 <jtc@lestat.cygnus.com> - - * 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 <kingdon@harvey.cyclic.com> - - * vers_ts.c: Remove ctime define. It is just asking for trouble. - -Mon Nov 6 11:58:26 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * entries.c (fgetentent): don't prototype ctime here; we include - cvs.h, which includes system.h, which includes <time.h> - unconditionally (either as <time.h> or <sys/time.h>). Anyway, IBM - C/C++ chokes on mid-function, or even mid-file, prototypes. Sigh. - -Thu Nov 2 21:51:04 1995 Dan Wilder <dan@gasboy.com> - - * rtag.c (rtag): Fix typo ("-T" -> "-F"). - -Tue Oct 31 19:09:11 1995 Dan Wilder <dan@gasboy.com> - - * 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 <nk@col.sw-ley.de> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <stdlib.h>). - 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 <jtc@slave.cygnus.com> - - * 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 <kingdon@harvey.cyclic.com> - - * 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 <ajlill@ajlc.waterloo.on.ca> - - * 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 <nk@col.sw-ley.de> - - * 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 <nk@col.sw-ley.de> - - * 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 <kingdon@harvey.cyclic.com> - - * logmsg.c (do_editor): Check for errors from stdio calls. - -Mon Oct 23 12:37:06 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <nk@col.sw-ley.de> - - * 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 <jtc@slave.cygnus.com> - - * 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 <kingdon@harvey.cyclic.com> - - * sanity.sh: Add test 87a, to test for bug fixed by garyo in - change below. - -Fri Oct 20 10:59:58 1995 Gary Oberbrunner <garyo@darkstar.avs.com> - - * 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 <nk@col.sw-ley.de> - - * 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 <kingdon@harvey.cyclic.com> - - * expand_path.c (expand_variable): Fix typo ('*'->'('). - -Thu Oct 19 14:58:40 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <kingdon@harvey.cyclic.com> - - * root.c (Create_Root): If noexec, don't create CVS/Root. - -Wed Oct 18 11:19:40 1995 J.T. Conklin <jtc@slave.cygnus.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <wjones@tc.fluke.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <vdemarco@bou.shl.com> - - * 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 <garyo@avs.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * main.c (main): begin to handle "pserver"; support not complete - yet, however. - -Thu Oct 12 02:52:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * expand_path.c: Don't #include <pwd.h>, since cvs.h already does, - and not all systems' <pwd.h>s are protected from multiple inclusion. - * login.c: Likewise. - -Wed Oct 11 15:23:24 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * login.c (login): handle everything correctly now. - -Wed Oct 11 12:02:48 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * rcs.c (RCS_gettag): support RCS keyword Name - -Tue Oct 10 19:11:16 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <kfogel@totoro.cyclic.com> - - * 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 <tholo@sigmasoft.com> - - * 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 <kingdon@harvey.cyclic.com> - - * 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 <peter@haywire.DIALix.COM> - - * 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 <nk@col.sw-ley.de> - - * 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 <nk@col.sw-ley.de> - - * 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 <sjbailey@sand.npl.washington.edu> - - * 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 <sdc@TracerTech.COM> - - * 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 <kingdon@harvey.cyclic.com> - - * version.c: Version 1.6.1. - -Fri Oct 6 21:31:28 1995 Jeff Johnson <jbj@brewster.jbj.org> - - * 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 <mhw@minster.york.ac.uk> - - * 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 <vdemarco@bou.shl.com> - - * 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 <kingdon@harvey.cyclic.com> - - * 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 <kfogel@totoro.cyclic.com> - - * sanity.sh: unset CVSREAD, since it causes the script to bomb. - -Thu Oct 5 18:29:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <nk@col.sw-ley.de> - - * commit.c (checkaddfile): New argument options; pass it to RCS. - (commit_fileproc): Pass it. - -Tue Oct 3 09:26:00 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: upped to 1.6. - -Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com> - - * server.c: if HAVE_SYS_BSDTYPES_H, include <sys/bsdtypes.h>. - -Mon Oct 2 10:34:53 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: Upped version to 1.5.95. - -Mon Oct 2 15:16:47 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * tag.c, rtag.c: pass "mov" instead of "add" if tag will be moved - (i.e. invoked with -F) - -Sun Oct 1 18:36:34 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: upped to 1.5.94. - - * server.c: reverted earlier ISC change (of Sep. 28). - - * version.c: upped to 1.5.93, for Peter Wemm's new SVR4 patch. - -Sun Oct 1 14:51:59 1995 Harlan Stenn <Harlan.Stenn@pfcs.com> - - * main.c: don't #include <pwd.h>; cvs.h does that already. - -Fri Sep 29 15:21:35 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * version.c: upped to 1.5.91 for another pre-1.6 release. - -Fri Sep 29 14:41:14 1995 <bmeier@rzu.unizh.ch> - - * root.c: start rcsid[] with "CVSid". - -Fri Sep 29 13:22:44 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * diff.c (diff): Doc fix. - -Fri Sep 29 14:32:36 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * 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 <kfogel@floss.cyclic.com> - - * cvs.h (USE): if __GNUC__ != 2, expand to a dummy var instead of - nothing. - -Thu Sep 28 13:37:05 1995 Larry Jones <larry.jones@sdrc.com> - - * server.c: ifdef ISC, include <sys/bsdtypes.h>. - -Fri Sep 29 07:54:22 1995 Mike Sutton <mws115@llcoolj.dayton.saic.com> - - * filesubr.c (last_component): Don't use ANSI style declaration. - -Wed Sep 27 15:24:00 1995 Del <del@matra.com.au> - - * tag.c, rtag.c: Pass a few extra options to the script - named in taginfo (del/add, and revision number). - - * tag.c: Support a -r option (at long last). Also needs - a -f option to tag the head if there is no matching -r tag. - -Tue Sep 26 11:41:08 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * version.c: Upped version to 1.5.89 for test release preceding - 1.6. - -Wed Sep 20 15:32:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * ignore.c (ign_add_file): Check for errors from fopen and fclose. - -Tue Sep 19 18:02:16 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * Makefile.in (DISTFILES): Remove sanity.el from this list; the - file has been deleted. - -Thu Sep 14 14:17:52 1995 Peter Wemm <peter@haywire.dialix.com> - - * import.c: Recover from being unable to open the user file. - - * update.c (join_file): Print a message in the case where the file - was added. - - * mkmodules.c: Deal with .db as well as .pag/.dir (for use with - BSD 4.4 and real dbm support). - -Mon Sep 11 15:44:13 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * release.c (release): Revise comment regarding why and how we - skip argv[0]. - -Mon Sep 11 10:03:59 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * release.c (release): use return value of pclose to determine - success of update. - -Mon Sep 11 09:56:33 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * release.c (release_delete): Fix comment. - -Sun Sep 10 18:48:35 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * release.c (release): made work with client/server. - Don't ask if <arg> is mentioned in `modules'. - -Fri Sep 8 13:25:55 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: When committing a removal, send stdout to LOGFILE; - this is no longer a silent operation. - - * sanity.sh: Remove OUTPUT variable; it is unused. - - * client.c: Add comment regarding deleting temp file. - * main.c: Add comment regarding getopt REQUIRE_ORDER. - -Thu Sep 7 20:24:46 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * main.c (main): use getopt_long(), accept "--help" and - "--version". - Don't assume EOF is -1. - -Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com> - - * cvs.h (unlink_file_dir): Add prototype for this. - -Thu Sep 7 14:38:06 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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. - -Mon Sep 4 23:30:41 1995 Magnus Hyllander <mhy@os.se> - - * checkout.c: cvs export now takes -k option and does not default - to -kv. - * checkout.c, cvs.h, modules.c: Modules file now takes -e option - for cvs export. - -Mon Sep 4 23:30:41 1995 Kirby Koster <koster@sctc.com> - - * commit.c: When committing a removal, print a message saying what - we are doing. - -Wed Aug 2 10:06:51 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * server.c: fix compiler warnings (on NeXT) (declare functions as - static inline instead of just static) functions: get_buffer_date, - buf_append_char, and buf_append_data - -Mon Sep 4 22:31:28 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (update_entries), import.c (expand_at_signs): Check for - errors from fread and putc. - -Fri Sep 1 00:03:17 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * sanity.sh: Fix TODO item pathname. - - * sanity.el: Removed. It was out of date, didn't do much, and I - doubt anyone was using it. - - * no_diff.c (No_Difference): Don't change the modes of the files. - -Thu Aug 31 13:14:34 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * version.c: Change version to 1.5.1. - - * client.c (start_rsh_server): Don't pass -d to "cvs server" - invocation via rsh (restore change which was lost when NT stuff - was merged in). - * sanity.sh: Add TODO item suggesting test for bug which this fixes. - -Wed Aug 30 12:36:37 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * sanity.sh (basic1): Make sure first-dir is deleted before - running this set of tests. - - * subr.c: Extract file twiddling functions to a different file, - because we want to use different versions of many of these - routines under Windows NT. - (copy_file, isdir, islink, isfile, isreadable, iswritable, - open_file, make_directory, make_directories, xchmod, - rename_file, link_file, unlink_file, xcmp, tmpnam, - unlink_file_dir, deep_remove_dir): Moved to... - * filesubr.c: ...this file, which is new. - * Makefile.in (SOURCES): Mention filesubr.c. - (COMMON_OBJECTS): Mention filesubr.o. - - * subr.c: Extract process execution guts to a different file, - because we want to replace these routines entirely under - Windows NT. - (VA_START, va_alist, va_dcl): Move this stuff... - (run_add_arg, run_init_prog): and these declarations... - (run_prog, run_argv, run_argc, run_argc_allocated): and these - variables... - (run_setup, run_arg, run_args, run_add_arg, run_init_prog, - run_exec, run_print, Popen): and these functions... - * run.c: To this file, which is new. - * Makefile.in (SOURCES): Mention run.c. - (COMMON_OBJECTS): Mention run.o. - - * status.c (status): Call ign_setup, if client_active. Otherwise, - we don't end up ignoring CVS directories and such. - - * server.c (mkdir_p, dirswitch): Use CVS_MKDIR instead of mkdir. - - * repos.c (Name_Repository): Use the isabsolute function instead of - checking the first character of the path. - * root.c (Name_Root): Same. - - * release.c (release): Use fncmp instead of strcmp to compare - filenames. - - * rcs.c (RCS_parse, RCS_parsercsfile) [LINES_CRLF_TERMINATED]: - Abort, because we have strong reason to believe this code is - wrong. - - * patch.c (patch): Register signal handlers iff the signal name is - #defined. - - * no_diff.c (No_Difference): Don't try to include server_active in - trace message unless SERVER_SUPPORT is #defined. - - * modules.c (do_module): Use CVS_MKDIR instead of mkdir. - - * mkmodules.c (main): Call last_component instead of writing it out. - - * main.c (main): Call last_component instead of writing it out. - Break up the long copyright string into several strings; Microsoft - Visual C++ can't handle a line that long. Feh. - Use fncmp instead of strcmp to compare filenames. - Register signal handlers iff the signal name is #defined. - - * lock.c (readers_exist): Don't check return value of closedir. - Most of the rest of the code doesn't, and some systems don't - provide a return value anyway. - (set_lock): Use CVS_MKDIR instead of mkdir. - - * import.c (import): Use the isabsolute function instead of - checking the first character of the path. - Try to delete the temporary file again after we close it, so it'll - get deleted on systems that don't let you delete files that are - open. - (add_rev): Instead of making a hard link to the working file and - checking in the revision with ci -r, use ci -u and restore the - permission bits. - (comtable): Include lines from SYSTEM_COMMENT_TABLE, if it is - #defined. - (add_rcs_file) [LINES_CRLF_TERMINATED]: Abort, because we have - strong reason to believe this code is wrong. - (import_descend_dir): Use CVS_MKDIR instead of mkdir. - - * history.c (read_hrecs): Open the file with OPEN_BINARY. - - * find_names.c (add_entries_proc, fsortcmp): Add prototypes. - * entries.c (write_ent_proc): Add prototype. - * hash.c (walklist): Add prototype for PROC argument. - (sortlist): Add prototype for COMP argument. - (printnode): Add a prototype, and make it static. - - * cvs.h (wrap_add_file, wrap_add): Add extern decls for these; - they're used in import.c and update.c. - * wrapper.c (wrap_add_file, wrap_add): Remove them from here. - - * cvs.h (RUN_NORMAL, RUN_COMBINED, RUN_REALLY, RUN_STDOUT_APPEND, - RUN_STDERR_APPEND, RUN_SIGNIGNORE, RUN_TTY, run_arg, run_print, - run_setup, run_args, run_exec, Popen, piped_child, close_on_exec, - filter_stream_through_program, waitpid): Move all these - declarations and definitions to the same section. - - * cvs.h (error_set_cleanup): Fix prototype. - - * cvs.h (isabsolute, last_component): New extern decls. - - * cvs.h (link_file): Function is deleted; remove extern decl. - - * cvs.h (DEATH_STATE, DEATH_SUPPORT): Move #definitions of these - above the point where we #include rcs.h, since rcs.h tests them - (or DEATH_SUPPORT, at least). - - * cvs.h (DEVNULL): #define this iff it isn't already #defined. - config.h may want to override it. - - * cvs.h (SERVER_SUPPORT, CLIENT_SUPPORT): Don't #define these - here; let config.h do that. On some systems, we don't have any - server support. - - * cvs.h: Don't #include <io.h> or <direct.h>; we take care of - those in lib/system.h. - - * commit.c (commit): Open logfile with the OPEN_BINARY flag. - (precommit_proc): Use the isabsolute function, instead of - comparing the first character with /. - (remove_file, checkaddfile): Use CVS_MKDIR instead of mkdir. - - * client.c (send_repository): Use larger line buffers. - - * client.c [LINES_CRLF_TERMINATED] (update_entries): If we've just - received a gzipped file, copy it over, converting LF to CRLF, - instead of just renaming it into place. - [LINES_CRLF_TERMINATED] (send_modified): Convert file to LF format - before sending with gzip. - (send_modified): Don't be disturbed if we get fewer than - sb.st_size characters when we read. The read function may be - collapsing CRLF to LF for us. - - * client.c: Add forward declarations for all the cvs command - functions we call. - - * client.c: Add forward static declarations for all the - handle_mumble functions. - - On some systems, RSH converts LF to CRLF; this screws us up. - * client.c (rsh_pid): Declare this iff RSH_NOT_TRANSPARENT is not - #defined. - (get_responses_and_close): Use SHUTDOWN_SERVER if it is #defined. - Only wait for rsh process to exit if RSH_NOT_TRANSPARENT is not - #defined. - (start_rsh_server): Declare and define only if - RSH_NOT_TRANSPARENT is not #defined. Use piped_child, instead of - writing all that out. - (start_server): Only try to call start_rsh_server if - RSH_NOT_TRANSPARENT is not #defined. Use START_SERVER if it is - #defined. Convert file descriptors to stdio file pointers using - the FOPEN_BINARY_WRITE and FOPEN_BINARY_READ strings. - - * client.h (rsh_pid): Don't declare this; it's never used elsewhere. - (supported_request): Add external declaration for this; - it's used in checkout.c. - - Move process-running functions to run.c; we need to totally - replace these on other systems, like Windows NT. - * client.c (close_on_exec, filter_stream_through_program): Moved - to run.c. - * run.c (close_on_exec, filter_stream_through_program): Here they - are. - - * add.c (add_directory): Use CVS_MKDIR instead of straight mkdir. - * checkout.c (checkout, build_dirs_and_chdir): Same. - (checkout_proc): Use fncmp instead of strcmp. - * client.c (call_in_directory): Use CVS_MKDIR instead of straight - mkdir. - - * client.c (handle_checksum): Cast return value of strtol. - -Wed Aug 30 10:35:46 1995 Stefan Monnier <stefan.monnier@epfl.ch> - - * main.c (main): Allow -d to override CVSROOT_ENV. - -Thu Aug 24 18:57:49 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h, rcscmds.c (RCS_unlock, RCS_deltag, RCS_lock): Add extra - parameter for whether to direct stderr to DEVNULL. - * checkin.c, tag.c, rtag.c, import.c, commit.c: Pass extra - argument. 1 if stderr had been directed to DEVNULL before - rcscmds.c was in use, 0 if it was RUN_TTY. - - * cvs.h: Add comment regarding attic. - -Tue Aug 22 10:09:29 1995 Alexander Dupuy <dupuy@smarts.com> - - * rcs.c (whitespace): Cast to unsigned char in case char is signed - and value is negative. - -Tue Aug 22 10:09:29 1995 Kirby Koster <koster@sctc.com> - and Jim Kingdon <kingdon@harvey.cyclic.com> - - * update.c (join_file): If vers->vn_user is NULL, just return. - -Tue Aug 22 10:09:29 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c, client.c: Add comments about modes and umasks. - -Mon Aug 21 12:54:14 1995 Rick Sladkey <jrs@world.std.com> - - * update.c (update_filesdone_proc): If pipeout, don't try to - create CVS/Root. - -Mon Aug 21 12:54:14 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * client.c (start_rsh_server): Don't pass -d to "cvs server" - invocation via rsh. - - * server.c (serve_root): Report errors via pending_error_text. - (serve_valid_requests): Check for pending errors. - -Sun Aug 20 00:59:46 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * options.h.in: Document usage of DIFF in update.c - * update.c: Use DIFF -c, not DIFF -u. The small improvement in - diff size is not worth the hassle in terms of everyone having to - make sure that DIFF is GNU diff (IMHO). - -Sat Aug 19 22:05:46 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * recurse.c (start_recursion): Doc fix. - - * server.c (do_cvs_command): Clear error_use_protocol in the - child. - (server): Set error_use_protocol. - -Sun Aug 13 15:33:37 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * server.c (do_cvs_command): Don't select on exceptions. - -Fri Aug 4 00:13:47 1995 Jim Meyering (meyering@comco.com) - - * Makefile.in (LDFLAGS): Set to @LDFLAGS@. - (options.h): Depend on ../config.status and options.h.in. - Add rule to build it from dependents. - - * add.c: Include save-cwd.h. - (add_directory): Use save_cwd and restore_cwd instead of - explicit getwd then chdir. - * import.c (import_descend_dir): Likewise. - * modules.c (do_module): Likewise. - - * recurse.c (save_cwd, restore_cwd, free_cwd): Remove functions. - New versions have been broken out into save-cwd.c. - (do_dir_proc): Adapt to handle status code returned by new versions - of save_cwd and restore_cwd -- and one fewer argument to restore_cwd. - (unroll_files_proc): Likewise. - - * wrapper.c (wrap_name_has): Add default: abort () to switch - statement to avoid warning from gcc -Wall. - (wrap_matching_entry): Remove dcl of unused TEMP. - (wrap_tocvs_process_file): Remove dcl of unused ERR. - (wrap_fromcvs_process_file): Likewise. - - * cvs.h: Remove prototype for error. Instead, include error.h. - Also, remove trailing white space. - -Thu Aug 3 10:12:20 1995 Jim Meyering (meyering@comco.com) - - * import.c (import_descend_dir): Don't print probably-bogus CWD - in error messages saying `cannot get working directory'. - -Sun Jul 30 20:52:04 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * parseinfo.c (Parse_Info): Revise comments and indentation. - -Sun Jul 30 15:30:16 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * history.c: put ifdef SERVER_SUPPORT around tracing code incase - the client/server code is not compiled into the program. - -Sat Jul 29 16:59:49 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * subr.c (deep_remove_dir): Use struct dirent, not struct direct. - -Sat Jul 29 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * add.c: Check wrap_name_has. - - * diff.c, checkin.c, import.c: have code call unlink_file_dir in - the appropriate places instead of just calling unlink_file. - - * checkin.c: Remove one unlink call. - - * import.c (comtable): Add .m .psw .pswm. - - * import.c (add_rcs_file): Remove tocvsPath before returning. - - * subr.c (unlink_file_dir): Add new function. unlinks the file if - it is a file. or will do a recursive delete if the path is - actually a directory. - (deep_remove_dir): New function, helps unlink_file_dir. - - * mkmodules.c: Added CVSROOTADM_WRAPPER (cvswrappers file) to the - checkout file list. - -Fri Jul 28 16:27:56 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (safe_location): Use PATH_MAX not MAXPATHLEN. - -Fri Jul 28 19:37:03 1995 Paul Eggert <eggert@twinsun.com> - - * log.c (cvslog, log_fileproc): Pass all options (except -l) - to rlog as-is, so that users can put spaces in options, - can specify multiple -d options, etc. - (ac, av): New variables. - (log_option_with_arg, options): Remove. - - (log_fileproc): Don't prepend `/' to file name if update_dir is empty. - -Tue Jul 25 00:52:26 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * checkout.c (safe_location): Don't use PROTO in function definition. - -Mon Jul 24 18:32:06 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * checkout.c (safe_location): fix a compiler warning. (Declare - safe_location). Changed code in safe_location to call getwd - instead of getcwd. getwd is declared in the ../lib directory and - used exclusively thoughout the code. (this helps portability on - non POSIX systems). - - * wrapper.c: updated Andrew Athan's email address. - - * main.c: fix an ifdef so the code will compile. syntax error in - the ifdef for CVS_NOADMIN. - -Mon Jul 24 13:25:00 1995 Del <del@babel.dialix.oz.au> - - * checkout.c: New procedure safe_location. - Ensures that you don't check out into the repository - itself. - - * tag.c, rtag.c, cvs.h, mkmodules.c: Added a "taginfo" file in - CVSROOT to perform pre-tag checks. - - * main.c, options.h.in: Added a compile time option to - disable the admin command. - -Fri Jul 21 17:07:42 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * update.c, status.c, patch.c, checkout.c, import.c, release.c, - rtag.c, tag.c: Now -q and -Q options just print an error message - telling you to use global -q and -Q options. The non-global - options were a mess because some commands accepted them and some - did not, and they were redundant with -q and -Q global options. - - * rcs.c, cvs.h, commit.c, log.c, find_names.c: Remove CVS.dea - stuff. It is slower than the alternatives and I don't think - anyone ever actually used it. - -Fri Jul 21 10:35:10 1995 Vince DeMarco <vdemarco@bou.shl.com> - - * Makefile.in (SOURCES, OBJECTS): Add wrapper.c, wrapper.o. - * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c, - remove.c, status.c: Call wrap_setup at start of commands. - * add.c (add): Check for wrapper, as well as directory, in repository. - * checkin.c: Add tocvsPath variable and associated handling. - * cvs.h: Add wrapper declarations. - * diff.c: Add tocvsPath variable and associated handling. - * import.c: Add -W option, CVSDOTWRAPPER handling. - (import_descend): check wrap_name_has. - (update_rcs_file, add_rev, add_rcs_file): add tocvsPath - variable and associated handling. - * no_diff.c: Add tocvsPath variable and associated handling. - * recurse.c (start_recursion): Check wrap_name_has. - * update.c: Copy, don't merge, copy-by-merge files. Attempt to - use -j on a copy-by-merge file generates a warning and no further - action. - * update.c: Add CVSDOTWRAPPER handling. - * wrapper.c: Added. - -Fri Jul 21 00:20:52 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * client.c: Revert David Lamkin patch, except for the bits about - removing temp_filename and the .rej file. - * sanity.sh (errmsg1): Test for the underlying bug which Lamkin - kludged around. - * client.c (call_in_directory): Set short_pathname to include the - filename, not just the directory. Improve comments regarding what - is passed to FUNC. - -Thu Jul 20 17:51:54 1995 David Lamkin <drl@net-tel.co.uk> - - * client.c (short_pathname): Fixes the fetching of the whole file - after a patch to bring it up to date has failed: - - failed_patches[] now holds short path to file that failed - - patch temp files are unlinked where the patch is done - -Thu Jul 20 12:37:10 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * cvs.h: Declare error_set_cleanup - * main.c: Call it. - (error_cleanup): New function. - -Thu Jul 20 12:17:16 1995 Mark H. Wilkinson <mhw@minster.york.ac.uk> - - * add.c, admin.c, checkin.c, checkout.c, classify.c, client.c, - client.h, commit.c, create_adm.c, cvs.h, diff.c, entries.c, - history.c, import.c, log.c, main.c, modules.c, no_diff.c, patch.c, - release.c, remove.c, repos.c, rtag.c, server.c, server.h, - status.c, subr.c, tag.c, update.c, vers_ts.c, version.c: Put - client code inside #ifdef CLIENT_SUPPORT, server code inside - #ifdef SERVER_SUPPORT. When reporting version, report whether - client and/or server are compiled in. - -Wed Jul 19 18:00:00 1995 Jim Blandy <jimb@cyclic.com> - - * subr.c (copy_file): Declare local var n to be an int, - not a size_t. size_t is unsigned, and the return values - of read and write are definitely not unsigned. - - * cvs.h [HAVE_IO_H]: #include <io.h>. - [HAVE_DIRECT_H]: #include <direct.h>. - -Fri Jul 14 22:28:46 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * server.c (dirswitch, serve_static_directory, serve_sticky, - serve_lost, server_write_entries, serve_checkin_prog, - serve_update_prog): Include more information in error messages. - (Thanks, DJM.) - - * cvsbug.sh: Use /usr/sbin/sendmail, unless it doesn't - exist, in which case use /usr/lib/sendmail. (Thanks, DJM.) - - * server.c (server, server_cleanup): Use "/tmp" instead of - "/usr/tmp" when the TMPDIR environment variable isn't set. This - is what the rest of the code uses. - -Thu Jul 13 11:03:17 1995 Jim Meyering (meyering@comco.com) - - * recurse.c (free_cwd): New function. - (save_cwd, restore_cwd): Use it instead of simply freeing any - string. The function also closes any open file descriptor. - - * import.c (comtable): Now static. - (comtable): Put braces around each element of initializer. - - * cvs.h: Add prototype for xgetwd. - * recurse.c (save_cwd, restore_cwd): New functions to encapsulate - run-time solution to secure-SunOS vs. fchown problem. - (do_dir_proc, unroll_files_proc): Use new functions instead of - open-coded fchdir/chdir calls with cpp directives. - - * sanity.sh: Change out of TESTDIR before removing it. - Some versions of rm fail when asked to delete the current directory. - -Wed Jul 12 22:35:04 1995 Jim Meyering (meyering@comco.com) - - * client.c (get_short_pathname): Add const qualifier to parameter dcl. - (copy_a_file): Remove set-but-not-used variable, LEN. - (handle_clear_static_directory): Likewise: SHORT_PATHNAME. - (set_sticky): Likewise: LEN. - (handle_set_sticky): Likewise: SHORT_PATHNAME. - (handle_clear_sticky): Likewise: SHORT_PATHNAME. - (start_rsh_server): Convert perl-style `cond || stmt' to more - conventional C-style `if (cond) stmt.' Sheesh. - Remove dcl of unused file-static, SEND_CONTENTS. - - * history.c: Remove dcls of set-but-not-used file-statics, - HISTSIZE, HISTDATA. - (read_hrecs): Don't set them. - - * import.c (add_rev): Remove dcl of set-but-not-used local, RETCODE. - - * repos.c (Name_Repository): Remove dcl of set-but-not-used local, - HAS_CVSADM. - - * cvsrc.c (read_cvsrc): Parenthesize assignment used as truth value. - -Tue Jul 11 16:49:41 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * hash.h (struct entnode, Entnode): moved from here... - * cvs.h: to here. - -Wed Jul 12 19:45:24 1995 Dominik Westner (dominik@gowest.ppp.informatik.uni-muenchen.de) - - * client.c (server_user): new var. - (parse_cvsroot): set above if repo is "user@host:/dir". - (start_rsh_server): if server_user set, then use it. - -Wed Jul 12 10:53:36 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * sanity.sh: remove the TESTDIR after done. - - * cvsbug.sh (GNATS_ADDR): now bug-cvs@prep.ai.mit.edu again. - -Tue Jul 11 15:53:08 1995 Greg A. Woods <woods@most.weird.com> - - * options.h.in: depend on configure for grep and diff, now that - changes to configure.in are applied. - -Tue Jul 11 14:32:14 1995 Michael Shields <shields@tembel.org> - - * Makefile.in (LDFLAGS): Pick up from configure. - -Tue Jul 11 14:20:00 1995 Loren James Rittle <rittle@supra.comm.mot.com> - - * import.c (add_rev), commit.c (remove_file, ci_new_rev), - checkin.c (Checkin), subr.c (make_message_rcslegal), cvs.h: - Always perform sanity check and fix-up on messages to be passed - directly to RCS via the '-m' switch. RCS 5.7 requires that a - non-total-whitespace, non-null message be provided or it will - abort with an error. CVS is not setup to handle any returned - error from 'ci' gracefully and, thus, the repository entered a - trashed state. - - * sanity.sh: Add regression tests for new code and interactions - with RCS 5.7. - -Sun Jul 9 19:03:00 1995 Greg A. Woods <woods@most.weird.com> - - * .cvsignore: added new backup file - - * options.h.in: our new configure.in finds the right diff and - grep paths now.... - - * subr.c: quote the string in run_print() for visibility - - indent a comment - - Jun Hamano's xchmod() patch to prevent writable files - (from previous local changes) - - * logmsg.c: fix a NULL pointer de-reference - - clean up some string handling code... - (from previous local changes) - - * parseinfo.c: add hack to expand $CVSROOT in an *info file. - - document "ALL" and "DEFAULT" in opening comment for Parse_Info() - - fix the code to match the comments w.r.t. callbacks for "ALL" - - add a line of trace output... - (from previous local changes) - - * mkmodules.c: add support for comments in CVSROOT/checkoutlist - - add CVSroot used by something other .o, ala main.c - (from previous local changes) - - * main.c, cvs.h: add support for $VISUAL as log msg editor - (from previous local changes) - - * status.c: add support for -q and -Q (from previous local changes) - - -Sun Jul 9 18:44:32 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * log.c: trivial change to test ChangeLog stuff. - -Sat Jul 8 20:33:57 1995 Paul Eggert <eggert@twinsun.com> - - * history.c: (history_write): Don't assume that fopen(..., "a") - lets one interleave writes to the history file from different processes - without interlocking. Use open's O_APPEND option instead. - Throw in an lseek to lessen the race bugs on non-Posix hosts. - * cvs.h, subr.c (Fopen): Remove. - - * log.c (log_fileproc): Pass working file name to rlog, so that - the name is reported correctly. - -Fri Jul 7 18:29:37 1995 Michael Hohmuth <hohmuth@inf.tu-dresden.de> - - * client.c, client.h (client_import_setup): New function. - (client_import_done, client_process_import_file): Add comments - regarding now-redundant code. - * import.c (import): Call client_import_setup. - -Tue Jul 4 09:21:26 1995 Bernd Leibing <bernd.leibing@rz.uni-ulm.de> - - * rcs.c (RCS_parsercsfile_i): Rename error to l_error; SunOS4 /bin/cc - doesn't like a label and function with the same name. - -Sun Jul 2 12:51:33 1995 Fred Appelman <Fred.Appelman@cv.ruu.nl> - - * logmsg.c: Rename strlist to str_list to avoid conflict with - Unixware 2.01. - -Thu Jun 29 17:37:22 1995 Paul Eggert <eggert@twinsun.com> - - * rcs.c (RCS_check_kflag): Allow RCS 5.7's new -kb option. - -Wed Jun 28 09:53:14 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (HEADERS): Remove options.h.in. - (DISTFILES): Add options.h.in. - Depend on options.h in addition to HEADERS. - -Tue Jun 27 22:37:28 1995 Vince Demarco <vdemarco@bou.shl.com> - - * subr.c: Don't try to do fancy waitstatus stuff for NeXT, - lib/wait.h is sufficient. - -Mon Jun 26 15:17:45 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (DISTFILES): Remove RCS-patches and convert.sh. - -Fri Jun 23 13:38:28 1995 J.T. Conklin (jtc@rtl.cygnus.com) - - * server.c (dirswitch, serve_co): Use CVSADM macro instead of - literal "CVS". - -Fri Jun 23 00:00:51 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * README-rm-add: Do not talk about patching RCS, that only - confuses people. - * RCS-patches, convert.sh: Removed (likewise). - -Thu Jun 22 10:41:41 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * subr.c: Change -1 to (size_t)-1 when comparing against a size_t. - -Wed Jun 21 16:51:54 1995 nk@ipgate.col.sw-ley.de (Norbert Kiesel) - - * create_adm.c, entries.c, modules.c: Avoid coredumps if - timestamps, tags, etc., are NULL. - -Tue Jun 20 15:52:53 1995 Jim Meyering (meyering@comco.com) - - * checkout.c (checkout): Remove dcl of unused variable. - * client.c (call_in_directory, handle_clear_static_directory, - handle_set_sticky, handle_clear_sticky, send_a_repository, - send_modified, send_dirent_proc): Remove dcls of unused variables. - * server.c (receive_file, serve_modified, server_cleanup): - Remove dcls of unused variables. - * subr.c (copy_file): Remove dcl of unused variable. - * vers_ts.c (time_stamp_server): Remove dcl of unused variable. - -Mon Jun 19 13:49:35 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * sanity.sh: Fix commencement message --- the test suite says - "Ok." when it's done. - -Fri Jun 16 11:23:44 1995 Jim Meyering (meyering@comco.com) - - * entries.c (fgetentent): Parenthesize assignment in if-conditional. - -Thu Jun 15 17:33:28 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * server.c (get_buffer_data, buf_append_char, buf_append_data): - Don't conditionalize use of "inline". Autoconf takes care of - defining it away on systems that don't grok it. - -Thu Jun 15 13:43:38 1995 Jim Kingdon (kingdon@cyclic.com) - - * options.h.in (DIFF): Default to "diff" not "diff -a" since diff - might not support the -a option. - -Wed Jun 14 11:29:42 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * import.c (import_descend): Initialize dirlist to NULL. - - * subr.c (copy_file): Fix infinite loop. - - * server.c (serve_directory): fix a memory leak. - - * checkout.c, commit.c, diff.c, history.c, import.c, log.c, - patch.c, release.c, remove.c, rtag.c, status.c, tag.c, update.c: - Use send_arg() to send command line arguments to server. - - * commit.c (fsortcmp), find_names (fsortcmp), hash.c (hashp, - findnode), hash.h (findnode), rcs.c (RCS_addnode, - RCS_check_kflag, RCS_check_tag, RCS_isdead, RCS_parse, - RCS_parsercsfile_i), rcs.h (RCS_addnode, RCS_check_kflag, - RCS_check_tag, RCS_parse): Added const qualifiers as - appropriate. - * rcs.h (RCS_isdead): Added prototype. - - * hash.h (walklist, sortlist): correct function prototypes. - - * ignore.c (ign_setup): don't bother checking to see if file - exists before calling ign_add_file. - -Fri Jun 9 11:24:06 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * all source files (rcsid): Added const qualifer. - * ignore.c (ign_default): Added const qualifier. - * subr.c (numdots): Added const qualifier to function argument. - * cvs.h (numdots): Added const qualifier to prototype argument. - - * client.c (change_mode): Tied consecutive if statements testing - the same variable together with else if. - - * import.c (import_descend): Build list of subdirectories when - reading directory, and then process the subdirectories in that - list. This change avoids I/O overhead of rereading directory - and reloading ignore list (.cvsignore) for each subdirectory. - -Thu Jun 8 11:54:24 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * import.c (import_descend): Use 4.4BSD d_type field if it is - present. - - * lock.c (set_lockers_name): Use %lu in format and cast st_uid - field to unsigned long. - - * import.c (import): Use RCS_check_kflag() to check -k options. - (keyword_usage, str2expmode, strn2expmode, expand_names): - Removed. - * rcs.c (RCS_check_kflag): Added keyword_usage array from import.c - for more descriptive error messages. - - * subr.c (run_setup, run_args): Changed variable argument - processing to work on machines that use <varargs.h>. - - * subr.c (copy_file, xcmp): Changed to read the file(s) by blocks - rather than by reading the whole file into a huge buffer. The - claim that this was reasonable because source files tend to be - small does not hold up in real world situations. CVS is used - to manage non-source files, and mallocs of 400K+ buffers (x2 - for xcmp) can easily fail due to lack of available memory or - even memory pool fragmentation. - (block_read): New function, taken from GNU cmp and slightly - modified. - - * subr.c (xcmp): Added const qualifier to function arguments. - * cvs.h (xcmp): Added const qualifer to prototype arguments. - -Wed Jun 7 11:28:31 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * cvs.h (Popen): Added prototype. - (Fopen, open_file, isreadable, iswritable, isdir, isfile, - islink, make_directory, make_directories, rename_file, - link_file, unlink_file, copy_file): Added const qualifer to - prototype arguments. - * subr.c (Fopen, Popen, open_file, isreadable, iswritable, isdir, - isfile, islink, make_directory, make_directories, rename_file, - link_file, unlink_file, copy_file): Added const qualifier to - function arguments. - - * logmsg.c (logfile_write), recurse.c (do_recursion, addfile): - Don't cast void functions to a void expression. There is at - least one compiler (MPW) that balks at this. - - * rcs.c (keysize, valsize): Change type to size_t. - - * add.c (add_directory): Don't cast umask() argument to int. - - * import.c (add_rcs_file): Changed type of mode to mode_t. - - * rcscmds.c (RCS_merge): New function. - * cvs.h (RCS_merge): Declare. - * update.c (merge_file, join_file): Call RCS_merge instead of - invoking rcsmerge directly. - - * cvs.h: Include <stdlib.h> if HAVE_STDC_HEADERS, otherwise - declared getenv(). - * cvsrc.c, ignore.c, main.c: Removed getenv() declaration. - - * client.c (mode_to_string): Changed to take mode_t instead of - struct statb argument. Simplified implementation, no longer - overallocates storage for returned mode string. - * client.h (mode_to_string): Updated declaration. - * server.c (server_updated): Updated for new calling conventions, - pass st_mode instead of pointer to struct statb. - - * cvs.h (CONST): Removed definition, use of const qualifier is - determined by autoconf. - * history.c, modules.c, parseinfo.c: Use const instead of CONST. - - * add.c, admin.c, checkout.c, commit.c, diff.c, import.c, log.c, - main.c, mkmodules.c, patch.c, recurse.c, remove.c, rtag.c, - server.c, status.c, subr.c, tag.c, update.c: Changed function - arguments "char *argv[]" to "char **argv" to silence lint - warnings about performing arithmetic on arrays. - -Tue Jun 6 18:57:21 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * version.c: Fix up version string, to say that this is Cyclic - CVS. - -Tue Jun 6 15:26:16 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * subr.c (run_setup, run_args, run_add_arg, xstrdup): Add const - qualifier to format argument. - * cvs.h (run_setup, run_args, xstrdup): Likewise. - - * Makefile.in (SOURCES): Added rcscmds.c. - (OBJECTS): Added rcscmds.o. - - * rcscmds.c: New file, with new functions RCS_settag, RCS_deltag, - RCS_setbranch, RCS_lock, RCS_unlock. - * checkin.c, commit.c, import.c, rtag.c, tag.c: Call above - functions instead of exec'ing rcs commands. - * cvs.h: Declare new functions. - -Mon May 29 21:40:54 1995 J.T. Conklin (jtc@rtl.cygnus.com) - - * recurse.c (start_recursion, do_recursion): Set entries to NULL - after calling Entries_Close(). - -Sat May 27 08:08:18 1995 Jim Meyering (meyering@comco.com) - - * Makefile.in (check): Export RCSBIN only if there exists an - `rcs' executable in ../../rcs/src. Before, tests would fail when - the directory existed but contained no executables. - (distclean): Remove options.h, now that it's generated. - (Makefile): Regenerate only *this* file when Makefile.in is - out of date. Depend on ../config.status. - -Fri May 26 14:34:28 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * entries.c (Entries_Open): Added missing fclose(). - (Entries_Close): Don't write Entries unless Entries.Log exists. - - * entries.c (Entries_Open): Renamed from ParseEntries; changed to - process Entries Log files left over from previous crashes or - aborted runs. - (Entries_Close): New function, write out Entries file if - neccessary and erase Log file. - (Register): Append changed records to Log file instead of - re-writing file. - (fgetentent): New function, parse one Entry record from a file. - (AddEntryNode): It's no longer an error for two records with the - same name to be added to the list. New records replace older - ones. - * cvs.h (Entries_Open, Entries_Close): Add prototypes. - (CVSADM_ENTLOG): New constant, name of Entries Log file. - * add.c, checkout.c, client.c, find_names.c, recurse.c: Use - Entries_Open()/Entries_Close() instead of ParseEntries()/dellist(). - - * add.c, admin.c, checkout.c, client.c, commit.c, diff.c, - history.c, import.c, log.c, patch.c, release.c, remove.c, - rtag.c, server.c, status.c, tag.c, update.c: Changed - conditionals so that return value of *printf is tested less than - 0 instead of equal to EOF. - -Thu May 25 08:30:12 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * subr.c (xmalloc): Never try to malloc zero bytes; if the user - asks for zero bytes, malloc one instead. - -Wed May 24 12:44:25 1995 Ken Raeburn <raeburn@cujo.cygnus.com> - - * subr.c (xmalloc): Don't complain about NULL if zero bytes were - requested. - -Tue May 16 21:49:05 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * subr.c (xmalloc): Never try to malloc zero bytes; if the user - asks for zero bytes, malloc one instead. - -Mon May 15 14:35:11 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * lock.c (L_LOCK_OWNED): Removed. - - * add.c, checkout.c, client.c, create_adm.c, cvs.h, entries.c, - find_names.c modules.c, recurse.c, release.c, repos.c, update.c: - removed CVS 1.2 compatibility/upgrade code. - -Mon May 8 11:25:07 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * lock.c (write_lock): Missed one instance where rmdir(tmp) should - have been changed to clear_lock(). - -Wed May 3 11:08:32 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * create_adm.c, entries.c, import.c, root.c: Changed conditionals - so that return value of *printf is tested less than 0 instead of - equal to EOF --- That's all Standard C requires. - -Wed May 3 18:03:37 1995 Samuel Tardieu <tardieu@emma.enst.fr> - - * rcs.h: removed #ifdef CVS_PRIVATE and #endif because cvs didn't - compile anymore. - -Mon May 1 13:58:53 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * rcs.c, rcs.h: Implemented lazy parsing of rcs files. - RCS_parsercsfile_i modified to read only the first two records - of rcs files, a new function RCS_reparsercsfile is called only - when additional information (tags, revision numbers, dates, - etc.) is required. - -Mon May 1 12:20:02 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in (INCLUDES): Include -I. for options.h. - -Fri Apr 28 16:16:33 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Makefile.in (SOURCES, HEADERS, DISTFILES): Updated. - (dist-dir): Renamed from dist; changed to work with DISTDIR - variable passed from parent. - - We don't want to include a file the user has to edit in the - distribution. - * options.h: No longer distributed. - * options.h.in: Distribute this instead. - * ../INSTALL, ../README: Installation instructions updated. - - * client.c (start_rsh_server): Send the remote command to rsh as a - single string. - -Fri Apr 28 00:29:49 1995 Noel Cragg <noel@vo.com> - - * commit.c: Added initializer for FORCE_CI - - * sanity.sh: Fix tests added 25 Apr -- they were expecting the - server to make noise, but the CVS_SERVER variable had been - accidentally set with the `-Q' flag. Ran all tests -- both - locally and remotely -- to verify that the change didn't break - anything. - -Thu Apr 27 12:41:52 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in: Revise comment regarding check vs. remotecheck. - -Thu Apr 27 12:52:28 1995 Bryan O'Sullivan <bos@cyclic.com> - - * client.c (start_rsh_server): If the CVS_RSH environment variable - is set, use its contents as the name of the program to invoke - instead of `rsh'. - -Thu Apr 27 12:18:38 1995 Noel Cragg <noel@vo.com> - - * checkout.c (checkout): To fix new bug created by Apr 23 change, - re-enabled "expand-module" functionality, because it has the side - effect of setting the checkin/update programs for a directory. To - solve the local/remote checkout problem that prompted this change - in the first place, I performed the next change. - * server.c (expand_proc): Now returns expansions for aliases only. - -Wed Apr 26 12:07:42 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * rcs.c (getrcskey): Rewritten to process runs of whitespace chars - and rcs @ strings instead of using state variables "white" and - "funky". - -Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * lock.c (unlock): Only call stat if we need to. - -Wed Apr 26 10:48:44 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (new_entries_line): Don't prototype. - -Tue Apr 25 22:19:16 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * sanity.sh: Add new tests to catch bugs in Apr 23 change. - -Tue Apr 25 17:10:55 1995 Roland McGrath <roland@baalperazim.frob.com> - - * create_adm.c (Create_Admin): Use getwd instead of getcwd. - -Sun Apr 23 20:58:32 1995 Noel Cragg <noel@vo.com> - - * checkout.c (checkout): Disabled "expand-module" functionality on - remote checkout, since it makes modules behave like aliases (see - longer note there). This change necessitated the change below. - Also merged the like parts of a conditional. - - * client.c (call_in_directory): Changed the algorithm that created - nested and directories and the "CVS" administration directories - therein. The algoithm wrongly assumed that the name of the - directory that that was to be created and the repository name were - the same, which breaks modules. - - * create_adm.c (Create_Admin), module.c (do_module), server.c - (server_register), subr.c, entries.c: Added fprintfs for trace-mode - debugging. - - * client.c (client_send_expansions): Argument to function didn't - have a type -- added one. - - * server.c (new_entries_line): Arguments to this function are - never used -- reoved them and fixed callers. - -Sat Apr 22 11:17:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * rcs.c (RCS_parse): If we can't open the file, give an error - message (except for ENOENT in case callers rely on that). - -Wed Apr 19 08:52:37 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_repository): Check for CVSADM_ENTSTAT in `dir', not - in `.'. - - * sanity.sh: Add TODO list. Revise some comments. Add tests of - one working directory adding a file and other updating it. - -Sat Apr 8 14:52:55 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Makefile.in (CFLAGS): Let configure set the default for CFLAGS. - Under GCC, we want -g -O. - -Fri Apr 7 15:49:25 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * root.c (Name_Root): merge identical adjacent conditionals. - - * create_admin.c (Create_Admin): Rearranged check for CVSADM and - OCVSADM directories so that CVSADM pathname is only built once. - - * update.c (update_dirleave_proc): Removed code to remove CVS - administration directory if command_name == "export" and to - create CVS/Root file if it is not present. Identical code - in update_filesdone_proc() will perform these same actions. - Also removed code that read and verfied CVS/Root. This is - expensive, and if it is necessary should happen in the - general recursion processor rather than in the update - callbacks. - - * lock.c (masterlock): New variable, pathname of master lockdir. - (set_lock): removed lockdir argument, now constructs it itself - and stores it in masterlock. - (clear_lock): new function, removes master lockdir. - (Reader_Lock, write_lock): call clear_lock instead of removing - master lockdir. - (Reader_Lock, write_lock): #ifdef'd out CVSTFL code. - - * main.c (main): register Lock_Cleanup signal handler. - * lock.c (Reader_Lock, write_lock): no longer register - Lock_Cleanup. - - * main.c (main): initialize new array hostname. - * lock.c (Reader_Lock, write_lock): Use global hostname array. - * logmsg.c (logfile_write): Likewise. - - * recurse.c (do_dir_proc, unroll_files_proc): Use open()/fchdir() - instead of getwd()/chdir() on systems that support the fchdir() - system call. - -Fri Apr 7 06:57:20 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c: Include the word "server" in error message for memory - exhausted, so the user knows which machine ran out of memory. - - * sanity.sh: For remote, set CVS_SERVER to test the right server, - rather than a random one from the PATH. - - * commit.c [DEATH_STATE]: Pass -f to `ci'. - -Thu Apr 6 13:05:15 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * commit.c (checkaddfile): If we didn't manage to fopen the file, - don't try to fclose it. - - * client.c (handle_m, handle_e): Use fwrite, rather than a loop of - putc's. Sometimes these streams are unbuffered. - -Tue Apr 4 11:33:56 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * (DISTFILES): Include cvsbug.sh, ChangeLog, NOTES, RCS-patches, - README-rm-add, ChangeLog.fsf, sanity.sh, sanity.el, and - .cvsignore. - -Mon Mar 27 08:58:42 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * rcs.c (RCS_parsercsfile_i): Accept `dead' state regardless of - DEATH_STATE define. Revise comments regarding DEATH_STATE versus - CVSDEA versus the scheme which uses a patched RCS. - * README-rm-add, RCS-patches: Explain what versions of CVS need - RCS patches. - -Sat Mar 25 18:51:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * server.c (server_cleanup): Only do the abysmal kludge of waiting - for command and draining the pipe #ifdef sun. The code makes - assumptions not valid on all systems, and is only there to - workaround a SunOS bug. - -Wed Mar 22 21:55:56 1995 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (mkdir_p): Call stat only if we get the EACCES. Faster - and more elegant. - -Tue Jan 31 20:59:19 1995 Ken Raeburn <raeburn@cujo.cygnus.com> - - * server.c: Try to avoid starting the "rm -rf" at cleanup time - until after subprocesses have finished. - (command_fds_to_drain, max_command_fd): New variables. - (do_cvs_command): Set them. - (command_pid_is_dead): New variable. - (wait_sig): New function. - (server_cleanup): If command_pid is nonzero, wait for it to die, - draining output from it in the meantime. If nonzero SIG was - passed, send a signal to the subprocess, to encourage it to die - soon. - - * main.c (usage): Argument is now `const char *const *'. - * cvs.h (usage): Changed prototype. - (USE): Make new variable `const'. - * add.c (add_usage), admin.c (admin_usage), checkout.c - (checkout_usage, export_usage, checkout), commit.c (commit_usage), - diff.c (diff_usage), history.c (history_usg), import.c - (import_usage, keyword_usage), log.c (log_usage), main.c (usg), - patch.c (patch_usage), release.c (release_usage), remove.c - (remove_usage), rtag.c (rtag_usage), server.c (server), status.c - (status_usage), tag.c (tag_usage), update.c (update_usage): Usage - messages are now const arrays of pointers to const char. - - * import.c (comtable): Now const. - * main.c (rcsid): Now static. - (cmd): Now const. - (main): Local variable CM now points to const. - * server.c (outbuf_memory_error): Local var MSG now const. - - * client.c (client_commit_usage): Deleted. - -Sat Dec 31 15:51:55 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * logmsg.c (do_editor): Allocate enough space for trailing '\0'. - -Fri Mar 3 11:59:49 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * cvsbug.sh: Call it "Cyclic CVS" now, not "Remote CVS". Call it - version C1.4A, not 1.4A2-remote. Send bugs to cyclic-cvs, not - remote-cvs. - - * classify.c (Classify_File): Put check for dead file inside - "#ifdef DEATH_SUPPORT". - -Thu Feb 23 23:03:43 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * update.c (join_file): Don't pass the -E option to rcsmerge here, - either (see Jan 22 change). - -Mon Feb 13 13:28:46 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * cvsbug.sh: Send bug reports to remote-cvs@cyclic.com, rather - than to the ordinary CVS bug address. This does mean we'll have - to wade through GNATS-style bug reports, sigh. - -Wed Feb 8 06:42:27 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * server.c: Don't include <sys/stat.h>; system.h already does, and - 4.3BSD can't take it twice. - - * subr.c [! HAVE_VPRINTF] (run_setup, run_args): Don't use va_dcl - in declaration. Declare the a1..a8 args which are used in the - sprintf call. - * cvs.h [! HAVE_VPRINTF] (run_setup, run_args): Don't prototype - args, to avoid conflicting with the function definitions - themselves. - -Tue Feb 7 20:10:00 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * client.c (update_entries): Pass the patch subprocess the switch - "-b ~", not "-b~"; the latter form seems not to work with patch - version 2.0 and earlier --- it takes the next argv element as the - backup suffix, and thus doesn't notice that the patch file's name - has been specified, thus doesn't find the patch, thus... *aargh* - -Fri Feb 3 20:28:21 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * log.c (log_option_with_arg): New function. - (cvslog): Use it and send_arg to handle the rlog options that take - arguments. The code used to use send_option_string for - everything, which assumes that "-d1995/01/02" is equivalent to - "-d -1 -9 -9 -5 ...". - -Tue Jan 31 15:02:01 1995 Jim Blandy <jimb@floss.life.uiuc.edu> - - * server.c: #include <sys/stat.h> for the new stat call in mkdir_p. - (mkdir_p): Don't try to create the intermediate directory if it - exists already. Some systems return EEXIST, but others return - EACCES, which we can't otherwise distinguish from a real access - problem. - -Sun Jan 22 15:25:45 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * update.c (merge_file): My rcsmerge doesn't accept a -E option, - and it doesn't look too important, so don't pass it. - -Fri Jan 20 14:24:58 1995 Ian Lance Taylor <ian@sanguine.cygnus.com> - - * client.c (do_deferred_progs): Don't try to chdir to toplevel_wd - if it has not been set. - (process_prune_candidates): Likewise. - -Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (client_commit): Move guts of function from here... - * commit.c (commit): ...to here. - -Mon Nov 28 15:14:36 1994 Ken Raeburn <raeburn@cujo.cygnus.com> - - * server.c (buf_input_data, buf_send_output): Start cpp directives - in column 1, otherwise Sun 4 pcc complains. - -Mon Nov 28 09:59:14 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (add_prune_candidate): Don't try to prune ".". - -Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c, client.c: More formatting cleanups. - - * client.h, client.c: New variable client_prune_dirs. - * update.c (update), checkout.c (checkout): Set it. - * client.c (add_prune_candidate, process_prune_candidates): New - functions. - (send_repository, call_in_directory, get_responses_and_close): - Call them. - -Wed Nov 23 01:17:32 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * server.c (do_cvs_command): Don't select on STDOUT_FILENO unless - we have something to write. - -Tue Nov 22 05:27:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * remove.c (remove_fileproc): Only call server_checked_in if we - actually are changing the entries file. - - * server.c (server_write_entries): New function. - (dirswitch, do_cvs_command): Call it. - (serve_entry, serve_updated): Just update in-memory data - structures, don't mess with CVS/Entries file. - -Mon Nov 21 10:15:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (server_checked_in): Set scratched_file to NULL after - using it. - - * checkin.c (Checkin): If the file was changed by the checkin, - call server_updated not server_checked_in. - -Sun Nov 20 08:01:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_repository): Move check for update_dir NULL to - before where we check last_update_dir. Check for "" here too. - - * client.c (send_repository): Use new argument dir. - - * client.c: Pass new argument dir to send_repository and - send_a_repository. - - * server.c, server.h (server_prog): New function. - * modules.c (do_modules): Call it if server_expanding. - * client.c: Support Set-checkin-prog and Set-update-prog responses. - * server.c, client.c: Add Checkin-prog and Update-prog requests. - -Fri Nov 18 14:04:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (get_short_pathname, is_cvsroot_level, - call_in_directory): Base whether this is new-style or - old-style based on whether we actually used the Directory request, - not based on whether the pathname is absolute. Rename - directory_supported to use_directory. - * server.c: Rename use_relative_pathnames to use_dir_and_repos. - * client.c (send_a_repository): If update_dir is absolute, don't - use it to try to reconstruct how far we have recursed. - - * server.c, server.h, client.c, client.h, vers_ts.c, update.h: - More cosmetic changes (identation, PARAMS vs. PROTO, eliminate - alloca, etc.) to remote CVS to make it more like the rest of CVS. - - * server.c: Make server_temp_dir just the dir name, not the name - with "%s" at the end. - * server.c, client.c: Add "Max-dotdot" request, and use it to make - extra directories in server_temp_dir if needed. - -Thu Nov 17 09:03:28 1994 Jim Kingdon <kingdon@cygnus.com> - - * client.c: Fix two cases where NULL was used and 0 was meant. - -Mon Nov 14 08:48:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (serve_unchanged): Set noexec to 0 when calling Register. - - * update.c (merge_file): Don't call xcmp if noexec. - -Fri Nov 11 13:58:22 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (call_in_directory): Deal with it if reposdirname is - not a subdirectory of toplevel_repos. - -Mon Nov 7 09:12:01 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * patch.c: If file is removed and we don't have a tag or date, - just print "current release". - - * classify.c (Classify_File): Treat dead files appropriately. - -Fri Nov 4 07:33:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * main.c (main) [SERVER_SUPPORT]: Move call to getwd past where we - know whether we are the server or not. Set CurDir to "<remote>" - if we are the server. - - * client.c: Remove #if 0'd function option_with_arg. - Remove #if 0'd code pertaining to the old way of logging the - session. - - * client.c (start_rsh_server): Don't invoke the server with the - -d option. - * server.c (serve_root): Test root for validity, just like main.c - does for non-remote CVS. - * main.c (main): If `cvs server' happens with a colon in the - CVSroot, just handle it normally; don't make it an error. - -Wed Nov 2 11:09:38 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_dirent_proc): If dir does not exist, just return - R_SKIP_ALL. - - * server.c, client.c: Add Directory request and support for - local relative pathnames (along with the repository absolute - pathnames). - * update.c, add.c, checkout.c, checkin.c, cvs.h, create_adm.c, - commit.c, modules.c, server.c, server.h, remove.c, client.h: - Pass update_dir to server_* functions. Include update_dir in - more error messages. - -Fri Oct 28 08:54:00 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c: Reformat to bring closer to cvs standards for brace - position, comment formatting, etc. - - * sanity.sh: Remove wrong "last mod" line. Convert more tests to - put PASS or FAIL in log file. Change it so arguments to the - script specify which tests to run. - - * client.c, client.h, server.c, checkout.c: Expand modules in - separate step from the checkout itself. - -Sat Oct 22 20:33:35 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * update.c (join_file): When checking for null return from - RCS_getversion, still do return even if quiet flag is set. - -Thu Oct 13 07:36:11 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_files): Call send_repository even if - toplevel_repos was NULL. - - * server.c (server_updated): If joining, don't remove file. - - * update.c (join_file): If server and file is unmodified, check it - out before joining. After joining, call server_updated. New - argument repository. - - * server.c, server.h (server_copy_file): New function. - * update.c (update_file_proc, join_file): Call it. - * client.c (copy_file, handle_copy_file): New functions. - * client.c (responses): Add "Copy-file". - - * client.c, client.h: Make toplevel_wd, failed_patches and - failed_patches_count extern. - * client.c (client_update): Move guts of function from here... - * update.c (update): ...to here. - - * client.c, checkout.c: Likewise for checkout. - - * client.c (is_cvsroot_level): New function. - (handle_set_sticky, handle_clear_sticky, - handle_clear_static_directory): Call it, instead of checking - short_pathname for a slash. - - * client.c, client.h (client_process_import_file, - client_import_done): New functions. - * import.c (import, import_descend): Use them. - * import.c (import_descend): If server, don't mention ignored CVS - directories. - * import.c (import_descend_dir): If client, don't print warm - fuzzies, or make directories in repository. If server, print warm - fuzzies to stdout not stderr. - * client.c (send_modified): New function, broken out from - send_fileproc. - (send_fileproc): Call it. - - * client.c (handle_clear_sticky, handle_set_sticky, - handle_clear_static_directory, handle_set_static_directory): If - command is export, just return. - (call_in_directory, update_entries): If command is export, don't - create CVS directories, CVS/Entries files, etc. - * update.c (update_filesdone_proc): Don't remove CVS directories if - client_active. - - * client.c (send_a_repository): Instead of insisting that - repository end with update_dir, just strip as many pathname - components from the end as there are in update_dir. - - * Makefile.in (remotecheck): New target, pass -r to sanity.sh. - * sanity.sh: Accept -r argument which means to test remote cvs. - - * tag.c (tag), rtag.c (rtag), patch.c (patch), import.c (import), - admin.c (admin), release.c (release): If client_active, connect to - the server and send the right requests. - * main.c (cmds): Add these commands. - (main): Remove code which would strip hostname off cvsroot and try - the command locally. There are no longer any commands which are - not supported. - * client.c, client.h (client_rdiff, client_tag, client_rtag, - client_import, client_admin, client_export, client_history, - client_release): New functions. - * server.c (serve_rdiff, serve_tag, serve_rtag, serve_import, - serve_admin, serve_export, serve_history, serve_release): New - functions. - (requests): List them. - * server.c: Declare cvs commands (add, admin, etc.). - * cvs.h, server.h: Don't declare any of them here. - * main.c: Restore declarations of cvs commands which were - previously removed. - - * cvs.h: New define DEATH_STATE, commented out for now. - * rcs.c (RCS_parsercsfile_i), commit.c (remove_file, checkaddfile) - [DEATH_STATE]: Use RCS state to record a dead file. - -Mon Oct 3 09:44:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * status.c (status_fileproc): Now that ts_rcs is just one time, - don't try to print the second time from it. (Same as raeburn 20 - Aug change, it accidentally got lost in 1.4 Alpha-1 merge). - - * cvs.h (CVSDEA): Added (but commented out for now). - * rcs.c (RCS_parsercsfile_i) [CVSDEA]: Also look in CVSDEA to see if - something is dead. - * commit.c (ci_new_rev, mark_file) [CVSDEA]: New functions. - (remove_file, checkaddfile) [CVSDEA]: Use them instead of ci -K. - * find_names.c (find_dirs) [CVSDEA]: Don't match CVSDEA directories. - * update.c (checkout_file): Check RCS_isdead rather than relying - on co to not create the file. - - * sanity.sh: Direct output to logfile, not /dev/null. - - * subr.c (run_exec): Print error message if we are unable to exec. - - * commit.c (remove_file): Call Scratch_Entry when removing tag - from file. The DEATH_SUPPORT ifdef was erroneous. - -Sun Oct 2 20:33:27 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * commit.c (checkaddfile): Instead of calling isdir before - attempting to create the directory, just ignore EEXIST errors from - mkdir. (This removes some DEATH_SUPPORT ifdefs which actually had - nothing to do with death support). - -Thu Sep 29 09:23:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * diff.c (diff): Search attic too if we have a second tag/date. - (diff_fileproc): If we have a second tag/date, don't do all the - checking regarding the user file. - -Mon Sep 26 12:02:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * checkin.c (Checkin): Check for error from unlink_file. - -Mon Sep 26 08:51:10 1994 Anthony J. Lill (ajlill@ajlc.waterloo.on.ca) - - * rcs.c (getrcskey): Allocate space for terminating '\0' if - necessary. - -Sat Sep 24 09:07:37 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * commit.c (commit_fileproc): Set got_message = 1 when calling - do_editor (accidentally omitted from last change). - -Fri Sep 23 11:59:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - Revert buggy parts of Rich's change of 1 Nov 1993 (keeping the - dynamic buffer allocation, which was the point of that change). - * logmsg.c (do_editor): Reinstate message arg, but make it char - **messagep instead of char *message. Change occurances of message - to *messagep. Char return type from char * back to void. - * cvs.h: Change do_editor declaration. - * commit.c: Reinstate got_message variable - (commit_filesdoneproc, commit_fileproc, commit_direntproc): Use it. - * import.c (import), commit.c (commit_fileproc, - commit_direntproc): Pass &message to do_editor; don't expect it to - return a value. - * client.c (client_commit): Likewise. - * import.c (import): Deal with it if message is NULL. - -Wed Sep 21 09:43:25 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (server_updated): If the file doesn't exist, skip it. - - * diff.c, client.h, client.c: Rename diff_client_senddate to - client_senddate and move from diff.c to client.c. - * client.c (client_update, client_checkout): Use it. - -Sat Sep 17 08:36:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * checkout.c (checkout_proc): Don't pass NULL to Register for - version. (should fix "cvs co -r <nonexistent-tag> <file>" - coredump on Solaris). - -Fri Sep 16 08:38:02 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * diff.c (diff_fileproc): Set top_rev from vn_user, not vn_rcs. - Rename it to user_file_rev because it need not be the head of any - branch. - (diff_file_nodiff): After checking user_file_rev, if we have both - use_rev1 and use_rev2, compare them instead of going on to code - which assumes use_rev2 == NULL. - -Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * status.c (status): Return a value in client_active case. - -Thu Sep 15 15:02:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * server.c (serve_modified): Create the file even if the size is - zero. - -Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * lock.c (readers_exist): Clear errno each time around the loop, - not just the first time. - - * client.c (start_server): Don't send Global_option -q twice. - - * no_diff.c (No_Difference): Check for error from unlink. - - * no_diff.c, cvs.h (No_Difference): New args repository, - update_dir. Call server_update_entries if needed. Use update_dir - in error message. - * classify.c (Classify_File): Pass new args to No_Difference. - - * server.c (server_update_entries, server_checked_in, - server_updated): Don't do anything if noexec. - - * client.c (send_fileproc): Rather than guessing how big the gzip - output may be, just realloc the buffer as needed. - -Tue Sep 13 13:22:03 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * lock.c: Check for errors from unlink, readdir, and closedir. - - * classify.c (Classify_File): Pass repository and update_dir to - sticky_ck. - (sticky_ck): New args repository and update_dir. - * server.c, server.h (server_update_entries): New function. - * classify.c (sticky_ck): Call it. - * client.c: New response "New-entry". - * client.c (send_fileproc): Send tag/date from vers->entdata, not - from vers itself. - -Mon Sep 12 07:07:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c: Clean up formatting ("= (errno)" -> "= errno"). - - * cvs.h: Declare strerror. - - * client.c: Add code to deal with Set-sticky and Clear-sticky - responses, and Sticky request. - * server.c: Add code to deal with Sticky request. - * server.c, server.h (server_set_sticky): New function. - * create_adm.c (Create_Admin), update.c (update, update_dirent_proc), - commit.c (commit_dirleaveproc): Call it. - * client.c, client.h (send_files): Add parameter aflag. - * add.c (add), diff.c (diff), log.c (cvslog), remove.c (cvsremove), - status.c (status), - client.c (client_commit, client_update, client_checkout): Pass it. - * client.c (client_update): Add -A flag. - -Fri Sep 9 07:05:35 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * entries.c (WriteTag): Check for error from unlink_file. - - * server.c (server_updated): Initialize size to 0. Previously if - the file was zero length, the variable size got used without being - set. - -Thu Sep 8 14:23:05 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (serve_repository): Check for error from fopen on - CVSADM_ENT. - - * update.c (update, update_dirent_proc): Check for errors when - removing Entries.Static. - - * client.c: Add code to deal with Set-static-directory and - Clear-static-directory responses, and Static-directory request. - * server.c, server.h (server_clear_entstat, server_set_entstat): - New functions. - * update.c, checkout.c, modules.c: Call them. - * server.c: Add code to deal with Static-directory request. - - * server.c, client.c: Use strchr and strrchr instead of index and - rindex. - - * server.c (serve_unchanged, serve_lost): Change comments which - referred to changing timestamp; we don't always change the - timestamp in those cases anymore. - -Wed Sep 7 10:58:12 1994 J.T. Conklin (jtc@rtl.cygnus.com) - - * cvsrc.c (read_cvsrc): Don't call getenv() three times when one - time will do. - - * subr.c (xmalloc, xrealloc): Change type of bytes argument from - int to size_t and remove the test that checks if it is less than - zero. - * cvs.h (xmalloc, xrealloc): Update prototype. - -Thu Sep 1 12:22:20 1994 Jim Kingdon (kingdon@cygnus.com) - - * update.c (merge_file, join_file): Pass -E to rcsmerge. - (merge_file): If rcsmerge doesn't change the file, say so. - - * recurse.c, cvs.h (start_recursion): New argument wd_is_repos. - * recurse.c (start_recursion): Use it instead of checking whether - command_name is rtag to find out if we are cd'd to the repository. - * client.c, update.c, commit.c, status.c, diff.c, log.c, admin.c, - remove.c, tag.c: Pass 0 for wd_is_repos. - * rtag.c, patch.c: Pass 1 for wd_is_repos. - - * classify.c, cvs.h (Classify_File): New argument pipeout. - * classify.c (Classify_File): If pipeout, don't complain if the - file is already there. - * update.c, commit.c, status.c: Change callers. - - * mkmodules.c (main): Don't print "reminders" if commitinfo, - loginfo, rcsinfo, or editinfo files are missing. - -Mon Aug 22 23:22:59 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * server.c (strerror): Static definition replaced by extern - declaration. - -Sun Aug 21 07:16:27 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * client.c (update_entries): Run "patch" with input from - /dev/null, so if it's the wrong version, it fails quickly rather - than waiting for EOF from terminal before failing. - -Sat Aug 20 04:16:33 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * server.c (serve_unchanged): Instead of creating a file with a - zero timestamp, rewrite the entries file to have "=" in the - timestamp field. - * vers_ts.c (mark_lost, mark_unchanged): New macros. - (time_stamp_server): Use them, for clarity. Interpret "=" - timestamp as an unchanged file. A zero-timestamp file should - never be encountered now in use_unchanged mode. - - * client.c (start_server): If CVS_CLIENT_PORT indicates a - non-positive port number, skip straight to rsh connection. - - * status.c (status_fileproc): Fix ts_rcs reference when printing - version info, to correspond to new Entries file format. Don't - print it at all if server_active, because it won't have any useful - data. - -Thu Aug 18 14:38:21 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * cvs.h (status): Declare. - * client.c (client_status): New function. - - * client.h (client_status): Declare. - * main.c (cmds): Include it. - * server.c (serve_status): New function. - (requests): Add it. - * status.c (status): Do the remote thing if client_active. - - * client.c (supported_request): New function. - (start_server): Use it. - - * server.c (receive_partial_file): New function, broken out from - serve_modified. Operate with fixed-size local buffer, instead of - growing stack frame by entire file size. - (receive_file): New function, broken out from serve_modified. - (serve_modified): Call it. - (server): Print out name of unrecognized request. - - More generic stream-filtering support: - * client.c (close_on_exec, filter_stream_through_program): New - functions. - (server_fd): New variable. - (get_responses_and_close): Direct non-rsh connection is now - indicated by server_fd being non-negative. File descriptors for - to_server and from_server may now be different in case "tee" - filtering is being done. Wait for rsh_pid specifically. - (start_server): Use filter_stream_through_program for "tee" - filter, and enable it for direct Kerberos-authenticated - connections. Use dup to create new file descriptors for server - connection if logging is enabled. - (start_rsh_server): Disable code that deals with logging. - - Per-file compression support: - * cvs.h (gzip_level): Declare. - * main.c (usg): Describe new -z argument. - (main): Recognize it and set gzip_level. - * client.c (filter_through_gzip, filter_through_gunzip): New - functions to handle compression. - (update_entries): If size starts with "z", uncompress - (start_server): If gzip_level is non-zero and server supports it, - issue gzip-file-contents request. - (send_fileproc): Optionally compress file contents. Use a - slightly larger buffer, anticipating the worst case. - * server.c (gzip_level): Define here. - (receive_file): Uncompress file contents if needed. - (serve_modified): Recognize "z" in file size and pass receive_file - appropriate flag. - (buf_read_file_to_eof, buf_chain_length): New functions. - (server_updated): Call them when sending a compressed file. - (serve_gzip_contents): New function; set gzip_level. - (requests): Added gzip-file-contents request. - -Wed Aug 17 09:37:44 1994 J.T. Conklin (jtc@cygnus.com) - - * find_names.c (find_dirs): Use 4.4BSD filesystem feature (it - contains the file type in the dirent structure) to avoid - stat'ing each file. - - * commit.c (remove_file,checkaddfile): Change type of umask - variables from int to mode_t. - * subr.c (): Likewise. - -Tue Aug 16 19:56:34 1994 Mark Eichin (eichin@cygnus.com) - - * diff.c (diff_fileproc): Don't use diff_rev* because they're - invariant across calls -- add new variable top_rev. - (diff_file_nodiff): After checking possible use_rev* values, if - top_rev is set drop it in as well (if we don't already have two - versions) and then clear it for next time around. - -Wed Aug 10 20:50:47 1994 Mark Eichin (eichin@cygnus.com) - - * diff.c (diff_fileproc): if ts_user and ts_rcs match, then the - file is at the top of the tree -- so we might not even have a - copy. Put the revision into diff_rev1 or diff_rev2. - -Wed Aug 10 14:55:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * server.c (do_cvs_command): Use waitpid. - - * subr.c (run_exec): Always use waitpid. - - * Makefile.in (CC, LIBS): Define here, in case "make" is run in - this directory instead of top level. - -Wed Aug 10 13:57:06 1994 Mark Eichin (eichin@cygnus.com) - - * client.c (krb_get_err_text): use HAVE_KRB_GET_ERR_TEXT to - determine if we need to use the array or the function. - * main.c: ditto. - -Tue Aug 9 16:43:30 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * entries.c (ParseEntries): If timestamp is in old format, rebuild - it in the new format. Fudge an unmatchable entry that won't - trigger this code next time around, if the file is modified. - - * vers_ts.c (time_stamp): Only put st_mtime field into timestamp, - and use GMT time for it. With st_ctime or in local time, copying - trees between machines in different time zones makes all the files - look modified. - (time_stamp_server): Likewise. - -Tue Aug 9 19:40:51 1994 Mark Eichin (eichin@cygnus.com) - - * main.c (main): use krb_get_err_text function instead of - krb_err_txt array. - -Thu Aug 4 15:37:50 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * main.c (main): When invoked as kserver, set LOGNAME and USER - environment variables to the remote user name. - -Thu Aug 4 07:44:37 1994 Mark Eichin (eichin@cygnus.com) - - * client.c: (handle_valid_requests): if we get an option that has - rq_enableme set, then send that option. If it is UseUnchanged, set - use_unchanged so that the rest of the client knows about - it. (Could become a more general method for dealing with protocol - upgrades.) - (send_fileproc): if use_unchanged didn't get set, send an - old-style "Lost" request, otherwise send an "Unchanged" request. - * server.c (serve_unchanged): new function, same as serve_lost, - but used in the opposite case. - (requests): add new UseUnchanged and Unchanged requests, and make - "Lost" optional (there isn't a good way to interlock these.) - * server.h (request.status): rq_enableme, new value for detecting - compatibility changes. - * vers_ts.c (time_stamp_server): swap meaning of zero timestamp if - use_unchanged is set. - -Tue Jul 26 10:19:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * sanity.sh: Separate CVSROOT_FILENAME, which must be the filename - of the root, from CVSROOT, which can include a hostname for - testing remote CVS. (but the tests aren't yet prepared to deal - with the bugs in remote CVS). - - * import.c (update_rcs_file): Change temporary file name in TMPDIR - from FILE_HOLDER to cvs-imp<process-id>. - - * sanity.sh: Add ">/dev/null" and "2>/dev/null" many places to - suppress spurious output. Comment out tests which don't work (cvs - add on top-level directory, cvs diff when non-committed adds or - removes have been made, cvs release, test 53 (already commented as - broken), retagging without deleting old tag, test 63). Now 'make - check' runs without any failures. - -Fri Jul 15 12:58:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * Makefile.in (install): Do not depend upon installdirs. - -Thu Jul 14 15:49:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c, server.c: Don't try to handle alloca here; it's - handled by cvs.h. - -Tue Jul 12 13:32:40 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (update_entries): Reset stored_checksum_valid if we - quit early because of a patch failure. - -Fri Jul 8 11:13:05 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (responses): Mark "Remove-entry" as optional. - -Thu Jul 7 14:07:58 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * server.c (server_updated): Add new checksum argument. If it is - not NULL, and the client supports the "Checksum" response, send - it. - * server.h (server_updated): Update prototype. - * update.c: Include md5.h. - (update_file_proc): Pass new arguments to patch_file and - server_updated. - (patch_file): Add new checksum argument. Set it to the MD5 - checksum of the version of the file being checked out. - (merge_file): Pass new argument to server_updated. - * client.c: Include md5.h. - (stored_checksum_valid, stored_checksum): New static variables. - (handle_checksum): New static function. - (update_entries): If a checksum was received, check it against the - MD5 checksum of the final file. - (responses): Add "Checksum". - (start_server): Clear stored_checksum_valid. - * commit.c (commit_fileproc): Pass new argument to server_updated. - - * client.h (struct response): Move definition in from client.c, - add status field. - (responses): Declare. - * client.c (struct response): Remove definition; moved to - client.h. - (responses): Make non-static. Initialize status field. - * server.c (serve_valid_responses): Check and record valid - responses, just as in handle_valid_requests in client.c. - - * diff.c (diff_client_senddate): New function. - (diff): Use it to send -D arguments to server. - -Wed Jul 6 12:52:37 1994 J.T. Conklin (jtc@phishhead.cygnus.com) - - * rcs.c (RCS_parsercsfile_i): New function, parse RCS file - referenced by file ptr argument. - (RCS_parsercsfile): Open file and pass its file ptr to above function. - (RCS_parse): Likewise. - -Wed Jul 6 01:25:38 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * client.c (update_entries): Print message indicating that an - unpatchable file will be refetched. - (client_update): Print message when refetching unpatchable files. - -Fri Jul 1 07:16:29 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * client.c (send_dirent_proc): Don't call send_a_repository if - repository is "". - -Fri Jul 1 13:58:11 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (last_dirname, last_repos): Move out of function. - (failed_patches, failed_patches_count): New static variables. - (update_entries): If patch program fails, save short_pathname in - failed_patches array, only exit program if retcode is -1, and - return out of the function rather than update the Entries line. - (start_server): Clear toplevel_repos, last_dirname, last_repos. - (client_update): If failed_patches is not NULL after doing first - update, do another update, but remove all the failed files first. - -Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (requests): Add request "Global_option". - (serve_global_option): New function, to handle it. - * client.c (start_server): Deal with global options. Check for - errors from fprintf. - - * client.c (send_fileproc): Split out code which sends repository - into new function send_a_repository. Also, deal with update_dir - being ".". - (send_dirent_proc): Call send_a_repository. - * add.c (add): If client_active, do special processing for - directories. - (add_directory): If server_active, don't try to create CVSADM - directory. - -Thu Jun 30 11:58:52 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (update_entries): If patch succeeds, remove the backup - file. - * server.c (server_updated): Add new argument file_info. If it is - not NULL, use it rather than sb to get the file mode. - * server.h (server_updated): Update prototype for new argument. - * update.c (update_file_proc): Pass new arguments to patch_file - and server_updated. - (patch_file): Add new argument file_info. Don't use -p to check - out new version, check it out into file and rename that to file2. - If result is not readable, assume file is dead and set docheckout. - Call xchmod on file2. Close the patch file after checking for a - binary diff. Set file_info to the results of stat on file2. - (merge_file): Pass new argument to server_updated. - * commit.c (commit_fileproc): Pass new argument to server_updated. - -Wed Jun 29 13:00:41 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (krb_realmofhost): Declare, since it's not the current - <krb.h>. - (start_server): Save the name returned by gethostbyname. Call - krb_realmofhost to get the realm. Pass the resulting realm to - krb_sendauth. Pass the saved real name to krb_sendauth, rather - than server_host. - - * update.c (update_file_proc): Pass &docheckout to patch_file. If - it is set to 1, fall through to T_CHECKOUT case. - (patch_file): Add docheckout argument. Set it to 1 if we can't - make a patch. Check out the files and run diff rather than - rcsdiff. If either file does not end in a newline, we can't make - a patch. If the patch starts with the string "Binary", assume - one or the other is a binary file, and that we can't make a patch. - -Tue Jun 28 11:57:29 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * client.c (update_entries): If the patch file is empty, don't run - patch program; avoids error message. - - * classify.c (Classify_File): Return T_CHECKOUT, not T_PATCH, if - the file is in the Attic. - - * cvs.h (enum classify_type): Add T_PATCH. - * config.h (PATCH_PROGRAM): Define. - * classify.c (Classify_File): If user file exists and is not - modified, and using the same -k options, return T_PATCH instead of - T_CHECKOUT. - * update.c (patches): New static variable. - (update): Add u to gnu_getopt argument. Handle it. - (update_file_proc): Handle T_PATCH. - (patch_file): New static function. - * server.h (enum server_updated_arg4): Add SERVER_PATCHED. - * server.c (server_updated): Handle SERVER_PATCHED by sending - "Patched" command. - (serve_ignore): New static function. - (requests): Add "update-patches". - (client_update): If the server supports "update-patches", send -u. - * client.c (struct update_entries_data): Change contents field - from int to an unnamed enum. - (update_entries): Correponding change. If contents is - UPDATE_ENTRIES_PATCH, pass the input to the patch program. - (handle_checked_in): Initialize contents to enum value, not int. - (handle_updated, handle_merged): Likewise. - (handle_patched): New static function. - (responses): Add "Patched". - * commit.c (check_fileproc): Handle T_PATCH. - * status.c (status_fileproc): Likewise. - - * client.c (start_server): If CVS_CLIENT_PORT is set in the - environment, connect to that port, rather than looking up "cvs" in - /etc/services. For debugging. - -Tue Jun 21 12:48:16 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * update.c (joining): Return result of comparing pointer with - NULL, not result of casting (truncating, on Alpha) pointer to int. - - * main.c (main) [HAVE_KERBEROS]: Impose a umask if starting as - Kerberos server, so temp directories won't be world-writeable. - - * update.c (update_filesdone_proc) [CVSADM_ROOT]: If environment - variable CVS_IGNORE_REMOTE_ROOT is set and repository is remote, - don't create CVS/Root file. - * main.c (main): If env var CVS_IGNORE_REMOTE_ROOT is set, don't - check CVS/Root. - -Fri Jun 10 18:48:32 1994 Mark Eichin (eichin@cygnus.com) - - * server.c (O_NDELAY): use POSIX O_NONBLOCK by default, unless it - isn't available (in which case substitute O_NDELAY.) - -Thu Jun 9 19:17:44 1994 Mark Eichin (eichin@cygnus.com) - - * server.c (server_cleanup): chdir out of server_temp_dir before - deleting it (so that it works on non-BSD systems.) Code for choice - of directory cloned from server(). - -Fri May 27 18:16:01 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * client.c (update_entries): Add return type of void. - (get_responses_and_close): If using Kerberos and from_server and - to_server are using the same file descriptor, use shutdown, not - fclose. Close from_server. - (start_server): New function; most of old version renamed to - start_rsh_server. - (start_rsh_server): Mostly renamed from old start_server. - (send_fileproc): Use %lu and cast sb.st_size in fprintf call. - (send_files): Remove unused variables repos and i. - (option_no_arg): Comment out; unused. - * main.c (main): Initialize cvs_update_env to 0. If command is - "kserver", authenticate and change command to "server". If - command is "server", don't call Name_Root, don't check access to - history file, and don't assume that CVSroot is not NULL. - * server.c (my_memmove): Removed. - (strerror): Change check from STRERROR_MISSING to HAVE_STRERROR. - (serve_root): Likewise for putenv. - (serve_modified): Initialize buf to NULL. - (struct output_buffer, buf_try_send): Remove old buffering code. - (struct buffer, struct buffer_data, BUFFER_DATA_SIZE, - allocate_buffer_datas, get_buffer_data, buf_empty_p, - buf_append_char, buf_append_data, buf_read_file, buf_input_data, - buf_copy_lines): New buffering code. - (buf_output, buf_output0, buf_send_output, set_nonblock, - set_block, buf_send_counted, buf_copy_counted): Rewrite for new - buffering code. - (protocol, protocol_memory_error, outbuf_memory_error, - do_cvs_command, server_updated): Rewrite for new buffering code. - (input_memory_error): New function. - (server): Put Rcsbin at start of PATH in environment. - * Makefile.in: Add @includeopt@ to DEFS. - -Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvs.h, classify.c (Classify_File): New argument update_dir. - Include it in user messages. - * commit.c (check_fileproc), status.c (status_fileproc), update.c - (update_file_proc): Pass update_dir to Classify_File. - * commit.c (check_fileproc), update.c (checkout_file): - Include update_dir in user messages. - * commit.c (check_fileproc) update.c (update_file_proc): Re-word - "unknown status" message. - - * server.c (server_checked_in): Deal with the case where - scratched_file is set rather than entries_line. - - * entries.c (Register): Write file even if server_active. - * add.c (add): Add comment about how we depend on above behavior. - -Tue May 17 08:16:42 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * mkmodules.c: Add dummy server_active and server_cleanup, to go - with the dummy Lock_Cleanup already there. - - * server.c (server_cleanup): No longer static. - -Sat May 7 10:17:17 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - Deal with add and remove: - * commit.c (checkaddfile): If CVSEXT_OPT or CVSEXT_LOG file does - not exist, just silently keep going. - (remove_file): If server_active, remove file before creating - temporary file with that name. - * server.c (serve_remove, serve_add): New functions. - (requests): Add them. - * server.c (server_register): If options is NULL, it means there - are no options. - * server.c, server.h (server_scratch_entry_only): New function. - New variable kill_scratched_file. - (server_scratch, server_updated): Deal with kill_scratched_file. - * commit.c (commit_fileproc): If server_active, call - server_scratch_entry_only and server_updated. - * add.c (add): Add client_active code. - (add): If server_active, call server_checked_in for each file added. - * remove.c (remove): Add client_active code. - (remove_fileproc): If server_active, call server_checked_in. - * main.c (cmds), client.c, client.h: New functions client_add and - client_remove. - * Move declarations of add, cvsremove, diff, and cvslog from - main.c to cvs.h. - * client.c (call_in_directory): Update comment regarding Root and - Repository files. - (send_fileproc): Only send Entries line if Version_TS really finds - an entry. If it doesn't find one, send Modified. - (update_entries): If version is empty or starts with 0 or -, - create a dummy timestamp. - -Thu May 5 19:02:51 1994 Per Bothner (bothner@kalessin.cygnus.com) - - * recurse/c (start_recursion): If we're doing rtag, and thus - have cd'd to the reporsitory, add ,v to a file name before stat'ing. - -Wed Apr 20 15:01:45 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * client.c (client_commit): Call ign_setup. - (client_update, client_checkout): Likewise. - * diff.c (diff): If client, call ign_setup. - * log.c (cvslog): Likewise. - * update.h (ignlist): Change definition to declaration to avoid - depending upon common semantics (not required by ANSI C, and not - the default on Irix 5). - * update.c (ignlist): Define. - -Tue Apr 19 00:02:54 1994 John Gilmore (gnu@cygnus.com) - - Add support for remote `cvs log'; clean up `cvs diff' a bit. - - * client.c (send_arg): Make external. - (send_option_string): New function. - (client_diff_usage): Remove, unused. - (client_diff): Just call diff, not do_diff. - (client_log): Add. - * client.h (client_log, send_arg, send_option_string): Declare. - * cvs.h (cvslog): Declare. - * diff.c (do_diff): Fold back into diff(), distinguish by checking - client_active. - (diff): Remove `-*' arg parsing crud; use send_option_string. - * log.c (cvslog): If a client, start the server, pass options - and files, and handle server responses. - * main.c (cmds): Add client_log. - (main): Remove obnoxious message every time CVS/Root is used. - Now CVS will be quiet about it -- unless there is a conflict - between $CVSROOT or -d value versus CVS/Root. - * server.c (serve_log): Add. - (requests): Add "log". - -Mon Apr 18 22:07:53 1994 John Gilmore (gnu@cygnus.com) - - Add support for remote `cvs diff'. - - * diff.c (diff): Break guts out into new fn do_diff. - Add code to handle starting server, writing args, - sending files, and retrieving responses. - (includes): Use PARAMS for static function declarations. - * client.c (to_server, from_server, rsh_pid, - get_responses_and_close, start_server, send_files, - option_with_arg): Make external. - (send_file_names): New function. - (client_diff): New function. - * client.h (client_diff, to_server, from_server, - rsh_pid, option_with_arg, get_responses_and_close, start_server, - send_file_names, send_files): Declare. - * cvs.h (diff): Declare. - * main.c (cmds): Add client_diff to command table. - * server.c (serve_diff): New function. - (requests): Add serve_diff. - (server): Bug fix: avoid free()ing incremented cmd pointer. - * update.h (update_filesdone_proc): Declare with PARAMS. - -Sat Apr 16 04:20:09 1994 John Gilmore (gnu@cygnus.com) - - * root.c (Name_root): Fix tyop (CVSroot when root meant). - -Sat Apr 16 03:49:36 1994 John Gilmore (gnu@cygnus.com) - - Clean up remote `cvs update' to properly handle ignored - files (and files that CVS can't identify), and to create - CVS/Root entries on the client side, not the server side. - - * client.c (send_fileproc): Handle the ignore list. - (send_dirent_proc): New function for handling ignores. - (send_files): Use update_filesdone_proc and send_dirent_proc - while recursing through the local filesystem. - * update.h: New file. - * update.c: Move a few things into update.h so that client.c - can use them. - -Fri Mar 11 13:13:20 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * server.c: If O_NDELAY is not defined, but O_NONBLOCK is, define - O_NDELAY to O_NONBLOCK. - -Wed Mar 9 21:08:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - Fix some spurious remote CVS errors caused by the CVS/Root patches: - * update.c (update_filesdone_proc): If server_active, don't try to - create CVS/Root. - * root.c (Name_Root): Make error messages which happen if root is - not an absolute pathname or if it doesn't exist a bit clearer. - Skip them if root contains a colon. - -Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * client.c (client_commit): dynamically allocate message. - -Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * server.h: remove alloca cruft - - * server.c: replace with better alloca cruft - -Mon May 24 11:25:11 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - * entries.c (Scratch_Entry): Update our local Entries file even if - server_active. - - * server.c (server_scratch, server_register): If both Register - and Scratch_Entry happen, use whichever one happened later. - If neither happen, silently continue. - - * client.c (client_checkout): Initialize tag and date (eichin and - I independently discovered this bug at the same time). - -Wed May 19 10:11:51 1993 Mark Eichin (eichin@cygnus.com) - - * client.c (update_entries): handle short reads over the net - (SVR4 fread is known to be broken, specifically for short - reads off of streams.) - -Tue May 18 15:53:44 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - * server.c (do_cvs_command): Fix fencepost error in setting - num_to_check. - - * server.c (do_cvs_command): If terminated with a core dump, print - message and set dont_delete_temp. - (server_cleanup): If dont_delete_temp, don't delete it. - - * client.c (get_server_responses): Don't change cmd since we - are going to "free (cmd)". - - * server.c: Rename memmove to my_memmove pending a real fix. - - * server.c (do_cvs_command): Set num_to_check to largest descriptor - we try to use, rather than using (non-portable) getdtablesize. - -Wed May 12 15:31:40 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - Add CVS client feature: - * client.{c,h}: New files. - * cvs.h: Include client.h. - * main.c: If CVSROOT has a colon, use client commands instead. - * vers_ts.c (Version_TS): If repository arg is NULL, don't worry - about the repository. - * logmsg.c (do_editor): If repository or changes is NULL, just don't - use those features. - * create_adm.c (Create_Admin), callers: Move the test for whether - the repository exists from here to callers. - * repos.c (Name_Repository): Don't test whether the repository exists - if client_active set (might be better to move test to callers). - - Add CVS server feature: - * server.{c,h}: New files. - * cvs.h: Include server.h. - * checkin.c (Checkin): Call server_checked_in. - * update.c (update_file_proc, merge_files): Call server_updated. - * entries.c (Register): Call server_register. - (Scratch_Entry): Call server_scratch. - * main.c: Add server to cmds. - * vers_ts.c (Version_TS): If server_active, call new function - time_stamp_server to set ts_user. - diff --git a/gnu/usr.bin/cvs/cvs/Makefile b/gnu/usr.bin/cvs/cvs/Makefile index 94c505f..c222fd0 100644 --- a/gnu/usr.bin/cvs/cvs/Makefile +++ b/gnu/usr.bin/cvs/cvs/Makefile @@ -1,4 +1,10 @@ -# $Id: Makefile,v 1.12 1995/12/11 02:22:27 peter Exp $ +# $Id: Makefile,v 1.13 1995/12/11 04:24:02 peter Exp $ + +.include "${.CURDIR}/../Makefile.inc" + +.PATH: ${CVSDIR}/src +.PATH: ${CVSDIR}/lib +.PATH: ${CVSDIR}/man PROG= cvs MAN1= cvs.1 @@ -10,11 +16,12 @@ SRCS= add.c admin.c checkin.c checkout.c classify.c client.c commit.c \ release.c remove.c repos.c root.c rtag.c server.c status.c tag.c \ update.c vers_ts.c wrapper.c -CFLAGS+= -I${.CURDIR}/../lib -DHAVE_CONFIG_H +SRCS+= subr.c error.c filesubr.c version.c myndbm.c fileattr.c watch.c run.c \ + hash.c edit.c mkmodules.c scramble.c -DPADD+= ${LIBCVS} ${LIBGNUREGEX} ${LIBMD} -LDADD+= -lcvs -lgnuregex -lmd +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../lib -I${CVSDIR}/src -I${CVSDIR}/lib -DHAVE_CONFIG_H -.include "../../Makefile.inc" -.include <bsd.prog.mk> +DPADD+= ${LIBCVS} ${LIBGNUREGEX} ${LIBMD} ${LIBCRYPT} +LDADD+= -lcvs -lgnuregex -lmd -lcrypt +.include <bsd.prog.mk> diff --git a/gnu/usr.bin/cvs/cvs/NOTES b/gnu/usr.bin/cvs/cvs/NOTES deleted file mode 100644 index 646ebdf..0000000 --- a/gnu/usr.bin/cvs/cvs/NOTES +++ /dev/null @@ -1,60 +0,0 @@ -wishlist - Tue Nov 2 15:22:58 PST 1993 - -* bcopy -> memcpy & friends. - ** done 12/18/93 - -* remove static buffers. -* replace list & node cache with recursive obstacks, (xmalloc, - getnode, getlist) -* check all io functions for error return codes. also check all - system calls. -* error check mkdir. - ---- -Old notes... - -* All sizing limits are gone. The rest of these items were incidental - in that effort. - -* login name from history was duplicated. taught existing routine to - cache and use that instead. Also add routines to cache uid, pid, - etc. - -* ign strings were never freed. Now they are. - -* there was a printf("... %s ...", cp) vs *cp bug in history.c. Now - fixed. - -* The environment variables TMPDIR, HOME, and LOGNAME were not - honored. Now they are. - -* extra line inserted by do_editor() is gone. Then obviated. Editor - is now called exactly once per checkin. - -* revised editor behaviour. Never use /dev/tty. If the editor - session fails, we haven't yet done anything. Therefor the user can - safely rerun cvs and we should just fail. Also use the editor for - initial log messages on added files. Also omit the confirmation - when adding directories. Adding directories will require an - explicit "commit" step soon. Make it possible to prevent null login - messages using #define REQUIRE_LOG_MESSAGES - -* prototypes for all callbacks. - -* all callbacks get ref pointers. - -* do_recursion/start_recursion now use recusion_frame's rather than a - list of a lot of pointers and global variables. - -* corrected types on status_dirproc(). - -* CONFIRM_DIRECTORY_ADDS - -* re_comp was innappropriate in a few places. I've eliminated it. - -* FORCE_MESSAGE_ON_ADD - -* So I built a regression test. Let's call it a sanity check to be - less ambitious. It exposed that cvs is difficult to call from - scripts. - diff --git a/gnu/usr.bin/cvs/cvs/README-rm-add b/gnu/usr.bin/cvs/cvs/README-rm-add deleted file mode 100644 index 17c721f..0000000 --- a/gnu/usr.bin/cvs/cvs/README-rm-add +++ /dev/null @@ -1,48 +0,0 @@ -WHAT THE "DEATH SUPPORT" FEATURES DO: - -(this really should be in the main manual, but noone has gotten around -to updating it). - -CVS with death support can record when a file is active, or alive, and -when it is removed, or dead. With this facility you can record the -history of a file, including the fact that at some point in its life -the file was removed and then later added. - -First, the following now works as expected: - - touch foo - cvs add foo ; cvs ci -m "added" foo - rm foo - cvs rm foo ; cvs ci -m "removed" foo - touch foo - cvs add foo ; cvs ci -m "resurrected" foo - -Second, files can now be added or removed in a branch and later merged -into the trunk. - - cvs update -A - touch a b c - cvs add a b c ; cvs ci -m "added" a b c - cvs tag -b branchtag - cvs update -r branchtag - touch d ; cvs add d - rm a ; cvs rm a - cvs ci -m "added d, removed a" - cvs update -A - cvs update -jbranchtag - -Added and removed files may also be merged between branches. - -Files removed in the trunk may be merged into branches. - -Files added on the trunk are a special case. They cannot be merged -into a branch. Instead, simply branch the file by hand. - -I also extended the "cvs update -j" semantic slightly. Like before, -if you use two -j options, the changes made between the first and the -second will be merged into your working files. This has not changed. - -If you use only one -j option, it is used as the second -j option. -The first is assumed to be the greatest common ancestor revision -between the revision specified by the -j and the BASE revision of your -working file. diff --git a/gnu/usr.bin/cvs/cvs/add.c b/gnu/usr.bin/cvs/cvs/add.c deleted file mode 100644 index f798a22..0000000 --- a/gnu/usr.bin/cvs/cvs/add.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * 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. - * - * Add - * - * Adds a file or directory to the RCS source repository. For a file, - * the entry is marked as "needing to be added" in the user's own CVS - * directory, and really added to the repository when it is committed. - * For a directory, it is added at the appropriate place in the source - * repository and a CVS directory is generated within the directory. - * - * The -m option is currently the only supported option. Some may wish to - * supply standard "rcs" options here, but I've found that this causes more - * trouble than anything else. - * - * The user files or directories must already exist. For a directory, it must - * not already have a CVS file in it. - * - * An "add" on a file that has been "remove"d but not committed will cause the - * file to be resurrected. - */ - -#include "cvs.h" -#include "save-cwd.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)add.c 1.55 94/10/22 $"; -USE(rcsid); -#endif - -static int add_directory PROTO((char *repository, char *dir)); -static int build_entry PROTO((char *repository, char *user, char *options, - char *message, List * entries, char *tag)); - -static const char *const add_usage[] = -{ - "Usage: %s %s [-k rcs-kflag] [-m message] files...\n", - "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n", - "\t-m\tUse \"message\" for the creation log.\n", - NULL -}; - -int -add (argc, argv) - int argc; - char **argv; -{ - char *message = NULL; - char *user; - int i; - char *repository; - int c; - int err = 0; - int added_files = 0; - char *options = NULL; - List *entries; - Vers_TS *vers; - - if (argc == 1 || argc == -1) - usage (add_usage); - - wrap_setup (); - - /* parse args */ - optind = 1; - while ((c = getopt (argc, argv, "k:m:")) != -1) - { - switch (c) - { - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - - case 'm': - message = xstrdup (optarg); - break; - case '?': - default: - usage (add_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (argc <= 0) - usage (add_usage); - - /* find the repository associated with our current dir */ - repository = Name_Repository ((char *) NULL, (char *) NULL); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - int i; - start_server (); - ign_setup (); - 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 - conditions which are only detected once the server gets its - hands on things? */ - if (isdir (argv[i])) - { - char *tag; - char *date; - char *rcsdir = xmalloc (strlen (repository) - + strlen (argv[i]) + 10); - - /* before we do anything else, see if we have any - per-directory tags */ - ParseTag (&tag, &date); - - sprintf (rcsdir, "%s/%s", repository, argv[i]); - - Create_Admin (argv[i], argv[i], rcsdir, tag, date); - - if (tag) - free (tag); - if (date) - free (date); - free (rcsdir); - } - send_files (argc, argv, 0, 0); - if (fprintf (to_server, "add\n") < 0) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } -#endif - - entries = Entries_Open (0); - - /* walk the arg list adding files/dirs */ - for (i = 0; i < argc; i++) - { - int begin_err = err; - int begin_added_files = added_files; - - user = argv[i]; - strip_trailing_slashes (user); - if (strchr (user, '/') != NULL) - { - error (0, 0, - "cannot add files with '/' in their name; %s not added", user); - err++; - continue; - } - - vers = Version_TS (repository, options, (char *) NULL, (char *) NULL, - user, 0, 0, entries, (List *) NULL); - if (vers->vn_user == NULL) - { - /* No entry available, ts_rcs is invalid */ - if (vers->vn_rcs == NULL) - { - /* There is no RCS file either */ - if (vers->ts_user == NULL) - { - /* There is no user file either */ - error (0, 0, "nothing known about %s", user); - err++; - } - else if (!isdir (user) || wrap_name_has (user, WRAP_TOCVS)) - { - /* - * See if a directory exists in the repository with - * the same name. If so, blow this request off. - */ - char dname[PATH_MAX]; - (void) sprintf (dname, "%s/%s", repository, user); - if (isdir (dname)) - { - error (0, 0, - "cannot add file `%s' since the directory", - user); - error (0, 0, "`%s' already exists in the repository", - dname); - error (1, 0, "illegal filename overlap"); - } - - /* There is a user file, so build the entry for it */ - if (build_entry (repository, user, vers->options, - message, entries, vers->tag) != 0) - err++; - else - { - added_files++; - if (!quiet) - { -#ifdef DEATH_SUPPORT - if (vers->tag) - error (0, 0, "\ -scheduling %s `%s' for addition on branch `%s'", - (wrap_name_has (user, WRAP_TOCVS) - ? "wrapper" - : "file"), - user, vers->tag); - else -#endif /* DEATH_SUPPORT */ - error (0, 0, "scheduling %s `%s' for addition", - (wrap_name_has (user, WRAP_TOCVS) - ? "wrapper" - : "file"), - user); - } - } - } - } -#ifdef DEATH_SUPPORT - else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - if (isdir (user) && !wrap_name_has (user, WRAP_TOCVS)) - { - error (0, 0, "the directory `%s' cannot be added because a file of the", user); - error (1, 0, "same name already exists in the repository."); - } - else - { - if (vers->tag) - error (0, 0, "file `%s' will be added on branch `%s' from version %s", - user, vers->tag, vers->vn_rcs); - else - error (0, 0, "version %s of `%s' will be resurrected", - vers->vn_rcs, user); - Register (entries, user, "0", vers->ts_user, NULL, - vers->tag, NULL, NULL); - ++added_files; - } - } -#endif /* DEATH_SUPPORT */ - else - { - /* - * There is an RCS file already, so somebody else must've - * added it - */ - error (0, 0, "%s added independently by second party", user); - err++; - } - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - - /* - * An entry for a new-born file, ts_rcs is dummy, but that is - * inappropriate here - */ - error (0, 0, "%s has already been entered", user); - err++; - } - else if (vers->vn_user[0] == '-') - { - /* An entry for a removed file, ts_rcs is invalid */ - if (vers->ts_user == NULL) - { - /* There is no user file (as it should be) */ - if (vers->vn_rcs == NULL) - { - - /* - * There is no RCS file, so somebody else must've removed - * it from under us - */ - error (0, 0, - "cannot resurrect %s; RCS file removed by second party", user); - err++; - } - else - { - - /* - * There is an RCS file, so remove the "-" from the - * version number and restore the file - */ - char *tmp = xmalloc (strlen (user) + 50); - - (void) strcpy (tmp, vers->vn_user + 1); - (void) strcpy (vers->vn_user, tmp); - (void) sprintf (tmp, "Resurrected %s", user); - Register (entries, user, vers->vn_user, tmp, vers->options, - vers->tag, vers->date, vers->ts_conflict); - free (tmp); - - /* XXX - bugs here; this really resurrect the head */ - /* Note that this depends on the Register above actually - having written Entries, or else it won't really - check the file out. */ - if (update (2, argv + i - 1) == 0) - { - error (0, 0, "%s, version %s, resurrected", user, - vers->vn_user); - } - else - { - error (0, 0, "could not resurrect %s", user); - err++; - } - } - } - else - { - /* The user file shouldn't be there */ - error (0, 0, "%s should be removed and is still there (or is back again)", user); - err++; - } - } - else - { - /* A normal entry, ts_rcs is valid, so it must already be there */ - error (0, 0, "%s already exists, with version number %s", user, - vers->vn_user); - err++; - } - freevers_ts (&vers); - - /* passed all the checks. Go ahead and add it if its a directory */ - if (begin_err == err - && isdir (user) - && !wrap_name_has (user, WRAP_TOCVS)) - { - err += add_directory (repository, user); - continue; - } -#ifdef SERVER_SUPPORT - if (server_active && begin_added_files != added_files) - server_checked_in (user, ".", repository); -#endif - } - if (added_files) - error (0, 0, "use 'cvs commit' to add %s permanently", - (added_files == 1) ? "this file" : "these files"); - - Entries_Close (entries); - - if (message) - free (message); - - return (err); -} - -/* - * The specified user file is really a directory. So, let's make sure that - * it is created in the RCS source repository, and that the user's directory - * is updated to include a CVS directory. - * - * Returns 1 on failure, 0 on success. - */ -static int -add_directory (repository, dir) - char *repository; - char *dir; -{ - char rcsdir[PATH_MAX]; - struct saved_cwd cwd; - char message[PATH_MAX + 100]; - char *tag, *date; - - if (strchr (dir, '/') != NULL) - { - error (0, 0, - "directory %s not added; must be a direct sub-directory", dir); - return (1); - } - if (strcmp (dir, CVSADM) == 0) - { - error (0, 0, "cannot add a `%s' directory", CVSADM); - return (1); - } - - /* before we do anything else, see if we have any per-directory tags */ - ParseTag (&tag, &date); - - /* now, remember where we were, so we can get back */ - if (save_cwd (&cwd)) - return (1); - if (chdir (dir) < 0) - { - error (0, errno, "cannot chdir to %s", dir); - return (1); - } -#ifdef SERVER_SUPPORT - if (!server_active && isfile (CVSADM)) -#else - if (isfile (CVSADM)) -#endif - { - error (0, 0, "%s/%s already exists", dir, CVSADM); - goto out; - } - - (void) sprintf (rcsdir, "%s/%s", repository, dir); - if (isfile (rcsdir) && !isdir (rcsdir)) - { - error (0, 0, "%s is not a directory; %s not added", rcsdir, dir); - goto out; - } - - /* setup the log message */ - (void) sprintf (message, "Directory %s added to the repository\n", rcsdir); - if (tag) - { - (void) strcat (message, "--> Using per-directory sticky tag `"); - (void) strcat (message, tag); - (void) strcat (message, "'\n"); - } - if (date) - { - (void) strcat (message, "--> Using per-directory sticky date `"); - (void) strcat (message, date); - (void) strcat (message, "'\n"); - } - - if (!isdir (rcsdir)) - { - mode_t omask; - Node *p; - List *ulist; - -#if 0 - char line[MAXLINELEN]; - - (void) printf ("Add directory %s to the repository (y/n) [n] ? ", - rcsdir); - (void) fflush (stdout); - clearerr (stdin); - if (fgets (line, sizeof (line), stdin) == NULL || - (line[0] != 'y' && line[0] != 'Y')) - { - error (0, 0, "directory %s not added", rcsdir); - goto out; - } -#endif - - omask = umask (cvsumask); - if (CVS_MKDIR (rcsdir, 0777) < 0) - { - error (0, errno, "cannot mkdir %s", rcsdir); - (void) umask (omask); - goto out; - } - (void) umask (omask); - - /* - * Set up an update list with a single title node for Update_Logfile - */ - ulist = getlist (); - p = getnode (); - p->type = UPDATE; - p->delproc = update_delproc; - p->key = xstrdup ("- New directory"); - p->data = (char *) T_TITLE; - (void) addnode (ulist, p); - Update_Logfile (rcsdir, message, (char *) NULL, (FILE *) NULL, ulist); - dellist (&ulist); - } - -#ifdef SERVER_SUPPORT - if (!server_active) - Create_Admin (".", dir, rcsdir, tag, date); -#else - Create_Admin (".", dir, rcsdir, tag, date); -#endif - if (tag) - free (tag); - if (date) - free (date); - - (void) printf ("%s", message); -out: - if (restore_cwd (&cwd, NULL)) - exit (1); - free_cwd (&cwd); - return (0); -} - -/* - * Builds an entry for a new file and sets up "CVS/file",[pt] by - * interrogating the user. Returns non-zero on error. - */ -static int -build_entry (repository, user, options, message, entries, tag) - char *repository; - char *user; - char *options; - char *message; - List *entries; - char *tag; -{ - char fname[PATH_MAX]; - char line[MAXLINELEN]; - FILE *fp; - -#ifndef DEATH_SUPPORT - /* when using the rcs death support, this case is not a problem. */ - /* - * There may be an old file with the same name in the Attic! This is, - * perhaps, an awkward place to check for this, but other places are - * equally awkward. - */ - (void) sprintf (fname, "%s/%s/%s%s", repository, CVSATTIC, user, RCSEXT); - if (isreadable (fname)) - { - error (0, 0, "there is an old file %s already in %s/%s", user, - repository, CVSATTIC); - return (1); - } -#endif /* no DEATH_SUPPORT */ - - if (noexec) - return (0); - - /* - * 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). - */ - (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG); - fp = open_file (fname, "w+"); - if (message && fputs (message, fp) == EOF) - error (1, errno, "cannot write to %s", fname); - if (fclose(fp) == EOF) - error(1, errno, "cannot close %s", fname); - - /* - * 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 - * ,t file, but who cares). - */ - (void) sprintf (line, "Initial %s", user); - Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0); - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/admin.c b/gnu/usr.bin/cvs/cvs/admin.c deleted file mode 100644 index f12e143..0000000 --- a/gnu/usr.bin/cvs/cvs/admin.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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. - * - * Administration - * - * For now, this is basically a front end for rcs. All options are passed - * directly on. - */ - -#include "cvs.h" -#ifdef CVS_ADMIN_GROUP -#include <grp.h> -#endif - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)admin.c 1.20 94/09/30 $"; -USE(rcsid); -#endif - -static Dtype admin_dirproc PROTO((char *dir, char *repos, char *update_dir)); -static int admin_fileproc PROTO((char *file, char *update_dir, - char *repository, List *entries, - List *srcfiles)); - -static const char *const admin_usage[] = -{ - "Usage: %s %s rcs-options files...\n", - NULL -}; - -static int ac; -static char **av; - -int -admin (argc, argv) - int argc; - 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 */ - for (ac = 1; ac < argc; ac++) - if (argv[ac][0] != '-') - break; - argc -= ac; - av = argv + 1; - argv += ac; - ac--; - if (ac == 0 || argc == 0) - usage (admin_usage); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - int i; - - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - for (i = 0; i <= ac; ++i) /* XXX send -ko too with i = 0 */ - send_arg (av[i]); - -#if 0 - /* 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"); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - /* start the recursion processor */ - err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc, - (DIRLEAVEPROC) NULL, argc, argv, 0, - W_LOCAL, 0, 1, (char *) NULL, 1, 0); - return (err); -} - -/* - * Called to run "rcs" on a particular file. - */ -/* ARGSUSED */ -static int -admin_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Vers_TS *vers; - char *version; - char **argv; - int argc; - int retcode = 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); - else if (strcmp (version, "0") == 0) - { - error (0, 0, "cannot admin newly added file `%s'", file); - return (0); - } - - run_setup ("%s%s", Rcsbin, RCS); - for (argc = ac, argv = av; argc; argc--, argv++) - run_arg (*argv); - run_arg (vers->srcfile->path); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "%s failed for `%s'", RCS, file); - return (1); - } - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -admin_dirproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "Administrating %s", update_dir); - return (R_PROCESS); -} diff --git a/gnu/usr.bin/cvs/cvs/checkin.c b/gnu/usr.bin/cvs/cvs/checkin.c deleted file mode 100644 index ef3b81a..0000000 --- a/gnu/usr.bin/cvs/cvs/checkin.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - * - * Check In - * - * Does a very careful checkin of the file "user", and tries not to spoil its - * modification time (to avoid needless recompilations). When RCS ID keywords - * get expanded on checkout, however, the modification time is updated and - * there is no good way to get around this. - * - * Returns non-zero on error. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)checkin.c 1.48 94/10/07 $"; -USE(rcsid); -#endif - -int -Checkin (type, file, update_dir, repository, - rcs, rev, tag, options, message, entries) - int type; - char *file; - char *update_dir; - char *repository; - char *rcs; - char *rev; - char *tag; - char *options; - char *message; - List *entries; -{ - char fname[PATH_MAX]; - Vers_TS *vers; - int set_time; - char *fullname; - - char *tocvsPath = NULL; - - fullname = xmalloc (strlen (update_dir) + strlen (file) + 10); - if (update_dir[0] == '\0') - strcpy (fullname, file); - else - sprintf (fullname, "%s/%s", update_dir, file); - - (void) printf ("Checking in %s;\n", fullname); - (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file); - - /* - * Move the user file to a backup file, so as to preserve its - * modification times, then place a copy back in the original file name - * for the checkin and checkout. - */ - - tocvsPath = wrap_tocvs_process_file (fullname); - - if (!noexec) - { - if (tocvsPath) - { - copy_file (tocvsPath, fname); - if (unlink_file_dir (file) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", file); - copy_file (tocvsPath, file); - } - else - { - copy_file (file, fname); - } - } - - run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI, - rev ? "-r" : "", rev ? rev : ""); - run_args ("-m%s", make_message_rcslegal (message)); - run_arg (rcs); - - switch (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) - { - case 0: /* everything normal */ - - /* - * The checkin succeeded, so now check the new file back out and - * see if it matches exactly with the one we checked in. If it - * does, just move the original user file back, thus preserving - * the modes; otherwise, we have no recourse but to leave the - * newly checkout file as the user file and remove the old - * original user file. - */ - - if (strcmp (options, "-V4") == 0) /* upgrade to V5 now */ - options[0] = '\0'; - run_setup ("%s%s -q %s %s%s", Rcsbin, RCS_CO, options, - rev ? "-r" : "", rev ? rev : ""); - run_arg (rcs); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - xchmod (file, 1); - if (xcmp (file, fname) == 0) - { - rename_file (fname, file); - /* the time was correct, so leave it alone */ - set_time = 0; - } - else - { - if (unlink_file (fname) < 0) - error (0, errno, "cannot remove %s", fname); - /* sync up with the time from the RCS file */ - set_time = 1; - } - - wrap_fromcvs_process_file (file); - - /* - * If we want read-only files, muck the permissions here, before - * getting the file time-stamp. - */ - if (cvswrite == FALSE) - xchmod (file, 0); - -#ifndef DEATH_SUPPORT - /* With death_support, files added with tags go into branches immediately. */ - - /* for added files with symbolic tags, need to add the tag too */ - if (type == 'A' && tag && !isdigit (*tag)) - { - (void) RCS_settag(rcs, tag, rev); - } -#endif /* No DEATH_SUPPORT */ - - /* re-register with the new data */ - vers = Version_TS (repository, (char *) NULL, tag, (char *) NULL, - file, 1, set_time, entries, (List *) NULL); - if (strcmp (vers->options, "-V4") == 0) - vers->options[0] = '\0'; - Register (entries, file, vers->vn_rcs, vers->ts_user, - vers->options, vers->tag, vers->date, (char *) 0); - history_write (type, (char *) 0, vers->vn_rcs, file, repository); - freevers_ts (&vers); - - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - break; - - case -1: /* fork failed */ - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - if (!noexec) - error (1, errno, "could not check in %s -- fork failed", - fullname); - return (1); - - default: /* ci failed */ - - /* - * The checkin failed, for some unknown reason, so we restore the - * original user file, print an error, and return an error - */ - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - if (!noexec) - { - rename_file (fname, file); - error (0, 0, "could not check in %s", fullname); - } - return (1); - } - - /* - * When checking in a specific revision, we may have locked the wrong - * branch, so to be sure, we do an extra unlock here before - * returning. - */ - if (rev) - { - (void) RCS_unlock (rcs, NULL, 1); - } - -#ifdef SERVER_SUPPORT - if (server_active) - { - if (set_time) - /* Need to update the checked out file on the client side. */ - server_updated (file, update_dir, repository, SERVER_UPDATED, - NULL, NULL); - else - server_checked_in (file, update_dir, repository); - } -#endif - - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/checkout.c b/gnu/usr.bin/cvs/cvs/checkout.c deleted file mode 100644 index bb126dd..0000000 --- a/gnu/usr.bin/cvs/cvs/checkout.c +++ /dev/null @@ -1,874 +0,0 @@ -/* - * 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. - * - * Create Version - * - * "checkout" creates a "version" of an RCS repository. This version is owned - * totally by the user and is actually an independent copy, to be dealt with - * as seen fit. Once "checkout" has been called in a given directory, it - * never needs to be called again. The user can keep up-to-date by calling - * "update" when he feels like it; this will supply him with a merge of his - * own modifications and the changes made in the RCS original. See "update" - * for details. - * - * "checkout" can be given a list of directories or files to be updated and in - * the case of a directory, will recursivley create any sub-directories that - * exist in the repository. - * - * When the user is satisfied with his own modifications, the present version - * can be committed by "commit"; this keeps the present version in tact, - * usually. - * - * The call is cvs checkout [options] <module-name>... - * - * "checkout" creates a directory ./CVS, in which it keeps its administration, - * in two files, Repository and Entries. The first contains the name of the - * repository. The second contains one line for each registered file, - * consisting of the version number it derives from, its time stamp at - * derivation time and its name. Both files are normal files and can be - * edited by the user, if necessary (when the repository is moved, e.g.) - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)checkout.c 1.78 94/10/07 $"; -USE(rcsid); -#endif - -static char *findslash PROTO((char *start, char *p)); -static int build_dirs_and_chdir PROTO((char *dir, char *prepath, char *realdir, - int sticky)); -static int checkout_proc PROTO((int *pargc, char **argv, char *where, - char *mwhere, char *mfile, int shorten, - int local_specified, char *omodule, - char *msg)); -static int safe_location PROTO((void)); - -static const char *const checkout_usage[] = -{ - "Usage:\n %s %s [-ANPcflnps] [-r rev | -D date] [-d dir] [-k kopt] modules...\n", - "\t-A\tReset any sticky tags/date/kopts.\n", - "\t-N\tDon't shorten module paths if -d specified.\n", - "\t-P\tPrune empty directories.\n", - "\t-c\t\"cat\" the module database.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-n\tDo not run module program (if any).\n", - "\t-p\tCheck out files to standard output.\n", - "\t-s\tLike -c, but include module status.\n", - "\t-r rev\tCheck out revision or tag. (implies -P)\n", - "\t-D date\tCheck out revisions as of date. (implies -P)\n", - "\t-d dir\tCheck out into dir instead of module name.\n", - "\t-k kopt\tUse RCS kopt -k option on checkout.\n", - "\t-j rev\tMerge in changes made between current revision and rev.\n", - NULL -}; - -static const char *const export_usage[] = -{ - "Usage: %s %s [-NPfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n", - "\t-N\tDon't shorten module paths if -d specified.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-n\tDo not run module program (if any).\n", - "\t-r rev\tCheck out revision or tag.\n", - "\t-D date\tCheck out revisions as of date.\n", - "\t-d dir\tCheck out into dir instead of module name.\n", - "\t-k kopt\tUse RCS kopt -k option on checkout.\n", - NULL -}; - -static int checkout_prune_dirs; -static int force_tag_match = 1; -static int pipeout; -static int aflag; -static char *options = NULL; -static char *tag = NULL; -static char *date = NULL; -static char *join_rev1 = NULL; -static char *join_rev2 = NULL; -static char *preload_update_dir = NULL; - -int -checkout (argc, argv) - int argc; - char **argv; -{ - int i; - int c; - DBM *db; - int cat = 0, err = 0, status = 0; - int run_module_prog = 1; - int local = 0; - int shorten = -1; - char *where = NULL; - char *valid_options; - const char *const *valid_usage; - enum mtype m_type; - - /* - * A smaller subset of options are allowed for the export command, which - * is essentially like checkout, except that it hard-codes certain - * options to be default (like -kv) and takes care to remove the CVS - * directory when it has done its duty - */ - if (strcmp (command_name, "export") == 0) - { - m_type = EXPORT; - valid_options = "Nnk:d:flRQqr:D:"; - valid_usage = export_usage; - } - else - { - m_type = CHECKOUT; - valid_options = "ANnk:d:flRpQqcsr:D:j:P"; - valid_usage = checkout_usage; - } - - if (argc == -1) - usage (valid_usage); - - ign_setup (); - wrap_setup (); - - optind = 1; - while ((c = getopt (argc, argv, valid_options)) != -1) - { - switch (c) - { - case 'A': - aflag = 1; - break; - case 'N': - shorten = 0; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'n': - run_module_prog = 0; - break; - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'P': - checkout_prune_dirs = 1; - break; - case 'p': - pipeout = 1; - run_module_prog = 0; /* don't run module prog when piping */ - noexec = 1; /* so no locks will be created */ - break; - case 'c': - cat = 1; - break; - case 'd': - where = optarg; - if (shorten == -1) - shorten = 1; - break; - case 's': - status = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'r': - tag = optarg; - checkout_prune_dirs = 1; - break; - case 'D': - date = Make_Date (optarg); - checkout_prune_dirs = 1; - break; - case 'j': - if (join_rev2) - error (1, 0, "only two -j options can be specified"); - if (join_rev1) - join_rev2 = optarg; - else - join_rev1 = optarg; - break; - case '?': - default: - usage (valid_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (shorten == -1) - shorten = 0; - - if ((!(cat + status) && argc == 0) || ((cat + status) && argc != 0) - || (tag && date)) - usage (valid_usage); - - if (where && pipeout) - error (1, 0, "-d and -p are mutually exclusive"); - - if (strcmp (command_name, "export") == 0) - { - if (!tag && !date) - { - error (0, 0, "must specify a tag or date"); - usage (valid_usage); - } - if (tag && isdigit (tag[0])) - error (1, 0, "tag `%s' must be a symbolic tag", tag); -/* - * mhy 950615: -kv doesn't work for binaries with RCS keywords. - * Instead use the default provided in the RCS file (-ko for binaries). - */ -#if 0 - if (!options) - options = RCS_check_kflag ("v");/* -kv is default */ -#endif - } - - if (!safe_location()) { - error(1, 0, "Cannot check out files into the repository itself"); - } - -#ifdef CLIENT_SUPPORT - if (client_active) - { - int expand_modules; - - start_server (); - - ign_setup (); - - /* We have to expand names here because the "expand-modules" - directive to the server has the side-effect of having the - server send the check-in and update programs for the - various modules/dirs requested. If we turn this off and - simply request the names of the modules and directories (as - below in !expand_modules), those files (CVS/Checking.prog - or CVS/Update.prog) don't get created. Grrr. */ - - expand_modules = (!cat && !status && !pipeout - && supported_request ("expand-modules")); - - if (expand_modules) - { - /* This is done here because we need to read responses - from the server before we send the command checkout or - export files. */ - - client_expand_modules (argc, argv, local); - } - - if (!run_module_prog) send_arg ("-n"); - if (local) send_arg ("-l"); - if (pipeout) send_arg ("-p"); - if (!force_tag_match) send_arg ("-f"); - if (aflag) - send_arg("-A"); - if (!shorten) - send_arg("-N"); - if (checkout_prune_dirs && strcmp (command_name, "export") != 0) - send_arg("-P"); - client_prune_dirs = checkout_prune_dirs; - if (cat) - send_arg("-c"); - if (where != NULL) - { - option_with_arg ("-d", where); - } - if (status) - send_arg("-s"); - if (strcmp (command_name, "export") != 0 - && options != NULL - && options[0] != '\0') - send_arg (options); - option_with_arg ("-r", tag); - if (date) - client_senddate (date); - if (join_rev1 != NULL) - option_with_arg ("-j", join_rev1); - if (join_rev2 != NULL) - option_with_arg ("-j", join_rev2); - - if (expand_modules) - { - client_send_expansions (local); - } - else - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - client_nonexpanded_setup (); - } - - if (fprintf - (to_server, - strcmp (command_name, "export") == 0 ? "export\n" : "co\n") - < 0) - error (1, errno, "writing to server"); - - return get_responses_and_close (); - } -#endif - - if (cat || status) - { - cat_module (status); - return (0); - } - db = open_module (); - - /* - * if we have more than one argument and where was specified, we make the - * where, cd into it, and try to shorten names as much as possible. - * Otherwise, we pass the where as a single argument to do_module. - */ - if (argc > 1 && where != NULL) - { - char repository[PATH_MAX]; - - (void) CVS_MKDIR (where, 0777); - if (chdir (where) < 0) - error (1, errno, "cannot chdir to %s", where); - preload_update_dir = xstrdup (where); - where = (char *) NULL; - if (!isfile (CVSADM)) - { - (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)) - error (1, 0, "there is no repository %s", repository); - - Create_Admin (".", where, repository, - (char *) NULL, (char *) NULL); - if (!noexec) - { - FILE *fp; - - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose(fp) == EOF) - error(1, errno, "cannot close %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_entstat (preload_update_dir, repository); -#endif - } - } - } - - /* - * if where was specified (-d) and we have not taken care of it already - * with the multiple arg stuff, and it was not a simple directory name - * but rather a path, we strip off everything but the last component and - * attempt to cd to the indicated place. where then becomes simply the - * last component - */ - if (where != NULL && strchr (where, '/') != NULL) - { - char *slash; - - slash = strrchr (where, '/'); - *slash = '\0'; - - if (chdir (where) < 0) - error (1, errno, "cannot chdir to %s", where); - - preload_update_dir = xstrdup (where); - - where = slash + 1; - if (*where == '\0') - where = NULL; - } - - for (i = 0; i < argc; i++) - err += do_module (db, argv[i], m_type, "Updating", checkout_proc, - where, shorten, local, run_module_prog, - (char *) NULL); - close_module (db); - return (err); -} - -static int -safe_location () -{ - char current[PATH_MAX]; - char hardpath[PATH_MAX+5]; - int x; - - x = readlink(CVSroot, hardpath, sizeof hardpath - 1); - if (x == -1) - { - strcpy(hardpath, CVSroot); - } - hardpath[x] = '\0'; - getwd (current); - if (strncmp(current, hardpath, strlen(hardpath)) == 0) - { - return (0); - } - return (1); -} - -/* - * process_module calls us back here so we do the actual checkout stuff - */ -/* ARGSUSED */ -static int -checkout_proc (pargc, argv, where, mwhere, mfile, shorten, - local_specified, omodule, msg) - int *pargc; - char **argv; - char *where; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *omodule; - char *msg; -{ - int err = 0; - int which; - char *cp; - char *cp2; - char repository[PATH_MAX]; - char xwhere[PATH_MAX]; - char *oldupdate = NULL; - char *prepath; - char *realdirs; - - /* - * OK, so we're doing the checkout! Our args are as follows: - * argc,argv contain either dir or dir followed by a list of files - * where contains where to put it (if supplied by checkout) - * mwhere contains the module name or -d from module file - * mfile says do only that part of the module - * shorten = TRUE says shorten as much as possible - * omodule is the original arg to do_module() - */ - - /* set up the repository (maybe) for the bottom directory */ - (void) sprintf (repository, "%s/%s", CVSroot, argv[0]); - - /* save the original value of preload_update_dir */ - if (preload_update_dir != NULL) - oldupdate = xstrdup (preload_update_dir); - - /* fix up argv[] for the case of partial modules */ - if (mfile != NULL) - { - char file[PATH_MAX]; - - /* if mfile is really a path, straighten it out first */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = 0; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - - /* - * Now we need to fill in the where correctly. if !shorten, tack - * the rest of the path onto where if where is filled in - * otherwise tack the rest of the path onto mwhere and make that - * the where - * - * If shorten is enabled, we might use mwhere to set where if - * nobody set it yet, so we'll need to setup mwhere as the last - * component of the path we are tacking onto repository - */ - if (!shorten) - { - if (where != NULL) - (void) sprintf (xwhere, "%s/%s", where, mfile); - else - (void) sprintf (xwhere, "%s/%s", mwhere, mfile); - where = xwhere; - } - else - { - char *slash; - - if ((slash = strrchr (mfile, '/')) != NULL) - mwhere = slash + 1; - else - mwhere = mfile; - } - mfile = cp + 1; - } - - (void) sprintf (file, "%s/%s", repository, mfile); - if (isdir (file)) - { - - /* - * The portion of a module was a directory, so kludge up where to - * be the subdir, and fix up repository - */ - (void) strcpy (repository, file); - - /* - * At this point, if shorten is not enabled, we make where either - * where with mfile concatenated, or if where hadn't been set we - * set it to mwhere with mfile concatenated. - * - * If shorten is enabled and where hasn't been set yet, then where - * becomes mfile - */ - if (!shorten) - { - if (where != NULL) - (void) sprintf (xwhere, "%s/%s", where, mfile); - else - (void) sprintf (xwhere, "%s/%s", mwhere, mfile); - where = xwhere; - } - else if (where == NULL) - where = mfile; - } - else - { - int i; - - /* - * The portion of a module was a file, so kludge up argv to be - * correct - */ - for (i = 1; i < *pargc; i++)/* free the old ones */ - free (argv[i]); - argv[1] = xstrdup (mfile); /* set up the new one */ - *pargc = 2; - - /* where gets mwhere if where isn't set */ - if (where == NULL) - where = mwhere; - } - } - - /* - * if shorten is enabled and where isn't specified yet, we pluck the last - * directory component of argv[0] and make it the where - */ - if (shorten && where == NULL) - { - if ((cp = strrchr (argv[0], '/')) != NULL) - { - (void) strcpy (xwhere, cp + 1); - where = xwhere; - } - } - - /* if where is still NULL, use mwhere if set or the argv[0] dir */ - if (where == NULL) - { - if (mwhere) - where = mwhere; - else - { - (void) strcpy (xwhere, argv[0]); - where = xwhere; - } - } - - if (preload_update_dir != NULL) - { - char tmp[PATH_MAX]; - - (void) sprintf (tmp, "%s/%s", preload_update_dir, where); - free (preload_update_dir); - preload_update_dir = xstrdup (tmp); - } - else - preload_update_dir = xstrdup (where); - - /* - * At this point, where is the directory we want to build, repository is - * the repository for the lowest level of the path. - */ - - /* - * If we are sending everything to stdout, we can skip a whole bunch of - * work from here - */ - if (!pipeout) - { - - /* - * We need to tell build_dirs not only the path we want it to build, - * but also the repositories we want it to populate the path with. To - * accomplish this, we pass build_dirs a ``real path'' with valid - * repositories and a string to pre-pend based on how many path - * elements exist in where. Big Black Magic - */ - prepath = xstrdup (repository); - cp = strrchr (where, '/'); - cp2 = strrchr (prepath, '/'); - while (cp != NULL) - { - cp = findslash (where, cp - 1); - cp2 = findslash (prepath, cp2 - 1); - } - *cp2 = '\0'; - realdirs = cp2 + 1; - - /* - * build dirs on the path if necessary and leave us in the bottom - * directory (where if where was specified) doesn't contain a CVS - * subdir yet, but all the others contain CVS and Entries.Static - * files - */ - if (build_dirs_and_chdir (where, prepath, realdirs, *pargc <= 1) != 0) - { - error (0, 0, "ignoring module %s", omodule); - free (prepath); - free (preload_update_dir); - preload_update_dir = oldupdate; - return (1); - } - - /* clean up */ - free (prepath); - - /* set up the repository (or make sure the old one matches) */ - if (!isfile (CVSADM)) - { - FILE *fp; - - if (!noexec && *pargc > 1) - { - /* I'm not sure whether this check is redundant. */ - if (!isdir (repository)) - error (1, 0, "there is no repository %s", repository); - - Create_Admin (".", where, repository, - (char *) NULL, (char *) NULL); - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose(fp) == EOF) - error(1, errno, "cannot close %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_entstat (where, repository); -#endif - } - else - { - /* I'm not sure whether this check is redundant. */ - if (!isdir (repository)) - error (1, 0, "there is no repository %s", repository); - - Create_Admin (".", where, repository, tag, date); - } - } - else - { - char *repos; - - /* get the contents of the previously existing repository */ - repos = Name_Repository ((char *) NULL, preload_update_dir); - if (fncmp (repository, repos) != 0) - { - error (0, 0, "existing repository %s does not match %s", - repos, repository); - error (0, 0, "ignoring module %s", omodule); - free (repos); - free (preload_update_dir); - preload_update_dir = oldupdate; - return (1); - } - free (repos); - } - } - - /* - * If we are going to be updating to stdout, we need to cd to the - * repository directory so the recursion processor can use the current - * directory as the place to find repository information - */ - if (pipeout) - { - if (chdir (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - free (preload_update_dir); - preload_update_dir = oldupdate; - return (1); - } - which = W_REPOS; - } - else - which = W_LOCAL | W_REPOS; - - if (tag != NULL || date != NULL) - which |= W_ATTIC; - - /* - * if we are going to be recursive (building dirs), go ahead and call the - * update recursion processor. We will be recursive unless either local - * only was specified, or we were passed arguments - */ - if (!(local_specified || *pargc > 1)) - { - if (strcmp (command_name, "export") != 0 && !pipeout) - history_write ('O', preload_update_dir, tag ? tag : date, where, - repository); - err += do_update (0, (char **) NULL, options, tag, date, - force_tag_match, 0 /* !local */ , - 1 /* update -d */ , aflag, checkout_prune_dirs, - pipeout, which, join_rev1, join_rev2, - preload_update_dir); - free (preload_update_dir); - preload_update_dir = oldupdate; - return (err); - } - - if (!pipeout) - { - int i; - List *entries; - - /* we are only doing files, so register them */ - entries = Entries_Open (0); - for (i = 1; i < *pargc; i++) - { - char line[MAXLINELEN]; - char *user; - Vers_TS *vers; - - user = argv[i]; - vers = Version_TS (repository, options, tag, date, user, - force_tag_match, 0, entries, (List *) NULL); - if (vers->ts_user == NULL) - { - (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); - } - freevers_ts (&vers); - } - - Entries_Close (entries); - } - - /* Don't log "export", just regular "checkouts" */ - if (strcmp (command_name, "export") != 0 && !pipeout) - history_write ('O', preload_update_dir, (tag ? tag : date), where, - repository); - - /* go ahead and call update now that everything is set */ - err += do_update (*pargc - 1, argv + 1, options, tag, date, - force_tag_match, local_specified, 1 /* update -d */, - aflag, checkout_prune_dirs, pipeout, which, join_rev1, - join_rev2, preload_update_dir); - free (preload_update_dir); - preload_update_dir = oldupdate; - return (err); -} - -static char * -findslash (start, p) - char *start; - char *p; -{ - while (p >= start && *p != '/') - p--; - if (p < start) - return (NULL); - else - return (p); -} - -/* - * build all the dirs along the path to dir with CVS subdirs with appropriate - * repositories and Entries.Static files - */ -static int -build_dirs_and_chdir (dir, prepath, realdir, sticky) - char *dir; - char *prepath; - char *realdir; - int sticky; -{ - FILE *fp; - char repository[PATH_MAX]; - char path[PATH_MAX]; - char path2[PATH_MAX]; - char *slash; - char *slash2; - char *cp; - char *cp2; - - (void) strcpy (path, dir); - (void) strcpy (path2, realdir); - for (cp = path, cp2 = path2; - (slash = strchr (cp, '/')) != NULL && (slash2 = strchr (cp2, '/')) != NULL; - cp = slash + 1, cp2 = slash2 + 1) - { - *slash = '\0'; - *slash2 = '\0'; - (void) CVS_MKDIR (cp, 0777); - if (chdir (cp) < 0) - { - error (0, errno, "cannot chdir to %s", cp); - return (1); - } - if (!isfile (CVSADM) && strcmp (command_name, "export") != 0) - { - (void) sprintf (repository, "%s/%s", prepath, path2); - /* I'm not sure whether this check is redundant. */ - if (!isdir (repository)) - error (1, 0, "there is no repository %s", repository); - Create_Admin (".", cp, repository, sticky ? (char *) NULL : tag, - sticky ? (char *) NULL : date); - if (!noexec) - { - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose(fp) == EOF) - error(1, errno, "cannot close %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_entstat (path, repository); -#endif - } - } - *slash = '/'; - *slash2 = '/'; - } - (void) CVS_MKDIR (cp, 0777); - if (chdir (cp) < 0) - { - error (0, errno, "cannot chdir to %s", cp); - return (1); - } - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/classify.c b/gnu/usr.bin/cvs/cvs/classify.c deleted file mode 100644 index 23fafca..0000000 --- a/gnu/usr.bin/cvs/cvs/classify.c +++ /dev/null @@ -1,504 +0,0 @@ -/* - * 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. - * - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)classify.c 1.17 94/10/07 $"; -USE(rcsid); -#endif - -#ifdef SERVER_SUPPORT -static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, - List * entries, - char *repository, char *update_dir)); -#else -static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries)); -#endif - -/* - * Classify the state of a file - */ -Ctype -Classify_File (file, tag, date, options, force_tag_match, aflag, repository, - entries, srcfiles, versp, update_dir, pipeout) - char *file; - char *tag; - char *date; - char *options; - int force_tag_match; - int aflag; - char *repository; - List *entries; - List *srcfiles; - Vers_TS **versp; - char *update_dir; - int pipeout; -{ - Vers_TS *vers; - Ctype ret; - char *fullname; - - fullname = xmalloc (strlen (update_dir) + strlen (file) + 10); - if (update_dir[0] == '\0') - strcpy (fullname, file); - else - sprintf (fullname, "%s/%s", update_dir, file); - - /* get all kinds of good data about the file */ - vers = Version_TS (repository, options, tag, date, file, - force_tag_match, 0, entries, srcfiles); - - if (vers->vn_user == NULL) - { - /* No entry available, ts_rcs is invalid */ - if (vers->vn_rcs == NULL) - { - /* there is no RCS file either */ - if (vers->ts_user == NULL) - { - /* there is no user file */ - if (!force_tag_match || !(vers->tag || vers->date)) - if (!really_quiet) - error (0, 0, "nothing known about %s", fullname); - ret = T_UNKNOWN; - } - else - { - /* there is a user file */ - if (!force_tag_match || !(vers->tag || vers->date)) - if (!really_quiet) - error (0, 0, "use `cvs add' to create an entry for %s", - fullname); - ret = T_UNKNOWN; - } - } -#ifdef DEATH_SUPPORT - else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - if (vers->ts_user == NULL) - /* - * Logically seems to me this should be T_UPTODATE. - * But the joining code in update.c seems to expect - * T_CHECKOUT, and that is what has traditionally been - * returned for this case. - */ - ret = T_CHECKOUT; - else - { - error (0, 0, "use `cvs add' to create an entry for %s", - fullname); - ret = T_UNKNOWN; - } - } -#endif - else - { - /* there is an rcs file */ - - if (vers->ts_user == NULL) - { - /* There is no user file; needs checkout */ - ret = T_CHECKOUT; - } - else - { - if (pipeout) - { - /* - * The user file doesn't necessarily have anything - * to do with this. - */ - ret = T_CHECKOUT; - } - /* - * There is a user file; print a warning and add it to the - * conflict list, only if it is indeed different from what we - * plan to extract - */ - else if (No_Difference (file, vers, entries, - repository, update_dir)) - { - /* the files were different so it is a conflict */ - if (!really_quiet) - error (0, 0, "move away %s; it is in the way", - fullname); - ret = T_CONFLICT; - } - else - /* since there was no difference, still needs checkout */ - ret = T_CHECKOUT; - } - } - } - else if (strcmp (vers->vn_user, "0") == 0) - { - /* An entry for a new-born file; ts_rcs is dummy */ - - if (vers->ts_user == NULL) - { - /* - * There is no user file, but there should be one; remove the - * entry - */ - if (!really_quiet) - error (0, 0, "warning: new-born %s has disappeared", fullname); - ret = T_REMOVE_ENTRY; - } - else - { - /* There is a user file */ - - if (vers->vn_rcs == NULL) - /* There is no RCS file, added file */ - ret = T_ADDED; -#ifdef DEATH_SUPPORT - else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) - /* we are resurrecting. */ - ret = T_ADDED; -#endif /* DEATH_SUPPORT */ - else - { -#ifdef DEATH_SUPPORT - if (vers->srcfile->flags & INATTIC - && vers->srcfile->flags & VALID) - { - /* This file has been added on some branch other than - the one we are looking at. In the branch we are - looking at, the file was already valid. */ - if (!really_quiet) - error (0, 0, - "conflict: %s has been added, but already exists", - fullname); - } - else - { -#endif /* DEATH_SUPPORT */ - /* - * There is an RCS file, so someone else must have checked - * one in behind our back; conflict - */ - if (!really_quiet) - error (0, 0, - "conflict: %s created independently by second party", - fullname); -#ifdef DEATH_SUPPORT - } -#endif - ret = T_CONFLICT; - } - } - } - else if (vers->vn_user[0] == '-') - { - /* An entry for a removed file, ts_rcs is invalid */ - - if (vers->ts_user == NULL) - { - char tmp[PATH_MAX]; - - /* There is no user file (as it should be) */ - - (void) sprintf (tmp, "-%s", vers->vn_rcs ? vers->vn_rcs : ""); - - if (vers->vn_rcs == NULL) - { - - /* - * There is no RCS file; this is all-right, but it has been - * removed independently by a second party; remove the entry - */ - ret = T_REMOVE_ENTRY; - } - else if (strcmp (tmp, vers->vn_user) == 0) - - /* - * The RCS file is the same version as the user file was, and - * that's OK; remove it - */ - ret = T_REMOVED; - else - { - - /* - * The RCS file is a newer version than the removed user file - * and this is definitely not OK; make it a conflict. - */ - if (!really_quiet) - error (0, 0, - "conflict: removed %s was modified by second party", - fullname); - ret = T_CONFLICT; - } - } - else - { - /* The user file shouldn't be there */ - if (!really_quiet) - error (0, 0, "%s should be removed and is still there", - fullname); - ret = T_REMOVED; - } - } - else - { - /* A normal entry, TS_Rcs is valid */ - if (vers->vn_rcs == NULL) - { - /* There is no RCS file */ - - if (vers->ts_user == NULL) - { - /* There is no user file, so just remove the entry */ - if (!really_quiet) - error (0, 0, "warning: %s is not (any longer) pertinent", - fullname); - ret = T_REMOVE_ENTRY; - } - else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) - { - - /* - * The user file is still unmodified, so just remove it from - * the entry list - */ - if (!really_quiet) - error (0, 0, "%s is no longer in the repository", - fullname); - ret = T_REMOVE_ENTRY; - } - else - { - /* - * The user file has been modified and since it is no longer - * in the repository, a conflict is raised - */ - if (No_Difference (file, vers, entries, - repository, update_dir)) - { - /* they are different -> conflict */ - if (!really_quiet) - error (0, 0, - "conflict: %s is modified but no longer in the repository", - fullname); - ret = T_CONFLICT; - } - else - { - /* they weren't really different */ - if (!really_quiet) - error (0, 0, - "warning: %s is not (any longer) pertinent", - fullname); - ret = T_REMOVE_ENTRY; - } - } - } - else if (strcmp (vers->vn_rcs, vers->vn_user) == 0) - { - /* The RCS file is the same version as the user file */ - - if (vers->ts_user == NULL) - { - - /* - * There is no user file, so note that it was lost and - * extract a new version - */ - if (strcmp (command_name, "update") == 0) - if (!really_quiet) - error (0, 0, "warning: %s was lost", fullname); - ret = T_CHECKOUT; - } - else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) - { - - /* - * The user file is still unmodified, so nothing special at - * all to do -- no lists updated, unless the sticky -k option - * has changed. If the sticky tag has changed, we just need - * to re-register the entry - */ - if (vers->entdata->options && - strcmp (vers->entdata->options, vers->options) != 0) - ret = T_CHECKOUT; - else - { -#ifdef SERVER_SUPPORT - sticky_ck (file, aflag, vers, entries, - repository, update_dir); -#else - sticky_ck (file, aflag, vers, entries); -#endif - ret = T_UPTODATE; - } - } - else - { - - /* - * The user file appears to have been modified, but we call - * No_Difference to verify that it really has been modified - */ - if (No_Difference (file, vers, entries, - repository, update_dir)) - { - - /* - * they really are different; modified if we aren't - * changing any sticky -k options, else needs merge - */ -#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED - if (strcmp (vers->entdata->options ? - vers->entdata->options : "", vers->options) == 0) - ret = T_MODIFIED; - else - ret = T_NEEDS_MERGE; -#else - ret = T_MODIFIED; -#ifdef SERVER_SUPPORT - sticky_ck (file, aflag, vers, entries, - repository, update_dir); -#else - sticky_ck (file, aflag, vers, entries); -#endif /* SERVER_SUPPORT */ -#endif - } - else - { - /* file has not changed; check out if -k changed */ - if (strcmp (vers->entdata->options ? - vers->entdata->options : "", vers->options) != 0) - { - ret = T_CHECKOUT; - } - else - { - - /* - * else -> note that No_Difference will Register the - * file already for us, using the new tag/date. This - * is the desired behaviour - */ - ret = T_UPTODATE; - } - } - } - } - else - { - /* The RCS file is a newer version than the user file */ - - if (vers->ts_user == NULL) - { - /* There is no user file, so just get it */ - - if (strcmp (command_name, "update") == 0) - if (!really_quiet) - error (0, 0, "warning: %s was lost", fullname); - ret = T_CHECKOUT; - } - else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) - { - - /* - * The user file is still unmodified, so just get it as well - */ -#ifdef SERVER_SUPPORT - if (strcmp (vers->entdata->options ? - vers->entdata->options : "", vers->options) != 0 - || (vers->srcfile != NULL - && (vers->srcfile->flags & INATTIC) != 0)) - ret = T_CHECKOUT; - else - ret = T_PATCH; -#else - ret = T_CHECKOUT; -#endif - } - else - { - if (No_Difference (file, vers, entries, - repository, update_dir)) - /* really modified, needs to merge */ - ret = T_NEEDS_MERGE; -#ifdef SERVER_SUPPORT - else if ((strcmp (vers->entdata->options ? - vers->entdata->options : "", vers->options) - != 0) - || (vers->srcfile != NULL - && (vers->srcfile->flags & INATTIC) != 0)) - /* not really modified, check it out */ - ret = T_CHECKOUT; - else - ret = T_PATCH; -#else - else - /* not really modified, check it out */ - ret = T_CHECKOUT; -#endif - } - } - } - - /* free up the vers struct, or just return it */ - if (versp != (Vers_TS **) NULL) - *versp = vers; - else - freevers_ts (&vers); - - free (fullname); - - /* return the status of the file */ - return (ret); -} - -static void -#ifdef SERVER_SUPPORT -sticky_ck (file, aflag, vers, entries, repository, update_dir) -#else -sticky_ck (file, aflag, vers, entries) -#endif - char *file; - int aflag; - Vers_TS *vers; - List *entries; -#ifdef SERVER_SUPPORT - char *repository; - char *update_dir; -#endif -{ - if (aflag || vers->tag || vers->date) - { - char *enttag = vers->entdata->tag; - char *entdate = vers->entdata->date; - - if ((enttag && vers->tag && strcmp (enttag, vers->tag)) || - ((enttag && !vers->tag) || (!enttag && vers->tag)) || - (entdate && vers->date && strcmp (entdate, vers->date)) || - ((entdate && !vers->date) || (!entdate && vers->date))) - { - Register (entries, file, vers->vn_user, vers->ts_rcs, - vers->options, vers->tag, vers->date, vers->ts_conflict); - -#ifdef SERVER_SUPPORT - if (server_active) - { - /* We need to update the entries line on the client side. - It is possible we will later update it again via - server_updated or some such, but that is OK. */ - server_update_entries - (file, update_dir, repository, - strcmp (vers->ts_rcs, vers->ts_user) == 0 ? - SERVER_UPDATED : SERVER_MERGED); - } -#endif - } - } -} diff --git a/gnu/usr.bin/cvs/cvs/client.c b/gnu/usr.bin/cvs/cvs/client.c deleted file mode 100644 index dd96db8..0000000 --- a/gnu/usr.bin/cvs/cvs/client.c +++ /dev/null @@ -1,3542 +0,0 @@ -/* CVS client-related stuff. */ - -#include "cvs.h" - -#ifdef CLIENT_SUPPORT - -#include "update.h" /* Things shared with update.c */ -#include "md5.h" - -#ifdef AUTH_CLIENT_SUPPORT -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -char *get_cvs_password PROTO((char *user, char *host, char *cvsrooot)); -#endif /* AUTH_CLIENT_SUPPORT */ - -#if HAVE_KERBEROS -#define CVS_PORT 1999 - -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <krb.h> - -extern char *krb_realmofhost (); -#ifndef HAVE_KRB_GET_ERR_TEXT -#define krb_get_err_text(status) krb_err_txt[status] -#endif /* HAVE_KRB_GET_ERR_TEXT */ -#endif /* HAVE_KERBEROS */ - -static void add_prune_candidate PROTO((char *)); - -/* All the commands. */ -int add PROTO((int argc, char **argv)); -int admin PROTO((int argc, char **argv)); -int checkout PROTO((int argc, char **argv)); -int commit PROTO((int argc, char **argv)); -int diff PROTO((int argc, char **argv)); -int history PROTO((int argc, char **argv)); -int import PROTO((int argc, char **argv)); -int cvslog PROTO((int argc, char **argv)); -int patch PROTO((int argc, char **argv)); -int release PROTO((int argc, char **argv)); -int cvsremove PROTO((int argc, char **argv)); -int rtag PROTO((int argc, char **argv)); -int status PROTO((int argc, char **argv)); -int tag PROTO((int argc, char **argv)); -int update PROTO((int argc, char **argv)); - -/* All the response handling functions. */ -static void handle_ok PROTO((char *, int)); -static void handle_error PROTO((char *, int)); -static void handle_valid_requests PROTO((char *, int)); -static void handle_checked_in PROTO((char *, int)); -static void handle_new_entry PROTO((char *, int)); -static void handle_checksum PROTO((char *, int)); -static void handle_copy_file PROTO((char *, int)); -static void handle_updated PROTO((char *, int)); -static void handle_merged PROTO((char *, int)); -static void handle_patched PROTO((char *, int)); -static void handle_removed PROTO((char *, int)); -static void handle_remove_entry PROTO((char *, int)); -static void handle_set_static_directory PROTO((char *, int)); -static void handle_clear_static_directory PROTO((char *, int)); -static void handle_set_sticky PROTO((char *, int)); -static void handle_clear_sticky PROTO((char *, int)); -static void handle_set_checkin_prog PROTO((char *, int)); -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)); - -#endif /* CLIENT_SUPPORT */ - -#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) - -/* Shared with server. */ - -/* - * Return a malloc'd, '\0'-terminated string - * corresponding to the mode in SB. - */ -char * -#ifdef __STDC__ -mode_to_string (mode_t mode) -#else /* ! __STDC__ */ -mode_to_string (mode) - mode_t mode; -#endif /* __STDC__ */ -{ - char buf[18], u[4], g[4], o[4]; - int i; - - i = 0; - if (mode & S_IRUSR) u[i++] = 'r'; - if (mode & S_IWUSR) u[i++] = 'w'; - if (mode & S_IXUSR) u[i++] = 'x'; - u[i] = '\0'; - - i = 0; - if (mode & S_IRGRP) g[i++] = 'r'; - if (mode & S_IWGRP) g[i++] = 'w'; - if (mode & S_IXGRP) g[i++] = 'x'; - g[i] = '\0'; - - i = 0; - if (mode & S_IROTH) o[i++] = 'r'; - if (mode & S_IWOTH) o[i++] = 'w'; - if (mode & S_IXOTH) o[i++] = 'x'; - o[i] = '\0'; - - sprintf(buf, "u=%s,g=%s,o=%s", u, g, o); - return xstrdup(buf); -} - -/* - * Change mode of FILENAME to MODE_STRING. - * Returns 0 for success or errno code. - */ -int -change_mode (filename, mode_string) - char *filename; - char *mode_string; -{ - char *p; - mode_t mode = 0; - - p = mode_string; - while (*p != '\0') - { - if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') - { - int can_read = 0, can_write = 0, can_execute = 0; - char *q = p + 2; - while (*q != ',' && *q != '\0') - { - if (*q == 'r') - can_read = 1; - else if (*q == 'w') - can_write = 1; - else if (*q == 'x') - can_execute = 1; - ++q; - } - if (p[0] == 'u') - { - if (can_read) - mode |= S_IRUSR; - if (can_write) - mode |= S_IWUSR; - if (can_execute) - { -#ifdef EXECUTE_PERMISSION_LOSES - KFF_DEBUG (printf ("*** S_IXUSR in change_mode().\n")); -#else /* ! EXECUTE_PERMISSION_LOSES */ - mode |= S_IXUSR; -#endif /* EXECUTE_PERMISSION_LOSES */ - } - } - else if (p[0] == 'g') - { - if (can_read) - mode |= S_IRGRP; - if (can_write) - mode |= S_IWGRP; - if (can_execute) - { -#ifdef EXECUTE_PERMISSION_LOSES - KFF_DEBUG (printf ("*** S_IXGRP in change_mode().\n")); -#else /* ! EXECUTE_PERMISSION_LOSES */ - mode |= S_IXGRP; -#endif /* EXECUTE_PERMISSION_LOSES */ - } - } - else if (p[0] == 'o') - { - if (can_read) - mode |= S_IROTH; - if (can_write) - mode |= S_IWOTH; - if (can_execute) - { -#ifdef EXECUTE_PERMISSION_LOSES - KFF_DEBUG (printf ("*** S_IXOTH in change_mode().\n")); -#else /* ! EXECUTE_PERMISSION_LOSES */ - mode |= S_IXOTH; -#endif /* EXECUTE_PERMISSION_LOSES */ - } - } - } - /* Skip to the next field. */ - while (*p != ',' && *p != '\0') - ++p; - if (*p == ',') - ++p; - } - if (chmod (filename, mode) < 0) - return errno; - return 0; -} - -#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ - -#ifdef CLIENT_SUPPORT - -/* The host part of CVSROOT. */ -static char *server_host; -/* The user part of CVSROOT */ -static char *server_user; -/* The repository part of CVSROOT. */ -static char *server_cvsroot; - -int client_active; - -int client_prune_dirs; - -/* Set server_host and server_cvsroot. */ -static void -parse_cvsroot () -{ - char *p; - - server_host = xstrdup (CVSroot); - server_cvsroot = strchr (server_host, ':'); - *server_cvsroot = '\0'; - ++server_cvsroot; - - if ( (p = strchr (server_host, '@')) == NULL) { - server_user = NULL; - } else { - server_user = server_host; - server_host = p; - ++server_host; - *p = '\0'; - } - - client_active = 1; -} - -/* Stream to write to the server. */ -FILE *to_server; -/* Stream to read from the server. */ -FILE *from_server; - -#if ! RSH_NOT_TRANSPARENT -/* Process ID of rsh subprocess. */ -static int rsh_pid = -1; -#endif /* ! RSH_NOT_TRANSPARENT */ - - -/* - * Read a line from the server. - * - * Space for the result is malloc'd and should be freed by the caller. - * - * Returns number of bytes read. If EOF_OK, then return 0 on end of file, - * else end of file is an error. - */ -static int -read_line (resultp, eof_ok) - char **resultp; - int eof_ok; -{ - int c; - char *result; - int input_index = 0; - int result_size = 80; - - fflush (to_server); - result = (char *) xmalloc (result_size); - - while (1) - { - c = getc (from_server); - - if (c == EOF) - { - free (result); - if (ferror (from_server)) - error (1, errno, "reading from server"); - /* It's end of file. */ - if (eof_ok) - return 0; - else - error (1, 0, "premature end of file from server"); - } - - if (c == '\n') - break; - - result[input_index++] = c; - while (input_index + 1 >= result_size) - { - result_size *= 2; - result = (char *) xrealloc (result, result_size); - } - } - - if (resultp) - *resultp = result; - - /* Terminate it just for kicks, but we *can* deal with embedded NULs. */ - result[input_index] = '\0'; - - if (resultp == NULL) - free (result); - return input_index; -} - -#endif /* CLIENT_SUPPORT */ - - -#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) - -/* - * Zero if compression isn't supported or requested; non-zero to indicate - * a compression level to request from gzip. - */ -int gzip_level; - -int filter_through_gzip (fd, dir, level, pidp) - int fd, dir, level; - pid_t *pidp; -{ - static char buf[5] = "-"; - static char *gzip_argv[3] = { "gzip", buf }; - - sprintf (buf+1, "%d", level); - return filter_stream_through_program (fd, dir, &gzip_argv[0], pidp); -} - -int filter_through_gunzip (fd, dir, pidp) - int fd, dir; - pid_t *pidp; -{ - static char *gunzip_argv[2] = { "gunzip" }; - return filter_stream_through_program (fd, dir, &gunzip_argv[0], pidp); -} - -#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ - -#ifdef CLIENT_SUPPORT - -/* - * The Repository for the top level of this command (not necessarily - * the CVSROOT, just the current directory at the time we do it). - */ -static char *toplevel_repos; - -/* Working directory when we first started. */ -char toplevel_wd[PATH_MAX]; - -static void -handle_ok (args, len) - char *args; - int len; -{ - return; -} - -static void -handle_error (args, len) - char *args; - int len; -{ - int something_printed; - - /* - * First there is a symbolic error code followed by a space, which - * we ignore. - */ - char *p = strchr (args, ' '); - if (p == NULL) - { - error (0, 0, "invalid data from cvs server"); - return; - } - ++p; - len -= p - args; - something_printed = 0; - for (; len > 0; --len) - { - something_printed = 1; - putc (*p++, stderr); - } - if (something_printed) - putc ('\n', stderr); -} - -static void -handle_valid_requests (args, len) - char *args; - int len; -{ - char *p = args; - char *q; - struct request *rq; - do - { - q = strchr (p, ' '); - if (q != NULL) - *q++ = '\0'; - for (rq = requests; rq->name != NULL; ++rq) - { - if (strcmp (rq->name, p) == 0) - break; - } - if (rq->name == NULL) - /* - * It is a request we have never heard of (and thus never - * will want to use). So don't worry about it. - */ - ; - else - { - if (rq->status == rq_enableme) - { - /* - * 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"); - if (!strcmp("UseUnchanged",rq->name)) - use_unchanged = 1; - } - else - rq->status = rq_supported; - } - p = q; - } while (q != NULL); - for (rq = requests; rq->name != NULL; ++rq) - { - if (rq->status == rq_essential) - error (1, 0, "request `%s' not supported by server", rq->name); - else if (rq->status == rq_optional) - rq->status = rq_not_supported; - } -} - -static int use_directory = -1; - -static char *get_short_pathname PROTO((const char *)); - -static char * -get_short_pathname (name) - const char *name; -{ - const char *retval; - if (use_directory) - return (char *) name; - if (strncmp (name, toplevel_repos, strlen (toplevel_repos)) != 0) - error (1, 0, "server bug: name `%s' doesn't specify file in `%s'", - name, toplevel_repos); - retval = name + strlen (toplevel_repos) + 1; - if (retval[-1] != '/') - error (1, 0, "server bug: name `%s' doesn't specify file in `%s'", - name, toplevel_repos); - return (char *) retval; -} - -/* - * Do all the processing for PATHNAME, where pathname consists of the - * repository and the filename. The parameters we pass to FUNC are: - * DATA is just the DATA parameter which was passed to - * call_in_directory; ENT_LIST is a pointer to an entries list (which - * we manage the storage for); SHORT_PATHNAME is the pathname of the - * file relative to the (overall) directory in which the command is - * taking place; and FILENAME is the filename portion only of - * SHORT_PATHNAME. When we call FUNC, the curent directory points to - * the directory portion of SHORT_PATHNAME. */ - -static char *last_dirname; - -static void -call_in_directory (pathname, func, data) - char *pathname; - void (*func) PROTO((char *data, List *ent_list, char *short_pathname, - char *filename)); - char *data; -{ - static List *last_entries; - - char *dirname; - char *filename; - /* Just the part of pathname relative to toplevel_repos. */ - char *short_pathname = get_short_pathname (pathname); - char *p; - - /* - * Do the whole descent in parallel for the repositories, so we - * know what to put in CVS/Repository files. I'm not sure the - * full hair is necessary since the server does a similar - * computation; I suspect that we only end up creating one - * directory at a time anyway. - * - * Also note that we must *only* worry about this stuff when we - * are creating directories; `cvs co foo/bar; cd foo/bar; cvs co - * CVSROOT; cvs update' is legitimate, but in this case - * foo/bar/CVSROOT/CVS/Repository is not a subdirectory of - * foo/bar/CVS/Repository. - */ - char *reposname; - char *short_repos; - char *reposdirname; - char *rdirp; - int reposdirname_absolute; - - reposname = NULL; - if (use_directory) - read_line (&reposname, 0); - - reposdirname_absolute = 0; - if (reposname != NULL) - { - if (strncmp (reposname, toplevel_repos, strlen (toplevel_repos)) != 0) - { - reposdirname_absolute = 1; - short_repos = reposname; - } - else - { - short_repos = reposname + strlen (toplevel_repos) + 1; - if (short_repos[-1] != '/') - { - reposdirname_absolute = 1; - short_repos = reposname; - } - } - } - else - { - short_repos = short_pathname; - } - reposdirname = xstrdup (short_repos); - p = strrchr (reposdirname, '/'); - if (p == NULL) - { - reposdirname = xrealloc (reposdirname, 2); - reposdirname[0] = '.'; reposdirname[1] = '\0'; - } - else - *p = '\0'; - - dirname = xstrdup (short_pathname); - p = strrchr (dirname, '/'); - if (p == NULL) - { - dirname = xrealloc (dirname, 2); - dirname[0] = '.'; dirname[1] = '\0'; - } - else - *p = '\0'; - if (client_prune_dirs) - add_prune_candidate (dirname); - - filename = strrchr (short_repos, '/'); - if (filename == NULL) - filename = short_repos; - else - ++filename; - - if (reposname != NULL) - { - /* This is the use_directory case. */ - - short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5); - strcpy (short_pathname, pathname); - strcat (short_pathname, filename); - } - - if (last_dirname == NULL - || strcmp (last_dirname, dirname) != 0) - { - if (last_dirname) - free (last_dirname); - last_dirname = dirname; - - if (toplevel_wd[0] == '\0') - if (getwd (toplevel_wd) == NULL) - error (1, 0, - "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; - char *dirp; - - if (! existence_error (errno)) - error (1, errno, "could not chdir to %s", dirname); - - /* Directory does not exist, we need to create it. */ - dir = xmalloc (strlen (dirname) + 1); - dirp = dirname; - rdirp = reposdirname; - - /* This algorithm makes nested directories one at a time - and create CVS administration files in them. For - example, we're checking out foo/bar/baz from the - repository: - - 1) create foo, point CVS/Repository to <root>/foo - 2) .. foo/bar .. <root>/foo/bar - 3) .. foo/bar/baz .. <root>/foo/bar/baz - - As you can see, we're just stepping along DIRNAME (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 - 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 - the RDIRP. That is, if we're down to a module name, - don't keep picking apart the repository directory name. */ - - do - { - dirp = strchr (dirp, '/'); - if (dirp) - { - strncpy (dir, dirname, dirp - dirname); - dir[dirp - dirname] = '\0'; - /* Skip the slash. */ - ++dirp; - if (rdirp == NULL) - error (0, 0, - "internal error: repository string too short."); - else - rdirp = strchr (rdirp, '/'); - } - else - { - /* If there are no more slashes in the dir name, - we're down to the most nested directory -OR- to - the name of a module. In the first case, we - should be down to a DIRP that has no slashes, - so it won't help/hurt to do another STRCHR call - on DIRP. It will definitely hurt, however, if - we're down to a module name, since a module - name can point to a nested directory (that is, - DIRP will still have slashes in it. Therefore, - we should set it to NULL so the routine below - copies the contents of REMOTEDIRNAME onto the - root repository directory (does this if rdirp - is set to NULL, because we used to do an extra - STRCHR call here). */ - - rdirp = NULL; - strcpy (dir, dirname); - } - - if (CVS_MKDIR (dir, 0777) < 0) - { - /* 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. */ - ; - else - { - /* - * Put repository in CVS/Repository. For historical - * (pre-CVS/Root) reasons, this is an absolute pathname, - * but what really matters is the part of it which is - * relative to cvsroot. - */ - char *repo; - char *r; - - repo = xmalloc (strlen (reposdirname) - + strlen (toplevel_repos) - + 80); - if (reposdirname_absolute) - r = repo; - else - { - strcpy (repo, toplevel_repos); - strcat (repo, "/"); - r = repo + strlen (repo); - } - - if (rdirp) - { - strncpy (r, reposdirname, rdirp - reposdirname); - r[rdirp - reposdirname] = '\0'; - } - else - strcpy (r, reposdirname); - - Create_Admin (dir, dir, repo, - (char *)NULL, (char *)NULL); - free (repo); - } - - if (rdirp != NULL) - { - /* Skip the slash. */ - ++rdirp; - } - - } while (dirp != NULL); - free (dir); - /* Now it better work. */ - if (chdir (dirname) < 0) - error (1, errno, "could not chdir to %s", dirname); - } - - if (strcmp (command_name, "export") != 0) - { - if (last_entries) - Entries_Close (last_entries); - last_entries = Entries_Open (0); - } - } - else - free (dirname); - free (reposdirname); - (*func) (data, last_entries, short_pathname, filename); - if (reposname != NULL) - { - free (short_pathname); - free (reposname); - } -} - -static void -copy_a_file (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - char *newname; - - read_line (&newname, 0); - copy_file (filename, newname); - free (newname); -} - -static void -handle_copy_file (args, len) - char *args; - int len; -{ - call_in_directory (args, copy_a_file, (char *)NULL); -} - -/* - * The Checksum response gives the checksum for the file transferred - * over by the next Updated, Merged or Patch response. We just store - * it here, and then check it in update_entries. - */ - -static int stored_checksum_valid; -static unsigned char stored_checksum[16]; - -static void -handle_checksum (args, len) - char *args; - int len; -{ - char *s; - char buf[3]; - int i; - - if (stored_checksum_valid) - error (1, 0, "Checksum received before last one was used"); - - s = args; - buf[2] = '\0'; - for (i = 0; i < 16; i++) - { - char *bufend; - - buf[0] = *s++; - buf[1] = *s++; - stored_checksum[i] = (char) strtol (buf, &bufend, 16); - if (bufend != buf + 2) - break; - } - - if (i < 16 || *s != '\0') - error (1, 0, "Invalid Checksum response: `%s'", args); - - stored_checksum_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 - * patches have failed. - */ - -char **failed_patches; -int failed_patches_count; - -struct update_entries_data -{ - enum { - /* - * We are just getting an Entries line; the local file is - * correct. - */ - UPDATE_ENTRIES_CHECKIN, - /* We are getting the file contents as well. */ - UPDATE_ENTRIES_UPDATE, - /* - * We are getting a patch against the existing local file, not - * an entire new file. - */ - UPDATE_ENTRIES_PATCH - } contents; - - /* - * String to put in the timestamp field or NULL to use the timestamp - * of the file. - */ - char *timestamp; -}; - -/* Update the Entries line for this file. */ -static void -update_entries (data_arg, ent_list, short_pathname, filename) - char *data_arg; - List *ent_list; - char *short_pathname; - char *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 = 0; - - 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; - - read_line (&mode_string, 0); - - read_line (&size_string, 0); - if (size_string[0] == 'z') - { - use_gzip = 1; - size = atoi (size_string+1); - } - else - { - use_gzip = 0; - size = atoi (size_string); - } - free (size_string); - - temp_filename = xmalloc (strlen (filename) + 80); -#ifdef _POSIX_NO_TRUNC - sprintf (temp_filename, ".new.%.9s", filename); -#else /* _POSIX_NO_TRUNC */ - sprintf (temp_filename, ".new.%s", filename); -#endif /* _POSIX_NO_TRUNC */ - buf = xmalloc (size); - - /* 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). */ - - bin = !(strcmp (options, "-kb")); - 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); - - if (use_gzip) - fd = filter_through_gunzip (fd, 0, &gzip_pid); - - 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); - } - if (close (fd) < 0) - error (1, errno, "writing %s", short_pathname); - if (gzip_pid > 0) - { - if (waitpid (gzip_pid, &gzip_status, 0) == -1) - error (1, errno, "waiting for gzip process %d", gzip_pid); - else if (gzip_status != 0) - error (1, 0, "gzip process exited %d", gzip_status); - } - - gzip_pid = -1; - - /* Since gunzip writes files without converting LF to CRLF - (a reasonable behavior), we now have a patch file in LF - format. Leave the file as is if we're just going to feed - it to patch; patch can handle it. However, if it's the - final source file, convert it. */ - - if (data->contents == UPDATE_ENTRIES_UPDATE) - { -#ifdef LINES_CRLF_TERMINATED - - /* `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); - } - else - rename_file (temp_filename, filename); - -#else /* ! LINES_CRLF_TERMINATED */ - rename_file (temp_filename, filename); -#endif /* LINES_CRLF_TERMINATED */ - } - else - { - int retcode; - char backup[PATH_MAX]; - struct stat s; - - (void) sprintf (backup, "%s~", filename); - (void) unlink_file (backup); - if (!isfile (filename)) - 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) - retcode = 0; - else - { - run_setup ("%s -f -s -b ~ %s %s", PATCH_PROGRAM, - filename, temp_filename); - retcode = run_exec (DEVNULL, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - /* FIXME: should we really be silently ignoring errors? */ - (void) unlink_file (temp_filename); - if (retcode == 0) - { - /* FIXME: should we really be silently ignoring errors? */ - (void) unlink_file (backup); - } - else - { - int old_errno = errno; - char *path_tmp; - - if (isfile (backup)) - rename_file (backup, filename); - - /* Get rid of the patch reject file. */ - path_tmp = xmalloc (strlen (filename + 10)); - strcpy (path_tmp, filename); - strcat (path_tmp, ".rej"); - /* FIXME: should we really be silently ignoring errors? */ - (void) unlink_file (path_tmp); - free (path_tmp); - - /* Save this file to retrieve later. */ - failed_patches = - (char **) xrealloc ((char *) failed_patches, - ((failed_patches_count + 1) - * sizeof (char *))); - failed_patches[failed_patches_count] = - xstrdup (short_pathname); - ++failed_patches_count; - - error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, - "could not patch %s%s", filename, - retcode == -1 ? "" : "; will refetch"); - - stored_checksum_valid = 0; - - return; - } - } - free (temp_filename); - - if (stored_checksum_valid) - { - FILE *e; - struct MD5Context context; - unsigned char buf[8192]; - unsigned len; - unsigned char checksum[16]; - - /* - * Compute the MD5 checksum. This will normally only be - * used when receiving a patch, so we always compute it - * here on the final file, rather than on the received - * data. - * - * Note that if the file is a text file, we should read it - * here using text mode, so its lines will be terminated the same - * way they were transmitted. - */ - e = fopen (filename, "r"); - if (e == NULL) - error (1, errno, "could not open %s", short_pathname); - - MD5Init (&context); - while ((len = fread (buf, 1, sizeof buf, e)) != 0) - MD5Update (&context, buf, len); - if (ferror (e)) - error (1, errno, "could not read %s", short_pathname); - MD5Final (checksum, &context); - - fclose (e); - - stored_checksum_valid = 0; - - if (memcmp (checksum, stored_checksum, 16) != 0) - { - if (data->contents != UPDATE_ENTRIES_PATCH) - error (1, 0, "checksum failure on %s", - short_pathname); - - error (0, 0, - "checksum failure after patch to %s; will refetch", - short_pathname); - - /* Save this file to retrieve later. */ - failed_patches = - (char **) xrealloc ((char *) failed_patches, - ((failed_patches_count + 1) - * sizeof (char *))); - failed_patches[failed_patches_count] = - xstrdup (short_pathname); - ++failed_patches_count; - - return; - } - } - - { - /* FIXME: we should be respecting the umask. */ - int status = change_mode (filename, mode_string); - if (status != 0) - error (0, status, "cannot change mode of %s", short_pathname); - } - - free (mode_string); - free (buf); - } - - /* - * Process the entries line. Do this after we've written the file, - * since we need the timestamp. - */ - if (strcmp (command_name, "export") != 0) - { - char *local_timestamp; - char *file_timestamp; - - 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 - * date. Create a dummy timestamp which will never compare - * equal to the timestamp of the file. - */ - if (vn[0] == '\0' || vn[0] == '0' || vn[0] == '-') - local_timestamp = "dummy timestamp"; - else if (local_timestamp == NULL) - local_timestamp = file_timestamp; - - 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); -} - -static void -handle_checked_in (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_CHECKIN; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_new_entry (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_CHECKIN; - dat.timestamp = "dummy timestamp from new-entry"; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_updated (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_UPDATE; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_merged (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_UPDATE; - dat.timestamp = "Result of merge"; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -handle_patched (args, len) - char *args; - int len; -{ - struct update_entries_data dat; - dat.contents = UPDATE_ENTRIES_PATCH; - dat.timestamp = NULL; - call_in_directory (args, update_entries, (char *)&dat); -} - -static void -remove_entry (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - Scratch_Entry (ent_list, filename); -} - -static void -handle_remove_entry (args, len) - char *args; - int len; -{ - call_in_directory (args, remove_entry, (char *)NULL); -} - -static void -remove_entry_and_file (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - Scratch_Entry (ent_list, filename); - if (unlink_file (filename) < 0) - error (0, errno, "unable to remove %s", short_pathname); -} - -static void -handle_removed (args, len) - char *args; - int len; -{ - call_in_directory (args, remove_entry_and_file, (char *)NULL); -} - -/* Is this the top level (directory containing CVSROOT)? */ -static int -is_cvsroot_level (pathname) - char *pathname; -{ - char *short_pathname; - - if (strcmp (toplevel_repos, server_cvsroot) != 0) - return 0; - - if (!use_directory) - { - if (strncmp (pathname, server_cvsroot, strlen (server_cvsroot)) != 0) - error (1, 0, - "server bug: pathname `%s' doesn't specify file in `%s'", - pathname, server_cvsroot); - short_pathname = pathname + strlen (server_cvsroot) + 1; - if (short_pathname[-1] != '/') - error (1, 0, - "server bug: pathname `%s' doesn't specify file in `%s'", - pathname, server_cvsroot); - return strchr (short_pathname, '/') == NULL; - } - else - { - return strchr (pathname, '/') == NULL; - } -} - -static void -set_static (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - FILE *fp; - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_ENTSTAT); -} - -static void -handle_set_static_directory (args, len) - char *args; - int len; -{ - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - return; - } - call_in_directory (args, set_static, (char *)NULL); -} - -static void -clear_static (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); -} - -static void -handle_clear_static_directory (pathname, len) - char *pathname; - int len; -{ - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - return; - } - - if (is_cvsroot_level (pathname)) - { - /* - * Top level (directory containing CVSROOT). This seems to normally - * lack a CVS directory, so don't try to create files in it. - */ - return; - } - call_in_directory (pathname, clear_static, (char *)NULL); -} - -static void -set_sticky (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - char *tagspec; - FILE *f; - - read_line (&tagspec, 0); - f = open_file (CVSADM_TAG, "w+"); - if (fprintf (f, "%s\n", tagspec) < 0) - error (1, errno, "writing %s", CVSADM_TAG); - if (fclose (f) == EOF) - error (1, errno, "closing %s", CVSADM_TAG); - free (tagspec); -} - -static void -handle_set_sticky (pathname, len) - char *pathname; - int len; -{ - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - /* Swallow the tag line. */ - (void) read_line (NULL, 0); - return; - } - if (is_cvsroot_level (pathname)) - { - /* - * Top level (directory containing CVSROOT). This seems to normally - * lack a CVS directory, so don't try to create files in it. - */ - - /* Swallow the repository. */ - read_line (NULL, 0); - /* Swallow the tag line. */ - (void) read_line (NULL, 0); - return; - } - - call_in_directory (pathname, set_sticky, (char *)NULL); -} - -static void -clear_sticky (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - if (unlink_file (CVSADM_TAG) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove %s", CVSADM_TAG); -} - -static void -handle_clear_sticky (pathname, len) - char *pathname; - int len; -{ - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - return; - } - - if (is_cvsroot_level (pathname)) - { - /* - * Top level (directory containing CVSROOT). This seems to normally - * lack a CVS directory, so don't try to create files in it. - */ - return; - } - - call_in_directory (pathname, clear_sticky, (char *)NULL); -} - -struct save_prog { - char *name; - char *dir; - struct save_prog *next; -}; - -static struct save_prog *checkin_progs; -static struct save_prog *update_progs; - -/* - * Unlike some requests this doesn't include the repository. So we can't - * just call call_in_directory and have the right thing happen; we save up - * the requests and do them at the end. - */ -static void -handle_set_checkin_prog (args, len) - char *args; - int len; -{ - char *prog; - struct save_prog *p; - read_line (&prog, 0); - p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); - p->next = checkin_progs; - p->dir = xstrdup (args); - p->name = prog; - checkin_progs = p; -} - -static void -handle_set_update_prog (args, len) - char *args; - int len; -{ - char *prog; - struct save_prog *p; - read_line (&prog, 0); - p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); - p->next = update_progs; - p->dir = xstrdup (args); - p->name = prog; - update_progs = p; -} - -static void do_deferred_progs PROTO((void)); - -static void -do_deferred_progs () -{ - struct save_prog *p; - struct save_prog *q; - - char fname[PATH_MAX]; - FILE *f; - if (toplevel_wd[0] != '\0') - { - if (chdir (toplevel_wd) < 0) - error (1, errno, "could not chdir to %s", toplevel_wd); - } - for (p = checkin_progs; p != NULL; ) - { - sprintf (fname, "%s/%s", p->dir, CVSADM_CIPROG); - f = open_file (fname, "w"); - if (fprintf (f, "%s\n", p->name) < 0) - error (1, errno, "writing %s", fname); - if (fclose (f) == EOF) - error (1, errno, "closing %s", fname); - free (p->name); - free (p->dir); - q = p->next; - free (p); - p = q; - } - checkin_progs = NULL; - for (p = update_progs; p != NULL; p = p->next) - { - sprintf (fname, "%s/%s", p->dir, CVSADM_UPROG); - f = open_file (fname, "w"); - if (fprintf (f, "%s\n", p->name) < 0) - error (1, errno, "writing %s", fname); - if (fclose (f) == EOF) - error (1, errno, "closing %s", fname); - free (p->name); - free (p->dir); - free (p); - } - update_progs = NULL; -} - -static int client_isemptydir PROTO((char *)); - -/* - * Returns 1 if the argument directory exists and is completely empty, - * other than the existence of the CVS directory entry. Zero otherwise. - */ -static int -client_isemptydir (dir) - char *dir; -{ - DIR *dirp; - struct dirent *dp; - - if ((dirp = opendir (dir)) == NULL) - { - if (! existence_error (errno)) - error (0, errno, "cannot open directory %s for empty check", dir); - return (0); - } - errno = 0; - while ((dp = readdir (dirp)) != NULL) - { - if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 && - strcmp (dp->d_name, CVSADM) != 0) - { - (void) closedir (dirp); - return (0); - } - } - if (errno != 0) - { - error (0, errno, "cannot read directory %s", dir); - (void) closedir (dirp); - return (0); - } - (void) closedir (dirp); - return (1); -} - -struct save_dir { - char *dir; - struct save_dir *next; -}; - -struct save_dir *prune_candidates; - -static void -add_prune_candidate (dir) - char *dir; -{ - struct save_dir *p; - - if (dir[0] == '.' && dir[1] == '\0') - return; - p = (struct save_dir *) xmalloc (sizeof (struct save_dir)); - p->dir = xstrdup (dir); - p->next = prune_candidates; - prune_candidates = p; -} - -static void process_prune_candidates PROTO((void)); - -static void -process_prune_candidates () -{ - struct save_dir *p; - struct save_dir *q; - - if (toplevel_wd[0] != '\0') - { - if (chdir (toplevel_wd) < 0) - error (1, errno, "could not chdir to %s", toplevel_wd); - } - for (p = prune_candidates; p != NULL; ) - { - if (client_isemptydir (p->dir)) - { - unlink_file_dir (p->dir); - } - free (p->dir); - q = p->next; - free (p); - p = q; - } -} - -/* Send a Repository line. */ - -static char *last_repos; -static char *last_update_dir; - -static void send_repository PROTO((char *, char *, char *)); - -static void -send_repository (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - char *adm_name; - - if (update_dir == NULL || update_dir[0] == '\0') - update_dir = "."; - - if (last_repos != NULL - && strcmp (repos, last_repos) == 0 - && last_update_dir != NULL - && strcmp (update_dir, last_update_dir) == 0) - /* We've already sent it. */ - return; - - if (client_prune_dirs) - add_prune_candidate (update_dir); - - /* 80 is large enough for any of CVSADM_*. */ - adm_name = xmalloc (strlen (dir) + 80); - - if (use_directory == -1) - use_directory = supported_request ("Directory"); - - 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"); - } - else - { - if (fprintf (to_server, "Repository %s\n", repos) < 0) - error (1, errno, "writing to server"); - } - if (supported_request ("Static-directory")) - { - adm_name[0] = '\0'; - if (dir[0] != '\0') - { - strcat (adm_name, dir); - strcat (adm_name, "/"); - } - strcat (adm_name, CVSADM_ENTSTAT); - if (isreadable (adm_name)) - { - if (fprintf (to_server, "Static-directory\n") < 0) - error (1, errno, "writing to server"); - } - } - if (supported_request ("Sticky")) - { - FILE *f; - if (dir[0] == '\0') - strcpy (adm_name, CVSADM_TAG); - else - sprintf (adm_name, "%s/%s", dir, CVSADM_TAG); - - f = fopen (adm_name, "r"); - if (f == NULL) - { - 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"); - while (fgets (line, sizeof (line), f) != NULL) - { - if (fprintf (to_server, "%s", line) < 0) - error (1, errno, "writing to server"); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); - if (fclose (f) == EOF) - error (0, errno, "closing %s", adm_name); - } - } - if (supported_request ("Checkin-prog")) - { - FILE *f; - if (dir[0] == '\0') - strcpy (adm_name, CVSADM_CIPROG); - else - sprintf (adm_name, "%s/%s", dir, CVSADM_CIPROG); - - f = fopen (adm_name, "r"); - if (f == NULL) - { - 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"); - while (fgets (line, sizeof (line), f) != NULL) - { - if (fprintf (to_server, "%s", line) < 0) - error (1, errno, "writing to server"); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); - if (fclose (f) == EOF) - error (0, errno, "closing %s", adm_name); - } - } - if (supported_request ("Update-prog")) - { - FILE *f; - if (dir[0] == '\0') - strcpy (adm_name, CVSADM_UPROG); - else - sprintf (adm_name, "%s/%s", dir, CVSADM_UPROG); - - f = fopen (adm_name, "r"); - if (f == NULL) - { - 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"); - while (fgets (line, sizeof (line), f) != NULL) - { - if (fprintf (to_server, "%s", line) < 0) - error (1, errno, "writing to server"); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); - if (fclose (f) == EOF) - error (0, errno, "closing %s", adm_name); - } - } - if (last_repos != NULL) - free (last_repos); - if (last_update_dir != NULL) - free (last_update_dir); - last_repos = xstrdup (repos); - last_update_dir = xstrdup (update_dir); -} - -/* Send a Repository line and set toplevel_repos. */ -static void send_a_repository PROTO((char *, char *, char *)); - -static void -send_a_repository (dir, repository, update_dir) - char *dir; - char *repository; - char *update_dir; -{ - if (toplevel_repos == NULL && repository != NULL) - { - if (update_dir[0] == '\0' - || (update_dir[0] == '.' && update_dir[1] == '\0')) - toplevel_repos = xstrdup (repository); - else - { - /* - * Get the repository from a CVS/Repository file if update_dir - * is absolute. This is not correct in general, because - * the CVS/Repository file might not be the top-level one. - * This is for cases like "cvs update /foo/bar" (I'm not - * sure it matters what toplevel_repos we get, but it does - * matter that we don't hit the "internal error" code below). - */ - if (update_dir[0] == '/') - toplevel_repos = Name_Repository (update_dir, update_dir); - else - { - /* - * Guess the repository of that directory by looking at a - * subdirectory and removing as many pathname components - * as are in update_dir. I think that will always (or at - * least almost always) be 1. - * - * So this deals with directories which have been - * renamed, though it doesn't necessarily deal with - * directories which have been put inside other - * directories (and cvs invoked on the containing - * directory). I'm not sure the latter case needs to - * work. - */ - /* - * This gets toplevel_repos wrong for "cvs update ../foo" - * but I'm not sure toplevel_repos matters in that case. - */ - int slashes_in_update_dir; - int slashes_skipped; - char *p; - - slashes_in_update_dir = 0; - for (p = update_dir; *p != '\0'; ++p) - if (*p == '/') - ++slashes_in_update_dir; - - slashes_skipped = 0; - p = repository + strlen (repository); - while (1) - { - if (p == repository) - error (1, 0, - "internal error: not enough slashes in %s", - repository); - if (*p == '/') - ++slashes_skipped; - if (slashes_skipped < slashes_in_update_dir + 1) - --p; - else - break; - } - toplevel_repos = xmalloc (p - repository + 1); - /* Note that we don't copy the trailing '/'. */ - strncpy (toplevel_repos, repository, p - repository); - toplevel_repos[p - repository] = '\0'; - } - } - } - - send_repository (dir, repository, update_dir); -} - -static int modules_count; -static int modules_allocated; -static char **modules_vector; - -static void -handle_module_expansion (args, len) - char *args; - int len; -{ - if (modules_vector == NULL) - { - modules_allocated = 1; /* Small for testing */ - modules_vector = (char **) xmalloc - (modules_allocated * sizeof (modules_vector[0])); - } - else if (modules_count >= modules_allocated) - { - modules_allocated *= 2; - modules_vector = (char **) xrealloc - ((char *) modules_vector, - modules_allocated * sizeof (modules_vector[0])); - } - modules_vector[modules_count] = xmalloc (strlen (args) + 1); - strcpy (modules_vector[modules_count], args); - ++modules_count; -} - -void -client_expand_modules (argc, argv, local) - int argc; - char **argv; - int local; -{ - int errs; - int i; - - 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"); - errs = get_server_responses (); - if (last_repos != NULL) - free (last_repos); - last_repos = NULL; - if (last_update_dir != NULL) - free (last_update_dir); - last_update_dir = NULL; - if (errs) - error (errs, 0, ""); -} - -void -client_send_expansions (local) - int local; -{ - int i; - char *argv[1]; - 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, ""); -} - -void -client_nonexpanded_setup () -{ - send_a_repository ("", server_cvsroot, ""); -} - -static void -handle_m (args, len) - char *args; - int len; -{ - fwrite (args, len, sizeof (*args), stdout); - putc ('\n', stdout); -} - -static void -handle_e (args, len) - char *args; - int len; -{ - fwrite (args, len, sizeof (*args), stderr); - putc ('\n', stderr); -} - -#endif /* CLIENT_SUPPORT */ -#if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) - -/* This table must be writeable if the server code is included. */ -struct response responses[] = -{ -#ifdef CLIENT_SUPPORT -#define RSP_LINE(n, f, t, s) {n, f, t, s} -#else /* ! CLIENT_SUPPORT */ -#define RSP_LINE(n, f, t, s) {n, s} -#endif /* CLIENT_SUPPORT */ - - RSP_LINE("ok", handle_ok, response_type_ok, rs_essential), - RSP_LINE("error", handle_error, response_type_error, rs_essential), - RSP_LINE("Valid-requests", handle_valid_requests, response_type_normal, - rs_essential), - RSP_LINE("Checked-in", handle_checked_in, response_type_normal, - rs_essential), - RSP_LINE("New-entry", handle_new_entry, response_type_normal, rs_optional), - RSP_LINE("Checksum", handle_checksum, response_type_normal, rs_optional), - RSP_LINE("Copy-file", handle_copy_file, response_type_normal, rs_optional), - 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("Removed", handle_removed, response_type_normal, rs_essential), - RSP_LINE("Remove-entry", handle_remove_entry, response_type_normal, - rs_optional), - RSP_LINE("Set-static-directory", handle_set_static_directory, - response_type_normal, - rs_optional), - RSP_LINE("Clear-static-directory", handle_clear_static_directory, - response_type_normal, - rs_optional), - RSP_LINE("Set-sticky", handle_set_sticky, response_type_normal, - rs_optional), - RSP_LINE("Clear-sticky", handle_clear_sticky, response_type_normal, - rs_optional), - RSP_LINE("Set-checkin-prog", handle_set_checkin_prog, response_type_normal, - rs_optional), - RSP_LINE("Set-update-prog", handle_set_update_prog, response_type_normal, - rs_optional), - RSP_LINE("Module-expansion", handle_module_expansion, response_type_normal, - rs_optional), - RSP_LINE("M", handle_m, response_type_normal, rs_essential), - RSP_LINE("E", handle_e, response_type_normal, rs_essential), - /* Possibly should be response_type_error. */ - RSP_LINE(NULL, NULL, response_type_normal, rs_essential) - -#undef RSP_LINE -}; - -#endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ -#ifdef CLIENT_SUPPORT - -/* - * Get some server responses and process them. Returns nonzero for - * error, 0 for success. - */ -int -get_server_responses () -{ - struct response *rs; - do - { - char *cmd; - int len; - - len = read_line (&cmd, 0); - for (rs = responses; rs->name != NULL; ++rs) - if (strncmp (cmd, rs->name, strlen (rs->name)) == 0) - { - int cmdlen = strlen (rs->name); - if (cmd[cmdlen] == '\0') - ; - else if (cmd[cmdlen] == ' ') - ++cmdlen; - else - /* - * The first len characters match, but it's a different - * response. e.g. the response is "oklahoma" but we - * matched "ok". - */ - continue; - (*rs->func) (cmd + cmdlen, len - cmdlen); - break; - } - if (rs->name == NULL) - /* It's OK to print just to the first '\0'. */ - error (0, 0, - "warning: unrecognized response `%s' from cvs server", - cmd); - free (cmd); - } while (rs->type == response_type_normal); - return rs->type == response_type_error ? 1 : 0; -} - -/* Get the responses and then close the connection. */ -int server_fd = -1; - -int -get_responses_and_close () -{ - int errs = get_server_responses (); - - do_deferred_progs (); - - if (client_prune_dirs) - process_prune_candidates (); - -#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); - /* - * 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); - } - } - else -#endif /* HAVE_KERBEROS || AUTH_CLIENT_SUPPORT */ - -#ifdef SHUTDOWN_SERVER - 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) - if (errno != ECHILD) - error (1, errno, "waiting for process %d", rsh_pid); -#endif /* ! RSH_NOT_TRANSPARENT */ - - return errs; -} - -#ifndef RSH_NOT_TRANSPARENT -static void start_rsh_server PROTO((int *, int *)); -#endif /* RSH_NOT_TRANSPARENT */ - -int -supported_request (name) - char *name; -{ - struct request *rq; - - for (rq = requests; rq->name; rq++) - if (!strcmp (rq->name, name)) - return rq->status == rq_supported; - error (1, 0, "internal error: testing support for unknown option?"); -} - - -#ifdef AUTH_CLIENT_SUPPORT -void -init_sockaddr (name, hostname, port) - struct sockaddr_in *name; - const char *hostname; - unsigned short int port; -{ - struct hostent *hostinfo; - - name->sin_family = AF_INET; - name->sin_port = htons (port); - hostinfo = gethostbyname (hostname); - if (hostinfo == NULL) - { - fprintf (stderr, "Unknown host %s.\n", hostname); - exit (EXIT_FAILURE); - } - name->sin_addr = *(struct in_addr *) hostinfo->h_addr; -} - -void -connect_to_pserver (tofdp, fromfdp, log) - int *tofdp, *fromfdp; - char *log; -{ - int sock; - int tofd, fromfd; - struct hostent *host; - struct sockaddr_in client_sai; - - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock == -1) - { - fprintf (stderr, "socket() failed\n"); - exit (1); - } - init_sockaddr (&client_sai, server_host, CVS_AUTH_PORT); - connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)); - - /* Run the authorization mini-protocol before anything else. */ - { - int i; - char ch, read_buf[PATH_MAX]; - char *begin = "BEGIN AUTH REQUEST\n"; - char *repository = server_cvsroot; - char *username = server_user; - char *password = NULL; - char *end = "END AUTH REQUEST\n"; - - /* Get the password, probably from ~/.cvspass. */ - password = get_cvs_password (server_user, server_host, server_cvsroot); - - /* Announce that we're starting the authorization protocol. */ - write (sock, begin, strlen (begin)); - - /* Send the data the server needs. */ - write (sock, repository, strlen (repository)); - write (sock, "\n", 1); - write (sock, username, strlen (username)); - write (sock, "\n", 1); - write (sock, password, strlen (password)); - write (sock, "\n", 1); - - /* Announce that we're ending the authorization protocol. */ - write (sock, end, strlen (end)); - - /* 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 read until "\n". - */ - ch = 0; - memset (read_buf, 0, PATH_MAX); - for (i = 0; (i < (PATH_MAX - 1)) && (ch != '\n'); i++) - { - read (sock, &ch, 1); - read_buf[i] = ch; - } - - if (strcmp (read_buf, "I HATE YOU\n") == 0) - { - /* Authorization not granted. */ - if (shutdown (sock, 2) < 0) - error (1, errno, "shutdown() failed (server %s)", server_host); - 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) - error (1, errno, "shutdown() failed (server %s)", server_host); - error (1, 0, - "unrecognized auth response from %s: %s", - server_host, read_buf); - } - /* Else authorization granted, so we can go on... */ - } - - /* This was stolen straight from start_kerberos_server(). */ - { - server_fd = sock; - 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 (sock); - fromfd = dup (sock); - } - else - tofd = fromfd = sock; - } - - /* Hand them back to the caller. */ - *tofdp = tofd; - *fromfdp = fromfd; -} -#endif /* AUTH_CLIENT_SUPPORT */ - - -#if HAVE_KERBEROS -void -start_kerberos_server (tofdp, fromfdp, log) - int *tofdp, *fromfdp; - char *log; -{ - 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, "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); - /* - * 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; - } - } - - 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 /* RSH_NOT_TRANSPARENT */ -#if defined (START_SERVER) - 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"); - -#if HAVE_KERBEROS - start_kerberos_server (&tofd, &fromfd, log); - -#else /* ! HAVE_KERBEROS */ - -#ifdef AUTH_CLIENT_SUPPORT - if (use_authenticating_server) - { - connect_to_pserver (&tofd, &fromfd, log); - } - else -#endif /* AUTH_CLIENT_SUPPORT */ - { -#if ! RSH_NOT_TRANSPARENT - 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 /* defined(START_SERVER) */ -#endif /* ! RSH_NOT_TRANSPARENT */ - } -#endif /* HAVE_KERBEROS */ - - /* todo: some OS's don't need these calls... */ - close_on_exec (tofd); - close_on_exec (fromfd); - - if (log) - { - int len = strlen (log); - char *buf = xmalloc (5 + len); - 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); - - strcpy (p, ".out"); - fromfd = filter_stream_through_program (fromfd, 1, teeprog, 0); - - free (buf); - } - - /* 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_repos != NULL) - free (last_repos); - last_repos = NULL; - if (last_update_dir != NULL) - free (last_update_dir); - last_update_dir = NULL; - stored_checksum_valid = 0; - - 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"); - for (rs = responses; rs->name != NULL; ++rs) - { - if (fprintf (to_server, " %s", rs->name) < 0) - error (1, errno, "writing to server"); - } - if (fprintf (to_server, "\n") < 0) - error (1, errno, "writing to server"); - } - if (fprintf (to_server, "valid-requests\n") < 0) - error (1, errno, "writing to server"); - if (get_server_responses ()) - exit (1); - - /* - * Now handle global options. - * - * -H, -f, -d, -e should be handled OK locally. - * - * -b we ignore (treating it as a server installation issue). - * FIXME: should be an error message. - * - * -v we print local version info; FIXME: Add a protocol request to get - * the version from the server so we can print that too. - * - * -l -t -r -w -q -n and -Q need to go to the server. - */ - - { - int have_global = supported_request ("Global_option"); - - if (noexec) - { - if (have_global) - { - if (fprintf (to_server, "Global_option -n\n") < 0) - error (1, errno, "writing to server"); - } - else - error (1, 0, - "This server does not support the global -n option."); - } - if (quiet) - { - if (have_global) - { - if (fprintf (to_server, "Global_option -q\n") < 0) - error (1, errno, "writing to server"); - } - else - error (1, 0, - "This server does not support the global -q option."); - } - if (really_quiet) - { - if (have_global) - { - if (fprintf (to_server, "Global_option -Q\n") < 0) - error (1, errno, "writing to server"); - } - else - error (1, 0, - "This server does not support the global -Q option."); - } - if (!cvswrite) - { - if (have_global) - { - if (fprintf (to_server, "Global_option -r\n") < 0) - error (1, errno, "writing to server"); - } - else - error (1, 0, - "This server does not support the global -r option."); - } - if (trace) - { - if (have_global) - { - if (fprintf (to_server, "Global_option -t\n") < 0) - error (1, errno, "writing to server"); - } - else - error (1, 0, - "This server does not support the global -t option."); - } - if (logoff) - { - if (have_global) - { - if (fprintf (to_server, "Global_option -l\n") < 0) - error (1, errno, "writing to server"); - } - else - error (1, 0, - "This server does not support the global -l option."); - } - } - if (gzip_level) - { - if (supported_request ("gzip-file-contents")) - { - if (fprintf (to_server, "gzip-file-contents %d\n", gzip_level) < 0) - error (1, 0, "writing to server"); - } - else - { - fprintf (stderr, "server doesn't support gzip-file-contents\n"); - gzip_level = 0; - } - } -} - -#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 - -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; - - /* "-b" for binary, under OS/2. */ - rsh_argv[i++] = "-b"; - - /* 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; - int *fromfdp; -{ - /* 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; - - if (!cvs_rsh) - cvs_rsh = "rsh"; - if (!cvs_server) - cvs_server = "cvs"; - - /* Pass the command to rsh as a single string. This shouldn't - affect most rsh servers at all, and will pacify some buggy - versions of rsh that grab switches out of the middle of the - command (they're calling the GNU getopt routines incorrectly). */ - command = xmalloc (strlen (cvs_server) - + strlen (server_cvsroot) - + 50); - - /* 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). */ - sprintf (command, "%s server", cvs_server); - - { - char *argv[10]; - char **p = argv; - - *p++ = cvs_rsh; - *p++ = server_host; - - /* If the login names differ between client and server - * pass it on to rsh. - */ - if (server_user != NULL) - { - *p++ = "-l"; - *p++ = server_user; - } - - *p++ = command; - *p++ = NULL; - - if (trace) - { - int i; - - fprintf (stderr, " -> Starting server: "); - for (i = 0; argv[i]; i++) - fprintf (stderr, "%s ", argv[i]); - putc ('\n', stderr); - } - rsh_pid = piped_child (argv, tofdp, fromfdp); - - if (rsh_pid < 0) - error (1, errno, "cannot start server via rsh"); - } -} - -#endif /* START_RSH_WITH_POPEN_RW */ -#endif /* ! RSH_NOT_TRANSPARENT */ - - - -/* Send an argument STRING. */ -void -send_arg (string) - char *string; -{ - char *p = string; - if (fprintf (to_server, "Argument ") < 0) - error (1, errno, "writing to server"); - while (*p) - { - if (*p == '\n') - { - if (fprintf (to_server, "\nArgumentx ") < 0) - error (1, errno, "writing to server"); - } - else if (putc (*p, to_server) == EOF) - error (1, errno, "writing to server"); - ++p; - } - if (putc ('\n', to_server) == EOF) - error (1, errno, "writing to server"); -} - -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; - int fd; - char *buf; - char *mode_string; - int bufsize; - int bin = 0; - - /* Don't think we can assume fstat exists. */ - if (stat (file, &sb) < 0) - error (1, errno, "reading %s", short_pathname); - - mode_string = mode_to_string (sb.st_mode); - - /* Beware: on systems using CRLF line termination conventions, - the read and write functions will convert CRLF to LF, so the - number of characters read is not the same as sb.st_size. Text - files should always be transmitted using the LF convention, so - we don't want to disable this conversion. */ - bufsize = sb.st_size; - buf = xmalloc (bufsize); - - /* Is the file marked as containing binary data by the "-kb" flag? - If so, make sure to open it in binary mode: */ - - bin = !(strcmp (vers->options, "-kb")); - fd = open (file, O_RDONLY | (bin ? OPEN_BINARY : 0)); - - if (fd < 0) - error (1, errno, "reading %s", short_pathname); - - if (gzip_level && sb.st_size > 100) - { - int nread, newsize = 0, gzip_status; - pid_t gzip_pid; - char *bufp = buf; - int readsize = 8192; -#ifdef LINES_CRLF_TERMINATED - char tempfile[L_tmpnam]; - int converting; -#endif /* LINES_CRLF_TERMINATED */ - -#ifdef LINES_CRLF_TERMINATED - /* Assume everything in a "cvs import" is text. */ - if (vers == NULL) - converting = 1; - else - /* Otherwise, we convert things unless they're binary. */ - converting = (! bin); - - 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) - { - if ((bufp - buf) + readsize >= bufsize) - { - /* - * We need to expand the buffer if gzip ends up expanding - * the file. - */ - newsize = bufp - buf; - while (newsize + readsize >= bufsize) - bufsize *= 2; - buf = xrealloc (buf, bufsize); - bufp = buf + newsize; - } - nread = read (fd, bufp, readsize); - if (nread < 0) - error (1, errno, "reading from gzip pipe"); - else if (nread == 0) - /* eof */ - break; - bufp += nread; - } - newsize = bufp - buf; - if (close (fd) < 0) - error (0, errno, "warning: can't close %s", short_pathname); - - if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid) - error (1, errno, "waiting for gzip proc %d", gzip_pid); - else if (gzip_status != 0) - error (1, errno, "gzip exited %d", gzip_status); - -#if 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"); - } - else - { - int newsize; - - { - char *bufp = buf; - int len; - - while ((len = read (fd, bufp, (buf + sb.st_size) - bufp)) > 0) - bufp += len; - - if (len < 0) - error (1, errno, "reading %s", short_pathname); - - newsize = bufp - buf; - } - 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"); - - /* - * 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"); - } - free (buf); - free (mode_string); -} - -/* Deal with one file. */ -static int -send_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Vers_TS *vers; - int update_dir_len = strlen (update_dir); - char *short_pathname = xmalloc (update_dir_len + strlen (file) + 40); - strcpy (short_pathname, update_dir); - if (update_dir[0] != '\0') - strcat (short_pathname, "/"); - strcat (short_pathname, file); - - send_a_repository ("", repository, update_dir); - - vers = Version_TS ((char *)NULL, (char *)NULL, (char *)NULL, - (char *)NULL, - file, 0, 0, entries, (List *)NULL); - - if (vers->vn_user != NULL) - { - /* 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"); - if (vers->entdata != NULL && vers->entdata->tag) - { - if (fprintf (to_server, "T%s", vers->entdata->tag) < 0) - error (1, errno, "writing to server"); - } - 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"); - } - - if (vers->ts_user == NULL) - { - /* - * Do we want to print "file was lost" like normal CVS? - * Would it always be appropriate? - */ - /* File no longer exists. */ - 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"); - /* - * Otherwise, don't do anything for missing files, - * they just happen. - */ - } - } - else if (vers->ts_rcs == NULL - || strcmp (vers->ts_user, vers->ts_rcs) != 0) - { - 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"); - } - - /* if this directory has an ignore list, add this file to it */ - if (ignlist) - { - Node *p; - - p = getnode (); - p->type = FILES; - p->key = xstrdup (file); - (void) addnode (ignlist, p); - } - - freevers_ts (&vers); - free (short_pathname); - return 0; -} - -/* - * send_dirent_proc () is called back by the recursion processor before a - * sub-directory is processed for update. - * A return code of 0 indicates the directory should be - * processed by the recursion code. A return of non-zero indicates the - * recursion code should skip this directory. - * - */ -static Dtype -send_dirent_proc (dir, repository, update_dir) - char *dir; - char *repository; - char *update_dir; -{ - int dir_exists; - char *cvsadm_repos_name; - - /* - * If the directory does not exist yet (e.g. "cvs update -d - * foo"), no need to send any files from it. - */ - dir_exists = isdir (dir); - - if (ignore_directory (update_dir)) - { - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Ignoring %s", update_dir); - return (R_SKIP_ALL); - } - - /* initialize the ignore list for this directory */ - ignlist = getlist (); - - /* - * If there is an empty directory (e.g. we are doing `cvs add' on a - * newly-created directory), the server still needs to know about it. - */ - - cvsadm_repos_name = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 80); - sprintf (cvsadm_repos_name, "%s/%s", dir, CVSADM_REP); - if (dir_exists && isreadable (cvsadm_repos_name)) - { - /* - * Get the repository from a CVS/Repository file whenever possible. - * The repository variable is wrong if the names in the local - * directory don't match the names in the repository. - */ - char *repos = Name_Repository (dir, update_dir); - send_a_repository (dir, repos, update_dir); - free (repos); - } - else - send_a_repository (dir, repository, update_dir); - free (cvsadm_repos_name); - - return (dir_exists ? R_PROCESS : R_SKIP_ALL); -} - -/* - * Send each option in a string to the server, one by one. - * This assumes that the options are single characters. For - * more complex parsing, do it yourself. - */ - -void -send_option_string (string) - char *string; -{ - char *p; - char it[3]; - - for (p = string; p[0]; p++) { - if (p[0] == ' ') - continue; - if (p[0] == '-') - continue; - it[0] = '-'; - it[1] = p[0]; - it[2] = '\0'; - send_arg (it); - } -} - - -/* Send the names of all the argument files to the server. */ - -void -send_file_names (argc, argv) - int argc; - char **argv; -{ - int i; - char *p; - char *q; - int level; - int max_level; - - /* Send Max-dotdot if needed. */ - max_level = 0; - for (i = 0; i < argc; ++i) - { - p = argv[i]; - level = 0; - do - { - q = strchr (p, '/'); - if (q != NULL) - ++q; - if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/')) - { - --level; - if (-level > max_level) - max_level = -level; - } - else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/')) - ; - else - ++level; - p = q; - } while (p != NULL); - } - if (max_level > 0) - { - if (supported_request ("Max-dotdot")) - { - if (fprintf (to_server, "Max-dotdot %d\n", max_level) < 0) - error (1, errno, "writing to server"); - } - else - /* - * "leading .." is not strictly correct, as this also includes - * cases like "foo/../..". But trying to explain that in the - * error message would probably just confuse users. - */ - error (1, 0, - "leading .. not supported by old (pre-Max-dotdot) servers"); - } - - for (i = 0; i < argc; ++i) - send_arg (argv[i]); -} - - -/* - * 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. - */ -void -send_files (argc, argv, local, aflag) - int argc; - char **argv; - int local; - int 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, (DIRLEAVEPROC)NULL, - argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0, 0); - if (err) - exit (1); - if (toplevel_repos == NULL) - /* - * This happens if we are not processing any files, - * or for checkouts in directories without any existing stuff - * checked out. The following assignment is correct for the - * latter case; I don't think toplevel_repos matters for the - * former. - */ - toplevel_repos = xstrdup (server_cvsroot); - send_repository ("", toplevel_repos, "."); -} - -void -client_import_setup (repository) - char *repository; -{ - if (toplevel_repos == NULL) /* should always be true */ - send_a_repository ("", repository, ""); -} - -/* - * Process the argument import file. - */ -int -client_process_import_file (message, vfile, vtag, targc, targv, repository) - char *message; - char *vfile; - char *vtag; - int targc; - char *targv[]; - char *repository; -{ - char *short_pathname; - int first_time; - - /* FIXME: I think this is always false now that we call - client_import_setup at the start. */ - - first_time = toplevel_repos == NULL; - - if (first_time) - send_a_repository ("", repository, ""); - - if (strncmp (repository, toplevel_repos, strlen (toplevel_repos)) != 0) - error (1, 0, - "internal error: pathname `%s' doesn't specify file in `%s'", - repository, toplevel_repos); - short_pathname = repository + strlen (toplevel_repos) + 1; - - if (!first_time) - { - send_a_repository ("", repository, short_pathname); - } - send_modified (vfile, short_pathname, NULL); - return 0; -} - -void -client_import_done () -{ - if (toplevel_repos == NULL) - /* - * This happens if we are not processing any files, - * or for checkouts in directories without any existing stuff - * checked out. The following assignment is correct for the - * latter case; I don't think toplevel_repos matters for the - * former. - */ - /* FIXME: "can't happen" now that we call client_import_setup - at the beginning. */ - toplevel_repos = xstrdup (server_cvsroot); - send_repository ("", toplevel_repos, "."); -} - -/* - * Send an option with an argument, dealing correctly with newlines in - * the argument. If ARG is NULL, forget the whole thing. - */ -void -option_with_arg (option, arg) - char *option; - char *arg; -{ - if (arg == NULL) - return; - if (fprintf (to_server, "Argument %s\n", option) < 0) - error (1, errno, "writing to server"); - send_arg (arg); -} - -/* - * Send a date to the server. This will passed a string which is the - * result of Make_Date, and looks like YY.MM.DD.HH.MM.SS, where all - * the letters are single digits. The time will be GMT. getdate on - * the server can't parse that, so we turn it back into something - * which it can parse. - */ - -void -client_senddate (date) - const char *date; -{ - int year, month, day, hour, minute, second; - char buf[100]; - - if (sscanf (date, DATEFORM, &year, &month, &day, &hour, &minute, &second) - != 6) - { - error (1, 0, "diff_client_senddate: sscanf failed on date"); - } - -#ifndef HAVE_RCS5 - /* We need to fix the timezone in this case; see Make_Date. */ - abort (); -#endif /* HAVE_RCS5 */ - - sprintf (buf, "%d/%d/%d %d:%d:%d GMT", month, day, year, - hour, minute, second); - option_with_arg ("-D", buf); -} - -int -client_commit (argc, argv) - int argc; - char **argv; -{ - parse_cvsroot (); - - return commit (argc, argv); -} - -int -client_update (argc, argv) - int argc; - char **argv; -{ - parse_cvsroot (); - - return update (argc, argv); -} - -int -client_checkout (argc, argv) - int argc; - char **argv; -{ - parse_cvsroot (); - - return checkout (argc, argv); -} - -int -client_diff (argc, argv) - int argc; - char **argv; -{ - parse_cvsroot (); - - return diff (argc, argv); /* Call real code */ -} - -int -client_status (argc, argv) - int argc; - char **argv; -{ - parse_cvsroot (); - return status (argc, argv); -} - -int -client_log (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return cvslog (argc, argv); /* Call real code */ -} - -int -client_add (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return add (argc, argv); /* Call real code */ -} - -int -client_remove (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return cvsremove (argc, argv); /* Call real code */ -} - -int -client_rdiff (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return patch (argc, argv); /* Call real code */ -} - -int -client_tag (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return tag (argc, argv); /* Call real code */ -} - -int -client_rtag (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return rtag (argc, argv); /* Call real code */ -} - -int -client_import (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return import (argc, argv); /* Call real code */ -} - -int -client_admin (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return admin (argc, argv); /* Call real code */ -} - -int -client_export (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return checkout (argc, argv); /* Call real code */ -} - -int -client_history (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return history (argc, argv); /* Call real code */ -} - -int -client_release (argc, argv) - int argc; - char **argv; -{ - - parse_cvsroot (); - - return release (argc, argv); /* Call real code */ -} - -#endif /* CLIENT_SUPPORT */ diff --git a/gnu/usr.bin/cvs/cvs/client.h b/gnu/usr.bin/cvs/cvs/client.h deleted file mode 100644 index 0602900..0000000 --- a/gnu/usr.bin/cvs/cvs/client.h +++ /dev/null @@ -1,163 +0,0 @@ -/* Interface between the client and the rest of CVS. */ - -/* Stuff shared with the server. */ -extern char *mode_to_string PROTO((mode_t)); -extern int change_mode PROTO((char *, char *)); - -extern int gzip_level; -extern int filter_through_gzip PROTO((int, int, int, pid_t *)); -extern int filter_through_gunzip PROTO((int, int, pid_t *)); - -#ifdef CLIENT_SUPPORT -/* - * Functions to perform CVS commands via the protocol. argc and argv - * are the arguments and the return value is the exit status (zero success - * nonzero failure). - */ -extern int client_commit PROTO((int argc, char **argv)); -extern int client_update PROTO((int argc, char **argv)); -extern int client_checkout PROTO((int argc, char **argv)); -extern int client_diff PROTO((int argc, char **argv)); -extern int client_log PROTO((int argc, char **argv)); -extern int client_add PROTO((int argc, char **argv)); -extern int client_remove PROTO((int argc, char **argv)); -extern int client_status PROTO((int argc, char **argv)); -extern int client_rdiff PROTO((int argc, char **argv)); -extern int client_tag PROTO((int argc, char **argv)); -extern int client_rtag PROTO((int argc, char **argv)); -extern int client_import PROTO((int argc, char **argv)); -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)); - -/* - * Flag variable for seeing whether common code is running as a client - * or to do a local operation. - */ -extern int client_active; - -/* 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; - -/* Internal functions that handle client communication to server, etc. */ -int supported_request PROTO ((char *)); -void option_with_arg PROTO((char *option, char *arg)); - -/* Get the responses and then close the connection. */ -extern int get_responses_and_close PROTO((void)); - -extern int get_server_responses PROTO((void)); - -/* Start up the connection to the server on the other end. */ -void -start_server PROTO((void)); - -/* Send the names of all the argument files to the server. */ -void -send_file_names PROTO((int argc, char **argv)); - -/* - * Send 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. - */ -void -send_files PROTO((int argc, char **argv, int local, int aflag)); - -/* - * Like send_files but never send "Unchanged"--just send the contents of the - * file in that case. This is used to fix it if you import a directory which - * happens to have CVS directories (yes it is obscure but the testsuite tests - * it). - */ -void -send_files_contents PROTO((int argc, char **argv, int local, int aflag)); - -/* Send an argument to the remote server. */ -void -send_arg PROTO((char *string)); - -/* Send a string of single-char options to the remote server, one by one. */ -void -send_option_string PROTO((char *string)); - -#endif /* CLIENT_SUPPORT */ - -/* - * This structure is used to catalog the responses the client is - * prepared to see from the server. - */ - -struct response -{ - /* Name of the response. */ - char *name; - -#ifdef CLIENT_SUPPORT - /* - * Function to carry out the response. ARGS is the text of the - * command after name and, if present, a single space, have been - * stripped off. The function can scribble into ARGS if it wants. - */ - void (*func) PROTO((char *args, int len)); - - /* - * ok and error are special; they indicate we are at the end of the - * responses, and error indicates we should exit with nonzero - * exitstatus. - */ - enum {response_type_normal, response_type_ok, response_type_error} type; -#endif - - /* Used by the server to indicate whether response is supported by - the client, as set by the Valid-responses request. */ - enum { - /* - * Failure to implement this response can imply a fatal - * error. This should be set only for responses which were in the - * original version of the protocol; it should not be set for new - * responses. - */ - rs_essential, - - /* Some clients might not understand this response. */ - rs_optional, - - /* - * Set by the server to one of the following based on what this - * client actually supports. - */ - rs_supported, - rs_not_supported - } status; -}; - -/* Table of responses ending in an entry with a NULL name. */ - -extern struct response responses[]; - -#ifdef CLIENT_SUPPORT - -extern void client_senddate PROTO((const char *date)); -extern void client_expand_modules PROTO((int argc, char **argv, int local)); -extern void client_send_expansions PROTO((int local)); -extern void client_nonexpanded_setup PROTO((void)); - -extern char **failed_patches; -extern int failed_patches_count; -extern char toplevel_wd[]; -extern void client_import_setup PROTO((char *repository)); -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)); - -#endif /* CLIENT_SUPPORT */ diff --git a/gnu/usr.bin/cvs/cvs/commit.c b/gnu/usr.bin/cvs/cvs/commit.c deleted file mode 100644 index 888804e..0000000 --- a/gnu/usr.bin/cvs/cvs/commit.c +++ /dev/null @@ -1,1834 +0,0 @@ -/* - * 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. - * - * Commit Files - * - * "commit" commits the present version to the RCS repository, AFTER - * having done a test on conflicts. - * - * The call is: cvs commit [options] files... - * - */ - -#include "cvs.h" -#include "getline.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)commit.c 1.101 94/10/07 $"; -USE(rcsid); -#endif - -static Dtype check_direntproc PROTO((char *dir, char *repos, char *update_dir)); -static int check_fileproc PROTO((char *file, char *update_dir, char *repository, - List * entries, List * srcfiles)); -static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir)); -static int checkaddfile PROTO((char *file, char *repository, char *tag, - char *options, List *srcfiles)); -static Dtype commit_direntproc PROTO((char *dir, char *repos, char *update_dir)); -static int commit_dirleaveproc PROTO((char *dir, int err, char *update_dir)); -static int commit_fileproc PROTO((char *file, char *update_dir, char *repository, - List * entries, List * srcfiles)); -static int commit_filesdoneproc PROTO((int err, char *repository, char *update_dir)); -static int finaladd PROTO((char *file, char *revision, char *tag, - char *options, char *update_dir, - char *repository, List *entries)); -static int findmaxrev PROTO((Node * p, void *closure)); -static int fsortcmp PROTO((const Node * p, const Node * q)); -static int lock_RCS PROTO((char *user, char *rcs, char *rev, char *repository)); -static int lock_filesdoneproc PROTO((int err, char *repository, char *update_dir)); -static int lockrcsfile PROTO((char *file, char *repository, char *rev)); -static int precommit_list_proc PROTO((Node * p, void *closure)); -static int precommit_proc PROTO((char *repository, char *filter)); -static int remove_file PROTO((char *file, char *repository, char *tag, - char *message, List *entries, List *srcfiles)); -static void fix_rcs_modes PROTO((char *rcs, char *user)); -static void fixaddfile PROTO((char *file, char *repository)); -static void fixbranch PROTO((char *file, char *repository, char *branch)); -static void unlockrcs PROTO((char *file, char *repository)); -static void ci_delproc PROTO((Node *p)); -static void masterlist_delproc PROTO((Node *p)); -static void locate_rcs PROTO((char *file, char *repository, char *rcs)); - -struct commit_info -{ - Ctype status; /* as returned from Classify_File() */ - char *rev; /* a numeric rev, if we know it */ - char *tag; /* any sticky tag, or -r option */ - char *options; /* Any sticky -k option */ -}; -struct master_lists -{ - List *ulist; /* list for Update_Logfile */ - List *cilist; /* list with commit_info structs */ -}; - -static int force_ci = 0; -static int got_message; -static int run_module_prog = 1; -static int aflag; -static char *tag; -static char *write_dirtag; -static char *logfile; -static List *mulist; -static List *locklist; -static char *message; - -static const char *const commit_usage[] = -{ - "Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n", - "\t-n\tDo not run the module program (if any).\n", - "\t-R\tProcess directories recursively.\n", - "\t-l\tLocal directory only (not recursive).\n", - "\t-f\tForce the file to be committed; disables recursion.\n", - "\t-F file\tRead the log message from file.\n", - "\t-m msg\tLog message.\n", - "\t-r rev\tCommit to this branch or trunk revision.\n", - NULL -}; - -int -commit (argc, argv) - int argc; - char **argv; -{ - int c; - int err = 0; - int local = 0; - - if (argc == -1) - usage (commit_usage); - -#ifdef CVS_BADROOT - /* - * For log purposes, do not allow "root" to commit files. If you look - * like root, but are really logged in as a non-root user, it's OK. - */ - if (geteuid () == (uid_t) 0) - { - struct passwd *pw; - - if ((pw = (struct passwd *) getpwnam (getcaller ())) == NULL) - error (1, 0, "you are unknown to this system"); - if (pw->pw_uid == (uid_t) 0) - error (1, 0, "cannot commit files as 'root'"); - } -#endif /* CVS_BADROOT */ - - optind = 1; - while ((c = getopt (argc, argv, "nlRm:fF:r:")) != -1) - { - switch (c) - { - case 'n': - run_module_prog = 0; - break; - case 'm': -#ifdef FORCE_USE_EDITOR - use_editor = TRUE; -#else - use_editor = FALSE; -#endif - if (message) - { - free (message); - message = NULL; - } - - message = xstrdup(optarg); - break; - case 'r': - if (tag) - free (tag); - tag = xstrdup (optarg); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'f': - force_ci = 1; - local = 1; /* also disable recursion */ - break; - case 'F': -#ifdef FORCE_USE_EDITOR - use_editor = TRUE; -#else - use_editor = FALSE; -#endif - logfile = optarg; - break; - case '?': - default: - usage (commit_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* numeric specified revision means we ignore sticky tags... */ - if (tag && isdigit (*tag)) - { - aflag = 1; - /* strip trailing dots */ - while (tag[strlen (tag) - 1] == '.') - tag[strlen (tag) - 1] = '\0'; - } - - /* some checks related to the "-F logfile" option */ - if (logfile) - { - int n, logfd; - struct stat statbuf; - - if (message) - 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); - - if (fstat(logfd, &statbuf) < 0) - error (1, errno, "cannot find size of log file %s", logfile); - - message = xmalloc (statbuf.st_size + 1); - - if ((n = read (logfd, message, statbuf.st_size + 1)) < 0) - error (1, errno, "cannot read log message from %s", logfile); - - (void) close (logfd); - message[n] = '\0'; - } - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* - * Do this now; don't ask for a log message if we can't talk to the - * server. But if there is a syntax error in the options, give - * an error message without connecting. - */ - start_server (); - - ign_setup (); - - /* - * We do this once, not once for each directory as in normal CVS. - * The protocol is designed this way. This is a feature. - * - * We could provide the lists of changed, modified, etc. files, - * however. Our failure to do so is just laziness, not design. - */ - if (use_editor) - do_editor (".", &message, (char *)NULL, (List *)NULL); - - /* We always send some sort of message, even if empty. */ - option_with_arg ("-m", message); - - if (local) - send_arg("-l"); - if (force_ci) - send_arg("-f"); - if (!run_module_prog) - send_arg("-n"); - option_with_arg ("-r", tag); - - send_files (argc, argv, local, 0); - - if (fprintf (to_server, "ci\n") < 0) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } -#endif - - /* XXX - this is not the perfect check for this */ - if (argc <= 0) - write_dirtag = tag; - - wrap_setup (); - - /* - * Run the recursion processor to find all the dirs to lock and lock all - * the dirs - */ - locklist = getlist (); - err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, argc, - argv, local, W_LOCAL, aflag, 0, (char *) NULL, 0, - 0); - sortlist (locklist, fsortcmp); - if (Writer_Lock (locklist) != 0) - error (1, 0, "lock failed - giving up"); - - /* - * Set up the master update list - */ - mulist = getlist (); - - /* - * Run the recursion processor to verify the files are all up-to-date - */ - err = start_recursion (check_fileproc, check_filesdoneproc, - check_direntproc, (DIRLEAVEPROC) NULL, argc, - argv, local, W_LOCAL, aflag, 0, (char *) NULL, 1, - 0); - if (err) - { - Lock_Cleanup (); - error (1, 0, "correct above errors first!"); - } - - /* - * Run the recursion processor to commit the files - */ - if (noexec == 0) - err = start_recursion (commit_fileproc, commit_filesdoneproc, - commit_direntproc, commit_dirleaveproc, - argc, argv, local, W_LOCAL, aflag, 0, - (char *) NULL, 1, 0); - - /* - * Unlock all the dirs and clean up - */ - Lock_Cleanup (); - dellist (&mulist); - dellist (&locklist); - return (err); -} - -/* - * compare two lock list nodes (for sort) - */ -static int -fsortcmp (p, q) - const Node *p; - const Node *q; -{ - return (strcmp (p->key, q->key)); -} - -/* - * Create a list of repositories to lock - */ -/* ARGSUSED */ -static int -lock_filesdoneproc (err, repository, update_dir) - int err; - char *repository; - char *update_dir; -{ - Node *p; - - p = getnode (); - p->type = LOCK; - p->key = xstrdup (repository); - /* FIXME-KRP: this error condition should not simply be passed by. */ - if (p->key == NULL || addnode (locklist, p) != 0) - freenode (p); - return (err); -} - -/* - * Check to see if a file is ok to commit and make sure all files are - * up-to-date - */ -/* ARGSUSED */ -static int -check_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Ctype status; - char *xdir; - Node *p; - List *ulist, *cilist; - Vers_TS *vers; - struct commit_info *ci; - int save_noexec, save_quiet, save_really_quiet; - - save_noexec = noexec; - save_quiet = quiet; - save_really_quiet = really_quiet; - noexec = quiet = really_quiet = 1; - - /* handle specified numeric revision specially */ - if (tag && isdigit (*tag)) - { - /* If the tag is for the trunk, make sure we're at the head */ - if (numdots (tag) < 2) - { - status = Classify_File (file, (char *) NULL, (char *) NULL, - (char *) NULL, 1, aflag, repository, - entries, srcfiles, &vers, update_dir, 0); - if (status == T_UPTODATE || status == T_MODIFIED || - status == T_ADDED) - { - Ctype xstatus; - - freevers_ts (&vers); - xstatus = Classify_File (file, tag, (char *) NULL, - (char *) NULL, 1, aflag, repository, - entries, srcfiles, &vers, update_dir, - 0); - if (xstatus == T_REMOVE_ENTRY) - status = T_MODIFIED; - else if (status == T_MODIFIED && xstatus == T_CONFLICT) - status = T_MODIFIED; - else - status = xstatus; - } - } - else - { - char *xtag, *cp; - - /* - * The revision is off the main trunk; make sure we're - * up-to-date with the head of the specified branch. - */ - xtag = xstrdup (tag); - if ((numdots (xtag) & 1) != 0) - { - cp = strrchr (xtag, '.'); - *cp = '\0'; - } - status = Classify_File (file, xtag, (char *) NULL, - (char *) NULL, 1, aflag, repository, - entries, srcfiles, &vers, update_dir, 0); - if ((status == T_REMOVE_ENTRY || status == T_CONFLICT) - && (cp = strrchr (xtag, '.')) != NULL) - { - /* pluck one more dot off the revision */ - *cp = '\0'; - freevers_ts (&vers); - status = Classify_File (file, xtag, (char *) NULL, - (char *) NULL, 1, aflag, repository, - entries, srcfiles, &vers, update_dir, - 0); - if (status == T_UPTODATE || status == T_REMOVE_ENTRY) - status = T_MODIFIED; - } - /* now, muck with vers to make the tag correct */ - free (vers->tag); - vers->tag = xstrdup (tag); - free (xtag); - } - } - else - status = Classify_File (file, tag, (char *) NULL, (char *) NULL, - 1, 0, repository, entries, srcfiles, &vers, - update_dir, 0); - noexec = save_noexec; - quiet = save_quiet; - really_quiet = save_really_quiet; - - /* - * If the force-commit option is enabled, and the file in question - * appears to be up-to-date, just make it look modified so that - * it will be committed. - */ - if (force_ci && status == T_UPTODATE) - status = T_MODIFIED; - - switch (status) - { - case T_CHECKOUT: -#ifdef SERVER_SUPPORT - case T_PATCH: -#endif - case T_NEEDS_MERGE: - case T_CONFLICT: - case T_REMOVE_ENTRY: - if (update_dir[0] == '\0') - error (0, 0, "Up-to-date check failed for `%s'", file); - else - error (0, 0, "Up-to-date check failed for `%s/%s'", - update_dir, file); - freevers_ts (&vers); - return (1); - case T_MODIFIED: - case T_ADDED: - case T_REMOVED: - /* - * some quick sanity checks; if no numeric -r option specified: - * - can't have a sticky date - * - can't have a sticky tag that is not a branch - * Also, - * - if status is T_REMOVED, can't have a numeric tag - * - if status is T_ADDED, rcs file must not exist - * - if status is T_ADDED, can't have a non-trunk numeric rev - * - if status is T_MODIFIED and a Conflict marker exists, don't - * allow the commit if timestamp is identical or if we find - * an RCS_MERGE_PAT in the file. - */ - if (!tag || !isdigit (*tag)) - { - if (vers->date) - { - if (update_dir[0] == '\0') - error (0, 0, - "cannot commit with sticky date for file `%s'", - file); - else - error - (0, 0, - "cannot commit with sticky date for file `%s/%s'", - update_dir, file); - freevers_ts (&vers); - return (1); - } - if (status == T_MODIFIED && vers->tag && - !RCS_isbranch (file, vers->tag, srcfiles)) - { - if (update_dir[0] == '\0') - error (0, 0, - "sticky tag `%s' for file `%s' is not a branch", - vers->tag, file); - else - error - (0, 0, - "sticky tag `%s' for file `%s/%s' is not a branch", - vers->tag, update_dir, file); - freevers_ts (&vers); - return (1); - } - } - if (status == T_MODIFIED && !force_ci && vers->ts_conflict) - { - char *filestamp; - int retcode; - - /* - * We found a "conflict" marker. - * - * If the timestamp on the file is the same as the - * timestamp stored in the Entries file, we block the commit. - */ -#ifdef SERVER_SUPPORT - if (server_active) - retcode = vers->ts_conflict[0] != '='; - else { - filestamp = time_stamp (file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); - } -#else - filestamp = time_stamp (file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); -#endif - if (retcode == 0) - { - if (update_dir[0] == '\0') - error (0, 0, - "file `%s' had a conflict and has not been modified", - file); - else - error (0, 0, - "file `%s/%s' had a conflict and has not been modified", - update_dir, file); - freevers_ts (&vers); - return (1); - } - - /* - * If the timestamps differ, look for Conflict indicators - * in the file to see if we should block the commit anyway - */ - run_setup ("%s", GREP); - run_arg (RCS_MERGE_PAT); - run_arg (file); - retcode = run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_REALLY); - - if (retcode == -1) - { - if (update_dir[0] == '\0') - error (1, errno, - "fork failed while examining conflict in `%s'", - file); - else - error (1, errno, - "fork failed while examining conflict in `%s/%s'", - update_dir, file); - } - else if (retcode == 0) - { - if (update_dir[0] == '\0') - error (0, 0, - "file `%s' still contains conflict indicators", - file); - else - error (0, 0, - "file `%s/%s' still contains conflict indicators", - update_dir, file); - freevers_ts (&vers); - return (1); - } - } - - if (status == T_REMOVED && vers->tag && isdigit (*vers->tag)) - { - if (update_dir[0] == '\0') - error (0, 0, - "cannot remove file `%s' which has a numeric sticky tag of `%s'", - file, vers->tag); - else - error (0, 0, - "cannot remove file `%s/%s' which has a numeric sticky tag of `%s'", - update_dir, file, vers->tag); - freevers_ts (&vers); - return (1); - } - if (status == T_ADDED) - { - char rcs[PATH_MAX]; - -#ifdef DEATH_SUPPORT - /* Don't look in the attic; if it exists there we will - move it back out in checkaddfile. */ - sprintf(rcs, "%s/%s%s", repository, file, RCSEXT); -#else - locate_rcs (file, repository, rcs); -#endif - if (isreadable (rcs)) - { - if (update_dir[0] == '\0') - error (0, 0, - "cannot add file `%s' when RCS file `%s' already exists", - file, rcs); - else - error (0, 0, - "cannot add file `%s/%s' when RCS file `%s' already exists", - update_dir, file, rcs); - freevers_ts (&vers); - return (1); - } - if (vers->tag && isdigit (*vers->tag) && - numdots (vers->tag) > 1) - { - if (update_dir[0] == '\0') - error (0, 0, - "cannot add file `%s' with revision `%s'; must be on trunk", - file, vers->tag); - else - error (0, 0, - "cannot add file `%s/%s' with revision `%s'; must be on trunk", - update_dir, file, vers->tag); - freevers_ts (&vers); - return (1); - } - } - - /* done with consistency checks; now, to get on with the commit */ - if (update_dir[0] == '\0') - xdir = "."; - else - xdir = update_dir; - if ((p = findnode (mulist, xdir)) != NULL) - { - ulist = ((struct master_lists *) p->data)->ulist; - cilist = ((struct master_lists *) p->data)->cilist; - } - else - { - struct master_lists *ml; - - ulist = getlist (); - cilist = getlist (); - p = getnode (); - p->key = xstrdup (xdir); - p->type = UPDATE; - ml = (struct master_lists *) - xmalloc (sizeof (struct master_lists)); - ml->ulist = ulist; - ml->cilist = cilist; - p->data = (char *) ml; - p->delproc = masterlist_delproc; - (void) addnode (mulist, p); - } - - /* first do ulist, then cilist */ - p = getnode (); - p->key = xstrdup (file); - p->type = UPDATE; - p->delproc = update_delproc; - p->data = (char *) status; - (void) addnode (ulist, p); - - p = getnode (); - p->key = xstrdup (file); - p->type = UPDATE; - p->delproc = ci_delproc; - ci = (struct commit_info *) xmalloc (sizeof (struct commit_info)); - ci->status = status; - if (vers->tag) - if (isdigit (*vers->tag)) - ci->rev = xstrdup (vers->tag); - else - ci->rev = RCS_whatbranch (file, vers->tag, srcfiles); - else - ci->rev = (char *) NULL; - ci->tag = xstrdup (vers->tag); - ci->options = xstrdup(vers->options); - p->data = (char *) ci; - (void) addnode (cilist, p); - break; - case T_UNKNOWN: - if (update_dir[0] == '\0') - error (0, 0, "nothing known about `%s'", file); - else - error (0, 0, "nothing known about `%s/%s'", update_dir, file); - freevers_ts (&vers); - return (1); - case T_UPTODATE: - break; - default: - error (0, 0, "CVS internal error: unknown status %d", status); - break; - } - - freevers_ts (&vers); - return (0); -} - -/* - * Print warm fuzzies while examining the dirs - */ -/* ARGSUSED */ -static Dtype -check_direntproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "Examining %s", update_dir); - - return (R_PROCESS); -} - -/* - * Walklist proc to run pre-commit checks - */ -static int -precommit_list_proc (p, closure) - Node *p; - void *closure; -{ - if (p->data == (char *) T_ADDED || p->data == (char *) T_MODIFIED || - p->data == (char *) T_REMOVED) - { - run_arg (p->key); - } - return (0); -} - -/* - * Callback proc for pre-commit checking - */ -static List *ulist; -static int -precommit_proc (repository, filter) - char *repository; - char *filter; -{ - /* see if the filter is there, only if it's a full path */ - if (isabsolute (filter)) - { - char *s, *cp; - - s = xstrdup (filter); - for (cp = s; *cp; cp++) - if (isspace (*cp)) - { - *cp = '\0'; - break; - } - if (!isfile (s)) - { - error (0, errno, "cannot find pre-commit filter `%s'", s); - free (s); - return (1); /* so it fails! */ - } - free (s); - } - - run_setup ("%s %s", filter, repository); - (void) walklist (ulist, precommit_list_proc, NULL); - return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY)); -} - -/* - * Run the pre-commit checks for the dir - */ -/* ARGSUSED */ -static int -check_filesdoneproc (err, repos, update_dir) - int err; - char *repos; - char *update_dir; -{ - int n; - Node *p; - - /* find the update list for this dir */ - p = findnode (mulist, update_dir); - if (p != NULL) - ulist = ((struct master_lists *) p->data)->ulist; - else - ulist = (List *) NULL; - - /* skip the checks if there's nothing to do */ - if (ulist == NULL || ulist->list->next == ulist->list) - return (err); - - /* run any pre-commit checks */ - if ((n = Parse_Info (CVSROOTADM_COMMITINFO, repos, precommit_proc, 1)) > 0) - { - error (0, 0, "Pre-commit check failed"); - err += n; - } - - return (err); -} - -/* - * Do the work of committing a file - */ -static int maxrev; -static char sbranch[PATH_MAX]; - -/* ARGSUSED */ -static int -commit_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Node *p; - int err = 0; - List *ulist, *cilist; - struct commit_info *ci; - char rcs[PATH_MAX]; - - if (update_dir[0] == '\0') - p = findnode (mulist, "."); - else - p = findnode (mulist, update_dir); - - /* - * if p is null, there were file type command line args which were - * all up-to-date so nothing really needs to be done - */ - if (p == NULL) - return (0); - ulist = ((struct master_lists *) p->data)->ulist; - cilist = ((struct master_lists *) p->data)->cilist; - - /* - * At this point, we should have the commit message unless we were called - * with files as args from the command line. In that latter case, we - * need to get the commit message ourselves - */ - if (use_editor && !got_message) - { - got_message = 1; - do_editor (update_dir, &message, repository, ulist); - } - - p = findnode (cilist, file); - if (p == NULL) - return (0); - - ci = (struct commit_info *) p->data; - if (ci->status == T_MODIFIED) - { - if (lockrcsfile (file, repository, ci->rev) != 0) - { - unlockrcs (file, repository); - err = 1; - goto out; - } - } - else if (ci->status == T_ADDED) - { - if (checkaddfile (file, repository, ci->tag, ci->options, - srcfiles) != 0) - { - fixaddfile (file, repository); - err = 1; - goto out; - } - -#ifdef DEATH_SUPPORT - /* adding files with a tag, now means adding them on a branch. - Since the branch test was done in check_fileproc for - modified files, we need to stub it in again here. */ - - if (ci->tag) { - locate_rcs (file, repository, rcs); - ci->rev = RCS_whatbranch (file, ci->tag, srcfiles); - err = Checkin ('A', file, update_dir, repository, rcs, ci->rev, - ci->tag, ci->options, message, entries); - if (err != 0) - { - unlockrcs (file, repository); - fixbranch (file, repository, sbranch); - } - - ci->status = T_UPTODATE; - } -#endif /* DEATH_SUPPORT */ - } - - /* - * Add the file for real - */ - if (ci->status == T_ADDED) - { - char *xrev = (char *) NULL; - - if (ci->rev == NULL) - { - /* find the max major rev number in this directory */ - maxrev = 0; - (void) walklist (entries, findmaxrev, NULL); - if (maxrev == 0) - maxrev = 1; - xrev = xmalloc (20); - (void) sprintf (xrev, "%d", maxrev); - } - - /* XXX - an added file with symbolic -r should add tag as well */ - err = finaladd (file, ci->rev ? ci->rev : xrev, ci->tag, ci->options, - update_dir, repository, entries); - if (xrev) - free (xrev); - } - else if (ci->status == T_MODIFIED) - { - locate_rcs (file, repository, rcs); - err = Checkin ('M', file, update_dir, repository, - rcs, ci->rev, ci->tag, - ci->options, message, entries); - if (err != 0) - { - unlockrcs (file, repository); - fixbranch (file, repository, sbranch); - } - } - else if (ci->status == T_REMOVED) - { - err = remove_file (file, repository, ci->tag, message, - entries, srcfiles); -#ifdef SERVER_SUPPORT - if (server_active) { - server_scratch_entry_only (); - server_updated (file, update_dir, repository, - /* Doesn't matter, it won't get checked. */ - SERVER_UPDATED, (struct stat *) NULL, - (unsigned char *) NULL); - } -#endif - } - -out: - if (err != 0) - { - /* on failure, remove the file from ulist */ - p = findnode (ulist, file); - if (p) - delnode (p); - } - - return (err); -} - -/* - * Log the commit and clean up the update list - */ -/* ARGSUSED */ -static int -commit_filesdoneproc (err, repository, update_dir) - int err; - char *repository; - char *update_dir; -{ - char *xtag = (char *) NULL; - Node *p; - List *ulist; - - p = findnode (mulist, update_dir); - if (p == NULL) - return (err); - - ulist = ((struct master_lists *) p->data)->ulist; - - got_message = 0; - - /* see if we need to specify a per-directory or -r option tag */ - if (tag == NULL) - ParseTag (&xtag, (char **) NULL); - - Update_Logfile (repository, message, tag ? tag : xtag, (FILE *) 0, ulist); - if (xtag) - free (xtag); - - if (err == 0 && run_module_prog) - { - FILE *fp; - - if ((fp = fopen (CVSADM_CIPROG, "r")) != NULL) - { - char *line; - int line_length; - size_t line_chars_allocated; - char *repository; - - line = NULL; - line_chars_allocated = 0; - line_length = getline (&line, &line_chars_allocated, fp); - if (line_length > 0) - { - /* Remove any trailing newline. */ - if (line[line_length - 1] == '\n') - line[--line_length] = '\0'; - repository = Name_Repository ((char *) NULL, update_dir); - run_setup ("%s %s", line, repository); - (void) printf ("%s %s: Executing '", program_name, - command_name); - run_print (stdout); - (void) printf ("'\n"); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - free (repository); - } - else - { - if (ferror (fp)) - error (0, errno, "warning: error reading %s", - CVSADM_CIPROG); - } - if (line != NULL) - free (line); - if (fclose (fp) < 0) - error (0, errno, "warning: cannot close %s", CVSADM_CIPROG); - } - else - { - if (! existence_error (errno)) - error (0, errno, "warning: cannot open %s", CVSADM_CIPROG); - } - } - - return (err); -} - -/* - * Get the log message for a dir and print a warm fuzzy - */ -/* ARGSUSED */ -static Dtype -commit_direntproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - Node *p; - List *ulist; - char *real_repos; - - /* find the update list for this dir */ - p = findnode (mulist, update_dir); - if (p != NULL) - ulist = ((struct master_lists *) p->data)->ulist; - else - ulist = (List *) NULL; - - /* skip the files as an optimization */ - if (ulist == NULL || ulist->list->next == ulist->list) - return (R_SKIP_FILES); - - /* print the warm fuzzy */ - if (!quiet) - error (0, 0, "Committing %s", update_dir); - - /* get commit message */ - if (use_editor) - { - got_message = 1; - real_repos = Name_Repository (dir, update_dir); - do_editor (update_dir, &message, real_repos, ulist); - free (real_repos); - } - return (R_PROCESS); -} - -/* - * Process the post-commit proc if necessary - */ -/* ARGSUSED */ -static int -commit_dirleaveproc (dir, err, update_dir) - char *dir; - int err; - char *update_dir; -{ - /* update the per-directory tag info */ - if (err == 0 && write_dirtag != NULL) - { - WriteTag ((char *) NULL, write_dirtag, (char *) NULL); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_sticky (update_dir, Name_Repository (dir, update_dir), - write_dirtag, (char *) NULL); -#endif - } - - return (err); -} - -/* - * find the maximum major rev number in an entries file - */ -static int -findmaxrev (p, closure) - Node *p; - void *closure; -{ - char *cp; - int thisrev; - Entnode *entdata; - - entdata = (Entnode *) p->data; - cp = strchr (entdata->version, '.'); - if (cp != NULL) - *cp = '\0'; - thisrev = atoi (entdata->version); - if (cp != NULL) - *cp = '.'; - if (thisrev > maxrev) - maxrev = thisrev; - return (0); -} - -/* - * Actually remove a file by moving it to the attic - * XXX - if removing a ,v file that is a relative symbolic link to - * another ,v file, we probably should add a ".." component to the - * link to keep it relative after we move it into the attic. - */ -static int -remove_file (file, repository, tag, message, entries, srcfiles) - char *file; - char *repository; - char *tag; - char *message; - List *entries; - List *srcfiles; -{ - mode_t omask; - int retcode; - char rcs[PATH_MAX]; - char *tmp; - -#ifdef DEATH_SUPPORT - int branch; - char *lockflag; - char *corev; - char *rev; - char *prev_rev; - Node *p; - RCSNode *rcsfile; - - corev = NULL; - rev = NULL; - prev_rev = NULL; - lockflag = 0; -#endif /* DEATH_SUPPORT */ - - retcode = 0; - - locate_rcs (file, repository, rcs); - -#ifdef DEATH_SUPPORT - branch = 0; - if (tag && !(branch = RCS_isbranch (file, tag, srcfiles))) -#else - if (tag) -#endif - { - /* a symbolic tag is specified; just remove the tag from the file */ - if ((retcode = RCS_deltag (rcs, tag, 1)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag `%s' from `%s'", tag, rcs); - return (1); - } - Scratch_Entry (entries, file); - return (0); - } - -#ifdef DEATH_SUPPORT - /* we are removing the file from either the head or a branch */ - /* commit a new, dead revision. */ - - /* Print message indicating that file is going to be removed. */ - (void) printf ("Removing %s;\n", file); - - rev = NULL; - lockflag = "-l"; - if (branch) - { - char *branchname; - - rev = RCS_whatbranch (file, tag, srcfiles); - if (rev == NULL) - { - error (0, 0, "cannot find branch \"%s\".", tag); - return (1); - } - - p = findnode (srcfiles, file); - if (p == NULL) - { - error (0, 0, "boy, I'm confused."); - return (1); - } - rcsfile = (RCSNode *) p->data; - branchname = RCS_getbranch (rcsfile, rev, 1); - if (branchname == NULL) - { - /* no revision exists on this branch. use the previous - revision but do not lock. */ - corev = RCS_gettag (rcsfile, tag, 1, 0); - prev_rev = xstrdup(rev); - lockflag = ""; - } else - { - corev = xstrdup (rev); - prev_rev = xstrdup(branchname); - free (branchname); - } - - } else /* Not a branch */ - { - - /* Get current head revision of file. */ - p = findnode (srcfiles, file); - if (p == NULL) - { - error (0, 0, "could not find parsed rcsfile %s", file); - return (1); - } - rcsfile = (RCSNode *) p->data; - prev_rev = RCS_head (rcsfile); - } - - /* if removing without a tag or a branch, then make sure the default - branch is the trunk. */ - if (!tag && !branch) - { - if (RCS_setbranch (rcs, NULL) != 0) - { - error (0, 0, "cannot change branch to default for %s", - rcs); - return (1); - } - } - -#ifdef SERVER_SUPPORT - if (server_active) { - /* If this is the server, there will be a file sitting in the - temp directory which is the kludgy way in which server.c - tells time_stamp that the file is no longer around. Remove - it so we can create temp files with that name (ignore errors). */ - unlink_file (file); - } -#endif - - /* check something out. Generally this is the head. If we have a - particular rev, then name it. except when creating a branch, - lock the rev we're checking out. */ - run_setup ("%s%s %s %s%s %s", Rcsbin, RCS_CO, - lockflag, - rev ? "-r" : "", - rev ? corev : "", rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) - != 0) { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to check out `%s'", rcs); - return (1); - } - - if (corev != NULL) - free (corev); - -#ifdef DEATH_STATE - run_setup ("%s%s -f -sdead %s%s", Rcsbin, RCS_CI, rev ? "-r" : "", -#else - run_setup ("%s%s -K %s%s", Rcsbin, RCS_CI, rev ? "-r" : "", -#endif - rev ? rev : ""); - run_args ("-m%s", make_message_rcslegal (message)); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) - != 0) { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to commit dead revision for `%s'", rcs); - return (1); - } - - if (rev != NULL) - free (rev); - - if (!branch) -#else /* No DEATH_SUPPORT */ - else -#endif /* No DEATH_SUPPORT */ - { - /* this was the head; really move it into the Attic */ - tmp = xmalloc(strlen(repository) + - sizeof('/') + - sizeof(CVSATTIC) + - sizeof('/') + - strlen(file) + - sizeof(RCSEXT) + 1); - (void) sprintf (tmp, "%s/%s", repository, CVSATTIC); - omask = umask (cvsumask); - (void) CVS_MKDIR (tmp, 0777); - (void) umask (omask); - (void) sprintf (tmp, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT); - -#ifdef DEATH_SUPPORT - if (strcmp (rcs, tmp) != 0 - && rename (rcs, tmp) == -1 - && (isreadable (rcs) || !isreadable (tmp))) - { - free(tmp); - return (1); - } - free(tmp); - } - - /* Print message that file was removed. */ - (void) printf ("%s <-- %s\n", rcs, file); - (void) printf ("new revision: delete; "); - (void) printf ("previous revision: %s\n", prev_rev); - (void) printf ("done\n"); - free(prev_rev); - - Scratch_Entry (entries, file); - return (0); -#else /* No DEATH_SUPPORT */ - - if ((strcmp (rcs, tmp) == 0 || rename (rcs, tmp) != -1) || - (!isreadable (rcs) && isreadable (tmp))) - { - Scratch_Entry (entries, file); - /* FIXME: should free tmp. */ - return (0); - } - /* FIXME: should free tmp. */ - } - return (1); -#endif /* No DEATH_SUPPORT */ -} - -/* - * Do the actual checkin for added files - */ -static int -finaladd (file, rev, tag, options, update_dir, repository, entries) - char *file; - char *rev; - char *tag; - char *options; - char *update_dir; - char *repository; - List *entries; -{ - int ret; - char tmp[PATH_MAX]; - char rcs[PATH_MAX]; - - locate_rcs (file, repository, rcs); - ret = Checkin ('A', file, update_dir, repository, rcs, rev, tag, options, - message, entries); - if (ret == 0) - { - (void) sprintf (tmp, "%s/%s%s", CVSADM, file, CVSEXT_LOG); - (void) unlink_file (tmp); - } - else - fixaddfile (file, repository); - return (ret); -} - -/* - * Unlock an rcs file - */ -static void -unlockrcs (file, repository) - char *file; - char *repository; -{ - char rcs[PATH_MAX]; - int retcode = 0; - - locate_rcs (file, repository, rcs); - - if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0) - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not unlock %s", rcs); -} - -/* - * remove a partially added file. if we can parse it, leave it alone. - */ -static void -fixaddfile (file, repository) - char *file; - char *repository; -{ - RCSNode *rcsfile; - char rcs[PATH_MAX]; - int save_really_quiet; - - locate_rcs (file, repository, rcs); - save_really_quiet = really_quiet; - really_quiet = 1; - if ((rcsfile = RCS_parsercsfile (rcs)) == NULL) - (void) unlink_file (rcs); - else - freercsnode (&rcsfile); - really_quiet = save_really_quiet; -} - -/* - * put the branch back on an rcs file - */ -static void -fixbranch (file, repository, branch) - char *file; - char *repository; - char *branch; -{ - char rcs[PATH_MAX]; - int retcode = 0; - - if (branch != NULL && branch[0] != '\0') - { - locate_rcs (file, repository, rcs); - if ((retcode = RCS_setbranch (rcs, branch)) != 0) - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "cannot restore branch to %s for %s", branch, rcs); - } -} - -/* - * do the initial part of a file add for the named file. if adding - * with a tag, put the file in the Attic and point the symbolic tag - * at the committed revision. - */ - -static int -checkaddfile (file, repository, tag, options, srcfiles) - char *file; - char *repository; - char *tag; - char *options; - List *srcfiles; -{ - char rcs[PATH_MAX]; - char fname[PATH_MAX]; - mode_t omask; - int retcode = 0; -#ifdef DEATH_SUPPORT - int newfile = 0; -#endif - - if (tag) - { - (void) sprintf(rcs, "%s/%s", repository, CVSATTIC); - omask = umask (cvsumask); - if (CVS_MKDIR (rcs, 0777) != 0 && errno != EEXIST) - error (1, errno, "cannot make directory `%s'", rcs);; - (void) umask (omask); - (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT); - } - else - locate_rcs (file, repository, rcs); - -#ifdef DEATH_SUPPORT - if (isreadable(rcs)) - { - /* file has existed in the past. Prepare to resurrect. */ - char oldfile[PATH_MAX]; - char *rev; - Node *p; - RCSNode *rcsfile; - - if (tag == NULL) - { - /* we are adding on the trunk, so move the file out of the - Attic. */ - strcpy (oldfile, rcs); - sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); - - if (strcmp (oldfile, rcs) == 0 - || rename (oldfile, rcs) != 0 - || isreadable (oldfile) - || !isreadable (rcs)) - { - error (0, 0, "failed to move `%s' out of the attic.", - file); - return (1); - } - } - - p = findnode (srcfiles, file); - if (p == NULL) - { - error (0, 0, "could not find parsed rcsfile %s", file); - return (1); - } - - rcsfile = (RCSNode *) p->data; - rev = RCS_getversion (rcsfile, tag, NULL, 1, 0); - /* and lock it */ - if (lock_RCS (file, rcs, rev, repository)) { - error (0, 0, "cannot lock `%s'.", rcs); - free (rev); - return (1); - } - - free (rev); - } else { - /* this is the first time we have ever seen this file; create - an rcs file. */ - run_setup ("%s%s -i", Rcsbin, RCS); - - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG); - /* If the file does not exist, no big deal. In particular, the - server does not (yet at least) create CVSEXT_LOG files. */ - if (isfile (fname)) - run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG); - - /* Set RCS keyword expansion options. */ - if (options && options[0] == '-' && options[1] == 'k') - run_arg (options); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) - { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not create %s", rcs); - return (1); - } - newfile = 1; - } - - /* when adding a file for the first time, and using a tag, we need - to create a dead revision on the trunk. */ - if (tag && newfile) - { - char tmp[PATH_MAX]; - - /* move the new file out of the way. */ - (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file); - rename_file (file, fname); - copy_file (DEVNULL, file); - - /* commit a dead revision. */ - (void) sprintf (tmp, "-mfile %s was initially added on branch %s.", file, tag); -#ifdef DEATH_STATE - run_setup ("%s%s -q -f -sdead", Rcsbin, RCS_CI); -#else - run_setup ("%s%s -q -K", Rcsbin, RCS_CI); -#endif - run_arg (tmp); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) - { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not create initial dead revision %s", rcs); - return (1); - } - - /* put the new file back where it was */ - rename_file (fname, file); - - /* and lock it once again. */ - if (lock_RCS (file, rcs, NULL, repository)) { - error (0, 0, "cannot lock `%s'.", rcs); - return (1); - } - } - - if (tag != NULL) - { - /* when adding with a tag, we need to stub a branch, if it - doesn't already exist. */ - Node *p; - RCSNode *rcsfile; - - rcsfile = RCS_parse (file, repository); - if (rcsfile == NULL) - { - error (0, 0, "could not read %s", rcs); - return (1); - } - - if (!RCS_nodeisbranch (tag, rcsfile)) { - /* branch does not exist. Stub it. */ - char *head; - char *magicrev; - - head = RCS_getversion (rcsfile, NULL, NULL, 0, 0); - magicrev = RCS_magicrev (rcsfile, head); - if ((retcode = RCS_settag(rcs, tag, magicrev)) != 0) - { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not stub branch %s for %s", tag, rcs); - return (1); - } - - freercsnode (&rcsfile); - - /* reparse the file, then add it to our list. */ - rcsfile = RCS_parse (file, repository); - if (rcsfile == NULL) - { - error (0, 0, "could not reparse %s", rcs); - return (1); - } - - free (head); - free (magicrev); - } - else - { - /* lock the branch. (stubbed branches need not be locked.) */ - if (lock_RCS (file, rcs, NULL, repository)) { - error (0, 0, "cannot lock `%s'.", rcs); - return (1); - } - } - - /* add (replace) this rcs file to our list */ - p = findnode (srcfiles, file); - - if (p != NULL) - freercsnode((RCSNode **) &p->data); - - delnode(p); - - RCS_addnode (file, rcsfile, srcfiles); - } -#else /* No DEATH_SUPPORT */ - run_setup ("%s%s -i", Rcsbin, RCS); - run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG); - /* Set RCS keyword expansion options. */ - if (options && options[0] == '-' && options[1] == 'k') - run_arg (options); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) - { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not create %s", rcs); - return (1); - } -#endif /* No DEATH_SUPPORT */ - - fix_rcs_modes (rcs, file); - return (0); -} - -/* - * Lock the rcs file ``file'' - */ -static int -lockrcsfile (file, repository, rev) - char *file; - char *repository; - char *rev; -{ - char rcs[PATH_MAX]; - - locate_rcs (file, repository, rcs); - if (lock_RCS (file, rcs, rev, repository) != 0) - return (1); - else - return (0); -} - -/* - * Attempt to place a lock on the RCS file; returns 0 if it could and 1 if it - * couldn't. If the RCS file currently has a branch as the head, we must - * move the head back to the trunk before locking the file, and be sure to - * put the branch back as the head if there are any errors. - */ -static int -lock_RCS (user, rcs, rev, repository) - char *user; - char *rcs; - char *rev; - char *repository; -{ - RCSNode *rcsfile; - char *branch = NULL; - int err = 0; - - /* - * For a specified, numeric revision of the form "1" or "1.1", (or when - * no revision is specified ""), definitely move the branch to the trunk - * before locking the RCS file. - * - * The assumption is that if there is more than one revision on the trunk, - * the head points to the trunk, not a branch... and as such, it's not - * necessary to move the head in this case. - */ - if (rev == NULL || (rev && isdigit (*rev) && numdots (rev) < 2)) - { - if ((rcsfile = RCS_parsercsfile (rcs)) == NULL) - { - /* invalid rcs file? */ - err = 1; - } - else - { - /* rcsfile is valid */ - branch = xstrdup (rcsfile->branch); - freercsnode (&rcsfile); - if (branch != NULL) - { - if (RCS_setbranch (rcs, NULL) != 0) - { - error (0, 0, "cannot change branch to default for %s", - rcs); - if (branch) - free (branch); - return (1); - } - } - err = RCS_lock(rcs, NULL, 0); - } - } - else - { - (void) RCS_lock(rcs, rev, 1); - } - - if (err == 0) - { - if (branch) - { - (void) strcpy (sbranch, branch); - free (branch); - } - else - sbranch[0] = '\0'; - return (0); - } - - /* try to restore the branch if we can on error */ - if (branch != NULL) - fixbranch (user, repository, branch); - - if (branch) - free (branch); - return (1); -} - -/* - * Called when "add"ing files to the RCS respository, as it is necessary to - * preserve the file modes in the same fashion that RCS does. This would be - * automatic except that we are placing the RCS ,v file very far away from - * the user file, and I can't seem to convince RCS of the location of the - * user file. So we munge it here, after the ,v file has been successfully - * initialized with "rcs -i". - */ -static void -fix_rcs_modes (rcs, user) - char *rcs; - char *user; -{ - struct stat sb; - - if (stat (user, &sb) != -1) - (void) chmod (rcs, (int) sb.st_mode & ~0222); -} - -/* - * free an UPDATE node's data (really nothing to do) - */ -void -update_delproc (p) - Node *p; -{ - p->data = (char *) NULL; -} - -/* - * Free the commit_info structure in p. - */ -static void -ci_delproc (p) - Node *p; -{ - struct commit_info *ci; - - ci = (struct commit_info *) p->data; - if (ci->rev) - free (ci->rev); - if (ci->tag) - free (ci->tag); - if (ci->options) - free (ci->options); - free (ci); -} - -/* - * Free the commit_info structure in p. - */ -static void -masterlist_delproc (p) - Node *p; -{ - struct master_lists *ml; - - ml = (struct master_lists *) p->data; - dellist (&ml->ulist); - dellist (&ml->cilist); - free (ml); -} - -/* - * Find an RCS file in the repository. - */ -static void -locate_rcs (file, repository, rcs) - char *file; - char *repository; - char *rcs; -{ - (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); - if (!isreadable (rcs)) - { - (void) sprintf (rcs, "%s/%s/%s%s", repository, CVSATTIC, file, RCSEXT); - if (!isreadable (rcs)) - (void) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); - } -} diff --git a/gnu/usr.bin/cvs/cvs/convert.sh b/gnu/usr.bin/cvs/cvs/convert.sh deleted file mode 100644 index 728e79f..0000000 --- a/gnu/usr.bin/cvs/cvs/convert.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# short script to convert cvs repositories to support file death. -# - -WORKDIR=/tmp/$$-cvs-convert -mkdir ${WORKDIR} -cd ${WORKDIR} - -case $# in -1) ;; -*) - echo Usage: convert repository 2>&1 - exit 1 - ;; -esac - -attics=`find $1 -name Attic -print` - -for i in ${attics} ; do - mkdir $i/SAVE - for j in $i/*,v ; do - echo $j - cp $j $i/SAVE - co -l $j - ci -f -sdead -m"recording file death" $j - done -done diff --git a/gnu/usr.bin/cvs/cvs/create_adm.c b/gnu/usr.bin/cvs/cvs/create_adm.c deleted file mode 100644 index 1fe8185..0000000 --- a/gnu/usr.bin/cvs/cvs/create_adm.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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. - * - * Create Administration. - * - * Creates a CVS administration directory based on the argument repository; the - * "Entries" file is prefilled from the "initrecord" argument. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)create_adm.c 1.28 94/09/23 $"; -USE(rcsid); -#endif - -/* update_dir includes dir as its last component. */ - -void -Create_Admin (dir, update_dir, repository, tag, date) - char *dir; - char *update_dir; - char *repository; - char *tag; - char *date; -{ - FILE *fout; - char *cp; - char tmp[PATH_MAX]; - -#ifdef SERVER_SUPPORT - if (trace) - { - char wd[PATH_MAX]; - getwd (wd); - fprintf (stderr, "%c-> Create_Admin (%s, %s, %s, %s, %s) in %s\n", - (server_active) ? 'S' : ' ', - dir, update_dir, repository, tag ? tag : "", - date ? date : "", wd); - } -#endif - - if (noexec) - return; - - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM); - else - (void) strcpy (tmp, CVSADM); - if (isfile (tmp)) - error (1, 0, "there is a version in %s already", update_dir); - - make_directory (tmp); - -#ifdef CVSADM_ROOT - /* record the current cvs root for later use */ - - Create_Root (dir, CVSroot); -#endif /* CVSADM_ROOT */ - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP); - else - (void) strcpy (tmp, CVSADM_REP); - fout = fopen (tmp, "w+"); - if (fout == NULL) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot open %s", tmp); - else - error (1, errno, "cannot open %s/%s", update_dir, CVSADM_REP); - } - cp = repository; - strip_path (cp); - -#ifdef RELATIVE_REPOS - /* - * If the Repository file is to hold a relative path, try to strip off - * the leading CVSroot argument. - */ - if (CVSroot != NULL) - { - char path[PATH_MAX]; - - (void) sprintf (path, "%s/", CVSroot); - if (strncmp (repository, path, strlen (path)) == 0) - cp = repository + strlen (path); - } -#endif - - if (fprintf (fout, "%s\n", cp) < 0) - { - if (update_dir[0] == '\0') - error (1, errno, "write to %s failed", tmp); - else - error (1, errno, "write to %s/%s failed", update_dir, CVSADM_REP); - } - if (fclose (fout) == EOF) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot close %s", tmp); - else - error (1, errno, "cannot close %s/%s", update_dir, CVSADM_REP); - } - - /* now, do the Entries file */ - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT); - else - (void) strcpy (tmp, CVSADM_ENT); - fout = fopen (tmp, "w+"); - if (fout == NULL) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot open %s", tmp); - else - error (1, errno, "cannot open %s/%s", update_dir, CVSADM_ENT); - } - if (fclose (fout) == EOF) - { - if (update_dir[0] == '\0') - error (1, errno, "cannot close %s", tmp); - else - error (1, errno, "cannot close %s/%s", update_dir, CVSADM_ENT); - } - - /* Create a new CVS/Tag file */ - WriteTag (dir, tag, date); - -#ifdef SERVER_SUPPORT - if (server_active) - server_set_sticky (update_dir, repository, tag, date); - - if (trace) - { - fprintf (stderr, "%c<- Create_Admin\n", - (server_active) ? 'S' : ' '); - } -#endif - -} diff --git a/gnu/usr.bin/cvs/cvs/cvs.1 b/gnu/usr.bin/cvs/cvs/cvs.1 deleted file mode 100644 index 2a566df..0000000 --- a/gnu/usr.bin/cvs/cvs/cvs.1 +++ /dev/null @@ -1,2185 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $Id: cvs.1,v 1.3 1995/12/10 23:01:58 peter Exp $ -.TH CVS 1 "\*(Dt" -.\" Full space in nroff; half space in troff -.de SP -.if n .sp -.if t .sp .5 -.. -.\" quoted command -.de ` -.RB ` "\|\\$1\|" '\\$2 -.. -.SH "NAME" -cvs \- Concurrent Versions System -.SH "SYNOPSIS" -.TP -\fBcvs\fP [ \fIcvs_options\fP ] -.I cvs_command -[ -.I command_options -] [ -.I command_args -] -.SH "DESCRIPTION" -.IX "revision control system" "\fLcvs\fR" -.IX cvs "" "\fLcvs\fP \- concurrent versions system" -.IX "concurrent versions system \- \fLcvs\fP" -.IX "release control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system" -.IX "source control system" "cvs command" "" "\fLcvs\fP \- concurrent versions system" -.IX revisions "cvs command" "" "\fLcvs\fP \- source control" -.B cvs -is a front end to the -.BR rcs ( 1 ) -revision control system which extends -the notion of revision control from a collection of files in a single -directory to a hierarchical collection of directories consisting of -revision controlled files. -These directories and files can be combined together to form a software -release. -.B cvs -provides the functions necessary to manage these software releases and to -control the concurrent editing of source files among multiple software -developers. -.SP -.B cvs -keeps a single copy of the master sources. -This copy is called the source ``repository''; it contains all the -information to permit extracting previous software releases at any -time based on either a symbolic revision tag, or a date in the past. -.SH "ESSENTIAL COMMANDS" -.B cvs -provides a rich variety of commands (\fIcvs_command\fP in the -Synopsis), each of which often has a wealth of options, to satisfy the -many needs of source management in distributed environments. However, -you don't have to master every detail to do useful work with -.BR cvs ; -in fact, five commands are sufficient to use (and contribute to) -the source repository. -.TP -\fBcvs checkout\fP \fImodules\fP\|.\|.\|. -A necessary preliminary for most \fBcvs\fP work: creates your private -copy of the source for \fImodules\fP (named collections of source; you -can also use a path relative to the source repository here). You can -work with this copy without interfering with others' work. At least -one subdirectory level is always created. -.TP -.B cvs update -Execute this command from \fIwithin\fP your private source -directory when you wish to update your copies of source files from -changes that other developers have made to the source in the -repository. -.TP -\fBcvs add\fP \fIfile\fP\|.\|.\|. -Use this command to enroll new files in \fBcvs\fP records of your -working directory. The files will be added to the repository the next -time you run -.` "cvs commit". -Note: -You should use the -.` "cvs import" -command to bootstrap new sources into the source repository. -.` "cvs add" -is only used for new files to an already checked-out module. -.TP -\fBcvs remove\fP \fIfile\fP\|.\|.\|. -Use this command (after erasing any files listed) to declare that you -wish to eliminate files from the repository. The removal does not -affect others until you run -.` "cvs commit". -.TP -\fBcvs commit\fP \fIfile\fP\|.\|.\|. -Use this command when you wish to ``publish'' your changes to other -developers, by incorporating them in the source repository. -.SH "OPTIONS" -The -.B cvs -command line can include -.IR cvs_options , -which apply to the overall -.B cvs -program; a -.IR cvs_command , -which specifies a particular action on the source repository; and -.I command_options -and -.I command_arguments -to fully specify what the -.I cvs_command -will do. -.SP -.I Warning: -you must be careful of precisely where you place options relative to the -.IR cvs_command . -The same option can mean different things depending on whether it -is in the -.I cvs_options -position (to the left of a -.B cvs -command) or in the -.I command_options -position (to the right of a -.B cvs -command). -.SP -There are only two situations where you may omit -.IR cvs_command : -.` "cvs \-H" -or -.` "cvs --help" -elicits a list of available commands, and -.` "cvs \-v" -or -.` "cvs --version" -displays version information on \fBcvs\fP itself. -.SP -.SH "CVS OPTIONS" -As of release 1.6, -.B cvs -supports -.SM GNU -style long options as well as short options. Only -a few long options are currently supported, these are listed in -brackets after the short options whose functions they duplicate. -.SP -Use these options to control the overall -.B cvs -program: -.TP -.B \-H [ --help ] -Display usage information about the specified -.I cvs_command -(but do not actually execute the command). If you don't specify a -command name, -.` "cvs \-H" -displays a summary of all the commands available. -.TP -.B \-Q -Causes the command to be -.I really -quiet; the command will generate output only for serious problems. -.TP -.B \-q -Causes the command to be somewhat quiet; informational messages, such -as reports of recursion through subdirectories, are suppressed. -.TP -\fB\-b\fP \fIbindir\fP -Use -.I bindir -as the directory where -.SM RCS -programs are located. -Overrides the setting of the -.SM RCSBIN -environment variable. -This value should be specified as an absolute pathname. -.TP -\fB\-d\fP \fICVS_root_directory\fP -Use -.I CVS_root_directory -as the root directory pathname of the master -.SM RCS -source repository. -Overrides the setting of the -.SM CVSROOT -environment variable. -This value should be specified as an absolute pathname. -.TP -\fB\-e\fP \fIeditor\fP -Use -.I editor -to enter revision log information. -Overrides the setting of the -.SM CVSEDITOR -and the -.SM EDITOR -environment variables. -.TP -.B \-f -Do not read the -.B cvs -startup file (\fI~/.cvsrc\fP). -.TP -.B \-l -Do not log the -.I cvs_command -in the command history (but execute it anyway). See the description -of the -.B history -command for information on command history. -.TP -.B \-n -Do not change any files. Attempt to execute the -.IR cvs_command , -but only to issue reports; do not remove, update, or merge any -existing files, or create any new files. -.TP -.B \-t -Trace program execution; display messages showing the steps of -.B cvs -activity. Particularly useful with -.B \-n -to explore the potential impact of an unfamiliar command. -.TP -.B \-r -Makes new working files read-only. -Same effect as if the -.SM CVSREAD -environment variable is set. -.TP -.B \-v [ --version ] -Displays version and copyright information for -.BR cvs . -.TP -.B \-w -Makes new working files read-write (default). -Overrides the setting of the -.SM CVSREAD -environment variable. -.TP -\fB\-z\fP \fIcompression\-level\fP -When transferring files across the network use -.B gzip -with compression level \fIcompression\-level\fP to compress and -de-compress data as it is transferred. Requires the presence of -the -.SM GNU -.B gzip -program in the current search path at both ends of the link. -.SH "USAGE" -Except when requesting general help with -.` "cvs \-H", -you must specify a -.I cvs_command -to -.B cvs -to select a specific release control function to perform. -Each -.B cvs -command accepts its own collection of options and arguments. -However, many options are available across several commands. -You can display a usage summary for each command by specifying the -.B \-H -option with the command. -.SH "CVS STARTUP FILE" -Normally, when CVS starts up, it reads the -.I .cvsrc -file from the home directory of the user reading it. This startup -procedure can be turned off with the -.B \-f -flag. -.SP -The -.I .cvsrc -file lists CVS commands with a list of arguments, one command per -line. For example, the following line in \fI.cvsrc\fP: -.SP -diff \-c -.SP -will mean that the -.` "cvs diff" -command will always be passed the \-c option in addition to any -other options that are specified in the command line (in this case -it will have the effect of producing context sensitive diffs for -all executions of -.` "cvs diff" -). -.SH "CVS COMMAND SUMMARY" -Here are brief descriptions of all the -.B cvs -commands: -.TP -.B add -Add a new file or directory to the repository, pending a -.` "cvs commit" -on the same file. -Can only be done from within sources created by a previous -.` "cvs checkout" -invocation. -Use -.` "cvs import" -to place whole new hierarchies of sources under -.B cvs -control. -(Does not directly affect repository; changes -working directory.) -.TP -.B admin -Execute -.SM RCS -control functions on the source repository. (Changes -repository directly; uses working directory without changing it.) -.TP -.B checkout -Make a working directory of source files for editing. (Creates or changes -working directory.) -.TP -.B commit -Apply to the source repository changes, additions, and deletions from your -working directory. (Changes repository.) -.TP -.B diff -Show differences between files in working directory and source -repository, or between two revisions in source repository. -(Does not change either repository or working directory.) -.TP -.B export -Prepare copies of a set of source files for shipment off site. -Differs from -.` "cvs checkout" -in that no -.B cvs -administrative directories are created (and therefore -.` "cvs commit" -cannot be executed from a directory prepared with -.` "cvs export"), -and a symbolic tag must be specified. -(Does not change repository; creates directory similar to working -directories). -.TP -.B history -Show reports on -.B cvs -commands that you or others have executed on a particular file or -directory in the source repository. (Does not change repository or -working directory.) History logs are kept only if enabled by creation -of the -.` "$CVSROOT/CVSROOT/history" -file; see -.BR cvs ( 5 ). -.TP -.B import -Incorporate a set of updates from off-site into the source repository, -as a ``vendor branch''. (Changes repository.) -.TP -.B log -Display -.SM RCS -log information. -(Does not change repository or working directory.) -.TP -.B rdiff -Prepare a collection of diffs as a patch file between two releases in -the repository. (Does not change repository or working directory.) -.TP -.B release -Cancel a -.` "cvs checkout", -abandoning any changes. -(Can delete working directory; no effect on repository.) -.TP -.B remove -Remove files from the source repository, pending a -.` "cvs commit" -on the same files. (Does not directly affect repository; -changes working directory.) -.TP -.B rtag -Explicitly specify a symbolic tag for particular revisions of files in the -source repository. See also -.` "cvs tag". -(Changes repository directly; does not require or affect -working directory.) -.TP -.B status -Show current status of files: latest version, version in working -directory, whether working version has been edited and, optionally, -symbolic tags in the -.SM RCS -file. (Does not change -repository or working directory.) -.TP -.B tag -Specify a symbolic tag for files in the repository. By default, tags -the revisions -that were last synchronized with your working directory. (Changes -repository directly; uses working directory without changing it.) -.TP -.B update -Bring your working directory up to date with changes from the -repository. Merges are performed automatically when possible; a -warning is issued if manual resolution is required for conflicting -changes. (Changes working directory; does not change repository.) -.SH "COMMON COMMAND OPTIONS" -This section describes the -.I command_options -that are available across several -.B cvs -commands. Not all commands support all of these options; each option -is only supported for commands where it makes sense. However, when -a command has one of these options you can count on the same meaning -for the option as in other commands. (Other command -options, which are listed with the individual commands, may have -different meanings from one -.B cvs -command to another.) -.I "Warning:" -the -.B history -command is an exception; -it supports many options that conflict -even with these standard options. -.TP -\fB\-D\fP \fIdate_spec\fP -Use the most recent revision no later than \fIdate_spec\fP (a single -argument, date description specifying a date in the -past). A wide variety of date formats are supported by the underlying -.SM RCS -facilities, similar to those described in -.BR co ( 1 ), -but not exactly the same. -The \fIdate_spec\fP is interpreted as being in the local timezone, unless a -specific timezone is specified. -The specification is ``sticky'' when you use it to make a -private copy of a source file; that is, when you get a working file -using \fB\-D\fP, \fBcvs\fP records the date you -specified, so that further updates in the same directory will use the -same date (unless you explicitly override it; see the description of -the \fBupdate\fP command). -.B \-D -is available with the -.BR checkout ", " diff ", " history ", " export ", " -.BR rdiff ", " rtag ", and " -.B update -commands. -Examples of valid date specifications include: -.in +1i -.ft B -.nf -1 month ago -2 hours ago -400000 seconds ago -last year -last Monday -yesterday -a fortnight ago -3/31/92 10:00:07 PST -January 23, 1987 10:05pm -22:00 GMT -.fi -.ft P -.in -1i -.TP -.B \-f -When you specify a particular date or tag to \fBcvs\fP commands, they -normally ignore files that do not contain the tag (or did not exist on -the date) that you specified. Use the \fB\-f\fP option if you want -files retrieved even when there is no match for the tag or date. (The -most recent version is used in this situation.) -.B \-f -is available with these commands: -.BR checkout ", " export ", " -.BR rdiff ", " rtag ", and " update . -.TP -.B \-H -Help; describe the options available for this command. This is the -only option supported for -.I all -.B cvs -commands. -.TP -\fB\-k\fP \fIkflag\fP -Alter the default -.SM RCS -processing of keywords; all the -.B \-k -options described in -.BR co ( 1 ) -are available. The \fB\-k\fP option is available with the -.BR add ", " checkout ", " diff ", " export ", " -.BR rdiff ", and " update -commands. Your \fIkflag\fP specification is ``sticky'' when you use -it to create a private copy of a source file; that is, when you use -this option with the \fBcheckout\fP or \fBupdate\fP commands, -\fBcvs\fP associates your selected \fIkflag\fP with the file, and -continues to use it with future \fBupdate\fP commands on the same file -until you specify otherwise. -.SP -Some of the more useful \fIkflag\fPs are \-ko and \-kb (for binary files, -only compatible with -.SM RCS -version 5.7 or later), and \-kv which is useful for an -.B export -where you wish to retain keyword information after an -.B import -at some other site. -.TP -.B \-l -Local; run only in current working directory, rather than recurring through -subdirectories. Available with the following commands: -.BR checkout ", " commit ", " diff ", " -.BR export ", " remove ", " rdiff ", " rtag ", " -.BR status ", " tag ", and " update . -.I Warning: -this is not the same -as the overall -.` "cvs \-l" -option, which you can specify to the -.I left -of a -.B cvs -command! -.TP -.B \-n -Do -.I not -run any -.BR checkout / commit / tag / update -program. (A program can be specified to run on each of these -activities, in the modules database; this option bypasses it.) -Available with the -.BR checkout ", " commit ", " export ", and " -.B rtag -commands. -.I Warning: -this is not the same -as the overall -.` "cvs \-n" -option, which you can specify to the -.I left -of a -.B cvs -command! -.TP -.B \-P -Prune (remove) directories that are empty after being updated, on -.BR checkout ", or " update . -Normally, an empty directory (one that is void of revision-controlled -files) is left alone. -Specifying -.B \-P -will cause these directories to be silently removed from your checked-out -sources. -This does not remove the directory from the repository, only from your -checked out copy. -Note that this option is implied by the -.B \-r -or -.B \-D -options of -.BR checkout " and " export . -.TP -.B \-p -Pipe the files retrieved from the repository to standard output, -rather than writing them in the current directory. Available with the -.BR checkout " and " update -commands. -.TP -\fB\-r\fP \fItag\fP -Use the revision specified by the -.I tag -argument instead of the default ``head'' revision. As well as -arbitrary tags defined with the \fBtag\fP or \fBrtag\fP command, two -special tags are always available: -.` "HEAD" -refers to the most -recent version available in the repository, and -.` "BASE" -refers to the revision you last checked out into the current working -directory. -.SP -The \fItag\fP specification is ``sticky'' when you use -this option with -.` "cvs checkout" -or -.` "cvs update" -to -make your own copy of a file: \fBcvs\fP remembers the \fItag\fP and -continues to use it on future \fBupdate\fP commands, until you specify -otherwise. -.I tag -can be either a symbolic or numeric tag, in -.SM RCS -fashion. -Specifying the -.B \-q -global option along with the -.B \-r -command option is often useful, to suppress the warning messages when the -.SM RCS -file does not contain the specified tag. -.B \-r -is available with the -.BR checkout ", " commit ", " diff ", " -.BR history ", " export ", " -.BR rdiff ", " rtag ", and " update -commands. -.I Warning: -this is not the same -as the overall -.` "cvs \-r" -option, which you can specify to the -.I left -of a -.B cvs -command! -.SH "CVS COMMANDS" -Here (finally) are details on all the -.B cvs -commands and the options each accepts. The summary lines at the top -of each command's description highlight three kinds of things: -.TP 1i -\ \ \ \ Command Options and Arguments -Special options are described in detail below; common command options -may appear only in the summary line. -.TP 1i -\ \ \ \ Working Directory, or Repository? -Some \fBcvs\fP commands require a working directory to operate; some -require a repository. Also, some commands \fIchange\fP the -repository, some change the working directory, and some change -nothing. -.TP 1i -\ \ \ \ Synonyms -Many commands have synonyms, which you may find easier to -remember (or type) than the principal name. -.PP -.TP -\fBadd\fP [\fB\-k\fP \fIkflag\fP] [\fB\-m '\fP\fImessage\fP\fB'\fP] \fIfiles.\|.\|.\fP -.I Requires: -repository, working directory. -.br -.I Changes: -working directory. -.br -.I Synonym: -.B new -.br -Use the -.B add -command to create a new file or directory in the -.SM RCS -source repository. -The files or directories specified with -.B add -must already exist in the current directory (which must have been created -with the -.B checkout -command). -To add a whole new directory hierarchy to the source repository -(for example, files received from a third-party vendor), use the -.` "cvs import" -command instead. -.SP -If the argument to -.` "cvs add" -refers to an immediate sub-directory, the directory is -created at the correct place in the -.SM RCS -source repository, and the necessary -.B cvs -administration files are created in your working directory. -If the directory already exists in the source repository, -.` "cvs add" -still creates the administration files in your version of the directory. -This allows you to use -.` "cvs add" -to add a particular directory to your private sources even if -someone else created that directory after your -.B checkout -of the sources. You can do the following: -.SP -.in +1i -.ft B -.nf -example% mkdir new_directory -example% cvs add new_directory -example% cvs update new_directory -.fi -.ft P -.in -1i -.SP -An alternate approach using -.` "cvs update" -might be: -.SP -.in +1i -.ft B -.nf -example% cvs update -d new_directory -.fi -.ft P -.in -1i -.SP -(To add \fIany available\fP new directories to your working directory, it's -probably simpler to use -.` "cvs checkout" -or -.` "cvs update -d".) -.SP -The added files are not placed in the -.SM RCS -source repository until you use -.` "cvs commit" -to make the change permanent. -Doing a -.` "cvs add" -on a file that was removed with the -.` "cvs remove" -command will resurrect the file, if no -.` "cvs commit" -command intervened. -.SP -You will have the opportunity to specify a logging message, as usual, -when you use -.` "cvs commit" -to make the new file permanent. If you'd like to have another -logging message associated with just -.I creation -of the file (for example, to describe the file's purpose), you can -specify it with the -.` "\-m \fImessage\fP" -option to the -.B add -command. -.SP -The -.` "-k kflag" -option specifies the default way that this -file will be checked out. -The -.` "kflag" -argument is stored in the -.SM RCS -file and can be changed with -.` "cvs admin". -Specifying -.` "-ko" -is useful for checking in binaries that -shouldn't have the -.SM RCS -id strings expanded. -.TP -\fBadmin\fP [\fIrcs-options\fP] \fIfiles.\|.\|.\fP -.I Requires: -repository, working directory. -.br -.I Changes: -repository. -.br -.I Synonym: -.B rcs -.br -This is the -.B cvs -interface to assorted administrative -.SM RCS -facilities, documented in -.BR rcs ( 1 ). -.` "cvs admin" -simply passes all its options and arguments to the -.B rcs -command; it does no filtering or other processing. -This command does work recursively, however, so extreme care should be -used. -.TP -\fBcheckout\fP [\fBoptions\fP] \fImodules\fP.\|.\|. -.I Requires: -repository. -.br -.I Changes: -working directory. -.br -.I Synonyms: -.BR co ", " get -.br -Make a working directory containing copies of the source files specified by -.IR modules . -You must execute -.` "cvs checkout" -before using most of the other -.B cvs -commands, since most of them operate on your working directory. -.SP -\fImodules\fP are either symbolic names (themselves defined as the -module -.` "modules" -in the source repository; see -.BR cvs ( 5 )) -for some collection of source directories and files, or paths to -directories or files in the repository. -.SP -Depending on the -.I modules -you specify, -.B checkout -may recursively create directories and populate them with the appropriate -source files. -You can then edit these source files at any time (regardless of whether -other software developers are editing their own copies of the sources); -update them to include new changes applied by others to the source -repository; or commit your work as a permanent change to the -.SM RCS -repository. -.SP -Note that -.B checkout -is used to create directories. -The top-level directory created is always added to the directory -where -.B checkout -is invoked, and usually has the same name as the specified -.IR module . -In the case of a -.I module -alias, the created sub-directory may have a different name, but you can be -sure that it will be a sub-directory, and that -.B checkout -will show the relative path leading to each file as it is extracted into -your private work area (unless you specify the -.B \-Q -global option). -.SP -Running -.` "cvs checkout" -on a directory that was already built by a prior -.B checkout -is also permitted, and -has the same effect as specifying the -.B \-d -option to the -.B update -command described below. -.SP -The -.I options -permitted with -.` "cvs checkout" -include the standard command options -.BR \-P ", " \-f ", " -.BI \-k " kflag" -\&, -.BR \-l ", " \-n ", " \-p ", " -.BR \-r -.IR tag ", and" -.BI \-D " date"\c -\&. -.SP -In addition to those, you can use these special command options -with -.BR checkout : -.SP -Use the -.B \-A -option to reset any sticky tags, dates, or -.B \-k -options. (If you get a working file using one of the -\fB\-r\fP, \fB\-D\fP, or \fB\-k\fP options, \fBcvs\fP remembers the -corresponding tag, date, or \fIkflag\fP and continues using it on -future updates; use the \fB\-A\fP option to make \fBcvs\fP forget these -specifications, and retrieve the ``head'' version of the file). -.SP -The -.BI \-j " branch" -option merges the changes made between the -resulting revision and the revision that it is based on (e.g., if -the tag refers to a branch, -.B cvs -will merge all changes made in that branch into your working file). -.SP -With two \fB-j\fP options, -.B cvs -will merge in the changes between the two respective revisions. -This can be used to ``remove'' a certain delta from your working file. -.SP -In addition, each \fB-j\fP option can contain on 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 -.` "cvs import" -tells you to do when you have -just imported sources that have conflicts with local changes: -.SP -.in +1i -.ft B -.nf -example% cvs checkout -jTAG:yesterday -jTAG module -.fi -.ft P -.in -1i -.SP -Use the -.B \-N -option with -.` "\-d \fIdir\fP" -to avoid shortening module paths in your working directory. (Normally, \fBcvs\fP shortens paths as much as possible when you specify an explicit target directory.) -.SP -Use the -.B \-c -option to copy the module file, sorted, to the standard output, -instead of creating or modifying any files or directories in your -working directory. -.SP -Use the -.BI \-d " dir" -option to create a directory called -.I dir -for the working files, instead of using the module name. Unless you -also use \fB\-N\fP, the paths created under \fIdir\fP will be as short -as possible. -.SP -Use the -.B \-s -option to display per-module status information stored with -the -.B \-s -option within the modules file. -.TP -\fBcommit\fP [\fB\-lnR\fP] [\fB\-m\fP '\fIlog_message\fP' | \fB\-f\fP \fIfile\fP] [\fB\-r\fP \fIrevision\fP] [\fIfiles.\|.\|.\fP] -.I Requires: -working directory, repository. -.br -.I Changes: -repository. -.br -.I Synonym: -.B ci -.br -Use -.` "cvs commit" -when you want to incorporate changes from your working source -files into the general source repository. -.SP -If you don't specify particular \fIfiles\fP to commit, all -of the files in your working current directory are examined. -.B commit -is careful to change in the repository only those files that you have -really changed. By default (or if you explicitly specify the -.B \-R -option), files -in subdirectories are also examined and committed if they have -changed; you can use the -.B \-l -option to limit -.B commit -to the current directory only. -Sometimes you may want to force a file to be committed even though it -is unchanged; this is achieved with the -.B \-f -flag, which also has the effect of disabling recursion (you can turn -it back on with -.B \-R -of course). -.SP -.B commit -verifies that the selected files are up to date with the current revisions -in the source repository; it will notify you, and exit without -committing, if any of the specified files must be made current first -with -.` "cvs update". -.B commit -does not call the -.B update -command for you, but rather leaves that for you to do when -the time is right. -.SP -When all is well, an editor is invoked to allow you to enter a log -message that will be written to one or more logging programs and placed in the -.SM RCS -source repository file. -You can instead specify the log message on the command line with the -.B \-m -option, thus suppressing the editor invocation, or use the -.B \-F -option to specify that the argument \fIfile\fP contains the log message. -.SP -The -.B \-r -option can be used to commit to a particular symbolic or numeric revision -within the -.SM RCS -file. -For example, to bring all your files up to the -.SM RCS -revision ``3.0'' (including those that haven't changed), you might do: -.SP -.in +1i -.ft B -.nf -example% cvs commit -r3.0 -.fi -.ft P -.in -1i -.SP -.B cvs -will only allow you to commit to a revision that is on the main trunk (a -revision with a single dot). -However, you can also commit to a branch revision (one that has an even -number of dots) with the -.B \-r -option. -To create a branch revision, one typically use the -.B \-b -option of the -.BR rtag " or " tag -commands. -Then, either -.BR checkout " or " update -can be used to base your sources on the newly created branch. -From that point on, all -.B commit -changes made within these working sources will be automatically added -to a branch revision, thereby not perturbing main-line development in any -way. -For example, if you had to create a patch to the 1.2 version of the -product, even though the 2.0 version is already under development, you -might do: -.SP -.in +1i -.ft B -.nf -example% cvs rtag -b -rFCS1_2 FCS1_2_Patch product_module -example% cvs checkout -rFCS1_2_Patch product_module -example% cd product_module -[[ hack away ]] -example% cvs commit -.fi -.ft P -.in -1i -.SP -Say you have been working on some extremely experimental software, based on -whatever revision you happened to checkout last week. -If others in your group would like to work on this software with you, but -without disturbing main-line development, you could commit your change to a -new branch. -Others can then checkout your experimental stuff and utilize the full -benefit of -.B cvs -conflict resolution. -The scenario might look like: -.SP -.in +1i -.ft B -.nf -example% cvs tag -b EXPR1 -example% cvs update -rEXPR1 -[[ hack away ]] -example% cvs commit -.fi -.ft P -.in -1i -.SP -Others would simply do -.` "cvs checkout -rEXPR1 whatever_module" -to work with you on the experimental change. -.TP -\fBdiff\fP [\fB\-kl\fP] [\fIrcsdiff_options\fP] [[\fB\-r\fP \fIrev1\fP | \fB\-D\fP \fIdate1\fP] [\fB\-r\fP \fIrev2\fP | \fB\-D\fP \fIdate2\fP]] [\fIfiles.\|.\|.\fP] -.I Requires: -working directory, repository. -.br -.I Changes: -nothing. -.br -You can compare your working files with revisions in the source -repository, with the -.` "cvs diff" -command. If you don't specify a particular revision, your files -are compared with the revisions they were based on. You can also use -the standard -.B cvs -command option -.B \-r -to specify a particular revision to compare your files with. Finally, -if you use -.B \-r -twice, you can see differences between two revisions in the -repository. -You can also specify -.B \-D -options to diff against a revision in the past. -The -.B \-r -and -.B \-D -options can be mixed together with at most two options ever specified. -.SP -See -.BR rcsdiff ( 1 ) -for a list of other accepted options. -.SP -If you don't specify any files, -.B diff -will display differences for all those files in the current directory -(and its subdirectories, unless you use the standard option -.BR \-l ) -that -differ from the corresponding revision in the source repository -(i.e. files that -.I you -have changed), or that differ from the revision specified. -.TP -\fBexport\fP [\-\fBf\|lNnQq\fP] \fB\-r\fP \fIrev\fP\||\|\fB\-D\fP \fIdate\fP [\fB\-d\fP \fIdir\fP] [\fB\-k\fP \fIkflag\fP] \fImodule\fP.\|.\|. -.I Requires: -repository. -.br -.I Changes: -current directory. -.br -This command is a variant of -.` "cvs checkout"; -use it when you want a copy of the source for \fImodule\fP -without the \fBcvs\fP administrative directories. For example, you -might use -.` "cvs export" -to prepare source for shipment -off-site. This command \fIrequires\fP that you specify a date or tag -(with \fB\-D\fP or \fB\-r\fP), so that you can count on reproducing -the source you ship to others. -.SP -The only non-standard options are -.` "\-d \fIdir\fP" -(write the -source into directory \fIdir\fP) and -.` "\-N" -(don't shorten -module paths). -These have the same meanings as the same options in -.` "cvs checkout". -.SP -The -.B \-kv -option is useful when -.B export -is used. -This causes any -.SM RCS -keywords to be expanded such that an -.B import -done at some other site will not lose the keyword revision information. -Other \fIkflag\fPs may be used with -.` "cvs export" -and are described in -.BR co ( 1 ). -.TP -\fBhistory\fP [\fB\-\fP\fIreport\fP] [\fB\-\fP\fIflags\fP] [\fB\-\fP\fIoptions args\fP] [\fIfiles\fP.\|.\|.] -.I Requires: -the file -.` "$CVSROOT/CVSROOT/history" -.br -.I Changes: -nothing. -.br -\fBcvs\fP keeps a history file that tracks each use of the -\fBcheckout\fP, \fBcommit\fP, \fBrtag\fP, \fBupdate\fP, and \fBrelease\fP -commands. You can use -.` "cvs history" -to display this -information in various formats. -.SP -.I Warning: -.` "cvs history" -uses -.` "\-f", -.` "\-l", -.` "\-n", -and -.` "\-p" -in ways that conflict with the -descriptions in -.SM -COMMON COMMAND OPTIONS\c -\&. -.SP -Several options (shown above as \fB\-\fP\fIreport\fP) control what -kind of report is generated: -.TP 1i -.B \ \ \ \ \ \ \-c -Report on each time \fBcommit\fP was used (i.e., each time the -repository was modified). -.TP 1i -\fB\ \ \ \ \ \ \-m\fP \fImodule\fP -Report on a particular \fImodule\fP. (You can meaningfully use -\fB\-m\fP more than once on the command line.) -.TP 1i -.B \ \ \ \ \ \ \-o -Report on checked-out modules. -.TP 1i -.B \ \ \ \ \ \ \-T -Report on all tags. -.TP 1i -\fB\ \ \ \ \ \ \-x\fP \fItype\fP -Extract a particular set of record types \fIX\fP from the \fBcvs\fP -history. The types are indicated by single letters, which you may -specify in combination. -Certain commands have a single record type: \fBcheckout\fP (type `O'), -\fBrelease\fP (type `F'), and \fBrtag\fP (type `T'). One of four -record types may result from an \fBupdate\fP: `W', when the working copy -of a file is deleted during update (because it was gone from the -repository); `U', when a working file was copied from the -repository; `G', when a merge was necessary and it succeeded; and 'C', -when a merge was necessary but collisions were detected (requiring -manual merging). Finally, one of three record types results from -\fBcommit\fP: `M', when a file was modified; `A', when a file is first -added; and `R', when a file is removed. -.TP 1i -.B \ \ \ \ \ \ \-e -Everything (all record types); equivalent to specifying -.` "\-xMACFROGWUT". -.TP 1i -\fB\ \ \ \ \ \ \-z\fP \fIzone\fP -Use time zone -.I zone -when outputting history records. -The zone name -.B LT -stands for local time; -numeric offsets stand for hours and minutes ahead of UTC. -For example, -.B +0530 -stands for 5 hours and 30 minutes ahead of (i.e. east of) UTC. -.PP -.RS .5i -The options shown as \fB\-\fP\fIflags\fP constrain the report without -requiring option arguments: -.RE -.TP 1i -.B \ \ \ \ \ \ \-a -Show data for all users (the default is to show data only for the user -executing -.` "cvs history"). -.TP 1i -.B \ \ \ \ \ \ \-l -Show last modification only. -.TP 1i -.B \ \ \ \ \ \ \-w -Show only the records for modifications done from the same working -directory where -.` "cvs history" -is executing. -.PP -.RS .5i -The options shown as \fB\-\fP\fIoptions args\fP constrain the report -based on an argument: -.RE -.TP 1i -\fB\ \ \ \ \ \ \-b\fP \fIstr\fP -Show data back to a record containing the string \fIstr\fP in either -the module name, the file name, or the repository path. -.TP 1i -\fB\ \ \ \ \ \ \-D\fP \fIdate\fP -Show data since \fIdate\fP. -.TP 1i -\fB\ \ \ \ \ \ \-p\fP \fIrepository\fP -Show data for a particular source repository (you can specify several -\fB\-p\fP options on the same command line). -.TP 1i -\fB\ \ \ \ \ \ \-r\fP \fIrev\fP -Show records referring to revisions since the revision or tag -named \fIrev\fP appears in individual RCS files. -Each -.SM RCS -file is searched for the revision or tag. -.TP 1i -\fB\ \ \ \ \ \ \-t\fP \fItag\fP -Show records since tag \fItag\fP was last added to the the history file. -This differs from the \fB-r\fP flag above in that it reads -only the history file, not the -.SM RCS -files, and is much faster. -.TP 1i -\fB\ \ \ \ \ \ \-u\fP \fIname\fP -Show records for user \fIname\fP. -.PP -.TP -\fBimport\fP [\fB\-\fP\fIoptions\fP] \fIrepository vendortag releasetag\fP.\|.\|. -.I Requires: -Repository, source distribution directory. -.br -.I Changes: -repository. -.br -Use -.` "cvs import" -to incorporate an entire source -distribution from an outside source (e.g., a source vendor) into your -source repository directory. You can use this command both for -initial creation of a repository, and for wholesale updates to the -module form the outside source. -.SP -The \fIrepository\fP argument gives a directory name (or a path to a -directory) under the CVS root directory for repositories; if the -directory did not exist, \fBimport\fP creates it. -.SP -When you use \fBimport\fP for updates to source that has been modified in your -source repository (since a prior \fBimport\fP), it -will notify you of any files that conflict in the two branches of -development; use -.` "cvs checkout -j" -to reconcile the differences, as \fBimport\fP instructs you to do. -.SP -By default, certain file names are ignored during -.` "cvs import": -names associated with -.SM 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: -.SP -.in +1i -.ft B -.nf -RCSLOG RCS SCCS -CVS* cvslog.* -tags TAGS -\&.make.state .nse_depinfo -*~ #* .#* ,* -*.old *.bak *.BAK *.orig *.rej .del\-* -*.a *.o *.so *.Z *.elc *.ln core -.fi -.ft P -.in -1i -.SP -The outside source is saved in a first-level -.SM RCS -branch, by default -.` "1.1.1". -Updates are leaves of this -branch; for example, files from the first imported collection of -source will be revision -.` "1.1.1.1", -then files from the first -imported update will be revision -.` "1.1.1.2", -and so on. -.SP -At least three arguments are required. \fIrepository\fP is needed to -identify the collection of source. \fIvendortag\fP is a tag for the -entire branch (e.g., for -.` "1.1.1"). -You must also specify at -least one \fIreleasetag\fP to identify the files at the leaves created -each time you execute -.` "cvs import". -.SP -One of the standard -.B cvs -command options is available: \fB\-m\fP -\fImessage\fP. If you do not specify a logging message with -\fB\-m\fP, your editor is invoked (as with \fBcommit\fP) to allow you -to enter one. -.SP -There are three additional special options. -.SP -Use -.` "\-d" -to specify that each file's time of last modification should be used -for the checkin date and time. -.SP -Use -.` "\-b \fIbranch\fP" -to specify a first-level branch other -than -.` "1.1.1". -.SP -Use -.` "\-I \fIname\fP" -to specify file names that should be -ignored during \fBimport\fP. You can use this option repeatedly. -To avoid ignoring any files at all (even those ignored by default), -specify -.` "\-I !". -.TP -\fBlog\fP [\fB\-l\fP] \fIrlog-options [files\fP\|.\|.\|.] -.I Requires: -repository, working directory. -.br -.I Changes: -nothing. -.br -.I Synonym: -.B rlog -.br -Display log information for \fIfiles\fP. -.` "cvs log" -calls -the -.SM RCS -utility \fBrlog\fP; all the options described in -.BR rlog ( 1 ) -are available. Among the more useful \fBrlog\fP options are \fB\-h\fP -to display only the header (including tag definitions, but omitting -most of the full log); \fB\-r\fP to select logs on particular -revisions or ranges of revisions; and \fB\-d\fP to select particular -dates or date ranges. See -.BR rlog ( 1 ) -for full explanations. -This command is recursive by default, unless the -.B \-l -option is specified. -.TP -\fBrdiff\fP [\fB\-\fP\fIflags\fP] [\fB\-V\fP \fIvn\fP] [\fB\-r\fP \fIt\fP|\fB\-D\fP \fId\fP [\fB\-r\fP \fIt2\fP|\fB\-D\fP \fId2\fP]] \fImodules\|.\|.\|.\fP -.I Requires: -repository. -.br -.I Changes: -nothing. -.br -.I Synonym: -.B patch -.br -Builds a Larry Wall format -.BR patch ( 1 ) -file between two releases, that can be fed directly into the -.B patch -program to bring an old release up-to-date with the new release. -(This is one of the few \fBcvs\fP commands that operates directly from -the repository, and doesn't require a prior -.BR checkout .) -The diff output is sent to the standard output device. -You can specify (using the standard \fB\-r\fP and \fB\-D\fP options) -any combination of one or two revisions or dates. -If only one revision or date is specified, the -patch file reflects differences between that revision or date and the -current ``head'' revisions in the -.SM RCS -file. -.SP -Note that if the software release affected -is contained in more than one directory, then it may be necessary to -specify the -.B \-p -option to the -.B patch -command when patching the old sources, so that -.B patch -is able to find the files that are located in other directories. -.SP -If you use the option \fB\-V\fP \fIvn\fP, -.SM RCS -keywords are expanded according to the rules current in -.SM RCS -version \fIvn\fP (the expansion format changed with -.SM RCS -version 5). -.SP -The standard option \fIflags\fP \fB\-f\fP, and \fB\-l\fP -are available with this command. There are also several -special options flags: -.SP -If you use the -.B \-s -option, no patch output is produced. -Instead, a summary of the changed or added files between the two -releases is sent to the standard output device. -This is useful for finding out, for example, which files have changed -between two dates or revisions. -.SP -If you use the -.B \-t -option, a diff of the top two revisions is sent to the standard output device. -This is most useful for seeing what the last change to a file was. -.SP -If you use the -.B \-u -option, the patch output uses the newer ``unidiff'' format for context -diffs. -.SP -You can use -.B \-c -to explicitly specify the -.` "diff \-c" -form of context diffs -(which is the default), if you like. -.TP -\fBrelease\fP [\fB\-dQq\fP] \fImodules\fP\|.\|.\|. -.I Requires: -Working directory. -.br -.I Changes: -Working directory, history log. -.br -This command is meant to safely cancel the effect of -.` "cvs checkout'. -Since -.B cvs -doesn't lock files, it isn't strictly necessary to use this command. -You can always simply delete your working directory, if you -like; but you risk losing changes you may have forgotten, and you -leave no trace in the -.B cvs -history file that you've abandoned your checkout. -.SP -Use -.` "cvs release" -to avoid these problems. This command -checks that no un-committed changes are present; that you are -executing it from immediately above, or inside, a \fBcvs\fP working -directory; and that the repository recorded for your files is the same -as the repository defined in the module database. -.SP -If all these conditions are true, -.` "cvs release" -leaves a -record of its execution (attesting to your intentionally abandoning -your checkout) in the -.B cvs -history log. -.SP -You can use the \fB\-d\fP flag to request that your working copies of -the source files be deleted if the \fBrelease\fP succeeds. -.TP -\fBremove\fP [\fB\-lR\fP] [\fIfiles\|.\|.\|.\fP] -.I Requires: -Working directory. -.br -.I Changes: -Working directory. -.br -.I Synonyms: -.BR rm ", " delete -.br -Use this command to declare that you wish to remove \fIfiles\fP from -the source repository. Like most -.B cvs -commands, -.` "cvs remove" -works on files in your working -directory, not directly on the repository. As a safeguard, it also -requires that you first erase the specified files from your working -directory. -.SP -The files are not actually removed until you apply your changes to the -repository with -.BR commit ; -at that point, the corresponding -.SM RCS -files in the source repository are -.I moved -into the -.` "Attic" -directory (also within the source repository). -.SP -This command is recursive by default, scheduling all physically removed -files that it finds for removal by the next -.BR commit . -Use the -.B \-l -option to avoid this recursion, or just specify that actual files that you -wish remove to consider. -.TP -\fBrtag\fP [\fB\-f\|alnRQq\fP] [\fB\-b\fP] [\fB\-d\fP] [\fB\-r\fP \fItag\fP | \fB\-D\fP \fIdate\fP] \fIsymbolic_tag\fP \fImodules\|.\|.\|.\fP -.I Requires: -repository. -.br -.I Changes: -repository. -.br -.I Synonym: -.B rfreeze -.br -You can use this command to assign symbolic tags to particular, -explicitly specified source versions in the repository. -.` "cvs rtag" -works directly on the repository contents (and requires no -prior -.BR checkout ). -Use -.` "cvs tag" -instead, to base the selection of -versions to tag on the contents of your working directory. -.SP -In general, tags (often the symbolic names of software distributions) -should not be removed, but the -.B \-d -option is available as a means to remove completely obsolete symbolic names -if necessary (as might be the case for an Alpha release, say). -.SP -.` "cvs rtag" -will not move a tag that already exists. With the \fB\-F\fP option, -however, -.` "cvs rtag" -will re-locate any instance of \fIsymbolic_tag\fP that already exists -on that file to the new repository versions. Without the \fB\-F\fP -option, attempting to use -.` "cvs rtag" -to apply a tag that already exists on that file will produce an error -message. -.SP -The \fB-b\fP option makes the tag a ``branch'' tag, allowing -concurrent, isolated development. -This is most useful for creating a patch to a previously released software -distribution. -.SP -You can use the standard \fB\-r\fP and \fB\-D\fP options to tag only those -files that already contain a certain tag. This method would be used -to rename a tag: tag only the files identified by the old tag, then delete the -old tag, leaving the new tag on exactly the same files as the old tag. -.SP -.B rtag -executes recursively by default, tagging all subdirectories of -\fImodules\fP you specify in the argument. You can restrict its -operation to top-level directories with the standard \fB\-l\fP option; -or you can explicitly request recursion with \fB\-R\fP. -.SP -The modules database can specify a program to execute whenever a tag -is specified; a typical use is to send electronic mail to a group of -interested parties. If you want to bypass that program, use the -standard \fB\-n\fP option. -.SP -Use the -.B \-a -option to have -.B rtag -look in the -.` "Attic" -for removed files that contain the specified tag. -The tag is removed from these files, which makes it convenient to re-use a -symbolic tag as development continues (and files get removed from the -up-coming distribution). -.TP -\fBstatus\fP [\fB\-lRqQ\fP] [\fB\-v\fP] [\fIfiles\fP\|.\|.\|.] -.I Requires: -working directory, repository. -.br -.I Changes: -nothing. -.br -Display a brief report on the current status of \fIfiles\fP with -respect to the source repository, including any ``sticky'' tags, -dates, or \fB\-k\fP options. (``Sticky'' options will restrict how -.` "cvs update" -operates until you reset them; see the -description of -.` "cvs update \-A\|.\|.\|.".) -.SP -You can also use this command to anticipate the potential impact of a -.` "cvs update" -on your working source directory. If you do -not specify any \fIfiles\fP explicitly, reports are shown for all -files that \fBcvs\fP has placed in your working directory. You can -limit the scope of this search to the current directory itself (not -its subdirectories) with the standard \fB\-l\fP option flag; or you -can explicitly request recursive status reports with the \fB\-R\fP -option. -.SP -The -.B \-v -option causes the symbolic tags for the -.SM RCS -file to be displayed as well. -.TP -\fBtag\fP [\fB\-lQqR\fP] [\fB\-F\fP] [\fB\-b\fP] [\fB\-d\fP] [\fB\-r\fP \fItag\fP | \fB\-D\fP \fIdate\fP] [\fB\-f\fP] \fIsymbolic_tag\fP [\fIfiles\fP\|.\|.\|.\|] -.I Requires: -working directory, repository. -.br -.I Changes: -repository. -.br -.I Synonym: -.B freeze -.br -Use this command to assign symbolic tags to the nearest repository -versions to your working sources. The tags are applied immediately to -the repository, as with \fBrtag\fP. -.SP -One use for tags is to record a ``snapshot'' of the current sources -when the software freeze date of a project arrives. As bugs are fixed -after the freeze date, only those changed sources that are to be part -of the release need be re-tagged. -.SP -The symbolic tags are meant to permanently record which revisions of which -files were used in creating a software distribution. -The -.BR checkout , -.B export -and -.B update -commands allow you to extract an exact copy of a tagged release at any time in -the future, regardless of whether files have been changed, added, or removed -since the release was tagged. -.SP -You can use the standard \fB\-r\fP and \fB\-D\fP options to tag only those -files that already contain a certain tag. This method would be used -to rename a tag: tag only the files identified by the old tag, then delete the -old tag, leaving the new tag on exactly the same files as the old tag. -.SP -Specifying the \fB\-f\fP flag in addition to the \fB\-r\fP or \fB\-D\fP -flags will tag those files named on the command line even if they do not -contain the old tag or did not exist on the specified date. -.SP -By default (without a \fB\-r\fP or \fB\-D\fP flag) -the versions to be tagged are supplied -implicitly by the \fBcvs\fP records of your working files' history -rather than applied explicitly. -.SP -If you use -.` "cvs tag \-d \fIsymbolic_tag\fP\|.\|.\|.", -the -symbolic tag you specify is -.I deleted -instead of being added. \fIWarning\fP: Be very certain of your ground -before you delete a tag; doing this effectively discards some -historical information, which may later turn out to have been valuable. -.SP -.` "cvs tag" -will not move a tag that already exists. With the \fB\-F\fP option, -however, -.` "cvs tag" -will re-locate any instance of \fIsymbolic_tag\fP that already exists -on that file to the new repository versions. Without the \fB\-F\fP -option, attempting to use -.` "cvs tag" -to apply a tag that already exists on that file will produce an error -message. -.SP -The \fB-b\fP option makes the tag a ``branch'' tag, allowing -concurrent, isolated development. -This is most useful for creating a patch to a previously released software -distribution. -.SP -Normally, -.B tag -executes recursively through subdirectories; you can prevent this by -using the standard \fB\-l\fP option, or specify the recursion -explicitly by using \fB\-R\fP. -.TP -\fBupdate\fP [\fB\-Adf\|lPpQqR\fP] [\fB\-d\fP] [\fB\-r\fP \fItag\fP|\fB\-D\fP \fIdate\fP] \fIfiles\|.\|.\|.\fP -.I Requires: -repository, working directory. -.br -.I Changes: -working directory. -.br -After you've run -.B checkout -to create your private copy of source from the common repository, -other developers will continue changing the central source. From time -to time, when it is convenient in your development process, you can -use the -.B update -command -from within your working directory to reconcile your work with any -revisions applied to the source repository since your last -.B checkout -or -.BR update . -.SP -.B update -keeps you informed of its progress by printing a line for each file, -prefaced with one of the characters -.` "U A R M C ?" -to indicate the status of the file: -.TP 1i -\fBU\fP \fIfile\fP -The file was brought \fIup to date\fP 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. -.TP 1i -\fBA\fP \fIfile\fP -The file has been \fIadded\fP to your private copy of the sources, and -will be added to the -.SM RCS -source repository when you run -.` "cvs commit" -on the file. -This is a reminder to you that the file needs to be committed. -.TP 1i -\fBR\fP \fIfile\fP -The file has been \fIremoved\fP from your private copy of the sources, and -will be removed from the -.SM RCS -source repository when you run -.` "cvs commit" -on the file. -This is a reminder to you that the file needs to be committed. -.TP 1i -\fBM\fP \fIfile\fP -The file is \fImodified\fP in your working directory. -.` "M" -can indicate one of two states for a file you're working on: either -there were no modifications to the same file in the repository, so -that your file remains as you last saw it; or there were modifications -in the repository as well as in your copy, but they were -\fImerged\fP successfully, without conflict, in your working -directory. -.TP 1i -\fBC\fP \fIfile\fP -A \fIconflict\fP was detected while trying to merge your changes to -\fIfile\fP with changes from the source repository. \fIfile\fP (the -copy in your working directory) is now the output of the -.BR rcsmerge ( 1 ) -command on the two versions; an unmodified copy of your file is also -in your working directory, with the name `\fB.#\fP\fIfile\fP\fB.\fP\fIversion\fP', -where -.I version -is the -.SM RCS -revision that your modified file started from. -(Note that some systems automatically purge files that begin with -\& -.` ".#" -if they have not been accessed for a few days. -If you intend to keep a copy of your original file, it is a very good -idea to rename it.) -.TP 1i -\fB?\fP \fIfile\fP -\fIfile\fP is in your working directory, but does not correspond to -anything in the source repository, and is not in the list of files -for \fBcvs\fP to ignore (see the description of the \fB\-I\fP option). -.PP -.RS .5i -.SP -Use the -.B \-A -option to reset any sticky tags, dates, or -.B \-k -options. (If you get a working copy of a file by using one of the -\fB\-r\fP, \fB\-D\fP, or \fB\-k\fP options, \fBcvs\fP remembers the -corresponding tag, date, or \fIkflag\fP and continues using it on -future updates; use the \fB\-A\fP option to make \fBcvs\fP forget these -specifications, and retrieve the ``head'' version of the file). -.SP -The \fB\-j\fP\fIbranch\fP option -merges the changes made between the -resulting revision and the revision that it is based on (e.g., if -the tag refers to a branch, -.B cvs -will merge all changes made in -that branch into your working file). -.SP -With two \fB-j\fP options, -.B cvs -will merge in the changes between the two respective revisions. -This can be used to ``remove'' a certain delta from your working file. -E.g., If the file foo.c is based on -revision 1.6 and I want to remove the changes made between 1.3 and -1.5, I might do: -.SP -.in +1i -.ft B -.nf -example% cvs update -j1.5 -j1.3 foo.c # note the order... -.fi -.ft P -.in -1i -.SP -In addition, each \fB-j\fP option can contain on 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. -.SP -.in +1i -.ft B -.nf --jSymbolic_Tag:Date_Specifier -.fi -.ft P -.in -1i -.SP -Use the -.B \-d -option to create any directories that exist in the repository if they're -missing from the working directory. (Normally, update acts only on -directories and files that were already enrolled in your -working directory.) This is useful for updating directories -that were created in the repository since the initial -\fBcheckout\fP; but it has an unfortunate side effect. If you -deliberately avoided certain directories in the repository when you -created your working directory (either through use of a module name or by -listing explicitly the files and directories you wanted on the -command line), then updating with -.B \-d -will create those directories, which may not be what you want. -.SP -Use \fB\-I\fP \fIname\fP to ignore files whose names match \fIname\fP -(in your working directory) during the update. You can specify -\fB\-I\fP more than once on the command line to specify several files -to ignore. By default, -\fBupdate\fP ignores files whose names match any of the following: -.SP -.in +1i -.ft B -.nf -RCSLOG RCS SCCS -CVS* cvslog.* -tags TAGS -\&.make.state .nse_depinfo -*~ #* .#* ,* -*.old *.bak *.BAK *.orig *.rej .del\-* -*.a *.o *.so *.Z *.elc *.ln core -.fi -.ft P -.in -1i -.SP -Use -.` "\-I !" -to avoid ignoring any files at all. -.SP -The standard \fBcvs\fP command options \fB\-f\fP, \fB\-k\fP, -\fB\-l\fP, \fB\-P\fP, \fB\-p\fP, and \fB\-r\fP -are also available with \fBupdate\fP. -.RE -.SH "FILES" -For more detailed information on -.B cvs -supporting files, see -.BR cvs ( 5 ). -.LP -.I -Files in home directories: -.TP -\&.cvsrc -The -.B cvs -initialisation file. Lines in this file can be used to specify default -options for each -.B cvs -command. For example the line -.` "diff \-c" -will ensure that -.` "cvs diff" -is always passed the -.B \-c -option in addition to any other options passed on the command line. -.TP -\&.cvswrappers -Specifies wrappers to be used in addition to those specified in the -CVSROOT/cvswrappers file in the repository. -.LP -.I -Files in working directories: -.TP -CVS -A directory of \fBcvs\fP administrative files. -.I -Do not delete. -.TP -CVS/Entries -List and status of files in your working directory. -.TP -CVS/Entries.Backup -A backup of -.` "CVS/Entries". -.TP -CVS/Entries.Static -Flag: do not add more entries on -.` "cvs update". -.TP -CVS/Root -Pathname to the repository ( -.SM CVSROOT -) location at the time of checkout. This file is used instead -of the -.SM CVSROOT -environment variable if the environment variable is not -set. A warning message will be issued when the contents of this -file and the -.SM CVSROOT -environment variable differ. The file may be over-ridden by the -presence of the -.SM CVS_IGNORE_REMOTE_ROOT -environment variable. -.TP -CVS/Repository -Pathname to the corresponding directory in the source repository. -.TP -CVS/Tag -Contains the per-directory ``sticky'' tag or date information. -This file is created/updated when you specify -.B \-r -or -.B \-D -to the -.B checkout -or -.B update -commands, and no files are specified. -.TP -CVS/Checkin.prog -Name of program to run on -.` "cvs commit". -.TP -CVS/Update.prog -Name of program to run on -.` "cvs update". -.LP -.I -Files in source repositories: -.TP -$CVSROOT/CVSROOT -Directory of global administrative files for repository. -.TP -CVSROOT/commitinfo,v -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/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/taginfo,v -Records programs for validating/logging -.` "cvs tag" -and -.` "cvs rtag" -operations. -.TP -MODULE/Attic -Directory for removed source files. -.TP -#cvs.lock -A lock directory created by -.B cvs -when doing sensitive changes to the -.SM RCS -source repository. -.TP -#cvs.tfl.\fIpid\fP -Temporary lock file for repository. -.TP -#cvs.rfl.\fIpid\fP -A read lock. -.TP -#cvs.wfl.\fIpid\fP -A write lock. -.SH "ENVIRONMENT VARIABLES" -.TP -.SM CVSROOT -Should contain the full pathname to the root of the -.B cvs -source repository (where the -.SM RCS -files are kept). This information must be available to \fBcvs\fP for -most commands to execute; if -.SM CVSROOT -is not set, or if you wish to override it for one invocation, you can -supply it on the command line: -.` "cvs \-d \fIcvsroot cvs_command\fP\|.\|.\|." -You may not need to set -.SM CVSROOT -if your \fBcvs\fP binary has the right path compiled in; use -.` "cvs \-v" -to display all compiled-in paths. -.TP -.SM CVSREAD -If this is set, -.B checkout -and -.B update -will try hard to make the files in your working directory read-only. -When this is not set, the default behavior is to permit modification -of your working files. -.TP -.SM RCSBIN -Specifies the full pathname where to find -.SM RCS -programs, such as -.BR co ( 1 ) -and -.BR ci ( 1 ). -If not set, a compiled-in value is used; see the display from -.` "cvs \-v". -.TP -.SM CVSEDITOR -Specifies the program to use for recording log messages during -.BR commit . -If not set, the -.SM EDITOR -environment variable is used instead. -If -.SM EDITOR -is not set either, the default is -.BR vi . -.TP -.SM CVS_IGNORE_REMOTE_ROOT -If this variable is set then -.B cvs -will ignore all references to remote repositories in the CVS/Root file. -.TP -.SM CVS_RSH -.B cvs -uses the contents of this variable to determine the name of the -remote shell command to use when starting a -.B cvs -server. If this variable is not set then -.` "rsh" -is used. -.TP -.SM CVS_SERVER -.B cvs -uses the contents of this variable to determine the name of the -.B cvs -server command. If this variable is not set then -.` "cvs" -is used. -.TP -.SM CVSWRAPPERS -This variable is used by the -.` "cvswrappers" -script to determine the name of the wrapper file, in addition to the -wrappers defaults contained in the repository -.SM (CVSROOT/cvswrappers) -and the user's home directory (~/.cvswrappers). -.SH "AUTHORS" -.TP -Dick Grune -Original author of the -.B cvs -shell script version posted to -.B comp.sources.unix -in the volume6 release of December, 1986. -Credited with much of the -.B cvs -conflict resolution algorithms. -.TP -Brian Berliner -Coder and designer of the -.B cvs -program itself in April, 1989, based on the original work done by Dick. -.TP -Jeff Polk -Helped Brian with the design of the -.B cvs -module and vendor branch support and author of the -.BR checkin ( 1 ) -shell script (the ancestor of -.` "cvs import"). -.SH "SEE ALSO" -.BR ci ( 1 ), -.BR co ( 1 ), -.BR cvs ( 5 ), -.BR cvsbug ( 8 ), -.BR cvsinit ( 8 ), -.BR diff ( 1 ), -.BR grep ( 1 ), -.BR mkmodules ( 1 ), -.BR patch ( 1 ), -.BR rcs ( 1 ), -.BR rcsdiff ( 1 ), -.BR rcsmerge ( 1 ), -.BR rlog ( 1 ), -.BR rm ( 1 ), -.BR sort ( 1 ). diff --git a/gnu/usr.bin/cvs/cvs/cvs.5 b/gnu/usr.bin/cvs/cvs/cvs.5 deleted file mode 100644 index cb4f455..0000000 --- a/gnu/usr.bin/cvs/cvs/cvs.5 +++ /dev/null @@ -1,367 +0,0 @@ -.TH cvs 5 "12 February 1992" -.\" Full space in nroff; half space in troff -.de SP -.if n .sp -.if t .sp .5 -.. -.SH NAME -cvs \- Concurrent Versions System support files -.SH SYNOPSIS -.hy 0 -.na -.TP -.B $CVSROOT/CVSROOT/commitinfo,v -.TP -.B $CVSROOT/CVSROOT/cvsignore,v -.TP -.B $CVSROOT/CVSROOT/cvswrappers,v -.TP -.B $CVSROOT/CVSROOT/editinfo,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 -.B cvs -is a system for providing source control to hierarchical collections -of source directories. Commands and procedures for using \fBcvs\fP -are described in -.BR cvs ( 1 ). -.SP -.B cvs -manages \fIsource repositories\fP, the directories containing master -copies of the revision-controlled files, by copying particular -revisions of the files to (and modifications back from) developers' -private \fIworking directories\fP. In terms of file structure, each -individual source repository is an immediate subdirectory of -\fB$CVSROOT\fP. -.SP -The files described here are supporting files; they do not have to -exist for \fBcvs\fP to operate, but they allow you to make \fBcvs\fP -operation more flexible. -.SP -The -.BR cvsinit ( 1 ) -shell script included at the top-level of the -.B cvs -distribution can be used to setup an initial -.B $CVSROOT/CVSROOT -area, if you don't have one already. -.SP -You can use the `\|modules\|' file to define symbolic names for -collections of source maintained with \fBcvs\fP. If there is no -`\|modules\|' file, developers must specify complete path names -(absolute, or relative to \fB$CVSROOT\fP) for the files they wish to -manage with \fBcvs\fP commands. -.SP -You can use the `\|commitinfo\|' file to define programs to execute -whenever `\|\fBcvs commit\fP\|' is about to execute. -These programs are used for ``pre-commit'' checking to verify that the -modified, added, and removed files are really ready to be committed. -Some uses for this check might be to turn off a portion (or all) of the -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 , -which writes a log entry for changes in the repository. -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 -editing/validating `\|\fBcvs commit\fP\|' log entries. -This is most useful when used with a `\|rcsinfo\|' forms specification, as -it can verify that the proper fields of the form have been filled in by the -user committing the change. -.SP -You can use the `\|cvsignore\|' file to specify the default list of -files to ignore during \fBupdate\fP. -.SP -You can use the `\|history\|' file to record the \fBcvs\fP commands -that affect the repository. -The creation of this file enables history logging. -.SH FILES -.TP -.B modules -The `\|modules\|' file records your definitions of names for -collections of source code. \fBcvs\fP will use these definitions if -you create a file with the right format in -`\|\fB$CVSROOT/CVSROOT/modules,v\fP\|'. -The -.BR mkmodules ( 1 ) -command should be run whenever the modules file changes, so that the -appropriate files can be generated (depending on how you have configured -.B cvs -operation). -.SP -To allow convenient editing of the `\|modules\|' file itself, the file should -include an entry like the following (where \fIlocalbin\fP represents the -directory where your site installs programs like -.BR mkmodules ( 1 )): -.SP -.nf -\&\fBmodules \-i /\fP\fIlocalbin\fP\fB/mkmodules CVSROOT modules\fP -.fi -.SP -This defines the name `\|\fBmodules\fP\|' as the module name for the -file itself, so that you can use -.SP -.in +1i -.ft B -.nf -example% cvs checkout modules -.fi -.ft P -.in -1i -.SP -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 ( 8 ) -script will setup a smilar `\|modules\|' file for you automatically. -.SP -The `\|modules\|' file may contain blank lines and comments (lines -beginning with `\|\fB#\fP\|') as well as module definitions. -Long lines can be continued on the next line by specifying a backslash -(``\e'') as the last character on the line. -.SP -A \fImodule definition\fP is a single line of the `\|modules\|' file, -in either of two formats. In both cases, \fImname\fP represents the -symbolic module name, and the remainder of the line is its definition. -.SP -\fImname\fP \fB\-a\fP \fIaliases\fP\|.\|.\|. -.br -This represents the simplest way of defining a module \fImname\fP. -The `\|\fB\-a\fP\|' flags the definition as a simple alias: \fBcvs\fP -will treat any use of \fImname\fP (as a command argument) as if the list -of names \fIaliases\fP had been specified instead. \fIaliases\fP may -contain either other module names or paths. When you use paths in -\fIaliases\fP, `\|\fBcvs checkout\fP\|' creates all intermediate -directories in the working directory, just as if the path had been -specified explicitly in the \fBcvs\fP arguments. -.SP -.nf -\fImname\fP [ \fIoptions\fP ] \fIdir\fP [ \fIfiles\fP\|.\|.\|. ] [ \fB&\fP\fImodule\fP\|.\|.\|. ] -.fi -.SP -In the simplest case, this form of module definition reduces to -`\|\fImname dir\fP\|'. This defines all the files in directory -\fIdir\fP as module \fImname\fP. \fIdir\fP is a relative path (from -\fB$CVSROOT\fP) to a directory of source in one of the source -repositories. In this case, on \fBcheckout\fP, a single directory -called \fImname\fP is created as a working directory; no intermediate -directory levels are used by default, even if \fIdir\fP was a path -involving several directory levels. -.SP -By explicitly specifying \fIfiles\fP in the module definition after -\fIdir\fP, you can select particular files from directory -\fIdir\fP. The sample definition for \fBmodules\fP is an example of -a module defined with a single file from a particular directory. Here -is another example: -.SP -.nf -.ft B -m4test unsupported/gnu/m4 foreach.m4 forloop.m4 -.ft P -.fi -.SP -With this definition, executing `\|\fBcvs checkout m4test\fP\|' -will create a single working directory `\|m4test\|' containing the two -files listed, which both come from a common directory several levels -deep in the \fBcvs\fP source repository. -.SP -A module definition can refer to other modules by including -`\|\fB&\fP\fImodule\fP\|' in its definition. \fBcheckout\fP creates -a subdirectory for each such \fImodule\fP, in your working directory. -.br -.I -New in \fBcvs\fP 1.3; -avoid this feature if sharing module definitions with older versions -of \fBcvs\fP. -.SP -Finally, you can use one or more of the following \fIoptions\fP in -module definitions: -.SP -\&`\|\fB\-d\fP \fIname\fP\|', to name the working directory something -other than the module name. -.br -.I -New in \fBcvs\fP 1.3; -avoid this feature if sharing module definitions with older versions -of \fBcvs\fP. -.SP -\&`\|\fB\-i\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP -to run whenever files in a module are committed. \fIprog\fP runs with a -single argument, the full pathname of the affected directory in a -source repository. The `\|commitinfo\|', `\|loginfo\|', and -`\|editinfo\|' files provide other ways to call a program on \fBcommit\fP. -.SP -`\|\fB\-o\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP -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. -.SP -`\|\fB\-u\fP \fIprog\fP\|' allows you to specify a program \fIprog\fP -to run whenever `\|\fBcvs update\fP\|' is executed from the top-level -directory of the checked-out module. \fIprog\fP runs with a -single argument, the full path to the source repository for this module. -.TP -\&\fBcommitinfo\fP, \fBloginfo\fP, \fBrcsinfo\fP, \fBeditinfo\fP -These files all specify programs to call at different points in the -`\|\fBcvs commit\fP\|' process. They have a common structure. -Each line is a pair of fields: a regular expression, separated by -whitespace from a filename or command-line template. -Whenever one of the regular expression matches a directory name in the -repository, the rest of the line is used. -If the line begins with a \fB#\fP character, the entire line is considered -a comment and is ignored. -Whitespace between the fields is also ignored. -.SP -For `\|loginfo\|', the rest of the -line is a command-line template to execute. -The templates can include not only -a program name, but whatever list of arguments you wish. If you write -`\|\fB%s\fP\|' somewhere on the argument list, \fBcvs\fP supplies, at -that point, the list of files affected by the \fBcommit\fP. -The first entry in the list is the relative path within the source -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 -list of arguments you wish. -The full path to the current source repository is appended to the template, -followed by the file names of any files involved in the commit (added, -removed, and modified files). -.SP -For `\|rcsinfo\|', the rest of the line is the full path to a file that -should be loaded into the log message template. -.SP -For `\|editinfo\|', the rest of the line is a command-line template to -execute. -The template can include not only a program name, but whatever -list of arguments you wish. -The full path to the current log message template file is appended to the -template. -.SP -You can use one of two special strings instead of a regular -expression: `\|\fBALL\fP\|' specifies a command line template that -must always be executed, and `\|\fBDEFAULT\fP\|' specifies a command -line template to use if no regular expression is a match. -.SP -The `\|commitinfo\|' file contains commands to execute \fIbefore\fP any -other \fBcommit\fP activity, to allow you to check any conditions that -must be satisfied before \fBcommit\fP can proceed. The rest of the -\fBcommit\fP will execute only if all selected commands from this file -exit with exit status \fB0\fP. -.SP -The `\|rcsinfo\|' file allows you to specify \fIlog templates\fP for -the \fBcommit\fP logging session; you can use this to provide a form -to edit when filling out the \fBcommit\fP log. The field after the -regular expression, in this file, contains filenames (of files -containing the logging forms) rather than command templates. -.SP -The `\|editinfo\|' file allows you to execute a script \fIbefore the -commit starts\fP, but after the log information is recorded. These -"edit" scripts can verify information recorded in the log file. If -the edit script exits wth a non-zero exit status, the commit is aborted. -.SP -The `\|loginfo\|' file contains commands to execute \fIat the end\fP -of a commit. The text specified as a commit log message is piped -through the command; typical uses include sending mail, filing an -article in a newsgroup, or appending to a central file. -.TP -\&\fBcvsignore\fP, \fB.cvsignore\fP -The default list of files (or -.BR sh ( 1 ) -file name patterns) to ignore during `\|\fBcvs update\fP\|'. -At startup time, \fBcvs\fP loads the compiled in default list of file name -patterns (see -.BR cvs ( 1 )). -Then the per-repository list included in \fB$CVSROOT/CVSROOT/cvsignore\fP -is loaded, if it exists. -Then the per-user list is loaded from `\|$HOME/.cvsignore\|'. -Finally, as \fBcvs\fP traverses through your directories, it will load any -per-directory `\|.cvsignore\|' files whenever it finds one. -These per-directory files are only valid for exactly the directory that -contains them, not for any sub-directories. -.TP -.B history -Create this file in \fB$CVSROOT/CVSROOT\fP to enable history logging -(see the description of `\|\fBcvs history\fP\|'). -.SH "SEE ALSO" -.BR cvs ( 1 ), -.BR mkmodules ( 1 ). -.SH COPYING -Copyright \(co 1992 Cygnus Support, Brian Berliner, and Jeff Polk -.PP -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. -.PP -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. -.PP -Permission is granted to copy and distribute translations of this -manual into another language, under the above conditions for modified -versions, except that this permission notice may be included in -translations approved by the Free Software Foundation instead of in -the original English. diff --git a/gnu/usr.bin/cvs/cvs/cvs.h b/gnu/usr.bin/cvs/cvs/cvs.h deleted file mode 100644 index 34c9d8c..0000000 --- a/gnu/usr.bin/cvs/cvs/cvs.h +++ /dev/null @@ -1,570 +0,0 @@ -/* $CVSid: @(#)cvs.h 1.86 94/10/22 $ */ - -/* - * basic information used in all source files - * - */ - - -#include "config.h" /* this is stuff found via autoconf */ -#include "options.h" /* these are some larger questions which - can't easily be automatically checked - for */ - -/* AIX requires this to be the first thing in the file. */ -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not __GNUC__ */ -#if HAVE_ALLOCA_H -#include <alloca.h> -#else /* not HAVE_ALLOCA_H */ -#ifdef _AIX - #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 __GNUC__ */ - -/* Changed from if __STDC__ to ifdef __STDC__ because of Sun's acc compiler */ - -#ifdef __STDC__ -#define PTR void * -#else -#define PTR char * -#endif - -/* Add prototype support. */ -#ifndef PROTO -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -#define PROTO(ARGS) ARGS -#else -#define PROTO(ARGS) () -#endif -#endif - -#if __GNUC__ == 2 -#define USE(var) static const char sizeof##var = sizeof(sizeof##var) + sizeof(var) -#else -#define USE(var) static const char standalone_semis_illegal_sigh -#endif - - -#include <stdio.h> - -/* Under OS/2, <stdio.h> doesn't define popen()/pclose(). */ -#ifdef USE_OWN_POPEN -#include "popen.h" -#endif - -#ifdef STDC_HEADERS -#include <stdlib.h> -#else -extern void exit (); -extern char *getenv(); -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef HAVE_STRING_H -#include <string.h> -#else -#include <strings.h> -#endif - -#ifdef SERVER_SUPPORT -/* If the system doesn't provide strerror, it won't be declared in - string.h. */ -char *strerror (); -#endif - -#include <fnmatch.h> /* This is supposed to be available on Posix systems */ - -#include <ctype.h> -#include <pwd.h> -#include <signal.h> - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#else -#ifndef errno -extern int errno; -#endif /* !errno */ -#endif /* HAVE_ERRNO_H */ - -#include "system.h" - -#include "hash.h" -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -#include "server.h" -#include "client.h" -#endif - -#ifdef AUTH_CLIENT_SUPPORT -extern int use_authenticating_server; -void connect_to_pserver(); -# ifndef CVS_AUTH_PORT -# define CVS_AUTH_PORT 2401 -# endif /* CVS_AUTH_PORT */ -#endif /* AUTH_CLIENT_SUPPORT */ - -#ifdef MY_NDBM -#include "myndbm.h" -#else -#include <ndbm.h> -#endif /* MY_NDBM */ - -#include "regex.h" -#include "getopt.h" -#include "wait.h" - -/* Define to enable alternate death support (which uses the RCS state). */ -#define DEATH_STATE 1 - -#define DEATH_SUPPORT 1 - -#include "rcs.h" - - -/* XXX - for now this is static */ -#ifndef PATH_MAX -#ifdef MAXPATHLEN -#define PATH_MAX MAXPATHLEN+2 -#else -#define PATH_MAX 1024+2 -#endif -#endif /* PATH_MAX */ - -/* just in case this implementation does not define this */ -#ifndef L_tmpnam -#define L_tmpnam 50 -#endif - - -/* - * 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. - * - * Definitions for the CVS Administrative directory and the files it contains. - * Here as #define's to make changing the names a simple task. - */ -#define CVSADM "CVS" -#define CVSADM_ENT "CVS/Entries" -#define CVSADM_ENTBAK "CVS/Entries.Backup" -#define CVSADM_ENTLOG "CVS/Entries.Log" -#define CVSADM_ENTSTAT "CVS/Entries.Static" -#define CVSADM_REP "CVS/Repository" -#define CVSADM_ROOT "CVS/Root" -#define CVSADM_CIPROG "CVS/Checkin.prog" -#define CVSADM_UPROG "CVS/Update.prog" -#define CVSADM_TAG "CVS/Tag" - -/* - * Definitions for the CVSROOT Administrative directory and the files it - * contains. This directory is created as a sub-directory of the $CVSROOT - * environment variable, and holds global administration information for the - * entire source repository beginning at $CVSROOT. - */ -#define CVSROOTADM "CVSROOT" -#define CVSROOTADM_MODULES "modules" -#define CVSROOTADM_LOGINFO "loginfo" -#define CVSROOTADM_RCSINFO "rcsinfo" -#define CVSROOTADM_COMMITINFO "commitinfo" -#define CVSROOTADM_TAGINFO "taginfo" -#define CVSROOTADM_EDITINFO "editinfo" -#define CVSROOTADM_HISTORY "history" -#define CVSROOTADM_IGNORE "cvsignore" -#define CVSROOTADM_CHECKOUTLIST "checkoutlist" -#define CVSROOTADM_WRAPPER "cvswrappers" -#define CVSNULLREPOS "Emptydir" /* an empty directory */ - -/* support for the modules file (CVSROOTADM_MODULES) */ -#define CVSMODULE_OPTS "ad:i:lo:e:s:t:u:"/* options in modules file */ -#define CVSMODULE_SPEC '&' /* special delimiter */ - -/* Other CVS file names */ - -/* Files go in the attic if the head main branch revision is dead, - otherwise they go in the regular repository directories. The whole - concept of having an attic is sort of a relic from before death - support but on the other hand, it probably does help the speed of - some operations (such as main branch checkouts and updates). */ -#define CVSATTIC "Attic" - -#define CVSLCK "#cvs.lock" -#define CVSTFL "#cvs.tfl" -#define CVSRFL "#cvs.rfl" -#define CVSWFL "#cvs.wfl" -#define CVSRFLPAT "#cvs.rfl.*" /* wildcard expr to match read locks */ -#define CVSEXT_LOG ",t" -#define CVSPREFIX ",," -#define CVSDOTIGNORE ".cvsignore" -#define CVSDOTWRAPPER ".cvswrappers" - -/* miscellaneous CVS defines */ -#define CVSEDITPREFIX "CVS: " -#define CVSLCKAGE (60*60) /* 1-hour old lock files cleaned up */ -#define CVSLCKSLEEP 30 /* wait 30 seconds before retrying */ -#define CVSBRANCH "1.1.1" /* RCS branch used for vendor srcs */ -#define BAKPREFIX ".#" /* when rcsmerge'ing */ -#ifndef DEVNULL -#define DEVNULL "/dev/null" -#endif - -#define FALSE 0 -#define TRUE 1 - -/* - * Special tags. -rHEAD refers to the head of an RCS file, regardless of any - * sticky tags. -rBASE refers to the current revision the user has checked - * out This mimics the behaviour of RCS. - */ -#define TAG_HEAD "HEAD" -#define TAG_BASE "BASE" - -/* Environment variable used by CVS */ -#define CVSREAD_ENV "CVSREAD" /* make files read-only */ -#define CVSREAD_DFLT FALSE /* writable files by default */ - -#define RCSBIN_ENV "RCSBIN" /* RCS binary directory */ -/* #define RCSBIN_DFLT Set by config.h */ - -#define EDITOR1_ENV "CVSEDITOR" /* which editor to use */ -#define EDITOR2_ENV "VISUAL" /* which editor to use */ -#define EDITOR3_ENV "EDITOR" /* which editor to use */ -/* #define EDITOR_DFLT Set by config.h */ - -#define CVSROOT_ENV "CVSROOT" /* source directory root */ -#define CVSROOT_DFLT NULL /* No dflt; must set for checkout */ - -#define IGNORE_ENV "CVSIGNORE" /* More files to ignore */ -#define WRAPPER_ENV "CVSWRAPPERS" /* name of the wrapper file */ - -#define CVSUMASK_ENV "CVSUMASK" /* Effective umask for repository */ -/* #define CVSUMASK_DFLT Set by config.h */ - -/* - * If the beginning of the Repository matches the following string, strip it - * so that the output to the logfile does not contain a full pathname. - * - * If the CVSROOT environment variable is set, it overrides this define. - */ -#define REPOS_STRIP "/master/" - -/* - * The maximum number of files per each CVS directory. This is mainly for - * sizing arrays statically rather than dynamically. 3000 seems plenty for - * now. - */ -#define MAXFILEPERDIR 3000 -#define MAXLINELEN 5000 /* max input line from a file */ -#define MAXPROGLEN 30000 /* max program length to system() */ -#define MAXLISTLEN 40000 /* For [A-Z]list holders */ -#define MAXDATELEN 50 /* max length for a date */ - -/* structure of a entry record */ -struct entnode -{ - char *user; - char *version; - char *timestamp; - char *options; - char *tag; - char *date; - char *conflict; -}; -typedef struct entnode Entnode; - -/* The type of request that is being done in do_module() */ -enum mtype -{ - CHECKOUT, TAG, PATCH, EXPORT -}; - -/* - * defines for Classify_File() to determine the current state of a file. - * These are also used as types in the data field for the list we make for - * Update_Logfile in commit, import, and add. - */ -enum classify_type -{ - T_UNKNOWN = 1, /* no old-style analog existed */ - T_CONFLICT, /* C (conflict) list */ - T_NEEDS_MERGE, /* G (needs merging) list */ - T_MODIFIED, /* M (needs checked in) list */ - T_CHECKOUT, /* O (needs checkout) list */ - T_ADDED, /* A (added file) list */ - T_REMOVED, /* R (removed file) list */ - T_REMOVE_ENTRY, /* W (removed entry) list */ - T_UPTODATE, /* File is up-to-date */ -#ifdef SERVER_SUPPORT - T_PATCH, /* P Like C, but can patch */ -#endif - T_TITLE /* title for node type */ -}; -typedef enum classify_type Ctype; - -/* - * a struct vers_ts contains all the information about a file including the - * user and rcs file names, and the version checked out and the head. - * - * this is usually obtained from a call to Version_TS which takes a tag argument - * for the RCS file if desired - */ -struct vers_ts -{ - char *vn_user; /* rcs version user file derives from - * it can have the following special - * values: - * empty = no user file - * 0 = user file is new - * -vers = user file to be removed */ - char *vn_rcs; /* the version for the rcs file - * (tag version?) */ - char *vn_tag; /* the symbolic tag name */ - char *ts_user; /* the timestamp for the user file */ - char *ts_rcs; /* the user timestamp from entries */ - char *options; /* opts from Entries file - * (keyword expansion) */ - char *ts_conflict; /* Holds time_stamp of conflict */ - char *tag; /* tag stored in the Entries file */ - char *date; /* date stored in the Entries file */ - Entnode *entdata; /* pointer to entries file node */ - RCSNode *srcfile; /* pointer to parsed src file info */ -}; -typedef struct vers_ts Vers_TS; - -/* - * structure used for list-private storage by Entries_Open() and - * Version_TS(). - */ -struct stickydirtag -{ - int aflag; - char *tag; - char *date; - char *options; -}; - -/* Flags for find_{names,dirs} routines */ -#define W_LOCAL 0x01 /* look for files locally */ -#define W_REPOS 0x02 /* look for files in the repository */ -#define W_ATTIC 0x04 /* look for files in the attic */ - -/* Flags for return values of direnter procs for the recursion processor */ -enum direnter_type -{ - R_PROCESS = 1, /* process files and maybe dirs */ - R_SKIP_FILES, /* don't process files in this dir */ - R_SKIP_DIRS, /* don't process sub-dirs */ - R_SKIP_ALL /* don't process files or dirs */ -}; -typedef enum direnter_type Dtype; - -extern char *program_name, *program_path, *command_name; -extern char *Rcsbin, *Editor, *CVSroot; -#ifdef CVSADM_ROOT -extern char *CVSADM_Root; -extern int cvsadmin_root; -#endif /* CVSADM_ROOT */ -extern char *CurDir; -extern int really_quiet, quiet; -extern int use_editor; -extern int cvswrite; -extern mode_t cvsumask; - -extern int trace; /* Show all commands */ -extern int noexec; /* Don't modify disk anywhere */ -extern int logoff; /* Don't write history entry */ - -extern char hostname[]; - -/* Externs that are included directly in the CVS sources */ -int RCS_settag PROTO((const char *, const char *, const char *)); -int RCS_deltag PROTO((const char *, const char *, int)); -int RCS_setbranch PROTO((const char *, const char *)); -int RCS_lock PROTO((const char *, const char *, int)); -int RCS_unlock PROTO((const char *, const char *, int)); -int RCS_merge PROTO((const char *, const char *, const char *, const char *)); - -#include "error.h" - -DBM *open_module PROTO((void)); -FILE *open_file PROTO((const char *, const char *)); -List *Find_Dirs PROTO((char *repository, int which)); -void Entries_Close PROTO((List *entries)); -List *Entries_Open PROTO((int aflag)); -char *Make_Date PROTO((char *rawdate)); -char *Name_Repository PROTO((char *dir, char *update_dir)); -#ifdef CVSADM_ROOT -char *Name_Root PROTO((char *dir, char *update_dir)); -void Create_Root PROTO((char *dir, char *rootdir)); -int same_directories PROTO((char *dir1, char *dir2)); -#endif /* CVSADM_ROOT */ -char *Short_Repository PROTO((char *repository)); -char *gca PROTO((char *rev1, char *rev2)); -char *getcaller PROTO((void)); -char *time_stamp PROTO((char *file)); -char *xmalloc PROTO((size_t bytes)); -char *xrealloc PROTO((char *ptr, size_t bytes)); -char *xstrdup PROTO((const char *str)); -void strip_trailing_newlines PROTO((char *str)); -int No_Difference PROTO((char *file, Vers_TS * vers, List * entries, - char *repository, char *update_dir)); -typedef int (*CALLPROC) PROTO((char *repository, char *value)); -int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc, int all)); -int Reader_Lock PROTO((char *xrepository)); -typedef RETSIGTYPE (*SIGCLEANUPPROC) PROTO(()); -int SIG_register PROTO((int sig, SIGCLEANUPPROC sigcleanup)); -int Writer_Lock PROTO((List * list)); -int ign_name PROTO((char *name)); -int isdir PROTO((const char *file)); -int isfile PROTO((const char *file)); -int islink PROTO((const char *file)); -int isreadable PROTO((const char *file)); -int iswritable PROTO((const char *file)); -int isaccessible PROTO((const char *file, const int mode)); -int isabsolute PROTO((const char *filename)); -char *last_component PROTO((char *path)); - -int joining PROTO((void)); -int numdots PROTO((const char *s)); -int unlink_file PROTO((const char *f)); -int unlink_file_dir PROTO((const char *f)); -int update PROTO((int argc, char *argv[])); -int xcmp PROTO((const char *file1, const char *file2)); -int yesno PROTO((void)); -void *valloc PROTO((size_t bytes)); -time_t get_date PROTO((char *date, struct timeb *now)); -void Create_Admin PROTO((char *dir, char *update_dir, - char *repository, char *tag, char *date)); -void Lock_Cleanup PROTO((void)); -void ParseTag PROTO((char **tagp, char **datep)); -void Scratch_Entry PROTO((List * list, char *fname)); -void WriteTag PROTO((char *dir, char *tag, char *date)); -void cat_module PROTO((int status)); -void check_entries PROTO((char *dir)); -void close_module PROTO((DBM * db)); -void copy_file PROTO((const char *from, const char *to)); -void (*error_set_cleanup PROTO((void (*) (void)))) PROTO ((void)); -void fperror PROTO((FILE * fp, int status, int errnum, char *message,...)); -void free_names PROTO((int *pargc, char *argv[])); -void freevers_ts PROTO((Vers_TS ** versp)); -void ign_add PROTO((char *ign, int hold)); -void ign_add_file PROTO((char *file, int hold)); -void ign_setup PROTO((void)); -void ign_dir_add PROTO((char *name)); -int ignore_directory PROTO((char *name)); -void line2argv PROTO((int *pargc, char *argv[], char *line)); -void make_directories PROTO((const char *name)); -void make_directory PROTO((const char *name)); -void rename_file PROTO((const char *from, const char *to)); -void strip_path PROTO((char *path)); -void strip_trailing_slashes PROTO((char *path)); -void update_delproc PROTO((Node * p)); -void usage PROTO((const char *const *cpp)); -void xchmod PROTO((char *fname, int writable)); -char *xgetwd PROTO((void)); -int Checkin PROTO((int type, char *file, char *update_dir, - char *repository, char *rcs, char *rev, - char *tag, char *options, char *message, List *entries)); -Ctype Classify_File PROTO((char *file, char *tag, char *date, char *options, - int force_tag_match, int aflag, char *repository, - List *entries, List *srcfiles, Vers_TS **versp, - char *update_dir, int pipeout)); -List *Find_Names PROTO((char *repository, int which, int aflag, - List ** optentries)); -void Register PROTO((List * list, char *fname, char *vn, char *ts, - char *options, char *tag, char *date, char *ts_conflict)); -void Update_Logfile PROTO((char *repository, char *xmessage, char *xrevision, - FILE * xlogfp, List * xchanges)); -Vers_TS *Version_TS PROTO((char *repository, char *options, char *tag, - char *date, char *user, int force_tag_match, - int set_time, List * entries, List * xfiles)); -void do_editor PROTO((char *dir, char **messagep, - char *repository, List * changes)); - -typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where, - char *mwhere, char *mfile, int horten, int local_specified, - char *omodule, char *msg)); -typedef int (*FILEPROC) PROTO((char *file, char *update_dir, char *repository, - List * entries, List * srcfiles)); -typedef int (*FILESDONEPROC) PROTO((int err, char *repository, char *update_dir)); -typedef Dtype (*DIRENTPROC) PROTO((char *dir, char *repos, char *update_dir)); -typedef int (*DIRLEAVEPROC) PROTO((char *dir, int err, char *update_dir)); - -int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg, - CALLBACKPROC callback_proc, char *where, int shorten, - int local_specified, int run_module_prog, char *extra_arg)); -int do_recursion PROTO((FILEPROC xfileproc, FILESDONEPROC xfilesdoneproc, - DIRENTPROC xdirentproc, DIRLEAVEPROC xdirleaveproc, - Dtype xflags, int xwhich, int xaflag, int xreadlock, - int xdosrcs)); -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)); -void history_write PROTO((int type, char *update_dir, char *revs, char *name, - char *repository)); -int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc, - DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc, - int argc, char *argv[], int local, int which, - int aflag, int readlock, char *update_preload, - int dosrcs, int wd_is_repos)); -void SIG_beginCrSect PROTO((void)); -void SIG_endCrSect PROTO((void)); -void read_cvsrc PROTO((int *argc, char ***argv)); - -char *make_message_rcslegal PROTO((char *message)); - -/* flags for run_exec(), the fast system() for CVS */ -#define RUN_NORMAL 0x0000 /* no special behaviour */ -#define RUN_COMBINED 0x0001 /* stdout is duped to stderr */ -#define RUN_REALLY 0x0002 /* do the exec, even if noexec is on */ -#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */ -#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */ -#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */ -#define RUN_TTY (char *)0 /* for the benefit of lint */ - -void run_arg PROTO((const char *s)); -void run_print PROTO((FILE * fp)); -#ifdef HAVE_VPRINTF -void run_setup PROTO((const char *fmt,...)); -void run_args PROTO((const char *fmt,...)); -#else -void run_setup (); -void run_args (); -#endif -int run_exec PROTO((char *stin, char *stout, char *sterr, int flags)); - -/* other similar-minded stuff from run.c. */ -FILE *Popen PROTO((const char *, const char *)); -int piped_child PROTO((char **, int *, int *)); -void close_on_exec PROTO((int)); -int filter_stream_through_program PROTO((int, int, char **, pid_t *)); - -pid_t waitpid PROTO((pid_t, int *, int)); - -/* Wrappers. */ - -typedef enum { WRAP_MERGE, WRAP_COPY } WrapMergeMethod; -typedef enum { WRAP_TOCVS, WRAP_FROMCVS, WRAP_CONFLICT } WrapMergeHas; - -void wrap_setup PROTO((void)); -int wrap_name_has PROTO((const char *name,WrapMergeHas has)); -char *wrap_tocvs_process_file PROTO((const char *fileName)); -int wrap_merge_is_copy PROTO((const char *fileName)); -char *wrap_fromcvs_process_file PROTO((const char *fileName)); -/* Pathname expansion */ -char *expand_path PROTO((char *name)); -void wrap_add_file PROTO((const char *file,int temp)); -void wrap_add PROTO((char *line,int temp)); diff --git a/gnu/usr.bin/cvs/cvs/cvsrc.c b/gnu/usr.bin/cvs/cvs/cvsrc.c deleted file mode 100644 index 5882afc..0000000 --- a/gnu/usr.bin/cvs/cvs/cvsrc.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 1993 david d zuhn - * - * written by david d `zoo' zuhn while at Cygnus Support - * - * 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. - * - */ - - -#include "cvs.h" -#include "getline.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)cvsrc.c 1.9 94/09/30 $"; -USE(rcsid); -#endif /* lint */ - -/* this file is to be found in the user's home directory */ - -#ifndef CVSRC_FILENAME -#define CVSRC_FILENAME ".cvsrc" -#endif -char cvsrc[] = CVSRC_FILENAME; - -#define GROW 10 - -extern char *strtok (); - -void -read_cvsrc (argc, argv) - int *argc; - char ***argv; -{ - char *homedir; - char *homeinit; - FILE *cvsrcfile; - - char *line; - int line_length; - size_t line_chars_allocated; - - char *optstart; - - int command_len; - int found = 0; - - int i; - - int new_argc; - int max_new_argv; - char **new_argv; - - /* don't do anything if argc is -1, since that implies "help" mode */ - if (*argc == -1) - return; - - /* setup the new options list */ - - new_argc = 1; - max_new_argv = (*argc) + GROW; - new_argv = (char **) xmalloc (max_new_argv * sizeof (char*)); - new_argv[0] = xstrdup ((*argv)[0]); - - /* determine filename for ~/.cvsrc */ - - homedir = getenv ("HOME"); - if (!homedir) - return; - - homeinit = (char *) xmalloc (strlen (homedir) + strlen (cvsrc) + 10); - strcpy (homeinit, homedir); - strcat (homeinit, "/"); - strcat (homeinit, cvsrc); - - /* if it can't be read, there's no point to continuing */ - - if (!isreadable (homeinit)) - { - free (homeinit); - return; - } - - /* 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 ((line_length = getline (&line, &line_chars_allocated, cvsrcfile)) - >= 0) - { - /* skip over comment lines */ - if (line[0] == '#') - continue; - - /* stop if we match the current command */ - if (!strncmp (line, command_name, command_len) - && isspace (*(line + command_len))) - { - found = 1; - break; - } - } - - fclose (cvsrcfile); - - if (found) - { - /* skip over command in the options line */ - optstart = strtok (line + command_len, "\t \n"); - - do - { - new_argv [new_argc] = xstrdup (optstart); - new_argv [new_argc+1] = NULL; - new_argc += 1; - - if (new_argc >= max_new_argv) - { - char **tmp_argv; - max_new_argv += GROW; - tmp_argv = (char **) xmalloc (max_new_argv * sizeof (char*)); - for (i = 0; i <= new_argc; i++) - tmp_argv[i] = new_argv[i]; - free(new_argv); - new_argv = tmp_argv; - } - - } - while ((optstart = strtok (NULL, "\t \n")) != NULL); - } - - if (line != NULL) - free (line); - - /* now copy the remaining arguments */ - - for (i=1; i < *argc; i++) - { - new_argv [new_argc] = (*argv)[i]; - new_argc += 1; - } - - *argc = new_argc; - *argv = new_argv; - - free (homeinit); - return; -} diff --git a/gnu/usr.bin/cvs/cvs/diff.c b/gnu/usr.bin/cvs/cvs/diff.c deleted file mode 100644 index 22fda75..0000000 --- a/gnu/usr.bin/cvs/cvs/diff.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * 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. - * - * Difference - * - * Run diff against versions in the repository. Options that are specified are - * passed on directly to "rcsdiff". - * - * Without any file arguments, runs diff against all the currently modified - * files. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)diff.c 1.61 94/10/22 $"; -USE(rcsid); -#endif - -static Dtype diff_dirproc PROTO((char *dir, char *pos_repos, char *update_dir)); -static int diff_filesdoneproc PROTO((int err, char *repos, char *update_dir)); -static int diff_dirleaveproc PROTO((char *dir, int err, char *update_dir)); -static int diff_file_nodiff PROTO((char *file, char *repository, List *entries, - List *srcfiles, Vers_TS *vers)); -static int diff_fileproc PROTO((char *file, char *update_dir, char *repository, - List * entries, List * srcfiles)); -static void diff_mark_errors PROTO((int err)); - -static char *diff_rev1, *diff_rev2; -static char *diff_date1, *diff_date2; -static char *use_rev1, *use_rev2; - -#ifdef SERVER_SUPPORT -/* Revision of the user file, if it is unchanged from something in the - repository and we want to use that fact. */ -static char *user_file_rev; -#endif - -static char *options; -static char opts[PATH_MAX]; -static int diff_errors; -static int empty_files = 0; - -static const char *const diff_usage[] = -{ - "Usage: %s %s [-lN] [rcsdiff-options]\n", -#ifdef CVS_DIFFDATE - " [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n", -#else - " [-r rev1 [-r rev2]] [files...] \n", -#endif - "\t-l\tLocal directory only, not recursive\n", - "\t-D d1\tDiff revision for date against working file.\n", - "\t-D d2\tDiff rev1/date1 against date2.\n", - "\t-N\tinclude diffs for added and removed files.\n", - "\t-r rev1\tDiff revision for rev1 against working file.\n", - "\t-r rev2\tDiff rev1/date1 against rev2.\n", - NULL -}; - -int -diff (argc, argv) - int argc; - char **argv; -{ - char tmp[50]; - int c, err = 0; - int local = 0; - int which; - - if (argc == -1) - usage (diff_usage); - - /* - * Note that we catch all the valid arguments here, so that we can - * intercept the -r arguments for doing revision diffs; and -l/-R for a - * non-recursive/recursive diff. - */ -#ifdef SERVER_SUPPORT - /* Need to be able to do this command more than once (according to - the protocol spec, even if the current client doesn't use it). */ - opts[0] = '\0'; -#endif - optind = 1; - while ((c = getopt (argc, argv, - "abcdefhilnpqtuw0123456789BHNQRTC:D:F:I:L:V:k:r:")) != -1) - { - switch (c) - { - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'h': case 'i': case 'n': case 'p': case 't': case 'u': - case 'w': case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': case 'B': - case 'H': case 'T': case 'Q': - (void) sprintf (tmp, " -%c", (char) c); - (void) strcat (opts, tmp); - if (c == 'Q') - { - quiet = 1; - really_quiet = 1; - c = 'q'; - } - break; - case 'C': case 'F': case 'I': case 'L': case 'V': -#ifndef CVS_DIFFDATE - case 'D': -#endif - (void) sprintf (tmp, " -%c%s", (char) c, optarg); - (void) strcat (opts, tmp); - break; - case 'R': - local = 0; - break; - case 'l': - local = 1; - break; - case 'q': - quiet = 1; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'r': - if (diff_rev2 != NULL || diff_date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (diff_rev1 != NULL || diff_date1 != NULL) - diff_rev2 = optarg; - else - diff_rev1 = optarg; - break; -#ifdef CVS_DIFFDATE - case 'D': - if (diff_rev2 != NULL || diff_date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (diff_rev1 != NULL || diff_date1 != NULL) - diff_date2 = Make_Date (optarg); - else - diff_date1 = Make_Date (optarg); - break; -#endif - case 'N': - empty_files = 1; - break; - case '?': - default: - usage (diff_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* make sure options is non-null */ - if (!options) - options = xstrdup (""); - -#ifdef CLIENT_SUPPORT - if (client_active) { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (empty_files) - send_arg("-N"); - send_option_string (opts); - if (diff_rev1) - option_with_arg ("-r", diff_rev1); - if (diff_date1) - client_senddate (diff_date1); - if (diff_rev2) - option_with_arg ("-r", diff_rev2); - if (diff_date2) - client_senddate (diff_date2); - -#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... */ - - /* 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 - - if (fprintf (to_server, "diff\n") < 0) - error (1, errno, "writing to server"); - err = get_responses_and_close (); - free (options); - return (err); - } -#endif - - which = W_LOCAL; - if (diff_rev2 != NULL || diff_date2 != NULL) - which |= W_REPOS | W_ATTIC; - - wrap_setup (); - - /* start the recursion processor */ - err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc, - diff_dirleaveproc, argc, argv, local, - which, 0, 1, (char *) NULL, 1, 0); - - /* clean up */ - free (options); - return (err); -} - -/* - * Do a file diff - */ -/* ARGSUSED */ -static int -diff_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - int status, err = 2; /* 2 == trouble, like rcsdiff */ - Vers_TS *vers; - enum { - DIFF_ERROR, - DIFF_ADDED, - DIFF_REMOVED, - DIFF_NEITHER - } empty_file = DIFF_NEITHER; - char tmp[L_tmpnam+1]; - char *tocvsPath; - char fname[PATH_MAX]; - -#ifdef SERVER_SUPPORT - user_file_rev = 0; -#endif - vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, - file, 1, 0, entries, srcfiles); - - if (diff_rev2 != NULL || diff_date2 != NULL) - { - /* Skip all the following checks regarding the user file; we're - not using it. */ - } - else if (vers->vn_user == NULL) - { - error (0, 0, "I know nothing about %s", file); - freevers_ts (&vers); - diff_mark_errors (err); - return (err); - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - if (empty_files) - empty_file = DIFF_ADDED; - else - { - error (0, 0, "%s is a new entry, no comparison available", file); - freevers_ts (&vers); - diff_mark_errors (err); - return (err); - } - } - else if (vers->vn_user[0] == '-') - { - if (empty_files) - empty_file = DIFF_REMOVED; - else - { - error (0, 0, "%s was removed, no comparison available", file); - freevers_ts (&vers); - diff_mark_errors (err); - return (err); - } - } - else - { - if (vers->vn_rcs == NULL && vers->srcfile == NULL) - { - error (0, 0, "cannot find revision control file for %s", file); - freevers_ts (&vers); - diff_mark_errors (err); - return (err); - } - else - { - if (vers->ts_user == NULL) - { - error (0, 0, "cannot find %s", file); - freevers_ts (&vers); - diff_mark_errors (err); - return (err); - } -#ifdef SERVER_SUPPORT - else if (!strcmp (vers->ts_user, vers->ts_rcs)) - { - /* The user file matches some revision in the repository - Diff against the repository (for remote CVS, we might not - have a copy of the user file around). */ - user_file_rev = vers->vn_user; - } -#endif - } - } - - if (empty_file == DIFF_NEITHER && diff_file_nodiff (file, repository, entries, srcfiles, vers)) - { - freevers_ts (&vers); - return (0); - } - -#ifdef DEATH_SUPPORT - /* FIXME: Check whether use_rev1 and use_rev2 are dead and deal - accordingly. */ -#endif - - /* Output an "Index:" line for patch to use */ - (void) fflush (stdout); - if (update_dir[0]) - (void) printf ("Index: %s/%s\n", update_dir, file); - else - (void) printf ("Index: %s\n", file); - (void) fflush (stdout); - - tocvsPath = wrap_tocvs_process_file(file); - if (tocvsPath) - { - /* 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 (! 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 */ - copy_file (tocvsPath, file); - } - - if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED) - { - (void) printf ("===================================================================\nRCS file: %s\n", - file); - (void) printf ("diff -N %s\n", file); - - if (empty_file == DIFF_ADDED) - { - run_setup ("%s %s %s %s", DIFF, opts, DEVNULL, file); - } - else - { - /* - * FIXME: Should be setting use_rev1 using the logic in - * diff_file_nodiff, and using that revision. This code - * is broken for "cvs diff -N -r foo". - */ - run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO, - *options ? options : vers->options, vers->vn_rcs); - run_arg (vers->srcfile->path); - 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); - } - - run_setup ("%s %s %s %s", DIFF, opts, tmp, DEVNULL); - } - } - else - { - if (use_rev2) - { - run_setup ("%s%s %s %s -r%s -r%s", Rcsbin, RCS_DIFF, - opts, *options ? options : vers->options, - use_rev1, use_rev2); - } - else - { - run_setup ("%s%s %s %s -r%s", Rcsbin, RCS_DIFF, opts, - *options ? options : vers->options, use_rev1); - } - run_arg (vers->srcfile->path); - } - - switch ((status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, - RUN_REALLY|RUN_COMBINED))) - { - case -1: /* fork failed */ - error (1, errno, "fork failed during rcsdiff of %s", - vers->srcfile->path); - case 0: /* everything ok */ - err = 0; - break; - default: /* other error */ - err = status; - break; - } - - if (tocvsPath) - { - if (unlink_file_dir (file) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", file); - - rename_file (fname,file); - if (unlink_file (tocvsPath) < 0) - error (1, errno, "cannot remove %s", file); - } - - if (empty_file == DIFF_REMOVED) - (void) unlink (tmp); - - (void) fflush (stdout); - freevers_ts (&vers); - diff_mark_errors (err); - return (err); -} - -/* - * Remember the exit status for each file. - */ -static void -diff_mark_errors (err) - int err; -{ - if (err > diff_errors) - diff_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 -diff_dirproc (dir, pos_repos, update_dir) - char *dir; - char *pos_repos; - 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); -} - -/* - * Concoct the proper exit status - done with files - */ -/* ARGSUSED */ -static int -diff_filesdoneproc (err, repos, update_dir) - int err; - char *repos; - char *update_dir; -{ - return (diff_errors); -} - -/* - * Concoct the proper exit status - leaving directories - */ -/* ARGSUSED */ -static int -diff_dirleaveproc (dir, err, update_dir) - char *dir; - int err; - char *update_dir; -{ - return (diff_errors); -} - -/* - * verify that a file is different 0=same 1=different - */ -static int -diff_file_nodiff (file, repository, entries, srcfiles, vers) - char *file; - char *repository; - List *entries; - List *srcfiles; - Vers_TS *vers; -{ - Vers_TS *xvers; - char tmp[L_tmpnam+1]; - - /* free up any old use_rev* variables and reset 'em */ - if (use_rev1) - free (use_rev1); - if (use_rev2) - free (use_rev2); - use_rev1 = use_rev2 = (char *) NULL; - - if (diff_rev1 || diff_date1) - { - /* special handling for TAG_HEAD */ - if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0) - use_rev1 = xstrdup (vers->vn_rcs); - else - { - xvers = Version_TS (repository, (char *) NULL, diff_rev1, - diff_date1, file, 1, 0, entries, srcfiles); - if (xvers->vn_rcs == NULL) - { - /* 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); - return (1); - } - use_rev1 = xstrdup (xvers->vn_rcs); - freevers_ts (&xvers); - } - } - if (diff_rev2 || diff_date2) - { - /* special handling for TAG_HEAD */ - if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0) - use_rev2 = xstrdup (vers->vn_rcs); - else - { - xvers = Version_TS (repository, (char *) NULL, diff_rev2, - diff_date2, file, 1, 0, entries, srcfiles); - if (xvers->vn_rcs == NULL) - { - /* 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_date2, file); - return (1); - } - use_rev2 = xstrdup (xvers->vn_rcs); - freevers_ts (&xvers); - } - - /* now, see if we really need to do the diff */ - if (use_rev1 && use_rev2) { - return (strcmp (use_rev1, use_rev2) == 0); - } else { - error(0, 0, "No HEAD revision for file %s", file); - return (1); - } - } -#ifdef SERVER_SUPPORT - if (user_file_rev) - { - /* drop user_file_rev into first unused use_rev */ - if (!use_rev1) - use_rev1 = xstrdup (user_file_rev); - else if (!use_rev2) - use_rev2 = xstrdup (user_file_rev); - /* and if not, it wasn't needed anyhow */ - user_file_rev = 0; - } - - /* now, see if we really need to do the diff */ - if (use_rev1 && use_rev2) - { - return (strcmp (use_rev1, use_rev2) == 0); - } -#endif /* SERVER_SUPPORT */ - if (use_rev1 == NULL || strcmp (use_rev1, vers->vn_user) == 0) - { - if (strcmp (vers->ts_rcs, vers->ts_user) == 0 && - (!(*options) || strcmp (options, vers->options) == 0)) - { - return (1); - } - if (use_rev1 == NULL) - use_rev1 = xstrdup (vers->vn_user); - } - - /* - * with 0 or 1 -r option specified, run a quick diff to see if we - * should bother with it at all. - */ - run_setup ("%s%s -p -q %s -r%s", Rcsbin, RCS_CO, - *options ? options : vers->options, use_rev1); - run_arg (vers->srcfile->path); - switch (run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY)) - { - case 0: /* everything ok */ - 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); - default: - break; - } - (void) unlink (tmp); - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/entries.c b/gnu/usr.bin/cvs/cvs/entries.c deleted file mode 100644 index 7ae3e58..0000000 --- a/gnu/usr.bin/cvs/cvs/entries.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * 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. - * - * Entries file to Files file - * - * Creates the file Files containing the names that comprise the project, from - * the Entries file. - */ - -#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, 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 - */ -static int write_ent_proc PROTO ((Node *, void *)); -static int -write_ent_proc (node, closure) - Node *node; - void *closure; -{ - if (fputentent(entfile, (Entnode *) node->data)) - error (1, errno, "cannot write %s", entfilename); - - return (0); -} - -/* - * write out the current entries file given a list, making a backup copy - * first of course - */ -static void -write_entries (list) - List *list; -{ - /* open the new one and walk the list writing entries */ - entfilename = CVSADM_ENTBAK; - entfile = open_file (entfilename, "w+"); - (void) walklist (list, write_ent_proc, NULL); - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", entfilename); - - /* now, atomically (on systems that support it) rename it */ - rename_file (entfilename, CVSADM_ENT); - - /* now, remove the log file */ - unlink_file (CVSADM_ENTLOG); -} - -/* - * Removes the argument file from the Entries file if necessary. - */ -void -Scratch_Entry (list, fname) - List *list; - char *fname; -{ - Node *node; - - if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n", - (server_active) ? 'S' : ' ', fname); -#else - (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname); -#endif - - /* hashlookup to see if it is there */ - if ((node = findnode (list, fname)) != NULL) - { - delnode (node); /* delete the node */ -#ifdef SERVER_SUPPORT - if (server_active) - server_scratch (fname); -#endif - if (!noexec) - write_entries (list); /* re-write the file */ - } -} - -/* - * Enters the given file name/version/time-stamp into the Entries file, - * removing the old entry first, if necessary. - */ -void -Register (list, fname, vn, ts, options, tag, date, ts_conflict) - List *list; - char *fname; - char *vn; - char *ts; - char *options; - char *tag; - char *date; - char *ts_conflict; -{ - Entnode *entnode; - Node *node; - -#ifdef SERVER_SUPPORT - if (server_active) - { - server_register (fname, vn, ts, options, tag, date, ts_conflict); - } -#endif - - if (trace) - { -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n", - (server_active) ? 'S' : ' ', - fname, vn, ts ? ts : "", - ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "", - options, tag ? tag : "", date ? date : ""); -#else - (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n", - fname, vn, ts ? ts : "", - ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "", - options, tag ? tag : "", date ? date : ""); -#endif - } - - entnode = Entnode_Create(fname, vn, ts, options, tag, date, ts_conflict); - node = AddEntryNode (list, entnode); - - if (!noexec) - { - entfile = open_file (CVSADM_ENTLOG, "a"); - - write_ent_proc (node, NULL); - - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", CVSADM_ENTLOG); - } -} - -/* - * Node delete procedure for list-private sticky dir tag/date info - */ -static void -freesdt (p) - Node *p; -{ - struct stickydirtag *sdtp; - - sdtp = (struct stickydirtag *) p->data; - if (sdtp->tag) - free (sdtp->tag); - if (sdtp->date) - free (sdtp->date); - if (sdtp->options) - free (sdtp->options); - free ((char *) sdtp); -} - -static Entnode * -fgetentent(fpin) - FILE *fpin; -{ - 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; - - line = NULL; - line_chars_allocated = 0; - - ent = NULL; - while (getline (&line, &line_chars_allocated, fpin) > 0) - { - if (line[0] != '/') - continue; - - user = line + 1; - if ((cp = strchr (user, '/')) == NULL) - continue; - *cp++ = '\0'; - vn = cp; - if ((cp = strchr (vn, '/')) == NULL) - continue; - *cp++ = '\0'; - ts = cp; - if ((cp = strchr (ts, '/')) == NULL) - continue; - *cp++ = '\0'; - options = cp; - if ((cp = strchr (options, '/')) == NULL) - continue; - *cp++ = '\0'; - tag_or_date = cp; - if ((cp = strchr (tag_or_date, '\n')) == NULL) - continue; - *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 ((ts_conflict = strchr (ts, '+'))) - *ts_conflict++ = '\0'; - - /* - * XXX - Convert timestamp from old format to new format. - * - * If the timestamp doesn't match the file's current - * mtime, we'd have to generate a string that doesn't - * match anyways, so cheat and base it on the existing - * string; it doesn't have to match the same mod time. - * - * For an unmodified file, write the correct timestamp. - */ - { - struct stat sb; - if (strlen (ts) > 30 && stat (user, &sb) == 0) - { - char *c = ctime (&sb.st_mtime); - - if (!strncmp (ts + 25, c, 24)) - ts = time_stamp (user); - else - { - ts += 24; - ts[0] = '*'; - } - } - } - - 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; - - 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 0; -} - - -/* - * Read the entries file into a list, hashing on the file name. - */ -List * -Entries_Open (aflag) - int aflag; -{ - List *entries; - Entnode *ent; - char *dirtag, *dirdate; - int do_rewrite = 0; - FILE *fpin; - - /* get a fresh list... */ - entries = getlist (); - - /* - * Parse the CVS/Tag file, to get any default tag/date settings. Use - * list-private storage to tuck them away for Version_TS(). - */ - ParseTag (&dirtag, &dirdate); - if (aflag || dirtag || dirdate) - { - struct stickydirtag *sdtp; - - sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp)); - memset ((char *) sdtp, 0, sizeof (*sdtp)); - sdtp->aflag = aflag; - sdtp->tag = xstrdup (dirtag); - sdtp->date = xstrdup (dirdate); - - /* feed it into the list-private area */ - entries->list->data = (char *) sdtp; - entries->list->delproc = freesdt; - } - - fpin = fopen (CVSADM_ENT, "r"); - if (fpin == NULL) - error (0, errno, "cannot open %s for reading", CVSADM_ENT); - else - { - while ((ent = fgetentent (fpin)) != NULL) - { - (void) AddEntryNode (entries, ent); - } - - fclose (fpin); - } - - fpin = fopen (CVSADM_ENTLOG, "r"); - if (fpin != NULL) - { - while ((ent = fgetentent (fpin)) != NULL) - { - (void) AddEntryNode (entries, ent); - } - do_rewrite = 1; - fclose (fpin); - } - - if (do_rewrite && !noexec) - write_entries (entries); - - /* clean up and return */ - if (fpin) - (void) fclose (fpin); - if (dirtag) - free (dirtag); - if (dirdate) - free (dirdate); - return (entries); -} - -void -Entries_Close(list) - List *list; -{ - if (list) - { - if (!noexec) - { - if (isfile (CVSADM_ENTLOG)) - write_entries (list); - } - dellist(&list); - } -} - - -/* - * Free up the memory associated with the data section of an ENTRIES type - * node - */ -static void -Entries_delproc (node) - Node *node; -{ - Entnode *p; - - p = (Entnode *) node->data; - Entnode_Destroy(p); -} - -/* - * Get an Entries file list node, initialize it, and add it to the specified - * list - */ -static Node * -AddEntryNode (list, entdata) - List *list; - Entnode *entdata; -{ - Node *p; - - /* was it already there? */ - if ((p = findnode (list, entdata->user)) != NULL) - { - /* take it out */ - delnode (p); - } - - /* get a node and fill in the regular stuff */ - p = getnode (); - p->type = ENTRIES; - p->delproc = Entries_delproc; - - /* this one gets a key of the name for hashing */ - /* 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); - return (p); -} - -/* - * Write out/Clear the CVS/Tag file. - */ -void -WriteTag (dir, tag, date) - char *dir; - char *tag; - char *date; -{ - FILE *fout; - char tmp[PATH_MAX]; - - if (noexec) - return; - - if (dir == NULL) - (void) strcpy (tmp, CVSADM_TAG); - else - (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG); - - if (tag || date) - { - fout = open_file (tmp, "w+"); - if (tag) - { - if (fprintf (fout, "T%s\n", tag) < 0) - error (1, errno, "write to %s failed", tmp); - } - else - { - if (fprintf (fout, "D%s\n", date) < 0) - error (1, errno, "write to %s failed", tmp); - } - if (fclose (fout) == EOF) - error (1, errno, "cannot close %s", tmp); - } - else - if (unlink_file (tmp) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove %s", tmp); -} - -/* - * Parse the CVS/Tag file for the current directory. - */ -void -ParseTag (tagp, datep) - char **tagp; - char **datep; -{ - FILE *fp; - - if (tagp) - *tagp = (char *) NULL; - if (datep) - *datep = (char *) NULL; - fp = fopen (CVSADM_TAG, "r"); - if (fp) - { - 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) - { - /* 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/cvs/expand_path.c b/gnu/usr.bin/cvs/cvs/expand_path.c deleted file mode 100644 index 7cc939f..0000000 --- a/gnu/usr.bin/cvs/cvs/expand_path.c +++ /dev/null @@ -1,139 +0,0 @@ -/* expand_path.c -- expand environmental variables in passed in string - The main routine is expand_pathname, 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: - c is some character - ${var_name} var_name is the name of the environ variable - $var_name var_name ends with a non ascii character - 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. - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include "cvs.h" -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#if HAVE_STRING_H -#include <string.h> -#else -#include <strings.h> -#endif -static char *expand_variable PROTO((char *env)); -extern char *xmalloc (); -extern void free (); -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/cvs/find_names.c b/gnu/usr.bin/cvs/cvs/find_names.c deleted file mode 100644 index 82959b5..0000000 --- a/gnu/usr.bin/cvs/cvs/find_names.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * 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. - * - * Find Names - * - * Finds all the pertinent file names, both from the administration and from the - * repository - * - * Find Dirs - * - * Finds all pertinent sub-directories of the checked out instantiation and the - * repository (and optionally the attic) - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)find_names.c 1.45 94/10/22 $"; -USE(rcsid); -#endif - -static int find_dirs PROTO((char *dir, List * list, int checkadm)); -static int find_rcs PROTO((char *dir, List * list)); - -static List *filelist; - -/* - * add the key from entry on entries list to the files list - */ -static int add_entries_proc PROTO((Node *, void *)); -static int -add_entries_proc (node, closure) - Node *node; - void *closure; -{ - Node *fnode; - - fnode = getnode (); - fnode->type = FILES; - fnode->key = xstrdup (node->key); - if (addnode (filelist, fnode) != 0) - freenode (fnode); - return (0); -} - -/* - * compare two files list node (for sort) - */ -static int fsortcmp PROTO ((const Node *, const Node *)); -static int -fsortcmp (p, q) - const Node *p; - const Node *q; -{ - return (strcmp (p->key, q->key)); -} - -List * -Find_Names (repository, which, aflag, optentries) - char *repository; - int which; - int aflag; - List **optentries; -{ - List *entries; - List *files; - char dir[PATH_MAX]; - - /* make a list for the files */ - files = filelist = getlist (); - - /* look at entries (if necessary) */ - if (which & W_LOCAL) - { - /* parse the entries file (if it exists) */ - entries = Entries_Open (aflag); - if (entries != NULL) - { - /* walk the entries file adding elements to the files list */ - (void) walklist (entries, add_entries_proc, NULL); - - /* if our caller wanted the entries list, return it; else free it */ - if (optentries != NULL) - *optentries = entries; - else - Entries_Close (entries); - } - } - - if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT)) - { - /* search the repository */ - if (find_rcs (repository, files) != 0) - error (1, errno, "cannot open directory %s", repository); - - /* search the attic too */ - if (which & W_ATTIC) - { - (void) sprintf (dir, "%s/%s", repository, CVSATTIC); - (void) find_rcs (dir, files); - } - } - - /* sort the list into alphabetical order and return it */ - sortlist (files, fsortcmp); - return (files); -} - -/* - * create a list of directories to traverse from the current directory - */ -List * -Find_Dirs (repository, which) - char *repository; - int which; -{ - List *dirlist; - - /* make a list for the directories */ - dirlist = getlist (); - - /* find the local ones */ - if (which & W_LOCAL) - { - /* look only for CVS controlled sub-directories */ - if (find_dirs (".", dirlist, 1) != 0) - error (1, errno, "cannot open current directory"); - } - - /* look for sub-dirs in the repository */ - if ((which & W_REPOS) && repository) - { - /* search the repository */ - if (find_dirs (repository, dirlist, 0) != 0) - error (1, errno, "cannot open directory %s", repository); - -#ifdef ATTIC_DIR_SUPPORT /* XXX - FIXME */ - /* search the attic too */ - if (which & W_ATTIC) - { - char dir[PATH_MAX]; - - (void) sprintf (dir, "%s/%s", repository, CVSATTIC); - (void) find_dirs (dir, dirlist, 0); - } -#endif - } - - /* sort the list into alphabetical order and return it */ - sortlist (dirlist, fsortcmp); - return (dirlist); -} - -/* - * Finds all the ,v files in the argument directory, and adds them to the - * files list. Returns 0 for success and non-zero if the argument directory - * cannot be opened. - */ -static int -find_rcs (dir, list) - char *dir; - List *list; -{ - Node *p; - struct dirent *dp; - DIR *dirp; - - /* set up to read the dir */ - if ((dirp = opendir (dir)) == NULL) - return (1); - - /* read the dir, grabbing the ,v files */ - while ((dp = readdir (dirp)) != NULL) - { - if (fnmatch (RCSPAT, dp->d_name, 0) == 0) - { - char *comma; - - comma = strrchr (dp->d_name, ','); /* strip the ,v */ - *comma = '\0'; - p = getnode (); - p->type = FILES; - p->key = xstrdup (dp->d_name); - if (addnode (list, p) != 0) - freenode (p); - } - } - (void) closedir (dirp); - return (0); -} - -/* - * Finds all the subdirectories of the argument dir and adds them to the - * specified list. Sub-directories without a CVS administration directory - * are optionally ignored Returns 0 for success or 1 on error. - */ -static int -find_dirs (dir, list, checkadm) - char *dir; - List *list; - int checkadm; -{ - Node *p; - char tmp[PATH_MAX]; - struct dirent *dp; - DIR *dirp; - - /* set up to read the dir */ - if ((dirp = opendir (dir)) == NULL) - return (1); - - /* read the dir, grabbing sub-dirs */ - while ((dp = readdir (dirp)) != NULL) - { - if (strcmp (dp->d_name, ".") == 0 || - strcmp (dp->d_name, "..") == 0 || - strcmp (dp->d_name, CVSATTIC) == 0 || - strcmp (dp->d_name, CVSLCK) == 0) - continue; - -#ifdef DT_DIR - if (dp->d_type != DT_DIR) - { - if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK) - continue; -#endif - /* don't bother stating ,v files */ - if (fnmatch (RCSPAT, dp->d_name, 0) == 0) - continue; - - sprintf (tmp, "%s/%s", dir, dp->d_name); - if (!isdir (tmp)) - continue; - -#ifdef DT_DIR - } -#endif - - /* check for administration directories (if needed) */ - if (checkadm) - { - /* blow off symbolic links to dirs in local dir */ -#ifdef DT_DIR - if (dp->d_type != DT_DIR) - { - /* we're either unknown or a symlink at this point */ - if (dp->d_type == DT_LNK) - continue; -#endif - if (islink (tmp)) - continue; -#ifdef DT_DIR - } -#endif - - /* check for new style */ - (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM); - if (!isdir (tmp)) - continue; - } - - /* put it in the list */ - p = getnode (); - p->type = DIRS; - p->key = xstrdup (dp->d_name); - if (addnode (list, p) != 0) - freenode (p); - } - (void) closedir (dirp); - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/history.c b/gnu/usr.bin/cvs/cvs/history.c deleted file mode 100644 index 7a40b7b..0000000 --- a/gnu/usr.bin/cvs/cvs/history.c +++ /dev/null @@ -1,1489 +0,0 @@ -/* - * - * You may distribute under the terms of the GNU General Public License - * as specified in the README file that comes with the CVS 1.0 kit. - * - * **************** History of Users and Module **************** - * - * LOGGING: Append record to "${CVSROOT}/CVSROOTADM/CVSROOTADM_HISTORY". - * - * On For each Tag, Add, Checkout, Commit, Update or Release command, - * one line of text is written to a History log. - * - * X date | user | CurDir | special | rev(s) | argument '\n' - * - * where: [The spaces in the example line above are not in the history file.] - * - * X is a single character showing the type of event: - * T "Tag" cmd. - * O "Checkout" cmd. - * F "Release" cmd. - * W "Update" cmd - No User file, Remove from Entries file. - * U "Update" cmd - File was checked out over User file. - * G "Update" cmd - File was merged successfully. - * C "Update" cmd - File was merged and shows overlaps. - * M "Commit" cmd - "Modified" file. - * A "Commit" cmd - "Added" file. - * R "Commit" cmd - "Removed" file. - * - * date is a fixed length 8-char hex representation of a Unix time_t. - * [Starting here, variable fields are delimited by '|' chars.] - * - * user is the username of the person who typed the command. - * - * CurDir The directory where the action occurred. This should be the - * absolute path of the directory which is at the same level as - * the "Repository" field (for W,U,G,C & M,A,R). - * - * Repository For record types [W,U,G,C,M,A,R] this field holds the - * repository read from the administrative data where the - * command was typed. - * T "A" --> New Tag, "D" --> Delete Tag - * Otherwise it is the Tag or Date to modify. - * O,F A "" (null field) - * - * rev(s) Revision number or tag. - * T The Tag to apply. - * O The Tag or Date, if specified, else "" (null field). - * F "" (null field) - * W The Tag or Date, if specified, else "" (null field). - * U The Revision checked out over the User file. - * G,C The Revision(s) involved in merge. - * M,A,R RCS Revision affected. - * - * argument The module (for [TOUF]) or file (for [WUGCMAR]) affected. - * - * - *** Report categories: "User" and "Since" modifiers apply to all reports. - * [For "sort" ordering see the "sort_order" routine.] - * - * Extract list of record types - * - * -e, -x [TOFWUGCMAR] - * - * Extracted records are simply printed, No analysis is performed. - * All "field" modifiers apply. -e chooses all types. - * - * Checked 'O'ut modules - * - * -o, -w - * Checked out modules. 'F' and 'O' records are examined and if - * the last record for a repository/file is an 'O', a line is - * printed. "-w" forces the "working dir" to be used in the - * comparison instead of the repository. - * - * Committed (Modified) files - * - * -c, -l, -w - * All 'M'odified, 'A'dded and 'R'emoved records are examined. - * "Field" modifiers apply. -l forces a sort by file within user - * and shows only the last modifier. -w works as in Checkout. - * - * Warning: Be careful with what you infer from the output of - * "cvs hi -c -l". It means the last time *you* - * changed the file, not the list of files for which - * you were the last changer!!! - * - * Module history for named modules. - * -m module, -l - * - * This is special. If one or more modules are specified, the - * module names are remembered and the files making up the - * modules are remembered. Only records matching exactly those - * files and repositories are shown. Sorting by "module", then - * filename, is implied. If -l ("last modified") is specified, - * then "update" records (types WUCG), tag and release records - * are ignored and the last (by date) "modified" record. - * - * TAG history - * - * -T All Tag records are displayed. - * - *** Modifiers. - * - * Since ... [All records contain a timestamp, so any report - * category can be limited by date.] - * - * -D date - The "date" is parsed into a Unix "time_t" and - * records with an earlier time stamp are ignored. - * -r rev/tag - A "rev" begins with a digit. A "tag" does not. If - * you use this option, every file is searched for the - * indicated rev/tag. - * -t tag - The "tag" is searched for in the history file and no - * record is displayed before the tag is found. An - * error is printed if the tag is never found. - * -b string - Records are printed only back to the last reference - * to the string in the "module", "file" or - * "repository" fields. - * - * Field Selections [Simple comparisons on existing fields. All field - * selections are repeatable.] - * - * -a - All users. - * -u user - If no user is given and '-a' is not given, only - * records for the user typing the command are shown. - * ==> If -a or -u is not specified, just use "self". - * - * -f filematch - Only records in which the "file" field contains the - * string "filematch" are considered. - * - * -p repository - Only records in which the "repository" string is a - * prefix of the "repos" field are considered. - * - * -m modulename - Only records which contain "modulename" in the - * "module" field are considered. - * - * - * EXAMPLES: ("cvs history", "cvs his" or "cvs hi") - * - *** Checked out files for username. (default self, e.g. "dgg") - * cvs hi [equivalent to: "cvs hi -o -u dgg"] - * cvs hi -u user [equivalent to: "cvs hi -o -u user"] - * cvs hi -o [equivalent to: "cvs hi -o -u dgg"] - * - *** Committed (modified) files from the beginning of the file. - * cvs hi -c [-u user] - * - *** Committed (modified) files since Midnight, January 1, 1990: - * cvs hi -c -D 'Jan 1 1990' [-u user] - * - *** Committed (modified) files since tag "TAG" was stored in the history file: - * cvs hi -c -t TAG [-u user] - * - *** Committed (modified) files since tag "TAG" was placed on the files: - * cvs hi -c -r TAG [-u user] - * - *** Who last committed file/repository X? - * cvs hi -c -l -[fp] X - * - *** Modified files since tag/date/file/repos? - * cvs hi -c {-r TAG | -D Date | -b string} - * - *** Tag history - * cvs hi -T - * - *** History of file/repository/module X. - * cvs hi -[fpn] X - * - *** History of user "user". - * cvs hi -e -u user - * - *** Dump (eXtract) specified record types - * cvs hi -x [TOFWUGCMAR] - * - * - * FUTURE: J[Join], I[Import] (Not currently implemented.) - * - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)history.c 1.33 94/09/21 $"; -USE(rcsid); -#endif - -static struct hrec -{ - char *type; /* Type of record (In history record) */ - char *user; /* Username (In history record) */ - char *dir; /* "Compressed" Working dir (In history record) */ - char *repos; /* (Tag is special.) Repository (In history record) */ - char *rev; /* Revision affected (In history record) */ - char *file; /* Filename (In history record) */ - char *end; /* Ptr into repository to copy at end of workdir */ - char *mod; /* The module within which the file is contained */ - time_t date; /* Calculated from date stored in record */ - int idx; /* Index of record, for "stable" sort. */ -} *hrec_head; - - -static char *fill_hrec PROTO((char *line, struct hrec * hr)); -static int accept_hrec PROTO((struct hrec * hr, struct hrec * lr)); -static int select_hrec PROTO((struct hrec * hr)); -static int sort_order PROTO((const PTR l, const PTR r)); -static int within PROTO((char *find, char *string)); -static time_t date_and_time PROTO((char *date_str)); -static void expand_modules PROTO((void)); -static void read_hrecs PROTO((char *fname)); -static void report_hrecs PROTO((void)); -static void save_file PROTO((char *dir, char *name, char *module)); -static void save_module PROTO((char *module)); -static void save_user PROTO((char *name)); - -#define ALL_REC_TYPES "TOFWUCGMAR" -#define USER_INCREMENT 2 -#define FILE_INCREMENT 128 -#define MODULE_INCREMENT 5 -#define HREC_INCREMENT 128 - -static short report_count; - -static short extract; -static short v_checkout; -static short modified; -static short tag_report; -static short module_report; -static short working; -static short last_entry; -static short all_users; - -static short user_sort; -static short repos_sort; -static short file_sort; -static short module_sort; - -#ifdef HAVE_RCS5 -static short tz_local; -static time_t tz_seconds_east_of_GMT; -static char *tz_name = "+0000"; -#else -static char tz_name[] = "LT"; -#endif - -static time_t since_date; -static char since_rev[20]; /* Maxrev ~= 99.99.99.999 */ -static char since_tag[64]; -static struct hrec *last_since_tag; -static char backto[128]; -static struct hrec *last_backto; -static char rec_types[20]; - -static int hrec_count; -static int hrec_max; - -static char **user_list; /* Ptr to array of ptrs to user names */ -static int user_max; /* Number of elements allocated */ -static int user_count; /* Number of elements used */ - -static struct file_list_str -{ - char *l_file; - char *l_module; -} *file_list; /* Ptr to array file name structs */ -static int file_max; /* Number of elements allocated */ -static int file_count; /* Number of elements used */ - -static char **mod_list; /* Ptr to array of ptrs to module names */ -static int mod_max; /* Number of elements allocated */ -static int mod_count; /* Number of elements used */ - -static char *histfile; /* Ptr to the history file name */ - -static const char *const history_usg[] = -{ - "Usage: %s %s [-report] [-flags] [-options args] [files...]\n\n", - " Reports:\n", - " -T Produce report on all TAGs\n", - " -c Committed (Modified) files\n", - " -o Checked out modules\n", - " -m <module> Look for specified module (repeatable)\n", - " -x [TOFWUCGMAR] Extract by record type\n", - " Flags:\n", - " -a All users (Default is self)\n", - " -e Everything (same as -x, but all record types)\n", - " -l Last modified (committed or modified report)\n", - " -w Working directory must match\n", - " Options:\n", - " -D <date> Since date (Many formats)\n", - " -b <str> Back to record with str in module/file/repos field\n", - " -f <file> Specified file (same as command line) (repeatable)\n", - " -n <modulename> In module (repeatable)\n", - " -p <repos> In repository (repeatable)\n", - " -r <rev/tag> Since rev or tag (looks inside RCS files!)\n", - " -t <tag> Since tag record placed in history file (by anyone).\n", - " -u <user> For user name (repeatable)\n", - " -z <tz> Output for time zone <tz> (e.g. -z -0700)\n", - NULL}; - -/* Sort routine for qsort: - - If a user is selected at all, sort it first. User-within-file is useless. - - If a module was selected explicitly, sort next on module. - - Then sort by file. "File" is "repository/file" unless "working" is set, - then it is "workdir/file". (Revision order should always track date.) - - Always sort timestamp last. -*/ -static int -sort_order (l, r) - const PTR l; - const PTR r; -{ - int i; - const struct hrec *left = (const struct hrec *) l; - const struct hrec *right = (const struct hrec *) r; - - if (user_sort) /* If Sort by username, compare users */ - { - if ((i = strcmp (left->user, right->user)) != 0) - return (i); - } - if (module_sort) /* If sort by modules, compare module names */ - { - if (left->mod && right->mod) - if ((i = strcmp (left->mod, right->mod)) != 0) - return (i); - } - if (repos_sort) /* If sort by repository, compare them. */ - { - if ((i = strcmp (left->repos, right->repos)) != 0) - return (i); - } - if (file_sort) /* If sort by filename, compare files, NOT dirs. */ - { - if ((i = strcmp (left->file, right->file)) != 0) - return (i); - - if (working) - { - if ((i = strcmp (left->dir, right->dir)) != 0) - return (i); - - if ((i = strcmp (left->end, right->end)) != 0) - return (i); - } - } - - /* - * By default, sort by date, time - * XXX: This fails after 2030 when date slides into sign bit - */ - if ((i = ((long) (left->date) - (long) (right->date))) != 0) - return (i); - - /* For matching dates, keep the sort stable by using record index */ - return (left->idx - right->idx); -} - -static time_t -date_and_time (date_str) - char *date_str; -{ - time_t t; - - t = get_date (date_str, (struct timeb *) NULL); - if (t == (time_t) - 1) - error (1, 0, "Can't parse date/time: %s", date_str); - return (t); -} - -int -history (argc, argv) - int argc; - char **argv; -{ - int i, c; - char fname[PATH_MAX]; - - if (argc == -1) - usage (history_usg); - - optind = 1; - while ((c = getopt (argc, argv, "Tacelow?D:b:f:m:n:p:r:t:u:x:X:z:")) != -1) - { - switch (c) - { - case 'T': /* Tag list */ - report_count++; - tag_report++; - break; - case 'a': /* For all usernames */ - all_users++; - break; - case 'c': - report_count++; - modified = 1; - break; - case 'e': - report_count++; - extract++; - (void) strcpy (rec_types, ALL_REC_TYPES); - break; - case 'l': /* Find Last file record */ - last_entry = 1; - break; - case 'o': - report_count++; - v_checkout = 1; - break; - case 'w': /* Match Working Dir (CurDir) fields */ - working = 1; - break; - case 'X': /* Undocumented debugging flag */ - histfile = optarg; - break; - case 'D': /* Since specified date */ - if (*since_rev || *since_tag || *backto) - { - error (0, 0, "date overriding rev/tag/backto"); - *since_rev = *since_tag = *backto = '\0'; - } - since_date = date_and_time (optarg); - break; - case 'b': /* Since specified file/Repos */ - if (since_date || *since_rev || *since_tag) - { - error (0, 0, "backto overriding date/rev/tag"); - *since_rev = *since_tag = '\0'; - since_date = 0; - } - if (strlen (optarg) >= sizeof (backto)) - { - error (0, 0, "backto truncated to %d bytes", - sizeof (backto) - 1); - optarg[sizeof (backto) - 1] = '\0'; - } - (void) strcpy (backto, optarg); - break; - case 'f': /* For specified file */ - save_file ("", optarg, (char *) NULL); - break; - case 'm': /* Full module report */ - report_count++; - module_report++; - case 'n': /* Look for specified module */ - save_module (optarg); - break; - case 'p': /* For specified directory */ - save_file (optarg, "", (char *) NULL); - break; - case 'r': /* Since specified Tag/Rev */ - if (since_date || *since_tag || *backto) - { - error (0, 0, "rev overriding date/tag/backto"); - *since_tag = *backto = '\0'; - since_date = 0; - } - (void) strcpy (since_rev, optarg); - break; - case 't': /* Since specified Tag/Rev */ - if (since_date || *since_rev || *backto) - { - error (0, 0, "tag overriding date/marker/file/repos"); - *since_rev = *backto = '\0'; - since_date = 0; - } - (void) strcpy (since_tag, optarg); /* tag */ - break; - case 'u': /* For specified username */ - save_user (optarg); - break; - case 'x': - report_count++; - extract++; - { - char *cp; - - for (cp = optarg; *cp; cp++) - if (!strchr (ALL_REC_TYPES, *cp)) - error (1, 0, "%c is not a valid report type", *cp); - } - (void) strcpy (rec_types, optarg); - break; - case 'z': -#ifndef HAVE_RCS5 - error (0, 0, "-z not supported with RCS 4"); -#else - tz_local = - (optarg[0] == 'l' || optarg[0] == 'L') - && (optarg[1] == 't' || optarg[1] == 'T') - && !optarg[2]; - if (tz_local) - tz_name = optarg; - else - { - /* - * Convert a known time with the given timezone to time_t. - * Use the epoch + 23 hours, so timezones east of GMT work. - */ - static char f[] = "1/1/1970 23:00 %s"; - char *buf = xmalloc (sizeof (f) - 2 + strlen (optarg)); - time_t t; - sprintf (buf, f, optarg); - t = get_date (buf, (struct timeb *) NULL); - free (buf); - if (t == (time_t) -1) - error (0, 0, "%s is not a known time zone", optarg); - else - { - /* - * Convert to seconds east of GMT, removing the - * 23-hour offset mentioned above. - */ - tz_seconds_east_of_GMT = (time_t)23 * 60 * 60 - t; - tz_name = optarg; - } - } -#endif - break; - case '?': - default: - usage (history_usg); - break; - } - } - c = optind; /* Save the handled option count */ - - /* ================ Now analyze the arguments a bit */ - if (!report_count) - v_checkout++; - else if (report_count > 1) - error (1, 0, "Only one report type allowed from: \"-Tcomx\"."); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - struct file_list_str *f1; - char **mod; - - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (tag_report) - send_arg("-T"); - if (all_users) - send_arg("-a"); - if (modified) - send_arg("-c"); - if (last_entry) - send_arg("-l"); - if (v_checkout) - send_arg("-o"); - if (working) - send_arg("-w"); - if (histfile) - send_arg("-X"); - if (since_date) - option_with_arg ("-D", asctime (gmtime (&since_date))); - if (backto[0] != '\0') - option_with_arg ("-b", backto); - for (f1 = file_list; f1 < &file_list[file_count]; ++f1) - { - if (f1->l_file[0] == '*') - option_with_arg ("-p", f1->l_file + 1); - else - option_with_arg ("-f", f1->l_file); - } - if (module_report) - send_arg("-m"); - for (mod = mod_list; mod < &mod_list[mod_count]; ++mod) - option_with_arg ("-n", *mod); - if (since_rev != NULL) - option_with_arg ("-r", since_rev); - if (since_tag != NULL) - option_with_arg ("-t", since_tag); - for (mod = user_list; mod < &user_list[user_count]; ++mod) - option_with_arg ("-u", *mod); - if (extract) - 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"); - return get_responses_and_close (); - } -#endif - - if (all_users) - save_user (""); - - if (mod_list) - expand_modules (); - - if (tag_report) - { - if (!strchr (rec_types, 'T')) - (void) strcat (rec_types, "T"); - } - else if (extract) - { - if (user_list) - user_sort++; - } - else if (modified) - { - (void) strcpy (rec_types, "MAR"); - /* - * If the user has not specified a date oriented flag ("Since"), sort - * by Repository/file before date. Default is "just" date. - */ - if (!since_date && !*since_rev && !*since_tag && !*backto) - { - repos_sort++; - file_sort++; - /* - * If we are not looking for last_modified and the user specified - * one or more users to look at, sort by user before filename. - */ - if (!last_entry && user_list) - user_sort++; - } - } - else if (module_report) - { - (void) strcpy (rec_types, last_entry ? "OMAR" : ALL_REC_TYPES); - module_sort++; - repos_sort++; - file_sort++; - working = 0; /* User's workdir doesn't count here */ - } - else - /* Must be "checkout" or default */ - { - (void) strcpy (rec_types, "OF"); - /* See comments in "modified" above */ - if (!last_entry && user_list) - user_sort++; - if (!since_date && !*since_rev && !*since_tag && !*backto) - file_sort++; - } - - /* If no users were specified, use self (-a saves a universal ("") user) */ - if (!user_list) - save_user (getcaller ()); - - /* If we're looking back to a Tag value, must consider "Tag" records */ - if (*since_tag && !strchr (rec_types, 'T')) - (void) strcat (rec_types, "T"); - - argc -= c; - argv += c; - for (i = 0; i < argc; i++) - save_file ("", argv[i], (char *) NULL); - - if (histfile) - (void) strcpy (fname, histfile); - else - (void) sprintf (fname, "%s/%s/%s", CVSroot, - CVSROOTADM, CVSROOTADM_HISTORY); - - read_hrecs (fname); - qsort ((PTR) hrec_head, hrec_count, sizeof (struct hrec), sort_order); - report_hrecs (); - - return (0); -} - -void -history_write (type, update_dir, revs, name, repository) - int type; - char *update_dir; - char *revs; - char *name; - char *repository; -{ - char fname[PATH_MAX], workdir[PATH_MAX], homedir[PATH_MAX]; - static char username[20]; /* !!! Should be global */ - int fd; - char *line; - char *slash = "", *cp, *cp2, *repos; - int i; - static char *tilde = ""; - static char *PrCurDir = NULL; - - if (logoff) /* History is turned off by cmd line switch */ - return; - (void) sprintf (fname, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_HISTORY); - - /* turn off history logging if the history file does not exist */ - if (!isfile (fname)) - { - logoff = 1; - return; - } - - if (trace) -#ifdef SERVER_SUPPORT - fprintf (stderr, "%c-> fopen(%s,a)\n", - (server_active) ? 'S' : ' ', fname); -#else - fprintf (stderr, "-> fopen(%s,a)\n", fname); -#endif - if (noexec) - return; - if ((fd = open (fname, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0) - error (1, errno, "cannot open history file: %s", fname); - - repos = Short_Repository (repository); - - if (!PrCurDir) - { - struct passwd *pw; - - (void) strcpy (username, getcaller ()); - PrCurDir = CurDir; - if (!(pw = (struct passwd *) getpwnam (username))) - error (0, 0, "cannot find own username"); - else - { - /* Assumes neither CurDir nor pw->pw_dir ends in '/' */ - i = strlen (pw->pw_dir); - if (!strncmp (CurDir, pw->pw_dir, i)) - { - PrCurDir += i; /* Point to '/' separator */ - tilde = "~"; - } - else - { - /* Try harder to find a "homedir" */ - 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); - if (!strncmp (CurDir, homedir, i)) - { - PrCurDir += i; /* Point to '/' separator */ - tilde = "~"; - } - } - } - } - - if (type == 'T') - { - repos = update_dir; - update_dir = ""; - } - else if (update_dir && *update_dir) - slash = "/"; - else - update_dir = ""; - - (void) sprintf (workdir, "%s%s%s%s", tilde, PrCurDir, slash, update_dir); - - /* - * "workdir" is the directory where the file "name" is. ("^~" == $HOME) - * "repos" is the Repository, relative to $CVSROOT where the RCS file is. - * - * "$workdir/$name" is the working file name. - * "$CVSROOT/$repos/$name,v" is the RCS file in the Repository. - * - * First, note that the history format was intended to save space, not - * to be human readable. - * - * The working file directory ("workdir") and the Repository ("repos") - * usually end with the same one or more directory elements. To avoid - * duplication (and save space), the "workdir" field ends with - * an integer offset into the "repos" field. This offset indicates the - * beginning of the "tail" of "repos", after which all characters are - * duplicates. - * - * In other words, if the "workdir" field has a '*' (a very stupid thing - * to put in a filename) in it, then every thing following the last '*' - * is a hex offset into "repos" of the first character from "repos" to - * append to "workdir" to finish the pathname. - * - * It might be easier to look at an example: - * - * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo - * - * Indicates that the workdir is really "~/work/cvs/examples", saving - * 10 characters, where "~/work*d" would save 6 characters and mean that - * the workdir is really "~/work/examples". It will mean more on - * directories like: usr/local/gnu/emacs/dist-19.17/lisp/term - * - * "workdir" is always an absolute pathname (~/xxx is an absolute path) - * "repos" is always a relative pathname. So we can assume that we will - * never run into the top of "workdir" -- there will always be a '/' or - * a '~' at the head of "workdir" that is not matched by anything in - * "repos". On the other hand, we *can* run off the top of "repos". - * - * Only "compress" if we save characters. - */ - - if (!repos) - repos = ""; - - cp = workdir + strlen (workdir) - 1; - cp2 = repos + strlen (repos) - 1; - for (i = 0; cp2 >= repos && cp > workdir && *cp == *cp2--; cp--) - i++; - - if (i > 2) - { - i = strlen (repos) - i; - (void) sprintf ((cp + 1), "*%x", i); - } - - if (!revs) - revs = ""; - line = xmalloc (strlen (username) + strlen (workdir) + strlen (repos) - + strlen (revs) + strlen (name) + 100); - sprintf (line, "%c%08lx|%s|%s|%s|%s|%s\n", - type, (long) time ((time_t *) NULL), - username, workdir, repos, revs, name); - - /* Lessen some race conditions on non-Posix-compliant hosts. */ - if (lseek (fd, (off_t) 0, SEEK_END) == -1) - error (1, errno, "cannot seek to end of history file: %s", fname); - - if (write (fd, line, strlen (line)) < 0) - error (1, errno, "cannot write to history file: %s", fname); - free (line); - if (close (fd) != 0) - error (1, errno, "cannot close history file: %s", fname); -} - -/* - * save_user() adds a user name to the user list to select. Zero-length - * username ("") matches any user. - */ -static void -save_user (name) - char *name; -{ - if (user_count == user_max) - { - user_max += USER_INCREMENT; - user_list = (char **) xrealloc ((char *) user_list, - (int) user_max * sizeof (char *)); - } - user_list[user_count++] = xstrdup (name); -} - -/* - * save_file() adds file name and associated module to the file list to select. - * - * If "dir" is null, store a file name as is. - * If "name" is null, store a directory name with a '*' on the front. - * Else, store concatenated "dir/name". - * - * Later, in the "select" stage: - * - if it starts with '*', it is prefix-matched against the repository. - * - if it has a '/' in it, it is matched against the repository/file. - * - else it is matched against the file name. - */ -static void -save_file (dir, name, module) - char *dir; - char *name; - char *module; -{ - char *cp; - struct file_list_str *fl; - - if (file_count == file_max) - { - file_max += FILE_INCREMENT; - file_list = (struct file_list_str *) xrealloc ((char *) file_list, - file_max * sizeof (*fl)); - } - fl = &file_list[file_count++]; - fl->l_file = cp = xmalloc (strlen (dir) + strlen (name) + 2); - fl->l_module = module; - - if (dir && *dir) - { - if (name && *name) - { - (void) strcpy (cp, dir); - (void) strcat (cp, "/"); - (void) strcat (cp, name); - } - else - { - *cp++ = '*'; - (void) strcpy (cp, dir); - } - } - else - { - if (name && *name) - { - (void) strcpy (cp, name); - } - else - { - error (0, 0, "save_file: null dir and file name"); - } - } -} - -static void -save_module (module) - char *module; -{ - if (mod_count == mod_max) - { - mod_max += MODULE_INCREMENT; - mod_list = (char **) xrealloc ((char *) mod_list, - mod_max * sizeof (char *)); - } - mod_list[mod_count++] = xstrdup (module); -} - -static void -expand_modules () -{ -} - -/* fill_hrec - * - * Take a ptr to 7-part history line, ending with a newline, for example: - * - * M273b3463|dgg|~/work*9|usr/local/cvs/examples|1.2|loginfo - * - * Split it into 7 parts and drop the parts into a "struct hrec". - * Return a pointer to the character following the newline. - */ - -#define NEXT_BAR(here) do { while (isspace(*line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return(rtn); *(line - 1) = '\0'; } while (0) - -static char * -fill_hrec (line, hr) - char *line; - struct hrec *hr; -{ - char *cp, *rtn; - int c; - int off; - static int idx = 0; - - memset ((char *) hr, 0, sizeof (*hr)); - while (isspace (*line)) - line++; - if (!(rtn = strchr (line, '\n'))) - return (""); - *rtn++ = '\0'; - - hr->type = line++; - (void) sscanf (line, "%x", &hr->date); - while (*line && strchr ("0123456789abcdefABCDEF", *line)) - line++; - if (*line == '\0') - return (rtn); - - line++; - NEXT_BAR (user); - NEXT_BAR (dir); - if ((cp = strrchr (hr->dir, '*')) != NULL) - { - *cp++ = '\0'; - (void) sscanf (cp, "%x", &off); - hr->end = line + off; - } - else - hr->end = line - 1; /* A handy pointer to '\0' */ - NEXT_BAR (repos); - NEXT_BAR (rev); - hr->idx = idx++; - if (strchr ("FOT", *(hr->type))) - hr->mod = line; - - NEXT_BAR (file); /* This returns ptr to next line or final '\0' */ - return (rtn); /* If it falls through, go on to next record */ -} - -/* read_hrecs's job is to read the history file and fill in all the "hrec" - * (history record) array elements with the ones we need to print. - * - * Logic: - * - Read the whole history file into a single buffer. - * - Walk through the buffer, parsing lines out of the buffer. - * 1. Split line into pointer and integer fields in the "next" hrec. - * 2. Apply tests to the hrec to see if it is wanted. - * 3. If it *is* wanted, bump the hrec pointer down by one. - */ -static void -read_hrecs (fname) - char *fname; -{ - char *cp, *cp2; - int i, fd; - struct hrec *hr; - struct stat st_buf; - - if ((fd = open (fname, O_RDONLY)) < 0) - error (1, errno, "cannot open history file: %s", fname); - - if (fstat (fd, &st_buf) < 0) - error (1, errno, "can't stat history file"); - - /* Exactly enough space for lines data */ - if (!(i = st_buf.st_size)) - error (1, 0, "history file is empty"); - cp = xmalloc (i + 2); - - if (read (fd, cp, i) != i) - error (1, errno, "cannot read log file"); - (void) close (fd); - - if (*(cp + i - 1) != '\n') - { - *(cp + i) = '\n'; /* Make sure last line ends in '\n' */ - i++; - } - *(cp + i) = '\0'; - for (cp2 = cp; cp2 - cp < i; cp2++) - { - if (*cp2 != '\n' && !isprint (*cp2)) - *cp2 = ' '; - } - - hrec_max = HREC_INCREMENT; - hrec_head = (struct hrec *) xmalloc (hrec_max * sizeof (struct hrec)); - - while (*cp) - { - if (hrec_count == hrec_max) - { - struct hrec *old_head = hrec_head; - - hrec_max += HREC_INCREMENT; - hrec_head = (struct hrec *) xrealloc ((char *) hrec_head, - hrec_max * sizeof (struct hrec)); - if (hrec_head != old_head) - { - if (last_since_tag) - last_since_tag = hrec_head + (last_since_tag - old_head); - if (last_backto) - last_backto = hrec_head + (last_backto - old_head); - } - } - - hr = hrec_head + hrec_count; - cp = fill_hrec (cp, hr); /* cp == next line or '\0' at end of buffer */ - - if (select_hrec (hr)) - hrec_count++; - } - - /* Special selection problem: If "since_tag" is set, we have saved every - * record from the 1st occurrence of "since_tag", when we want to save - * records since the *last* occurrence of "since_tag". So what we have - * to do is bump hrec_head forward and reduce hrec_count accordingly. - */ - if (last_since_tag) - { - hrec_count -= (last_since_tag - hrec_head); - hrec_head = last_since_tag; - } - - /* Much the same thing is necessary for the "backto" option. */ - if (last_backto) - { - hrec_count -= (last_backto - hrec_head); - hrec_head = last_backto; - } -} - -/* Utility program for determining whether "find" is inside "string" */ -static int -within (find, string) - char *find, *string; -{ - int c, len; - - if (!find || !string) - return (0); - - c = *find++; - len = strlen (find); - - while (*string) - { - if (!(string = strchr (string, c))) - return (0); - string++; - if (!strncmp (find, string, len)) - return (1); - } - return (0); -} - -/* The purpose of "select_hrec" is to apply the selection criteria based on - * the command arguments and defaults and return a flag indicating whether - * this record should be remembered for printing. - */ -static int -select_hrec (hr) - struct hrec *hr; -{ - char **cpp, *cp, *cp2; - struct file_list_str *fl; - int count; - - /* "Since" checking: The argument parser guarantees that only one of the - * following four choices is set: - * - * 1. If "since_date" is set, it contains a Unix time_t specified on the - * command line. hr->date fields earlier than "since_date" are ignored. - * 2. If "since_rev" is set, it contains either an RCS "dotted" revision - * number (which is of limited use) or a symbolic TAG. Each RCS file - * is examined and the date on the specified revision (or the revision - * corresponding to the TAG) in the RCS file (CVSROOT/repos/file) is - * compared against hr->date as in 1. above. - * 3. If "since_tag" is set, matching tag records are saved. The field - * "last_since_tag" is set to the last one of these. Since we don't - * know where the last one will be, all records are saved from the - * first occurrence of the TAG. Later, at the end of "select_hrec" - * records before the last occurrence of "since_tag" are skipped. - * 4. If "backto" is set, all records with a module name or file name - * matching "backto" are saved. In addition, all records with a - * repository field with a *prefix* matching "backto" are saved. - * The field "last_backto" is set to the last one of these. As in - * 3. above, "select_hrec" adjusts to include the last one later on. - */ - if (since_date) - { - if (hr->date < since_date) - return (0); - } - else if (*since_rev) - { - Vers_TS *vers; - time_t t; - - vers = Version_TS (hr->repos, (char *) NULL, since_rev, (char *) NULL, - hr->file, 1, 0, (List *) NULL, (List *) NULL); - if (vers->vn_rcs) - { - if ((t = RCS_getrevtime (vers->srcfile, vers->vn_rcs, (char *) 0, 0)) - != (time_t) 0) - { - if (hr->date < t) - { - freevers_ts (&vers); - return (0); - } - } - } - freevers_ts (&vers); - } - else if (*since_tag) - { - if (*(hr->type) == 'T') - { - /* - * A 'T'ag record, the "rev" field holds the tag to be set, - * while the "repos" field holds "D"elete, "A"dd or a rev. - */ - if (within (since_tag, hr->rev)) - { - last_since_tag = hr; - return (1); - } - else - return (0); - } - if (!last_since_tag) - return (0); - } - else if (*backto) - { - if (within (backto, hr->file) || within (backto, hr->mod) || - within (backto, hr->repos)) - last_backto = hr; - else - return (0); - } - - /* User checking: - * - * Run down "user_list", match username ("" matches anything) - * If "" is not there and actual username is not there, return failure. - */ - if (user_list && hr->user) - { - for (cpp = user_list, count = user_count; count; cpp++, count--) - { - if (!**cpp) - break; /* null user == accept */ - if (!strcmp (hr->user, *cpp)) /* found listed user */ - break; - } - if (!count) - return (0); /* Not this user */ - } - - /* Record type checking: - * - * 1. If Record type is not in rec_types field, skip it. - * 2. If mod_list is null, keep everything. Otherwise keep only modules - * on mod_list. - * 3. If neither a 'T', 'F' nor 'O' record, run through "file_list". If - * file_list is null, keep everything. Otherwise, keep only files on - * file_list, matched appropriately. - */ - if (!strchr (rec_types, *(hr->type))) - return (0); - if (!strchr ("TFO", *(hr->type))) /* Don't bother with "file" if "TFO" */ - { - if (file_list) /* If file_list is null, accept all */ - { - for (fl = file_list, count = file_count; count; fl++, count--) - { - /* 1. If file_list entry starts with '*', skip the '*' and - * compare it against the repository in the hrec. - * 2. If file_list entry has a '/' in it, compare it against - * the concatenation of the repository and file from hrec. - * 3. Else compare the file_list entry against the hrec file. - */ - char cmpfile[PATH_MAX]; - - if (*(cp = fl->l_file) == '*') - { - cp++; - /* if argument to -p is a prefix of repository */ - if (!strncmp (cp, hr->repos, strlen (cp))) - { - hr->mod = fl->l_module; - break; - } - } - else - { - if (strchr (cp, '/')) - { - (void) sprintf (cp2 = cmpfile, "%s/%s", - hr->repos, hr->file); - } - else - { - cp2 = hr->file; - } - - /* if requested file is found within {repos}/file fields */ - if (within (cp, cp2)) - { - hr->mod = fl->l_module; - break; - } - } - } - if (!count) - return (0); /* String specified and no match */ - } - } - if (mod_list) - { - for (cpp = mod_list, count = mod_count; count; cpp++, count--) - { - if (hr->mod && !strcmp (hr->mod, *cpp)) /* found module */ - break; - } - if (!count) - return (0); /* Module specified & this record is not one of them. */ - } - - return (1); /* Select this record unless rejected above. */ -} - -/* The "sort_order" routine (when handed to qsort) has arranged for the - * hrecs files to be in the right order for the report. - * - * Most of the "selections" are done in the select_hrec routine, but some - * selections are more easily done after the qsort by "accept_hrec". - */ -static void -report_hrecs () -{ - struct hrec *hr, *lr; - struct tm *tm; - int i, count, ty; - char *cp; - int user_len, file_len, rev_len, mod_len, repos_len; - - if (*since_tag && !last_since_tag) - { - (void) printf ("No tag found: %s\n", since_tag); - return; - } - else if (*backto && !last_backto) - { - (void) printf ("No module, file or repository with: %s\n", backto); - return; - } - else if (hrec_count < 1) - { - (void) printf ("No records selected.\n"); - return; - } - - user_len = file_len = rev_len = mod_len = repos_len = 0; - - /* Run through lists and find maximum field widths */ - hr = lr = hrec_head; - hr++; - for (count = hrec_count; count--; lr = hr, hr++) - { - char repos[PATH_MAX]; - - if (!count) - hr = NULL; - if (!accept_hrec (lr, hr)) - continue; - - ty = *(lr->type); - (void) strcpy (repos, lr->repos); - if ((cp = strrchr (repos, '/')) != NULL) - { - if (lr->mod && !strcmp (++cp, lr->mod)) - { - (void) strcpy (cp, "*"); - } - } - if ((i = strlen (lr->user)) > user_len) - user_len = i; - if ((i = strlen (lr->file)) > file_len) - file_len = i; - if (ty != 'T' && (i = strlen (repos)) > repos_len) - repos_len = i; - if (ty != 'T' && (i = strlen (lr->rev)) > rev_len) - rev_len = i; - if (lr->mod && (i = strlen (lr->mod)) > mod_len) - mod_len = i; - } - - /* Walk through hrec array setting "lr" (Last Record) to each element. - * "hr" points to the record following "lr" -- It is NULL in the last - * pass. - * - * There are two sections in the loop below: - * 1. Based on the report type (e.g. extract, checkout, tag, etc.), - * decide whether the record should be printed. - * 2. Based on the record type, format and print the data. - */ - for (lr = hrec_head, hr = (lr + 1); hrec_count--; lr = hr, hr++) - { - char workdir[PATH_MAX], repos[PATH_MAX]; - - if (!hrec_count) - hr = NULL; - if (!accept_hrec (lr, hr)) - continue; - - ty = *(lr->type); -#ifdef HAVE_RCS5 - if (!tz_local) - { - time_t t = lr->date + tz_seconds_east_of_GMT; - tm = gmtime (&t); - } - else -#endif - tm = localtime (&(lr->date)); - (void) printf ("%c %02d/%02d %02d:%02d %s %-*s", ty, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, tz_name, - user_len, lr->user); - - (void) sprintf (workdir, "%s%s", lr->dir, lr->end); - if ((cp = strrchr (workdir, '/')) != NULL) - { - if (lr->mod && !strcmp (++cp, lr->mod)) - { - (void) strcpy (cp, "*"); - } - } - (void) strcpy (repos, lr->repos); - if ((cp = strrchr (repos, '/')) != NULL) - { - if (lr->mod && !strcmp (++cp, lr->mod)) - { - (void) strcpy (cp, "*"); - } - } - - switch (ty) - { - case 'T': - /* 'T'ag records: repository is a "tag type", rev is the tag */ - (void) printf (" %-*s [%s:%s]", mod_len, lr->mod, lr->rev, - repos); - if (working) - (void) printf (" {%s}", workdir); - break; - case 'F': - case 'O': - if (lr->rev && *(lr->rev)) - (void) printf (" [%s]", lr->rev); - (void) printf (" %-*s =%s%-*s %s", repos_len, repos, lr->mod, - mod_len + 1 - strlen (lr->mod), "=", workdir); - break; - case 'W': - case 'U': - case 'C': - case 'G': - case 'M': - case 'A': - case 'R': - (void) printf (" %-*s %-*s %-*s =%s= %s", rev_len, lr->rev, - file_len, lr->file, repos_len, repos, - lr->mod ? lr->mod : "", workdir); - break; - default: - (void) printf ("Hey! What is this junk? RecType[0x%2.2x]", ty); - break; - } - (void) putchar ('\n'); - } -} - -static int -accept_hrec (lr, hr) - struct hrec *hr, *lr; -{ - int ty; - - ty = *(lr->type); - - if (last_since_tag && ty == 'T') - return (1); - - if (v_checkout) - { - if (ty != 'O') - return (0); /* Only interested in 'O' records */ - - /* We want to identify all the states that cause the next record - * ("hr") to be different from the current one ("lr") and only - * print a line at the allowed boundaries. - */ - - if (!hr || /* The last record */ - strcmp (hr->user, lr->user) || /* User has changed */ - strcmp (hr->mod, lr->mod) ||/* Module has changed */ - (working && /* If must match "workdir" */ - (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */ - strcmp (hr->end, lr->end)))) /* the 2nd parts differ */ - - return (1); - } - else if (modified) - { - if (!last_entry || /* Don't want only last rec */ - !hr || /* Last entry is a "last entry" */ - strcmp (hr->repos, lr->repos) || /* Repository has changed */ - strcmp (hr->file, lr->file))/* File has changed */ - return (1); - - if (working) - { /* If must match "workdir" */ - if (strcmp (hr->dir, lr->dir) || /* and the 1st parts or */ - strcmp (hr->end, lr->end)) /* the 2nd parts differ */ - return (1); - } - } - else if (module_report) - { - if (!last_entry || /* Don't want only last rec */ - !hr || /* Last entry is a "last entry" */ - strcmp (hr->mod, lr->mod) ||/* Module has changed */ - strcmp (hr->repos, lr->repos) || /* Repository has changed */ - strcmp (hr->file, lr->file))/* File has changed */ - return (1); - } - else - { - /* "extract" and "tag_report" always print selected records. */ - return (1); - } - - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/ignore.c b/gnu/usr.bin/cvs/cvs/ignore.c deleted file mode 100644 index f70fe78..0000000 --- a/gnu/usr.bin/cvs/cvs/ignore.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com> - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)ignore.c 1.16 94/09/24 $"; -USE(rcsid); -#endif - -/* - * Ignore file section. - * - * "!" may be included any time to reset the list (i.e. ignore nothing); - * "*" may be specified to ignore everything. It stays as the first - * element forever, unless a "!" clears it out. - */ - -static char **ign_list; /* List of files to ignore in update - * and import */ -static char **s_ign_list = NULL; -static int ign_count; /* Number of active entries */ -static int s_ign_count = 0; -static int ign_size; /* This many slots available (plus - * one for a NULL) */ -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"; - -#define IGN_GROW 16 /* grow the list by 16 elements at a - * time */ - -/* - * To the "ignore list", add the hard-coded default ignored wildcards above, - * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in - * ~/.cvsignore and the wildcards found in the CVSIGNORE environment - * variable. - */ -void -ign_setup () -{ - struct passwd *pw; - char file[PATH_MAX]; - char *tmp; - - /* Start with default list and special case */ - tmp = xstrdup (ign_default); - ign_add (tmp, 0); - free (tmp); - -#ifdef CLIENT_SUPPORT - /* Chances are we should have some way to provide this feature - client/server, but I'm not sure how (surely not by introducing - another network turnaround to each operation--perhaps by - putting a file in the CVS directory on checkout, or with some - sort of "slave cvsroot" on the client). */ - 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) - { - (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTIGNORE); - ign_add_file (file, 0); - } - - /* Then add entries found in CVSIGNORE environment variable. */ - ign_add (getenv (IGNORE_ENV), 0); - - /* Later, add ignore entries found in -I arguments */ -} - -/* - * Open a file and read lines, feeding each line to a line parser. Arrange - * for keeping a temporary list of wildcards at the end, if the "hold" - * argument is set. - */ -void -ign_add_file (file, hold) - char *file; - int hold; -{ - FILE *fp; - char line[1024]; - - /* restore the saved list (if any) */ - if (s_ign_list != NULL) - { - int i; - - for (i = 0; i < s_ign_count; i++) - ign_list[i] = s_ign_list[i]; - ign_count = s_ign_count; - ign_list[ign_count] = NULL; - - s_ign_count = 0; - free (s_ign_list); - s_ign_list = NULL; - } - - /* is this a temporary ignore file? */ - if (hold) - { - /* re-set if we had already done a temporary file */ - if (ign_hold) - { - int i; - - for (i = ign_hold; i < ign_count; i++) - free (ign_list[i]); - ign_count = ign_hold; - ign_list[ign_count] = NULL; - } - else - { - ign_hold = ign_count; - } - } - - /* load the file */ - fp = fopen (file, "r"); - if (fp == NULL) - { - if (! existence_error (errno)) - error (0, errno, "cannot open %s", file); - return; - } - while (fgets (line, sizeof (line), fp)) - ign_add (line, hold); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", file); -} - -/* Parse a line of space-separated wildcards and add them to the list. */ -void -ign_add (ign, hold) - char *ign; - int hold; -{ - if (!ign || !*ign) - return; - - for (; *ign; ign++) - { - char *mark; - char save; - - /* ignore whitespace before the token */ - if (isspace (*ign)) - continue; - - /* - * if we find a single character !, we must re-set the ignore list - * (saving it if necessary). We also catch * as a special case in a - * global ignore file as an optimization - */ - if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*')) - { - if (!hold) - { - /* permanently reset the ignore list */ - int i; - - for (i = 0; i < ign_count; i++) - free (ign_list[i]); - ign_count = 0; - ign_list[0] = NULL; - - /* if we are doing a '!', continue; otherwise add the '*' */ - if (*ign == '!') - continue; - } - else if (*ign == '!') - { - /* temporarily reset the ignore list */ - int i; - - if (ign_hold) - { - for (i = ign_hold; i < ign_count; i++) - free (ign_list[i]); - ign_hold = 0; - } - s_ign_list = (char **) xmalloc (ign_count * sizeof (char *)); - for (i = 0; i < ign_count; i++) - s_ign_list[i] = ign_list[i]; - s_ign_count = ign_count; - ign_count = 0; - ign_list[0] = NULL; - continue; - } - } - - /* If we have used up all the space, add some more */ - if (ign_count >= ign_size) - { - ign_size += IGN_GROW; - ign_list = (char **) xrealloc ((char *) ign_list, - (ign_size + 1) * sizeof (char *)); - } - - /* find the end of this token */ - for (mark = ign; *mark && !isspace (*mark); mark++) - /* do nothing */ ; - - save = *mark; - *mark = '\0'; - - ign_list[ign_count++] = xstrdup (ign); - ign_list[ign_count] = NULL; - - *mark = save; - if (save) - ign = mark; - else - ign = mark - 1; - } -} - -/* Return 1 if the given filename should be ignored by update or import. */ -int -ign_name (name) - char *name; -{ - char **cpp = ign_list; - - if (cpp == NULL) - return (0); - - while (*cpp) - if (fnmatch (*cpp++, name, 0) == 0) - return (1); - return (0); -} - - -static char **dir_ign_list = NULL; -static int dir_ign_max = 0; -static int dir_ign_current = 0; - -/* add a directory to list of dirs to ignore */ -void ign_dir_add (name) - char *name; -{ - /* make sure we've got the space for the entry */ - if (dir_ign_current <= dir_ign_max) - { - dir_ign_max += IGN_GROW; - dir_ign_list = (char **) xrealloc ((char *) dir_ign_list, (dir_ign_max+1) * sizeof(char*)); - } - - dir_ign_list[dir_ign_current] = name; - - dir_ign_current += 1 ; -} - - -/* this function returns 1 (true) if the given directory name is part of - * the list of directories to ignore - */ - -int ignore_directory (name) - char *name; -{ - int i; - - if (!dir_ign_list) - return 0; - - i = dir_ign_current; - while (i--) - { - if (strncmp(name, dir_ign_list[i], strlen(dir_ign_list[i])) == 0) - return 1; - } - - return 0; -} diff --git a/gnu/usr.bin/cvs/cvs/import.c b/gnu/usr.bin/cvs/cvs/import.c deleted file mode 100644 index 187f109..0000000 --- a/gnu/usr.bin/cvs/cvs/import.c +++ /dev/null @@ -1,1188 +0,0 @@ -/* - * 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. - * - * "import" checks in the vendor release located in the current directory into - * the CVS source repository. The CVS vendor branch support is utilized. - * - * At least three arguments are expected to follow the options: - * repository Where the source belongs relative to the CVSROOT - * VendorTag Vendor's major tag - * VendorReleTag Tag for this particular release - * - * Additional arguments specify more Vendor Release Tags. - */ - -#include "cvs.h" -#include "save-cwd.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)import.c 1.63 94/09/30 $"; -USE(rcsid); -#endif - -#define FILE_HOLDER ".#cvsxxx" - -static char *get_comment PROTO((char *user)); -static int add_rcs_file PROTO((char *message, char *rcs, char *user, char *vtag, - int targc, char *targv[])); -static int expand_at_signs PROTO((char *buf, off_t size, FILE *fp)); -static int add_rev PROTO((char *message, char *rcs, char *vfile, char *vers)); -static int add_tags PROTO((char *rcs, char *vfile, char *vtag, int targc, - char *targv[])); -static int import_descend PROTO((char *message, char *vtag, int targc, char *targv[])); -static int import_descend_dir PROTO((char *message, char *dir, char *vtag, - int targc, char *targv[])); -static int process_import_file PROTO((char *message, char *vfile, char *vtag, - int targc, char *targv[])); -static int update_rcs_file PROTO((char *message, char *vfile, char *vtag, int targc, - char *targv[], int inattic)); -static void add_log PROTO((int ch, char *fname)); - -static int repos_len; -static char vhead[50]; -static char vbranch[50]; -static FILE *logfp; -static char repository[PATH_MAX]; -static int conflicts; -static int use_file_modtime; -static char *keyword_opt = NULL; - -static const char *const import_usage[] = -{ - "Usage: %s %s [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n", - " [-W spec] repository vendor-tag release-tags...\n", - "\t-d\tUse the file's modification time as the time of import.\n", - "\t-k sub\tSet default RCS keyword substitution mode.\n", - "\t-I ign\tMore files to ignore (! to reset).\n", - "\t-b bra\tVendor branch id.\n", - "\t-m msg\tLog message.\n", - "\t-W spec\tWrappers specification line.\n", - NULL -}; - -int -import (argc, argv) - int argc; - char **argv; -{ - char *message = NULL; - char tmpfile[L_tmpnam+1]; - char *cp; - int i, c, msglen, err; - List *ulist; - Node *p; - - if (argc == -1) - usage (import_usage); - - ign_setup (); - wrap_setup (); - - (void) strcpy (vbranch, CVSBRANCH); - optind = 1; - while ((c = getopt (argc, argv, "Qqdb:m:I:k:W:")) != -1) - { - switch (c) - { - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'd': - use_file_modtime = 1; - break; - case 'b': - (void) strcpy (vbranch, optarg); - break; - case 'm': -#ifdef FORCE_USE_EDITOR - use_editor = TRUE; -#else - use_editor = FALSE; -#endif - message = xstrdup(optarg); - break; - case 'I': - ign_add (optarg, 0); - break; - case 'k': - /* RCS_check_kflag returns strings of the form -kxx. We - only use it for validation, so we can free the value - as soon as it is returned. */ - free (RCS_check_kflag(optarg)); - keyword_opt = optarg; - break; - case 'W': - wrap_add (optarg, 0); - break; - case '?': - default: - usage (import_usage); - break; - } - } - argc -= optind; - argv += optind; - if (argc < 3) - usage (import_usage); - - for (i = 1; i < argc; i++) /* check the tags for validity */ - { - int j; - - RCS_check_tag (argv[i]); - for (j = 1; j < i; j++) - if (strcmp (argv[j], argv[i]) == 0) - error (1, 0, "tag `%s' was specified more than once", argv[i]); - } - - /* XXX - this should be a module, not just a pathname */ - if (! isabsolute (argv[0])) - { - if (CVSroot == NULL) - { - error (0, 0, "missing CVSROOT environment variable\n"); - error (1, 0, "Set it or specify the '-d' option to %s.", - program_name); - } - (void) sprintf (repository, "%s/%s", CVSroot, argv[0]); - repos_len = strlen (CVSroot); - } - else - { - (void) strcpy (repository, argv[0]); - repos_len = 0; - } - - /* - * Consistency checks on the specified vendor branch. It must be - * composed of only numbers and dots ('.'). Also, for now we only - * support branching to a single level, so the specified vendor branch - * must only have two dots in it (like "1.1.1"). - */ - for (cp = vbranch; *cp != '\0'; cp++) - if (!isdigit (*cp) && *cp != '.') - error (1, 0, "%s is not a numeric branch", vbranch); - if (numdots (vbranch) != 2) - error (1, 0, "Only branches with two dots are supported: %s", vbranch); - (void) strcpy (vhead, vbranch); - cp = strrchr (vhead, '.'); - *cp = '\0'; - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* Do this now; don't ask for a log message if we can't talk to the - server. But if there is a syntax error in the options, give - an error message without connecting. */ - start_server (); - } -#endif - - if (use_editor) - { - do_editor ((char *) NULL, &message, repository, - (List *) NULL); - } - - msglen = message == NULL ? 0 : strlen (message); - if (msglen == 0 || message[msglen - 1] != '\n') - { - char *nm = xmalloc (msglen + 2); - if (message != NULL) - { - (void) strcpy (nm, message); - free (message); - } - (void) strcat (nm + msglen, "\n"); - message = nm; - } - -#ifdef CLIENT_SUPPORT - if (client_active) - { - int err; - - ign_setup (); - - if (use_file_modtime) - send_arg("-d"); - - if (vbranch[0] != '\0') - option_with_arg ("-b", vbranch); - if (message) - option_with_arg ("-m", message); - if (keyword_opt != NULL) - option_with_arg ("-k", keyword_opt); - - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - } - - logfp = stdin; - 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"); - err += get_responses_and_close (); - return err; - } -#endif - - /* - * Make all newly created directories writable. Should really use a more - * sophisticated security mechanism here. - */ - (void) umask (cvsumask); - make_directories (repository); - - /* 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"); - for (i = 2; i < argc; i++) - (void) fprintf (logfp, "%s\n\t\t", argv[i]); - (void) fprintf (logfp, "\n"); - - /* Just Do It. */ - err = import_descend (message, argv[1], argc - 2, argv + 2); - if (conflicts) - { - if (!really_quiet) - { - (void) printf ("\n%d conflicts created by this import.\n", - conflicts); - (void) printf ("Use the following command to help the merge:\n\n"); - (void) printf ("\t%s checkout -j%s:yesterday -j%s %s\n\n", - program_name, argv[1], argv[1], argv[0]); - } - - (void) fprintf (logfp, "\n%d conflicts created by this import.\n", - conflicts); - (void) fprintf (logfp, - "Use the following command to help the merge:\n\n"); - (void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n", - program_name, argv[1], argv[1], argv[0]); - } - else - { - if (!really_quiet) - (void) printf ("\nNo conflicts created by this import\n\n"); - (void) fprintf (logfp, "\nNo conflicts created by this import\n\n"); - } - - /* - * Write out the logfile and clean up. - */ - ulist = getlist (); - p = getnode (); - p->type = UPDATE; - p->delproc = update_delproc; - p->key = xstrdup ("- Imported sources"); - p->data = (char *) T_TITLE; - (void) addnode (ulist, p); - Update_Logfile (repository, message, vbranch, logfp, ulist); - dellist (&ulist); - (void) fclose (logfp); - - /* 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) - free (message); - - return (err); -} - -/* - * process all the files in ".", then descend into other directories. - */ -static int -import_descend (message, vtag, targc, targv) - char *message; - char *vtag; - int targc; - char *targv[]; -{ - DIR *dirp; - struct dirent *dp; - int err = 0; - List *dirlist = NULL; - - /* first, load up any per-directory ignore lists */ - ign_add_file (CVSDOTIGNORE, 1); - wrap_add_file (CVSDOTWRAPPER, 1); - - if ((dirp = opendir (".")) == NULL) - { - err++; - } - else - { - while ((dp = readdir (dirp)) != NULL) - { - 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; -#endif - add_log ('I', dp->d_name); - continue; - } - - if ( -#ifdef DT_DIR - (dp->d_type == DT_DIR - || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name))) -#else - isdir (dp->d_name) -#endif - && !wrap_name_has (dp->d_name, WRAP_TOCVS) - ) - { - Node *n; - - if (dirlist == NULL) - dirlist = getlist(); - - n = getnode(); - n->key = xstrdup (dp->d_name); - addnode(dirlist, n); - } - else if ( -#ifdef DT_DIR - dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && -#endif - islink (dp->d_name)) - { - add_log ('L', dp->d_name); - err++; - } - else - { -#ifdef CLIENT_SUPPORT - if (client_active) - err += client_process_import_file (message, dp->d_name, - vtag, targc, targv, - repository); - else -#endif - err += process_import_file (message, dp->d_name, - vtag, targc, targv); - } - } - (void) closedir (dirp); - } - - if (dirlist != NULL) - { - Node *head, *p; - - head = dirlist->list; - for (p = head->next; p != head; p = p->next) - { - err += import_descend_dir (message, p->key, vtag, targc, targv); - } - - dellist(&dirlist); - } - - return (err); -} - -/* - * Process the argument import file. - */ -static int -process_import_file (message, vfile, vtag, targc, targv) - char *message; - char *vfile; - char *vtag; - int targc; - char *targv[]; -{ - char attic_name[PATH_MAX]; - char rcs[PATH_MAX]; - int inattic = 0; - - (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT); - if (!isfile (rcs)) - { - (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC, - vfile, RCSEXT); - if (!isfile (attic_name)) - { - - /* - * A new import source file; it doesn't exist as a ,v within the - * repository nor in the Attic -- create it anew. - */ - add_log ('N', vfile); - return (add_rcs_file (message, rcs, vfile, vtag, targc, targv)); - } - inattic = 1; - } - - /* - * an rcs file exists. have to do things the official, slow, way. - */ - return (update_rcs_file (message, vfile, vtag, targc, targv, inattic)); -} - -/* - * The RCS file exists; update it by adding the new import file to the - * (possibly already existing) vendor branch. - */ -static int -update_rcs_file (message, vfile, vtag, targc, targv, inattic) - char *message; - char *vfile; - char *vtag; - int targc; - char *targv[]; - int inattic; -{ - Vers_TS *vers; - int letter; - int ierrno; - char *tmpdir; - char *tocvsPath; - - vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile, - 1, 0, (List *) NULL, (List *) NULL); -#ifdef DEATH_SUPPORT - if (vers->vn_rcs != NULL - && !RCS_isdead(vers->srcfile, vers->vn_rcs)) -#else - if (vers->vn_rcs != NULL) -#endif - { - char xtmpfile[PATH_MAX]; - int different; - int retcode = 0; - - tmpdir = getenv ("TMPDIR"); - if (tmpdir == NULL || tmpdir[0] == '\0') - tmpdir = "/tmp"; - - (void) sprintf (xtmpfile, "%s/cvs-imp%d", tmpdir, getpid()); - - /* - * The rcs file does have a revision on the vendor branch. Compare - * this revision with the import file; if they match exactly, there - * is no need to install the new import file as a new revision to the - * branch. Just tag the revision with the new import tags. - * - * This is to try to cut down the number of "C" conflict messages for - * locally modified import source files. - */ -#ifdef HAVE_RCS5 - run_setup ("%s%s -q -f -r%s -p -ko", Rcsbin, RCS_CO, vers->vn_rcs); -#else - run_setup ("%s%s -q -f -r%s -p", Rcsbin, RCS_CO, vers->vn_rcs); -#endif - run_arg (vers->srcfile->path); - if ((retcode = run_exec (RUN_TTY, xtmpfile, RUN_TTY, - RUN_NORMAL|RUN_REALLY)) != 0) - { - ierrno = errno; - fperror (logfp, 0, retcode == -1 ? ierrno : 0, - "ERROR: cannot co revision %s of file %s", vers->vn_rcs, - vers->srcfile->path); - error (0, retcode == -1 ? ierrno : 0, - "ERROR: cannot co revision %s of file %s", vers->vn_rcs, - vers->srcfile->path); - (void) unlink_file (xtmpfile); - return (1); - } - - tocvsPath = wrap_tocvs_process_file (vfile); - different = xcmp (xtmpfile, vfile); - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - (void) unlink_file (xtmpfile); - if (!different) - { - int retval = 0; - - /* - * The two files are identical. Just update the tags, print the - * "U", signifying that the file has changed, but needs no - * attention, and we're done. - */ - if (add_tags (vers->srcfile->path, vfile, vtag, targc, targv)) - retval = 1; - add_log ('U', vfile); - freevers_ts (&vers); - return (retval); - } - } - - /* We may have failed to parse the RCS file; check just in case */ - if (vers->srcfile == NULL || - add_rev (message, vers->srcfile->path, vfile, vers->vn_rcs) || - add_tags (vers->srcfile->path, vfile, vtag, targc, targv)) - { - freevers_ts (&vers); - return (1); - } - - if (vers->srcfile->branch == NULL || inattic || - strcmp (vers->srcfile->branch, vbranch) != 0) - { - conflicts++; - letter = 'C'; - } - else - letter = 'U'; - add_log (letter, vfile); - - freevers_ts (&vers); - return (0); -} - -/* - * Add the revision to the vendor branch - */ -static int -add_rev (message, rcs, vfile, vers) - char *message; - char *rcs; - char *vfile; - char *vers; -{ - int locked, status, ierrno; - char *tocvsPath; - struct stat vfile_stat; - - if (noexec) - return (0); - - locked = 0; - if (vers != NULL) - { - /* Before RCS_lock existed, we were directing stdout, as well as - stderr, from the RCS command, to DEVNULL. I wouldn't guess that - was necessary, but I don't know for sure. */ - if (RCS_lock (rcs, vbranch, 1) != 0) - { - error (0, errno, "fork failed"); - return (1); - } - locked = 1; - } - tocvsPath = wrap_tocvs_process_file (vfile); - - /* 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_args ("-m%s", make_message_rcslegal (message)); - if (use_file_modtime) - run_arg ("-d"); - run_arg (tocvsPath == NULL ? vfile : tocvsPath); - run_arg (rcs); - 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 (status) - { - if (!noexec) - { - fperror (logfp, 0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs); - error (0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs); - } - if (locked) - { - (void) RCS_unlock(rcs, vbranch, 0); - } - return (1); - } - return (0); -} - -/* - * Add the vendor branch tag and all the specified import release tags to the - * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the - * vendor release tags go on the newly added leaf of the branch (1.1.1.1, - * 1.1.1.2, ...). - */ -static int -add_tags (rcs, vfile, vtag, targc, targv) - char *rcs; - char *vfile; - char *vtag; - int targc; - char *targv[]; -{ - int i, ierrno; - Vers_TS *vers; - int retcode = 0; - - if (noexec) - return (0); - - if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0) - { - ierrno = errno; - fperror (logfp, 0, retcode == -1 ? ierrno : 0, - "ERROR: Failed to set tag %s in %s", vtag, rcs); - error (0, retcode == -1 ? ierrno : 0, - "ERROR: Failed to set tag %s in %s", vtag, rcs); - return (1); - } - vers = Version_TS (repository, (char *) NULL, vtag, (char *) NULL, vfile, - 1, 0, (List *) NULL, (List *) NULL); - for (i = 0; i < targc; i++) - { - if ((retcode = RCS_settag (rcs, targv[i], vers->vn_rcs)) != 0) - { - ierrno = errno; - fperror (logfp, 0, retcode == -1 ? ierrno : 0, - "WARNING: Couldn't add tag %s to %s", targv[i], rcs); - error (0, retcode == -1 ? ierrno : 0, - "WARNING: Couldn't add tag %s to %s", targv[i], rcs); - } - } - freevers_ts (&vers); - return (0); -} - -/* - * Stolen from rcs/src/rcsfnms.c, and adapted/extended. - */ -struct compair -{ - char *suffix, *comlead; -}; - -static const struct compair comtable[] = -{ - -/* - * comtable pairs each filename suffix with a comment leader. The comment - * leader is placed before each line generated by the $Log keyword. This - * table is used to guess the proper comment leader from the working file's - * suffix during initial ci (see InitAdmin()). Comment leaders are needed for - * languages without multiline comments; for others they are optional. - */ - {"a", "-- "}, /* Ada */ - {"ada", "-- "}, - {"adb", "-- "}, - {"asm", ";; "}, /* assembler (MS-DOS) */ - {"ads", "-- "}, /* Ada */ - {"bat", ":: "}, /* batch (MS-DOS) */ - {"body", "-- "}, /* Ada */ - {"c", " * "}, /* C */ - {"c++", "// "}, /* C++ in all its infinite guises */ - {"cc", "// "}, - {"cpp", "// "}, - {"cxx", "// "}, - {"m", "// "}, /* Objective-C */ - {"cl", ";;; "}, /* Common Lisp */ - {"cmd", ":: "}, /* command (OS/2) */ - {"cmf", "c "}, /* CM Fortran */ - {"cs", " * "}, /* C* */ - {"csh", "# "}, /* shell */ - {"e", "# "}, /* efl */ - {"epsf", "% "}, /* encapsulated postscript */ - {"epsi", "% "}, /* encapsulated postscript */ - {"el", "; "}, /* Emacs Lisp */ - {"f", "c "}, /* Fortran */ - {"for", "c "}, - {"h", " * "}, /* C-header */ - {"hh", "// "}, /* C++ header */ - {"hpp", "// "}, - {"hxx", "// "}, - {"in", "# "}, /* for Makefile.in */ - {"l", " * "}, /* lex (conflict between lex and - * franzlisp) */ - {"mac", ";; "}, /* macro (DEC-10, MS-DOS, PDP-11, - * VMS, etc) */ - {"me", ".\\\" "}, /* me-macros t/nroff */ - {"ml", "; "}, /* mocklisp */ - {"mm", ".\\\" "}, /* mm-macros t/nroff */ - {"ms", ".\\\" "}, /* ms-macros t/nroff */ - {"man", ".\\\" "}, /* man-macros t/nroff */ - {"1", ".\\\" "}, /* feeble attempt at man pages... */ - {"2", ".\\\" "}, - {"3", ".\\\" "}, - {"4", ".\\\" "}, - {"5", ".\\\" "}, - {"6", ".\\\" "}, - {"7", ".\\\" "}, - {"8", ".\\\" "}, - {"9", ".\\\" "}, - {"p", " * "}, /* pascal */ - {"pas", " * "}, - {"pl", "# "}, /* perl (conflict with Prolog) */ - {"ps", "% "}, /* postscript */ - {"psw", "% "}, /* postscript wrap */ - {"pswm", "% "}, /* postscript wrap */ - {"r", "# "}, /* ratfor */ - {"red", "% "}, /* psl/rlisp */ -#ifdef sparc - {"s", "! "}, /* assembler */ -#endif -#ifdef mc68000 - {"s", "| "}, /* assembler */ -#endif -#ifdef pdp11 - {"s", "/ "}, /* assembler */ -#endif -#ifdef vax - {"s", "# "}, /* assembler */ -#endif -#ifdef __ksr__ - {"s", "# "}, /* assembler */ - {"S", "# "}, /* Macro assembler */ -#endif - {"sh", "# "}, /* shell */ - {"sl", "% "}, /* psl */ - {"spec", "-- "}, /* Ada */ - {"tex", "% "}, /* tex */ - {"y", " * "}, /* yacc */ - {"ye", " * "}, /* yacc-efl */ - {"yr", " * "}, /* yacc-ratfor */ -#ifdef SYSTEM_COMMENT_TABLE - SYSTEM_COMMENT_TABLE -#endif - {"", "# "}, /* default for empty suffix */ - {NULL, "# "} /* default for unknown suffix; */ -/* must always be last */ -}; - -static char * -get_comment (user) - char *user; -{ - char *cp, *suffix; - char suffix_path[PATH_MAX]; - int i; - - cp = strrchr (user, '.'); - if (cp != NULL) - { - cp++; - - /* - * Convert to lower-case, since we are not concerned about the - * case-ness of the suffix. - */ - (void) strcpy (suffix_path, cp); - for (cp = suffix_path; *cp; cp++) - if (isupper (*cp)) - *cp = tolower (*cp); - suffix = suffix_path; - } - else - suffix = ""; /* will use the default */ - for (i = 0;; i++) - { - if (comtable[i].suffix == NULL) /* default */ - return (comtable[i].comlead); - if (strcmp (suffix, comtable[i].suffix) == 0) - return (comtable[i].comlead); - } -} - -static int -add_rcs_file (message, rcs, user, vtag, targc, targv) - char *message; - char *rcs; - char *user; - char *vtag; - int targc; - char *targv[]; -{ - FILE *fprcs, *fpuser; - struct stat sb; - struct tm *ftm; - time_t now; - char altdate1[50]; -#ifndef HAVE_RCS5 - char altdate2[50]; -#endif - char *author, *buf; - int i, ierrno, err = 0; - mode_t mode; - char *tocvsPath; - char *userfile; - - if (noexec) - return (0); - -#ifdef LINES_CRLF_TERMINATED - /* There exits a port of RCS to such a system that stores files with - straight newlines. If we ever reach this point on such a system, - we'll need to decide what to do with the open_file call below. */ - abort (); -#endif - tocvsPath = wrap_tocvs_process_file (user); - userfile = (tocvsPath == NULL ? user : tocvsPath); - fpuser = fopen (userfile, "r"); - if (fpuser == NULL) { - /* not fatal, continue import */ - fperror (logfp, 0, errno, "ERROR: cannot read file %s", userfile); - error (0, errno, "ERROR: cannot read file %s", userfile); - goto read_error; - } - fprcs = fopen (rcs, "w+"); - if (fprcs == NULL) { - ierrno = errno; - goto write_error_noclose; - } - - /* - * putadmin() - */ - if (fprintf (fprcs, "head %s;\n", vhead) < 0 || - fprintf (fprcs, "branch %s;\n", vbranch) < 0 || - fprintf (fprcs, "access ;\n") < 0 || - fprintf (fprcs, "symbols ") < 0) - { - goto write_error; - } - - for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */ - if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) < 0) - goto write_error; - - if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) < 0 || - fprintf (fprcs, "locks ; strict;\n") < 0 || - /* XXX - make sure @@ processing works in the RCS file */ - fprintf (fprcs, "comment @%s@;\n", get_comment (user)) < 0) - { - goto write_error; - } - - if (keyword_opt != NULL) - if (fprintf (fprcs, "expand @%s@;\n", keyword_opt) < 0) - { - goto write_error; - } - - if (fprintf (fprcs, "\n") < 0) - goto write_error; - - /* - * puttree() - */ - if (fstat (fileno (fpuser), &sb) < 0) - error (1, errno, "cannot fstat %s", user); - if (use_file_modtime) - now = sb.st_mtime; - else - (void) time (&now); -#ifdef HAVE_RCS5 - ftm = gmtime (&now); -#else - ftm = localtime (&now); -#endif - (void) sprintf (altdate1, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); -#ifdef HAVE_RCS5 -#define altdate2 altdate1 -#else - /* - * If you don't have RCS V5 or later, you need to lie about the ci - * time, since RCS V4 and earlier insist that the times differ. - */ - now++; - ftm = localtime (&now); - (void) sprintf (altdate2, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); -#endif - author = getcaller (); - - if (fprintf (fprcs, "\n%s\n", vhead) < 0 || - fprintf (fprcs, "date %s; author %s; state Exp;\n", - altdate1, author) < 0 || - fprintf (fprcs, "branches %s.1;\n", vbranch) < 0 || - fprintf (fprcs, "next ;\n") < 0 || - fprintf (fprcs, "\n%s.1\n", vbranch) < 0 || - fprintf (fprcs, "date %s; author %s; state Exp;\n", - altdate2, author) < 0 || - fprintf (fprcs, "branches ;\n") < 0 || - fprintf (fprcs, "next ;\n\n") < 0 || - /* - * putdesc() - */ - fprintf (fprcs, "\ndesc\n") < 0 || - fprintf (fprcs, "@@\n\n\n") < 0 || - /* - * putdelta() - */ - fprintf (fprcs, "\n%s\n", vhead) < 0 || - fprintf (fprcs, "log\n") < 0 || - fprintf (fprcs, "@Initial revision\n@\n") < 0 || - fprintf (fprcs, "text\n@") < 0) - { - goto write_error; - } - - if (sb.st_size > 0) - { - off_t size; - - size = sb.st_size; - buf = xmalloc ((int) size); - if (fread (buf, (int) size, 1, fpuser) != 1) - error (1, errno, "cannot read file %s for copying", user); - if (expand_at_signs (buf, size, fprcs) < 0) - { - free (buf); - goto write_error; - } - free (buf); - } - if (fprintf (fprcs, "@\n\n") < 0 || - fprintf (fprcs, "\n%s.1\n", vbranch) < 0 || - fprintf (fprcs, "log\n@") < 0 || - expand_at_signs (message, (off_t) strlen (message), fprcs) < 0 || - fprintf (fprcs, "@\ntext\n") < 0 || - fprintf (fprcs, "@@\n") < 0) - { - goto write_error; - } - if (fclose (fprcs) == EOF) - { - ierrno = errno; - goto write_error_noclose; - } - (void) fclose (fpuser); - - /* - * 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 | - (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; - fperror (logfp, 0, ierrno, - "WARNING: cannot change mode of file %s", rcs); - error (0, ierrno, "WARNING: cannot change mode of file %s", rcs); - err++; - } - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - return (err); - -write_error: - ierrno = errno; - (void) fclose (fprcs); -write_error_noclose: - (void) fclose (fpuser); - fperror (logfp, 0, ierrno, "ERROR: cannot write file %s", rcs); - error (0, ierrno, "ERROR: cannot write file %s", rcs); - if (ierrno == ENOSPC) - { - (void) unlink (rcs); - fperror (logfp, 0, 0, "ERROR: out of space - aborting"); - error (1, 0, "ERROR: out of space - aborting"); - } -read_error: - if (tocvsPath) - if (unlink_file_dir (tocvsPath) < 0) - error (0, errno, "cannot remove %s", tocvsPath); - - return (err + 1); -} - -/* - * Write SIZE bytes at BUF to FP, expanding @ signs into double @ - * signs. If an error occurs, return a negative value and set errno - * to indicate the error. If not, return a nonnegative value. - */ -static int -expand_at_signs (buf, size, fp) - char *buf; - off_t size; - FILE *fp; -{ - char *cp, *end; - - errno = 0; - for (cp = buf, end = buf + size; cp < end; cp++) - { - if (*cp == '@') - { - if (putc ('@', fp) == EOF && errno != 0) - return EOF; - } - if (putc (*cp, fp) == EOF && errno != 0) - return (EOF); - } - return (1); -} - -/* - * Write an update message to (potentially) the screen and the log file. - */ -static void -add_log (ch, fname) - int ch; - char *fname; -{ - if (!really_quiet) /* write to terminal */ - { - if (repos_len) - (void) printf ("%c %s/%s\n", ch, repository + repos_len + 1, fname); - else if (repository[0]) - (void) printf ("%c %s/%s\n", ch, repository, fname); - else - (void) printf ("%c %s\n", ch, fname); - } - - if (repos_len) /* write to logfile */ - (void) fprintf (logfp, "%c %s/%s\n", ch, - repository + repos_len + 1, fname); - else if (repository[0]) - (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname); - else - (void) fprintf (logfp, "%c %s\n", ch, fname); -} - -/* - * This is the recursive function that walks the argument directory looking - * for sub-directories that have CVS administration files in them and updates - * them recursively. - * - * Note that we do not follow symbolic links here, which is a feature! - */ -static int -import_descend_dir (message, dir, vtag, targc, targv) - char *message; - char *dir; - char *vtag; - int targc; - char *targv[]; -{ - struct saved_cwd cwd; - char *cp; - int ierrno, err; - - if (islink (dir)) - return (0); - if (save_cwd (&cwd)) - { - fperror (logfp, 0, 0, "ERROR: cannot get working directory"); - return (1); - } - if (repository[0] == '\0') - (void) strcpy (repository, dir); - else - { - (void) strcat (repository, "/"); - (void) strcat (repository, dir); - } -#ifdef CLIENT_SUPPORT - if (!quiet && !client_active) -#else - if (!quiet) -#endif -#ifdef SERVER_SUPPORT - /* Needs to go on stdout, not stderr, to avoid being interspersed - with the add_log messages. */ - printf ("%s %s: Importing %s\n", - program_name, command_name, repository); -#else - error (0, 0, "Importing %s", repository); -#endif - - if (chdir (dir) < 0) - { - ierrno = errno; - fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository); - error (0, ierrno, "ERROR: cannot chdir to %s", repository); - err = 1; - goto out; - } -#ifdef CLIENT_SUPPORT - if (!client_active && !isdir (repository)) -#else - if (!isdir (repository)) -#endif - { - if (isfile (repository)) - { - fperror (logfp, 0, 0, "ERROR: %s is a file, should be a directory!", - repository); - error (0, 0, "ERROR: %s is a file, should be a directory!", - repository); - err = 1; - goto out; - } - if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0) - { - ierrno = errno; - fperror (logfp, 0, ierrno, - "ERROR: cannot mkdir %s -- not added", repository); - error (0, ierrno, - "ERROR: cannot mkdir %s -- not added", repository); - err = 1; - goto out; - } - } - err = import_descend (message, vtag, targc, targv); - out: - if ((cp = strrchr (repository, '/')) != NULL) - *cp = '\0'; - else - repository[0] = '\0'; - if (restore_cwd (&cwd, NULL)) - exit (1); - free_cwd (&cwd); - return (err); -} diff --git a/gnu/usr.bin/cvs/cvs/lock.c b/gnu/usr.bin/cvs/cvs/lock.c deleted file mode 100644 index 3e15fbb..0000000 --- a/gnu/usr.bin/cvs/cvs/lock.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * 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. - * - * Set Lock - * - * Lock file support for CVS. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)lock.c 1.50 94/09/30 $"; -USE(rcsid); -#endif - -static int readers_exist PROTO((char *repository)); -static int set_lock PROTO((char *repository, int will_wait)); -static void clear_lock PROTO((void)); -static void set_lockers_name PROTO((struct stat *statp)); -static int set_writelock_proc PROTO((Node * p, void *closure)); -static int unlock_proc PROTO((Node * p, void *closure)); -static int write_lock PROTO((char *repository)); -static void unlock PROTO((char *repository)); -static void lock_wait PROTO((char *repository)); -static int Check_Owner PROTO((char *lockdir)); - -static char lockers_name[20]; -static char *repository; -static char readlock[PATH_MAX], writelock[PATH_MAX], masterlock[PATH_MAX]; -static int cleanup_lckdir; -static List *locklist; - -#define L_OK 0 /* success */ -#define L_ERROR 1 /* error condition */ -#define L_LOCKED 2 /* lock owned by someone else */ - -/* - * Clean up all outstanding locks - */ -void -Lock_Cleanup () -{ - /* clean up simple locks (if any) */ - if (repository != NULL) - { - unlock (repository); - repository = (char *) NULL; - } - - /* clean up multiple locks (if any) */ - if (locklist != (List *) NULL) - { - (void) walklist (locklist, unlock_proc, NULL); - locklist = (List *) NULL; - } -} - -/* - * walklist proc for removing a list of locks - */ -static int -unlock_proc (p, closure) - Node *p; - void *closure; -{ - unlock (p->key); - return (0); -} - -/* - * Remove the lock files (without complaining if they are not there), - */ -static void -unlock (repository) - char *repository; -{ - char tmp[PATH_MAX]; - - if (readlock[0] != '\0') - { - (void) sprintf (tmp, "%s/%s", repository, readlock); - if (unlink (tmp) < 0 && ! existence_error (errno)) - error (0, errno, "failed to remove lock %s", tmp); - } - - if (writelock[0] != '\0') - { - (void) sprintf (tmp, "%s/%s", repository, writelock); - if (unlink (tmp) < 0 && ! existence_error (errno)) - error (0, errno, "failed to remove lock %s", tmp); - } - - /* - * Only remove the lock directory if it is ours, note that this does - * lead to the limitation that one user ID should not be committing - * files into the same Repository directory at the same time. Oh well. - */ - if (writelock[0] != '\0' || (readlock[0] != '\0' && cleanup_lckdir)) - { - (void) sprintf (tmp, "%s/%s", repository, CVSLCK); - if (Check_Owner(tmp)) - { -#ifdef AFSCVS - char rmuidlock[PATH_MAX]; - sprintf(rmuidlock, "rm -f %s/uidlock%d", tmp, geteuid() ); - system(rmuidlock); -#endif - (void) rmdir (tmp); - } - } - cleanup_lckdir = 0; -} - -/* - * Check the owner of a lock. Returns 1 if we own it, 0 otherwise. - */ -static int -Check_Owner(lockdir) - char *lockdir; -{ - struct stat sb; - -#ifdef AFSCVS - /* In the Andrew File System (AFS), user ids from stat don't match - those from geteuid(). The AFSCVS code can deal with either AFS or - non-AFS repositories; the non-AFSCVS code is faster. */ - char uidlock[PATH_MAX]; - - /* 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 - return 0; /* The file didn't exist or some other error. - * Assume that we don't own it. - */ -#else - if (stat (lockdir, &sb) != -1 && sb.st_uid == geteuid ()) - return 1; - else - return 0; -#endif -} /* end Check_Owner() */ - - -/* - * Create a lock file for readers - */ -int -Reader_Lock (xrepository) - char *xrepository; -{ - int err = 0; - FILE *fp; - char tmp[PATH_MAX]; - - if (noexec) - return (0); - - /* we only do one directory at a time for read locks! */ - if (repository != NULL) - { - error (0, 0, "Reader_Lock called while read locks set - Help!"); - return (1); - } - - if (readlock[0] == '\0') - (void) sprintf (readlock, -#ifdef HAVE_LONG_FILE_NAMES - "%s.%s.%d", CVSRFL, hostname, -#else - "%s.%d", CVSRFL, -#endif - getpid ()); - - /* remember what we're locking (for lock_cleanup) */ - repository = xrepository; - -#ifdef BOGUS_UNLESS_PROVEN_OTHERWISE - /* make sure we can write the repository */ - (void) sprintf (tmp, -#ifdef HAVE_LONG_FILE_NAMES - "%s/%s.%s.%d", xrepository, CVSTFL, hostname, -#else - "%s/%s.%d", xrepository, CVSTFL, -#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 - - /* get the lock dir for our own */ - if (set_lock (xrepository, 1) != L_OK) - { - error (0, 0, "failed to obtain dir lock in repository `%s'", - xrepository); - readlock[0] = '\0'; - return (1); - } - - /* 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'", - xrepository); - readlock[0] = '\0'; - err = 1; - } - - /* free the lock dir */ - clear_lock(); - - return (err); -} - -/* - * Lock a list of directories for writing - */ -static char *lock_error_repos; -static int lock_error; -int -Writer_Lock (list) - List *list; -{ - if (noexec) - return (0); - - /* We only know how to do one list at a time */ - if (locklist != (List *) NULL) - { - error (0, 0, "Writer_Lock called while write locks set - Help!"); - return (1); - } - - for (;;) - { - /* try to lock everything on the list */ - lock_error = L_OK; /* init for set_writelock_proc */ - lock_error_repos = (char *) NULL; /* init for set_writelock_proc */ - locklist = list; /* init for Lock_Cleanup */ - (void) strcpy (lockers_name, "unknown"); - - (void) walklist (list, set_writelock_proc, NULL); - - switch (lock_error) - { - case L_ERROR: /* Real Error */ - Lock_Cleanup (); /* clean up any locks we set */ - error (0, 0, "lock failed - giving up"); - return (1); - - case L_LOCKED: /* Someone already had a lock */ - Lock_Cleanup (); /* clean up any locks we set */ - lock_wait (lock_error_repos); /* sleep a while and try again */ - continue; - - case L_OK: /* we got the locks set */ - return (0); - - default: - error (0, 0, "unknown lock status %d in Writer_Lock", - lock_error); - return (1); - } - } -} - -/* - * walklist proc for setting write locks - */ -static int -set_writelock_proc (p, closure) - Node *p; - void *closure; -{ - /* if some lock was not OK, just skip this one */ - if (lock_error != L_OK) - return (0); - - /* apply the write lock */ - lock_error_repos = p->key; - lock_error = write_lock (p->key); - return (0); -} - -/* - * Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if - * lock held by someone else or L_ERROR if an error occurred - */ -static int -write_lock (repository) - char *repository; -{ - int status; - FILE *fp; - char tmp[PATH_MAX]; - - if (writelock[0] == '\0') - (void) sprintf (writelock, -#ifdef HAVE_LONG_FILE_NAMES - "%s.%s.%d", CVSWFL, hostname, -#else - "%s.%d", CVSWFL, -#endif - getpid()); - -#ifdef BOGUS_UNLESS_PROVEN_OTHERWISE - /* make sure we can write the repository */ - (void) sprintf (tmp, -#ifdef HAVE_LONG_FILE_NAMES - "%s/%s.%s.%d", repository, CVSTFL, hostname, -#else - "%s/%s.%d", repository, CVSTFL, -#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 - - /* make sure the lock dir is ours (not necessarily unique to us!) */ - status = set_lock (repository, 0); - if (status == L_OK) - { - /* we now own a writer - make sure there are no readers */ - if (readers_exist (repository)) - { - /* clean up the lock dir if we created it */ - if (status == L_OK) - { - clear_lock(); - } - - /* indicate we failed due to read locks instead of error */ - return (L_LOCKED); - } - - /* 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); - - /* free the lock dir if we created it */ - if (status == L_OK) - { - clear_lock(); - } - - /* return the error */ - error (0, xerrno, "cannot create write lock in repository `%s'", - repository); - return (L_ERROR); - } - return (L_OK); - } - else - return (status); -} - -/* - * readers_exist() returns 0 if there are no reader lock files remaining in - * the repository; else 1 is returned, to indicate that the caller should - * sleep a while and try again. - */ -static int -readers_exist (repository) - char *repository; -{ - char line[MAXLINELEN]; - DIR *dirp; - struct dirent *dp; - struct stat sb; - int ret = 0; - -#ifdef CVS_FUDGELOCKS -again: -#endif - - if ((dirp = opendir (repository)) == NULL) - error (1, 0, "cannot open directory %s", repository); - - errno = 0; - while ((dp = readdir (dirp)) != NULL) - { - if (fnmatch (CVSRFLPAT, dp->d_name, 0) == 0) - { -#ifdef CVS_FUDGELOCKS - time_t now; - (void) time (&now); -#endif - - (void) sprintf (line, "%s/%s", repository, dp->d_name); - if (stat (line, &sb) != -1) - { -#ifdef CVS_FUDGELOCKS - /* - * If the create time of the file is more than CVSLCKAGE - * seconds ago, try to clean-up the lock file, and if - * successful, re-open the directory and try again. - */ - if (now >= (sb.st_ctime + CVSLCKAGE) && unlink (line) != -1) - { - (void) closedir (dirp); - goto again; - } -#endif - set_lockers_name (&sb); - } - - ret = 1; - break; - } - errno = 0; - } - if (errno != 0) - error (0, errno, "error reading directory %s", repository); - - closedir (dirp); - return (ret); -} - -/* - * Set the static variable lockers_name appropriately, based on the stat - * structure passed in. - */ -static void -set_lockers_name (statp) - struct stat *statp; -{ - struct passwd *pw; - - if ((pw = (struct passwd *) getpwuid (statp->st_uid)) != - (struct passwd *) NULL) - { - (void) strcpy (lockers_name, pw->pw_name); - } - else - (void) sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid); -} - -/* - * Persistently tries to make the directory "lckdir",, which serves as a - * lock. If the create time on the directory is greater than CVSLCKAGE - * seconds old, just try to remove the directory. - */ -static int -set_lock (repository, will_wait) - char *repository; - int will_wait; -{ - struct stat sb; - mode_t omask; -#ifdef CVS_FUDGELOCKS - time_t now; -#endif - - (void) sprintf (masterlock, "%s/%s", repository, CVSLCK); - - /* - * Note that it is up to the callers of set_lock() to arrange for signal - * handlers that do the appropriate things, like remove the lock - * directory before they exit. - */ - cleanup_lckdir = 0; - for (;;) - { - int status = -1; - omask = umask (cvsumask); - SIG_beginCrSect (); - if (CVS_MKDIR (masterlock, 0777) == 0) - { -#ifdef AFSCVS - char uidlock[PATH_MAX]; - FILE *fp; - - sprintf(uidlock, "%s/uidlock%d", masterlock, geteuid() ); - if ((fp = fopen(uidlock, "w+")) == NULL) - { - /* We failed to create the uidlock, - so rm masterlock and leave */ - rmdir(masterlock); - SIG_endCrSect (); - status = L_ERROR; - goto out; - } - - /* We successfully created the uid lock, so close the file */ - fclose(fp); -#endif - cleanup_lckdir = 1; - SIG_endCrSect (); - status = L_OK; - goto out; - } - SIG_endCrSect (); - out: - (void) umask (omask); - if (status != -1) - return status; - - if (errno != EEXIST) - { - error (0, errno, - "failed to create lock directory in repository `%s'", - repository); - return (L_ERROR); - } - - /* - * stat the dir - if it is non-existent, re-try the loop since - * someone probably just removed it (thus releasing the lock) - */ - if (stat (masterlock, &sb) < 0) - { - if (existence_error (errno)) - continue; - - error (0, errno, "couldn't stat lock directory `%s'", masterlock); - return (L_ERROR); - } - -#ifdef CVS_FUDGELOCKS - /* - * If the create time of the directory is more than CVSLCKAGE seconds - * ago, try to clean-up the lock directory, and if successful, just - * quietly retry to make it. - */ - (void) time (&now); - if (now >= (sb.st_ctime + CVSLCKAGE)) - { -#ifdef AFSCVS - /* Remove the uidlock first */ - char rmuidlock[PATH_MAX]; - sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() ); - system(rmuidlock); -#endif - if (rmdir (masterlock) >= 0) - continue; - } -#endif - - /* set the lockers name */ - set_lockers_name (&sb); - - /* if he wasn't willing to wait, return an error */ - if (!will_wait) - return (L_LOCKED); - lock_wait (repository); - } -} - -/* - * Clear master lock. We don't have to recompute the lock name since - * clear_lock is never called except after a successful set_lock(). - */ -static void -clear_lock() -{ -#ifdef AFSCVS - /* Remove the uidlock first */ - char rmuidlock[PATH_MAX]; - sprintf(rmuidlock, "rm -f %s/uidlock%d", masterlock, geteuid() ); - system(rmuidlock); -#endif - if (rmdir (masterlock) < 0) - error (0, errno, "failed to remove lock dir `%s'", masterlock); - cleanup_lckdir = 0; -} - -/* - * Print out a message that the lock is still held, then sleep a while. - */ -static void -lock_wait (repos) - char *repos; -{ - time_t now; - - (void) time (&now); - error (0, 0, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11, - lockers_name, repos); - (void) sleep (CVSLCKSLEEP); -} diff --git a/gnu/usr.bin/cvs/cvs/log.c b/gnu/usr.bin/cvs/cvs/log.c deleted file mode 100644 index 88c9adc..0000000 --- a/gnu/usr.bin/cvs/cvs/log.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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. - * - * Print Log Information - * - * This line exists solely to test some pcl-cvs/ChangeLog stuff. You - * can delete it, if indeed it's still here when you read it. -Karl - * - * Prints the RCS "log" (rlog) information for the specified files. With no - * argument, prints the log information for all the files in the directory - * (recursive by default). - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)log.c 1.44 94/09/30 $"; -USE(rcsid); -#endif - -static Dtype log_dirproc PROTO((char *dir, char *repository, char *update_dir)); -static int log_fileproc PROTO((char *file, char *update_dir, char *repository, - List * entries, List * srcfiles)); - -static const char *const log_usage[] = -{ - "Usage: %s %s [-l] [rlog-options] [files...]\n", - "\t-l\tLocal directory only, no recursion.\n", - NULL -}; - -static int ac; -static char **av; - -int -cvslog (argc, argv) - int argc; - char **argv; -{ - int i; - int err = 0; - int local = 0; - - if (argc == -1) - usage (log_usage); - - /* - * All 'log' command options except -l are passed directly on to 'rlog' - */ - for (i = 1; i < argc && argv[i][0] == '-'; i++) - if (argv[i][1] == 'l') - local = 1; - - wrap_setup (); - -#ifdef CLIENT_SUPPORT - if (client_active) { - /* We're the local client. Fire up the remote server. */ - start_server (); - - ign_setup (); - - for (i = 1; i < argc && argv[i][0] == '-'; i++) - send_arg (argv[i]); - -#if 0 -/* 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"); - err = get_responses_and_close (); - return err; - } - - ac = argc; - av = argv; -#endif - - 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); -} - - -/* - * Do an rlog on a file - */ -/* ARGSUSED */ -static int -log_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Node *p; - RCSNode *rcsfile; - int retcode = 0; - - p = findnode (srcfiles, file); - if (p == NULL || (rcsfile = (RCSNode *) p->data) == NULL) - { - /* no rcs file. What *do* we know about this file? */ - p = findnode (entries, file); - if (p != NULL) - { - Entnode *e; - - e = (Entnode *) p->data; - if (e->version[0] == '0' || e->version[1] == '\0') - { - if (!really_quiet) - error (0, 0, "%s has been added, but not committed", - file); - return(0); - } - } - - if (!really_quiet) - error (0, 0, "nothing known about %s", file); - - return (1); - } - - run_setup ("%s%s", Rcsbin, RCS_RLOG); - { - int i; - for (i = 1; i < ac && av[i][0] == '-'; i++) - if (av[i][1] != 'l') - run_arg (av[i]); - } - run_arg (rcsfile->path); - - if (*update_dir) - { - char *workfile = xmalloc (strlen (update_dir) + strlen (file) + 2); - sprintf (workfile, "%s/%s", update_dir, file); - run_arg (workfile); - free (workfile); - } - - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_REALLY)) == -1) - { - error (1, errno, "fork failed for rlog on %s", file); - } - return (retcode); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -log_dirproc (dir, repository, update_dir) - char *dir; - char *repository; - char *update_dir; -{ - if (!isdir (dir)) - return (R_SKIP_ALL); - - if (!quiet) - error (0, 0, "Logging %s", update_dir); - return (R_PROCESS); -} diff --git a/gnu/usr.bin/cvs/cvs/login.c b/gnu/usr.bin/cvs/cvs/login.c deleted file mode 100644 index ccb757c..0000000 --- a/gnu/usr.bin/cvs/cvs/login.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * 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 <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> - -#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 - - -/* The return value will need to be freed. */ -char * -construct_cvspass_filename () -{ - char *homedir; - char *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 cleartext_password - * user@host:/path cleartext_password - * ... - * - * Of course, the "user@" might be left off -- it's just based on the - * value of CVSroot. - * - * 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[MAXLINELEN]; - 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); - fgets (linebuf, MAXLINELEN, stdin); - - tmp = xmalloc (strlen (linebuf) + 1); - - strcpy (tmp, linebuf); - tmp[strlen (linebuf) - 1] = '\0'; - CVSroot = tmp; - } - - /* Check to make sure it's fully-qualified before going on. */ - if (! CVSroot) - { - error (1, 0, "CVSroot is NULL"); - } - else if ((! strchr (CVSroot, '@')) && (! strchr (CVSroot, ':'))) - { - error (1, 0, "CVSroot not fully-qualified: %s", CVSroot); - } - - - passfile = construct_cvspass_filename (); - typed_password = getpass ("Enter CVS 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) - { - error (1, errno, "unable to open %s", passfile); - return 1; - } - - /* Check each line to see if we have this entry already. */ - while (fgets (linebuf, MAXLINELEN, fp) != NULL) - { - if (! strncmp (CVSroot, linebuf, root_len)) - { - already_entered = 1; - break; - } - } - fclose (fp); - - - if (already_entered) - { - /* This user/host has a password in the file already. */ - - /* todo: what about these charsets??? */ - strtok (linebuf, " \n"); - 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); - - while (fgets (linebuf, MAXLINELEN, fp) != NULL) - { - if (strncmp (CVSroot, linebuf, root_len)) - fprintf (tmp_fp, "%s", linebuf); - else - fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password); - } - 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; - } - - /* It's safer this way, and blank lines in the file are OK. */ - fprintf (fp, "\n%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 (passfile); - return 0; -} - -/* todo: "cvs logout" could erase an entry from the file. - * But to what purpose? - */ - - -char * -get_cvs_password (user, host, cvsroot) -{ - int root_len; - int found_it = 0; - char *password; - char linebuf[MAXLINELEN]; - FILE *fp; - char *passfile; - - passfile = construct_cvspass_filename (); - fp = fopen (passfile, "r"); - if (fp == NULL) - { - error (0, errno, "could not open %s", passfile); - free (passfile); - goto prompt_for_it; - } - - root_len = strlen (CVSroot); - - /* Check each line to see if we have this entry already. */ - while (fgets (linebuf, MAXLINELEN, fp) != NULL) - { - if (strncmp (CVSroot, linebuf, root_len) == 0) - { - /* This is it! So break out and deal with linebuf. */ - found_it = 1; - break; - } - } - - 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 - { - prompt_for_it: - return getpass ("CVS password: "); - } -} - -#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */ - diff --git a/gnu/usr.bin/cvs/cvs/logmsg.c b/gnu/usr.bin/cvs/cvs/logmsg.c deleted file mode 100644 index 7686a36..0000000 --- a/gnu/usr.bin/cvs/cvs/logmsg.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * 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. - */ - -#include "cvs.h" -#include "getline.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)logmsg.c 1.48 94/09/29 $"; -USE(rcsid); -#endif - -static int find_type PROTO((Node * p, void *closure)); -static int fmt_proc PROTO((Node * p, void *closure)); -static int logfile_write PROTO((char *repository, char *filter, char *title, - char *message, char *revision, FILE * logfp, - List * changes)); -static int rcsinfo_proc PROTO((char *repository, char *template)); -static int title_proc PROTO((Node * p, void *closure)); -static int update_logfile_proc PROTO((char *repository, char *filter)); -static void setup_tmpfile PROTO((FILE * xfp, char *xprefix, List * changes)); -static int editinfo_proc PROTO((char *repository, char *template)); - -static FILE *fp; -static char *str_list; -static char *editinfo_editor; -static Ctype type; - -/* - * Puts a standard header on the output which is either being prepared for an - * editor session, or being sent to a logfile program. The modified, added, - * and removed files are included (if any) and formatted to look pretty. */ -static char *prefix; -static int col; -static void -setup_tmpfile (xfp, xprefix, changes) - FILE *xfp; - char *xprefix; - List *changes; -{ - /* set up statics */ - fp = xfp; - prefix = xprefix; - - type = T_MODIFIED; - if (walklist (changes, find_type, NULL) != 0) - { - (void) fprintf (fp, "%sModified Files:\n", prefix); - (void) fprintf (fp, "%s\t", prefix); - col = 8; - (void) walklist (changes, fmt_proc, NULL); - (void) fprintf (fp, "\n"); - } - type = T_ADDED; - if (walklist (changes, find_type, NULL) != 0) - { - (void) fprintf (fp, "%sAdded Files:\n", prefix); - (void) fprintf (fp, "%s\t", prefix); - col = 8; - (void) walklist (changes, fmt_proc, NULL); - (void) fprintf (fp, "\n"); - } - type = T_REMOVED; - if (walklist (changes, find_type, NULL) != 0) - { - (void) fprintf (fp, "%sRemoved Files:\n", prefix); - (void) fprintf (fp, "%s\t", prefix); - col = 8; - (void) walklist (changes, fmt_proc, NULL); - (void) fprintf (fp, "\n"); - } -} - -/* - * Looks for nodes of a specified type and returns 1 if found - */ -static int -find_type (p, closure) - Node *p; - void *closure; -{ - if (p->data == (char *) type) - return (1); - else - return (0); -} - -/* - * Breaks the files list into reasonable sized lines to avoid line wrap... - * all in the name of pretty output. It only works on nodes whose types - * match the one we're looking for - */ -static int -fmt_proc (p, closure) - Node *p; - void *closure; -{ - if (p->data == (char *) type) - { - if ((col + (int) strlen (p->key)) > 70) - { - (void) fprintf (fp, "\n%s\t", prefix); - col = 8; - } - (void) fprintf (fp, "%s ", p->key); - col += strlen (p->key) + 1; - } - return (0); -} - -/* - * Builds a temporary file using setup_tmpfile() and invokes the user's - * editor on the file. The header garbage in the resultant file is then - * stripped and the log message is stored in the "message" argument. - * - * rcsinfo - is the name of a file containing lines tacked onto the end of the - * RCS info offered to the user for editing. If specified, the '-m' flag to - * "commit" is disabled -- users are forced to run the editor. - * - */ -void -do_editor (dir, messagep, repository, changes) - char *dir; - char **messagep; - char *repository; - List *changes; -{ - static int reuse_log_message = 0; - 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; - - /* Create a temporary file */ - (void) tmpnam (fname); - again: - if ((fp = fopen (fname, "w+")) == NULL) - error (1, 0, "cannot create temporary file %s", fname); - - if (*messagep) - { - (void) fprintf (fp, "%s", *messagep); - - if ((*messagep)[strlen (*messagep) - 1] != '\n') - (void) fprintf (fp, "\n"); - } - else - (void) fprintf (fp, "\n"); - - if (repository != NULL) - /* tack templates on if necessary */ - (void) Parse_Info (CVSROOTADM_RCSINFO, repository, rcsinfo_proc, 1); - - (void) fprintf (fp, - "%s----------------------------------------------------------------------\n", - CVSEDITPREFIX); - (void) fprintf (fp, - "%sEnter Log. Lines beginning with `%s' are removed automatically\n%s\n", - CVSEDITPREFIX, CVSEDITPREFIX, CVSEDITPREFIX); - if (dir != NULL && *dir) - (void) fprintf (fp, "%sCommitting in %s\n%s\n", CVSEDITPREFIX, - dir, CVSEDITPREFIX); - if (changes != NULL) - setup_tmpfile (fp, CVSEDITPREFIX, changes); - (void) fprintf (fp, - "%s----------------------------------------------------------------------\n", - CVSEDITPREFIX); - - /* finish off the temp file */ - if (fclose (fp) == EOF) - error (1, errno, "%s", fname); - if (stat (fname, &pre_stbuf) == -1) - pre_stbuf.st_mtime = 0; - - if (editinfo_editor) - free (editinfo_editor); - editinfo_editor = (char *) NULL; - if (repository != NULL) - (void) Parse_Info (CVSROOTADM_EDITINFO, repository, editinfo_proc, 0); - - /* run the editor */ - run_setup ("%s", editinfo_editor ? editinfo_editor : Editor); - run_arg (fname); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, - RUN_NORMAL | RUN_SIGIGNORE)) != 0) - error (editinfo_editor ? 1 : 0, retcode == -1 ? errno : 0, - editinfo_editor ? "Logfile verification failed" : - "warning: editor session failed"); - - /* put the entire message back into the *messagep variable */ - - fp = open_file (fname, "r"); - - if (*messagep) - free (*messagep); - - if (stat (fname, &post_stbuf) != 0) - error (1, errno, "cannot find size of temp file %s", fname); - - if (post_stbuf.st_size == 0) - *messagep = NULL; - else - { - *messagep = (char *) xmalloc (post_stbuf.st_size + 1); - *messagep[0] = '\0'; - } - - line = NULL; - line_chars_allocated = 0; - - if (*messagep) - { - 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) strcpy (p, line); - p += line_length; - } - } - 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) - { - for (;;) - { - (void) printf ("\nLog message unchanged or not specified\n"); - (void) printf ("a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs\n"); - (void) printf ("Action: (continue) "); - (void) fflush (stdout); - 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"); - if (*line == 'e' || *line == 'E') - goto again; - if (*line == '!') - { - reuse_log_message = 1; - break; - } - (void) printf ("Unknown input\n"); - } - } - if (line) - free (line); - if (unlink_file (fname) < 0) - error (0, errno, "warning: cannot remove temp file %s", fname); -} - -/* - * callback proc for Parse_Info for rcsinfo templates this routine basically - * copies the matching template onto the end of the tempfile we are setting - * up - */ -/* ARGSUSED */ -static int -rcsinfo_proc (repository, template) - char *repository; - char *template; -{ - static char *last_template; - FILE *tfp; - - /* nothing to do if the last one included is the same as this one */ - if (last_template && strcmp (last_template, template) == 0) - return (0); - if (last_template) - free (last_template); - last_template = xstrdup (template); - - if ((tfp = fopen (template, "r")) != NULL) - { - char *line = NULL; - size_t line_chars_allocated = 0; - - while (getline (&line, &line_chars_allocated, tfp) >= 0) - (void) fputs (line, fp); - 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, errno, "Couldn't open rcsinfo template file %s", template); - return (1); - } -} - -/* - * Uses setup_tmpfile() to pass the updated message on directly to any - * logfile programs that have a regular expression match for the checked in - * directory in the source repository. The log information is fed into the - * specified program as standard input. - */ -static char *title; -static FILE *logfp; -static char *message; -static char *revision; -static List *changes; - -void -Update_Logfile (repository, xmessage, xrevision, xlogfp, xchanges) - char *repository; - char *xmessage; - char *xrevision; - FILE *xlogfp; - List *xchanges; -{ - char *srepos; - - /* nothing to do if the list is empty */ - if (xchanges == NULL || xchanges->list->next == xchanges->list) - return; - - /* set up static vars for update_logfile_proc */ - message = xmessage; - revision = xrevision; - logfp = xlogfp; - changes = xchanges; - - /* figure out a good title string */ - srepos = Short_Repository (repository); - - /* allocate a chunk of memory to hold the title string */ - if (!str_list) - str_list = xmalloc (MAXLISTLEN); - str_list[0] = '\0'; - - type = T_TITLE; - (void) walklist (changes, title_proc, NULL); - type = T_ADDED; - (void) walklist (changes, title_proc, NULL); - type = T_MODIFIED; - (void) walklist (changes, title_proc, NULL); - type = T_REMOVED; - (void) walklist (changes, title_proc, NULL); - title = xmalloc (strlen (srepos) + strlen (str_list) + 1 + 2); /* for 's */ - (void) sprintf (title, "'%s%s'", srepos, str_list); - - /* to be nice, free up this chunk of memory */ - free (str_list); - str_list = (char *) NULL; - - /* call Parse_Info to do the actual logfile updates */ - (void) Parse_Info (CVSROOTADM_LOGINFO, repository, update_logfile_proc, 1); - - /* clean up */ - free (title); -} - -/* - * callback proc to actually do the logfile write from Update_Logfile - */ -static int -update_logfile_proc (repository, filter) - char *repository; - char *filter; -{ - return (logfile_write (repository, filter, title, message, revision, - logfp, changes)); -} - -/* - * concatenate each name onto str_list - */ -static int -title_proc (p, closure) - Node *p; - void *closure; -{ - if (p->data == (char *) type) - { - (void) strcat (str_list, " "); - (void) strcat (str_list, p->key); - } - return (0); -} - -/* - * Since some systems don't define this... - */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -/* - * Writes some stuff to the logfile "filter" and returns the status of the - * filter program. - */ -static int -logfile_write (repository, filter, title, message, revision, logfp, changes) - char *repository; - char *filter; - char *title; - char *message; - char *revision; - FILE *logfp; - List *changes; -{ - char cwd[PATH_MAX]; - FILE *pipefp, *Popen (); - char *prog = xmalloc (MAXPROGLEN); - char *cp; - int c; - - /* XXX <woods@web.net> -- this is gross, ugly, and a hack! FIXME! */ - /* - * A maximum of 6 %s arguments are supported in the filter - */ - (void) sprintf (prog, filter, title, title, title, title, title, title); - if ((pipefp = Popen (prog, "w")) == NULL) - { - if (!noexec) - error (0, 0, "cannot write entry to log filter: %s", prog); - free (prog); - return (1); - } - (void) fprintf (pipefp, "Update of %s\n", repository); - (void) fprintf (pipefp, "In directory %s:%s\n\n", hostname, - ((cp = getwd (cwd)) != NULL) ? cp : cwd); - if (revision && *revision) - (void) fprintf (pipefp, "Revision/Branch: %s\n\n", revision); - setup_tmpfile (pipefp, "", changes); - (void) fprintf (pipefp, "Log Message:\n%s\n", message); - if (logfp != (FILE *) 0) - { - (void) fprintf (pipefp, "Status:\n"); - rewind (logfp); - while ((c = getc (logfp)) != EOF) - (void) putc ((char) c, pipefp); - } - free (prog); - return (pclose (pipefp)); -} - -/* - * We choose to use the *last* match within the editinfo file for this - * repository. This allows us to have a global editinfo program for the - * root of some hierarchy, for example, and different ones within different - * sub-directories of the root (like a special checker for changes made to - * the "src" directory versus changes made to the "doc" or "test" - * directories. - */ -/* ARGSUSED */ -static int -editinfo_proc(repository, editor) - char *repository; - char *editor; -{ - /* nothing to do if the last match is the same as this one */ - if (editinfo_editor && strcmp (editinfo_editor, editor) == 0) - return (0); - if (editinfo_editor) - free (editinfo_editor); - - editinfo_editor = xstrdup (editor); - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/main.c b/gnu/usr.bin/cvs/cvs/main.c deleted file mode 100644 index 91e376d..0000000 --- a/gnu/usr.bin/cvs/cvs/main.c +++ /dev/null @@ -1,769 +0,0 @@ -/* - * 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 is the main C driver for the CVS system. - * - * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing - * the shell-script CVS system that this is based on. - * - * Usage: - * cvs [options] command [options] [files/modules...] - * - * Where "command" is composed of: - * admin RCS command - * checkout Check out a module/dir/file - * export Like checkout, but used for exporting sources - * update Brings work tree in sync with repository - * commit Checks files into the repository - * diff Runs diffs between revisions - * log Prints "rlog" information for files - * login Record user, host, repos, password - * add Adds an entry to the repository - * remove Removes an entry from the repository - * status Status info on the revisions - * rdiff "patch" format diff listing between releases - * tag Add/delete a symbolic tag to the RCS file - * rtag Add/delete a symbolic tag to the RCS file - * import Import sources into CVS, using vendor branches - * release Indicate that Module is no longer in use. - * history Display history of Users and Modules. - */ - -#include "cvs.h" -#include "patchlevel.h" - -#if HAVE_KERBEROS -#include <sys/socket.h> -#include <netinet/in.h> -#include <krb.h> -#ifndef HAVE_KRB_GET_ERR_TEXT -#define krb_get_err_text(status) krb_err_txt[status] -#endif -#endif - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)main.c 1.78 94/10/07 $\n"; -USE(rcsid); -#endif - -char *program_name; -char *program_path; -/* - * Initialize comamnd_name to "cvs" so that the first call to - * read_cvsrc tries to find global cvs options. - */ -char *command_name = "cvs"; - -/* - * Since some systems don't define this... - */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -char hostname[MAXHOSTNAMELEN]; - -#ifdef AUTH_CLIENT_SUPPORT -int use_authenticating_server = FALSE; -#endif /* AUTH_CLIENT_SUPPORT */ -int use_editor = TRUE; -int use_cvsrc = TRUE; -int cvswrite = !CVSREAD_DFLT; -int really_quiet = FALSE; -int quiet = FALSE; -int trace = FALSE; -int noexec = FALSE; -int logoff = FALSE; -mode_t cvsumask = UMASK_DFLT; - -char *CurDir; - -/* - * Defaults, for the environment variables that are not set - */ -char *Rcsbin = RCSBIN_DFLT; -char *Editor = EDITOR_DFLT; -char *CVSroot = CVSROOT_DFLT; -#ifdef CVSADM_ROOT -/* - * The path found in CVS/Root must match $CVSROOT and/or 'cvs -d root' - */ -char *CVSADM_Root = CVSROOT_DFLT; -#endif /* CVSADM_ROOT */ - -int add PROTO((int argc, char **argv)); -int admin PROTO((int argc, char **argv)); -int checkout PROTO((int argc, char **argv)); -int commit PROTO((int argc, char **argv)); -int diff PROTO((int argc, char **argv)); -int history PROTO((int argc, char **argv)); -int import PROTO((int argc, char **argv)); -int cvslog PROTO((int argc, char **argv)); -#ifdef AUTH_CLIENT_SUPPORT -int login PROTO((int argc, char **argv)); -#endif /* AUTH_CLIENT_SUPPORT */ -int patch PROTO((int argc, char **argv)); -int release PROTO((int argc, char **argv)); -int cvsremove PROTO((int argc, char **argv)); -int rtag PROTO((int argc, char **argv)); -int status PROTO((int argc, char **argv)); -int tag PROTO((int argc, char **argv)); -int update PROTO((int argc, char **argv)); - -const struct cmd -{ - char *fullname; /* Full name of the function (e.g. "commit") */ - char *nick1; /* alternate name (e.g. "ci") */ - char *nick2; /* another alternate names (e.g. "ci") */ - int (*func) (); /* Function takes (argc, argv) arguments. */ -#ifdef CLIENT_SUPPORT - int (*client_func) (); /* Function to do it via the protocol. */ -#endif -} cmds[] = - -{ -#ifdef CLIENT_SUPPORT -#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1, f2 } -#else -#define CMD_ENTRY(n1, n2, n3, f1, f2) { n1, n2, n3, f1 } -#endif - - CMD_ENTRY("add", "ad", "new", add, client_add), -#ifndef CVS_NOADMIN - CMD_ENTRY("admin", "adm", "rcs", admin, client_admin), -#endif - CMD_ENTRY("checkout", "co", "get", checkout, client_checkout), - CMD_ENTRY("commit", "ci", "com", commit, client_commit), - CMD_ENTRY("diff", "di", "dif", diff, client_diff), - CMD_ENTRY("export", "exp", "ex", checkout, client_export), - CMD_ENTRY("history", "hi", "his", history, client_history), - CMD_ENTRY("import", "im", "imp", import, client_import), - CMD_ENTRY("log", "lo", "rlog", cvslog, client_log), -#ifdef AUTH_CLIENT_SUPPORT - CMD_ENTRY("login", "logon", "lgn", login, login), -#endif /* AUTH_CLIENT_SUPPORT */ - CMD_ENTRY("rdiff", "patch", "pa", patch, client_rdiff), - CMD_ENTRY("release", "re", "rel", release, client_release), - CMD_ENTRY("remove", "rm", "delete", cvsremove, client_remove), - CMD_ENTRY("status", "st", "stat", status, client_status), - CMD_ENTRY("rtag", "rt", "rfreeze", rtag, client_rtag), - CMD_ENTRY("tag", "ta", "freeze", tag, client_tag), - CMD_ENTRY("update", "up", "upd", update, client_update), - -#ifdef SERVER_SUPPORT - /* - * The client_func is also server because we might have picked up a - * CVSROOT environment variable containing a colon. The client will send - * the real root later. - */ - CMD_ENTRY("server", "server", "server", server, server), -#endif - CMD_ENTRY(NULL, NULL, NULL, NULL, NULL), - -#undef CMD_ENTRY -}; - -static const char *const usg[] = -{ - "Usage: %s [cvs-options] command [command-options] [files...]\n", - " Where 'cvs-options' are:\n", - " -H Displays Usage information for command\n", - " -Q Cause CVS to be really quiet.\n", - " -q Cause CVS to be somewhat quiet.\n", -#ifdef AUTH_CLIENT_SUPPORT - " -a Use the authenticating server, not rsh.\n", -#endif /* AUTH_CLIENT_SUPPORT */ - " -r Make checked-out files read-only\n", - " -w Make checked-out files read-write (default)\n", - " -l Turn History logging off\n", - " -n Do not execute anything that will change the disk\n", - " -t Show trace of program execution -- Try with -n\n", - " -v CVS version and copyright\n", - " -b bindir Find RCS programs in 'bindir'\n", - " -e editor Use 'editor' for editing log information\n", - " -d CVS_root Overrides $CVSROOT as the root of the CVS tree\n", - " -f Do not use the ~/.cvsrc file\n", -#ifdef CLIENT_SUPPORT - " -z # Use 'gzip -#' for net traffic if possible.\n", -#endif - "\n", - " and where 'command' is:\n", - " add Adds a new file/directory to the repository\n", - " admin Administration front end for rcs\n", - " checkout Checkout sources for editing\n", - " commit Checks files into the repository\n", - " diff Runs diffs between revisions\n", - " history Shows status of files and users\n", - " import Import sources into CVS, using vendor branches\n", - " export Export sources from CVS, similar to checkout\n", - " log Prints out 'rlog' information for files\n", -#ifdef AUTH_CLIENT_SUPPORT - " login Prompt for password for authenticating server.\n", -#endif /* AUTH_CLIENT_SUPPORT */ - " rdiff 'patch' format diffs between releases\n", - " release Indicate that a Module is no longer in use\n", - " remove Removes an entry from the repository\n", - " status Status info on the revisions\n", - " tag Add a symbolic tag to checked out version of RCS file\n", - " rtag Add a symbolic tag to the RCS file\n", - " update Brings work tree in sync with repository\n", - NULL, -}; - -static RETSIGTYPE -main_cleanup () -{ - exit (1); -} - -static void -error_cleanup () -{ - Lock_Cleanup(); -#ifdef SERVER_SUPPORT - if (server_active) - server_cleanup (0); -#endif -} - -int -main (argc, argv) - int argc; - char **argv; -{ - extern char *version_string; - extern char *config_string; - char *cp, *end; - const struct cmd *cm; - int c, err = 0; - static int help = FALSE, version_flag = FALSE; - int rcsbin_update_env, cvs_update_env = 0; - char tmp[PATH_MAX]; - static struct option long_options[] = - { - {"help", 0, &help, TRUE}, - {"version", 0, &version_flag, TRUE}, - {0, 0, 0, 0} - }; - /* `getopt_long' stores the option index here, but right now we - don't use it. */ - int option_index = 0; - - error_set_cleanup (error_cleanup); - -/* The IBM TCP/IP library under OS/2 needs to be initialized: */ -#ifdef NEED_CALL_SOCKINIT - if (SockInit () != TRUE) - { - fprintf (stderr, "SockInit() failed!\n"); - exit (1); - } -#endif /* NEED_CALL_SOCKINIT */ - - /* - * Just save the last component of the path for error messages - */ - program_path = xstrdup (argv[0]); - program_name = last_component (argv[0]); - - CurDir = xmalloc (PATH_MAX); -#ifndef SERVER_SUPPORT - if (!getwd (CurDir)) - error (1, 0, "cannot get working directory: %s", CurDir); -#endif - - /* - * Query the environment variables up-front, so that - * they can be overridden by command line arguments - */ - rcsbin_update_env = *Rcsbin; /* RCSBIN_DFLT must be set */ - cvs_update_env = 0; - if ((cp = getenv (RCSBIN_ENV)) != NULL) - { - Rcsbin = cp; - rcsbin_update_env = 0; /* it's already there */ - } - if ((cp = getenv (EDITOR1_ENV)) != NULL) - Editor = cp; - else if ((cp = getenv (EDITOR2_ENV)) != NULL) - Editor = cp; - else if ((cp = getenv (EDITOR3_ENV)) != NULL) - Editor = cp; - if ((cp = getenv (CVSROOT_ENV)) != NULL) - { - CVSroot = cp; - cvs_update_env = 0; /* it's already there */ - } - if (getenv (CVSREAD_ENV) != NULL) - cvswrite = FALSE; - if ((cp = getenv (CVSUMASK_ENV)) != NULL) - { - /* FIXME: Should be accepting symbolic as well as numeric mask. */ - cvsumask = strtol (cp, &end, 8) & 0777; - if (*end != '\0') - error (1, errno, "invalid umask value in %s (%s)", - CVSUMASK_ENV, cp); - } - - /* - * Scan cvsrc file for global options. - */ - read_cvsrc(&argc, &argv); - - /* This has the effect of setting getopt's ordering to REQUIRE_ORDER, - which is what we need to distinguish between global options and - command options. FIXME: It would appear to be possible to do this - much less kludgily by passing "+" as the first character to the - option string we pass to getopt_long. */ - optind = 1; - - while ((c = getopt_long - (argc, argv, "Qqrawtnlvb:e:d:Hfz:", long_options, &option_index)) - != EOF) - { - switch (c) - { - case 0: - /* getopt_long took care of setting the flag. */ - break; - case 'Q': - really_quiet = TRUE; - /* FALL THROUGH */ - case 'q': - quiet = TRUE; - break; - case 'r': - cvswrite = FALSE; - break; -#ifdef AUTH_CLIENT_SUPPORT - case 'a': - use_authenticating_server = TRUE; - break; -#endif /* AUTH_CLIENT_SUPPORT */ - case 'w': - cvswrite = TRUE; - break; - case 't': - trace = TRUE; - break; - case 'n': - noexec = TRUE; - case 'l': /* Fall through */ - logoff = TRUE; - break; - case 'v': - version_flag = TRUE; - break; - case 'b': - Rcsbin = optarg; - rcsbin_update_env = 1; /* need to update environment */ - break; - case 'e': - Editor = optarg; - break; - case 'd': - CVSroot = optarg; - cvs_update_env = 1; /* need to update environment */ - break; - case 'H': - use_cvsrc = FALSE; /* this ensure that cvs -H works */ - help = TRUE; - break; - case 'f': - use_cvsrc = FALSE; - break; -#ifdef CLIENT_SUPPORT - case 'z': - gzip_level = atoi (optarg); - if (gzip_level <= 0 || gzip_level > 9) - error (1, 0, - "gzip compression level must be between 1 and 9"); - break; -#endif - case '?': - default: - usage (usg); - } - } - - if (version_flag == TRUE) - { - (void) fputs (version_string, stdout); - (void) fputs (config_string, stdout); - (void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL); - (void) fputs (tmp, stdout); - (void) fputs ("\n", stdout); - (void) fputs ("Copyright (c) 1993-1994 Brian Berliner\n", stdout); - (void) fputs ("Copyright (c) 1993-1994 david d `zoo' zuhn\n", stdout); - (void) fputs ("Copyright (c) 1992, Brian Berliner and Jeff Polk\n", stdout); - (void) fputs ("Copyright (c) 1989-1992, Brian Berliner\n", stdout); - (void) fputs ("\n", stdout); - (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); - (void) fputs ("a copy of which can be found with the CVS distribution kit.\n", stdout); - exit (0); - } - - argc -= optind; - argv += optind; - if (argc < 1) - usage (usg); - -#ifdef HAVE_KERBEROS - /* If we are invoked with a single argument "kserver", then we are - running as Kerberos server as root. Do the authentication as - the very first thing, to minimize the amount of time we are - running as root. */ - if (strcmp (argv[0], "kserver") == 0) - { - int status; - char instance[INST_SZ]; - struct sockaddr_in peer; - struct sockaddr_in laddr; - int len; - KTEXT_ST ticket; - AUTH_DAT auth; - char version[KRB_SENDAUTH_VLEN]; - Key_schedule sched; - char user[ANAME_SZ]; - struct passwd *pw; - - strcpy (instance, "*"); - len = sizeof peer; - if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0 - || getsockname (STDIN_FILENO, (struct sockaddr *) &laddr, - &len) < 0) - { - printf ("E Fatal error, aborting.\n\ -error %s getpeername or getsockname failed\n", strerror (errno)); - exit (1); - } - - status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd", - instance, &peer, &laddr, &auth, "", sched, - version); - if (status != KSUCCESS) - { - printf ("E Fatal error, aborting.\n\ -error 0 kerberos: %s\n", krb_get_err_text(status)); - exit (1); - } - - /* Get the local name. */ - status = krb_kntoln (&auth, user); - if (status != KSUCCESS) - { - printf ("E Fatal error, aborting.\n\ -error 0 kerberos: can't get local name: %s\n", krb_get_err_text(status)); - exit (1); - } - - pw = getpwnam (user); - if (pw == NULL) - { - printf ("E Fatal error, aborting.\n\ -error 0 %s: no such user\n", user); - exit (1); - } - - initgroups (pw->pw_name, pw->pw_gid); - setgid (pw->pw_gid); - setuid (pw->pw_uid); - /* Inhibit access by randoms. Don't want people randomly - changing our temporary tree before we check things in. */ - umask (077); - -#if HAVE_PUTENV - /* Set LOGNAME and USER in the environment, in case they are - already set to something else. */ - { - char *env; - - env = xmalloc (sizeof "LOGNAME=" + strlen (user)); - (void) sprintf (env, "LOGNAME=%s", user); - (void) putenv (env); - - env = xmalloc (sizeof "USER=" + strlen (user)); - (void) sprintf (env, "USER=%s", user); - (void) putenv (env); - } -#endif - - /* Pretend we were invoked as a plain server. */ - argv[0] = "server"; - } -#endif /* HAVE_KERBEROS */ - - -#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT) - if (strcmp (argv[0], "pserver") == 0) - { - /* Gets username and password from client, authenticates, then - switches to run as that user and sends an ACK back to the - client. */ - authenticate_connection (); - - /* Pretend we were invoked as a plain server. */ - argv[0] = "server"; - } -#endif /* AUTH_SERVER_SUPPORT && SERVER_SUPPORT */ - - -#ifdef CVSADM_ROOT - /* - * See if we are able to find a 'better' value for CVSroot in the - * CVSADM_ROOT directory. - */ -#ifdef SERVER_SUPPORT - if (strcmp (argv[0], "server") == 0 && CVSroot == NULL) - CVSADM_Root = NULL; - else - CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); -#else /* No SERVER_SUPPORT */ - CVSADM_Root = Name_Root((char *) NULL, (char *) NULL); -#endif /* No SERVER_SUPPORT */ - if (CVSADM_Root != NULL) - { - if (CVSroot == NULL || !cvs_update_env) - { - CVSroot = CVSADM_Root; - cvs_update_env = 1; /* need to update environment */ - } -#ifdef CLIENT_SUPPORT - else if (!getenv ("CVS_IGNORE_REMOTE_ROOT")) -#else - else -#endif - { - /* - * Now for the hard part, compare the two directories. If they - * are not identical, then abort this command. - */ - if ((fncmp (CVSroot, CVSADM_Root) != 0) && - !same_directories(CVSroot, CVSADM_Root)) - { - error (0, 0, "%s value for CVS Root found in %s", - CVSADM_Root, CVSADM_ROOT); - error (0, 0, "does not match command line -d %s setting", - CVSroot); - error (1, 0, - "you may wish to try the cvs command again without the -d option "); - } - } - } -#endif /* CVSADM_ROOT */ - - /* - * Specifying just the '-H' flag to the sub-command causes a Usage - * message to be displayed. - */ - command_name = cp = argv[0]; - if (help == TRUE || (argc > 1 && strcmp (argv[1], "-H") == 0)) - argc = -1; - else - { - /* - * Check to see if we can write into the history file. If not, - * we assume that we can't work in the repository. - * BUT, only if the history file exists. - */ -#ifdef SERVER_SUPPORT - if (strcmp (command_name, "server") != 0 || CVSroot != NULL) -#endif - { - char path[PATH_MAX]; - int save_errno; - - if (!CVSroot || !*CVSroot) - error (1, 0, "You don't have a %s environment variable", - CVSROOT_ENV); - (void) sprintf (path, "%s/%s", CVSroot, CVSROOTADM); - if (!isaccessible (path, R_OK | X_OK)) - { - save_errno = errno; -#ifdef CLIENT_SUPPORT - if (strchr (CVSroot, ':') == NULL) - { -#endif - error (0, 0, - "Sorry, you don't have sufficient access to %s", CVSroot); - error (1, save_errno, "%s", path); -#ifdef CLIENT_SUPPORT - } -#endif - } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (isfile (path) && !isaccessible (path, R_OK | W_OK)) - { - save_errno = errno; - error (0, 0, - "Sorry, you don't have read/write access to the history file"); - error (1, save_errno, "%s", path); - } - } - } - -#ifdef SERVER_SUPPORT - if (strcmp (command_name, "server") == 0) - /* This is only used for writing into the history file. Might - be nice to have hostname and/or remote path, on the other hand - I'm not sure whether it is worth the trouble. */ - strcpy (CurDir, "<remote>"); - else if (!getwd (CurDir)) - error (1, 0, "cannot get working directory: %s", CurDir); -#endif - -#ifdef HAVE_PUTENV - /* Now, see if we should update the environment with the Rcsbin value */ - if (cvs_update_env) - { - char *env; - - env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1); - (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot); - (void) putenv (env); - /* do not free env, as putenv has control of it */ - } - if (rcsbin_update_env) - { - char *env; - - env = xmalloc (strlen (RCSBIN_ENV) + strlen (Rcsbin) + 1 + 1); - (void) sprintf (env, "%s=%s", RCSBIN_ENV, Rcsbin); - (void) putenv (env); - /* do not free env, as putenv has control of it */ - } -#endif - - /* - * If Rcsbin is set to something, make sure it is terminated with - * a slash character. If not, add one. - */ - if (*Rcsbin) - { - int len = strlen (Rcsbin); - char *rcsbin; - - if (Rcsbin[len - 1] != '/') - { - rcsbin = Rcsbin; - Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */ - (void) strcpy (Rcsbin, rcsbin); - (void) strcat (Rcsbin, "/"); - } - } - - for (cm = cmds; cm->fullname; cm++) - { - if (cm->nick1 && !strcmp (cp, cm->nick1)) - break; - if (cm->nick2 && !strcmp (cp, cm->nick2)) - break; - if (!strcmp (cp, cm->fullname)) - break; - } - - if (!cm->fullname) - usage (usg); /* no match */ - else - { - command_name = cm->fullname; /* Global pointer for later use */ - - /* make sure we clean up on error */ -#ifdef SIGHUP - (void) SIG_register (SIGHUP, main_cleanup); - (void) SIG_register (SIGHUP, Lock_Cleanup); -#endif -#ifdef SIGINT - (void) SIG_register (SIGINT, main_cleanup); - (void) SIG_register (SIGINT, Lock_Cleanup); -#endif -#ifdef SIGQUIT - (void) SIG_register (SIGQUIT, main_cleanup); - (void) SIG_register (SIGQUIT, Lock_Cleanup); -#endif -#ifdef SIGPIPE - (void) SIG_register (SIGPIPE, main_cleanup); - (void) SIG_register (SIGPIPE, Lock_Cleanup); -#endif -#ifdef SIGTERM - (void) SIG_register (SIGTERM, main_cleanup); - (void) SIG_register (SIGTERM, Lock_Cleanup); -#endif - - gethostname(hostname, sizeof (hostname)); - -#ifdef HAVE_SETVBUF - /* - * Make stdout line buffered, so 'tail -f' can monitor progress. - * Patch creates too much output to monitor and it runs slowly. - */ - if (strcmp (cm->fullname, "patch")) - (void) setvbuf (stdout, (char *) NULL, _IOLBF, 0); -#endif - - if (use_cvsrc) - read_cvsrc(&argc, &argv); - -#ifdef CLIENT_SUPPORT - /* If cvsroot contains a colon, try to do it via the protocol. */ - { - char *p = CVSroot == NULL ? NULL : strchr (CVSroot, ':'); - if (p) - err = (*(cm->client_func)) (argc, argv); - else - err = (*(cm->func)) (argc, argv); - } -#else /* No CLIENT_SUPPORT */ - err = (*(cm->func)) (argc, argv); - -#endif /* No CLIENT_SUPPORT */ - } - /* - * If the command's error count is modulo 256, we need to change it - * so that we don't overflow the 8-bits we get to report exit status - */ - if (err && (err % 256) == 0) - err = 1; - Lock_Cleanup (); - return (err); -} - -char * -Make_Date (rawdate) - char *rawdate; -{ - struct tm *ftm; - time_t unixtime; - char date[256]; /* XXX bigger than we'll ever need? */ - char *ret; - - unixtime = get_date (rawdate, (struct timeb *) NULL); - if (unixtime == (time_t) - 1) - error (1, 0, "Can't parse date/time: %s", rawdate); -#ifdef HAVE_RCS5 - ftm = gmtime (&unixtime); -#else - ftm = localtime (&unixtime); -#endif - (void) sprintf (date, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); - ret = xstrdup (date); - return (ret); -} - -void -usage (cpp) - register const char *const *cpp; -{ - (void) fprintf (stderr, *cpp++, program_name, command_name); - for (; *cpp; cpp++) - (void) fprintf (stderr, *cpp); - exit (1); -} diff --git a/gnu/usr.bin/cvs/cvs/modules.c b/gnu/usr.bin/cvs/cvs/modules.c deleted file mode 100644 index 5946052..0000000 --- a/gnu/usr.bin/cvs/cvs/modules.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - * 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. - * - * Modules - * - * Functions for accessing the modules file. - * - * The modules file supports basically three formats of lines: - * key [options] directory files... [ -x directory [files] ] ... - * key [options] directory [ -x directory [files] ] ... - * key -a aliases... - * - * The -a option allows an aliasing step in the parsing of the modules - * file. The "aliases" listed on a line following the -a are - * processed one-by-one, as if they were specified as arguments on the - * command line. - */ - -#include "cvs.h" -#include "save-cwd.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)modules.c 1.62 94/09/29 $"; -USE(rcsid); -#endif - -struct sortrec -{ - char *modname; - char *status; - char *rest; - char *comment; -}; - -static int sort_order PROTO((const PTR l, const PTR r)); -static void save_d PROTO((char *k, int ks, char *d, int ds)); - - -/* - * Open the modules file, and die if the CVSROOT environment variable - * was not set. If the modules file does not exist, that's fine, and - * a warning message is displayed and a NULL is returned. - */ -DBM * -open_module () -{ - char mfile[PATH_MAX]; - - if (CVSroot == NULL) - { - (void) fprintf (stderr, - "%s: must set the CVSROOT environment variable\n", - program_name); - error (1, 0, "or specify the '-d' option to %s", program_name); - } - (void) sprintf (mfile, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_MODULES); - return (dbm_open (mfile, O_RDONLY, 0666)); -} - -/* - * Close the modules file, if the open succeeded, that is - */ -void -close_module (db) - DBM *db; -{ - if (db != NULL) - dbm_close (db); -} - -/* - * This is the recursive function that processes a module name. - * It calls back the passed routine for each directory of a module - * It runs the post checkout or post tag proc from the modules file - */ -int -do_module (db, mname, m_type, msg, callback_proc, where, - shorten, local_specified, run_module_prog, extra_arg) - DBM *db; - char *mname; - enum mtype m_type; - char *msg; - CALLBACKPROC callback_proc; - char *where; - int shorten; - int local_specified; - int run_module_prog; - char *extra_arg; -{ - char *checkin_prog = NULL; - char *checkout_prog = NULL; - char *export_prog = NULL; - char *tag_prog = NULL; - char *update_prog = NULL; - struct saved_cwd cwd; - char line[MAXLINELEN]; - 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 alias = 0; - datum key, val; - char *cp; - int c, err = 0; - -#ifdef SERVER_SUPPORT - if (trace) - { - fprintf (stderr, "%c-> do_module (%s, %s, %s, %s)\n", - (server_active) ? 'S' : ' ', - mname, msg, where ? where : "", - extra_arg ? extra_arg : ""); - } -#endif - - /* remember where we start */ - if (save_cwd (&cwd)) - exit (1); - - /* if this is a directory to ignore, add it to that list */ - if (mname[0] == '!' && mname[1] != '\0') - { - ign_dir_add (mname+1); - return(err); - } - - /* strip extra stuff from the module name */ - strip_path (mname); - - /* - * Look up the module using the following scheme: - * 1) look for mname as a module name - * 2) look for mname as a directory - * 3) look for mname as a file - * 4) take mname up to the first slash and look it up as a module name - * (this is for checking out only part of a module) - */ - - /* look it up as a module name */ - key.dptr = mname; - key.dsize = strlen (key.dptr); - if (db != NULL) - val = dbm_fetch (db, key); - else - val.dptr = NULL; - if (val.dptr != NULL) - { - /* null terminate the value XXX - is this space ours? */ - val.dptr[val.dsize] = '\0'; - - /* If the line ends in a comment, strip it off */ - if ((cp = strchr (val.dptr, '#')) != NULL) - { - do - *cp-- = '\0'; - while (isspace (*cp)); - } - else - { - /* Always strip trailing spaces */ - cp = strchr (val.dptr, '\0'); - while (cp > val.dptr && isspace(*--cp)) - *cp = '\0'; - } - - value = val.dptr; - mwhere = xstrdup (mname); - goto found; - } - else - { - char file[PATH_MAX]; - char attic_file[PATH_MAX]; - char *acp; - - /* check to see if mname is a directory or file */ - - (void) sprintf (file, "%s/%s", CVSroot, mname); - if ((acp = strrchr (mname, '/')) != NULL) - { - *acp = '\0'; - (void) sprintf (attic_file, "%s/%s/%s/%s%s", CVSroot, mname, - CVSATTIC, acp + 1, RCSEXT); - *acp = '/'; - } - else - (void) sprintf (attic_file, "%s/%s/%s%s", CVSroot, CVSATTIC, - mname, RCSEXT); - - if (isdir (file)) - { - value = mname; - goto found; - } - else - { - (void) strcat (file, RCSEXT); - if (isfile (file) || isfile (attic_file)) - { - /* if mname was a file, we have to split it into "dir file" */ - if ((cp = strrchr (mname, '/')) != NULL && cp != mname) - { - char *slashp; - - /* put the ' ' in a copy so we don't mess up the original */ - value = strcpy (xvalue, mname); - slashp = strrchr (value, '/'); - *slashp = ' '; - } - else - { - /* - * the only '/' at the beginning or no '/' at all - * means the file we are interested in is in CVSROOT - * itself so the directory should be '.' - */ - if (cp == mname) - { - /* drop the leading / if specified */ - value = strcpy (xvalue, ". "); - (void) strcat (xvalue, mname + 1); - } - else - { - /* otherwise just copy it */ - value = strcpy (xvalue, ". "); - (void) strcat (xvalue, mname); - } - } - goto found; - } - } - } - - /* look up everything to the first / as a module */ - if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL) - { - /* Make the slash the new end of the string temporarily */ - *cp = '\0'; - key.dptr = mname; - key.dsize = strlen (key.dptr); - - /* do the lookup */ - if (db != NULL) - val = dbm_fetch (db, key); - else - val.dptr = NULL; - - /* if we found it, clean up the value and life is good */ - if (val.dptr != NULL) - { - char *cp2; - - /* null terminate the value XXX - is this space ours? */ - val.dptr[val.dsize] = '\0'; - - /* If the line ends in a comment, strip it off */ - if ((cp2 = strchr (val.dptr, '#')) != NULL) - { - do - *cp2-- = '\0'; - while (isspace (*cp2)); - } - value = val.dptr; - - /* mwhere gets just the module name */ - mwhere = xstrdup (mname); - mfile = cp + 1; - - /* put the / back in mname */ - *cp = '/'; - - goto found; - } - - /* put the / back in mname */ - *cp = '/'; - } - - /* if we got here, we couldn't find it using our search, so give up */ - error (0, 0, "cannot find module `%s' - ignored", mname); - err++; - if (mwhere) - free (mwhere); - return (err); - - - /* - * At this point, we found what we were looking for in one - * of the many different forms. - */ - found: - - /* copy value to our own string since if we go recursive we'll be - really screwed if we do another dbm lookup */ - zvalue = xstrdup (value); - value = zvalue; - - /* search the value for the special delimiter and save for later */ - if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL) - { - *cp = '\0'; /* null out the special char */ - spec_opt = cp + 1; /* save the options for later */ - - if (cp != value) /* strip whitespace if necessary */ - while (isspace (*--cp)) - *cp = '\0'; - - if (cp == value) - { - /* - * we had nothing but special options, so skip arg - * parsing and regular stuff entirely - * - * If there were only special ones though, we must - * make the appropriate directory and cd to it - */ - char *dir; - - /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to - be !pipeout, but we don't know that here yet */ - if (!run_module_prog) - goto out; - - dir = where ? where : mname; - /* XXX - think about making null repositories at each dir here - instead of just at the bottom */ - make_directories (dir); - if (chdir (dir) < 0) - { - error (0, errno, "cannot chdir to %s", dir); - spec_opt = NULL; - err++; - goto out; - } - if (!isfile (CVSADM)) - { - char nullrepos[PATH_MAX]; - - (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); - - Create_Admin (".", dir, - nullrepos, (char *) NULL, (char *) NULL); - if (!noexec) - { - FILE *fp; - - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_entstat (dir, nullrepos); -#endif - } - } - out: - goto do_special; - } - } - - /* don't do special options only part of a module was specified */ - if (mfile != NULL) - spec_opt = NULL; - - /* - * value now contains one of the following: - * 1) dir - * 2) dir file - * 3) the value from modules without any special args - * [ args ] dir [file] [file] ... - * or -a module [ module ] ... - */ - - /* Put the value on a line with XXX prepended for getopt to eat */ - (void) sprintf (line, "%s %s", "XXX", value); - - /* turn the line into an argv[] array */ - line2argv (&xmodargc, xmodargv, line); - modargc = xmodargc; - modargv = xmodargv; - - /* parse the args */ - optind = 1; - while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1) - { - switch (c) - { - case 'a': - alias = 1; - break; - case 'd': - if (mwhere) - free (mwhere); - mwhere = xstrdup (optarg); - break; - case 'i': - checkin_prog = optarg; - break; - case 'l': - local_specified = 1; - case 'o': - checkout_prog = optarg; - break; - case 'e': - export_prog = optarg; - break; - case 't': - tag_prog = optarg; - break; - case 'u': - update_prog = optarg; - break; - case '?': - error (0, 0, - "modules file has invalid option for key %s value %s", - key.dptr, val.dptr); - err++; - if (mwhere) - free (mwhere); - free (zvalue); - return (err); - } - } - modargc -= optind; - modargv += optind; - if (modargc == 0) - { - error (0, 0, "modules file missing directory for module %s", mname); - if (mwhere) - free (mwhere); - free (zvalue); - return (++err); - } - - /* if this was an alias, call ourselves recursively for each module */ - if (alias) - { - int i; - - for (i = 0; i < modargc; i++) - { - if (strcmp (mname, modargv[i]) == 0) - error (0, 0, - "module `%s' in modules file contains infinite loop", - mname); - else - err += do_module (db, modargv[i], m_type, msg, callback_proc, - where, shorten, local_specified, - run_module_prog, extra_arg); - } - if (mwhere) - free (mwhere); - free (zvalue); - return (err); - } - - /* otherwise, process this module */ - err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten, - local_specified, mname, msg); - -#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 */ - - do_special: - - /* blow off special options if -l was specified */ - if (local_specified) - spec_opt = NULL; - - while (spec_opt != NULL) - { - char *next_opt; - - cp = strchr (spec_opt, CVSMODULE_SPEC); - if (cp != NULL) - { - /* save the beginning of the next arg */ - next_opt = cp + 1; - - /* strip whitespace off the end */ - do - *cp = '\0'; - while (isspace (*--cp)); - } - else - next_opt = NULL; - - /* strip whitespace from front */ - while (isspace (*spec_opt)) - spec_opt++; - - if (*spec_opt == '\0') - error (0, 0, "Mal-formed %c option for module %s - ignored", - CVSMODULE_SPEC, mname); - else - err += do_module (db, spec_opt, m_type, msg, callback_proc, - (char *) NULL, 0, local_specified, - run_module_prog, extra_arg); - spec_opt = next_opt; - } - - /* write out the checkin/update prog files if necessary */ -#ifdef SERVER_SUPPORT - if (err == 0 && !noexec && m_type == CHECKOUT && server_expanding) - { - if (checkin_prog != NULL) - server_prog (where ? where : mname, checkin_prog, PROG_CHECKIN); - if (update_prog != NULL) - server_prog (where ? where : mname, update_prog, PROG_UPDATE); - } - else -#endif - if (err == 0 && !noexec && m_type == CHECKOUT && run_module_prog) - { - FILE *fp; - - if (checkin_prog != NULL) - { - fp = open_file (CVSADM_CIPROG, "w+"); - (void) fprintf (fp, "%s\n", checkin_prog); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_CIPROG); - } - if (update_prog != NULL) - { - fp = open_file (CVSADM_UPROG, "w+"); - (void) fprintf (fp, "%s\n", update_prog); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_UPROG); - } - } - - /* cd back to where we started */ - if (restore_cwd (&cwd, NULL)) - exit (1); - free_cwd (&cwd); - - /* run checkout or tag prog if appropriate */ - if (err == 0 && run_module_prog) - { - if ((m_type == TAG && tag_prog != NULL) || - (m_type == CHECKOUT && checkout_prog != NULL) || - (m_type == EXPORT && export_prog != NULL)) - { - /* - * If a relative pathname is specified as the checkout, tag - * or export proc, try to tack on the current "where" value. - * if we can't find a matching program, just punt and use - * whatever is specified in the modules file. - */ - char real_prog[PATH_MAX]; - char *prog = (m_type == TAG ? tag_prog : - (m_type == CHECKOUT ? checkout_prog : export_prog)); - char *real_where = (where != NULL ? where : mwhere); - - if ((*prog != '/') && (*prog != '.')) - { - (void) sprintf (real_prog, "%s/%s", real_where, prog); - if (isfile (real_prog)) - prog = real_prog; - } - - run_setup ("%s %s", prog, real_where); - if (extra_arg) - run_arg (extra_arg); - - if (!quiet) - { - (void) printf ("%s %s: Executing '", program_name, - command_name); - run_print (stdout); - (void) printf ("'\n"); - } - err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - } - - /* clean up */ - if (mwhere) - free (mwhere); - free (zvalue); - - return (err); -} - -/* - Read all the records from the modules database into an array. - - Sort the array depending on what format is desired. - - Print the array in the format desired. - - Currently, there are only two "desires": - - 1. Sort by module name and format the whole entry including switches, - files and the comment field: (Including aliases) - - modulename -s switches, one per line, even if - -i it has many switches. - Directories and files involved, formatted - to cover multiple lines if necessary. - # Comment, also formatted to cover multiple - # lines if necessary. - - 2. Sort by status field string and print: (*not* including aliases) - - modulename STATUS Directories and files involved, formatted - to cover multiple lines if necessary. - # Comment, also formatted to cover multiple - # lines if necessary. -*/ - -static struct sortrec *s_head; - -static int s_max = 0; /* Number of elements allocated */ -static int s_count = 0; /* Number of elements used */ - -static int Status; /* Nonzero if the user is - interested in status - information as well as - module name */ -static char def_status[] = "NONE"; - -/* Sort routine for qsort: - - If we want the "Status" field to be sorted, check it first. - - Then compare the "module name" fields. Since they are unique, we don't - have to look further. -*/ -static int -sort_order (l, r) - const PTR l; - const PTR r; -{ - int i; - const struct sortrec *left = (const struct sortrec *) l; - const struct sortrec *right = (const struct sortrec *) r; - - if (Status) - { - /* If Sort by status field, compare them. */ - if ((i = strcmp (left->status, right->status)) != 0) - return (i); - } - return (strcmp (left->modname, right->modname)); -} - -static void -save_d (k, ks, d, ds) - char *k; - int ks; - char *d; - int ds; -{ - char *cp, *cp2; - struct sortrec *s_rec; - - if (Status && *d == '-' && *(d + 1) == 'a') - return; /* We want "cvs co -s" and it is an alias! */ - - if (s_count == s_max) - { - s_max += 64; - s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head)); - } - s_rec = &s_head[s_count]; - s_rec->modname = cp = xmalloc (ks + 1); - (void) strncpy (cp, k, ks); - *(cp + ks) = '\0'; - - s_rec->rest = cp2 = xmalloc (ds + 1); - cp = d; - *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */ - - while (isspace (*cp)) - cp++; - /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */ - while (*cp) - { - if (isspace (*cp)) - { - *cp2++ = ' '; - while (isspace (*cp)) - cp++; - } - else - *cp2++ = *cp++; - } - *cp2 = '\0'; - - /* Look for the "-s statusvalue" text */ - if (Status) - { - s_rec->status = def_status; - - /* Minor kluge, but general enough to maintain */ - for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2) - { - if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ') - { - s_rec->status = (cp2 += 3); - while (*cp2 != ' ') - cp2++; - *cp2++ = '\0'; - cp = cp2; - break; - } - } - } - else - cp = s_rec->rest; - - /* Find comment field, clean up on all three sides & compress blanks */ - if ((cp2 = cp = strchr (cp, '#')) != NULL) - { - if (*--cp2 == ' ') - *cp2 = '\0'; - if (*++cp == ' ') - cp++; - s_rec->comment = cp; - } - else - s_rec->comment = ""; - - s_count++; -} - -/* Print out the module database as we know it. If STATUS is - non-zero, print out status information for each module. */ - -void -cat_module (status) - int status; -{ - DBM *db; - datum key, val; - int i, c, wid, argc, cols = 80, indent, fill; - int moduleargc; - struct sortrec *s_h; - char *cp, *cp2, **argv; - char line[MAXLINELEN], *moduleargv[MAXFILEPERDIR]; - -#ifdef sun -#ifdef TIOCGSIZE - struct ttysize ts; - - (void) ioctl (0, TIOCGSIZE, &ts); - cols = ts.ts_cols; -#endif -#else -#ifdef TIOCGWINSZ - struct winsize ws; - - (void) ioctl (0, TIOCGWINSZ, &ws); - cols = ws.ws_col; -#endif -#endif - - Status = status; - - /* Read the whole modules file into allocated records */ - if (!(db = open_module ())) - error (1, 0, "failed to open the modules file"); - - for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db)) - { - val = dbm_fetch (db, key); - if (val.dptr != NULL) - save_d (key.dptr, key.dsize, val.dptr, val.dsize); - } - - /* Sort the list as requested */ - qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order); - - /* - * Run through the sorted array and format the entries - * indent = space for modulename + space for status field - */ - indent = 12 + (status * 12); - fill = cols - (indent + 2); - for (s_h = s_head, i = 0; i < s_count; i++, s_h++) - { - /* Print module name (and status, if wanted) */ - (void) printf ("%-12s", s_h->modname); - if (status) - { - (void) printf (" %-11s", s_h->status); - if (s_h->status != def_status) - *(s_h->status + strlen (s_h->status)) = ' '; - } - - /* Parse module file entry as command line and print options */ - (void) sprintf (line, "%s %s", s_h->modname, s_h->rest); - line2argv (&moduleargc, moduleargv, line); - argc = moduleargc; - argv = moduleargv; - - optind = 0; - wid = 0; - while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1) - { - if (!status) - { - if (c == 'a' || c == 'l') - { - (void) printf (" -%c", c); - wid += 3; /* Could just set it to 3 */ - } - else - { - if (strlen (optarg) + 4 + wid > (unsigned) fill) - { - (void) printf ("\n%*s", indent, ""); - wid = 0; - } - (void) printf (" -%c %s", c, optarg); - wid += strlen (optarg) + 4; - } - } - } - argc -= optind; - argv += optind; - - /* Format and Print all the files and directories */ - for (; argc--; argv++) - { - if (strlen (*argv) + wid > (unsigned) fill) - { - (void) printf ("\n%*s", indent, ""); - wid = 0; - } - (void) printf (" %s", *argv); - wid += strlen (*argv) + 1; - } - (void) printf ("\n"); - - /* Format the comment field -- save_d (), compressed spaces */ - for (cp2 = cp = s_h->comment; *cp; cp2 = cp) - { - (void) printf ("%*s # ", indent, ""); - if (strlen (cp2) < (unsigned) (fill - 2)) - { - (void) printf ("%s\n", cp2); - break; - } - cp += fill - 2; - while (*cp != ' ' && cp > cp2) - cp--; - if (cp == cp2) - { - (void) printf ("%s\n", cp2); - break; - } - - *cp++ = '\0'; - (void) printf ("%s\n", cp2); - } - - free_names(&moduleargc, moduleargv); - } -} diff --git a/gnu/usr.bin/cvs/cvs/no_diff.c b/gnu/usr.bin/cvs/cvs/no_diff.c deleted file mode 100644 index 281d348..0000000 --- a/gnu/usr.bin/cvs/cvs/no_diff.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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. - * - * No Difference - * - * The user file looks modified judging from its time stamp; however it needn't - * be. No_difference() finds out whether it is or not. If it is not, it - * updates the administration. - * - * returns 0 if no differences are found and non-zero otherwise - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)no_diff.c 1.39 94/10/07 $"; -USE(rcsid); -#endif - -int -No_Difference (file, vers, entries, repository, update_dir) - char *file; - Vers_TS *vers; - List *entries; - char *repository; - char *update_dir; -{ - Node *p; - char tmp[L_tmpnam+1]; - int ret; - char *ts, *options; - int retcode = 0; - char *tocvsPath; - - if (!vers->srcfile || !vers->srcfile->path) - return (-1); /* different since we couldn't tell */ - - if (vers->entdata && vers->entdata->options) - options = xstrdup (vers->entdata->options); - else - options = xstrdup (""); - - run_setup ("%s%s -p -q -r%s %s", Rcsbin, RCS_CO, - vers->vn_user ? vers->vn_user : "", options); - run_arg (vers->srcfile->path); - if ((retcode = run_exec (RUN_TTY, tmpnam (tmp), RUN_TTY, RUN_REALLY)) == 0) - { -#if 0 - /* Why would we want to munge the modes? And only if the timestamps - are different? And even for commands like "cvs status"???? */ - if (!iswritable (file)) /* fix the modes as a side effect */ - xchmod (file, 1); -#endif - - tocvsPath = wrap_tocvs_process_file (file); - - /* do the byte by byte compare */ - if (xcmp (tocvsPath == NULL ? file : tocvsPath, tmp) == 0) - { -#if 0 - /* Why would we want to munge the modes? And only if the - timestamps are different? And even for commands like - "cvs status"???? */ - if (cvswrite == FALSE) /* fix the modes as a side effect */ - xchmod (file, 0); -#endif - - /* no difference was found, so fix the entries file */ - ts = time_stamp (file); - Register (entries, file, - vers->vn_user ? vers->vn_user : vers->vn_rcs, ts, - options, vers->tag, vers->date, (char *) 0); -#ifdef SERVER_SUPPORT - if (server_active) - { - /* We need to update the entries line on the client side. */ - server_update_entries - (file, update_dir, repository, SERVER_UPDATED); - } -#endif - free (ts); - - /* update the entdata pointer in the vers_ts structure */ - p = findnode (entries, file); - vers->entdata = (Entnode *) p->data; - - ret = 0; - } - else - ret = 1; /* files were really different */ - if (tocvsPath) - { - /* Need to call unlink myself because the noexec variable - * has been set to 1. */ - if (trace) - (void) fprintf (stderr, "%c-> unlink (%s)\n", -#ifdef SERVER_SUPPORT - (server_active) ? 'S' : ' ', -#else - ' ', -#endif - tocvsPath); - if (unlink (tocvsPath) < 0) - error (0, errno, "could not remove %s", tocvsPath); - } - } - else - { - if (update_dir[0] == '\0') - error (0, retcode == -1 ? errno : 0, - "could not check out revision %s of %s", - vers->vn_user, file); - else - error (0, retcode == -1 ? errno : 0, - "could not check out revision %s of %s/%s", - vers->vn_user, update_dir, file); - ret = -1; /* different since we couldn't tell */ - } - - if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> unlink2 (%s)\n", - (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); - return (ret); -} diff --git a/gnu/usr.bin/cvs/cvs/options.h b/gnu/usr.bin/cvs/cvs/options.h index 9944653..b917063 100644 --- a/gnu/usr.bin/cvs/cvs/options.h +++ b/gnu/usr.bin/cvs/cvs/options.h @@ -1,3 +1,4 @@ +/* src/options.h. Generated automatically by configure. */ /* * Copyright (c) 1992, Brian Berliner and Jeff Polk * Copyright (c) 1989-1992, Brian Berliner @@ -54,9 +55,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,7 +66,7 @@ */ #ifndef DIFF -#define DIFF "/usr/bin/diff -a" +#define DIFF "diff" #endif /* @@ -80,23 +81,6 @@ #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. @@ -114,8 +98,23 @@ * 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. + * If you use the password-authenticating server, then you need to + * make sure that the server can find the RCS programs to invoke them. + * The authenticating server starts out running as root, and then + * switches to run as the appropriate user once authentication is + * complete. But no actual 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. + * + * One way to solve this problem is to set RCSBIN_DFLT here. An + * alternative 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. */ #ifndef RCSBIN_DFLT #define RCSBIN_DFLT "" @@ -212,19 +211,6 @@ #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 * cpp-style #define's around the output differences. CVS, by default, uses @@ -236,20 +222,24 @@ #define CVS_DIFFDATE #endif -/* - * define this to enable the SETXID support (see FAQ 4D.13) - */ +/* Define this to enable the SETXID support. The way to use this is + to create a group with no users in it (except perhaps cvs + administrators), set the cvs executable to setgid that group, chown + all the repository files to that group, and change all directory + permissions in the repository to 770. The last person to modify a + file will own it, but as long as directory permissions are set + right that won't matter. You'll need a system which inherits file + groups from the parent directory. I don't know how carefully this + has been inspected for security holes. */ + #ifndef SETXID_SUPPORT /* #define SETXID_SUPPORT */ #endif -/* - * The authenticated client/server is under construction. Don't - * define either of these unless you're testing them, in which case - * you're me and you already know that. - */ -/* #undef AUTH_CLIENT_SUPPORT */ -/* #undef AUTH_SERVER_SUPPORT */ +/* Should we build the password-authenticating client? Whether to + include the password-authenticating _server_, on the other hand, is + set in config.h. */ +#define AUTH_CLIENT_SUPPORT 1 /* * If you are working with a large remote repository and a 'cvs checkout' is @@ -265,9 +255,9 @@ * 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) +#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/cvs/parseinfo.c b/gnu/usr.bin/cvs/cvs/parseinfo.c deleted file mode 100644 index 6d59884..0000000 --- a/gnu/usr.bin/cvs/cvs/parseinfo.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)parseinfo.c 1.18 94/09/23 $"; -USE(rcsid); -#endif - -/* - * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for - * the first line in the file that matches the REPOSITORY, or if ALL != 0, any lines - * matching "ALL", or if no lines match, the last line matching "DEFAULT". - * - * Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure. - */ -int -Parse_Info (infofile, repository, callproc, all) - char *infofile; - char *repository; - CALLPROC callproc; - int all; -{ - int err = 0; - FILE *fp_info; - 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; - - if (CVSroot == NULL) - { - /* XXX - should be error maybe? */ - error (0, 0, "CVSROOT variable not set"); - return (1); - } - - /* find the info file and open it */ - (void) sprintf (infopath, "%s/%s/%s", CVSroot, - CVSROOTADM, infofile); - if ((fp_info = fopen (infopath, "r")) == NULL) - return (0); /* no file -> nothing special done */ - - /* strip off the CVSROOT if repository was absolute */ - srepos = Short_Repository (repository); - - if (trace) - (void) fprintf (stderr, "-> ParseInfo(%s, %s, %s)\n", - infopath, srepos, all ? "ALL" : "not ALL"); - - /* search the info file for lines that match */ - callback_done = line_number = 0; - while (fgets (line, sizeof (line), fp_info) != NULL) - { - line_number++; - - /* skip lines starting with # */ - if (line[0] == '#') - continue; - - /* skip whitespace at beginning of line */ - for (cp = line; *cp && isspace (*cp); cp++) - ; - - /* if *cp is null, the whole line was blank */ - if (*cp == '\0') - continue; - - /* the regular expression is everything up to the first space */ - for (exp = cp; *cp && !isspace (*cp); cp++) - ; - if (*cp != '\0') - *cp++ = '\0'; - - /* skip whitespace up to the start of the matching value */ - while (*cp && isspace (*cp)) - cp++; - - /* no value to match with the regular expression is an error */ - if (*cp == '\0') - { - error (0, 0, "syntax error at line %d file %s; ignored", - line_number, infofile); - continue; - } - value = cp; - - /* strip the newline off the end of the value */ - if ((cp = strrchr (value, '\n')) != NULL) - *cp = '\0'; - - expanded_value = expand_path (value); - if (!expanded_value) - { - error (0, 0, - "Invalid environmental variable at line %d in file %s", - line_number, infofile); - continue; - - } - - /* - * At this point, exp points to the regular expression, and value - * points to the value to call the callback routine with. Evaluate - * the regular expression against srepos and callback with the value - * if it matches. - */ - - /* save the default value so we have it later if we need it */ - if (strcmp (exp, "DEFAULT") == 0) - { - default_value = xstrdup (expanded_value); - continue; - } - - /* - * For a regular expression of "ALL", do the callback always We may - * execute lots of ALL callbacks in addition to *one* regular matching - * callback or default - */ - if (strcmp (exp, "ALL") == 0) - { - if (all) - err += callproc (repository, expanded_value); - else - error(0, 0, "Keyword `ALL' is ignored at line %d in %s file", - line_number, infofile); - continue; - } - - if (callback_done) - /* only first matching, plus "ALL"'s */ - continue; - - /* see if the repository matched this regular expression */ - if ((regex_err = re_comp (exp)) != NULL) - { - error (0, 0, "bad regular expression at line %d file %s: %s", - line_number, infofile, regex_err); - continue; - } - if (re_exec (srepos) == 0) - continue; /* no match */ - - /* it did, so do the callback and note that we did one */ - err += callproc (repository, expanded_value); - callback_done = 1; - } - (void) fclose (fp_info); - - /* if we fell through and didn't callback at all, do the default */ - if (callback_done == 0 && default_value != NULL) - err += callproc (repository, default_value); - - /* 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/cvs/patch.c b/gnu/usr.bin/cvs/cvs/patch.c deleted file mode 100644 index 560f4b4..0000000 --- a/gnu/usr.bin/cvs/cvs/patch.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * 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. - * - * Patch - * - * Create a Larry Wall format "patch" file between a previous release and the - * current head of a module, or between two releases. Can specify the - * release as either a date or a revision number. - */ - -#include "cvs.h" -#include "getline.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)patch.c 1.57 94/09/30 $"; -USE(rcsid); -#endif - -static RETSIGTYPE patch_cleanup PROTO((void)); -static Dtype patch_dirproc PROTO((char *dir, char *repos, char *update_dir)); -static int patch_fileproc PROTO((char *file, char *update_dir, char *repository, - List * entries, List * srcfiles)); -static int patch_proc PROTO((int *pargc, char **argv, char *xwhere, - char *mwhere, char *mfile, int shorten, - int local_specified, char *mname, char *msg)); - -static int force_tag_match = 1; -static int patch_short = 0; -static int toptwo_diffs = 0; -static int local = 0; -static char *options = NULL; -static char *rev1 = NULL; -static char *rev2 = NULL; -static char *date1 = NULL; -static char *date2 = NULL; -static char tmpfile1[L_tmpnam+1], tmpfile2[L_tmpnam+1], tmpfile3[L_tmpnam+1]; -static int unidiff = 0; - -static const char *const patch_usage[] = -{ - "Usage: %s %s [-fl] [-c|-u] [-s|-t] [-V %%d]\n", - " -r rev|-D date [-r rev2 | -D date2] modules...\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-c\tContext diffs (default)\n", - "\t-u\tUnidiff format.\n", - "\t-s\tShort patch - one liner per file.\n", - "\t-t\tTop two diffs - last change made to the file.\n", - "\t-D date\tDate.\n", - "\t-r rev\tRevision - symbolic or numeric.\n", - "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n", - NULL -}; - -int -patch (argc, argv) - int argc; - char **argv; -{ - register int i; - int c; - int err = 0; - DBM *db; - - if (argc == -1) - usage (patch_usage); - - optind = 1; - while ((c = getopt (argc, argv, "V:k:cuftsQqlRD:r:")) != -1) - { - switch (c) - { - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'f': - force_tag_match = 0; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 't': - toptwo_diffs = 1; - break; - case 's': - patch_short = 1; - break; - case 'D': - if (rev2 != NULL || date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (rev1 != NULL || date1 != NULL) - date2 = Make_Date (optarg); - else - date1 = Make_Date (optarg); - break; - case 'r': - if (rev2 != NULL || date2 != NULL) - error (1, 0, - "no more than two revisions/dates can be specified"); - if (rev1 != NULL || date1 != NULL) - rev2 = optarg; - else - rev1 = optarg; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'V': - if (atoi (optarg) <= 0) - error (1, 0, "must specify a version number to -V"); - if (options) - free (options); - options = xmalloc (strlen (optarg) + 1 + 2); /* for the -V */ - (void) sprintf (options, "-V%s", optarg); - break; - case 'u': - unidiff = 1; /* Unidiff */ - break; - case 'c': /* Context diff */ - unidiff = 0; - break; - case '?': - default: - usage (patch_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* Sanity checks */ - if (argc < 1) - usage (patch_usage); - - if (toptwo_diffs && patch_short) - error (1, 0, "-t and -s options are mutually exclusive"); - if (toptwo_diffs && (date1 != NULL || date2 != NULL || - rev1 != NULL || rev2 != NULL)) - error (1, 0, "must not specify revisions/dates with -t option!"); - - if (!toptwo_diffs && (date1 == NULL && date2 == NULL && - rev1 == NULL && rev2 == NULL)) - error (1, 0, "must specify at least one revision/date!"); - if (date1 != NULL && date2 != NULL) - if (RCS_datecmp (date1, date2) >= 0) - error (1, 0, "second date must come after first date!"); - - /* if options is NULL, make it a NULL string */ - if (options == NULL) - options = xstrdup (""); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (force_tag_match) - send_arg("-f"); - if (toptwo_diffs) - send_arg("-t"); - if (patch_short) - send_arg("-s"); - if (unidiff) - send_arg("-u"); - - if (rev1) - option_with_arg ("-r", rev1); - if (date1) - client_senddate (date1); - if (rev2) - option_with_arg ("-r", rev2); - if (date2) - client_senddate (date2); - if (options[0] != '\0') - send_arg (options); - - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - } - - if (fprintf (to_server, "rdiff\n") < 0) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } -#endif - - /* clean up if we get a signal */ -#ifdef SIGHUP - (void) SIG_register (SIGHUP, patch_cleanup); -#endif -#ifdef SIGINT - (void) SIG_register (SIGINT, patch_cleanup); -#endif -#ifdef SIGQUIT - (void) SIG_register (SIGQUIT, patch_cleanup); -#endif -#ifdef SIGPIPE - (void) SIG_register (SIGPIPE, patch_cleanup); -#endif -#ifdef SIGTERM - (void) SIG_register (SIGTERM, patch_cleanup); -#endif - - db = open_module (); - for (i = 0; i < argc; i++) - err += do_module (db, argv[i], PATCH, "Patching", patch_proc, - (char *) NULL, 0, 0, 0, (char *) NULL); - close_module (db); - free (options); - patch_cleanup (); - return (err); -} - -/* - * callback proc for doing the real work of patching - */ -/* ARGSUSED */ -static char where[PATH_MAX]; -static int -patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, - mname, msg) - int *pargc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *mname; - char *msg; -{ - int err = 0; - int which; - char repository[PATH_MAX]; - - (void) sprintf (repository, "%s/%s", CVSroot, argv[0]); - (void) strcpy (where, argv[0]); - - /* if mfile isn't null, we need to set up to do only part of the module */ - if (mfile != NULL) - { - char *cp; - char path[PATH_MAX]; - - /* if the portion of the module is a path, put the dir part on repos */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - (void) sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void) strcpy (repository, path); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - } - else - { - int i; - - /* a file means muck argv */ - for (i = 1; i < *pargc; i++) - free (argv[i]); - argv[1] = xstrdup (mfile); - (*pargc) = 2; - } - } - - /* cd to the starting repository */ - if (chdir (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - return (1); - } - - if (force_tag_match) - which = W_REPOS | W_ATTIC; - else - which = W_REPOS; - - /* start the recursion processor */ - err = start_recursion (patch_fileproc, (FILESDONEPROC) NULL, patch_dirproc, - (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local, - which, 0, 1, where, 1, 1); - - return (err); -} - -/* - * Called to examine a particular RCS file, as appropriate with the options - * that were set above. - */ -/* ARGSUSED */ -static int -patch_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - struct utimbuf t; - char *vers_tag, *vers_head; - char rcsspace[PATH_MAX]; - char *rcs = rcsspace; - Node *p; - RCSNode *rcsfile; - FILE *fp1, *fp2, *fp3; - int ret = 0; - int isattic = 0; - int retcode = 0; - char file1[PATH_MAX], file2[PATH_MAX], strippath[PATH_MAX]; - char *line1, *line2; - size_t line1_chars_allocated; - size_t line2_chars_allocated; - char *cp1, *cp2, *commap; - FILE *fp; - - /* find the parsed rcs file */ - p = findnode (srcfiles, file); - if (p == NULL) - return (1); - rcsfile = (RCSNode *) p->data; - if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) - isattic = 1; - - (void) sprintf (rcs, "%s%s", file, RCSEXT); - - /* if vers_head is NULL, may have been removed from the release */ - if (isattic && rev2 == NULL && date2 == NULL) - vers_head = NULL; - else - vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, 0); - - if (toptwo_diffs) - { - if (vers_head == NULL) - return (1); - - if (!date1) - date1 = xmalloc (50); /* plenty big :-) */ - *date1 = '\0'; - if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == -1) - { - if (!really_quiet) - error (0, 0, "cannot find date in rcs file %s revision %s", - rcs, vers_head); - return (1); - } - } - 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 */ - - if (vers_tag && vers_head && strcmp (vers_head, vers_tag) == 0) - return (0); /* not changed between releases */ - - if (patch_short) - { - (void) printf ("File "); - if (vers_tag == NULL) - (void) printf ("%s is new; current revision %s\n", rcs, vers_head); - else if (vers_head == NULL) -#ifdef DEATH_SUPPORT - { - (void) printf ("%s is removed; not included in ", rcs); - if (rev2 != NULL) - (void) printf ("release tag %s", rev2); - else if (date2 != NULL) - (void) printf ("release date %s", date2); - else - (void) printf ("current release"); - (void) printf ("\n"); - } -#else - (void) printf ("%s is removed; not included in release %s\n", - rcs, rev2 ? rev2 : date2); -#endif - else - (void) printf ("%s changed from revision %s to %s\n", - rcs, vers_tag, vers_head); - 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) - { - error (0, 0, "cannot create temporary files"); - ret = 1; - goto out; - } - if (vers_tag != NULL) - { - run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_tag); - run_arg (rcsfile->path); - if ((retcode = run_exec (RUN_TTY, tmpfile1, RUN_TTY, RUN_NORMAL)) != 0) - { - if (!really_quiet) - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "co of revision %s in %s failed", vers_tag, rcs); - ret = 1; - goto out; - } - memset ((char *) &t, 0, sizeof (t)); - if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag, - (char *) 0, 0)) != -1) - (void) utime (tmpfile1, &t); - } - else if (toptwo_diffs) - { - ret = 1; - goto out; - } - if (vers_head != NULL) - { - run_setup ("%s%s %s -p -q -r%s", Rcsbin, RCS_CO, options, vers_head); - run_arg (rcsfile->path); - if ((retcode = run_exec (RUN_TTY, tmpfile2, RUN_TTY, RUN_NORMAL)) != 0) - { - if (!really_quiet) - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "co of revision %s in %s failed", vers_head, rcs); - ret = 1; - goto out; - } - if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head, - (char *) 0, 0)) != -1) - (void) utime (tmpfile2, &t); - } - 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 */ - error (1, errno, "fork for diff failed on %s", rcs); - break; - case 0: /* nothing to do */ - break; - case 1: - /* - * The two revisions are really different, so read the first two - * lines of the diff output file, and munge them to include more - * reasonable file names that "patch" will understand. - */ - - /* Output an "Index:" line for patch to use */ - (void) fflush (stdout); - if (update_dir[0]) - (void) printf ("Index: %s/%s\n", update_dir, file); - else - (void) printf ("Index: %s\n", file); - (void) fflush (stdout); - - fp = open_file (tmpfile3, "r"); - 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); - ret = 1; - (void) fclose (fp); - goto out; - } - if (!unidiff) - { - if (strncmp (line1, "*** ", 4) != 0 || - strncmp (line2, "--- ", 4) != 0 || - (cp1 = strchr (line1, '\t')) == NULL || - (cp2 = strchr (line2, '\t')) == NULL) - { - error (0, 0, "invalid diff header for %s", rcs); - ret = 1; - (void) fclose (fp); - goto out; - } - } - else - { - if (strncmp (line1, "--- ", 4) != 0 || - strncmp (line2, "+++ ", 4) != 0 || - (cp1 = strchr (line1, '\t')) == NULL || - (cp2 = strchr (line2, '\t')) == NULL) - { - error (0, 0, "invalid unidiff header for %s", rcs); - ret = 1; - (void) fclose (fp); - goto out; - } - } - if (CVSroot != NULL) - (void) sprintf (strippath, "%s/", CVSroot); - else - (void) strcpy (strippath, REPOS_STRIP); - if (strncmp (rcs, strippath, strlen (strippath)) == 0) - rcs += strlen (strippath); - commap = strrchr (rcs, ','); - *commap = '\0'; - if (vers_tag != NULL) - { - (void) sprintf (file1, "%s%s%s:%s", update_dir, - update_dir[0] ? "/" : "", rcs, vers_tag); - } - else - { - (void) strcpy (file1, DEVNULL); - } - (void) sprintf (file2, "%s%s%s:%s", update_dir, - update_dir[0] ? "/" : "", rcs, - vers_head ? vers_head : "removed"); - if (unidiff) - { - (void) printf ("diff -u %s %s\n", file1, file2); - (void) printf ("--- %s%s+++ ", file1, cp1); - } - else - { - (void) printf ("diff -c %s %s\n", file1, file2); - (void) printf ("*** %s%s--- ", file1, cp1); - } - - if (update_dir[0] != '\0') - (void) printf ("%s/", update_dir); - (void) printf ("%s%s", rcs, cp2); - /* 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); - return (ret); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -patch_dirproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "Diffing %s", update_dir); - return (R_PROCESS); -} - -/* - * Clean up temporary files - */ -static RETSIGTYPE -patch_cleanup () -{ - if (tmpfile1[0] != '\0') - (void) unlink_file (tmpfile1); - if (tmpfile2[0] != '\0') - (void) unlink_file (tmpfile2); - if (tmpfile3[0] != '\0') - (void) unlink_file (tmpfile3); -} diff --git a/gnu/usr.bin/cvs/cvs/patchlevel.h b/gnu/usr.bin/cvs/cvs/patchlevel.h deleted file mode 100644 index 50d3863..0000000 --- a/gnu/usr.bin/cvs/cvs/patchlevel.h +++ /dev/null @@ -1 +0,0 @@ -#define PATCHLEVEL 2 diff --git a/gnu/usr.bin/cvs/cvs/rcs.c b/gnu/usr.bin/cvs/cvs/rcs.c deleted file mode 100644 index 43282a6..0000000 --- a/gnu/usr.bin/cvs/cvs/rcs.c +++ /dev/null @@ -1,1726 +0,0 @@ -/* - * Copyright (c) 1992, Brian Berliner and Jeff Polk - * - * 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. - * - * The routines contained in this file do all the rcs file parsing and - * manipulation - */ - -#include <assert.h> -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)rcs.c 1.40 94/10/07 $"; -USE(rcsid); -#endif - -static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile)); -static char *RCS_getdatebranch PROTO((RCSNode * rcs, char *date, char *branch)); -static int getrcskey PROTO((FILE * fp, char **keyp, char **valp)); -static int parse_rcs_proc PROTO((Node * file, void *closure)); -static int checkmagic_proc PROTO((Node *p, void *closure)); -static void do_branches PROTO((List * list, char *val)); -static void do_symbols PROTO((List * list, char *val)); -static void null_delproc PROTO((Node * p)); -static void rcsnode_delproc PROTO((Node * p)); -static void rcsvers_delproc PROTO((Node * p)); - -static List *rcslist; -static char *repository; - -/* - * We don't want to use isspace() from the C library because: - * - * 1. The definition of "whitespace" in RCS files includes ASCII - * backspace, but the C locale doesn't. - * 2. isspace is an very expensive function call in some implementations - * due to the addition of wide character support. - */ -static const char spacetab[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, /* 0x00 - 0x0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */ -}; - -#define whitespace(c) (spacetab[(unsigned char)c] != 0) - -/* - * Parse all the rcs files specified and return a list - */ -List * -RCS_parsefiles (files, xrepos) - List *files; - char *xrepos; -{ - /* initialize */ - repository = xrepos; - rcslist = getlist (); - - /* walk the list parsing files */ - if (walklist (files, parse_rcs_proc, NULL) != 0) - { - /* free the list and return NULL on error */ - dellist (&rcslist); - return ((List *) NULL); - } - else - /* return the list we built */ - return (rcslist); -} - -/* - * Parse an rcs file into a node on the rcs list - */ -static int -parse_rcs_proc (file, closure) - Node *file; - void *closure; -{ - RCSNode *rdata; - - /* parse the rcs file into rdata */ - rdata = RCS_parse (file->key, repository); - - /* if we got a valid RCSNode back, put it on the list */ - if (rdata != (RCSNode *) NULL) - RCS_addnode (file->key, rdata, rcslist); - - return (0); -} - -/* - * Add an RCSNode to a list of them. - */ - -void -RCS_addnode (file, rcs, list) - const char *file; - RCSNode *rcs; - List *list; -{ - Node *p; - - p = getnode (); - p->key = xstrdup (file); - p->delproc = rcsnode_delproc; - p->type = RCSNODE; - p->data = (char *) rcs; - (void) addnode (list, p); -} - - -/* - * Parse an rcsfile given a user file name and a repository - */ -RCSNode * -RCS_parse (file, repos) - const char *file; - const char *repos; -{ - RCSNode *rcs; - FILE *fp; - char rcsfile[PATH_MAX]; - -#ifdef LINES_CRLF_TERMINATED - /* Some ports of RCS to Windows NT write RCS files with newline- - delimited lines. We would need to pass fopen a "binary" flag. */ - abort (); -#endif - - (void) sprintf (rcsfile, "%s/%s%s", repos, file, RCSEXT); - if ((fp = fopen (rcsfile, "r")) != NULL) - { - rcs = RCS_parsercsfile_i(fp, rcsfile); - if (rcs != NULL) - rcs->flags |= VALID; - - fclose (fp); - return (rcs); - } - else if (! existence_error (errno)) - { - error (0, errno, "cannot open %s", rcsfile); - return NULL; - } - -#ifdef LINES_CRLF_TERMINATED - /* Some ports of RCS to Windows NT write RCS files with newline- - delimited lines. We would need to pass fopen a "binary" flag. */ - abort (); -#endif - - (void) sprintf (rcsfile, "%s/%s/%s%s", repos, CVSATTIC, file, RCSEXT); - if ((fp = fopen (rcsfile, "r")) != NULL) - { - rcs = RCS_parsercsfile_i(fp, rcsfile); - if (rcs != NULL) - { - rcs->flags |= INATTIC; - rcs->flags |= VALID; - } - - fclose (fp); - return (rcs); - } - else if (! existence_error (errno)) - { - error (0, errno, "cannot open %s", rcsfile); - return NULL; - } - - return (NULL); -} - -/* - * Parse a specific rcsfile. - */ -RCSNode * -RCS_parsercsfile (rcsfile) - char *rcsfile; -{ - FILE *fp; - RCSNode *rcs; - -#ifdef LINES_CRLF_TERMINATED - /* Some ports of RCS to Windows NT write RCS files with newline- - delimited lines. We would need to pass fopen a "binary" flag. */ - abort (); -#endif - - /* open the rcsfile */ - if ((fp = fopen (rcsfile, "r")) == NULL) - { - error (0, errno, "Couldn't open rcs file `%s'", rcsfile); - return (NULL); - } - - rcs = RCS_parsercsfile_i (fp, rcsfile); - - fclose (fp); - return (rcs); -} - - -/* - */ -static RCSNode * -RCS_parsercsfile_i (fp, rcsfile) - FILE *fp; - const char *rcsfile; -{ - RCSNode *rdata; - char *key, *value; - - /* make a node */ - rdata = (RCSNode *) xmalloc (sizeof (RCSNode)); - memset ((char *) rdata, 0, sizeof (RCSNode)); - rdata->refcount = 1; - rdata->path = xstrdup (rcsfile); - - /* Process HEAD and BRANCH keywords from the RCS header. - * - * Most cvs operatations on the main branch don't need any more - * information. Those that do call XXX to completely parse the - * RCS file. */ - - if (getrcskey (fp, &key, &value) == -1 || key == NULL) - goto l_error; - - if (strcmp (RCSHEAD, key) == 0 && value != NULL) - rdata->head = xstrdup (value); - - if (getrcskey (fp, &key, &value) == -1 || key == NULL) - goto l_error; - - if (strcmp (RCSBRANCH, key) == 0 && value != NULL) - { - char *cp; - - rdata->branch = xstrdup (value); - if ((numdots (rdata->branch) & 1) != 0) - { - /* turn it into a branch if it's a revision */ - cp = strrchr (rdata->branch, '.'); - *cp = '\0'; - } - } - - rdata->flags |= PARTIAL; - return rdata; - -l_error: - if (!really_quiet) - { - if (ferror(fp)) - { - error (1, 0, "error reading `%s'", rcsfile); - } - else - { - error (0, 0, "`%s' does not appear to be a valid rcs file", - rcsfile); - } - } - freercsnode (&rdata); - return (NULL); -} - - -/* - * Do the real work of parsing an RCS file - * - * There are no allowances for error here. - */ -void -RCS_reparsercsfile (rdata) - RCSNode *rdata; -{ - FILE *fp; - char *rcsfile; - - Node *q, *r; - RCSVers *vnode; - int n; - char *cp; - char *key, *value; - - rcsfile = rdata->path; - -#ifdef LINES_CRLF_TERMINATED - /* Some ports of RCS to Windows NT write RCS files with newline- - delimited lines. We would need to pass fopen a "binary" flag. */ - abort (); -#endif - - fp = fopen(rcsfile, "r"); - if (fp == NULL) - error (1, 0, "unable to reopen `%s'", rcsfile); - - /* make a node */ - rdata->versions = getlist (); - rdata->dates = getlist (); - - /* - * process all the special header information, break out when we get to - * the first revision delta - */ - for (;;) - { - /* get the next key/value pair */ - - /* if key is NULL here, then the file is missing some headers - or we had trouble reading the file. */ - if (getrcskey (fp, &key, &value) == -1 || key == NULL) - { - if (ferror(fp)) - { - error (1, 0, "error reading `%s'", rcsfile); - } - else - { - error (1, 0, "`%s' does not appear to be a valid rcs file", - rcsfile); - } - } - - if (strcmp (RCSSYMBOLS, key) == 0) - { - if (value != NULL) - { - rdata->symbols_data = xstrdup(value); - continue; - } - } - - 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 - * revision deltas, so we break out of the loop - */ - for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++) - /* do nothing */ ; - if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) - break; - - /* if we haven't grabbed it yet, we didn't want it */ - } - - /* - * we got out of the loop, so we have the first part of the first - * revision delta in our hand key=the revision and value=the date key and - * its value - */ - for (;;) - { - char *valp; - char date[MAXDATELEN]; - - /* grab the value of the date from value */ - valp = value + strlen (RCSDATE);/* skip the "date" keyword */ - while (whitespace (*valp)) /* take space off front of value */ - valp++; - (void) strcpy (date, valp); - - /* get the nodes (q is by version, r is by date) */ - q = getnode (); - r = getnode (); - q->type = RCSVERS; - r->type = RCSVERS; - q->delproc = rcsvers_delproc; - r->delproc = null_delproc; - q->data = r->data = xmalloc (sizeof (RCSVers)); - memset (q->data, 0, sizeof (RCSVers)); - vnode = (RCSVers *) q->data; - - /* fill in the version before we forget it */ - q->key = vnode->version = xstrdup (key); - - /* throw away the author field */ - (void) getrcskey (fp, &key, &value); - - /* throw away the state field */ - (void) getrcskey (fp, &key, &value); -#ifdef DEATH_SUPPORT - /* Accept this regardless of DEATH_STATE, so that we can read - repositories created with different versions of CVS. */ - if (strcmp (key, "state") != 0) - error (1, 0, "\ -unable to parse rcs file; `state' not in the expected place"); - if (strcmp (value, "dead") == 0) - { - vnode->dead = 1; - } -#endif - - /* fill in the date field */ - r->key = vnode->date = xstrdup (date); - - /* fill in the branch list (if any branches exist) */ - (void) getrcskey (fp, &key, &value); - if (value != (char *) NULL) - { - vnode->branches = getlist (); - do_branches (vnode->branches, value); - } - - /* fill in the next field if there is a next revision */ - (void) getrcskey (fp, &key, &value); - if (value != (char *) NULL) - vnode->next = xstrdup (value); - - /* - * at this point, we skip any user defined fields XXX - this is where - * we put the symbolic link stuff??? - */ - while ((n = getrcskey (fp, &key, &value)) >= 0) - { -#ifdef DEATH_SUPPORT - /* Enable use of repositories created with a CVS which defines - DEATH_SUPPORT and not DEATH_STATE. */ - if (strcmp(key, RCSDEAD) == 0) - { - vnode->dead = 1; - continue; - } -#endif - /* if we have a revision, break and do it */ - for (cp = key; (isdigit (*cp) || *cp == '.') && *cp != '\0'; cp++) - /* do nothing */ ; - if (*cp == '\0' && strncmp (RCSDATE, value, strlen (RCSDATE)) == 0) - break; - } - - /* add the nodes to the lists */ - (void) addnode (rdata->versions, q); - (void) addnode (rdata->dates, r); - - /* - * if we left the loop because there were no more keys, we break out - * of the revision processing loop - */ - if (n < 0) - break; - } - - fclose (fp); - rdata->flags &= ~PARTIAL; -} - -/* - * rcsnode_delproc - free up an RCS type node - */ -static void -rcsnode_delproc (p) - Node *p; -{ - freercsnode ((RCSNode **) & p->data); -} - -/* - * freercsnode - free up the info for an RCSNode - */ -void -freercsnode (rnodep) - RCSNode **rnodep; -{ - if (rnodep == NULL || *rnodep == NULL) - return; - - ((*rnodep)->refcount)--; - if ((*rnodep)->refcount != 0) - { - *rnodep = (RCSNode *) NULL; - return; - } - free ((*rnodep)->path); - dellist (&(*rnodep)->versions); - dellist (&(*rnodep)->dates); - if ((*rnodep)->symbols != (List *) NULL) - 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) - free ((*rnodep)->branch); - free ((char *) *rnodep); - *rnodep = (RCSNode *) NULL; -} - -/* - * rcsvers_delproc - free up an RCSVers type node - */ -static void -rcsvers_delproc (p) - Node *p; -{ - RCSVers *rnode; - - rnode = (RCSVers *) p->data; - - if (rnode->branches != (List *) NULL) - dellist (&rnode->branches); - if (rnode->next != (char *) NULL) - free (rnode->next); - free ((char *) rnode); -} - -/* - * null_delproc - don't free anything since it will be free'd by someone else - */ -/* ARGSUSED */ -static void -null_delproc (p) - Node *p; -{ - /* don't do anything */ -} - -/* - * getrcskey - fill in the key and value from the rcs file the algorithm is - * as follows - * - * o skip whitespace o fill in key with everything up to next white - * space or semicolon - * o if key == "desc" then key and data are NULL and return -1 - * o if key wasn't terminated by a semicolon, skip white space and fill - * in value with everything up to a semicolon - * o compress all whitespace down to a single space - * o if a word starts with @, do funky rcs processing - * o strip whitespace off end of value or set value to NULL if it empty - * o return 0 since we found something besides "desc" - */ - -static char *key = NULL; -static char *value = NULL; -static size_t keysize = 0; -static size_t valsize = 0; - -#define ALLOCINCR 1024 - -static int -getrcskey (fp, keyp, valp) - FILE *fp; - char **keyp; - char **valp; -{ - char *cur, *max; - int c; - - /* skip leading whitespace */ - do - { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - } while (whitespace (c)); - - /* fill in key */ - cur = key; - max = key + keysize; - while (!whitespace (c) && c != ';') - { - if (cur >= max) - { - key = xrealloc (key, keysize + ALLOCINCR); - cur = key + keysize; - keysize += ALLOCINCR; - max = key + keysize; - } - *cur++ = c; - - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - } - if (cur >= max) - { - key = xrealloc (key, keysize + ALLOCINCR); - cur = key + keysize; - keysize += ALLOCINCR; - max = key + keysize; - } - *cur = '\0'; - - /* if we got "desc", we are done with the file */ - if (strcmp (RCSDESC, key) == 0) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - - /* skip whitespace between key and val */ - while (whitespace (c)) - { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - } - - /* if we ended key with a semicolon, there is no value */ - if (c == ';') - { - *keyp = key; - *valp = (char *) NULL; - return (0); - } - - /* otherwise, there might be a value, so fill it in */ - cur = value; - max = value + valsize; - - /* process the value */ - for (;;) - { - /* handle RCS "strings" */ - if (c == '@') - { - for (;;) - { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - - if (c == '@') - { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - - if (c != '@') - break; - } - - if (cur >= max) - { - value = xrealloc (value, valsize + ALLOCINCR); - cur = value + valsize; - valsize += ALLOCINCR; - max = value + valsize; - } - *cur++ = c; - } - } - - /* compress whitespace down to a single space */ - if (whitespace (c)) - { - do { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - } while (whitespace (c)); - - if (cur >= max) - { - value = xrealloc (value, valsize + ALLOCINCR); - cur = value + valsize; - valsize += ALLOCINCR; - max = value + valsize; - } - *cur++ = ' '; - } - - /* if we got a semi-colon we are done with the entire value */ - if (c == ';') - break; - - if (cur >= max) - { - value = xrealloc (value, valsize + ALLOCINCR); - cur = value + valsize; - valsize += ALLOCINCR; - max = value + valsize; - } - *cur++ = c; - - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - } - - /* terminate the string */ - if (cur >= max) - { - value = xrealloc (value, valsize + ALLOCINCR); - cur = value + valsize; - valsize += ALLOCINCR; - max = value + valsize; - } - *cur = '\0'; - - /* if the string is empty, make it null */ - if (value && *value != '\0') - *valp = value; - else - *valp = NULL; - *keyp = key; - return (0); -} - -/* - * process the symbols list of the rcs file - */ -static void -do_symbols (list, val) - List *list; - char *val; -{ - Node *p; - char *cp = val; - char *tag, *rev; - - for (;;) - { - /* skip leading whitespace */ - while (whitespace (*cp)) - cp++; - - /* if we got to the end, we are done */ - if (*cp == '\0') - break; - - /* split it up into tag and rev */ - tag = cp; - cp = strchr (cp, ':'); - *cp++ = '\0'; - rev = cp; - while (!whitespace (*cp) && *cp != '\0') - cp++; - if (*cp != '\0') - *cp++ = '\0'; - - /* make a new node and add it to the list */ - p = getnode (); - p->key = xstrdup (tag); - p->data = xstrdup (rev); - (void) addnode (list, p); - } -} - -/* - * process the branches list of a revision delta - */ -static void -do_branches (list, val) - List *list; - char *val; -{ - Node *p; - char *cp = val; - char *branch; - - for (;;) - { - /* skip leading whitespace */ - while (whitespace (*cp)) - cp++; - - /* if we got to the end, we are done */ - if (*cp == '\0') - break; - - /* find the end of this branch */ - branch = cp; - while (!whitespace (*cp) && *cp != '\0') - cp++; - if (*cp != '\0') - *cp++ = '\0'; - - /* make a new node and add it to the list */ - p = getnode (); - p->key = xstrdup (branch); - (void) addnode (list, p); - } -} - -/* - * Version Number - * - * Returns the requested version number of the RCS file, satisfying tags and/or - * dates, and walking branches, if necessary. - * - * The result is returned; null-string if error. - */ -char * -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... */ - assert (rcs != NULL); - - if (tag && date) - { - char *cp, *rev, *tagrev; - - /* - * 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, 0); - if (tagrev == NULL) - return ((char *) NULL); - - if ((cp = strrchr (tagrev, '.')) != NULL) - *cp = '\0'; - rev = RCS_getdatebranch (rcs, date, tagrev); - free (tagrev); - return (rev); - } - else if (tag) - return (RCS_gettag (rcs, tag, force_tag_match, return_both)); - else if (date) - return (RCS_getdate (rcs, date, force_tag_match)); - else - return (RCS_head (rcs)); - -} - -/* - * Find the revision for a specific tag. - * If force_tag_match is set, return NULL if an exact match is not - * possible otherwise return RCS_head (). We are careful to look for - * and handle "magic" revisions specially. - * - * If the matched tag is a branch tag, find the head of the branch. - */ -char * -RCS_gettag (rcs, symtag, force_tag_match, return_both) - RCSNode *rcs; - char *symtag; - int force_tag_match; - int return_both; -{ - Node *p; - char *tag = symtag; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - /* XXX this is probably not necessary, --jtc */ - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - /* If tag is "HEAD", special case to get head RCS revision */ - if (tag && (strcmp (tag, TAG_HEAD) == 0 || *tag == '\0')) -#if 0 /* This #if 0 is only in the Cygnus code. Why? Death support? */ - if (force_tag_match && (rcs->flags & VALID) && (rcs->flags & INATTIC)) - return ((char *) NULL); /* head request for removed file */ - else -#endif - return (RCS_head (rcs)); - - if (!isdigit (tag[0])) - { - /* If we got a symbolic tag, resolve it to a numeric */ - if (rcs == NULL) - p = NULL; - else { - p = findnode (RCS_symbols(rcs), tag); - } - if (p != NULL) - { - int dots; - char *magic, *branch, *cp; - - tag = p->data; - - /* - * If this is a magic revision, we turn it into either its - * physical branch equivalent (if one exists) or into - * its base revision, which we assume exists. - */ - dots = numdots (tag); - if (dots > 2 && (dots & 1) != 0) - { - branch = strrchr (tag, '.'); - cp = branch++ - 1; - while (*cp != '.') - cp--; - - /* see if we have .magic-branch. (".0.") */ - magic = xmalloc (strlen (tag) + 1); - (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); - if (strncmp (magic, cp, strlen (magic)) == 0) - { - char *xtag; - - /* it's magic. See if the branch exists */ - *cp = '\0'; /* turn it into a revision */ - xtag = xstrdup (tag); - *cp = '.'; /* and back again */ - (void) sprintf (magic, "%s.%s", xtag, branch); - branch = RCS_getbranch (rcs, magic, 1); - free (magic); - if (branch != NULL) - { - free (xtag); - return (branch); - } - return (xtag); - } - free (magic); - } - } - else - { - /* The tag wasn't there, so return the head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - } - - /* - * numeric tag processing: - * 1) revision number - just return it - * 2) branch number - find head of branch - */ - - /* strip trailing dots */ - while (tag[strlen (tag) - 1] == '.') - tag[strlen (tag) - 1] = '\0'; - - if ((numdots (tag) & 1) == 0) - { - /* we have a branch tag, so we need to walk the branch */ - return (RCS_getbranch (rcs, tag, force_tag_match)); - } - else - { - /* we have a revision tag, so make sure it exists */ - if (rcs == NULL) - p = NULL; - else - p = findnode (rcs->versions, tag); - if (p != NULL) - { - /* - * 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 */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - } -} - -/* - * Return a "magic" revision as a virtual branch off of REV for the RCS file. - * A "magic" revision is one which is unique in the RCS file. By unique, I - * mean we return a revision which: - * - has a branch of 0 (see rcs.h RCS_MAGIC_BRANCH) - * - has a revision component which is not an existing branch off REV - * - has a revision component which is not an existing magic revision - * - is an even-numbered revision, to avoid conflicts with vendor branches - * The first point is what makes it "magic". - * - * As an example, if we pass in 1.37 as REV, we will look for an existing - * branch called 1.37.2. If it did not exist, we would look for an - * existing symbolic tag with a numeric part equal to 1.37.0.2. If that - * didn't exist, then we know that the 1.37.2 branch can be reserved by - * creating a symbolic tag with 1.37.0.2 as the numeric part. - * - * This allows us to fork development with very little overhead -- just a - * symbolic tag is used in the RCS file. When a commit is done, a physical - * branch is dynamically created to hold the new revision. - * - * Note: We assume that REV is an RCS revision and not a branch number. - */ -static char *check_rev; -char * -RCS_magicrev (rcs, rev) - RCSNode *rcs; - char *rev; -{ - int rev_num; - char *xrev, *test_branch; - - xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */ - check_rev = xrev; - - /* only look at even numbered branches */ - for (rev_num = 2; ; rev_num += 2) - { - /* see if the physical branch exists */ - (void) sprintf (xrev, "%s.%d", rev, rev_num); - test_branch = RCS_getbranch (rcs, xrev, 1); - if (test_branch != NULL) /* it did, so keep looking */ - { - free (test_branch); - continue; - } - - /* now, create a "magic" revision */ - (void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num); - - /* walk the symbols list to see if a magic one already exists */ - if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0) - continue; - - /* we found a free magic branch. Claim it as ours */ - return (xrev); - } -} - -/* - * walklist proc to look for a match in the symbols list. - * Returns 0 if the symbol does not match, 1 if it does. - */ -static int -checkmagic_proc (p, closure) - Node *p; - void *closure; -{ - if (strcmp (check_rev, p->data) == 0) - return (1); - else - return (0); -} - -/* - * Given a list of RCSNodes, returns non-zero if the specified - * revision number or symbolic tag resolves to a "branch" within the - * rcs file. - */ -int -RCS_isbranch (file, rev, srcfiles) - char *file; - char *rev; - List *srcfiles; -{ - Node *p; - RCSNode *rcs; - - /* numeric revisions are easy -- even number of dots is a branch */ - if (isdigit (*rev)) - return ((numdots (rev) & 1) == 0); - - /* assume a revision if you can't find the RCS info */ - p = findnode (srcfiles, file); - if (p == NULL) - return (0); - - /* now, look for a match in the symbols list */ - rcs = (RCSNode *) p->data; - return (RCS_nodeisbranch (rev, rcs)); -} - -/* - * Given an RCSNode, returns non-zero if the specified revision number - * or symbolic tag resolves to a "branch" within the rcs file. We do - * take into account any magic branches as well. - */ -int -RCS_nodeisbranch (rev, rcs) - char *rev; - RCSNode *rcs; -{ - int dots; - Node *p; - - /* numeric revisions are easy -- even number of dots is a branch */ - if (isdigit (*rev)) - return ((numdots (rev) & 1) == 0); - - p = findnode (RCS_symbols(rcs), rev); - if (p == NULL) - return (0); - dots = numdots (p->data); - if ((dots & 1) == 0) - return (1); - - /* got a symbolic tag match, but it's not a branch; see if it's magic */ - if (dots > 2) - { - char *magic; - char *branch = strrchr (p->data, '.'); - char *cp = branch - 1; - while (*cp != '.') - cp--; - - /* see if we have .magic-branch. (".0.") */ - magic = xmalloc (strlen (p->data) + 1); - (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); - if (strncmp (magic, cp, strlen (magic)) == 0) - { - free (magic); - return (1); - } - free (magic); - } - return (0); -} - -/* - * Returns a pointer to malloc'ed memory which contains the branch - * for the specified *symbolic* tag. Magic branches are handled correctly. - */ -char * -RCS_whatbranch (file, rev, srcfiles) - char *file; - char *rev; - List *srcfiles; -{ - int dots; - Node *p; - RCSNode *rcs; - - /* assume no branch if you can't find the RCS info */ - p = findnode (srcfiles, file); - if (p == NULL) - return ((char *) NULL); - - /* now, look for a match in the symbols list */ - rcs = (RCSNode *) p->data; - p = findnode (RCS_symbols(rcs), rev); - if (p == NULL) - return ((char *) NULL); - dots = numdots (p->data); - if ((dots & 1) == 0) - return (xstrdup (p->data)); - - /* got a symbolic tag match, but it's not a branch; see if it's magic */ - if (dots > 2) - { - char *magic; - char *branch = strrchr (p->data, '.'); - char *cp = branch++ - 1; - while (*cp != '.') - cp--; - - /* see if we have .magic-branch. (".0.") */ - magic = xmalloc (strlen (p->data) + 1); - (void) sprintf (magic, ".%d.", RCS_MAGIC_BRANCH); - if (strncmp (magic, cp, strlen (magic)) == 0) - { - /* yep. it's magic. now, construct the real branch */ - *cp = '\0'; /* turn it into a revision */ - (void) sprintf (magic, "%s.%s", p->data, branch); - *cp = '.'; /* and turn it back */ - return (magic); - } - free (magic); - } - return ((char *) NULL); -} - -/* - * Get the head of the specified branch. If the branch does not exist, - * return NULL or RCS_head depending on force_tag_match - */ -char * -RCS_getbranch (rcs, tag, force_tag_match) - RCSNode *rcs; - char *tag; - int force_tag_match; -{ - Node *p, *head; - RCSVers *vn; - char *xtag; - char *nextvers; - char *cp; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - /* find out if the tag contains a dot, or is on the trunk */ - cp = strrchr (tag, '.'); - - /* trunk processing is the special case */ - if (cp == NULL) - { - xtag = xmalloc (strlen (tag) + 1 + 1); /* +1 for an extra . */ - (void) strcpy (xtag, tag); - (void) strcat (xtag, "."); - for (cp = rcs->head; cp != NULL;) - { - if (strncmp (xtag, cp, strlen (xtag)) == 0) - break; - p = findnode (rcs->versions, cp); - if (p == NULL) - { - free (xtag); - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - vn = (RCSVers *) p->data; - cp = vn->next; - } - free (xtag); - if (cp == NULL) - { - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - return (xstrdup (cp)); - } - - /* if it had a `.', terminate the string so we have the base revision */ - *cp = '\0'; - - /* look up the revision this branch is based on */ - p = findnode (rcs->versions, tag); - - /* put the . back so we have the branch again */ - *cp = '.'; - - if (p == NULL) - { - /* if the base revision didn't exist, return head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - - /* find the first element of the branch we are looking for */ - vn = (RCSVers *) p->data; - if (vn->branches == NULL) - return (NULL); - xtag = xmalloc (strlen (tag) + 1 + 1); /* 1 for the extra '.' */ - (void) strcpy (xtag, tag); - (void) strcat (xtag, "."); - head = vn->branches->list; - for (p = head->next; p != head; p = p->next) - if (strncmp (p->key, xtag, strlen (xtag)) == 0) - break; - free (xtag); - - if (p == head) - { - /* we didn't find a match so return head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - - /* now walk the next pointers of the branch */ - nextvers = p->key; - do - { - p = findnode (rcs->versions, nextvers); - if (p == NULL) - { - /* a link in the chain is missing - return head or NULL */ - if (force_tag_match) - return (NULL); - else - return (RCS_head (rcs)); - } - vn = (RCSVers *) p->data; - nextvers = vn->next; - } while (nextvers != NULL); - - /* we have the version in our hand, so go for it */ - return (xstrdup (vn->version)); -} - -/* - * Get the head of the RCS file. If branch is set, this is the head of the - * branch, otherwise the real head - */ -char * -RCS_head (rcs) - RCSNode *rcs; -{ - /* make sure we have something to look at... */ - 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)); -} - -/* - * Get the most recent revision, based on the supplied date, but use some - * funky stuff and follow the vendor branch maybe - */ -char * -RCS_getdate (rcs, date, force_tag_match) - RCSNode *rcs; - char *date; - int force_tag_match; -{ - char *cur_rev = NULL; - char *retval = NULL; - Node *p; - RCSVers *vers = NULL; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - /* if the head is on a branch, try the branch first */ - if (rcs->branch != NULL) - retval = RCS_getdatebranch (rcs, date, rcs->branch); - - /* if we found a match, we are done */ - if (retval != NULL) - return (retval); - - /* otherwise if we have a trunk, try it */ - if (rcs->head) - { - p = findnode (rcs->versions, rcs->head); - while (p != NULL) - { - /* if the date of this one is before date, take it */ - vers = (RCSVers *) p->data; - if (RCS_datecmp (vers->date, date) <= 0) - { - cur_rev = vers->version; - break; - } - - /* if there is a next version, find the node */ - if (vers->next != NULL) - p = findnode (rcs->versions, vers->next); - else - p = (Node *) NULL; - } - } - - /* - * at this point, either we have the revision we want, or we have the - * first revision on the trunk (1.1?) in our hands - */ - - /* if we found what we're looking for, and it's not 1.1 return it */ - if (cur_rev != NULL && strcmp (cur_rev, "1.1") != 0) - return (xstrdup (cur_rev)); - - /* look on the vendor branch */ - retval = RCS_getdatebranch (rcs, date, CVSBRANCH); - - /* - * if we found a match, return it; otherwise, we return the first - * revision on the trunk or NULL depending on force_tag_match and the - * date of the first rev - */ - if (retval != NULL) - return (retval); - - if (!force_tag_match || RCS_datecmp (vers->date, date) <= 0) - return (xstrdup (vers->version)); - else - return (NULL); -} - -/* - * Look up the last element on a branch that was put in before the specified - * date (return the rev or NULL) - */ -static char * -RCS_getdatebranch (rcs, date, branch) - RCSNode *rcs; - char *date; - char *branch; -{ - char *cur_rev = NULL; - char *cp; - char *xbranch, *xrev; - Node *p; - RCSVers *vers; - - /* look up the first revision on the branch */ - xrev = xstrdup (branch); - cp = strrchr (xrev, '.'); - if (cp == NULL) - { - free (xrev); - return (NULL); - } - *cp = '\0'; /* turn it into a revision */ - - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - p = findnode (rcs->versions, xrev); - free (xrev); - if (p == NULL) - return (NULL); - vers = (RCSVers *) p->data; - - /* if no branches list, return NULL */ - if (vers->branches == NULL) - return (NULL); - - /* walk the branches list looking for the branch number */ - xbranch = xmalloc (strlen (branch) + 1 + 1); /* +1 for the extra dot */ - (void) strcpy (xbranch, branch); - (void) strcat (xbranch, "."); - for (p = vers->branches->list->next; p != vers->branches->list; p = p->next) - if (strncmp (p->key, xbranch, strlen (xbranch)) == 0) - break; - free (xbranch); - if (p == vers->branches->list) - return (NULL); - - p = findnode (rcs->versions, p->key); - - /* walk the next pointers until you find the end, or the date is too late */ - while (p != NULL) - { - vers = (RCSVers *) p->data; - if (RCS_datecmp (vers->date, date) <= 0) - cur_rev = vers->version; - else - break; - - /* if there is a next version, find the node */ - if (vers->next != NULL) - p = findnode (rcs->versions, vers->next); - else - p = (Node *) NULL; - } - - /* if we found something acceptable, return it - otherwise NULL */ - if (cur_rev != NULL) - return (xstrdup (cur_rev)); - else - return (NULL); -} - -/* - * Compare two dates in RCS format. Beware the change in format on January 1, - * 2000, when years go from 2-digit to full format. - */ -int -RCS_datecmp (date1, date2) - char *date1, *date2; -{ - int length_diff = strlen (date1) - strlen (date2); - - return (length_diff ? length_diff : strcmp (date1, date2)); -} - -/* - * Lookup the specified revision in the ,v file and return, in the date - * argument, the date specified for the revision *minus one second*, so that - * the logically previous revision will be found later. - * - * Returns zero on failure, RCS revision time as a Unix "time_t" on success. - */ -time_t -RCS_getrevtime (rcs, rev, date, fudge) - RCSNode *rcs; - char *rev; - char *date; - int fudge; -{ - char tdate[MAXDATELEN]; - struct tm xtm, *ftm; - time_t revdate = 0; - Node *p; - RCSVers *vers; - - /* make sure we have something to look at... */ - assert (rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - /* look up the revision */ - p = findnode (rcs->versions, rev); - if (p == NULL) - return (-1); - vers = (RCSVers *) p->data; - - /* split up the date */ - ftm = &xtm; - (void) sscanf (vers->date, SDATEFORM, &ftm->tm_year, &ftm->tm_mon, - &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min, - &ftm->tm_sec); - if (ftm->tm_year > 1900) - ftm->tm_year -= 1900; - - /* put the date in a form getdate can grok */ -#ifdef HAVE_RCS5 - (void) sprintf (tdate, "%d/%d/%d GMT %d:%d:%d", ftm->tm_mon, - ftm->tm_mday, ftm->tm_year, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); -#else - (void) sprintf (tdate, "%d/%d/%d %d:%d:%d", ftm->tm_mon, - ftm->tm_mday, ftm->tm_year, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); -#endif - - /* turn it into seconds since the epoch */ - revdate = get_date (tdate, (struct timeb *) NULL); - if (revdate != (time_t) -1) - { - revdate -= fudge; /* remove "fudge" seconds */ - if (date) - { - /* put an appropriate string into ``date'' if we were given one */ -#ifdef HAVE_RCS5 - ftm = gmtime (&revdate); -#else - ftm = localtime (&revdate); -#endif - (void) sprintf (date, DATEFORM, - ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900), - ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour, - ftm->tm_min, ftm->tm_sec); - } - } - return (revdate); -} - -List * -RCS_symbols(rcs) - RCSNode *rcs; -{ - assert(rcs != NULL); - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - if (rcs->symbols_data) { - rcs->symbols = getlist (); - do_symbols (rcs->symbols, rcs->symbols_data); - free(rcs->symbols_data); - rcs->symbols_data = NULL; - } - - return rcs->symbols; -} - -/* - * The argument ARG is the getopt remainder of the -k option specified on the - * command line. This function returns malloc'ed space that can be used - * directly in calls to RCS V5, with the -k flag munged correctly. - */ -char * -RCS_check_kflag (arg) - const char *arg; -{ - static const char *const kflags[] = - {"kv", "kvl", "k", "v", "o", "b", (char *) NULL}; - static const char *const keyword_usage[] = - { - "%s %s: invalid RCS keyword expansion mode\n", - "Valid expansion modes include:\n", - " -kkv\tGenerate keywords using the default form.\n", - " -kkvl\tLike -kkv, except locker's name inserted.\n", - " -kk\tGenerate only keyword names in keyword strings.\n", - " -kv\tGenerate only keyword values in keyword strings.\n", - " -ko\tGenerate the old keyword string (no changes from checked in file).\n", - " -kb\tGenerate binary file unmodified (merges not allowed) (RCS 5.7).\n", - NULL, - }; - char karg[10]; - char const *const *cpp = NULL; - -#ifndef HAVE_RCS5 - error (1, 0, "%s %s: your version of RCS does not support the -k option", - program_name, command_name); -#endif - - if (arg) - { - for (cpp = kflags; *cpp != NULL; cpp++) - { - if (strcmp (arg, *cpp) == 0) - break; - } - } - - if (arg == NULL || *cpp == NULL) - { - usage (keyword_usage); - } - - (void) sprintf (karg, "-k%s", *cpp); - return (xstrdup (karg)); -} - -/* - * Do some consistency checks on the symbolic tag... These should equate - * pretty close to what RCS checks, though I don't know for certain. - */ -void -RCS_check_tag (tag) - const char *tag; -{ - char *invalid = "$,.:;@"; /* invalid RCS tag characters */ - const char *cp; - - /* - * The first character must be an alphabetic letter. The remaining - * characters cannot be non-visible graphic characters, and must not be - * in the set of "invalid" RCS identifier characters. - */ - if (isalpha (*tag)) - { - for (cp = tag; *cp; cp++) - { - if (!isgraph (*cp)) - error (1, 0, "tag `%s' has non-visible graphic characters", - tag); - if (strchr (invalid, *cp)) - error (1, 0, "tag `%s' must not contain the characters `%s'", - tag, invalid); - } - } - else - error (1, 0, "tag `%s' must start with a letter", tag); -} - -#ifdef DEATH_SUPPORT -/* - * Return true if RCS revision with TAG is a dead revision. - */ -int -RCS_isdead (rcs, tag) - RCSNode *rcs; - const char *tag; -{ - Node *p; - RCSVers *version; - - if (rcs->flags & PARTIAL) - RCS_reparsercsfile (rcs); - - p = findnode (rcs->versions, tag); - if (p == NULL) - return (0); - - version = (RCSVers *) p->data; - return (version->dead); -} -#endif /* DEATH_SUPPORT */ diff --git a/gnu/usr.bin/cvs/cvs/rcs.h b/gnu/usr.bin/cvs/cvs/rcs.h deleted file mode 100644 index f64501d..0000000 --- a/gnu/usr.bin/cvs/cvs/rcs.h +++ /dev/null @@ -1,107 +0,0 @@ -/* $CVSid: @(#)rcs.h 1.18 94/09/23 $ */ - -/* - * 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. - * - * RCS source control definitions needed by rcs.c and friends - */ - -#define RCS "rcs" -#define RCS_CI "ci" -#define RCS_CO "co" -#define RCS_RLOG "rlog" -#define RCS_DIFF "rcsdiff" -#define RCS_MERGE "merge" -#define RCS_RCSMERGE "rcsmerge" -#define RCS_MERGE_PAT "^>>>>>>> " /* runs "grep" with this pattern */ -#define RCSEXT ",v" -#define RCSPAT "*,v" -#define RCSHEAD "head" -#define RCSBRANCH "branch" -#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" - -/* - * Opaque structure definitions used by RCS specific lookup routines - */ -#define VALID 0x1 /* flags field contains valid data */ -#define INATTIC 0x2 /* RCS file is located in the Attic */ -#define PARTIAL 0x4 /* RCS file not completly parsed */ - -struct rcsnode -{ - int refcount; - int flags; - char *path; - char *head; - char *branch; - char *symbols_data; - char *expand; - List *symbols; - List *versions; - List *dates; -}; - -typedef struct rcsnode RCSNode; - -struct rcsversnode -{ - char *version; - char *date; - char *next; - int dead; - List *branches; -}; -typedef struct rcsversnode RCSVers; - -/* - * CVS reserves all even-numbered branches for its own use. "magic" branches - * (see rcs.c) are contained as virtual revision numbers (within symbolic - * tags only) off the RCS_MAGIC_BRANCH, which is 0. CVS also reserves the - * ".1" branch for vendor revisions. So, if you do your own branching, you - * should limit your use to odd branch numbers starting at 3. - */ -#define RCS_MAGIC_BRANCH 0 - -/* - * exported interfaces - */ -List *RCS_parsefiles PROTO((List * files, char *xrepos)); -RCSNode *RCS_parse PROTO((const char *file, const char *repos)); -RCSNode *RCS_parsercsfile PROTO((char *rcsfile)); -char *RCS_check_kflag PROTO((const char *arg)); -char *RCS_getdate PROTO((RCSNode * rcs, char *date, 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 return_both)); -char *RCS_magicrev PROTO((RCSNode *rcs, char *rev)); -int RCS_isbranch PROTO((char *file, char *rev, List *srcfiles)); -int RCS_nodeisbranch PROTO((char *rev, RCSNode *rcs)); -char *RCS_whatbranch PROTO((char *file, char *tag, List *srcfiles)); -char *RCS_head PROTO((RCSNode * rcs)); -int RCS_datecmp PROTO((char *date1, char *date2)); -time_t RCS_getrevtime PROTO((RCSNode * rcs, char *rev, char *date, int fudge)); -List *RCS_symbols PROTO((RCSNode *rcs)); -void RCS_check_tag PROTO((const char *tag)); -void freercsnode PROTO((RCSNode ** rnodep)); -void RCS_addnode PROTO((const char *file, RCSNode *rcs, List *list)); -char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match)); - -#ifdef DEATH_SUPPORT -int RCS_isdead PROTO((RCSNode *, const char *)); -#endif diff --git a/gnu/usr.bin/cvs/cvs/rcscmds.c b/gnu/usr.bin/cvs/cvs/rcscmds.c deleted file mode 100644 index af32cea..0000000 --- a/gnu/usr.bin/cvs/cvs/rcscmds.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - * - * The functions in this file provide an interface for performing - * operations directly on RCS files. - */ - -#include "cvs.h" - -int -RCS_settag(path, tag, rev) - const char *path; - const char *tag; - const char *rev; -{ - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev); - run_arg (path); - return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); -} - -/* NOERR is 1 to suppress errors--FIXME it would - be better to avoid the errors or some cleaner solution. */ -int -RCS_deltag(path, tag, noerr) - const char *path; - const char *tag; - int noerr; -{ - run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag); - run_arg (path); - return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL); -} - -/* set RCS branch to REV */ -int -RCS_setbranch(path, rev) - const char *path; - const char *rev; -{ - run_setup ("%s%s -q -b%s", Rcsbin, RCS, rev ? rev : ""); - run_arg (path); - return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); -} - -/* Lock revision REV. NOERR is 1 to suppress errors--FIXME it would - be better to avoid the errors or some cleaner solution. */ -int -RCS_lock(path, rev, noerr) - const char *path; - const char *rev; - int noerr; -{ - run_setup ("%s%s -q -l%s", Rcsbin, RCS, rev ? rev : ""); - run_arg (path); - return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL); -} - -/* Unlock revision REV. NOERR is 1 to suppress errors--FIXME it would - be better to avoid the errors or some cleaner solution. */ -int -RCS_unlock(path, rev, noerr) - const char *path; - const char *rev; - int noerr; -{ - run_setup ("%s%s -q -u%s", Rcsbin, RCS, rev ? rev : ""); - run_arg (path); - return run_exec (RUN_TTY, RUN_TTY, noerr ? DEVNULL : RUN_TTY, RUN_NORMAL); -} - -/* Merge revisions REV1 and REV2. */ -int -RCS_merge(path, options, rev1, rev2) - const char *path; - const char *options; - const char *rev1; - const char *rev2; -{ - int status; - - /* 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, - options, rev1, rev2, path); - status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); -#ifndef HAVE_RCS5 - if (status == 0) - { - /* Run GREP to see if there appear to be conflicts in the file */ - run_setup ("%s", GREP); - run_arg (RCS_MERGE_PAT); - run_arg (path); - status = (run_exec (RUN_TTY, DEVNULL, RUN_TTY, RUN_NORMAL) == 0); - - } -#endif - return status; -} diff --git a/gnu/usr.bin/cvs/cvs/recurse.c b/gnu/usr.bin/cvs/cvs/recurse.c deleted file mode 100644 index f5d9433..0000000 --- a/gnu/usr.bin/cvs/cvs/recurse.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright (c) 1992, Brian Berliner and Jeff Polk - * - * 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. - * - * General recursion handler - * - */ - -#include "cvs.h" -#include "save-cwd.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)recurse.c 1.31 94/09/30 $"; -USE(rcsid); -#endif - -static int do_dir_proc PROTO((Node * p, void *closure)); -static int do_file_proc PROTO((Node * p, void *closure)); -static void addlist PROTO((List ** listp, char *key)); -static int unroll_files_proc PROTO((Node *p, void *closure)); -static void addfile PROTO((List **listp, char *dir, char *file)); - - -/* - * Local static versions eliminates the need for globals - */ -static FILEPROC fileproc; -static FILESDONEPROC filesdoneproc; -static DIRENTPROC direntproc; -static DIRLEAVEPROC dirleaveproc; -static int which; -static Dtype flags; -static int aflag; -static int readlock; -static int dosrcs; -static char update_dir[PATH_MAX]; -static char *repository = NULL; -static List *entries = NULL; -static List *srcfiles = NULL; - -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 { - FILEPROC fileproc; - FILESDONEPROC filesdoneproc; - DIRENTPROC direntproc; - DIRLEAVEPROC dirleaveproc; - Dtype flags; - int which; - int aflag; - int readlock; - int dosrcs; -}; - -/* - * Called to start a recursive command. - * - * Command line arguments dictate the directories and files on which - * we operate. In the special case of no arguments, we default to - * ".". - * - * The general algorithm is as follows. - */ -int -start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, - argc, argv, local, which, aflag, readlock, - update_preload, dosrcs, wd_is_repos) - FILEPROC fileproc; - FILESDONEPROC filesdoneproc; - DIRENTPROC direntproc; - DIRLEAVEPROC dirleaveproc; - int argc; - char **argv; - int local; - int which; - int aflag; - int readlock; - char *update_preload; - int dosrcs; - int wd_is_repos; /* Set if caller has already cd'd to the repository */ -{ - int i, err = 0; - Dtype flags; - List *files_by_dir = NULL; - struct recursion_frame frame; - - if (update_preload == NULL) - update_dir[0] = '\0'; - else - (void) strcpy (update_dir, update_preload); - - if (local) - flags = R_SKIP_DIRS; - else - flags = R_PROCESS; - - /* clean up from any previous calls to start_recursion */ - if (repository) - { - free (repository); - repository = (char *) NULL; - } - if (entries) - { - Entries_Close (entries); - entries = NULL; - } - if (srcfiles) - dellist (&srcfiles); - if (filelist) - dellist (&filelist); /* FIXME-krp: no longer correct. */ -/* FIXME-krp: clean up files_by_dir */ - if (dirlist) - dellist (&dirlist); - - if (argc == 0) - { - - /* - * There were no arguments, so we'll probably just recurse. The - * exception to the rule is when we are called from a directory - * without any CVS administration files. That has always meant to - * process each of the sub-directories, so we pretend like we were - * called with the list of sub-dirs of the current dir as args - */ - if ((which & W_LOCAL) && !isdir (CVSADM)) - dirlist = Find_Dirs ((char *) NULL, W_LOCAL); - else - addlist (&dirlist, "."); - - err += do_recursion (fileproc, filesdoneproc, direntproc, - dirleaveproc, flags, which, aflag, - readlock, dosrcs); - return(err); - } - - - /* - * There were arguments, so we have to handle them by hand. To do - * that, we set up the filelist and dirlist with the arguments and - * call do_recursion. do_recursion recognizes the fact that the - * lists are non-null when it starts and doesn't update them. - * - * explicitly named directories are stored in dirlist. - * explicitly named files are stored in filelist. - * other possibility is named entities whicha are not currently in - * the working directory. - */ - - for (i = 0; i < argc; i++) - { - /* if this argument is a directory, then add it to the list of - directories. */ - - if (!wrap_name_has (argv[i], WRAP_TOCVS) && isdir (argv[i])) - addlist (&dirlist, argv[i]); - else - { - /* otherwise, split argument into directory and component names. */ - char *dir; - char *comp; - char tmp[PATH_MAX]; - char *file_to_try; - - dir = xstrdup (argv[i]); - if ((comp = strrchr (dir, '/')) == NULL) - { - /* no dir component. What we have is an implied "./" */ - comp = dir; - dir = xstrdup("."); - } - else - { - char *p = comp; - - *p++ = '\0'; - comp = xstrdup (p); - } - - /* if this argument exists as a file in the current - working directory tree, then add it to the files list. */ - - if (wd_is_repos) - { - /* If doing rtag, we've done a chdir to the repository. */ - sprintf (tmp, "%s%s", argv[i], RCSEXT); - file_to_try = tmp; - } - else - file_to_try = argv[i]; - - if(isfile(file_to_try)) - addfile (&files_by_dir, dir, comp); - else if (isdir (dir)) - { - if (isdir (CVSADM)) - { - /* otherwise, look for it in the repository. */ - char *save_update_dir; - char *repos; - - /* save & set (aka push) update_dir */ - save_update_dir = xstrdup (update_dir); - - if (*update_dir != '\0') - (void) strcat (update_dir, "/"); - - (void) strcat (update_dir, dir); - - /* 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]); - else - addfile (&files_by_dir, dir, comp); - - (void) sprintf (update_dir, "%s", save_update_dir); - free (save_update_dir); - } - else - addfile (&files_by_dir, dir, comp); - } - else - error (1, 0, "no such directory `%s'", dir); - - free (dir); - free (comp); - } - } - - /* At this point we have looped over all named arguments and built - a coupla lists. Now we unroll the lists, setting up and - calling do_recursion. */ - - frame.fileproc = fileproc; - frame.filesdoneproc = filesdoneproc; - frame.direntproc = direntproc; - frame.dirleaveproc = dirleaveproc; - frame.flags = flags; - frame.which = which; - frame.aflag = aflag; - frame.readlock = readlock; - frame.dosrcs = dosrcs; - err += walklist (files_by_dir, unroll_files_proc, (void *) &frame); - - /* then do_recursion on the dirlist. */ - if (dirlist != NULL) - err += do_recursion (frame.fileproc, frame.filesdoneproc, - frame.direntproc, frame.dirleaveproc, - frame.flags, frame.which, frame.aflag, - frame.readlock, frame.dosrcs); - - - return (err); -} - -/* - * Implement the recursive policies on the local directory. This may be - * called directly, or may be called by start_recursion - */ -int -do_recursion (xfileproc, xfilesdoneproc, xdirentproc, xdirleaveproc, - xflags, xwhich, xaflag, xreadlock, xdosrcs) - FILEPROC xfileproc; - FILESDONEPROC xfilesdoneproc; - DIRENTPROC xdirentproc; - DIRLEAVEPROC xdirleaveproc; - Dtype xflags; - int xwhich; - int xaflag; - int xreadlock; - int xdosrcs; -{ - int err = 0; - int dodoneproc = 1; - char *srepository; - - /* do nothing if told */ - if (xflags == R_SKIP_ALL) - return (0); - - /* set up the static vars */ - fileproc = xfileproc; - filesdoneproc = xfilesdoneproc; - direntproc = xdirentproc; - dirleaveproc = xdirleaveproc; - flags = xflags; - which = xwhich; - aflag = xaflag; - 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 - */ - if (which & W_LOCAL) - { - if (isdir (CVSADM)) - repository = Name_Repository ((char *) NULL, update_dir); - else - repository = NULL; - } - else - { - repository = xmalloc (PATH_MAX); - (void) getwd (repository); - } - srepository = repository; /* remember what to free */ - - /* - * The filesdoneproc needs to be called for each directory where files - * processed, or each directory that is processed by a call where no - * directories were passed in. In fact, the only time we don't want to - * call back the filesdoneproc is when we are processing directories that - * were passed in on the command line (or in the special case of `.' when - * we were called with no args - */ - if (dirlist != NULL && filelist == NULL) - dodoneproc = 0; - - /* - * If filelist or dirlist is already set, we don't look again. Otherwise, - * find the files and directories - */ - if (filelist == NULL && dirlist == NULL) - { - /* both lists were NULL, so start from scratch */ - if (fileproc != NULL && flags != R_SKIP_FILES) - { - int lwhich = which; - - /* be sure to look in the attic if we have sticky tags/date */ - if ((lwhich & W_ATTIC) == 0) - if (isreadable (CVSADM_TAG)) - lwhich |= W_ATTIC; - - /* find the files and fill in entries if appropriate */ - filelist = Find_Names (repository, lwhich, aflag, &entries); - } - - /* find sub-directories if we will recurse */ - if (flags != R_SKIP_DIRS) - dirlist = Find_Dirs (repository, which); - } - else - { - /* something was passed on the command line */ - if (filelist != NULL && fileproc != NULL) - { - /* we will process files, so pre-parse entries */ - if (which & W_LOCAL) - entries = Entries_Open (aflag); - } - } - - /* process the files (if any) */ - if (filelist != NULL) - { - /* read lock it if necessary */ - if (readlock && repository && Reader_Lock (repository) != 0) - error (1, 0, "read lock failed - giving up"); - - /* pre-parse the source files */ - if (dosrcs && repository) - srcfiles = RCS_parsefiles (filelist, repository); - else - srcfiles = (List *) NULL; - - /* process the files */ - err += walklist (filelist, do_file_proc, NULL); - - /* unlock it */ - if (readlock) - Lock_Cleanup (); - - /* clean up */ - dellist (&filelist); - dellist (&srcfiles); - Entries_Close (entries); - entries = NULL; - } - - /* call-back files done proc (if any) */ - if (dodoneproc && filesdoneproc != NULL) - err = filesdoneproc (err, repository, update_dir[0] ? update_dir : "."); - - /* process the directories (if necessary) */ - if (dirlist != NULL) - err += walklist (dirlist, do_dir_proc, NULL); -#ifdef notdef - else if (dirleaveproc != NULL) - err += dirleaveproc(".", err, "."); -#endif - dellist (&dirlist); - - /* free the saved copy of the pointer if necessary */ - if (srepository) - { - free (srepository); - repository = (char *) NULL; - } - - return (err); -} - -/* - * Process each of the files in the list with the callback proc - */ -static int -do_file_proc (p, closure) - Node *p; - void *closure; -{ - if (fileproc != NULL) - return (fileproc (p->key, update_dir, repository, entries, srcfiles)); - else - return (0); -} - -/* - * Process each of the directories in the list (recursing as we go) - */ -static int -do_dir_proc (p, closure) - Node *p; - void *closure; -{ - char *dir = p->key; - char newrepos[PATH_MAX]; - List *sdirlist; - char *srepository; - char *cp; - Dtype dir_return = R_PROCESS; - int stripped_dot = 0; - int err = 0; - struct saved_cwd cwd; - - /* set up update_dir - skip dots if not at start */ - if (strcmp (dir, ".") != 0) - { - if (update_dir[0] != '\0') - { - (void) strcat (update_dir, "/"); - (void) strcat (update_dir, dir); - } - else - (void) strcpy (update_dir, dir); - - /* - * Here we need a plausible repository name for the sub-directory. We - * create one by concatenating the new directory name onto the - * previous repository name. The only case where the name should be - * used is in the case where we are creating a new sub-directory for - * update -d and in that case the generated name will be correct. - */ - if (repository == NULL) - newrepos[0] = '\0'; - else - (void) sprintf (newrepos, "%s/%s", repository, dir); - } - else - { - if (update_dir[0] == '\0') - (void) strcpy (update_dir, dir); - - if (repository == NULL) - newrepos[0] = '\0'; - else - (void) strcpy (newrepos, repository); - } - - /* call-back dir entry proc (if any) */ - if (direntproc != NULL) - dir_return = direntproc (dir, newrepos, update_dir); - - /* only process the dir if the return code was 0 */ - if (dir_return != R_SKIP_ALL) - { - /* save our current directory and static vars */ - if (save_cwd (&cwd)) - exit (1); - sdirlist = dirlist; - srepository = repository; - dirlist = NULL; - - /* cd to the sub-directory */ - if (chdir (dir) < 0) - error (1, errno, "could not chdir to %s", dir); - - /* honor the global SKIP_DIRS (a.k.a. local) */ - if (flags == R_SKIP_DIRS) - dir_return = R_SKIP_DIRS; - - /* remember if the `.' will be stripped for subsequent dirs */ - if (strcmp (update_dir, ".") == 0) - { - update_dir[0] = '\0'; - stripped_dot = 1; - } - - /* make the recursive call */ - err += do_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, - dir_return, which, aflag, readlock, dosrcs); - - /* put the `.' back if necessary */ - if (stripped_dot) - (void) strcpy (update_dir, "."); - - /* call-back dir leave proc (if any) */ - if (dirleaveproc != NULL) - err = dirleaveproc (dir, err, update_dir); - - /* get back to where we started and restore state vars */ - if (restore_cwd (&cwd, NULL)) - exit (1); - free_cwd (&cwd); - dirlist = sdirlist; - repository = srepository; - } - - /* put back update_dir */ - if ((cp = strrchr (update_dir, '/')) != NULL) - *cp = '\0'; - else - update_dir[0] = '\0'; - - return (err); -} - -/* - * Add a node to a list allocating the list if necessary. - */ -static void -addlist (listp, key) - List **listp; - char *key; -{ - Node *p; - - if (*listp == NULL) - *listp = getlist (); - p = getnode (); - p->type = FILES; - p->key = xstrdup (key); - if (addnode (*listp, p) != 0) - freenode (p); -} - -static void -addfile (listp, dir, file) - List **listp; - char *dir; - char *file; -{ - Node *n; - - /* add this dir. */ - addlist (listp, dir); - - n = findnode (*listp, dir); - if (n == NULL) - { - error (1, 0, "can't find recently added dir node `%s' in start_recursion.", - dir); - } - - n->type = DIRS; - addlist ((List **) &n->data, file); - return; -} - -static int -unroll_files_proc (p, closure) - Node *p; - void *closure; -{ - Node *n; - struct recursion_frame *frame = (struct recursion_frame *) closure; - int err = 0; - List *save_dirlist; - char *save_update_dir = NULL; - struct saved_cwd cwd; - - /* if this dir was also an explicitly named argument, then skip - it. We'll catch it later when we do dirs. */ - n = findnode (dirlist, p->key); - if (n != NULL) - return (0); - - /* otherwise, call dorecusion for this list of files. */ - filelist = (List *) p->data; - save_dirlist = dirlist; - dirlist = NULL; - - if (strcmp(p->key, ".") != 0) - { - if (save_cwd (&cwd)) - exit (1); - if (chdir (p->key) < 0) - error (1, errno, "could not chdir to %s", p->key); - - save_update_dir = xstrdup (update_dir); - - if (*update_dir != '\0') - (void) strcat (update_dir, "/"); - - (void) strcat (update_dir, p->key); - } - - err += do_recursion (frame->fileproc, frame->filesdoneproc, - frame->direntproc, frame->dirleaveproc, - frame->flags, frame->which, frame->aflag, - frame->readlock, frame->dosrcs); - - if (save_update_dir != NULL) - { - (void) strcpy (update_dir, save_update_dir); - free (save_update_dir); - - if (restore_cwd (&cwd, NULL)) - exit (1); - free_cwd (&cwd); - } - - dirlist = save_dirlist; - filelist = NULL; - return(err); -} diff --git a/gnu/usr.bin/cvs/cvs/release.c b/gnu/usr.bin/cvs/cvs/release.c deleted file mode 100644 index c768bd3..0000000 --- a/gnu/usr.bin/cvs/cvs/release.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Release: "cancel" a checkout in the history log. - * - * - Don't allow release if anything is active - Don't allow release if not - * above or inside repository. - Don't allow release if ./CVS/Repository is - * not the same as the directory specified in the module database. - * - * - Enter a line in the history log indicating the "release". - If asked to, - * delete the local working directory. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)release.c 1.23 94/09/21 $"; -USE(rcsid); -#endif - -static void release_delete PROTO((char *dir)); - -static const char *const release_usage[] = -{ - "Usage: %s %s [-d] modules...\n", - "\t-d\tDelete the given directory.\n", - NULL -}; - -static short delete; - -int -release (argc, argv) - int argc; - char **argv; -{ - FILE *fp; - register int i, c; - char *repository, *srepos; - char line[PATH_MAX], update_cmd[PATH_MAX]; - char *thisarg; - int arg_start_idx; - -#ifdef SERVER_SUPPORT - if (!server_active) - { -#endif /* SERVER_SUPPORT */ - if (argc == -1) - usage (release_usage); - optind = 1; - while ((c = getopt (argc, argv, "Qdq")) != -1) - { - switch (c) - { - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'd': - delete++; - break; - case '?': - default: - usage (release_usage); - break; - } - } - argc -= optind; - argv += optind; -#ifdef SERVER_SUPPORT - } -#endif /* SERVER_SUPPORT */ - - /* We're going to run "cvs -n -q update" and check its output; if - * the output is sufficiently unalarming, then we release with no - * questions asked. Else we prompt, then maybe release. - */ - /* Construct the update command. */ - sprintf (update_cmd, "%s -n -q -d %s update", - program_path, CVSroot); - -#ifdef CLIENT_SUPPORT - /* Start the server; we'll close it after looping. */ - if (client_active) - { - start_server (); - ign_setup (); - } -#endif /* CLIENT_SUPPORT */ - - /* If !server_active, we already skipped over argv[0] in the "argc - -= optind;" statement above. But if server_active, we need to - skip it now. */ -#ifdef SERVER_SUPPORT - if (server_active) - arg_start_idx = 1; - else - arg_start_idx = 0; -#endif /* SERVER_SUPPORT */ - - for (i = arg_start_idx; i < argc; i++) - { - thisarg = argv[i]; - -#ifdef SERVER_SUPPORT - if (server_active) - { - /* Just log the release -- all the interesting stuff happened - * on the client. - */ - history_write ('F', thisarg, "", thisarg, ""); /* F == Free */ - } - else - { -#endif /* SERVER_SUPPORT */ - - /* - * If we are in a repository, do it. Else if we are in the parent of - * a directory with the same name as the module, "cd" into it and - * look for a repository there. - */ - if (isdir (thisarg)) - { - if (chdir (thisarg) < 0) - { - if (!really_quiet) - error (0, 0, "can't chdir to: %s", thisarg); - continue; - } - if (!isdir (CVSADM)) - { - if (!really_quiet) - error (0, 0, "no repository module: %s", thisarg); - continue; - } - } - else - { - if (!really_quiet) - error (0, 0, "no such directory: %s", thisarg); - continue; - } - - repository = Name_Repository ((char *) NULL, (char *) NULL); - srepos = Short_Repository (repository); - - if (!really_quiet) - { - /* The "release" command piggybacks on "update", which - * does the real work of finding out if anything is not - * up-to-date with the repository. Then "release" prompts - * the user, telling her how many files have been - * modified, and asking if she still wants to do the - * release. - */ - fp = Popen (update_cmd, "r"); - c = 0; - - while (fgets (line, sizeof (line), fp)) - { - if (strchr ("MARCZ", *line)) - c++; - (void) printf (line); - } - - /* If the update exited with an error, then we just want to - * complain and go on to the next arg. Especially, we do - * not want to delete the local copy, since it's obviously - * not what the user thinks it is. - */ - if ((pclose (fp)) != 0) - { - error (0, 0, "unable to release `%s'", thisarg); - continue; - } - - (void) printf ("You have [%d] altered files in this repository.\n", - c); - (void) printf ("Are you sure you want to release %smodule `%s': ", - delete ? "(and delete) " : "", thisarg); - c = !yesno (); - if (c) /* "No" */ - { - (void) fprintf (stderr, "** `%s' aborted by user choice.\n", - command_name); - free (repository); - continue; - } - } - -#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"); - } - else - { -#endif /* CLIENT_SUPPORT */ - history_write ('F', thisarg, "", thisarg, ""); /* F == Free */ -#ifdef CLIENT_SUPPORT - } /* else client not active */ -#endif /* CLIENT_SUPPORT */ - - free (repository); - if (delete) release_delete (thisarg); - -#ifdef CLIENT_SUPPORT - if (client_active) - return get_responses_and_close (); - else -#endif /* CLIENT_SUPPORT */ - return (0); - -#ifdef SERVER_SUPPORT - } /* else server not active */ -#endif /* SERVER_SUPPORT */ - } /* `for' loop */ - return (0); -} - - -/* We want to "rm -r" the working directory, but let us be a little - paranoid. */ -static void -release_delete (dir) - char *dir; -{ - struct stat st; - ino_t ino; - int retcode = 0; - - (void) stat (".", &st); - ino = st.st_ino; - (void) chdir (".."); - (void) stat (dir, &st); - if (ino != st.st_ino) - { - error (0, 0, - "Parent dir on a different disk, delete of %s aborted", dir); - return; - } - /* - * 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); -} diff --git a/gnu/usr.bin/cvs/cvs/remove.c b/gnu/usr.bin/cvs/cvs/remove.c deleted file mode 100644 index a33c4f9..0000000 --- a/gnu/usr.bin/cvs/cvs/remove.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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. - * - * Remove a File - * - * Removes entries from the present version. The entries will be removed from - * the RCS repository upon the next "commit". - * - * "remove" accepts no options, only file names that are to be removed. The - * file must not exist in the current directory for "remove" to work - * correctly. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)remove.c 1.39 94/10/07 $"; -USE(rcsid); -#endif - -static int remove_fileproc PROTO((char *file, char *update_dir, - char *repository, List *entries, - List *srcfiles)); -static Dtype remove_dirproc PROTO((char *dir, char *repos, char *update_dir)); - -static int force; -static int local; -static int removed_files; -static int existing_files; - -static const char *const remove_usage[] = -{ - "Usage: %s %s [-flR] [files...]\n", - "\t-f\tDelete the file before removing it.\n", - "\t-l\tProcess this directory only (not recursive).\n", - "\t-R\tProcess directories recursively.\n", - NULL -}; - -int -cvsremove (argc, argv) - int argc; - char **argv; -{ - int c, err; - - if (argc == -1) - usage (remove_usage); - - optind = 1; - while ((c = getopt (argc, argv, "flR")) != -1) - { - switch (c) - { - case 'f': - force = 1; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (remove_usage); - break; - } - } - argc -= optind; - argv += optind; - - wrap_setup (); - -#ifdef CLIENT_SUPPORT - if (client_active) { - start_server (); - ign_setup (); - if (local) - send_arg("-l"); - send_files (argc, argv, local, 0); - if (fprintf (to_server, "remove\n") < 0) - error (1, errno, "writing to server"); - 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); - - if (removed_files) - error (0, 0, "use '%s commit' to remove %s permanently", program_name, - (removed_files == 1) ? "this file" : "these files"); - - if (existing_files) - error (0, 0, - ((existing_files == 1) ? - "%d file exists; use `%s' to remove it first" : - "%d files exist; use `%s' to remove them first"), - existing_files, RM); - - return (err); -} - -/* - * remove the file, only if it has already been physically removed - */ -/* ARGSUSED */ -static int -remove_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - char fname[PATH_MAX]; - Vers_TS *vers; - - if (force) - { - 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); - - if (vers->ts_user != NULL) - { - existing_files++; - if (!quiet) - error (0, 0, "file `%s' still in working directory", file); - } - else if (vers->vn_user == NULL) - { - if (!quiet) - error (0, 0, "nothing known about `%s'", file); - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - /* - * It's a file that has been added, but not commited yet. So, - * 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_LOG); - (void) unlink_file (fname); - if (!quiet) - error (0, 0, "removed `%s'", file); - -#ifdef SERVER_SUPPORT - if (server_active) - server_checked_in (file, update_dir, repository); -#endif - } - else if (vers->vn_user[0] == '-') - { - if (!quiet) - error (0, 0, "file `%s' already scheduled for removal", file); - } - else - { - /* Re-register it with a negative version number. */ - (void) strcpy (fname, "-"); - (void) strcat (fname, vers->vn_user); - Register (entries, file, fname, vers->ts_rcs, vers->options, - vers->tag, vers->date, vers->ts_conflict); - if (!quiet) - error (0, 0, "scheduling `%s' for removal", file); - removed_files++; - -#ifdef SERVER_SUPPORT - if (server_active) - server_checked_in (file, update_dir, repository); -#endif - } - - freevers_ts (&vers); - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -remove_dirproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "Removing %s", update_dir); - return (R_PROCESS); -} diff --git a/gnu/usr.bin/cvs/cvs/repos.c b/gnu/usr.bin/cvs/cvs/repos.c deleted file mode 100644 index 8566433..0000000 --- a/gnu/usr.bin/cvs/cvs/repos.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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. - * - * Name of Repository - * - * Determine the name of the RCS repository and sets "Repository" accordingly. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)repos.c 1.32 94/09/23 $"; -USE(rcsid); -#endif - -char * -Name_Repository (dir, update_dir) - char *dir; - char *update_dir; -{ - FILE *fpin; - char *ret, *xupdate_dir; - char repos[PATH_MAX]; - char path[PATH_MAX]; - char tmp[PATH_MAX]; - char cvsadm[PATH_MAX]; - char *cp; - - if (update_dir && *update_dir) - xupdate_dir = update_dir; - else - xupdate_dir = "."; - - if (dir != NULL) - (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); - else - (void) strcpy (cvsadm, CVSADM); - - /* sanity checks */ - if (!isdir (cvsadm)) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "there is no version here; do '%s checkout' first", - program_name); - } - - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENT); - else - (void) strcpy (tmp, CVSADM_ENT); - - if (!isreadable (tmp)) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "*PANIC* administration files missing"); - } - - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_REP); - else - (void) strcpy (tmp, CVSADM_REP); - - if (!isreadable (tmp)) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "*PANIC* administration files missing"); - } - - /* - * The assumption here is that the repository is always contained in the - * first line of the "Repository" file. - */ - fpin = open_file (tmp, "r"); - - if (fgets (repos, PATH_MAX, fpin) == NULL) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, errno, "cannot read %s", CVSADM_REP); - } - (void) fclose (fpin); - if ((cp = strrchr (repos, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * If this is a relative repository pathname, turn it into an absolute - * one by tacking on the CVSROOT environment variable. If the CVSROOT - * environment variable is not set, die now. - */ - if (strcmp (repos, "..") == 0 || strncmp (repos, "../", 3) == 0) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, "`..'-relative repositories are not supported."); - error (1, 0, "illegal source repository"); - } - if (! isabsolute(repos)) - { - if (CVSroot == NULL) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, "must set the CVSROOT environment variable\n"); - error (0, 0, "or specify the '-d' option to %s.", program_name); - error (1, 0, "illegal repository setting"); - } - (void) strcpy (path, repos); - (void) sprintf (repos, "%s/%s", CVSroot, path); - } -#ifdef CLIENT_SUPPORT - if (!client_active && !isdir (repos)) -#else - if (!isdir (repos)) -#endif - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "there is no repository %s", repos); - } - - /* allocate space to return and fill it in */ - strip_path (repos); - ret = xstrdup (repos); - return (ret); -} - -/* - * Return a pointer to the repository name relative to CVSROOT from a - * possibly fully qualified repository - */ -char * -Short_Repository (repository) - char *repository; -{ - if (repository == NULL) - return (NULL); - - /* If repository matches CVSroot at the beginning, strip off CVSroot */ - /* And skip leading '/' in rep, in case CVSroot ended with '/'. */ - if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0) - { - char *rep = repository + strlen (CVSroot); - return (*rep == '/') ? rep+1 : rep; - } - else - return (repository); -} diff --git a/gnu/usr.bin/cvs/cvs/root.c b/gnu/usr.bin/cvs/cvs/root.c deleted file mode 100644 index e3cb979..0000000 --- a/gnu/usr.bin/cvs/cvs/root.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 1992, Mark D. Baushke - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS 1.4 kit. - * - * Name of Root - * - * Determine the path to the CVSROOT and set "Root" accordingly. - * If this looks like of modified clone of Name_Repository() in - * repos.c, it is... - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)root.c,v 1.2 1994/09/15 05:32:17 zoo Exp"; -USE(rcsid); -#endif - -char * -Name_Root(dir, update_dir) - char *dir; - char *update_dir; -{ - FILE *fpin; - char *ret, *xupdate_dir; - char root[PATH_MAX]; - char tmp[PATH_MAX]; - char cvsadm[PATH_MAX]; - char *cp; - - if (update_dir && *update_dir) - xupdate_dir = update_dir; - else - xupdate_dir = "."; - - if (dir != NULL) - { - (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT); - } - else - { - (void) strcpy (cvsadm, CVSADM); - (void) strcpy (tmp, CVSADM_ROOT); - } - - /* - * Do not bother looking for a readable file if there is no cvsadm - * directory present. - * - * 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. - */ - if ((!isdir (cvsadm)) || (!isreadable (tmp))) - { - if (CVSroot == NULL) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, "must set the CVSROOT environment variable"); - error (0, 0, "or specify the '-d' option to %s.", program_name); - } - return (NULL); - } - - /* - * The assumption here is that the CVS Root is always contained in the - * first line of the "Root" file. - */ - fpin = open_file (tmp, "r"); - - if (fgets (root, PATH_MAX, fpin) == NULL) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, errno, "cannot read %s", CVSADM_ROOT); - error (0, 0, "please correct this problem"); - return (NULL); - } - (void) fclose (fpin); - if ((cp = strrchr (root, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * root now contains a candidate for CVSroot. It must be an - * absolute pathname - */ - -#ifdef CLIENT_SUPPORT - /* It must specify a server via remote CVS or be an absolute pathname. */ - if ((strchr (root, ':') == NULL) - && ! isabsolute (root)) -#else - if (root[0] != '/') -#endif - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, - "ignoring %s because it does not contain an absolute pathname.", - CVSADM_ROOT); - return (NULL); - } - -#ifdef CLIENT_SUPPORT - if ((strchr (root, ':') == NULL) && !isdir (root)) -#else - if (!isdir (root)) -#endif - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, - "ignoring %s because it specifies a non-existent repository %s", - CVSADM_ROOT, root); - return (NULL); - } - - /* allocate space to return and fill it in */ - strip_path (root); - ret = xstrdup (root); - return (ret); -} - -/* - * Returns non-zero if the two directories have the same stat values - * which indicates that they are really the same directories. - */ -int -same_directories (dir1, dir2) - char *dir1; - char *dir2; -{ - struct stat sb1; - struct stat sb2; - int ret; - - if (stat (dir1, &sb1) < 0) - return (0); - if (stat (dir2, &sb2) < 0) - return (0); - - ret = 0; - if ( (memcmp( &sb1.st_dev, &sb2.st_dev, sizeof(dev_t) ) == 0) && - (memcmp( &sb1.st_ino, &sb2.st_ino, sizeof(ino_t) ) == 0)) - ret = 1; - - return (ret); -} - - -/* - * Write the CVS/Root file so that the environment variable CVSROOT - * and/or the -d option to cvs will be validated or not necessary for - * future work. - */ -void -Create_Root (dir, rootdir) - char *dir; - char *rootdir; -{ - FILE *fout; - char tmp[PATH_MAX]; - - if (noexec) - return; - - /* record the current cvs root */ - - if (rootdir != NULL) - { - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT); - else - (void) strcpy (tmp, CVSADM_ROOT); - fout = open_file (tmp, "w+"); - if (fprintf (fout, "%s\n", rootdir) < 0) - error (1, errno, "write to %s failed", tmp); - if (fclose (fout) == EOF) - error (1, errno, "cannot close %s", tmp); - } -} diff --git a/gnu/usr.bin/cvs/cvs/rtag.c b/gnu/usr.bin/cvs/cvs/rtag.c deleted file mode 100644 index 76e1776..0000000 --- a/gnu/usr.bin/cvs/cvs/rtag.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * 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. - * - * Rtag - * - * Add or delete a symbolic name to an RCS file, or a collection of RCS files. - * Uses the modules database, if necessary. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)rtag.c 1.61 94/09/30 $"; -USE(rcsid); -#endif - -static int check_fileproc PROTO((char *file, char *update_dir, - char *repository, List * entries, - List * srcfiles)); -static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir)); -static int pretag_proc PROTO((char *repository, char *filter)); -static void masterlist_delproc PROTO((Node *p)); -static void tag_delproc PROTO((Node *p)); -static int pretag_list_proc PROTO((Node *p, void *closure)); - -static Dtype rtag_dirproc PROTO((char *dir, char *repos, char *update_dir)); -static int rtag_fileproc PROTO((char *file, char *update_dir, - char *repository, List * entries, - List * srcfiles)); -static int rtag_proc PROTO((int *pargc, char **argv, char *xwhere, - char *mwhere, char *mfile, int shorten, - int local_specified, char *mname, char *msg)); -static int rtag_delete PROTO((RCSNode *rcsfile)); - - -struct tag_info -{ - Ctype status; - char *rev; - char *tag; - char *options; -}; - -struct master_lists -{ - List *tlist; -}; - -static List *mtlist; -static List *tlist; - -static char *symtag; -static char *numtag; -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 */ -static char *date; -static int local; /* recursive by default */ -static int force_tag_match = 1; /* force by default */ -static int force_tag_move; /* don't move existing tags by default */ - -static const char *const rtag_usage[] = -{ - "Usage: %s %s [-aflRnF] [-b] [-d] [-r tag|-D date] tag modules...\n", - "\t-a\tClear tag from removed files that would not otherwise be tagged.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-R\tProcess directories recursively.\n", - "\t-n\tNo execution of 'tag program'\n", - "\t-d\tDelete the given Tag.\n", - "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n", - "\t-[rD]\tExisting tag or Date.\n", - "\t-F\tMove tag if it already exists\n", - NULL -}; - -int -rtag (argc, argv) - int argc; - char **argv; -{ - register int i; - int c; - DBM *db; - int run_module_prog = 1; - int err = 0; - - if (argc == -1) - usage (rtag_usage); - - optind = 1; - while ((c = getopt (argc, argv, "FanfQqlRdbr:D:")) != -1) - { - switch (c) - { - case 'a': - attic_too = 1; - break; - case 'n': - run_module_prog = 0; - break; - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'd': - delete = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'b': - branch_mode = 1; - break; - case 'r': - numtag = optarg; - break; - case 'D': - if (date) - free (date); - date = Make_Date (optarg); - break; - case 'F': - force_tag_move = 1; - break; - case '?': - default: - usage (rtag_usage); - break; - } - } - argc -= optind; - argv += optind; - if (argc < 2) - usage (rtag_usage); - symtag = argv[0]; - 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); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (delete) - send_arg("-d"); - if (branch_mode) - send_arg("-b"); - if (force_tag_move) - send_arg("-F"); - if (run_module_prog) - send_arg("-n"); - if (attic_too) - send_arg("-a"); - - if (numtag) - option_with_arg ("-r", numtag); - if (date) - client_senddate (date); - - send_arg (symtag); - - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - } - - if (fprintf (to_server, "rtag\n") < 0) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } -#endif - - db = open_module (); - for (i = 0; i < argc; i++) - { - /* XXX last arg should be repository, but doesn't make sense here */ - history_write ('T', (delete ? "D" : (numtag ? numtag : - (date ? date : "A"))), symtag, argv[i], ""); - err += do_module (db, argv[i], TAG, delete ? "Untagging" : "Tagging", - rtag_proc, (char *) NULL, 0, 0, run_module_prog, - symtag); - } - close_module (db); - return (err); -} - -/* - * callback proc for doing the real work of tagging - */ -/* ARGSUSED */ -static int -rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, - mname, msg) - int *pargc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *mname; - char *msg; -{ - int err = 0; - int which; - char repository[PATH_MAX]; - char where[PATH_MAX]; - - (void) sprintf (repository, "%s/%s", CVSroot, argv[0]); - (void) strcpy (where, argv[0]); - - /* if mfile isn't null, we need to set up to do only part of the module */ - if (mfile != NULL) - { - char *cp; - char path[PATH_MAX]; - - /* if the portion of the module is a path, put the dir part on repos */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - (void) sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void) strcpy (repository, path); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - } - else - { - int i; - - /* a file means muck argv */ - for (i = 1; i < *pargc; i++) - free (argv[i]); - argv[1] = xstrdup (mfile); - (*pargc) = 2; - } - } - - /* chdir to the starting directory */ - if (chdir (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - return (1); - } - - if (delete || attic_too || (force_tag_match && numtag)) - which = W_REPOS | W_ATTIC; - else - which = W_REPOS; - - /* 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, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, - *pargc - 1, argv + 1, local, which, 0, 1, - where, 1, 1); - - if (err) - { - error (1, 0, "correct the above errors first!"); - } - - /* start the recursion processor */ - err = start_recursion (rtag_fileproc, (FILESDONEPROC) NULL, rtag_dirproc, - (DIRLEAVEPROC) NULL, *pargc - 1, argv + 1, local, - which, 0, 1, where, 1, 1); - - dellist(&mtlist); - - return (err); -} - -/* check file that is to be tagged */ -/* All we do here is add it to our list */ - -static int -check_fileproc(file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List * entries; - List * srcfiles; -{ - char *xdir; - Node *p; - Vers_TS *vers; - - if (update_dir[0] == '\0') - xdir = "."; - else - xdir = update_dir; - if ((p = findnode (mtlist, xdir)) != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - struct master_lists *ml; - - tlist = getlist (); - p = getnode (); - p->key = xstrdup (xdir); - p->type = UPDATE; - ml = (struct master_lists *) - xmalloc (sizeof (struct master_lists)); - ml->tlist = tlist; - p->data = (char *) ml; - p->delproc = masterlist_delproc; - (void) addnode (mtlist, p); - } - /* do tlist */ - p = getnode (); - p->key = xstrdup (file); - p->type = UPDATE; - 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, 0); - if (p->data != NULL) - { - int addit = 1; - char *oversion; - - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); - if (oversion == NULL) - { - if (delete) - { - addit = 0; - } - } - else if (strcmp(oversion, p->data) == 0) - { - addit = 0; - } - else if (!force_tag_move) - { - addit = 0; - } - if (oversion != NULL) - { - free(oversion); - } - if (!addit) - { - free(p->data); - p->data = NULL; - } - } - freevers_ts (&vers); - (void) addnode (tlist, p); - return (0); -} - -static int -check_filesdoneproc(err, repos, update_dir) - int err; - char *repos; - char *update_dir; -{ - int n; - Node *p; - - p = findnode(mtlist, update_dir); - if (p != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - tlist = (List *) NULL; - } - if ((tlist == NULL) || (tlist->list->next == tlist->list)) - { - return (err); - } - if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0) - { - error (0, 0, "Pre-tag check failed"); - err += n; - } - return (err); -} - -static int -pretag_proc(repository, filter) - char *repository; - char *filter; -{ - if (filter[0] == '/') - { - char *s, *cp; - - s = xstrdup(filter); - for (cp=s; *cp; cp++) - { - if (isspace(*cp)) - { - *cp = '\0'; - break; - } - } - if (!isfile(s)) - { - error (0, errno, "cannot find pre-tag filter '%s'", s); - free(s); - return (1); - } - free(s); - } - run_setup("%s %s %s %s", - filter, - symtag, - delete ? "del" : force_tag_move ? "mov" : "add", - repository); - walklist(tlist, pretag_list_proc, NULL); - return (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY)); -} - -static void -masterlist_delproc(p) - Node *p; -{ - struct master_lists *ml; - - ml = (struct master_lists *)p->data; - dellist(&ml->tlist); - free(ml); - return; -} - -static void -tag_delproc(p) - Node *p; -{ - if (p->data != NULL) - { - free(p->data); - p->data = NULL; - } - return; -} - -static int -pretag_list_proc(p, closure) - Node *p; - void *closure; -{ - if (p->data != NULL) - { - run_arg(p->key); - run_arg(p->data); - } - return (0); -} - -/* - * Called to tag a particular file, as appropriate with the options that were - * set above. - */ -/* ARGSUSED */ -static int -rtag_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Node *p; - RCSNode *rcsfile; - char *version, *rev; - int retcode = 0; - - /* find the parsed RCS data */ - p = findnode (srcfiles, file); - if (p == NULL) - return (1); - rcsfile = (RCSNode *) p->data; - - /* - * For tagging an RCS file which is a symbolic link, you'd best be - * running with RCS 5.6, since it knows how to handle symbolic links - * correctly without breaking your link! - */ - - if (delete) - return (rtag_delete (rcsfile)); - - /* - * If we get here, we are adding a tag. But, if -a was specified, we - * need to check to see if a -r or -D option was specified. If neither - * was specified and the file is in the Attic, remove the tag. - */ - if (attic_too && (!numtag && !date)) - { - if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) - return (rtag_delete (rcsfile)); - } - - version = RCS_getversion (rcsfile, numtag, date, force_tag_match, 0); - if (version == NULL) - { - /* If -a specified, clean up any old tags */ - if (attic_too) - (void) rtag_delete (rcsfile); - - if (!quiet && !force_tag_match) - { - error (0, 0, "cannot find tag `%s' in `%s'", - numtag ? numtag : "head", rcsfile->path); - return (1); - } - return (0); - } - if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0) - { - - /* - * We didn't find a match for the numeric tag that was specified, but - * that's OK. just pass the numeric tag on to rcs, to be tagged as - * specified. Could get here if one tried to tag "1.1.1" and there - * was a 1.1.1 branch with some head revision. In this case, we want - * the tag to reference "1.1.1" and not the revision at the head of - * the branch. Use a symbolic tag for that. - */ - rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag; - retcode = RCS_settag(rcsfile->path, symtag, numtag); - } - else - { - char *oversion; - - /* - * As an enhancement for the case where a tag is being re-applied to - * a large body of a module, make one extra call to Version_Number to - * see if the tag is already set in the RCS file. If so, check to - * see if it needs to be moved. If not, do nothing. This will - * likely save a lot of time when simply moving the tag to the - * "current" head revisions of a module -- which I have found to be a - * typical tagging operation. - */ - rev = branch_mode ? RCS_magicrev (rcsfile, version) : version; - oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0); - if (oversion != NULL) - { - int isbranch = RCS_isbranch (file, symtag, srcfiles); - - /* - * if versions the same and neither old or new are branches don't - * have to do anything - */ - if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) - { - free (oversion); - free (version); - return (0); - } - - if (!force_tag_move) { /* we're NOT going to move the tag */ - if (update_dir[0]) - (void) printf ("W %s/%s", update_dir, file); - else - (void) printf ("W %s", file); - - (void) printf (" : %s already exists on %s %s", - symtag, isbranch ? "branch" : "version", oversion); - (void) printf (" : NOT MOVING tag to %s %s\n", - branch_mode ? "branch" : "version", rev); - free (oversion); - free (version); - return (0); - } - free (oversion); - } - retcode = RCS_settag(rcsfile->path, symtag, rev); - } - - if (retcode != 0) - { - error (1, retcode == -1 ? errno : 0, - "failed to set tag `%s' to revision `%s' in `%s'", - symtag, rev, rcsfile->path); - free (version); - return (1); - } - free (version); - return (0); -} - -/* - * If -d is specified, "force_tag_match" is set, so that this call to - * Version_Number() will return a NULL version string if the symbolic - * tag does not exist in the RCS file. - * - * If the -r flag was used, numtag is set, and we only delete the - * symtag from files that have numtag. - * - * This is done here because it's MUCH faster than just blindly calling - * "rcs" to remove the tag... trust me. - */ -static int -rtag_delete (rcsfile) - RCSNode *rcsfile; -{ - char *version; - int retcode; - - if (numtag) - { - version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1, 0); - if (version == NULL) - return (0); - free (version); - } - - version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, 0); - if (version == NULL) - return (0); - free (version); - - if ((retcode = RCS_deltag(rcsfile->path, symtag, 1)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag `%s' from `%s'", symtag, - rcsfile->path); - return (1); - } - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -rtag_dirproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir); - return (R_PROCESS); -} - - - diff --git a/gnu/usr.bin/cvs/cvs/sanity.sh b/gnu/usr.bin/cvs/cvs/sanity.sh deleted file mode 100644 index 21aa454..0000000 --- a/gnu/usr.bin/cvs/cvs/sanity.sh +++ /dev/null @@ -1,1674 +0,0 @@ -#! /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} @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 a final "OK".' - -if test x"$1" = x"-r"; then - shift - remote=yes -else - remote=no -fi - -# Use full path for CVS executable, so that CVS_SERVER gets set properly -# for remote. -case $1 in -/*) - testcvs=$1 - ;; -*) - testcvs=`pwd`/$1 - ;; -esac - -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. -# -# 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}. -# and then they've obviously got to do something with the output.... -# -CVS="${testcvs} -Q -f" - -LOGFILE=`pwd`/check.log - -# 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 - -# clean any old remnants -rm -rf ${TESTDIR} -mkdir ${TESTDIR} -cd ${TESTDIR} - -# Remaining arguments are the names of tests to run. -# -# FIXME: not all combinations are possible; basic3 depends on files set up -# by previous tests, 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="basic0 basic1 basic2 basic3 rtags death import new conflicts modules mflag errmsg1" -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 -else - 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 -else - 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 -else - echo "PASS: test 3" >>${LOGFILE} -fi - -# This one should work, although it should spit a warning. -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 - -# This one should succeed. No warnings. -mkdir tmp ; cd tmp -if ${CVS} -d `pwd`/../cvsroot co CVSROOT ; then - echo "PASS: test 4" >>${LOGFILE} -else - echo "FAIL: test 4" | tee -a ${LOGFILE} - exit 1 -fi - -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 -if [ -d tmp ] ; then - echo "FAIL: test 4.75" | tee -a ${LOGFILE} - exit 1 -fi - -# 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_DIRNAME=${TESTDIR}/cvsroot -CVSROOT=${CVSROOT_DIRNAME} ; export CVSROOT -if test "x$remote" = xyes; then - 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 - -mkdir tmp ; cd tmp -if ${CVS} co CVSROOT ; then - if [ -r CVSROOT/CVS/Entries ] ; then - echo "PASS: test 5" >>${LOGFILE} - else - echo "FAIL: test 5" | tee -a ${LOGFILE} - exit 1 - fi -else - echo "FAIL: test 5" | tee -a ${LOGFILE}; exit 1 -fi - -if echo "yes" | ${CVS} release -d CVSROOT ; then - echo "PASS: test 5.5" >>${LOGFILE} -else - echo "FAIL: test 5.5" | tee -a ${LOGFILE} - exit 1 -fi -# this had better etmpy now... -cd ..; rmdir tmp -if [ -d tmp ] ; then - echo "FAIL: test 5.75" | tee -a ${LOGFILE} - exit 1 -fi - -# start keeping history -touch ${CVSROOT_DIRNAME}/CVSROOT/history - -### The big loop -for what in $tests; do - case $what in - basic0) # Now, let's build something. -# mkdir first-dir - # this doesn't yet work, though I think maybe it should. xoxorich. -# if ${CVS} add first-dir ; then -# true -# else -# echo cvs does not yet add top level directories cleanly. - mkdir ${CVSROOT_DIRNAME}/first-dir -# fi -# rm -rf first-dir - - # check out an empty directory - if ${CVS} co first-dir ; then - 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 - - # update the empty directory - if ${CVS} update first-dir ; then - echo "PASS: test 7" >>${LOGFILE} - else - echo "FAIL: test 7" | tee -a ${LOGFILE}; exit 1 - fi - - # diff -u the empty directory - if ${CVS} diff -u first-dir ; then - echo "PASS: test 8" >>${LOGFILE} - else - echo "FAIL: test 8" | tee -a ${LOGFILE}; exit 1 - fi - - # diff -c the empty directory - if ${CVS} diff -c first-dir ; then - echo "PASS: test 9" >>${LOGFILE} - else - echo "FAIL: test 9" | tee -a ${LOGFILE}; exit 1 - fi - - # log the empty directory - if ${CVS} log first-dir ; then - echo "PASS: test 10" >>${LOGFILE} - else - echo "FAIL: test 10" | tee -a ${LOGFILE}; exit 1 - fi - - # status the empty directory - if ${CVS} status first-dir ; then - echo "PASS: test 11" >>${LOGFILE} - else - echo "FAIL: test 11" | tee -a ${LOGFILE}; exit 1 - fi - - # tag the empty directory - if ${CVS} tag first first-dir ; then - echo "PASS: test 12" >>${LOGFILE} - else - echo "FAIL: test 12" | tee -a ${LOGFILE}; exit 1 - fi - - # rtag the empty directory - if ${CVS} rtag empty first-dir ; then - echo "PASS: test 13" >>${LOGFILE} - else - echo "FAIL: test 13" | tee -a ${LOGFILE}; exit 1 - fi - ;; - - basic1) # first dive - add a files, first singly, then in a group. - rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -rf first-dir - mkdir ${CVSROOT_DIRNAME}/first-dir - # check out an empty directory - if ${CVS} co first-dir ; then - echo "PASS: test 13a" >>${LOGFILE} - else - echo "FAIL: test 13a" | tee -a ${LOGFILE}; exit 1 - fi - - cd first-dir - files=first-file - for i in a b ; do - for j in ${files} ; do - echo $j > $j - done - - for do in add rm ; do - for j in ${do} "commit -m test" ; do - # ${do} - if ${CVS} $j ${files} >> ${LOGFILE} 2>&1; then - echo "PASS: test 14-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 14-${do}-$j" | tee -a ${LOGFILE}; exit 1 - fi - - # update it. - if [ "${do}" = "rm" -a "$j" != "commit -m test" ] || ${CVS} update ${files} ; then - echo "PASS: test 15-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 15-${do}-$j" | tee -a ${LOGFILE}; exit 1 - fi - - # update all. - if ${CVS} update ; then - echo "PASS: test 16-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 16-${do}-$j" | tee -a ${LOGFILE}; exit 1 - fi - - # status all. - if ${CVS} status >> ${LOGFILE}; then - echo "PASS: test 17-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 17-${do}-$j" | tee -a ${LOGFILE}; exit 1 - fi - - # FIXME: this one doesn't work yet for added files. - # log all. - if ${CVS} log >> ${LOGFILE}; then - echo "PASS: test 18-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 18-${do}-$j" | tee -a ${LOGFILE} - fi - - if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then - true - else - # diff -c all - if ${CVS} diff -c >> ${LOGFILE} || [ $? = 1 ] ; then - echo "PASS: test 19-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 19-${do}-$j" | tee -a ${LOGFILE} - fi - - # diff -u all - if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then - echo "PASS: test 20-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 20-${do}-$j" | tee -a ${LOGFILE} - fi - fi - - cd .. - # update all. - if ${CVS} update ; then - echo "PASS: test 21-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 21-${do}-$j" | tee -a ${LOGFILE}; exit 1 - fi - - # log all. - # FIXME: doesn't work right for added files. - if ${CVS} log first-dir >> ${LOGFILE}; then - echo "PASS: test 22-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 22-${do}-$j" | tee -a ${LOGFILE} - fi - - # status all. - if ${CVS} status first-dir >> ${LOGFILE}; then - echo "PASS: test 23-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 23-${do}-$j" | tee -a ${LOGFILE}; exit 1 - fi - - # update all. - if ${CVS} update first-dir ; then - echo "PASS: test 24-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 24-${do}-$j" | tee -a ${LOGFILE} ; exit 1 - fi - - if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then - echo "PASS: test 25-${do}-$j" >>${LOGFILE} - else - # diff all - if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then - echo "PASS: test 25-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 25-${do}-$j" | tee -a ${LOGFILE} - # FIXME; exit 1 - fi - - # diff all - if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then - echo "PASS: test 26-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 26-${do}-$j" | tee -a ${LOGFILE} - # FIXME; exit 1 - fi - fi - - # update all. - if ${CVS} co first-dir ; then - echo "PASS: test 27-${do}-$j" >>${LOGFILE} - else - echo "FAIL: test 27-${do}-$j" | tee -a ${LOGFILE} ; exit 1 - fi - - cd first-dir - done # j - rm -f ${files} - done # do - - files="file2 file3 file4 file5" - done - if ${CVS} tag first-dive ; then - echo "PASS: test 28" >>${LOGFILE} - else - echo "FAIL: test 28" | tee -a ${LOGFILE} ; exit 1 - fi - cd .. - ;; - - basic2) # second dive - add bunch o' files in bunch o' added directories - for i in first-dir dir1 dir2 dir3 dir4 ; do - if [ ! -d $i ] ; then - mkdir $i - if ${CVS} add $i >> ${LOGFILE}; then - echo "PASS: test 29-$i" >>${LOGFILE} - else - echo "FAIL: test 29-$i" | tee -a ${LOGFILE} ; exit 1 - fi - fi - - cd $i - - for j in file6 file7 file8 file9 file10 file11 file12 file13; do - echo $j > $j - done - - if ${CVS} add file6 file7 file8 file9 file10 file11 file12 file13 2>> ${LOGFILE}; then - echo "PASS: test 30-$i-$j" >>${LOGFILE} - else - echo "FAIL: test 30-$i-$j" | tee -a ${LOGFILE} ; exit 1 - fi - done - cd ../../../../.. - if ${CVS} update first-dir ; then - echo "PASS: test 31" >>${LOGFILE} - else - 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 - echo "PASS: test 32" >>${LOGFILE} - else - echo "FAIL: test 32" | tee -a ${LOGFILE} # ; exit 1 - fi - - if ${CVS} status first-dir >> ${LOGFILE}; then - echo "PASS: test 33" >>${LOGFILE} - else - echo "FAIL: test 33" | tee -a ${LOGFILE} ; exit 1 - fi - -# if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then -# echo "PASS: test 34" >>${LOGFILE} -# else -# echo "FAIL: test 34" | tee -a ${LOGFILE} # ; exit 1 -# fi - - if ${CVS} ci -m "second dive" first-dir >> ${LOGFILE} 2>&1; then - echo "PASS: test 35" >>${LOGFILE} - else - echo "FAIL: test 35" | tee -a ${LOGFILE} ; exit 1 - fi - - if ${CVS} tag second-dive first-dir ; then - echo "PASS: test 36" >>${LOGFILE} - else - 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. - for i in first-dir dir1 dir2 dir3 dir4 ; do - cd $i - - # modify some files - for j in file6 file8 file10 file12 ; do - echo $j >> $j - done - - # delete some files - rm file7 file9 file11 file13 - - if ${CVS} rm file7 file9 file11 file13 2>> ${LOGFILE}; then - echo "PASS: test 37-$i" >>${LOGFILE} - else - echo "FAIL: test 37-$i" | tee -a ${LOGFILE} ; exit 1 - fi - - # and add some new ones - for j in file14 file15 file16 file17 ; do - echo $j > $j - done - - if ${CVS} add file14 file15 file16 file17 2>> ${LOGFILE}; then - echo "PASS: test 38-$i" >>${LOGFILE} - else - echo "FAIL: test 38-$i" | tee -a ${LOGFILE} ; exit 1 - fi - done - cd ../../../../.. - if ${CVS} update first-dir ; then - echo "PASS: test 39" >>${LOGFILE} - else - 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 - echo "PASS: test 40" >>${LOGFILE} - else - echo "FAIL: test 40" | tee -a ${LOGFILE} # ; exit 1 - fi - - if ${CVS} status first-dir >> ${LOGFILE}; then - echo "PASS: test 41" >>${LOGFILE} - else - echo "FAIL: test 41" | tee -a ${LOGFILE} ; exit 1 - fi - -# if ${CVS} diff -u first-dir >> ${LOGFILE} || [ $? = 1 ] ; then -# echo "PASS: test 42" >>${LOGFILE} -# else -# echo "FAIL: test 42" | tee -a ${LOGFILE} # ; exit 1 -# fi - - if ${CVS} ci -m "third dive" first-dir >>${LOGFILE} 2>&1; then - echo "PASS: test 43" >>${LOGFILE} - else - echo "FAIL: test 43" | tee -a ${LOGFILE} ; exit 1 - fi - - if ${CVS} tag third-dive first-dir ; then - echo "PASS: test 44" >>${LOGFILE} - else - echo "FAIL: test 44" | tee -a ${LOGFILE} ; 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 - if [ -d test-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 - echo "PASS: test 46" >>${LOGFILE} - else - 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 - echo "PASS: test 47" >>${LOGFILE} - else - echo "FAIL: test 47" | tee -a ${LOGFILE} ; exit 1 - fi - - # tag by revision - if ${CVS} rtag -r1.1 rtagged-by-revision first-dir ; then - echo "PASS: test 48" >>${LOGFILE} - else - 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 - echo "PASS: test 49" >>${LOGFILE} - else - 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 - echo "PASS: test 50" >>${LOGFILE} - else - echo "FAIL: test 50" | tee -a ${LOGFILE} ; exit 1 - fi - - mv first-dir 1dir - if ${CVS} export -r rtagged-by-tag first-dir ; then - echo "PASS: test 51" >>${LOGFILE} - else - echo "FAIL: test 51" | tee -a ${LOGFILE} ; exit 1 - fi - - directory_cmp 1dir first-dir - - if $ISDIFF ; then - echo "FAIL: test 52" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 52" >>${LOGFILE} - fi - rm -rf 1dir first-dir - - # 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 -r1.1 first-dir ; then - echo "PASS: test 54" >>${LOGFILE} - else - echo "FAIL: test 54" | tee -a ${LOGFILE} ; exit 1 - fi - - # 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 -)) - - directory_cmp first-dir export-dir - - if $ISDIFF ; then - echo "FAIL: test 55" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 55" >>${LOGFILE} - fi - - # interrupt, while we've got a clean 1.1 here, let's import it into another tree. - cd export-dir - if ${CVS} import -m "first-import" second-dir first-immigration immigration1 immigration1_0 ; then - echo "PASS: test 56" >>${LOGFILE} - else - echo "FAIL: test 56" | tee -a ${LOGFILE} ; exit 1 - fi - cd .. - - if ${CVS} export -r HEAD second-dir ; then - echo "PASS: test 57" >>${LOGFILE} - else - echo "FAIL: test 57" | tee -a ${LOGFILE} ; exit 1 - fi - - directory_cmp first-dir second-dir - - if $ISDIFF ; then - echo "FAIL: test 58" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 58" >>${LOGFILE} - fi - - 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 - echo "PASS: test 59" >>${LOGFILE} - else - 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 - echo "PASS: test 60a" >>${LOGFILE} - else - echo "FAIL: test 60a" | tee -a ${LOGFILE} ; exit 1 - fi - if ${CVS} tag -l rtagged-by-revision ; then - echo "PASS: test 60b" >>${LOGFILE} - else - echo "FAIL: test 60b" | tee -a ${LOGFILE} ; exit 1 - fi - - cd .. - mv first-dir 1dir - mv first-dir.cpy first-dir - cd first-dir - - if ${CVS} diff -u >> ${LOGFILE} || [ $? = 1 ] ; then - echo "PASS: test 61" >>${LOGFILE} - else - echo "FAIL: test 61" | tee -a ${LOGFILE} ; exit 1 - fi - - if ${CVS} update ; then - echo "PASS: test 62" >>${LOGFILE} - else - echo "FAIL: test 62" | tee -a ${LOGFILE} ; exit 1 - fi - - cd .. - - #### 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 "PASS: test 63" >>${LOGFILE} -# fi - rm -rf 1dir first-dir - - if ${CVS} his -e -a >> ${LOGFILE}; then - echo "PASS: test 64" >>${LOGFILE} - else - echo "FAIL: test 64" | tee -a ${LOGFILE} ; exit 1 - fi - ;; - - death) # next dive. test death support. - rm -rf ${CVSROOT_DIRNAME}/first-dir - mkdir ${CVSROOT_DIRNAME}/first-dir - if ${CVS} co first-dir ; then - echo "PASS: test 65" >>${LOGFILE} - else - echo "FAIL: test 65" | tee -a ${LOGFILE} ; exit 1 - fi - - cd first-dir - - # add a file. - touch file1 - if ${CVS} add file1 2>> ${LOGFILE}; then - echo "PASS: test 66" >>${LOGFILE} - else - echo "FAIL: test 66" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - echo "PASS: test 67" >>${LOGFILE} - else - echo "FAIL: test 67" | tee -a ${LOGFILE} ; exit 1 - fi - - # remove - rm file1 - if ${CVS} rm file1 2>> ${LOGFILE}; then - echo "PASS: test 68" >>${LOGFILE} - else - echo "FAIL: test 68" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE} ; then - echo "PASS: test 69" >>${LOGFILE} - else - 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 - echo "PASS: test 70" >>${LOGFILE} - else - echo "FAIL: test 70" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - echo "PASS: test 71" >>${LOGFILE} - else - echo "FAIL: test 71" | tee -a ${LOGFILE} ; exit 1 - fi - - # log - if ${CVS} log file1 >> ${LOGFILE}; then - echo "PASS: test 72" >>${LOGFILE} - else - echo "FAIL: test 72" | tee -a ${LOGFILE} ; exit 1 - fi - - - # branch1 - if ${CVS} tag -b branch1 ; then - echo "PASS: test 73" >>${LOGFILE} - else - echo "FAIL: test 73" | tee -a ${LOGFILE} ; exit 1 - fi - - # and move to the branch. - if ${CVS} update -r branch1 ; then - echo "PASS: test 74" >>${LOGFILE} - else - echo "FAIL: test 74" | tee -a ${LOGFILE} ; exit 1 - fi - - # add a file in the branch - echo line1 from branch1 >> file3 - if ${CVS} add file3 2>> ${LOGFILE}; then - echo "PASS: test 75" >>${LOGFILE} - else - echo "FAIL: test 75" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - echo "PASS: test 76" >>${LOGFILE} - else - echo "FAIL: test 76" | tee -a ${LOGFILE} ; exit 1 - fi - - # remove - rm file3 - if ${CVS} rm file3 2>> ${LOGFILE}; then - echo "PASS: test 77" >>${LOGFILE} - else - echo "FAIL: test 77" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE} ; then - echo "PASS: test 78" >>${LOGFILE} - else - echo "FAIL: test 78" | tee -a ${LOGFILE} ; exit 1 - fi - - # add again - echo line1 from branch1 >> file3 - if ${CVS} add file3 2>> ${LOGFILE}; then - echo "PASS: test 79" >>${LOGFILE} - else - echo "FAIL: test 79" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - echo "PASS: test 80" >>${LOGFILE} - else - echo "FAIL: test 80" | tee -a ${LOGFILE} ; exit 1 - fi - - # change the first file - echo line2 from branch1 >> file1 - - # commit - if ${CVS} ci -m test >> ${LOGFILE} 2>&1; then - echo "PASS: test 81" >>${LOGFILE} - else - echo "FAIL: test 81" | tee -a ${LOGFILE} ; exit 1 - fi - - # remove the second - rm file2 - if ${CVS} rm file2 2>> ${LOGFILE}; then - echo "PASS: test 82" >>${LOGFILE} - else - echo "FAIL: test 82" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE}; then - echo "PASS: test 83" >>${LOGFILE} - else - echo "FAIL: test 83" | tee -a ${LOGFILE} ; exit 1 - fi - - # back to the trunk. - if ${CVS} update -A 2>> ${LOGFILE}; then - echo "PASS: test 84" >>${LOGFILE} - else - echo "FAIL: test 84" | tee -a ${LOGFILE} ; exit 1 - fi - - if [ -f file3 ] ; then - echo "FAIL: test 85" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 85" >>${LOGFILE} - fi - - # join - if ${CVS} update -j branch1 >> ${LOGFILE} 2>&1; then - echo "PASS: test 86" >>${LOGFILE} - else - echo "FAIL: test 86" | tee -a ${LOGFILE} ; exit 1 - fi - - if [ -f file3 ] ; then - echo "PASS: test 87" >>${LOGFILE} - else - 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 - echo "PASS: test 88" >>${LOGFILE} - else - echo "FAIL: test 88" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE} 2>&1; then - echo "PASS: test 89" >>${LOGFILE} - else - echo "FAIL: test 89" | tee -a ${LOGFILE} ; exit 1 - fi - - # remove first file. - rm file1 - if ${CVS} rm file1 2>> ${LOGFILE}; then - echo "PASS: test 90" >>${LOGFILE} - else - echo "FAIL: test 90" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m test >>${LOGFILE}; then - echo "PASS: test 91" >>${LOGFILE} - else - echo "FAIL: test 91" | tee -a ${LOGFILE} ; exit 1 - fi - - if [ -f file1 ] ; then - echo "FAIL: test 92" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 92" >>${LOGFILE} - fi - - # back to branch1 - if ${CVS} update -r branch1 2>> ${LOGFILE}; then - echo "PASS: test 93" >>${LOGFILE} - else - echo "FAIL: test 93" | tee -a ${LOGFILE} ; exit 1 - fi - - if [ -f file1 ] ; then - echo "PASS: test 94" >>${LOGFILE} - else - echo "FAIL: test 94" | tee -a ${LOGFILE} ; exit 1 - fi - - # and join - if ${CVS} update -j HEAD >> ${LOGFILE} 2>&1; then - echo "PASS: test 95" >>${LOGFILE} - else - echo "FAIL: test 95" | tee -a ${LOGFILE} ; exit 1 - fi - - cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - ;; - - import) # test death after import - # import - mkdir import-dir ; cd import-dir - - for i in 1 2 3 4 ; do - echo imported file"$i" > imported-file"$i" - done - - if ${CVS} import -m first-import first-dir vendor-branch junk-1_0 ; then - echo "PASS: test 96" >>${LOGFILE} - else - echo "FAIL: test 96" | tee -a ${LOGFILE} ; exit 1 - fi - cd .. - - # co - if ${CVS} co first-dir ; then - echo "PASS: test 97" >>${LOGFILE} - else - 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 - echo "PASS: test 98-$i" >>${LOGFILE} - else - echo "FAIL: test 98-$i" | tee -a ${LOGFILE} ; exit 1 - fi - done - - # remove - rm imported-file1 - if ${CVS} rm imported-file1 2>> ${LOGFILE}; then - echo "PASS: test 99" >>${LOGFILE} - else - echo "FAIL: test 99" | tee -a ${LOGFILE} ; exit 1 - fi - - # change - # this sleep is significant. Otherwise, on some machines, things happen so - # fast that the file mod times do not differ. - sleep 1 - echo local-change >> imported-file2 - - # commit - if ${CVS} ci -m local-changes >> ${LOGFILE} 2>&1; then - echo "PASS: test 100" >>${LOGFILE} - else - echo "FAIL: test 100" | tee -a ${LOGFILE} ; exit 1 - fi - - # log - if ${CVS} log imported-file1 | grep '1.1.1.2 (dead)' ; then - echo "FAIL: test 101" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 101" >>${LOGFILE} - fi - - # update into the vendor branch. - if ${CVS} update -rvendor-branch ; then - echo "PASS: test 102" >>${LOGFILE} - else - 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 - echo "PASS: test 103" >>${LOGFILE} - else - echo "FAIL: test 103" | tee -a ${LOGFILE} ; exit 1 - fi - - # commit - if ${CVS} ci -m vendor-removed imported-file4 >>${LOGFILE}; then - echo "PASS: test 104" >>${LOGFILE} - else - echo "FAIL: test 104" | tee -a ${LOGFILE} ; exit 1 - fi - - # update to main line - if ${CVS} update -A 2>> ${LOGFILE}; then - echo "PASS: test 105" >>${LOGFILE} - else - echo "FAIL: test 105" | tee -a ${LOGFILE} ; exit 1 - fi - - # second import - file4 deliberately unchanged - cd ../import-dir - for i in 1 2 3 ; do - echo rev 2 of file $i >> imported-file"$i" - done - - if ${CVS} import -m second-import first-dir vendor-branch junk-2_0 ; then - echo "PASS: test 106" >>${LOGFILE} - else - echo "FAIL: test 106" | tee -a ${LOGFILE} ; exit 1 - fi - cd .. - - # co - if ${CVS} co first-dir ; then - echo "PASS: test 107" >>${LOGFILE} - else - echo "FAIL: test 107" | tee -a ${LOGFILE} ; exit 1 - fi - - cd first-dir - - if [ -f imported-file1 ] ; then - echo "FAIL: test 108" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 108" >>${LOGFILE} - fi - - for i in 2 3 ; do - if [ -f imported-file"$i" ] ; then - echo "PASS: test 109-$i" >>${LOGFILE} - else - echo "FAIL: test 109-$i" | tee -a ${LOGFILE} ; exit 1 - fi - done - - # check vendor branch for file4 - if ${CVS} update -rvendor-branch ; then - echo "PASS: test 110" >>${LOGFILE} - else - echo "FAIL: test 110" | tee -a ${LOGFILE} ; exit 1 - fi - - if [ -f imported-file4 ] ; then - echo "PASS: test 111" >>${LOGFILE} - else - echo "FAIL: test 111" | tee -a ${LOGFILE} ; exit 1 - fi - - # update to main line - if ${CVS} update -A 2>> ${LOGFILE}; then - echo "PASS: test 112" >>${LOGFILE} - else - 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 - echo "PASS: test 113" >>${LOGFILE} - else - echo "FAIL: test 113" | tee -a ${LOGFILE} ; exit 1 - fi - - cd first-dir - - if [ -f imported-file1 ] ; then - echo "FAIL: test 114" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 114" >>${LOGFILE} - fi - - for i in 2 3 ; do - if [ -f imported-file"$i" ] ; then - echo "PASS: test 115-$i" >>${LOGFILE} - else - echo "FAIL: test 115-$i" | tee -a ${LOGFILE} ; exit 1 - fi - done - - if cat imported-file2 | grep '====' >> ${LOGFILE}; then - echo "PASS: test 116" >>${LOGFILE} - else - echo "FAIL: test 116" | tee -a ${LOGFILE} ; exit 1 - fi - cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - ;; - - new) # look for stray "no longer pertinent" messages. - rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - mkdir ${CVSROOT_DIRNAME}/first-dir - - if ${CVS} co first-dir ; then - echo "PASS: test 117" >>${LOGFILE} - else - echo "FAIL: test 117" | tee -a ${LOGFILE} ; exit 1 - fi - - cd first-dir - touch a - - if ${CVS} add a 2>>${LOGFILE}; then - echo "PASS: test 118" >>${LOGFILE} - else - echo "FAIL: test 118" | tee -a ${LOGFILE} ; exit 1 - fi - - if ${CVS} ci -m added >>${LOGFILE} 2>&1; then - echo "PASS: test 119" >>${LOGFILE} - else - echo "FAIL: test 119" | tee -a ${LOGFILE} ; exit 1 - fi - - rm a - - if ${CVS} rm a 2>>${LOGFILE}; then - echo "PASS: test 120" >>${LOGFILE} - else - echo "FAIL: test 120" | tee -a ${LOGFILE} ; exit 1 - fi - - if ${CVS} ci -m removed >>${LOGFILE} ; then - echo "PASS: test 121" >>${LOGFILE} - else - echo "FAIL: test 121" | tee -a ${LOGFILE} ; exit 1 - fi - - if ${CVS} update -A 2>&1 | grep longer ; then - echo "FAIL: test 122" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 122" >>${LOGFILE} - fi - - if ${CVS} update -rHEAD 2>&1 | grep longer ; then - echo "FAIL: test 123" | tee -a ${LOGFILE} ; exit 1 - else - echo "PASS: test 123" >>${LOGFILE} - fi - - cd .. ; rm -rf first-dir ; rm -rf ${CVSROOT_DIRNAME}/first-dir - ;; - - conflicts) - rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - mkdir ${CVSROOT_DIRNAME}/first-dir - - mkdir 1 - cd 1 - - if ${CVS} co first-dir ; then - echo 'PASS: test 124' >>${LOGFILE} - else - echo 'FAIL: test 124' | tee -a ${LOGFILE} - fi - - cd first-dir - touch a - - if ${CVS} add a 2>>${LOGFILE} ; then - echo 'PASS: test 125' >>${LOGFILE} - else - echo 'FAIL: test 125' | tee -a ${LOGFILE} - fi - - if ${CVS} ci -m added >>${LOGFILE} 2>&1; then - echo 'PASS: test 126' >>${LOGFILE} - else - echo 'FAIL: test 126' | tee -a ${LOGFILE} - fi - - cd ../.. - mkdir 2 - cd 2 - - if ${CVS} co first-dir ; then - echo 'PASS: test 127' >>${LOGFILE} - else - echo 'FAIL: test 127' | tee -a ${LOGFILE} - fi - cd first-dir - if test -f a; then - echo 'PASS: test 127a' >>${LOGFILE} - else - echo 'FAIL: test 127a' | tee -a ${LOGFILE} - fi - - cd ../../1/first-dir - echo add a line >>a - if ${CVS} ci -m changed >>${LOGFILE} 2>&1; then - echo 'PASS: test 128' >>${LOGFILE} - else - echo 'FAIL: test 128' | tee -a ${LOGFILE} - fi - - cd ../../2/first-dir - echo add a conflicting line >>a - if ${CVS} ci -m changed >>${LOGFILE} 2>&1; then - echo 'FAIL: test 129' | tee -a ${LOGFILE} - else - # Should be printing `out of date check failed'. - echo 'PASS: test 129' >>${LOGFILE} - fi - - if ${CVS} update 2>>${LOGFILE}; then - # We should get a conflict, but that doesn't affect - # exit status - echo 'PASS: test 130' >>${LOGFILE} - else - echo 'FAIL: test 130' | tee -a ${LOGFILE} - fi - - # Try to check in the file with the conflict markers in it. - if ${CVS} ci -m try 2>>${LOGFILE}; then - echo 'FAIL: test 131' | tee -a ${LOGFILE} - else - # Should tell us to resolve conflict first - echo 'PASS: test 131' >>${LOGFILE} - fi - - echo lame attempt at resolving it >>a - # Try to check in the file with the conflict markers in it. - if ${CVS} ci -m try >>${LOGFILE} 2>&1; then - echo 'FAIL: test 132' | tee -a ${LOGFILE} - else - # Should tell us to resolve conflict first - echo 'PASS: test 132' >>${LOGFILE} - fi - - echo resolve conflict >a - if ${CVS} ci -m resolved >>${LOGFILE} 2>&1; then - echo 'PASS: test 133' >>${LOGFILE} - else - echo 'FAIL: test 133' | tee -a ${LOGFILE} - fi - - # Now test that we can add a file in one working directory - # and have an update in another get it. - cd ../../1/first-dir - echo abc >abc - if ${testcvs} add abc >>${LOGFILE} 2>&1; then - echo 'PASS: test 134' >>${LOGFILE} - else - echo 'FAIL: test 134' | tee -a ${LOGFILE} - fi - if ${testcvs} ci -m 'add abc' abc >>${LOGFILE} 2>&1; then - echo 'PASS: test 135' >>${LOGFILE} - else - echo 'FAIL: test 135' | tee -a ${LOGFILE} - fi - cd ../../2 - if ${testcvs} -q update >>${LOGFILE}; then - echo 'PASS: test 136' >>${LOGFILE} - else - echo 'FAIL: test 136' | tee -a ${LOGFILE} - fi - if test -f first-dir/abc; then - echo 'PASS: test 137' >>${LOGFILE} - else - echo 'FAIL: test 137' | tee -a ${LOGFILE} - fi - - # Now test something similar, but in which the parent directory - # (not the directory in question) has the Entries.Static flag - # set. - cd ../1/first-dir - mkdir subdir - if ${testcvs} add subdir >>${LOGFILE}; then - echo 'PASS: test 138' >>${LOGFILE} - else - echo 'FAIL: test 138' | tee -a ${LOGFILE} - fi - cd ../.. - mkdir 3 - cd 3 - if ${testcvs} -q co first-dir/abc first-dir/subdir \ - >>${LOGFILE}; then - echo 'PASS: test 139' >>${LOGFILE} - else - echo 'FAIL: test 139' | tee -a ${LOGFILE} - fi - cd ../1/first-dir/subdir - echo sss >sss - if ${testcvs} add sss >>${LOGFILE} 2>&1; then - echo 'PASS: test 140' >>${LOGFILE} - else - echo 'FAIL: test 140' | tee -a ${LOGFILE} - fi - if ${testcvs} ci -m adding sss >>${LOGFILE} 2>&1; then - echo 'PASS: test 140' >>${LOGFILE} - else - echo 'FAIL: test 140' | tee -a ${LOGFILE} - fi - cd ../../../3/first-dir - if ${testcvs} -q update >>${LOGFILE}; then - echo 'PASS: test 141' >>${LOGFILE} - else - echo 'FAIL: test 141' | tee -a ${LOGFILE} - fi - if test -f subdir/sss; then - echo 'PASS: test 142' >>${LOGFILE} - else - echo 'FAIL: test 142' | tee -a ${LOGFILE} - fi - - cd ../.. - 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_DIRNAME}/CVSROOT; ci -q -u -t/dev/null \ - -m'initial checkin of modules' modules) - - rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir - mkdir ${CVSROOT_DIRNAME}/first-dir - - mkdir 1 - cd 1 - - if ${testcvs} -q co first-dir; then - echo 'PASS: test 143' >>${LOGFILE} - else - echo 'FAIL: test 143' | tee -a ${LOGFILE} - exit 1 - fi - - cd first-dir - mkdir subdir - ${testcvs} add subdir >>${LOGFILE} - cd subdir - - touch a - - if ${testcvs} add a 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 .. - if ${testcvs} -q co CVSROOT >>${LOGFILE}; then - 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 - # is at top level) in the same directory as subdir (whose repository - # is a subdirectory of first-dir). TODO: Might want to check that - # files can actually get updated in this state. - if ${testcvs} -q update; then - 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 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 .. - if ${testcvs} co realmodule >>${LOGFILE}; then - echo 'PASS: test 149' >>${LOGFILE} - else - echo 'FAIL: test 149' | tee -a ${LOGFILE} - exit 1 - fi - if test -d realmodule && test -f realmodule/a; then - echo 'PASS: test 150' >>${LOGFILE} - else - echo 'FAIL: test 150' | tee -a ${LOGFILE} - exit 1 - fi - 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 - echo abc >>first-dir/subdir/a - if (${testcvs} -q co aliasmodule | tee test153.tmp) \ - >>${LOGFILE}; then - 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} - exit 1 - 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_DIRNAME}/first-dir - ;; - mflag) - for message in '' ' ' ' - ' ' test' ; do - # Set up - mkdir a-dir; cd a-dir - # Test handling of -m during import - echo testa >>test - if ${testcvs} import -m "$message" a-dir A A1 >>${LOGFILE} 2>&1;then - 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. - echo testb >>test - if ${testcvs} import -m "$message" a-dir A A2 >>${LOGFILE} 2>&1;then - 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; - if ${testcvs} co a-dir >>${LOGFILE} 2>&1; then - echo 'PASS: test 158' >>${LOGFILE} - else - echo 'FAIL: test 158' | tee -a ${LOGFILE} - exit 1 - fi - cd a-dir - echo testc >>test - if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then - 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; - if ${testcvs} rm test >>${LOGFILE} 2>&1; then - 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_DIRNAME}/a-dir - done - ;; - errmsg1) - 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 - if ${testcvs} add foo 2>>${LOGFILE}; then - 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 - cd 2 - if ${testcvs} -q co 1dir >>${LOGFILE}; then - echo 'PASS: test 165' >>${LOGFILE} - else - echo 'FAIL: test 165' | tee -a ${LOGFILE} - exit 1 - fi - chmod a-w 1dir - cd ../1/1dir - rm foo; - if ${testcvs} rm foo >>${LOGFILE} 2>&1; then - 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 <<EOF >../tst167.ans -$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 "$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_DIRNAME}/1dir - ;; - - *) - echo $what is not the name of a test -- ignored - ;; - esac -done - -echo "OK, all tests completed." - -# TODO: -# * Test `cvs admin'. -# * Test `cvs update -d foo' (where foo does not exist). -# * 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. -# Test that ciprog gets run both on checkin in that directory, or a -# higher-level checkin which recurses into it. -# * Test that $ followed by "Header" followed by $ gets expanded on checkin. -# * Test operations on a directory that contains other directories but has -# no files of its own. -# * -t global option -# * cvs rm followed by cvs add or vice versa (with no checkin in between). -# * cvs rm twice (should be a nice error message). -# * -P option to checkout--(a) refrains from checking out new empty dirs, -# (b) prunes empty dirs already there. -# * Test that cvs -d `hostname`:/tmp/cvs-sanity/non/existent co foo -# gives an appropriate error (e.g. -# Cannot access /tmp/cvs-sanity/non-existent/CVSROOT -# No such file or directory). -# End of TODO list. - -# Remove the test directory, but first change out of it. -cd /tmp -rm -rf ${TESTDIR} - -# end of sanity.sh diff --git a/gnu/usr.bin/cvs/cvs/server.c b/gnu/usr.bin/cvs/cvs/server.c deleted file mode 100644 index fbfca86..0000000 --- a/gnu/usr.bin/cvs/cvs/server.c +++ /dev/null @@ -1,3992 +0,0 @@ -#include "cvs.h" - -#ifdef SERVER_SUPPORT - -/* for select */ -#include <sys/types.h> -#ifdef HAVE_SYS_BSDTYPES_H -#include <sys/bsdtypes.h> -#endif -#include <sys/time.h> - -#if HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif - -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif - -#ifndef O_NONBLOCK -#define O_NONBLOCK O_NDELAY -#endif - - -/* Functions which the server calls. */ -int add PROTO((int argc, char **argv)); -int admin PROTO((int argc, char **argv)); -int checkout PROTO((int argc, char **argv)); -int commit PROTO((int argc, char **argv)); -int diff PROTO((int argc, char **argv)); -int history PROTO((int argc, char **argv)); -int import PROTO((int argc, char **argv)); -int cvslog PROTO((int argc, char **argv)); -int patch PROTO((int argc, char **argv)); -int release PROTO((int argc, char **argv)); -int cvsremove PROTO((int argc, char **argv)); -int rtag PROTO((int argc, char **argv)); -int status PROTO((int argc, char **argv)); -int tag PROTO((int argc, char **argv)); -int update PROTO((int argc, char **argv)); - - -/* - * This is where we stash stuff we are going to use. Format string - * which expects a single directory within it, starting with a slash. - */ -static char *server_temp_dir; - -/* Nonzero if we should keep the temp directory around after we exit. */ -static int dont_delete_temp; - -static char no_mem_error; -#define NO_MEM_ERROR (&no_mem_error) - -static void server_write_entries PROTO((void)); - -/* - * Read a line from the stream "instream" without command line editing. - * - * Action is compatible with "readline", e.g. space for the result is - * malloc'd and should be freed by the caller. - * - * A NULL return means end of file. A return of NO_MEM_ERROR means - * that we are out of memory. - */ -static char *read_line PROTO((FILE *)); - -static char * -read_line (stream) - FILE *stream; -{ - int c; - char *result; - int input_index = 0; - int result_size = 80; - - fflush (stdout); - result = (char *) malloc (result_size); - if (result == NULL) - return NO_MEM_ERROR; - - while (1) - { - c = fgetc (stream); - - if (c == EOF) - { - free (result); - return NULL; - } - - if (c == '\n') - break; - - result[input_index++] = c; - while (input_index >= result_size) - { - result_size *= 2; - result = (char *) realloc (result, result_size); - if (result == NULL) - return NO_MEM_ERROR; - } - } - - result[input_index++] = '\0'; - return result; -} - -/* - * Make directory DIR, including all intermediate directories if necessary. - * Returns 0 for success or errno code. - */ -static int mkdir_p PROTO((char *)); - -static int -mkdir_p (dir) - char *dir; -{ - char *p; - char *q = malloc (strlen (dir) + 1); - int retval; - - if (q == NULL) - return ENOMEM; - - /* - * Skip over leading slash if present. We won't bother to try to - * make '/'. - */ - p = dir + 1; - while (1) - { - while (*p != '/' && *p != '\0') - ++p; - if (*p == '/') - { - strncpy (q, dir, p - dir); - q[p - dir] = '\0'; - if (CVS_MKDIR (q, 0777) < 0) - { - if (errno != EEXIST - && (errno != EACCES || !isdir(q))) - { - retval = errno; - goto done; - } - } - ++p; - } - else - { - if (CVS_MKDIR (dir, 0777) < 0) - retval = errno; - else - retval = 0; - goto done; - } - } - done: - free (q); - return retval; -} - -/* - * Print the error response for error code STATUS. The caller is - * reponsible for making sure we get back to the command loop without - * any further output occuring. - */ -static void -print_error (status) - int status; -{ - char *msg; - printf ("error "); - msg = strerror (status); - if (msg) - printf ("%s", msg); - printf ("\n"); -} - -static int pending_error; -/* - * Malloc'd text for pending error. Each line must start with "E ". The - * last line should not end with a newline. - */ -static char *pending_error_text; - -/* If an error is pending, print it and return 1. If not, return 0. */ -static int -print_pending_error () -{ - if (pending_error_text) - { - printf ("%s\n", pending_error_text); - if (pending_error) - print_error (pending_error); - else - printf ("error \n"); - pending_error = 0; - free (pending_error_text); - pending_error_text = NULL; - return 1; - } - else if (pending_error) - { - print_error (pending_error); - pending_error = 0; - return 1; - } - else - return 0; -} - -/* Is an error pending? */ -#define error_pending() (pending_error || pending_error_text) - -int -supported_response (name) - char *name; -{ - struct response *rs; - - for (rs = responses; rs->name != NULL; ++rs) - if (strcmp (rs->name, name) == 0) - return rs->status == rs_supported; - error (1, 0, "internal error: testing support for unknown response?"); -} - -static void -serve_valid_responses (arg) - char *arg; -{ - char *p = arg; - char *q; - struct response *rs; - do - { - q = strchr (p, ' '); - if (q != NULL) - *q++ = '\0'; - for (rs = responses; rs->name != NULL; ++rs) - { - if (strcmp (rs->name, p) == 0) - break; - } - if (rs->name == NULL) - /* - * It is a response we have never heard of (and thus never - * will want to use). So don't worry about it. - */ - ; - else - rs->status = rs_supported; - p = q; - } while (q != NULL); - for (rs = responses; rs->name != NULL; ++rs) - { - if (rs->status == rs_essential) - { - printf ("E response `%s' not supported by client\nerror \n", - rs->name); - exit (1); - } - else if (rs->status == rs_optional) - rs->status = rs_not_supported; - } -} - -static int use_dir_and_repos = 0; - -static void -serve_root (arg) - char *arg; -{ - char *env; - extern char *CVSroot; - char path[PATH_MAX]; - int save_errno; - - if (error_pending()) return; - - (void) sprintf (path, "%s/%s", arg, CVSROOTADM); - if (!isaccessible (path, R_OK | X_OK)) - { - save_errno = errno; - pending_error_text = malloc (80 + strlen (path)); - if (pending_error_text != NULL) - sprintf (pending_error_text, "E Cannot access %s", path); - pending_error = save_errno; - } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (isfile (path) && !isaccessible (path, R_OK | W_OK)) - { - save_errno = errno; - pending_error_text = malloc (80 + strlen (path)); - if (pending_error_text != NULL) - sprintf (pending_error_text, "E \ -Sorry, you don't have read/write access to the history file %s", path); - pending_error = save_errno; - } - - CVSroot = malloc (strlen (arg) + 1); - if (CVSroot == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (CVSroot, arg); -#ifdef HAVE_PUTENV - env = malloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1); - if (env == NULL) - { - pending_error = ENOMEM; - return; - } - (void) sprintf (env, "%s=%s", CVSROOT_ENV, arg); - (void) putenv (env); - /* do not free env, as putenv has control of it */ -#endif -} - -/* - * Add as many directories to the temp directory as the client tells us it - * will use "..", so we never try to access something outside the temp - * directory via "..". - */ -static void -serve_max_dotdot (arg) - char *arg; -{ - int lim = atoi (arg); - int i; - char *p; - - if (lim < 0) - return; - p = malloc (strlen (server_temp_dir) + 2 * lim + 10); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (p, server_temp_dir); - for (i = 0; i < lim; ++i) - strcat (p, "/d"); - free (server_temp_dir); - server_temp_dir = p; -} - -static void -dirswitch (dir, repos) - char *dir; - char *repos; -{ - char *dirname; - int status; - FILE *f; - - server_write_entries (); - - if (error_pending()) return; - - dirname = malloc (strlen (server_temp_dir) + strlen (dir) + 40); - if (dirname == NULL) - { - pending_error = ENOMEM; - return; - } - - strcpy (dirname, server_temp_dir); - strcat (dirname, "/"); - strcat (dirname, dir); - - status = mkdir_p (dirname); - if (status != 0 - && status != EEXIST) - { - pending_error = status; - pending_error_text = malloc (80 + strlen(dirname)); - sprintf(pending_error_text, "E cannot mkdir %s", dirname); - return; - } - if (chdir (dirname) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(dirname)); - sprintf(pending_error_text, "E cannot change to %s", dirname); - return; - } - /* - * This is pretty much like calling Create_Admin, but Create_Admin doesn't - * report errors in the right way for us. - */ - if (CVS_MKDIR (CVSADM, 0777) < 0) - { - if (errno == EEXIST) - /* Don't create the files again. */ - return; - pending_error = errno; - return; - } - f = fopen (CVSADM_REP, "w"); - if (f == NULL) - { - pending_error = errno; - return; - } - if (fprintf (f, "%s\n", repos) < 0) - { - pending_error = errno; - fclose (f); - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - return; - } - f = fopen (CVSADM_ENT, "w+"); - if (f == NULL) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENT)); - sprintf(pending_error_text, "E cannot open %s", CVSADM_ENT); - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENT)); - sprintf(pending_error_text, "E cannot close %s", CVSADM_ENT); - return; - } - free (dirname); -} - -static void -serve_repository (arg) - char *arg; -{ - dirswitch (arg + 1, arg); -} - -static void -serve_directory (arg) - char *arg; -{ - char *repos; - use_dir_and_repos = 1; - repos = read_line (stdin); - if (repos == NULL) - { - pending_error_text = malloc (80 + strlen (arg)); - if (pending_error_text) - { - if (feof (stdin)) - sprintf (pending_error_text, - "E end of file reading mode for %s", arg); - else - { - sprintf (pending_error_text, - "E error reading mode for %s", arg); - pending_error = errno; - } - } - else - pending_error = ENOMEM; - } - else if (repos == NO_MEM_ERROR) - { - pending_error = ENOMEM; - } - else - { - dirswitch (arg, repos); - free (repos); - } -} - -static void -serve_static_directory (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_ENTSTAT, "w+"); - if (f == NULL) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENTSTAT)); - sprintf(pending_error_text, "E cannot open %s", CVSADM_ENTSTAT); - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENTSTAT)); - sprintf(pending_error_text, "E cannot close %s", CVSADM_ENTSTAT); - return; - } -} - -static void -serve_sticky (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_TAG, "w+"); - if (f == NULL) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_TAG)); - sprintf(pending_error_text, "E cannot open %s", CVSADM_TAG); - return; - } - if (fprintf (f, "%s\n", arg) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_TAG)); - sprintf(pending_error_text, "E cannot write to %s", CVSADM_TAG); - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_TAG)); - sprintf(pending_error_text, "E cannot close %s", CVSADM_TAG); - return; - } -} - -/* - * Read SIZE bytes from stdin, write them to FILE. - * - * Currently this isn't really used for receiving parts of a file -- - * the file is still sent over in one chunk. But if/when we get - * spiffy in-process gzip support working, perhaps the compressed - * pieces could be sent over as they're ready, if the network is fast - * enough. Or something. - */ -static void -receive_partial_file (size, file) - int size; - int file; -{ - char buf[16*1024], *bufp; - int toread, nread, nwrote; - while (size > 0) - { - toread = sizeof (buf); - if (toread > size) - toread = size; - - nread = fread (buf, 1, toread, stdin); - if (nread <= 0) - { - if (feof (stdin)) - { - pending_error_text = malloc (80); - if (pending_error_text) - { - sprintf (pending_error_text, - "E premature end of file from client"); - pending_error = 0; - } - else - pending_error = ENOMEM; - } - else if (ferror (stdin)) - { - pending_error_text = malloc (40); - if (pending_error_text) - sprintf (pending_error_text, - "E error reading from client"); - pending_error = errno; - } - else - { - pending_error_text = malloc (40); - if (pending_error_text) - sprintf (pending_error_text, - "E short read from client"); - pending_error = 0; - } - return; - } - size -= nread; - bufp = buf; - while (nread) - { - nwrote = write (file, bufp, nread); - if (nwrote < 0) - { - pending_error_text = malloc (40); - if (pending_error_text) - sprintf (pending_error_text, "E unable to write"); - pending_error = errno; - return; - } - nread -= nwrote; - bufp += nwrote; - } - } -} - -/* Receive SIZE bytes, write to filename FILE. */ -static void -receive_file (size, file, gzipped) - int size; - char *file; - int gzipped; -{ - int fd; - char *arg = file; - pid_t gzip_pid = 0; - int gzip_status; - - /* Write the file. */ - fd = open (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) - { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) - sprintf (pending_error_text, "E cannot open %s", arg); - pending_error = errno; - return; - } - - /* - * FIXME: This doesn't do anything reasonable with gunzip's stderr, which - * means that if gunzip writes to stderr, it will cause all manner of - * protocol violations. - */ - if (gzipped) - fd = filter_through_gunzip (fd, 0, &gzip_pid); - - receive_partial_file (size, fd); - - if (pending_error_text) - { - char *p = realloc (pending_error_text, - strlen (pending_error_text) + strlen (arg) + 30); - if (p) - { - pending_error_text = p; - sprintf (p + strlen (p), ", file %s", arg); - } - /* else original string is supposed to be unchanged */ - } - - if (close (fd) < 0 && !error_pending ()) - { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) - sprintf (pending_error_text, "E cannot close %s", arg); - pending_error = errno; - if (gzip_pid) - waitpid (gzip_pid, (int *) 0, 0); - return; - } - - if (gzip_pid) - { - if (waitpid (gzip_pid, &gzip_status, 0) != gzip_pid) - error (1, errno, "waiting for gunzip process %d", gzip_pid); - else if (gzip_status != 0) - error (1, 0, "gunzip exited %d", gzip_status); - } -} - -static void -serve_modified (arg) - char *arg; -{ - int size; - char *size_text; - char *mode_text; - - int gzipped = 0; - - if (error_pending ()) return; - - mode_text = read_line (stdin); - if (mode_text == NULL) - { - pending_error_text = malloc (80 + strlen (arg)); - if (pending_error_text) - { - if (feof (stdin)) - sprintf (pending_error_text, - "E end of file reading mode for %s", arg); - else - { - sprintf (pending_error_text, - "E error reading mode for %s", arg); - pending_error = errno; - } - } - else - pending_error = ENOMEM; - return; - } - else if (mode_text == NO_MEM_ERROR) - { - pending_error = ENOMEM; - return; - } - size_text = read_line (stdin); - if (size_text == NULL) - { - pending_error_text = malloc (80 + strlen (arg)); - if (pending_error_text) - { - if (feof (stdin)) - sprintf (pending_error_text, - "E end of file reading size for %s", arg); - else - { - sprintf (pending_error_text, - "E error reading size for %s", arg); - pending_error = errno; - } - } - else - pending_error = ENOMEM; - return; - } - else if (size_text == NO_MEM_ERROR) - { - pending_error = ENOMEM; - return; - } - if (size_text[0] == 'z') - { - gzipped = 1; - size = atoi (size_text + 1); - } - else - size = atoi (size_text); - free (size_text); - - if (size >= 0) - { - receive_file (size, arg, gzipped); - if (error_pending ()) return; - } - - { - int status = change_mode (arg, mode_text); - free (mode_text); - if (status) - { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) - sprintf (pending_error_text, - "E cannot change mode for %s", arg); - pending_error = status; - return; - } - } -} - -#endif /* SERVER_SUPPORT */ - -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) - -int use_unchanged = 0; - -#endif -#ifdef SERVER_SUPPORT - -static void -serve_enable_unchanged (arg) - char *arg; -{ - use_unchanged = 1; -} - -static void -serve_lost (arg) - char *arg; -{ - if (use_unchanged) - { - /* A missing file already indicates it is nonexistent. */ - return; - } - else - { - struct utimbuf ut; - int fd = open (arg, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (fd < 0 || close (fd) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(arg)); - sprintf(pending_error_text, "E cannot open %s", arg); - return; - } - /* - * Set the times to the beginning of the epoch to tell time_stamp() - * that the file was lost. - */ - ut.actime = 0; - ut.modtime = 0; - if (utime (arg, &ut) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(arg)); - sprintf(pending_error_text, "E cannot utime %s", arg); - return; - } - } -} - -struct an_entry { - struct an_entry *next; - char *entry; -}; - -static struct an_entry *entries; - -static void -serve_unchanged (arg) - char *arg; -{ - if (error_pending ()) - return; - if (!use_unchanged) - { - /* A missing file already indicates it is unchanged. */ - return; - } - else - { - struct an_entry *p; - char *name; - char *cp; - char *timefield; - - /* Rewrite entries file to have `=' in timestamp field. */ - for (p = entries; p != NULL; p = p->next) - { - name = p->entry + 1; - cp = strchr (name, '/'); - if (cp != NULL - && strlen (arg) == cp - name - && strncmp (arg, name, cp - name) == 0) - { - timefield = strchr (cp + 1, '/') + 1; - if (*timefield != '=') - { - cp = timefield + strlen (timefield); - cp[1] = '\0'; - while (cp > timefield) - { - *cp = cp[-1]; - --cp; - } - *timefield = '='; - } - break; - } - } - } -} - -static void -serve_entry (arg) - char *arg; -{ - struct an_entry *p; - char *cp; - if (error_pending()) return; - p = (struct an_entry *) malloc (sizeof (struct an_entry)); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - /* Leave space for serve_unchanged to write '=' if it wants. */ - cp = malloc (strlen (arg) + 2); - if (cp == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (cp, arg); - p->next = entries; - p->entry = cp; - entries = p; -} - -static void -server_write_entries () -{ - FILE *f; - struct an_entry *p; - struct an_entry *q; - - if (entries == NULL) - return; - - f = NULL; - /* Note that we free all the entries regardless of errors. */ - if (!error_pending ()) - { - f = fopen (CVSADM_ENT, "w"); - if (f == NULL) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENT)); - sprintf(pending_error_text, "E cannot open %s", CVSADM_ENT); - } - } - for (p = entries; p != NULL;) - { - if (!error_pending ()) - { - if (fprintf (f, "%s\n", p->entry) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENT)); - sprintf(pending_error_text, "E cannot write to %s", CVSADM_ENT); - } - } - free (p->entry); - q = p->next; - free (p); - p = q; - } - entries = NULL; - if (f != NULL && fclose (f) == EOF && !error_pending ()) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_ENT)); - sprintf(pending_error_text, "E cannot close %s", CVSADM_ENT); - } -} - -static int argument_count; -static char **argument_vector; -static int argument_vector_size; - -static void -serve_argument (arg) - char *arg; -{ - char *p; - - if (error_pending()) return; - - if (argument_vector_size <= argument_count) - { - argument_vector_size *= 2; - argument_vector = - (char **) realloc ((char *)argument_vector, - argument_vector_size * sizeof (char *)); - if (argument_vector == NULL) - { - pending_error = ENOMEM; - return; - } - } - p = malloc (strlen (arg) + 1); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (p, arg); - argument_vector[argument_count++] = p; -} - -static void -serve_argumentx (arg) - char *arg; -{ - char *p; - - if (error_pending()) return; - - p = argument_vector[argument_count - 1]; - p = realloc (p, strlen (p) + 1 + strlen (arg) + 1); - if (p == NULL) - { - pending_error = ENOMEM; - return; - } - strcat (p, "\n"); - strcat (p, arg); - argument_vector[argument_count - 1] = p; -} - -static void -serve_global_option (arg) - char *arg; -{ - if (arg[0] != '-' || arg[1] == '\0' || arg[2] != '\0') - { - error_return: - pending_error_text = malloc (strlen (arg) + 80); - sprintf (pending_error_text, "E Protocol error: bad global option %s", - arg); - return; - } - switch (arg[1]) - { - case 'n': - noexec = 1; - break; - case 'q': - quiet = 1; - break; - case 'r': - cvswrite = 0; - break; - case 'Q': - really_quiet = 1; - break; - case 'l': - logoff = 1; - break; - case 't': - trace = 1; - break; - default: - goto error_return; - } -} - -/* - * We must read data from a child process and send it across the - * network. We do not want to block on writing to the network, so we - * store the data from the child process in memory. A BUFFER - * structure holds the status of one communication, and uses a linked - * list of buffer_data structures to hold data. - */ - -struct buffer -{ - /* Data. */ - struct buffer_data *data; - - /* Last buffer on data chain. */ - struct buffer_data *last; - - /* File descriptor to write to or read from. */ - int fd; - - /* Nonzero if this is an output buffer (sanity check). */ - int output; - - /* Nonzero if the file descriptor is in nonblocking mode. */ - int nonblocking; - - /* Function to call if we can't allocate memory. */ - void (*memory_error) PROTO((struct buffer *)); -}; - -/* Data is stored in lists of these structures. */ - -struct buffer_data -{ - /* Next buffer in linked list. */ - struct buffer_data *next; - - /* - * A pointer into the data area pointed to by the text field. This - * is where to find data that has not yet been written out. - */ - char *bufp; - - /* The number of data bytes found at BUFP. */ - int size; - - /* - * Actual buffer. This never changes after the structure is - * allocated. The buffer is BUFFER_DATA_SIZE bytes. - */ - char *text; -}; - -/* The size we allocate for each buffer_data structure. */ -#define BUFFER_DATA_SIZE (4096) - -#ifdef SERVER_FLOWCONTROL -/* The maximum we'll queue to the remote client before blocking. */ -# ifndef SERVER_HI_WATER -# define SERVER_HI_WATER (2 * 1024 * 1024) -# endif /* SERVER_HI_WATER */ -/* When the buffer drops to this, we restart the child */ -# ifndef SERVER_LO_WATER -# define SERVER_LO_WATER (1 * 1024 * 1024) -# endif /* SERVER_LO_WATER */ -#endif /* SERVER_FLOWCONTROL */ - -/* Linked list of available buffer_data structures. */ -static struct buffer_data *free_buffer_data; - -static void allocate_buffer_datas PROTO((void)); -static inline struct buffer_data *get_buffer_data PROTO((void)); -static int buf_empty_p PROTO((struct buffer *)); -static void buf_output PROTO((struct buffer *, const char *, int)); -static void buf_output0 PROTO((struct buffer *, const char *)); -static inline void buf_append_char PROTO((struct buffer *, int)); -static int buf_send_output PROTO((struct buffer *)); -static int set_nonblock PROTO((struct buffer *)); -static int set_block PROTO((struct buffer *)); -static int buf_send_counted PROTO((struct buffer *)); -static inline void buf_append_data PROTO((struct buffer *, - struct buffer_data *, - struct buffer_data *)); -static int buf_read_file PROTO((FILE *, long, struct buffer_data **, - struct buffer_data **)); -static int buf_input_data PROTO((struct buffer *, int *)); -static void buf_copy_lines PROTO((struct buffer *, struct buffer *, int)); -static int buf_copy_counted PROTO((struct buffer *, struct buffer *)); - -#ifdef SERVER_FLOWCONTROL -static int buf_count_mem PROTO((struct buffer *)); -static int set_nonblock_fd PROTO((int)); -#endif /* SERVER_FLOWCONTROL */ - -/* Allocate more buffer_data structures. */ - -static void -allocate_buffer_datas () -{ - struct buffer_data *alc; - char *space; - int i; - - /* Allocate buffer_data structures in blocks of 16. */ -#define ALLOC_COUNT (16) - - alc = ((struct buffer_data *) - malloc (ALLOC_COUNT * sizeof (struct buffer_data))); - space = (char *) valloc (ALLOC_COUNT * BUFFER_DATA_SIZE); - if (alc == NULL || space == NULL) - return; - for (i = 0; i < ALLOC_COUNT; i++, alc++, space += BUFFER_DATA_SIZE) - { - alc->next = free_buffer_data; - free_buffer_data = alc; - alc->text = space; - } -} - -/* Get a new buffer_data structure. */ - -static inline struct buffer_data * -get_buffer_data () -{ - struct buffer_data *ret; - - if (free_buffer_data == NULL) - { - allocate_buffer_datas (); - if (free_buffer_data == NULL) - return NULL; - } - - ret = free_buffer_data; - free_buffer_data = ret->next; - return ret; -} - -/* See whether a buffer is empty. */ - -static int -buf_empty_p (buf) - struct buffer *buf; -{ - struct buffer_data *data; - - for (data = buf->data; data != NULL; data = data->next) - if (data->size > 0) - return 0; - return 1; -} - -#ifdef SERVER_FLOWCONTROL -/* - * Count how much data is stored in the buffer.. - * Note that each buffer is a malloc'ed chunk BUFFER_DATA_SIZE. - */ - -static int -buf_count_mem (buf) - struct buffer *buf; -{ - struct buffer_data *data; - int mem = 0; - - for (data = buf->data; data != NULL; data = data->next) - mem += BUFFER_DATA_SIZE; - - return mem; -} -#endif /* SERVER_FLOWCONTROL */ - -/* Add data DATA of length LEN to BUF. */ - -static void -buf_output (buf, data, len) - struct buffer *buf; - const char *data; - int len; -{ - if (! buf->output) - abort (); - - if (buf->data != NULL - && (((buf->last->text + BUFFER_DATA_SIZE) - - (buf->last->bufp + buf->last->size)) - >= len)) - { - memcpy (buf->last->bufp + buf->last->size, data, len); - buf->last->size += len; - return; - } - - while (1) - { - struct buffer_data *newdata; - - newdata = get_buffer_data (); - if (newdata == NULL) - { - (*buf->memory_error) (buf); - return; - } - - if (buf->data == NULL) - buf->data = newdata; - else - buf->last->next = newdata; - newdata->next = NULL; - buf->last = newdata; - - newdata->bufp = newdata->text; - - if (len <= BUFFER_DATA_SIZE) - { - newdata->size = len; - memcpy (newdata->text, data, len); - return; - } - - newdata->size = BUFFER_DATA_SIZE; - memcpy (newdata->text, data, BUFFER_DATA_SIZE); - - data += BUFFER_DATA_SIZE; - len -= BUFFER_DATA_SIZE; - } - - /*NOTREACHED*/ -} - -/* Add a '\0' terminated string to BUF. */ - -static void -buf_output0 (buf, string) - struct buffer *buf; - const char *string; -{ - buf_output (buf, string, strlen (string)); -} - -/* Add a single character to BUF. */ - -static inline void -buf_append_char (buf, ch) - struct buffer *buf; - int ch; -{ - if (buf->data != NULL - && (buf->last->text + BUFFER_DATA_SIZE - != buf->last->bufp + buf->last->size)) - { - *(buf->last->bufp + buf->last->size) = ch; - ++buf->last->size; - } - else - { - char b; - - b = ch; - buf_output (buf, &b, 1); - } -} - -/* - * Send all the output we've been saving up. Returns 0 for success or - * errno code. If the buffer has been set to be nonblocking, this - * will just write until the write would block. - */ - -static int -buf_send_output (buf) - struct buffer *buf; -{ - if (! buf->output) - abort (); - - while (buf->data != NULL) - { - struct buffer_data *data; - - data = buf->data; - while (data->size > 0) - { - int nbytes; - - nbytes = write (buf->fd, data->bufp, data->size); - if (nbytes <= 0) - { - int status; - - if (buf->nonblocking - && (nbytes == 0 -#ifdef EWOULDBLOCK - || errno == EWOULDBLOCK -#endif - || errno == EAGAIN)) - { - /* - * A nonblocking write failed to write any data. - * Just return. - */ - return 0; - } - - /* - * An error, or EOF. Throw away all the data and - * return. - */ - if (nbytes == 0) - status = EIO; - else - status = errno; - - buf->last->next = free_buffer_data; - free_buffer_data = buf->data; - buf->data = NULL; - buf->last = NULL; - - return status; - } - - data->size -= nbytes; - data->bufp += nbytes; - } - - buf->data = data->next; - data->next = free_buffer_data; - free_buffer_data = data; - } - - buf->last = NULL; - - return 0; -} - -#ifdef SERVER_FLOWCONTROL -/* - * Set buffer BUF to non-blocking I/O. Returns 0 for success or errno - * code. - */ - -static int -set_nonblock_fd (fd) - int fd; -{ - int flags; - - flags = fcntl (fd, F_GETFL, 0); - if (flags < 0) - return errno; - if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0) - return errno; - return 0; -} -#endif /* SERVER_FLOWCONTROL */ - -static int -set_nonblock (buf) - struct buffer *buf; -{ - int flags; - - if (buf->nonblocking) - return 0; - flags = fcntl (buf->fd, F_GETFL, 0); - if (flags < 0) - return errno; - if (fcntl (buf->fd, F_SETFL, flags | O_NONBLOCK) < 0) - return errno; - buf->nonblocking = 1; - return 0; -} - -/* - * Set buffer BUF to blocking I/O. Returns 0 for success or errno - * code. - */ - -static int -set_block (buf) - struct buffer *buf; -{ - int flags; - - if (! buf->nonblocking) - return 0; - flags = fcntl (buf->fd, F_GETFL, 0); - if (flags < 0) - return errno; - if (fcntl (buf->fd, F_SETFL, flags & ~O_NONBLOCK) < 0) - return errno; - buf->nonblocking = 0; - return 0; -} - -/* - * Send a character count and some output. Returns errno code or 0 for - * success. - * - * Sending the count in binary is OK since this is only used on a pipe - * within the same system. - */ - -static int -buf_send_counted (buf) - struct buffer *buf; -{ - int size; - struct buffer_data *data; - - if (! buf->output) - abort (); - - size = 0; - for (data = buf->data; data != NULL; data = data->next) - size += data->size; - - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return ENOMEM; - } - - data->next = buf->data; - buf->data = data; - if (buf->last == NULL) - buf->last = data; - - data->bufp = data->text; - data->size = sizeof (int); - - *((int *) data->text) = size; - - return buf_send_output (buf); -} - -/* Append a list of buffer_data structures to an buffer. */ - -static inline void -buf_append_data (buf, data, last) - struct buffer *buf; - struct buffer_data *data; - struct buffer_data *last; -{ - if (data != NULL) - { - if (buf->data == NULL) - buf->data = data; - else - buf->last->next = data; - buf->last = last; - } -} - -/* - * Copy the contents of file F into buffer_data structures. We can't - * copy directly into an buffer, because we want to handle failure and - * succeess differently. Returns 0 on success, or -2 if out of - * memory, or a status code on error. Since the caller happens to - * know the size of the file, it is passed in as SIZE. On success, - * this function sets *RETP and *LASTP, which may be passed to - * buf_append_data. - */ - -static int -buf_read_file (f, size, retp, lastp) - FILE *f; - long size; - struct buffer_data **retp; - struct buffer_data **lastp; -{ - int status; - - *retp = NULL; - *lastp = NULL; - - while (size > 0) - { - struct buffer_data *data; - int get; - - data = get_buffer_data (); - if (data == NULL) - { - status = -2; - goto error_return; - } - - if (*retp == NULL) - *retp = data; - else - (*lastp)->next = data; - data->next = NULL; - *lastp = data; - - data->bufp = data->text; - data->size = 0; - - if (size > BUFFER_DATA_SIZE) - get = BUFFER_DATA_SIZE; - else - get = size; - - errno = EIO; - if (fread (data->text, get, 1, f) != 1) - { - status = errno; - goto error_return; - } - - data->size += get; - size -= get; - } - - return 0; - - error_return: - if (*retp != NULL) - { - (*lastp)->next = free_buffer_data; - free_buffer_data = *retp; - } - return status; -} - -static int -buf_read_file_to_eof (f, retp, lastp) - FILE *f; - struct buffer_data **retp; - struct buffer_data **lastp; -{ - int status; - - *retp = NULL; - *lastp = NULL; - - while (!feof (f)) - { - struct buffer_data *data; - int get, nread; - - data = get_buffer_data (); - if (data == NULL) - { - status = -2; - goto error_return; - } - - if (*retp == NULL) - *retp = data; - else - (*lastp)->next = data; - data->next = NULL; - *lastp = data; - - data->bufp = data->text; - data->size = 0; - - get = BUFFER_DATA_SIZE; - - errno = EIO; - nread = fread (data->text, 1, get, f); - if (nread == 0 && !feof (f)) - { - status = errno; - goto error_return; - } - - data->size = nread; - } - - return 0; - - error_return: - if (*retp != NULL) - { - (*lastp)->next = free_buffer_data; - free_buffer_data = *retp; - } - return status; -} - -static int -buf_chain_length (buf) - struct buffer_data *buf; -{ - int size = 0; - while (buf) - { - size += buf->size; - buf = buf->next; - } - return size; -} - -/* - * Read an arbitrary amount of data from a file descriptor into an - * input buffer. The file descriptor will be in nonblocking mode, and - * we just grab what we can. Return 0 on success, or -1 on end of - * file, or -2 if out of memory, or an error code. If COUNTP is not - * NULL, *COUNTP is set to the number of bytes read. - */ - -static int -buf_input_data (buf, countp) - struct buffer *buf; - int *countp; -{ - if (buf->output) - abort (); - - if (countp != NULL) - *countp = 0; - - while (1) - { - int get; - int nbytes; - - if (buf->data == NULL - || (buf->last->bufp + buf->last->size - == buf->last->text + BUFFER_DATA_SIZE)) - { - struct buffer_data *data; - - data = get_buffer_data (); - if (data == NULL) - { - (*buf->memory_error) (buf); - return -2; - } - - if (buf->data == NULL) - buf->data = data; - else - buf->last->next = data; - data->next = NULL; - buf->last = data; - - data->bufp = data->text; - data->size = 0; - } - - get = ((buf->last->text + BUFFER_DATA_SIZE) - - (buf->last->bufp + buf->last->size)); - nbytes = read (buf->fd, buf->last->bufp + buf->last->size, get); - if (nbytes <= 0) - { - if (nbytes == 0) - { - /* - * This assumes that we are using POSIX or BSD style - * nonblocking I/O. On System V we will get a zero - * return if there is no data, even when not at EOF. - */ - return -1; - } - - if (errno == EAGAIN -#ifdef EWOULDBLOCK - || errno == EWOULDBLOCK -#endif - ) - return 0; - - return errno; - } - - buf->last->size += nbytes; - if (countp != NULL) - *countp += nbytes; - } - - /*NOTREACHED*/ -} - -/* - * Copy lines from an input buffer to an output buffer. This copies - * all complete lines (characters up to a newline) from INBUF to - * OUTBUF. Each line in OUTBUF is preceded by the character COMMAND - * and a space. - */ - -static void -buf_copy_lines (outbuf, inbuf, command) - struct buffer *outbuf; - struct buffer *inbuf; - int command; -{ - if (! outbuf->output || inbuf->output) - abort (); - - while (1) - { - struct buffer_data *data; - struct buffer_data *nldata; - char *nl; - int len; - - /* See if there is a newline in INBUF. */ - nldata = NULL; - nl = NULL; - for (data = inbuf->data; data != NULL; data = data->next) - { - nl = memchr (data->bufp, '\n', data->size); - if (nl != NULL) - { - nldata = data; - break; - } - } - - if (nldata == NULL) - { - /* There are no more lines in INBUF. */ - return; - } - - /* Put in the command. */ - buf_append_char (outbuf, command); - buf_append_char (outbuf, ' '); - - if (inbuf->data != nldata) - { - /* - * Simply move over all the buffers up to the one containing - * the newline. - */ - for (data = inbuf->data; data->next != nldata; data = data->next) - ; - data->next = NULL; - buf_append_data (outbuf, inbuf->data, data); - inbuf->data = nldata; - } - - /* - * If the newline is at the very end of the buffer, just move - * the buffer onto OUTBUF. Otherwise we must copy the data. - */ - len = nl + 1 - nldata->bufp; - if (len == nldata->size) - { - inbuf->data = nldata->next; - if (inbuf->data == NULL) - inbuf->last = NULL; - - nldata->next = NULL; - buf_append_data (outbuf, nldata, nldata); - } - else - { - buf_output (outbuf, nldata->bufp, len); - nldata->bufp += len; - nldata->size -= len; - } - } -} - -/* - * Copy counted data from one buffer to another. The count is an - * integer, host size, host byte order (it is only used across a - * pipe). If there is enough data, it should be moved over. If there - * is not enough data, it should remain on the original buffer. This - * returns the number of bytes it needs to see in order to actually - * copy something over. - */ - -static int -buf_copy_counted (outbuf, inbuf) - struct buffer *outbuf; - struct buffer *inbuf; -{ - if (! outbuf->output || inbuf->output) - abort (); - - while (1) - { - struct buffer_data *data; - int need; - union - { - char intbuf[sizeof (int)]; - int i; - } u; - char *intp; - int count; - struct buffer_data *start; - int startoff; - struct buffer_data *stop; - int stopwant; - - /* See if we have enough bytes to figure out the count. */ - need = sizeof (int); - intp = u.intbuf; - for (data = inbuf->data; data != NULL; data = data->next) - { - if (data->size >= need) - { - memcpy (intp, data->bufp, need); - break; - } - memcpy (intp, data->bufp, data->size); - intp += data->size; - need -= data->size; - } - if (data == NULL) - { - /* We don't have enough bytes to form an integer. */ - return need; - } - - count = u.i; - start = data; - startoff = need; - - /* - * We have an integer in COUNT. We have gotten all the data - * from INBUF in all buffers before START, and we have gotten - * STARTOFF bytes from START. See if we have enough bytes - * remaining in INBUF. - */ - need = count - (start->size - startoff); - if (need <= 0) - { - stop = start; - stopwant = count; - } - else - { - for (data = start->next; data != NULL; data = data->next) - { - if (need <= data->size) - break; - need -= data->size; - } - if (data == NULL) - { - /* We don't have enough bytes. */ - return need; - } - stop = data; - stopwant = need; - } - - /* - * We have enough bytes. Free any buffers in INBUF before - * START, and remove STARTOFF bytes from START, so that we can - * forget about STARTOFF. - */ - start->bufp += startoff; - start->size -= startoff; - - if (start->size == 0) - start = start->next; - - if (stop->size == stopwant) - { - stop = stop->next; - stopwant = 0; - } - - while (inbuf->data != start) - { - data = inbuf->data; - inbuf->data = data->next; - data->next = free_buffer_data; - free_buffer_data = data; - } - - /* - * We want to copy over the bytes from START through STOP. We - * only want STOPWANT bytes from STOP. - */ - - if (start != stop) - { - /* Attach the buffers from START through STOP to OUTBUF. */ - for (data = start; data->next != stop; data = data->next) - ; - inbuf->data = stop; - data->next = NULL; - buf_append_data (outbuf, start, data); - } - - if (stopwant > 0) - { - buf_output (outbuf, stop->bufp, stopwant); - stop->bufp += stopwant; - stop->size -= stopwant; - } - } - - /*NOTREACHED*/ -} - -static struct buffer protocol; - -static void -protocol_memory_error (buf) - struct buffer *buf; -{ - error (1, ENOMEM, "Virtual memory exhausted"); -} - -/* - * Process IDs of the subprocess, or negative if that subprocess - * does not exist. - */ -static pid_t command_pid; - -static void -outbuf_memory_error (buf) - struct buffer *buf; -{ - static const char msg[] = "E Fatal server error\n\ -error ENOMEM Virtual memory exhausted.\n"; - if (command_pid > 0) - kill (command_pid, SIGTERM); - - /* - * We have arranged things so that printing this now either will - * be legal, or the "E fatal error" line will get glommed onto the - * end of an existing "E" or "M" response. - */ - - /* If this gives an error, not much we could do. syslog() it? */ - write (STDOUT_FILENO, msg, sizeof (msg) - 1); - server_cleanup (0); - exit (1); -} - -static void -input_memory_error (buf) - struct buffer *buf; -{ - outbuf_memory_error (buf); -} - -/* Execute COMMAND in a subprocess with the approriate funky things done. */ - -static struct fd_set_wrapper { fd_set fds; } command_fds_to_drain; -static int max_command_fd; - -#ifdef SERVER_FLOWCONTROL -static int flowcontrol_pipe[2]; -#endif /* SERVER_FLOWCONTROL */ - -static void -do_cvs_command (command) - int (*command) PROTO((int argc, char **argv)); -{ - /* - * The following file descriptors are set to -1 if that file is not - * currently open. - */ - - /* Data on these pipes is a series of '\n'-terminated lines. */ - int stdout_pipe[2]; - int stderr_pipe[2]; - - /* - * Data on this pipe is a series of counted (see buf_send_counted) - * packets. Each packet must be processed atomically (i.e. not - * interleaved with data from stdout_pipe or stderr_pipe). - */ - int protocol_pipe[2]; - - int dev_null_fd = -1; - - int errs; - - command_pid = -1; - stdout_pipe[0] = -1; - stdout_pipe[1] = -1; - stderr_pipe[0] = -1; - stderr_pipe[1] = -1; - protocol_pipe[0] = -1; - protocol_pipe[1] = -1; - - server_write_entries (); - - if (print_pending_error ()) - goto free_args_and_return; - - /* - * We use a child process which actually does the operation. This - * is so we can intercept its standard output. Even if all of CVS - * were written to go to some special routine instead of writing - * to stdout or stderr, we would still need to do the same thing - * for the RCS commands. - */ - - if (pipe (stdout_pipe) < 0) - { - print_error (errno); - goto error_exit; - } - if (pipe (stderr_pipe) < 0) - { - print_error (errno); - goto error_exit; - } - if (pipe (protocol_pipe) < 0) - { - print_error (errno); - goto error_exit; - } -#ifdef SERVER_FLOWCONTROL - if (pipe (flowcontrol_pipe) < 0) - { - print_error (errno); - goto error_exit; - } - set_nonblock_fd (flowcontrol_pipe[0]); - set_nonblock_fd (flowcontrol_pipe[1]); -#endif /* SERVER_FLOWCONTROL */ - - dev_null_fd = open ("/dev/null", O_RDONLY); - if (dev_null_fd < 0) - { - print_error (errno); - goto error_exit; - } - - /* Don't use vfork; we're not going to exec(). */ - command_pid = fork (); - if (command_pid < 0) - { - print_error (errno); - goto error_exit; - } - if (command_pid == 0) - { - int exitstatus; - - /* Since we're in the child, and the parent is going to take - care of packaging up our error messages, we can clear this - flag. */ - error_use_protocol = 0; - - protocol.data = protocol.last = NULL; - protocol.fd = protocol_pipe[1]; - protocol.output = 1; - protocol.nonblocking = 0; - protocol.memory_error = protocol_memory_error; - - if (dup2 (dev_null_fd, STDIN_FILENO) < 0) - error (1, errno, "can't set up pipes"); - if (dup2 (stdout_pipe[1], STDOUT_FILENO) < 0) - error (1, errno, "can't set up pipes"); - if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) - error (1, errno, "can't set up pipes"); - close (stdout_pipe[0]); - close (stderr_pipe[0]); - close (protocol_pipe[0]); -#ifdef SERVER_FLOWCONTROL - close (flowcontrol_pipe[1]); -#endif /* SERVER_FLOWCONTROL */ - - /* - * Set this in .bashrc if you want to give yourself time to attach - * to the subprocess with a debugger. - */ - if (getenv ("CVS_SERVER_SLEEP")) - { - int secs = atoi (getenv ("CVS_SERVER_SLEEP")); - sleep (secs); - } - - exitstatus = (*command) (argument_count, argument_vector); - - /* - * When we exit, that will close the pipes, giving an EOF to - * the parent. - */ - exit (exitstatus); - } - - /* OK, sit around getting all the input from the child. */ - { - struct buffer outbuf; - struct buffer stdoutbuf; - struct buffer stderrbuf; - struct buffer protocol_inbuf; - /* Number of file descriptors to check in select (). */ - int num_to_check; - int count_needed = 0; -#ifdef SERVER_FLOWCONTROL - int have_flowcontrolled = 0; -#endif /* SERVER_FLOWCONTROL */ - - FD_ZERO (&command_fds_to_drain.fds); - num_to_check = stdout_pipe[0]; - FD_SET (stdout_pipe[0], &command_fds_to_drain.fds); - if (stderr_pipe[0] > num_to_check) - num_to_check = stderr_pipe[0]; - FD_SET (stderr_pipe[0], &command_fds_to_drain.fds); - if (protocol_pipe[0] > num_to_check) - num_to_check = protocol_pipe[0]; - FD_SET (protocol_pipe[0], &command_fds_to_drain.fds); - if (STDOUT_FILENO > num_to_check) - num_to_check = STDOUT_FILENO; - max_command_fd = num_to_check; - /* - * File descriptors are numbered from 0, so num_to_check needs to - * be one larger than the largest descriptor. - */ - ++num_to_check; - if (num_to_check > FD_SETSIZE) - { - printf ("E internal error: FD_SETSIZE not big enough.\nerror \n"); - goto error_exit; - } - - outbuf.data = outbuf.last = NULL; - outbuf.fd = STDOUT_FILENO; - outbuf.output = 1; - outbuf.nonblocking = 0; - outbuf.memory_error = outbuf_memory_error; - - stdoutbuf.data = stdoutbuf.last = NULL; - stdoutbuf.fd = stdout_pipe[0]; - stdoutbuf.output = 0; - stdoutbuf.nonblocking = 0; - stdoutbuf.memory_error = input_memory_error; - - stderrbuf.data = stderrbuf.last = NULL; - stderrbuf.fd = stderr_pipe[0]; - stderrbuf.output = 0; - stderrbuf.nonblocking = 0; - stderrbuf.memory_error = input_memory_error; - - protocol_inbuf.data = protocol_inbuf.last = NULL; - protocol_inbuf.fd = protocol_pipe[0]; - protocol_inbuf.output = 0; - protocol_inbuf.nonblocking = 0; - protocol_inbuf.memory_error = input_memory_error; - - set_nonblock (&outbuf); - set_nonblock (&stdoutbuf); - set_nonblock (&stderrbuf); - set_nonblock (&protocol_inbuf); - - if (close (stdout_pipe[1]) < 0) - { - print_error (errno); - goto error_exit; - } - stdout_pipe[1] = -1; - - if (close (stderr_pipe[1]) < 0) - { - print_error (errno); - goto error_exit; - } - stderr_pipe[1] = -1; - - if (close (protocol_pipe[1]) < 0) - { - print_error (errno); - goto error_exit; - } - protocol_pipe[1] = -1; - -#ifdef SERVER_FLOWCONTROL - if (close (flowcontrol_pipe[0]) < 0) - { - print_error (errno); - goto error_exit; - } - flowcontrol_pipe[0] = -1; -#endif /* SERVER_FLOWCONTROL */ - - if (close (dev_null_fd) < 0) - { - print_error (errno); - goto error_exit; - } - dev_null_fd = -1; - - while (stdout_pipe[0] >= 0 - || stderr_pipe[0] >= 0 - || protocol_pipe[0] >= 0) - { - fd_set readfds; - fd_set writefds; - int numfds; -#ifdef SERVER_FLOWCONTROL - int bufmemsize; - - /* - * See if we are swamping the remote client and filling our VM. - * Tell child to hold off if we do. - */ - bufmemsize = buf_count_mem (&outbuf); - if (!have_flowcontrolled && (bufmemsize > SERVER_HI_WATER)) - { - if (write(flowcontrol_pipe[1], "S", 1) == 1) - have_flowcontrolled = 1; - } - else if (have_flowcontrolled && (bufmemsize < SERVER_LO_WATER)) - { - if (write(flowcontrol_pipe[1], "G", 1) == 1) - have_flowcontrolled = 0; - } -#endif /* SERVER_FLOWCONTROL */ - - FD_ZERO (&readfds); - FD_ZERO (&writefds); - if (! buf_empty_p (&outbuf)) - FD_SET (STDOUT_FILENO, &writefds); - - if (stdout_pipe[0] >= 0) - { - FD_SET (stdout_pipe[0], &readfds); - } - if (stderr_pipe[0] >= 0) - { - FD_SET (stderr_pipe[0], &readfds); - } - if (protocol_pipe[0] >= 0) - { - FD_SET (protocol_pipe[0], &readfds); - } - - do { - /* This used to select on exceptions too, but as far - as I know there was never any reason to do that and - SCO doesn't let you select on exceptions on pipes. */ - numfds = select (num_to_check, &readfds, &writefds, - (fd_set *)0, (struct timeval *)NULL); - if (numfds < 0 - && errno != EINTR) - { - print_error (errno); - goto error_exit; - } - } while (numfds < 0); - - if (FD_ISSET (STDOUT_FILENO, &writefds)) - { - /* What should we do with errors? syslog() them? */ - buf_send_output (&outbuf); - } - - if (stdout_pipe[0] >= 0 - && (FD_ISSET (stdout_pipe[0], &readfds))) - { - int status; - - status = buf_input_data (&stdoutbuf, (int *) NULL); - - buf_copy_lines (&outbuf, &stdoutbuf, 'M'); - - if (status == -1) - stdout_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (&outbuf); - } - - if (stderr_pipe[0] >= 0 - && (FD_ISSET (stderr_pipe[0], &readfds))) - { - int status; - - status = buf_input_data (&stderrbuf, (int *) NULL); - - buf_copy_lines (&outbuf, &stderrbuf, 'E'); - - if (status == -1) - stderr_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (&outbuf); - } - - if (protocol_pipe[0] >= 0 - && (FD_ISSET (protocol_pipe[0], &readfds))) - { - int status; - int count_read; - - status = buf_input_data (&protocol_inbuf, &count_read); - - /* - * We only call buf_copy_counted if we have read - * enough bytes to make it worthwhile. This saves us - * from continually recounting the amount of data we - * have. - */ - count_needed -= count_read; - if (count_needed <= 0) - count_needed = buf_copy_counted (&outbuf, &protocol_inbuf); - - if (status == -1) - protocol_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (&outbuf); - } - } - - /* - * OK, we've gotten EOF on all the pipes. If there is - * anything left on stdoutbuf or stderrbuf (this could only - * happen if there was no trailing newline), send it over. - */ - if (! buf_empty_p (&stdoutbuf)) - { - buf_append_char (&stdoutbuf, '\n'); - buf_copy_lines (&outbuf, &stdoutbuf, 'M'); - } - if (! buf_empty_p (&stderrbuf)) - { - buf_append_char (&stderrbuf, '\n'); - buf_copy_lines (&outbuf, &stderrbuf, 'E'); - } - if (! buf_empty_p (&protocol_inbuf)) - buf_output0 (&outbuf, - "E Protocol error: uncounted data discarded\n"); - - errs = 0; - - while (command_pid > 0) - { - int status; - pid_t waited_pid; - waited_pid = waitpid (command_pid, &status, 0); - if (waited_pid < 0) - { - /* - * Intentionally ignoring EINTR. Other errors - * "can't happen". - */ - continue; - } - - if (WIFEXITED (status)) - errs += WEXITSTATUS (status); - else - { - int sig = WTERMSIG (status); - /* - * This is really evil, because signals might be numbered - * differently on the two systems. We should be using - * signal names (either of the "Terminated" or the "SIGTERM" - * variety). But cvs doesn't currently use libiberty...we - * could roll our own.... FIXME. - */ - printf ("E Terminated with fatal signal %d\n", sig); - - /* Test for a core dump. Is this portable? */ - if (status & 0x80) - { - printf ("E Core dumped; preserving %s on server.\n\ -E CVS locks may need cleaning up.\n", - server_temp_dir); - dont_delete_temp = 1; - } - ++errs; - } - if (waited_pid == command_pid) - command_pid = -1; - } - - /* - * OK, we've waited for the child. By now all CVS locks are free - * and it's OK to block on the network. - */ - set_block (&outbuf); - buf_send_output (&outbuf); - } - - if (errs) - /* We will have printed an error message already. */ - printf ("error \n"); - else - printf ("ok\n"); - goto free_args_and_return; - - error_exit: - if (command_pid > 0) - kill (command_pid, SIGTERM); - - while (command_pid > 0) - { - pid_t waited_pid; - waited_pid = waitpid (command_pid, (int *) 0, 0); - if (waited_pid < 0 && errno == EINTR) - continue; - if (waited_pid == command_pid) - command_pid = -1; - } - - close (dev_null_fd); - close (protocol_pipe[0]); - close (protocol_pipe[1]); - close (stderr_pipe[0]); - close (stderr_pipe[1]); - close (stdout_pipe[0]); - close (stdout_pipe[1]); - - free_args_and_return: - /* Now free the arguments. */ - { - /* argument_vector[0] is a dummy argument, we don't mess with it. */ - char **cp; - for (cp = argument_vector + 1; - cp < argument_vector + argument_count; - ++cp) - free (*cp); - - argument_count = 1; - } - return; -} - -#ifdef SERVER_FLOWCONTROL -/* - * Called by the child at convenient points in the server's execution for - * the server child to block.. ie: when it has no locks active. - */ -void -server_pause_check() -{ - int paused = 0; - char buf[1]; - - while (read (flowcontrol_pipe[0], buf, 1) == 1) - { - if (*buf == 'S') /* Stop */ - paused = 1; - else if (*buf == 'G') /* Go */ - paused = 0; - else - return; /* ??? */ - } - while (paused) { - int numfds, numtocheck; - fd_set fds; - - FD_ZERO (&fds); - FD_SET (flowcontrol_pipe[0], &fds); - numtocheck = flowcontrol_pipe[0] + 1; - - do { - numfds = select (numtocheck, &fds, (fd_set *)0, - (fd_set *)0, (struct timeval *)NULL); - if (numfds < 0 - && errno != EINTR) - { - print_error (errno); - return; - } - } while (numfds < 0); - - if (FD_ISSET (flowcontrol_pipe[0], &fds)) - { - while (read (flowcontrol_pipe[0], buf, 1) == 1) - { - if (*buf == 'S') /* Stop */ - paused = 1; - else if (*buf == 'G') /* Go */ - paused = 0; - else - return; /* ??? */ - } - } - } -} -#endif /* SERVER_FLOWCONTROL */ - -static void output_dir PROTO((char *, char *)); - -static void -output_dir (update_dir, repository) - char *update_dir; - char *repository; -{ - if (use_dir_and_repos) - { - if (update_dir[0] == '\0') - buf_output0 (&protocol, "."); - else - buf_output0 (&protocol, update_dir); - buf_output0 (&protocol, "/\n"); - } - buf_output0 (&protocol, repository); - buf_output0 (&protocol, "/"); -} - -/* - * Entries line that we are squirreling away to send to the client when - * we are ready. - */ -static char *entries_line; - -/* - * File which has been Scratch_File'd, we are squirreling away that fact - * to inform the client when we are ready. - */ -static char *scratched_file; - -/* - * The scratched_file will need to be removed as well as having its entry - * removed. - */ -static int kill_scratched_file; - -void -server_register (name, version, timestamp, options, tag, date, conflict) - char *name; - char *version; - char *timestamp; - char *options; - char *tag; - char *date; - char *conflict; -{ - int len; - - if (trace) - { - (void) fprintf (stderr, - "%c-> server_register(%s, %s, %s, %s, %s, %s, %s)\n", - (server_active) ? 'S' : ' ', /* silly */ - name, version, timestamp, options, tag ? tag : "", - date ? date : "", conflict ? conflict : ""); - } - - if (options == NULL) - options = ""; - - if (entries_line != NULL) - { - /* - * If CVS decides to Register it more than once (which happens - * on "cvs update foo/foo.c" where foo and foo.c are already - * checked out), use the last of the entries lines Register'd. - */ - free (entries_line); - } - - /* - * I have reports of Scratch_Entry and Register both happening, in - * two different cases. Using the last one which happens is almost - * surely correct; I haven't tracked down why they both happen (or - * even verified that they are for the same file). - */ - if (scratched_file != NULL) - { - free (scratched_file); - scratched_file = NULL; - } - - len = (strlen (name) + strlen (version) + strlen (options) + 80); - if (tag) - len += strlen (tag); - if (date) - len += strlen (date); - - entries_line = xmalloc (len); - sprintf (entries_line, "/%s/%s/", name, version); - if (conflict != NULL) - { - strcat (entries_line, "+="); - } - strcat (entries_line, "/"); - strcat (entries_line, options); - strcat (entries_line, "/"); - if (tag != NULL) - { - strcat (entries_line, "T"); - strcat (entries_line, tag); - } - else if (date != NULL) - { - strcat (entries_line, "D"); - strcat (entries_line, date); - } -} - -void -server_scratch (fname) - char *fname; -{ - /* - * I have reports of Scratch_Entry and Register both happening, in - * two different cases. Using the last one which happens is almost - * surely correct; I haven't tracked down why they both happen (or - * even verified that they are for the same file). - */ - if (entries_line != NULL) - { - free (entries_line); - entries_line = NULL; - } - - if (scratched_file != NULL) - { - buf_output0 (&protocol, - "E CVS server internal error: duplicate Scratch_Entry\n"); - buf_send_counted (&protocol); - return; - } - scratched_file = xstrdup (fname); - kill_scratched_file = 1; -} - -void -server_scratch_entry_only () -{ - kill_scratched_file = 0; -} - -/* Print a new entries line, from a previous server_register. */ -static void -new_entries_line () -{ - if (entries_line) - { - buf_output0 (&protocol, entries_line); - buf_output (&protocol, "\n", 1); - } - else - /* Return the error message as the Entries line. */ - buf_output0 (&protocol, - "CVS server internal error: Register missing\n"); - free (entries_line); - entries_line = NULL; -} - -static void -serve_ci (arg) - char *arg; -{ - do_cvs_command (commit); -} - -void -server_checked_in (file, update_dir, repository) - char *file; - char *update_dir; - char *repository; -{ - if (noexec) - return; - if (scratched_file != NULL && entries_line == NULL) - { - /* - * This happens if we are now doing a "cvs remove" after a previous - * "cvs add" (without a "cvs ci" in between). - */ - buf_output0 (&protocol, "Remove-entry "); - output_dir (update_dir, repository); - buf_output0 (&protocol, file); - buf_output (&protocol, "\n", 1); - free (scratched_file); - scratched_file = NULL; - } - else - { - buf_output0 (&protocol, "Checked-in "); - output_dir (update_dir, repository); - buf_output0 (&protocol, file); - buf_output (&protocol, "\n", 1); - new_entries_line (); - } - buf_send_counted (&protocol); -} - -void -server_update_entries (file, update_dir, repository, updated) - char *file; - char *update_dir; - char *repository; - enum server_updated_arg4 updated; -{ - if (noexec) - return; - if (updated == SERVER_UPDATED) - buf_output0 (&protocol, "Checked-in "); - else - { - if (!supported_response ("New-entry")) - return; - buf_output0 (&protocol, "New-entry "); - } - - output_dir (update_dir, repository); - buf_output0 (&protocol, file); - buf_output (&protocol, "\n", 1); - new_entries_line (); - buf_send_counted (&protocol); -} - -static void -serve_update (arg) - char *arg; -{ - do_cvs_command (update); -} - -static void -serve_diff (arg) - char *arg; -{ - do_cvs_command (diff); -} - -static void -serve_log (arg) - char *arg; -{ - do_cvs_command (cvslog); -} - -static void -serve_add (arg) - char *arg; -{ - do_cvs_command (add); -} - -static void -serve_remove (arg) - char *arg; -{ - do_cvs_command (cvsremove); -} - -static void -serve_status (arg) - char *arg; -{ - do_cvs_command (status); -} - -static void -serve_rdiff (arg) - char *arg; -{ - do_cvs_command (patch); -} - -static void -serve_tag (arg) - char *arg; -{ - do_cvs_command (tag); -} - -static void -serve_rtag (arg) - char *arg; -{ - do_cvs_command (rtag); -} - -static void -serve_import (arg) - char *arg; -{ - do_cvs_command (import); -} - -static void -serve_admin (arg) - char *arg; -{ - do_cvs_command (admin); -} - -static void -serve_history (arg) - char *arg; -{ - do_cvs_command (history); -} - -static void -serve_release (arg) - char *arg; -{ - do_cvs_command (release); -} - -static void -serve_co (arg) - char *arg; -{ - char *tempdir; - int status; - - if (print_pending_error ()) - return; - - if (!isdir (CVSADM)) - { - /* - * The client has not sent a "Repository" line. Check out - * into a pristine directory. - */ - tempdir = malloc (strlen (server_temp_dir) + 80); - if (tempdir == NULL) - { - printf ("E Out of memory\n"); - return; - } - strcpy (tempdir, server_temp_dir); - strcat (tempdir, "/checkout-dir"); - status = mkdir_p (tempdir); - if (status != 0 && status != EEXIST) - { - printf ("E Cannot create %s\n", tempdir); - print_error (errno); - free (tempdir); - return; - } - - if (chdir (tempdir) < 0) - { - printf ("E Cannot change to directory %s\n", tempdir); - print_error (errno); - free (tempdir); - return; - } - free (tempdir); - } - do_cvs_command (checkout); -} - -static void -serve_export (arg) - char *arg; -{ - /* Tell checkout() to behave like export not checkout. */ - command_name = "export"; - serve_co (arg); -} - -void -server_copy_file (file, update_dir, repository, newfile) - char *file; - char *update_dir; - char *repository; - char *newfile; -{ - if (!supported_response ("Copy-file")) - return; - buf_output0 (&protocol, "Copy-file "); - output_dir (update_dir, repository); - buf_output0 (&protocol, file); - buf_output0 (&protocol, "\n"); - buf_output0 (&protocol, newfile); - buf_output0 (&protocol, "\n"); -} - -void -server_updated (file, update_dir, repository, updated, file_info, checksum) - char *file; - char *update_dir; - char *repository; - enum server_updated_arg4 updated; - struct stat *file_info; - unsigned char *checksum; -{ - char *short_pathname; - - if (noexec) - return; - - short_pathname = xmalloc (strlen (update_dir) + strlen (file) + 10); - if (update_dir[0] == '\0') - strcpy (short_pathname, file); - else - sprintf (short_pathname, "%s/%s", update_dir, file); - - if (entries_line != NULL && scratched_file == NULL) - { - FILE *f; - struct stat sb; - struct buffer_data *list, *last; - unsigned long size; - char size_text[80]; - - if (stat (file, &sb) < 0) - { - if (existence_error (errno)) - { - /* - * If we have a sticky tag for a branch on which the - * file is dead, and cvs update the directory, it gets - * a T_CHECKOUT but no file. So in this case just - * forget the whole thing. - */ - free (entries_line); - entries_line = NULL; - goto done; - } - error (1, errno, "reading %s", short_pathname); - } - - if (checksum != NULL) - { - static int checksum_supported = -1; - - if (checksum_supported == -1) - { - checksum_supported = supported_response ("Checksum"); - } - - if (checksum_supported) - { - int i; - char buf[3]; - - buf_output0 (&protocol, "Checksum "); - for (i = 0; i < 16; i++) - { - sprintf (buf, "%02x", (unsigned int) checksum[i]); - buf_output0 (&protocol, buf); - } - buf_append_char (&protocol, '\n'); - } - } - - if (updated == SERVER_UPDATED) - buf_output0 (&protocol, "Updated "); - else if (updated == SERVER_MERGED) - buf_output0 (&protocol, "Merged "); - else if (updated == SERVER_PATCHED) - buf_output0 (&protocol, "Patched "); - else - abort (); - output_dir (update_dir, repository); - buf_output0 (&protocol, file); - buf_output (&protocol, "\n", 1); - - new_entries_line (); - - { - char *mode_string; - - /* FIXME: When we check out files the umask of the server - (set in .bashrc if rsh is in use, or set in main.c in - the kerberos case, I think) affects what mode we send, - and it shouldn't. */ - if (file_info != NULL) - mode_string = mode_to_string (file_info->st_mode); - else - mode_string = mode_to_string (sb.st_mode); - buf_output0 (&protocol, mode_string); - buf_output0 (&protocol, "\n"); - free (mode_string); - } - - list = last = NULL; - size = 0; - if (sb.st_size > 0) - { - if (gzip_level - /* - * For really tiny files, the gzip process startup - * time will outweigh the compression savings. This - * might be computable somehow; using 100 here is just - * a first approximation. - */ - && sb.st_size > 100) - { - int status, fd, gzip_status; - pid_t gzip_pid; - - fd = open (file, O_RDONLY, 0); - if (fd < 0) - error (1, errno, "reading %s", short_pathname); - fd = filter_through_gzip (fd, 1, gzip_level, &gzip_pid); - f = fdopen (fd, "r"); - status = buf_read_file_to_eof (f, &list, &last); - size = buf_chain_length (list); - if (status == -2) - (*protocol.memory_error) (&protocol); - else if (status != 0) - error (1, ferror (f) ? errno : 0, "reading %s", - short_pathname); - if (fclose (f) == EOF) - error (1, errno, "reading %s", short_pathname); - if (waitpid (gzip_pid, &gzip_status, 0) == -1) - error (1, errno, "waiting for gzip process %d", gzip_pid); - else if (gzip_status != 0) - error (1, 0, "gzip exited %d", gzip_status); - /* Prepending length with "z" is flag for using gzip here. */ - buf_output0 (&protocol, "z"); - } - else - { - long status; - - size = sb.st_size; - f = fopen (file, "r"); - if (f == NULL) - error (1, errno, "reading %s", short_pathname); - status = buf_read_file (f, sb.st_size, &list, &last); - if (status == -2) - (*protocol.memory_error) (&protocol); - else if (status != 0) - error (1, ferror (f) ? errno : 0, "reading %s", - short_pathname); - if (fclose (f) == EOF) - error (1, errno, "reading %s", short_pathname); - } - } - - sprintf (size_text, "%lu\n", size); - buf_output0 (&protocol, size_text); - - buf_append_data (&protocol, list, last); - /* Note we only send a newline here if the file ended with one. */ - - /* - * Avoid using up too much disk space for temporary files. - * A file which does not exist indicates that the file is up-to-date, - * which is now the case. If this is SERVER_MERGED, the file is - * not up-to-date, and we indicate that by leaving the file there. - * I'm thinking of cases like "cvs update foo/foo.c foo". - */ - if ((updated == SERVER_UPDATED || updated == SERVER_PATCHED) - /* But if we are joining, we'll need the file when we call - join_file. */ - && !joining ()) - unlink (file); - } - else if (scratched_file != NULL && entries_line == NULL) - { - if (strcmp (scratched_file, file) != 0) - error (1, 0, - "CVS server internal error: `%s' vs. `%s' scratched", - scratched_file, - file); - free (scratched_file); - scratched_file = NULL; - - if (kill_scratched_file) - buf_output0 (&protocol, "Removed "); - else - buf_output0 (&protocol, "Remove-entry "); - output_dir (update_dir, repository); - buf_output0 (&protocol, file); - buf_output (&protocol, "\n", 1); - } - else if (scratched_file == NULL && entries_line == NULL) - { - /* - * This can happen with death support if we were processing - * a dead file in a checkout. - */ - } - else - error (1, 0, - "CVS server internal error: Register *and* Scratch_Entry.\n"); - buf_send_counted (&protocol); - done: - free (short_pathname); -} - -void -server_set_entstat (update_dir, repository) - char *update_dir; - char *repository; -{ - static int set_static_supported = -1; - if (set_static_supported == -1) - set_static_supported = supported_response ("Set-static-directory"); - if (!set_static_supported) return; - - buf_output0 (&protocol, "Set-static-directory "); - output_dir (update_dir, repository); - buf_output0 (&protocol, "\n"); - buf_send_counted (&protocol); -} - -void -server_clear_entstat (update_dir, repository) - char *update_dir; - char *repository; -{ - static int clear_static_supported = -1; - if (clear_static_supported == -1) - clear_static_supported = supported_response ("Clear-static-directory"); - if (!clear_static_supported) return; - - if (noexec) - return; - - buf_output0 (&protocol, "Clear-static-directory "); - output_dir (update_dir, repository); - buf_output0 (&protocol, "\n"); - buf_send_counted (&protocol); -} - -void -server_set_sticky (update_dir, repository, tag, date) - char *update_dir; - char *repository; - char *tag; - char *date; -{ - static int set_sticky_supported = -1; - if (set_sticky_supported == -1) - set_sticky_supported = supported_response ("Set-sticky"); - if (!set_sticky_supported) return; - - if (noexec) - return; - - if (tag == NULL && date == NULL) - { - buf_output0 (&protocol, "Clear-sticky "); - output_dir (update_dir, repository); - buf_output0 (&protocol, "\n"); - } - else - { - buf_output0 (&protocol, "Set-sticky "); - output_dir (update_dir, repository); - buf_output0 (&protocol, "\n"); - if (tag != NULL) - { - buf_output0 (&protocol, "T"); - buf_output0 (&protocol, tag); - } - else - { - buf_output0 (&protocol, "D"); - buf_output0 (&protocol, date); - } - buf_output0 (&protocol, "\n"); - } - buf_send_counted (&protocol); -} - -static void -serve_gzip_contents (arg) - char *arg; -{ - int level; - level = atoi (arg); - if (level == 0) - level = 6; - gzip_level = level; -} - -static void -serve_ignore (arg) - char *arg; -{ - /* - * Just ignore this command. This is used to support the - * update-patches command, which is not a real command, but a signal - * to the client that update will accept the -u argument. - */ -} - -static int -expand_proc (pargc, argv, where, mwhere, mfile, shorten, - local_specified, omodule, msg) - int *pargc; - char **argv; - char *where; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *omodule; - char *msg; -{ - int i; - char *dir = argv[0]; - - /* If mwhere has been specified, the thing we're expanding is a - module -- just return its name so the client will ask for the - right thing later. If it is an alias or a real directory, - mwhere will not be set, so send out the appropriate - expansion. */ - - if (mwhere != NULL) - printf ("Module-expansion %s\n", mwhere); - else - { - /* We may not need to do this anymore -- check the definition - of aliases before removing */ - if (*pargc == 1) - printf ("Module-expansion %s\n", dir); - else - for (i = 1; i < *pargc; ++i) - printf ("Module-expansion %s/%s\n", dir, argv[i]); - } - return 0; -} - -static void -serve_expand_modules (arg) - char *arg; -{ - int i; - int err; - DBM *db; - err = 0; - - /* - * FIXME: error handling is bogus; do_module can write to stdout and/or - * stderr and we're not using do_cvs_command. - */ - - server_expanding = 1; - db = open_module (); - for (i = 1; i < argument_count; i++) - err += do_module (db, argument_vector[i], - CHECKOUT, "Updating", expand_proc, - NULL, 0, 0, 0, - (char *) NULL); - close_module (db); - server_expanding = 0; - { - /* argument_vector[0] is a dummy argument, we don't mess with it. */ - char **cp; - for (cp = argument_vector + 1; - cp < argument_vector + argument_count; - ++cp) - free (*cp); - - argument_count = 1; - } - if (err) - /* We will have printed an error message already. */ - printf ("error \n"); - else - printf ("ok\n"); -} - -void -server_prog (dir, name, which) - char *dir; - char *name; - enum progs which; -{ - if (!supported_response ("Set-checkin-prog")) - { - printf ("E \ -warning: this client does not support -i or -u flags in the modules file.\n"); - return; - } - switch (which) - { - case PROG_CHECKIN: - printf ("Set-checkin-prog "); - break; - case PROG_UPDATE: - printf ("Set-update-prog "); - break; - } - printf ("%s\n%s\n", dir, name); -} - -static void -serve_checkin_prog (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_CIPROG, "w+"); - if (f == NULL) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_CIPROG)); - sprintf(pending_error_text, "E cannot open %s", CVSADM_CIPROG); - return; - } - if (fprintf (f, "%s\n", arg) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_CIPROG)); - sprintf(pending_error_text, "E cannot write to %s", CVSADM_CIPROG); - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_CIPROG)); - sprintf(pending_error_text, "E cannot close %s", CVSADM_CIPROG); - return; - } -} - -static void -serve_update_prog (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_UPROG, "w+"); - if (f == NULL) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_UPROG)); - sprintf(pending_error_text, "E cannot open %s", CVSADM_UPROG); - return; - } - if (fprintf (f, "%s\n", arg) < 0) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_UPROG)); - sprintf(pending_error_text, "E cannot write to %s", CVSADM_UPROG); - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - pending_error_text = malloc (80 + strlen(CVSADM_UPROG)); - sprintf(pending_error_text, "E cannot close %s", CVSADM_UPROG); - return; - } -} - -static void serve_valid_requests PROTO((char *arg)); - -#endif /* SERVER_SUPPORT */ -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) - -/* - * Parts of this table are shared with the client code, - * but the client doesn't need to know about the handler - * functions. - */ - -struct request requests[] = -{ -#ifdef SERVER_SUPPORT -#define REQ_LINE(n, f, s) {n, f, s} -#else -#define REQ_LINE(n, f, s) {n, s} -#endif - - REQ_LINE("Root", serve_root, rq_essential), - REQ_LINE("Valid-responses", serve_valid_responses, rq_essential), - REQ_LINE("valid-requests", serve_valid_requests, rq_essential), - REQ_LINE("Repository", serve_repository, rq_essential), - REQ_LINE("Directory", serve_directory, rq_optional), - REQ_LINE("Max-dotdot", serve_max_dotdot, rq_optional), - REQ_LINE("Static-directory", serve_static_directory, rq_optional), - REQ_LINE("Sticky", serve_sticky, rq_optional), - REQ_LINE("Checkin-prog", serve_checkin_prog, rq_optional), - REQ_LINE("Update-prog", serve_update_prog, rq_optional), - REQ_LINE("Entry", serve_entry, rq_essential), - REQ_LINE("Modified", serve_modified, rq_essential), - REQ_LINE("Lost", serve_lost, rq_optional), - REQ_LINE("UseUnchanged", serve_enable_unchanged, rq_enableme), - REQ_LINE("Unchanged", serve_unchanged, rq_optional), - REQ_LINE("Argument", serve_argument, rq_essential), - REQ_LINE("Argumentx", serve_argumentx, rq_essential), - REQ_LINE("Global_option", serve_global_option, rq_optional), - REQ_LINE("expand-modules", serve_expand_modules, rq_optional), - REQ_LINE("ci", serve_ci, rq_essential), - REQ_LINE("co", serve_co, rq_essential), - REQ_LINE("update", serve_update, rq_essential), - REQ_LINE("diff", serve_diff, rq_optional), - REQ_LINE("log", serve_log, rq_optional), - REQ_LINE("add", serve_add, rq_optional), - REQ_LINE("remove", serve_remove, rq_optional), - REQ_LINE("update-patches", serve_ignore, rq_optional), - REQ_LINE("gzip-file-contents", serve_gzip_contents, rq_optional), - REQ_LINE("status", serve_status, rq_optional), - REQ_LINE("rdiff", serve_rdiff, rq_optional), - REQ_LINE("tag", serve_tag, rq_optional), - REQ_LINE("rtag", serve_rtag, rq_optional), - REQ_LINE("import", serve_import, rq_optional), - REQ_LINE("admin", serve_admin, rq_optional), - REQ_LINE("export", serve_export, rq_optional), - REQ_LINE("history", serve_history, rq_optional), - REQ_LINE("release", serve_release, rq_optional), - REQ_LINE(NULL, NULL, rq_optional) - -#undef REQ_LINE -}; - -#endif /* SERVER_SUPPORT or CLIENT_SUPPORT */ -#ifdef SERVER_SUPPORT - -static void -serve_valid_requests (arg) - char *arg; -{ - struct request *rq; - if (print_pending_error ()) - return; - printf ("Valid-requests"); - for (rq = requests; rq->name != NULL; rq++) - if (rq->func != NULL) - printf (" %s", rq->name); - printf ("\nok\n"); -} - -#ifdef sun -/* - * Delete temporary files. SIG is the signal making this happen, or - * 0 if not called as a result of a signal. - */ -static int command_pid_is_dead; -static void wait_sig (sig) - int sig; -{ - int status; - pid_t r = wait (&status); - if (r == command_pid) - command_pid_is_dead++; -} -#endif - -void -server_cleanup (sig) - int sig; -{ - /* Do "rm -rf" on the temp directory. */ - int len; - char *cmd; - char *temp_dir; - - if (dont_delete_temp) - return; - - /* What a bogus kludge. This disgusting code makes all kinds of - assumptions about SunOS, and is only for a bug in that system. - So only enable it on Suns. */ -#ifdef sun - if (command_pid > 0) { - /* To avoid crashes on SunOS due to bugs in SunOS tmpfs - triggered by the use of rename() in RCS, wait for the - subprocess to die. Unfortunately, this means draining output - while waiting for it to unblock the signal we sent it. Yuck! */ - int status; - pid_t r; - - signal (SIGCHLD, wait_sig); - if (sig) - /* Perhaps SIGTERM would be more correct. But the child - process will delay the SIGINT delivery until its own - children have exited. */ - kill (command_pid, SIGINT); - /* The caller may also have sent a signal to command_pid, so - always try waiting. First, though, check and see if it's still - there.... */ - do_waitpid: - r = waitpid (command_pid, &status, WNOHANG); - if (r == 0) - ; - else if (r == command_pid) - command_pid_is_dead++; - else if (r == -1) - switch (errno) { - case ECHILD: - command_pid_is_dead++; - break; - case EINTR: - goto do_waitpid; - } - else - /* waitpid should always return one of the above values */ - abort (); - while (!command_pid_is_dead) { - struct timeval timeout; - struct fd_set_wrapper readfds; - char buf[100]; - int i; - - /* Use a non-zero timeout to avoid eating up CPU cycles. */ - timeout.tv_sec = 2; - timeout.tv_usec = 0; - readfds = command_fds_to_drain; - switch (select (max_command_fd + 1, &readfds.fds, - (fd_set *)0, (fd_set *)0, - &timeout)) { - case -1: - if (errno != EINTR) - abort (); - case 0: - /* timeout */ - break; - case 1: - for (i = 0; i <= max_command_fd; i++) - { - if (!FD_ISSET (i, &readfds.fds)) - continue; - /* this fd is non-blocking */ - while (read (i, buf, sizeof (buf)) >= 1) - ; - } - break; - default: - abort (); - } - } - } -#endif - - /* This might be set by the user in ~/.bashrc, ~/.cshrc, etc. */ - temp_dir = getenv ("TMPDIR"); - if (temp_dir == NULL || temp_dir[0] == '\0') - temp_dir = "/tmp"; - chdir(temp_dir); - - len = strlen (server_temp_dir) + 80; - cmd = malloc (len); - if (cmd == NULL) - { - printf ("E Cannot delete %s on server; out of memory\n", - server_temp_dir); - return; - } - sprintf (cmd, "rm -rf %s", server_temp_dir); - system (cmd); - free (cmd); -} - -int server_active = 0; -int server_expanding = 0; - -int -server (argc, argv) - int argc; - char **argv; -{ - if (argc == -1) - { - static const char *const msg[] = - { - "Usage: %s %s\n", - " Normally invoked by a cvs client on a remote machine.\n", - NULL - }; - usage (msg); - } - /* Ignore argc and argv. They might be from .cvsrc. */ - - /* Since we're in the server parent process, error should use the - protocol to report error messages. */ - error_use_protocol = 1; - - /* - * Put Rcsbin at the start of PATH, so that rcs programs can find - * themselves. - */ -#ifdef HAVE_PUTENV - if (Rcsbin != NULL && *Rcsbin) - { - char *p; - char *env; - - p = getenv ("PATH"); - if (p != NULL) - { - env = malloc (strlen (Rcsbin) + strlen (p) + sizeof "PATH=:"); - if (env != NULL) - sprintf (env, "PATH=%s:%s", Rcsbin, p); - } - else - { - env = malloc (strlen (Rcsbin) + sizeof "PATH="); - if (env != NULL) - sprintf (env, "PATH=%s", Rcsbin); - } - if (env == NULL) - { - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - exit (1); - } - putenv (env); - } -#endif - - /* OK, now figure out where we stash our temporary files. */ - { - char *p; - - /* This might be set by the user in ~/.bashrc, ~/.cshrc, etc. */ - char *temp_dir = getenv ("TMPDIR"); - if (temp_dir == NULL || temp_dir[0] == '\0') - temp_dir = "/tmp"; - - server_temp_dir = malloc (strlen (temp_dir) + 80); - if (server_temp_dir == NULL) - { - /* - * Strictly speaking, we're not supposed to output anything - * now. But we're about to exit(), give it a try. - */ - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - exit (1); - } - strcpy (server_temp_dir, temp_dir); - - /* Remove a trailing slash from TMPDIR if present. */ - p = server_temp_dir + strlen (server_temp_dir) - 1; - if (*p == '/') - *p = '\0'; - - /* - * I wanted to use cvs-serv/PID, but then you have to worry about - * the permissions on the cvs-serv directory being right. So - * use cvs-servPID. - */ - strcat (server_temp_dir, "/cvs-serv"); - - p = server_temp_dir + strlen (server_temp_dir); - sprintf (p, "%d", getpid ()); - } - - (void) SIG_register (SIGHUP, server_cleanup); - (void) SIG_register (SIGINT, server_cleanup); - (void) SIG_register (SIGQUIT, server_cleanup); - (void) SIG_register (SIGPIPE, server_cleanup); - (void) SIG_register (SIGTERM, server_cleanup); - - /* Now initialize our argument vector (for arguments from the client). */ - - /* Small for testing. */ - argument_vector_size = 1; - argument_vector = - (char **) malloc (argument_vector_size * sizeof (char *)); - if (argument_vector == NULL) - { - /* - * Strictly speaking, we're not supposed to output anything - * now. But we're about to exit(), give it a try. - */ - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - exit (1); - } - - argument_count = 1; - argument_vector[0] = "Dummy argument 0"; - - server_active = 1; - while (1) - { - char *cmd, *orig_cmd; - struct request *rq; - - orig_cmd = cmd = read_line (stdin); - if (cmd == NULL) - break; - if (cmd == NO_MEM_ERROR) - { - printf ("E Fatal server error, aborting.\n\ -error ENOMEM Virtual memory exhausted.\n"); - break; - } - for (rq = requests; rq->name != NULL; ++rq) - if (strncmp (cmd, rq->name, strlen (rq->name)) == 0) - { - int len = strlen (rq->name); - if (cmd[len] == '\0') - cmd += len; - else if (cmd[len] == ' ') - cmd += len + 1; - else - /* - * The first len characters match, but it's a different - * command. e.g. the command is "cooperate" but we matched - * "co". - */ - continue; - (*rq->func) (cmd); - break; - } - if (rq->name == NULL) - { - if (!print_pending_error ()) - printf ("error unrecognized request `%s'\n", cmd); - } - free (orig_cmd); - } - server_cleanup (0); - return 0; -} - - -#ifdef AUTH_SERVER_SUPPORT - -/* This was test code, which we may need again. */ -#if 0 - /* If we were invoked this way, then stdin comes from the - client and stdout/stderr writes to it. */ - int c; - while ((c = getc (stdin)) != EOF && c != '*') - { - printf ("%c", toupper (c)); - fflush (stdout); - } - exit (0); -#endif /* 1/0 */ - - -/* - * 0 means no entry found for this user. - * 1 means entry found and password matches. - * 2 means entry found, but password does not match. - */ -int -check_repository_password (username, password, repository) - char *username, *password, *repository; -{ - int retval = 0; - FILE *fp; - char *filename; - char linebuf[MAXLINELEN]; - int found_it = 0, len; - - filename = xmalloc (strlen (repository) - + 1 - + strlen ("CVSROOT") - + 1 - + strlen ("passwd") - + 1); - - strcpy (filename, repository); - strcat (filename, "/CVSROOT"); - strcat (filename, "/passwd"); - - fp = fopen (filename, "r"); - if (fp == NULL) - { - /* This is ok -- the cvs passwd file might not exist. */ - fclose (fp); - return 0; - } - - /* Look for a relevant line -- one with this user's name. */ - len = strlen (username); - while (fgets (linebuf, MAXPATHLEN - 1, fp)) - { - if ((strncmp (linebuf, username, len) == 0) - && (linebuf[len] == ':')) - { - found_it = 1; - break; - } - } - fclose (fp); - - /* If found_it != 0, then linebuf contains the information we need. */ - if (found_it) - { - char *found_password; - - strtok (linebuf, ":"); - found_password = strtok (NULL, ": \n"); - - if (strcmp (found_password, crypt (password, found_password)) == 0) - retval = 1; - else - retval = 2; - } - else - retval = 0; - - free (filename); - - return retval; -} - - -/* Return 1 if password matches, else 0. */ -int -check_password (username, password, repository) - char *username, *password, *repository; -{ - int rc; - - /* First we see if this user has a password in the CVS-specific - password file. If so, that's enough to authenticate with. If - not, we'll check /etc/passwd. */ - - rc = check_repository_password (username, password, repository); - - if (rc == 1) - return 1; - else if (rc == 2) - return 0; - else if (rc == 0) - { - /* No cvs password found, so try /etc/passwd. */ - - struct passwd *pw; - char *found_passwd; - - pw = getpwnam (username); - if (pw == NULL) - { - printf ("E Fatal error, aborting.\n" - "error 0 %s: no such user\n", username); - exit (1); - } - found_passwd = pw->pw_passwd; - - if (found_passwd && *found_passwd) - return (! strcmp (found_passwd, crypt (password, found_passwd))); - else if (password && *password) - return 1; - else - return 0; - } - else - { - /* Something strange happened. We don't know what it was, but - we certainly won't grant authorization. */ - return 0; - } -} - - -/* Read username and password from client (i.e., stdin). - If correct, then switch to run as that user and send an ACK to the - client via stdout, else send NACK and die. */ -void -authenticate_connection () -{ - int len; - char tmp[PATH_MAX]; - char repository[PATH_MAX]; - char username[PATH_MAX]; - char password[PATH_MAX]; - char server_user[PATH_MAX]; - struct passwd *pw; - - /* The Authentication Protocol. Client sends: - * - * BEGIN AUTH REQUEST\n - * <REPOSITORY>\n - * <USERNAME>\n - * <PASSWORD>\n - * END AUTH REQUEST\n - * - * Server uses above information to authenticate, then sends - * - * I LOVE YOU\n - * - * if it grants access, else - * - * I HATE YOU\n - * - * if it denies access (and it exits if denying). - * - * Note that the actual client/server protocol has not started up - * yet, because we haven't authenticated! Therefore, there are - * certain things we can't take for granted. For example, don't use - * error() because `error_use_protocol' has not yet been set by - * server(). - * - * We need to know where the repository is too, to look up the - * password in the special CVS passwd file before we try - * /etc/passwd. However, the repository is normally transmitted in - * the regular client/server protocol, which has not yet started, - * blah blah blah. This is why the client transmits the repository - * as part of the "authentication protocol". Thus, the repository - * will be redundantly retransmitted later, but that's no big deal. - */ - - /* Make sure the protocol starts off on the right foot... */ - fgets (tmp, PATH_MAX, stdin); - if (strcmp (tmp, "BEGIN AUTH REQUEST\n")) - { - printf ("error: bad auth protocol start: %s", tmp); - fflush (stdout); - exit (1); - } - - /* Get the three important pieces of information in order. */ - fgets (repository, PATH_MAX, stdin); - fgets (username, PATH_MAX, stdin); - fgets (password, PATH_MAX, stdin); - - /* Make them pure. */ - strip_trailing_newlines (repository); - strip_trailing_newlines (username); - strip_trailing_newlines (password); - - /* ... and make sure the protocol ends on the right foot. */ - fgets (tmp, PATH_MAX, stdin); - if (strcmp (tmp, "END AUTH REQUEST\n")) - { - printf ("error: bad auth protocol end: %s", tmp); - fflush (stdout); - exit (1); - } - - if (check_password (username, password, repository)) - { - printf ("I LOVE YOU\n"); - fflush (stdout); - } - else - { - printf ("I HATE YOU\n"); - fflush (stdout); - exit (1); - } - - /* Do everything that kerberos did. */ - pw = getpwnam (username); - if (pw == NULL) - { - printf ("E Fatal error, aborting.\n" - "error 0 %s: no such user\n", username); - exit (1); - } - - initgroups (pw->pw_name, pw->pw_gid); - setgid (pw->pw_gid); - setuid (pw->pw_uid); - /* Inhibit access by randoms. Don't want people randomly - changing our temporary tree before we check things in. */ - umask (077); - -#if HAVE_PUTENV - /* Set LOGNAME and USER in the environment, in case they are - already set to something else. */ - { - char *env; - - env = xmalloc (sizeof "LOGNAME=" + strlen (username)); - (void) sprintf (env, "LOGNAME=%s", username); - (void) putenv (env); - - env = xmalloc (sizeof "USER=" + strlen (username)); - (void) sprintf (env, "USER=%s", username); - (void) putenv (env); - } -#endif /* HAVE_PUTENV */ -} - -#endif AUTH_SERVER_SUPPORT - - -#endif /* SERVER_SUPPORT */ - diff --git a/gnu/usr.bin/cvs/cvs/server.h b/gnu/usr.bin/cvs/cvs/server.h deleted file mode 100644 index cb49267..0000000 --- a/gnu/usr.bin/cvs/cvs/server.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Interface between the server and the rest of CVS. */ - -/* Miscellaneous stuff which isn't actually particularly server-specific. */ -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 -#endif - -#ifdef SERVER_SUPPORT - -/* - * Nonzero if we are using the server. Used by various places to call - * server-specific functions. - */ -extern int server_active; -extern int server_expanding; - -/* Server functions exported to the rest of CVS. */ - -/* Run the server. */ -extern int server PROTO((int argc, char **argv)); - -/* We have a new Entries line for a file. TAG or DATE can be NULL. */ -extern void server_register - PROTO((char *name, char *version, char *timestamp, - char *options, char *tag, char *date, char *conflict)); - -/* - * We want to nuke the Entries line for a file, and (unless - * server_scratch_entry_only is subsequently called) the file itself. - */ -extern void server_scratch PROTO((char *name)); - -/* - * The file which just had server_scratch called on it needs to have only - * the Entries line removed, not the file itself. - */ -extern void server_scratch_entry_only PROTO((void)); - -/* - * We just successfully checked in FILE (which is just the bare - * filename, with no directory). REPOSITORY is the directory for the - * repository. - */ -extern void server_checked_in - PROTO((char *file, char *update_dir, char *repository)); - -extern void server_copy_file - PROTO((char *file, char *update_dir, char *repository, char *newfile)); - -/* - * We just successfully updated FILE (bare filename, no directory). - * REPOSITORY is the directory for the repository. This is called - * after server_register or server_scratch, in the latter case the - * file is to be removed. UPDATED indicates whether the file is now - * up to date (SERVER_UPDATED, yes, SERVER_MERGED, no, SERVER_PATCHED, - * yes, but file is a diff from user version to repository version). - */ -enum server_updated_arg4 {SERVER_UPDATED, SERVER_MERGED, SERVER_PATCHED}; -extern void server_updated - PROTO((char *file, char *update_dir, char *repository, - enum server_updated_arg4 updated, struct stat *, - unsigned char *checksum)); - -/* Set the Entries.Static flag. */ -extern void server_set_entstat PROTO((char *update_dir, char *repository)); -/* Clear it. */ -extern void server_clear_entstat PROTO((char *update_dir, char *repository)); - -/* Set or clear a per-directory sticky tag or date. */ -extern void server_set_sticky PROTO((char *update_dir, char *repository, - char *tag, - char *date)); - -extern void server_update_entries - PROTO((char *file, char *update_dir, char *repository, - enum server_updated_arg4 updated)); - -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 */ - -/* Stuff shared with the client. */ -struct request -{ - /* Name of the request. */ - char *name; - -#ifdef SERVER_SUPPORT - /* - * Function to carry out the request. ARGS is the text of the command - * after name and, if present, a single space, have been stripped off. - */ - void (*func) PROTO((char *args)); -#endif - - /* Stuff for use by the client. */ - enum { - /* - * Failure to implement this request can imply a fatal - * error. This should be set only for commands which were in the - * original version of the protocol; it should not be set for new - * commands. - */ - rq_essential, - - /* Some servers might lack this request. */ - rq_optional, - - /* - * Set by the client to one of the following based on what this - * server actually supports. - */ - rq_supported, - rq_not_supported, - - /* - * If the server supports this request, and we do too, tell the - * server by making the request. - */ - rq_enableme - } status; -}; - -/* Table of requests ending with an entry with a NULL name. */ -extern struct request requests[]; - -extern int use_unchanged; diff --git a/gnu/usr.bin/cvs/cvs/status.c b/gnu/usr.bin/cvs/cvs/status.c deleted file mode 100644 index fe53bcb..0000000 --- a/gnu/usr.bin/cvs/cvs/status.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * 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. - * - * Status Information - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)status.c 1.56 94/10/07 $"; -USE(rcsid); -#endif - -static Dtype status_dirproc PROTO((char *dir, char *repos, char *update_dir)); -static int status_fileproc PROTO((char *file, char *update_dir, - char *repository, List * entries, - List * srcfiles)); -static int tag_list_proc PROTO((Node * p, void *closure)); - -static int local = 0; -static int long_format = 0; -static char *xfile; -static List *xsrcfiles; - -static const char *const status_usage[] = -{ - "Usage: %s %s [-vlR] [files...]\n", - "\t-v\tVerbose format; includes tag information for the file\n", - "\t-l\tProcess this directory only (not recursive).\n", - "\t-R\tProcess directories recursively.\n", - NULL -}; - -int -status (argc, argv) - int argc; - char **argv; -{ - int c; - int err = 0; - - if (argc == -1) - usage (status_usage); - - optind = 1; - while ((c = getopt (argc, argv, "vlR")) != -1) - { - switch (c) - { - case 'v': - long_format = 1; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case '?': - default: - usage (status_usage); - break; - } - } - argc -= optind; - argv += optind; - - wrap_setup (); - -#ifdef CLIENT_SUPPORT - if (client_active) { - start_server (); - - ign_setup (); - - if (long_format) - send_arg("-v"); - if (local) - send_arg("-l"); - - /* 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"); - err = get_responses_and_close (); - - return err; - } -#endif - - /* start the recursion processor */ - err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, status_dirproc, - (DIRLEAVEPROC) NULL, argc, argv, local, - W_LOCAL, 0, 1, (char *) NULL, 1, 0); - - return (err); -} - -/* - * display the status of a file - */ -/* ARGSUSED */ -static int -status_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - Ctype status; - char *sstat; - Vers_TS *vers; - - status = Classify_File (file, (char *) NULL, (char *) NULL, (char *) NULL, - 1, 0, repository, entries, srcfiles, &vers, - update_dir, 0); - switch (status) - { - case T_UNKNOWN: - sstat = "Unknown"; - break; - case T_CHECKOUT: - sstat = "Needs Checkout"; - break; -#ifdef SERVER_SUPPORT - case T_PATCH: - sstat = "Needs Patch"; - break; -#endif - case T_CONFLICT: - sstat = "Unresolved Conflict"; - break; - case T_ADDED: - sstat = "Locally Added"; - break; - case T_REMOVED: - sstat = "Locally Removed"; - break; - case T_MODIFIED: - if (vers->ts_conflict) - sstat = "Unresolved Conflict"; - else - sstat = "Locally Modified"; - break; - case T_REMOVE_ENTRY: - sstat = "Entry Invalid"; - break; - case T_UPTODATE: - sstat = "Up-to-date"; - break; - case T_NEEDS_MERGE: - sstat = "Needs Merge"; - break; - default: - sstat = "Classify Error"; - break; - } - - (void) printf ("===================================================================\n"); - if (vers->ts_user == NULL) - (void) printf ("File: no file %s\t\tStatus: %s\n\n", file, sstat); - else - (void) printf ("File: %-17s\tStatus: %s\n\n", file, sstat); - - if (vers->vn_user == NULL) - (void) printf (" Working revision:\tNo entry for %s\n", file); - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - (void) printf (" Working revision:\tNew file!\n"); -#ifdef SERVER_SUPPORT - else if (server_active) - (void) printf (" Working revision:\t%s\n", vers->vn_user); -#endif - else - (void) printf (" Working revision:\t%s\t%s\n", vers->vn_user, - vers->ts_rcs); - - if (vers->vn_rcs == NULL) - (void) printf (" Repository revision:\tNo revision control file\n"); - else - (void) printf (" Repository revision:\t%s\t%s\n", vers->vn_rcs, - vers->srcfile->path); - - if (vers->entdata) - { - Entnode *edata; - - edata = vers->entdata; - if (edata->tag) - { - if (vers->vn_rcs == NULL) - (void) printf ( - " Sticky Tag:\t\t%s - MISSING from RCS file!\n", - edata->tag); - else - { - if (isdigit (edata->tag[0])) - (void) printf (" Sticky Tag:\t\t%s\n", edata->tag); - else - { - int isbranch = RCS_isbranch (file, edata->tag, srcfiles); - - (void) printf (" Sticky Tag:\t\t%s (%s: %s)\n", - edata->tag, - isbranch ? "branch" : "revision", - isbranch ? - RCS_whatbranch(file, edata->tag, srcfiles) : - vers->vn_rcs); - } - } - } - else if (!really_quiet) - (void) printf (" Sticky Tag:\t\t(none)\n"); - - if (edata->date) - (void) printf (" Sticky Date:\t\t%s\n", edata->date); - else if (!really_quiet) - (void) printf (" Sticky Date:\t\t(none)\n"); - - if (edata->options && edata->options[0]) - (void) printf (" Sticky Options:\t%s\n", edata->options); - else if (!really_quiet) - (void) printf (" Sticky Options:\t(none)\n"); - - if (long_format && vers->srcfile) - { - List *symbols = RCS_symbols(vers->srcfile); - - (void) printf ("\n Existing Tags:\n"); - if (symbols) - { - xfile = file; - xsrcfiles = srcfiles; - (void) walklist (symbols, tag_list_proc, NULL); - } - else - (void) printf ("\tNo Tags Exist\n"); - } - } - - (void) printf ("\n"); - freevers_ts (&vers); - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -status_dirproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "Examining %s", update_dir); - return (R_PROCESS); -} - -/* - * Print out a tag and its type - */ -static int -tag_list_proc (p, closure) - Node *p; - void *closure; -{ - int isbranch = RCS_isbranch (xfile, p->key, xsrcfiles); - - (void) printf ("\t%-25.25s\t(%s: %s)\n", p->key, - isbranch ? "branch" : "revision", - isbranch ? RCS_whatbranch(xfile, p->key, xsrcfiles) : - p->data); - return (0); -} diff --git a/gnu/usr.bin/cvs/cvs/tag.c b/gnu/usr.bin/cvs/cvs/tag.c deleted file mode 100644 index 55c8659..0000000 --- a/gnu/usr.bin/cvs/cvs/tag.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * 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. - * - * Tag - * - * Add or delete a symbolic name to an RCS file, or a collection of RCS files. - * Uses the checked out revision in the current directory. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)tag.c 1.60 94/09/30 $"; -USE(rcsid); -#endif - -static int check_fileproc PROTO((char *file, char *update_dir, - char *repository, List * entries, - List * srcfiles)); -static int check_filesdoneproc PROTO((int err, char *repos, char *update_dir)); -static int pretag_proc PROTO((char *repository, char *filter)); -static void masterlist_delproc PROTO((Node *p)); -static void tag_delproc PROTO((Node *p)); -static int pretag_list_proc PROTO((Node *p, void *closure)); - -static Dtype tag_dirproc PROTO((char *dir, char *repos, char *update_dir)); -static int tag_fileproc PROTO((char *file, char *update_dir, - char *repository, List * entries, - List * srcfiles)); - -static char *numtag; -static char *date = NULL; -static char *symtag; -static int delete; /* adding a tag by default */ -static int branch_mode; /* make an automagic "branch" tag */ -static int local; /* recursive by default */ -static int force_tag_match = 1; /* force tag to match by default */ -static int force_tag_move; /* don't force tag to move by default */ - -struct tag_info -{ - Ctype status; - char *rev; - char *tag; - char *options; -}; - -struct master_lists -{ - List *tlist; -}; - -static List *mtlist; -static List *tlist; - -static const char *const tag_usage[] = -{ - "Usage: %s %s [-lRF] [-b] [-d] tag [files...]\n", - "\t-l\tLocal directory only, not recursive.\n", - "\t-R\tProcess directories recursively.\n", - "\t-d\tDelete the given Tag.\n", - "\t-[rD]\tExisting tag or date.\n", - "\t-f\tForce a head revision if tag etc not found.\n", - "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n", - "\t-F\tMove tag if it already exists\n", - NULL -}; - -int -tag (argc, argv) - int argc; - char **argv; -{ - int c; - int err = 0; - - if (argc == -1) - usage (tag_usage); - - optind = 1; - while ((c = getopt (argc, argv, "FQqlRdr:D:bf")) != -1) - { - switch (c) - { - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'd': - delete = 1; - break; - case 'r': - numtag = optarg; - break; - case 'D': - if (date) - free (date); - date = Make_Date (optarg); - break; - case 'f': - force_tag_match = 0; - break; - case 'b': - branch_mode = 1; - break; - case 'F': - force_tag_move = 1; - break; - case '?': - default: - usage (tag_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (argc == 0) - usage (tag_usage); - symtag = argv[0]; - argc--; - argv++; - - if (delete && branch_mode) - error (0, 0, "warning: -b ignored with -d options"); - RCS_check_tag (symtag); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (delete) - send_arg("-d"); - if (branch_mode) - send_arg("-b"); - if (force_tag_move) - send_arg("-F"); - - send_arg (symtag); - -#if 0 - /* 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"); - return get_responses_and_close (); - } -#endif - - /* 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, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, - argc, argv, local, W_LOCAL, 0, 1, - (char *) NULL, 1, 0); - - if (err) - { - error (1, 0, "correct the above errors first!"); - } - - /* start the recursion processor */ - 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); -} - -/* check file that is to be tagged */ -/* All we do here is add it to our list */ - -static int -check_fileproc(file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List * entries; - List * srcfiles; -{ - char *xdir; - Node *p; - Vers_TS *vers; - - if (update_dir[0] == '\0') - xdir = "."; - else - xdir = update_dir; - if ((p = findnode (mtlist, xdir)) != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - struct master_lists *ml; - - tlist = getlist (); - p = getnode (); - p->key = xstrdup (xdir); - p->type = UPDATE; - ml = (struct master_lists *) - xmalloc (sizeof (struct master_lists)); - ml->tlist = tlist; - p->data = (char *) ml; - p->delproc = masterlist_delproc; - (void) addnode (mtlist, p); - } - /* do tlist */ - p = getnode (); - p->key = xstrdup (file); - p->type = UPDATE; - 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, 0); - if (p->data != NULL) - { - int addit = 1; - char *oversion; - - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); - if (oversion == NULL) - { - if (delete) - { - addit = 0; - } - } - else if (strcmp(oversion, p->data) == 0) - { - addit = 0; - } - else if (!force_tag_move) - { - addit = 0; - } - if (oversion != NULL) - { - free(oversion); - } - if (!addit) - { - free(p->data); - p->data = NULL; - } - } - freevers_ts(&vers); - (void) addnode (tlist, p); - return (0); -} - -static int -check_filesdoneproc(err, repos, update_dir) - int err; - char *repos; - char *update_dir; -{ - int n; - Node *p; - - p = findnode(mtlist, update_dir); - if (p != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - tlist = (List *) NULL; - } - if ((tlist == NULL) || (tlist->list->next == tlist->list)) - { - return (err); - } - if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0) - { - error (0, 0, "Pre-tag check failed"); - err += n; - } - return (err); -} - -static int -pretag_proc(repository, filter) - char *repository; - char *filter; -{ - if (filter[0] == '/') - { - char *s, *cp; - - s = xstrdup(filter); - for (cp=s; *cp; cp++) - { - if (isspace(*cp)) - { - *cp = '\0'; - break; - } - } - if (!isfile(s)) - { - error (0, errno, "cannot find pre-tag filter '%s'", s); - free(s); - return (1); - } - free(s); - } - run_setup("%s %s %s %s", - filter, - symtag, - delete ? "del" : force_tag_move ? "mov" : "add", - repository); - walklist(tlist, pretag_list_proc, NULL); - return (run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY)); -} - -static void -masterlist_delproc(p) - Node *p; -{ - struct master_lists *ml; - - ml = (struct master_lists *)p->data; - dellist(&ml->tlist); - free(ml); - return; -} - -static void -tag_delproc(p) - Node *p; -{ - if (p->data != NULL) - { - free(p->data); - p->data = NULL; - } - return; -} - -static int -pretag_list_proc(p, closure) - Node *p; - void *closure; -{ - if (p->data != NULL) - { - run_arg(p->key); - run_arg(p->data); - } - return (0); -} - - -/* - * Called to tag a particular file (the currently checked out version is - * tagged with the specified tag - or the specified tag is deleted). - */ -/* ARGSUSED */ -static int -tag_fileproc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - char *version, *oversion; - char *nversion = NULL; - char *rev; - Vers_TS *vers; - int retcode = 0; - - vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, - file, 0, 0, entries, srcfiles); - - if ((numtag != NULL) || (date != NULL)) - { - nversion = RCS_getversion(vers->srcfile, - numtag, - date, - force_tag_match, 0); - if (nversion == NULL) - { - freevers_ts (&vers); - return (0); - } - } - if (delete) - { - - /* - * If -d is specified, "force_tag_match" is set, so that this call to - * Version_Number() will return a NULL version string if the symbolic - * tag does not exist in the RCS file. - * - * This is done here because it's MUCH faster than just blindly calling - * "rcs" to remove the tag... trust me. - */ - - version = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); - if (version == NULL || vers->srcfile == NULL) - { - freevers_ts (&vers); - return (0); - } - free (version); - - if ((retcode = RCS_deltag(vers->srcfile->path, symtag, 1)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag %s from %s", symtag, - vers->srcfile->path); - freevers_ts (&vers); - return (1); - } - - /* warm fuzzies */ - if (!really_quiet) - { - if (update_dir[0]) - (void) printf ("D %s/%s\n", update_dir, file); - else - (void) printf ("D %s\n", file); - } - - freevers_ts (&vers); - return (0); - } - - /* - * If we are adding a tag, we need to know which version we have checked - * out and we'll tag that version. - */ - if (nversion == NULL) - { - version = vers->vn_user; - } - else - { - version = nversion; - } - if (version == NULL) - { - freevers_ts (&vers); - return (0); - } - else if (strcmp (version, "0") == 0) - { - if (!quiet) - error (0, 0, "couldn't tag added but un-commited file `%s'", file); - freevers_ts (&vers); - return (0); - } - else if (version[0] == '-') - { - if (!quiet) - error (0, 0, "skipping removed but un-commited file `%s'", file); - freevers_ts (&vers); - return (0); - } - else if (vers->srcfile == NULL) - { - if (!quiet) - error (0, 0, "cannot find revision control file for `%s'", file); - freevers_ts (&vers); - return (0); - } - - /* - * As an enhancement for the case where a tag is being re-applied to a - * large number of files, make one extra call to Version_Number to see if - * the tag is already set in the RCS file. If so, check to see if it - * needs to be moved. If not, do nothing. This will likely save a lot of - * time when simply moving the tag to the "current" head revisions of a - * module -- which I have found to be a typical tagging operation. - */ - rev = branch_mode ? RCS_magicrev (vers->srcfile, version) : version; - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, 0); - if (oversion != NULL) - { - int isbranch = RCS_isbranch (file, symtag, srcfiles); - - /* - * if versions the same and neither old or new are branches don't have - * to do anything - */ - if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) - { - free (oversion); - freevers_ts (&vers); - return (0); - } - - if (!force_tag_move) { /* we're NOT going to move the tag */ - if (update_dir[0]) - (void) printf ("W %s/%s", update_dir, file); - else - (void) printf ("W %s", file); - - (void) printf (" : %s already exists on %s %s", - symtag, isbranch ? "branch" : "version", oversion); - (void) printf (" : NOT MOVING tag to %s %s\n", - branch_mode ? "branch" : "version", rev); - free (oversion); - freevers_ts (&vers); - return (0); - } - free (oversion); - } - - if ((retcode = RCS_settag(vers->srcfile->path, symtag, rev)) != 0) - { - error (1, retcode == -1 ? errno : 0, - "failed to set tag %s to revision %s in %s", - symtag, rev, vers->srcfile->path); - freevers_ts (&vers); - return (1); - } - - /* more warm fuzzies */ - if (!really_quiet) - { - if (update_dir[0]) - (void) printf ("T %s/%s\n", update_dir, file); - else - (void) printf ("T %s\n", file); - } - - freevers_ts (&vers); - if (nversion != NULL) - { - free(nversion); - } - return (0); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -tag_dirproc (dir, repos, update_dir) - char *dir; - char *repos; - char *update_dir; -{ - if (!quiet) - error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir); - return (R_PROCESS); -} diff --git a/gnu/usr.bin/cvs/cvs/update.c b/gnu/usr.bin/cvs/cvs/update.c deleted file mode 100644 index 0dd0e1b..0000000 --- a/gnu/usr.bin/cvs/cvs/update.c +++ /dev/null @@ -1,1908 +0,0 @@ -/* - * 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. - * - * "update" updates the version in the present directory with respect to the RCS - * repository. The present version must have been created by "checkout". The - * user can keep up-to-date by calling "update" whenever he feels like it. - * - * The present version can be committed by "commit", but this keeps the version - * in tact. - * - * Arguments following the options are taken to be file names to be updated, - * rather than updating the entire directory. - * - * Modified or non-existent RCS files are checked out and reported as U - * <user_file> - * - * Modified user files are reported as M <user_file>. If both the RCS file and - * the user file have been modified, the user file is replaced by the result - * of rcsmerge, and a backup file is written for the user in .#file.version. - * If this throws up irreconcilable differences, the file is reported as C - * <user_file>, and as M <user_file> otherwise. - * - * Files added but not yet committed are reported as A <user_file>. Files - * removed but not yet committed are reported as R <user_file>. - * - * If the current directory contains subdirectories that hold concurrent - * versions, these are updated too. If the -d option was specified, new - * directories added to the repository are automatically created and updated - * as well. - */ - -#include "cvs.h" -#ifdef CLIENT_SUPPORT -#include "update.h" -#endif -#ifdef SERVER_SUPPORT -#include "md5.h" -#endif - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)update.c 1.95 94/10/22 $"; -USE(rcsid); -#endif - -static int checkout_file PROTO((char *file, char *repository, List *entries, - List *srcfiles, Vers_TS *vers_ts, char *update_dir)); -#ifdef SERVER_SUPPORT -static int patch_file PROTO((char *file, char *repository, List *entries, - List *srcfiles, Vers_TS *vers_ts, char *update_dir, - int *docheckout, struct stat *file_info, - unsigned char *checksum)); -#endif -static int isemptydir PROTO((char *dir)); -static int merge_file PROTO((char *file, char *repository, List *entries, - Vers_TS *vers, char *update_dir)); -static int scratch_file PROTO((char *file, char *repository, List * entries, - char *update_dir)); -static Dtype update_dirent_proc PROTO((char *dir, char *repository, char *update_dir)); -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 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)); -#else -static void join_file PROTO((char *file, List *srcfiles, Vers_TS *vers_ts, - char *update_dir, List *entries)); -#endif - -static char *options = NULL; -static char *tag = NULL; -static char *date = NULL; -static char *join_rev1, *date_rev1; -static char *join_rev2, *date_rev2; -static int aflag = 0; -static int force_tag_match = 1; -static int update_build_dirs = 0; -static int update_prune_dirs = 0; -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[] = -{ - "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n", - " [-I ign] [-W spec] [files...]\n", - "\t-A\tReset any sticky tags/date/kopts.\n", - "\t-P\tPrune empty directories.\n", - "\t-d\tBuild directories, like checkout does.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, no recursion.\n", - "\t-R\tProcess directories recursively.\n", - "\t-p\tSend updates to standard output.\n", - "\t-k kopt\tUse RCS kopt -k option on checkout.\n", - "\t-r rev\tUpdate using specified revision/tag.\n", - "\t-D date\tSet date to update from.\n", - "\t-j rev\tMerge in changes made between current revision and rev.\n", - "\t-I ign\tMore files to ignore (! to reset).\n", - "\t-W spec\tWrappers specification line.\n", - NULL -}; - -/* - * update is the argv,argc based front end for arg parsing - */ -int -update (argc, argv) - int argc; - char **argv; -{ - int c, err; - int local = 0; /* recursive by default */ - int which; /* where to look for files and dirs */ - - if (argc == -1) - usage (update_usage); - - ign_setup (); - wrap_setup (); - - /* parse the args */ - optind = 1; - while ((c = getopt (argc, argv, "ApPflRQqduk:r:D:j:I:W:")) != -1) - { - switch (c) - { - case 'A': - aflag = 1; - break; - case 'I': - ign_add (optarg, 0); - break; - case 'W': - wrap_add (optarg, 0); - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'd': - update_build_dirs = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'r': - tag = optarg; - break; - case 'D': - date = Make_Date (optarg); - break; - case 'P': - update_prune_dirs = 1; - break; - case 'p': - pipeout = 1; - noexec = 1; /* so no locks will be created */ - break; - case 'j': - if (join_rev2) - error (1, 0, "only two -j options can be specified"); - if (join_rev1) - join_rev2 = optarg; - else - join_rev1 = optarg; - break; - case 'u': -#ifdef SERVER_SUPPORT - if (server_active) - patches = 1; - else -#endif - usage (update_usage); - break; - case '?': - default: - usage (update_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* The first pass does the regular update. If we receive at least - one patch which failed, we do a second pass and just fetch - those files whose patches failed. */ - do - { - int status; - - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (update_build_dirs) - send_arg("-d"); - if (pipeout) - send_arg("-p"); - if (!force_tag_match) - send_arg("-f"); - if (aflag) - send_arg("-A"); - if (update_prune_dirs) - send_arg("-P"); - client_prune_dirs = update_prune_dirs; - option_with_arg ("-r", tag); - if (date) - client_senddate (date); - if (join_rev1) - option_with_arg ("-j", join_rev1); - if (join_rev2) - option_with_arg ("-j", join_rev2); - - /* If the server supports the command "update-patches", that means - that it knows how to handle the -u argument to update, which - means to send patches instead of complete files. */ - if (failed_patches == NULL) - { - struct request *rq; - - for (rq = requests; rq->name != NULL; rq++) - { - if (strcmp (rq->name, "update-patches") == 0) - { - if (rq->status == rq_supported) - { - send_arg("-u"); - } - break; - } - } - } - - if (failed_patches == NULL) - send_files (argc, argv, local, aflag); - else - { - int i; - - (void) printf ("%s client: refetching unpatchable files\n", - program_name); - - if (toplevel_wd[0] != '\0' - && chdir (toplevel_wd) < 0) - { - error (1, errno, "could not chdir to %s", toplevel_wd); - } - - for (i = 0; i < failed_patches_count; i++) - (void) unlink_file (failed_patches[i]); - send_files (failed_patches_count, failed_patches, local, - aflag); - } - - failed_patches = NULL; - failed_patches_count = 0; - - if (fprintf (to_server, "update\n") < 0) - error (1, errno, "writing to server"); - - status = get_responses_and_close (); - if (status != 0) - return status; - - } while (failed_patches != NULL); - - return 0; - } -#endif - - /* - * 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 - * tag file as appropriate - */ - if (argc <= 0 && !pipeout) - { - if (update_build_dirs) - { - if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - server_clear_entstat (".", Name_Repository (NULL, NULL)); -#endif - } - - /* keep the CVS/Tag file current with the specified arguments */ - if (aflag || tag || date) - { - WriteTag ((char *) NULL, tag, date); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_sticky (".", Name_Repository (NULL, NULL), tag, date); -#endif - } - } - - /* look for files/dirs locally and in the repository */ - which = W_LOCAL | W_REPOS; - - /* look in the attic too if a tag or date is specified */ - if (tag != NULL || date != NULL || joining()) - which |= W_ATTIC; - - /* call the command line interface */ - err = do_update (argc, argv, options, tag, date, force_tag_match, - local, update_build_dirs, aflag, update_prune_dirs, - pipeout, which, join_rev1, join_rev2, (char *) NULL); - - /* free the space Make_Date allocated if necessary */ - if (date != NULL) - free (date); - - return (err); -} - -/* - * Command line interface to update (used by checkout) - */ -int -do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, - xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir) - 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 err = 0; - char *cp; - - /* fill in the statics */ - options = xoptions; - tag = xtag; - date = xdate; - force_tag_match = xforce; - update_build_dirs = xbuild; - aflag = xaflag; - update_prune_dirs = xprune; - pipeout = xpipeout; - - /* setup the join support */ - join_rev1 = xjoin_rev1; - join_rev2 = xjoin_rev2; - if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL) - { - *cp++ = '\0'; - date_rev1 = Make_Date (cp); - } - else - date_rev1 = (char *) NULL; - if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL) - { - *cp++ = '\0'; - date_rev2 = Make_Date (cp); - } - else - date_rev2 = (char *) NULL; - - /* call the recursion processor */ - err = start_recursion (update_file_proc, update_filesdone_proc, - update_dirent_proc, update_dirleave_proc, - argc, argv, local, which, aflag, 1, - preload_update_dir, 1, 0); - - /* see if we need to sleep before returning */ - if (last_register_time) - { - time_t now; - - (void) time (&now); - if (now == last_register_time) - sleep (1); /* to avoid time-stamp races */ - } - - return (err); -} - -/* - * This is the callback proc for update. It is called for each file in each - * directory by the recursion code. The current directory is the local - * instantiation. file is the file name we are to operate on. update_dir is - * set to the path relative to where we started (for pretty printing). - * repository is the repository. entries and srcfiles are the pre-parsed - * entries and source control files. - * - * This routine decides what needs to be done for each file and does the - * appropriate magic for checkout - */ -static int -update_file_proc (file, update_dir, repository, entries, srcfiles) - char *file; - char *update_dir; - char *repository; - List *entries; - List *srcfiles; -{ - int retval; - Ctype status; - Vers_TS *vers; - - status = Classify_File (file, tag, date, options, force_tag_match, - aflag, repository, entries, srcfiles, &vers, - update_dir, pipeout); - if (pipeout) - { - /* - * We just return success without doing anything if any of the really - * funky cases occur - * - * If there is still a valid RCS file, do a regular checkout type - * operation - */ - switch (status) - { - case T_UNKNOWN: /* unknown file was explicitly asked - * about */ - case T_REMOVE_ENTRY: /* needs to be un-registered */ - case T_ADDED: /* added but not committed */ - retval = 0; - break; - case T_CONFLICT: /* old punt-type errors */ - retval = 1; - break; - case T_UPTODATE: /* file was already up-to-date */ - case T_NEEDS_MERGE: /* needs merging */ - case T_MODIFIED: /* locally modified */ - case T_REMOVED: /* removed but not committed */ - case T_CHECKOUT: /* needs checkout */ -#ifdef SERVER_SUPPORT - case T_PATCH: /* needs patch */ -#endif - retval = checkout_file (file, repository, entries, srcfiles, - vers, update_dir); - break; - - default: /* can't ever happen :-) */ - error (0, 0, - "unknown file status %d for file %s", status, file); - retval = 0; - break; - } - } - else - { - switch (status) - { - case T_UNKNOWN: /* unknown file was explicitly asked - * about */ - case T_UPTODATE: /* file was already up-to-date */ - retval = 0; - break; - case T_CONFLICT: /* old punt-type errors */ - retval = 1; - (void) write_letter (file, 'C', update_dir); - break; - case T_NEEDS_MERGE: /* needs merging */ - if (noexec) - { - retval = 1; - (void) write_letter (file, 'C', update_dir); - } - else - { - if (wrap_merge_is_copy (file)) - /* Should we be warning the user that we are - * overwriting the user's copy of the file? */ - retval = checkout_file (file, repository, entries, - srcfiles, vers, update_dir); - else - retval = merge_file (file, repository, entries, - vers, update_dir); - } - break; - case T_MODIFIED: /* locally modified */ - retval = 0; - if (vers->ts_conflict) - { - char *filestamp; - int retcode; - - /* - * If the timestamp has changed and no conflict indicators - * are found, it isn't a 'C' any more. - */ -#ifdef SERVER_SUPPORT - if (server_active) - retcode = vers->ts_conflict[0] != '='; - else { - filestamp = time_stamp (file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); - } -#else - filestamp = time_stamp (file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); -#endif - - if (retcode) - { - /* - * If the timestamps differ, look for Conflict - * indicators to see if 'C' anyway. - */ - run_setup ("%s", GREP); - run_arg (RCS_MERGE_PAT); - run_arg (file); - retcode = run_exec (RUN_TTY, DEVNULL, - RUN_TTY,RUN_NORMAL); - if (retcode == -1) - { - if (update_dir[0] == '\0') - error (1, errno, - "fork failed while examining conflict in `%s'", - file); - else - error (1, errno, - "fork failed while examining conflict in `%s/%s'", - update_dir, file); - } - } - if (!retcode) - { - (void) write_letter (file, 'C', update_dir); - retval = 1; - } - else - { - /* Reregister to clear conflict flag. */ - Register (entries, file, vers->vn_rcs, vers->ts_rcs, - vers->options, vers->tag, - vers->date, (char *)0); - } - } - if (!retval) - retval = write_letter (file, 'M', update_dir); - break; -#ifdef SERVER_SUPPORT - case T_PATCH: /* needs patch */ - if (patches) - { - int docheckout; - struct stat file_info; - unsigned char checksum[16]; - - retval = patch_file (file, repository, entries, srcfiles, - vers, update_dir, &docheckout, - &file_info, checksum); - if (! docheckout) - { - if (server_active && retval == 0) - server_updated (file, update_dir, repository, - SERVER_PATCHED, &file_info, - checksum); - break; - } - } - /* Fall through. */ - /* If we're not running as a server, just check the - file out. It's simpler and faster than starting up - two new processes (diff and patch). */ - /* Fall through. */ -#endif - case T_CHECKOUT: /* needs checkout */ - retval = checkout_file (file, repository, entries, srcfiles, - vers, update_dir); -#ifdef SERVER_SUPPORT - if (server_active && retval == 0) - server_updated (file, update_dir, repository, - SERVER_UPDATED, (struct stat *) NULL, - (unsigned char *) NULL); -#endif - break; - case T_ADDED: /* added but not committed */ - retval = write_letter (file, 'A', update_dir); - break; - case T_REMOVED: /* removed but not committed */ - retval = write_letter (file, 'R', update_dir); - break; - case T_REMOVE_ENTRY: /* needs to be un-registered */ - retval = scratch_file (file, repository, entries, update_dir); -#ifdef SERVER_SUPPORT - if (server_active && retval == 0) - server_updated (file, update_dir, repository, - SERVER_UPDATED, (struct stat *) NULL, - (unsigned char *) NULL); -#endif - break; - default: /* can't ever happen :-) */ - error (0, 0, - "unknown file status %d for file %s", status, file); - retval = 0; - break; - } - } - - /* only try to join if things have gone well thus far */ - if (retval == 0 && join_rev1) -#ifdef SERVER_SUPPORT - join_file (file, srcfiles, vers, update_dir, entries, repository); -#else - join_file (file, srcfiles, vers, update_dir, entries); -#endif - - /* if this directory has an ignore list, add this file to it */ - if (ignlist) - { - Node *p; - - p = getnode (); - p->type = FILES; - p->key = xstrdup (file); - if (addnode (ignlist, p) != 0) - freenode (p); - } - - freevers_ts (&vers); - return (retval); -} - -/* - * update_filesdone_proc () is used - */ -/* 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; - char *update_dir; -{ - /* if this directory has an ignore list, process it then free it */ - if (ignlist) - { - ignore_files (ignlist, update_dir); - 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); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } -#ifdef CVSADM_ROOT -#ifdef SERVER_SUPPORT - else if (!server_active && !pipeout) -#else - else if (!pipeout) -#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 */ - - return (err); -} - -/* - * update_dirent_proc () is called back by the recursion processor before a - * sub-directory is processed for update. In this case, update_dirent proc - * will probably create the directory unless -d isn't specified and this is a - * new directory. A return code of 0 indicates the directory should be - * processed by the recursion code. A return of non-zero indicates the - * recursion code should skip this directory. - */ -static Dtype -update_dirent_proc (dir, repository, update_dir) - char *dir; - char *repository; - char *update_dir; -{ - if (ignore_directory (update_dir)) - { - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Ignoring %s", update_dir); - return R_SKIP_ALL; - } - - if (!isdir (dir)) - { - /* if we aren't building dirs, blow it off */ - if (!update_build_dirs) - return (R_SKIP_ALL); - - if (noexec) - { - /* ignore the missing dir if -n is specified */ - error (0, 0, "New directory `%s' -- ignored", dir); - return (R_SKIP_ALL); - } - else - { - /* otherwise, create the dir and appropriate adm files */ - make_directory (dir); - Create_Admin (dir, update_dir, repository, tag, date); - } - } - - /* - * If we are building dirs and not going to stdout, we make sure there is - * no static entries file and write the tag file as appropriate - */ - if (!pipeout) - { - if (update_build_dirs) - { - char tmp[PATH_MAX]; - - (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT); - if (unlink_file (tmp) < 0 && ! existence_error (errno)) - error (1, errno, "cannot remove file %s", tmp); -#ifdef SERVER_SUPPORT - if (server_active) - server_clear_entstat (update_dir, repository); -#endif - } - - /* keep the CVS/Tag file current with the specified arguments */ - if (aflag || tag || date) - { - WriteTag (dir, tag, date); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_sticky (update_dir, repository, tag, date); -#endif - } - - /* initialize the ignore list for this directory */ - ignlist = getlist (); - } - - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Updating %s", update_dir); - - return (R_PROCESS); -} - -/* - * update_dirleave_proc () is called back by the recursion code upon leaving - * a directory. It will prune empty directories if needed and will execute - * any appropriate update programs. - */ -/* ARGSUSED */ -static int -update_dirleave_proc (dir, err, update_dir) - char *dir; - int err; - char *update_dir; -{ - FILE *fp; - - /* run the update_prog if there is one */ - if (err == 0 && !pipeout && !noexec && - (fp = fopen (CVSADM_UPROG, "r")) != NULL) - { - char *cp; - char *repository; - char line[MAXLINELEN]; - - repository = Name_Repository ((char *) NULL, update_dir); - if (fgets (line, sizeof (line), fp) != NULL) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; - run_setup ("%s %s", line, repository); - (void) printf ("%s %s: Executing '", program_name, command_name); - run_print (stdout); - (void) printf ("'\n"); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - (void) fclose (fp); - free (repository); - } - - /* FIXME: chdir ("..") loses with symlinks. */ - /* Prune empty dirs on the way out - if necessary */ - (void) chdir (".."); - if (update_prune_dirs && isemptydir (dir)) - { - run_setup ("%s -fr", RM); - run_arg (dir); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - - return (err); -} - -/* - * Returns 1 if the argument directory is completely empty, other than the - * existence of the CVS directory entry. Zero otherwise. - */ -static int -isemptydir (dir) - char *dir; -{ - DIR *dirp; - struct dirent *dp; - - if ((dirp = opendir (dir)) == NULL) - { - error (0, 0, "cannot open directory %s for empty check", dir); - return (0); - } - while ((dp = readdir (dirp)) != NULL) - { - if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 && - strcmp (dp->d_name, CVSADM) != 0) - { - (void) closedir (dirp); - return (0); - } - } - (void) closedir (dirp); - return (1); -} - -/* - * scratch the Entries file entry associated with a file - */ -static int -scratch_file (file, repository, entries, update_dir) - char *file; - char *repository; - List *entries; - char *update_dir; -{ - history_write ('W', update_dir, "", file, repository); - Scratch_Entry (entries, file); - (void) unlink_file (file); - return (0); -} - -/* - * check out a file - essentially returns the result of the fork on "co". - */ -static int -checkout_file (file, repository, entries, srcfiles, vers_ts, update_dir) - char *file; - char *repository; - List *entries; - List *srcfiles; - Vers_TS *vers_ts; - char *update_dir; -{ - char backup[PATH_MAX]; - int set_time, retval = 0; - int retcode = 0; -#ifdef DEATH_SUPPORT - int file_is_dead; -#endif - - /* don't screw with backup files if we're going to stdout */ - if (!pipeout) - { - (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file); - if (isfile (file)) - rename_file (file, backup); - else - (void) unlink_file (backup); - } - -#ifdef DEATH_SUPPORT - file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs); - - if (!file_is_dead) { -#endif - - run_setup ("%s%s -q -r%s %s", Rcsbin, RCS_CO, vers_ts->vn_tag, - vers_ts->options); - - /* - * if we are checking out to stdout, print a nice message to stderr, and - * add the -p flag to the command - */ - if (pipeout) - { - run_arg ("-p"); - if (!quiet) - { - (void) fprintf (stderr, "===================================================================\n"); - if (update_dir[0]) - (void) fprintf (stderr, "Checking out %s/%s\n", - update_dir, file); - else - (void) fprintf (stderr, "Checking out %s\n", file); - (void) fprintf (stderr, "RCS: %s\n", vers_ts->srcfile->path); - (void) fprintf (stderr, "VERS: %s\n", vers_ts->vn_rcs); - (void) fprintf (stderr, "***************\n"); - } - } - - /* tack on the rcs and maybe the user file */ - run_arg (vers_ts->srcfile->path); - if (!pipeout) - run_arg (file); - -#ifdef DEATH_SUPPORT - } - if (file_is_dead || (retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, -#else - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, -#endif - (pipeout ? (RUN_NORMAL|RUN_REALLY) : RUN_NORMAL))) == 0) - { - if (!pipeout) - { - Vers_TS *xvers_ts; -#ifdef DEATH_SUPPORT - int resurrecting; - - resurrecting = 0; - - 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) - { - 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; - } - - if (cvswrite == TRUE && !file_is_dead) - xchmod (file, 1); -#else /* No DEATH_SUPPORT */ - if (cvswrite == TRUE) - xchmod (file, 1); -#endif /* No DEATH_SUPPORT */ - - /* set the time from the RCS file iff it was unknown before */ - if (vers_ts->vn_user == NULL || - strncmp (vers_ts->ts_rcs, "Initial", 7) == 0) - { - set_time = 1; - } - else - set_time = 0; - - wrap_fromcvs_process_file (file); - - xvers_ts = Version_TS (repository, options, tag, date, file, - 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); - -#ifdef DEATH_SUPPORT - if (file_is_dead) - { - if (xvers_ts->vn_user != NULL) - { - if (update_dir[0] == '\0') - error (0, 0, - "warning: %s is not (any longer) pertinent", - file); - else - error (0, 0, - "warning: %s/%s is not (any longer) pertinent", - update_dir, file); - } - Scratch_Entry (entries, file); - if (unlink_file (file) < 0 && ! existence_error (errno)) - { - if (update_dir[0] == '\0') - error (0, errno, "cannot remove %s", file); - else - error (0, errno, "cannot remove %s/%s", update_dir, - file); - } - } - else - Register (entries, file, - resurrecting ? "0" : xvers_ts->vn_rcs, - xvers_ts->ts_user, xvers_ts->options, - xvers_ts->tag, xvers_ts->date, - (char *)0); /* Clear conflict flag on fresh checkout */ -#else /* No DEATH_SUPPORT */ - Register (entries, file, xvers_ts->vn_rcs, xvers_ts->ts_user, - xvers_ts->options, xvers_ts->tag, xvers_ts->date, - (char *)0); /* Clear conflict flag on fresh checkout */ -#endif /* No DEATH_SUPPORT */ - - /* fix up the vers structure, in case it is used by join */ - if (join_rev1) - { - if (vers_ts->vn_user != NULL) - free (vers_ts->vn_user); - if (vers_ts->vn_rcs != NULL) - free (vers_ts->vn_rcs); - vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs); - vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs); - } - - /* If this is really Update and not Checkout, recode history */ - if (strcmp (command_name, "update") == 0) - history_write ('U', update_dir, xvers_ts->vn_rcs, file, - repository); - - freevers_ts (&xvers_ts); - -#ifdef DEATH_SUPPORT - if (!really_quiet && !file_is_dead) -#else - if (!really_quiet) -#endif - { - if (update_dir[0]) - (void) printf ("U %s/%s\n", update_dir, file); - else - (void) printf ("U %s\n", file); - } - } - } - else - { - int old_errno = errno; /* save errno value over the rename */ - - if (!pipeout && isfile (backup)) - rename_file (backup, file); - - error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, - "could not check out %s", file); - - retval = retcode; - } - - if (!pipeout) - (void) unlink_file (backup); - - return (retval); -} - -#ifdef SERVER_SUPPORT -/* Patch a file. Runs rcsdiff. This is only done when running as the - * server. The hope is that the diff will be smaller than the file - * itself. - */ -static int -patch_file (file, repository, entries, srcfiles, vers_ts, update_dir, - docheckout, file_info, checksum) - char *file; - char *repository; - List *entries; - List *srcfiles; - Vers_TS *vers_ts; - char *update_dir; - int *docheckout; - struct stat *file_info; - unsigned char *checksum; -{ - char backup[PATH_MAX]; - char file1[PATH_MAX]; - char file2[PATH_MAX]; - int retval = 0; - int retcode = 0; - int fail; - FILE *e; - - *docheckout = 0; - - if (pipeout || joining ()) - { - *docheckout = 1; - return 0; - } - - (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file); - if (isfile (file)) - rename_file (file, backup); - else - (void) unlink_file (backup); - - (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, file); - (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, file); - - fail = 0; - - /* We need to check out both revisions first, to see if either one - has a trailing newline. Because of this, we don't use rcsdiff, - but just use diff. */ - run_setup ("%s%s -q -p -r%s %s %s", Rcsbin, RCS_CO, vers_ts->vn_user, - vers_ts->options, vers_ts->srcfile->path); - if (run_exec (RUN_TTY, file1, RUN_TTY, RUN_NORMAL) != 0) - fail = 1; - else - { - e = fopen (file1, "r"); - if (e == NULL) - fail = 1; - else - { - if (fseek (e, (long) -1, SEEK_END) == 0 - && getc (e) != '\n') - { - fail = 1; - } - fclose (e); - } - } - - if (! fail) - { - /* Check it out into file, and then move to file2, so that we - can get the right modes into *FILE_INFO. We can't check it - out directly into file2 because co doesn't understand how - to do that. */ - run_setup ("%s%s -q -r%s %s %s %s", Rcsbin, RCS_CO, vers_ts->vn_rcs, - vers_ts->options, vers_ts->srcfile->path, file); - if (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0) - fail = 1; - else - { - if (!isreadable (file)) - { - /* File is dead. */ - fail = 1; - } - else - { - rename_file (file, file2); - if (cvswrite == TRUE) - xchmod (file2, 1); - e = fopen (file2, "r"); - if (e == NULL) - fail = 1; - else - { - struct MD5Context context; - int nl; - unsigned char buf[8192]; - unsigned len; - - nl = 0; - - /* Compute the MD5 checksum and make sure there is - a trailing newline. */ - MD5Init (&context); - while ((len = fread (buf, 1, sizeof buf, e)) != 0) - { - nl = buf[len - 1] == '\n'; - MD5Update (&context, buf, len); - } - MD5Final (checksum, &context); - - if (ferror (e) || ! nl) - { - fail = 1; - } - - fclose (e); - } - } - } - } - - if (! fail) - { - /* FIXME: This whole thing with diff/patch is rather more - convoluted than necessary (lots of forks and execs, need to - worry about versions of diff and patch, etc.). Also, we - send context lines which aren't needed (in the rare case in - which the diff doesn't apply, the checksum would catches it). - Solution perhaps is to librarify the RCS routines which apply - deltas or something equivalent. */ - /* This is -c, not -u, because we have no way of knowing which - DIFF is in use. */ - run_setup ("%s -c %s %s", DIFF, file1, file2); - - /* A retcode of 0 means no differences. 1 means some differences. */ - if ((retcode = run_exec (RUN_TTY, file, RUN_TTY, RUN_NORMAL)) != 0 - && retcode != 1) - { - fail = 1; - } - else - { -#define BINARY "Binary" - char buf[sizeof BINARY]; - unsigned int c; - - /* 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); - c = fread (buf, 1, sizeof BINARY - 1, e); - buf[c] = '\0'; - if (strcmp (buf, BINARY) == 0) - { - /* These are binary files. We could use diff -a, but - patch can't handle that. */ - fail = 1; - } - fclose (e); - } - } - - if (! fail) - { - Vers_TS *xvers_ts; - - /* This stuff is just copied blindly from checkout_file. I - don't really know what it does. */ - xvers_ts = Version_TS (repository, options, tag, date, file, - force_tag_match, 0, entries, srcfiles); - if (strcmp (xvers_ts->options, "-V4") == 0) - xvers_ts->options[0] = '\0'; - - Register (entries, file, xvers_ts->vn_rcs, - xvers_ts->ts_user, xvers_ts->options, - xvers_ts->tag, xvers_ts->date, NULL); - - if (stat (file2, file_info) < 0) - error (1, errno, "could not stat %s", file2); - - /* If this is really Update and not Checkout, recode history */ - if (strcmp (command_name, "update") == 0) - history_write ('P', update_dir, xvers_ts->vn_rcs, file, - repository); - - freevers_ts (&xvers_ts); - - if (!really_quiet) - { - if (update_dir[0]) - (void) printf ("P %s/%s\n", update_dir, file); - else - (void) printf ("P %s\n", file); - } - } - else - { - int old_errno = errno; /* save errno value over the rename */ - - if (isfile (backup)) - rename_file (backup, file); - - if (retcode != 0 && retcode != 1) - error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, - "could not diff %s", file); - - *docheckout = 1; - retval = retcode; - } - - (void) unlink_file (backup); - (void) unlink_file (file1); - (void) unlink_file (file2); - - return (retval); -} -#endif - -/* - * Several of the types we process only print a bit of information consisting - * of a single letter and the name. - */ -static int -write_letter (file, letter, update_dir) - char *file; - int letter; - char *update_dir; -{ - if (!really_quiet) - { - if (update_dir[0]) - (void) printf ("%c %s/%s\n", letter, update_dir, file); - else - (void) printf ("%c %s\n", letter, file); - } - return (0); -} - -/* - * Do all the magic associated with a file which needs to be merged - */ -static int -merge_file (file, repository, entries, vers, update_dir) - char *file; - char *repository; - List *entries; - Vers_TS *vers; - char *update_dir; -{ - char user[PATH_MAX]; - char backup[PATH_MAX]; - int status; - int retcode = 0; - - /* - * The users currently modified file is moved to a backup file name - * ".#filename.version", so that it will stay around for a few days - * before being automatically removed by some cron daemon. The "version" - * is the version of the file that the user was most up-to-date with - * before the merge. - */ - (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user); - if (update_dir[0]) - (void) sprintf (user, "%s/%s", update_dir, file); - else - (void) strcpy (user, file); - - (void) unlink_file (backup); - copy_file (file, backup); - xchmod (file, 1); - - status = RCS_merge(vers->srcfile->path, - vers->options, vers->vn_user, vers->vn_rcs); - if (status != 0 && status != 1) - { - error (0, status == -1 ? errno : 0, - "could not merge revision %s of %s", vers->vn_user, user); - error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", - user, backup); - rename_file (backup, file); - return (1); - } - - if (strcmp (vers->options, "-V4") == 0) - vers->options[0] = '\0'; - (void) time (&last_register_time); - { - char *cp = 0; - - if (status) - cp = time_stamp (file); - Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options, - vers->tag, vers->date, cp); - if (cp) - free (cp); - } - - /* fix up the vers structure, in case it is used by join */ - if (join_rev1) - { - if (vers->vn_user != NULL) - free (vers->vn_user); - vers->vn_user = xstrdup (vers->vn_rcs); - } - -#ifdef SERVER_SUPPORT - /* Send the new contents of the file before the message. If we - wanted to be totally correct, we would have the client write - the message only after the file has safely been written. */ - if (server_active) - { - server_copy_file (file, update_dir, repository, backup); - server_updated (file, update_dir, repository, SERVER_MERGED, - (struct stat *) NULL, (unsigned char *) NULL); - } -#endif - - if (!noexec && !xcmp (backup, file)) - { - printf ("%s already contains the differences between %s and %s\n", - user, vers->vn_user, vers->vn_rcs); - history_write ('G', update_dir, vers->vn_rcs, file, repository); - return (0); - } - - if (status == 1) - { - if (!noexec) - error (0, 0, "conflicts found in %s", user); - - if (!really_quiet) - (void) printf ("C %s\n", user); - - history_write ('C', update_dir, vers->vn_rcs, file, repository); - - } - else if (retcode == -1) - { - error (1, errno, "fork failed while examining update of %s", user); - } - else - { - if (!really_quiet) - (void) printf ("M %s\n", user); - history_write ('G', update_dir, vers->vn_rcs, file, repository); - } - return (0); -} - -/* - * Do all the magic associated with a file which needs to be joined - * (-j option) - */ -static void -#ifdef SERVER_SUPPORT -join_file (file, srcfiles, vers, update_dir, entries, repository) - char *repository; -#else -join_file (file, srcfiles, vers, update_dir, entries) -#endif - char *file; - List *srcfiles; - Vers_TS *vers; - char *update_dir; - List *entries; -{ - char user[PATH_MAX]; - char backup[PATH_MAX]; - char *options; - int status; - - char *rev1; - char *rev2; - char *jrev1; - char *jrev2; - char *jdate1; - char *jdate2; - - jrev1 = join_rev1; - jrev2 = join_rev2; - jdate1 = date_rev1; - jdate2 = date_rev2; - - if (wrap_merge_is_copy (file)) - { - /* FIXME: Should be including update_dir in message. */ - error (0, 0, - "Cannot merge %s because it is a merge-by-copy file.", file); - return; - } - - /* determine if we need to do anything at all */ - if (vers->srcfile == NULL || - vers->srcfile->path == NULL) - { - return; - } - - /* in all cases, use two revs. */ - - /* if only one rev is specified, it becomes the second rev */ - if (jrev2 == NULL) - { - jrev2 = jrev1; - jrev1 = NULL; - jdate2 = jdate1; - jdate1 = NULL; - } - - /* The file in the working directory doesn't exist in CVS/Entries. - FIXME: Shouldn't this case result in additional processing (if - the file was added going from rev1 to rev2, then do the equivalent - of a "cvs add")? (yes; easier said than done.. :-) */ - if (vers->vn_user == NULL) - { - /* No merge possible YET. */ - if (jdate2 != NULL) - error (0, 0, - "file %s is present in revision %s as of %s", - file, jrev2, jdate2); - else - error (0, 0, - "file %s is present in revision %s", - file, jrev2); - 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, 0); - if (rev2 == NULL) - { - if (!quiet) - { - if (jdate2 != NULL) - error (0, 0, - "cannot find revision %s as of %s in file %s", - jrev2, jdate2, file); - else - error (0, 0, - "cannot find revision %s in file %s", - jrev2, file); - } - return; - } - - /* skip joining identical revs */ - if (strcmp (rev2, vers->vn_user) == 0) - { - /* No merge necessary. */ - free (rev2); - return; - } - - if (jrev1 == NULL) - { - char *tst; - /* if the first rev is missing, then it is implied to be the - greatest common ancestor of both the join rev, and the - checked out rev. */ - - /* FIXME: What is this check for '!' about? If it is legal to - have '!' in the first character of vn_user, it isn't - documented at struct vers_ts in cvs.h. */ - tst = vers->vn_user; - if (*tst == '!') - { - /* file was dead. merge anyway and pretend it's been - added. */ - ++tst; - Register (entries, file, "0", vers->ts_user, vers->options, - vers->tag, (char *) 0, (char *) 0); - } - rev1 = gca (tst, rev2); - if (rev1 == NULL) - { - /* this should not be possible */ - error (0, 0, "bad gca"); - abort(); - } - - tst = RCS_gettag (vers->srcfile, rev2, 1, 0); - if (tst == NULL) - { - /* this should not be possible. */ - error (0, 0, "cannot find gca"); - abort(); - } - - free (tst); - - /* these two cases are noops */ - if (strcmp (rev1, rev2) == 0) - { - free (rev1); - free (rev2); - return; - } - } - else - { - /* otherwise, convert the first rev spec, walking branches and - dates. */ - - rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, 0); - if (rev1 == NULL) - { - if (!quiet) { - if (jdate1 != NULL) - error (0, 0, - "cannot find revision %s as of %s in file %s", - jrev1, jdate1, file); - else - error (0, 0, - "cannot find revision %s in file %s", - jrev1, file); - } - return; - } - } - - /* do the join */ - -#if 0 - dome { - /* special handling when two revisions are specified */ - if (join_rev1 && join_rev2) - { - rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1, 0); - if (rev == NULL) - { - if (!quiet && date_rev2 == NULL) - error (0, 0, - "cannot find revision %s in file %s", join_rev2, file); - return; - } - - baserev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0); - if (baserev == NULL) - { - if (!quiet && date_rev1 == NULL) - error (0, 0, - "cannot find revision %s in file %s", join_rev1, file); - free (rev); - return; - } - - /* - * nothing to do if: - * second revision matches our BASE revision (vn_user) && - * both revisions are on the same branch - */ - if (strcmp (vers->vn_user, rev) == 0 && - numdots (baserev) == numdots (rev)) - { - /* might be the same branch. take a real look */ - char *dot = strrchr (baserev, '.'); - int len = (dot - baserev) + 1; - - if (strncmp (baserev, rev, len) == 0) - return; - } - } - else - { - 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 */ - { - free (rev); - return; - } - - baserev = RCS_whatbranch (file, join_rev1, srcfiles); - if (baserev) - { - char *cp; - - /* we get a branch -- turn it into a revision, or NULL if trunk */ - if ((cp = strrchr (baserev, '.')) == NULL) - { - free (baserev); - baserev = (char *) NULL; - } - else - *cp = '\0'; - } - } - if (baserev && strcmp (baserev, rev) == 0) - { - /* they match -> nothing to do */ - free (rev); - free (baserev); - return; - } - } -#endif - - /* OK, so we have two revisions; continue on */ - -#ifdef SERVER_SUPPORT - if (server_active && !isreadable (file)) - { - int retcode; - /* The file is up to date. Need to check out the current contents. */ - run_setup ("%s%s -q -r%s", Rcsbin, RCS_CO, vers->vn_user); - run_arg (vers->srcfile->path); - retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - if (retcode != 0) - error (1, retcode == -1 ? errno : 0, - "failed to check out %s file", file); - } -#endif - - /* - * The users currently modified file is moved to a backup file name - * ".#filename.version", so that it will stay around for a few days - * before being automatically removed by some cron daemon. The "version" - * is the version of the file that the user was most up-to-date with - * before the merge. - */ - (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user); - if (update_dir[0]) - (void) sprintf (user, "%s/%s", update_dir, file); - else - (void) strcpy (user, file); - - (void) unlink_file (backup); - copy_file (file, backup); - xchmod (file, 1); - - options = vers->options; -#ifdef HAVE_RCS5 -#if 0 - if (*options == '\0') - options = "-kk"; /* to ignore keyword expansions */ -#endif -#endif - - status = RCS_merge (vers->srcfile->path, options, rev1, rev2); - if (status != 0 && status != 1) - { - error (0, status == -1 ? errno : 0, - "could not merge revision %s of %s", rev2, user); - error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s", - user, backup); - rename_file (backup, file); - } - 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; - - if (status) - cp = time_stamp (file); - Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options, - vers->tag, vers->date, cp); - if (cp) - free(cp); - } - -#ifdef SERVER_SUPPORT - if (server_active) - { - server_copy_file (file, update_dir, repository, backup); - server_updated (file, update_dir, repository, SERVER_MERGED, - (struct stat *) NULL, (unsigned char *) NULL); - } -#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 () -{ - return (join_rev1 != NULL); -} diff --git a/gnu/usr.bin/cvs/cvs/update.h b/gnu/usr.bin/cvs/cvs/update.h deleted file mode 100644 index 68c91d5..0000000 --- a/gnu/usr.bin/cvs/cvs/update.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Definitions of routines shared between local and client/server - "update" code. */ - -/* 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; - -extern int -update_filesdone_proc PROTO((int err, char *repository, char *update_dir)); diff --git a/gnu/usr.bin/cvs/cvs/vers_ts.c b/gnu/usr.bin/cvs/cvs/vers_ts.c deleted file mode 100644 index ebb7ca8..0000000 --- a/gnu/usr.bin/cvs/cvs/vers_ts.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)vers_ts.c 1.45 94/10/07 $"; -USE(rcsid); -#endif - -#ifdef SERVER_SUPPORT -static void time_stamp_server PROTO((char *, Vers_TS *)); -#endif - -/* - * Fill in and return a Vers_TS structure "user" is the name of the local - * file; entries is the entries file - preparsed for our pleasure. xfiles is - * all source code control files, preparsed for our pleasure - */ -Vers_TS * -Version_TS (repository, options, tag, date, user, force_tag_match, - set_time, entries, xfiles) - char *repository; - char *options; - char *tag; - char *date; - char *user; - int force_tag_match; - int set_time; - List *entries; - List *xfiles; -{ - Node *p; - RCSNode *rcsdata; - Vers_TS *vers_ts; - struct stickydirtag *sdtp; - - /* get a new Vers_TS struct */ - vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS)); - memset ((char *) vers_ts, 0, sizeof (*vers_ts)); - - /* - * look up the entries file entry and fill in the version and timestamp - * if entries is NULL, there is no entries file so don't bother trying to - * look it up (used by checkout -P) - */ - if (entries == NULL) - { - sdtp = NULL; - p = NULL; - } - else - { - p = findnode (entries, user); - sdtp = (struct stickydirtag *) entries->list->data; /* list-private */ - } - - if (p != NULL) - { - Entnode *entdata = (Entnode *) p->data; - - vers_ts->vn_user = xstrdup (entdata->version); - vers_ts->ts_rcs = xstrdup (entdata->timestamp); - vers_ts->ts_conflict = xstrdup (entdata->conflict); - if (!tag) - { - if (!(sdtp && sdtp->aflag)) - vers_ts->tag = xstrdup (entdata->tag); - } - if (!date) - { - if (!(sdtp && sdtp->aflag)) - vers_ts->date = xstrdup (entdata->date); - } - if (!options || (options && *options == '\0')) - { - if (!(sdtp && sdtp->aflag)) - vers_ts->options = xstrdup (entdata->options); - } - vers_ts->entdata = entdata; - } - - /* - * -k options specified on the command line override (and overwrite) - * options stored in the entries file - */ - if (options) - vers_ts->options = xstrdup (options); - else if (sdtp && sdtp->aflag == 0) - { - if (!vers_ts->options) - vers_ts->options = xstrdup (sdtp->options); - } - if (!vers_ts->options) - vers_ts->options = xstrdup (""); - - /* - * if tags were specified on the command line, they override what is in - * the Entries file - */ - if (tag || date) - { - vers_ts->tag = xstrdup (tag); - vers_ts->date = xstrdup (date); - } - else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0)) - { - if (!vers_ts->tag) - vers_ts->tag = xstrdup (sdtp->tag); - if (!vers_ts->date) - vers_ts->date = xstrdup (sdtp->date); - } - - /* Now look up the info on the source controlled file */ - if (xfiles != (List *) NULL) - { - p = findnode (xfiles, user); - if (p != NULL) - { - rcsdata = (RCSNode *) p->data; - rcsdata->refcount++; - } - else - rcsdata = NULL; - } - else if (repository != NULL) - rcsdata = RCS_parse (user, repository); - else - rcsdata = NULL; - - if (rcsdata != NULL) - { - /* squirrel away the rcsdata pointer for others */ - vers_ts->srcfile = rcsdata; - -#ifndef DEATH_SUPPORT - /* (is this indeed death support? I haven't looked carefully). */ - /* get RCS version number into vn_rcs (if appropriate) */ - if (((vers_ts->tag || vers_ts->date) && force_tag_match) || - ((rcsdata->flags & VALID) && (rcsdata->flags & INATTIC) == 0)) - { -#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, 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 - - /* - * If the source control file exists and has the requested revision, - * get the Date the revision was checked in. If "user" exists, set - * its mtime. - */ - if (set_time) - { - struct utimbuf t; - - memset ((char *) &t, 0, sizeof (t)); - if (vers_ts->vn_rcs && - (t.actime = t.modtime = RCS_getrevtime (rcsdata, - vers_ts->vn_rcs, (char *) 0, 0)) != -1) - (void) utime (user, &t); - } - } - - /* get user file time-stamp in ts_user */ - if (entries != (List *) NULL) - { -#ifdef SERVER_SUPPORT - if (server_active) - time_stamp_server (user, vers_ts); - else -#endif - vers_ts->ts_user = time_stamp (user); - } - - return (vers_ts); -} - -#ifdef SERVER_SUPPORT - -/* Set VERS_TS->TS_USER to time stamp for FILE. */ - -/* Separate these out to keep the logic below clearer. */ -#define mark_lost(V) ((V)->ts_user = 0) -#define mark_unchanged(V) ((V)->ts_user = xstrdup ((V)->ts_rcs)) - -static void -time_stamp_server (file, vers_ts) - char *file; - Vers_TS *vers_ts; -{ - struct stat sb; - char *cp; - - if (stat (file, &sb) < 0) - { - if (! existence_error (errno)) - error (1, errno, "cannot stat temp file"); - if (use_unchanged) - { - /* Missing file means lost or unmodified; check entries - file to see which. - - XXX FIXME - If there's no entries file line, we - wouldn't be getting the file at all, so consider it - lost. I don't know that that's right, but it's not - clear to me that either choice is. Besides, would we - have an RCS string in that case anyways? */ - if (vers_ts->entdata == NULL) - mark_lost (vers_ts); - else if (vers_ts->entdata->timestamp - && vers_ts->entdata->timestamp[0] == '=') - mark_unchanged (vers_ts); - else - mark_lost (vers_ts); - } - else - { - /* Missing file in the temp directory means that the file - was not modified. */ - mark_unchanged (vers_ts); - } - } - else if (sb.st_mtime == 0) - { - if (use_unchanged) - /* We shouldn't reach this case any more! */ - abort (); - - /* Special code used by server.c to indicate the file was lost. */ - mark_lost (vers_ts); - } - else - { - vers_ts->ts_user = xmalloc (25); - cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */ - cp[24] = 0; - (void) strcpy (vers_ts->ts_user, cp); - } -} - -#endif /* SERVER_SUPPORT */ -/* - * Gets the time-stamp for the file "file" and returns it in space it - * allocates - */ -char * -time_stamp (file) - char *file; -{ - struct stat sb; - char *cp; - char *ts; - - if (stat (file, &sb) < 0) - { - ts = NULL; - } - else - { - ts = xmalloc (25); - cp = asctime (gmtime (&sb.st_mtime)); /* copy in the modify time */ - cp[24] = 0; - (void) strcpy (ts, cp); - } - - return (ts); -} - -/* - * free up a Vers_TS struct - */ -void -freevers_ts (versp) - Vers_TS **versp; -{ - if ((*versp)->srcfile) - freercsnode (&((*versp)->srcfile)); - if ((*versp)->vn_user) - 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) - free ((*versp)->ts_rcs); - if ((*versp)->options) - free ((*versp)->options); - if ((*versp)->tag) - free ((*versp)->tag); - if ((*versp)->date) - free ((*versp)->date); - if ((*versp)->ts_conflict) - free ((*versp)->ts_conflict); - free ((char *) *versp); - *versp = (Vers_TS *) NULL; -} diff --git a/gnu/usr.bin/cvs/cvs/wrapper.c b/gnu/usr.bin/cvs/cvs/wrapper.c deleted file mode 100644 index ec5f43e..0000000 --- a/gnu/usr.bin/cvs/cvs/wrapper.c +++ /dev/null @@ -1,371 +0,0 @@ -#include "cvs.h" - -/* - Original Author: athan@morgan.com <Andrew C. Athan> 2/1/94 - Modified By: vdemarco@bou.shl.com - - This package was written to support the NEXTSTEP concept of - "wrappers." These 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. To solve the problem - effectively, it was also necessary to be able to prevent rcsmerge - application at appropriate times. - - ------------------ - Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) - - wildcard [option value][option value]... - - where option is one of - -f from cvs filter value: path to filter - -t to cvs filter value: path to filter - -m update methodology value: MERGE or COPY - - and value is a single-quote delimited value. - - E.g: - *.nib -f 'gunzipuntar' -t 'targzip' -m 'COPY' -*/ - - -typedef struct { - char *wildCard; - char *tocvsFilter; - char *fromcvsFilter; - char *conflictHook; - WrapMergeMethod mergeMethod; -} WrapperEntry; - -static WrapperEntry **wrap_list=NULL; -static WrapperEntry **wrap_saved_list=NULL; - -static int wrap_size=0; -static int wrap_count=0; -static int wrap_tempcount=0; -static int wrap_saved_count=0; -static int wrap_saved_tempcount=0; - -#define WRAPPER_GROW 8 - -void wrap_add_entry PROTO((WrapperEntry *e,int temp)); -void wrap_kill PROTO((void)); -void wrap_kill_temp PROTO((void)); -void wrap_free_entry PROTO((WrapperEntry *e)); -void wrap_free_entry_internal PROTO((WrapperEntry *e)); -void wrap_restore_saved PROTO((void)); - -void wrap_setup() -{ - char file[PATH_MAX]; - struct passwd *pw; - - /* Then add entries found in repository, if it exists */ - (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_WRAPPER); - if (isfile (file)){ - wrap_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){ - (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTWRAPPER); - if (isfile (file)){ - wrap_add_file (file, 0); - } - } - - /* Then add entries found in CVSWRAPPERS environment variable. */ - wrap_add (getenv (WRAPPER_ENV), 0); -} - -/* - * Open a file and read lines, feeding each line to a line parser. Arrange - * for keeping a temporary list of wrappers at the end, if the "temp" - * argument is set. - */ -void -wrap_add_file (file, temp) - const char *file; - int temp; -{ - FILE *fp; - char line[1024]; - - wrap_restore_saved(); - wrap_kill_temp(); - - /* load the file */ - if (!(fp = fopen (file, "r"))) - return; - while (fgets (line, sizeof (line), fp)) - wrap_add (line, temp); - (void) fclose (fp); -} - -void -wrap_kill() -{ - wrap_kill_temp(); - while(wrap_count) - wrap_free_entry(wrap_list[--wrap_count]); -} - -void -wrap_kill_temp() -{ - WrapperEntry **temps=wrap_list+wrap_count; - - while(wrap_tempcount) - wrap_free_entry(temps[--wrap_tempcount]); -} - -void -wrap_free_entry(e) - WrapperEntry *e; -{ - wrap_free_entry_internal(e); - free(e); -} - -void -wrap_free_entry_internal(e) - WrapperEntry *e; -{ - free(e->wildCard); - if(e->tocvsFilter) - free(e->tocvsFilter); - if(e->fromcvsFilter) - free(e->fromcvsFilter); - if(e->conflictHook) - free(e->conflictHook); -} - -void -wrap_restore_saved() -{ - if(!wrap_saved_list) - return; - - wrap_kill(); - - free(wrap_list); - - wrap_list=wrap_saved_list; - wrap_count=wrap_saved_count; - wrap_tempcount=wrap_saved_tempcount; - - wrap_saved_list=NULL; - wrap_saved_count=0; - wrap_saved_tempcount=0; -} - -void -wrap_add (line, isTemp) - char *line; - int isTemp; -{ - char *temp; - char ctemp; - WrapperEntry e; - char opt; - - if (!line || line[0] == '#') - return; - - memset (&e, 0, sizeof(e)); - - /* Search for the wild card */ - while(*line && isspace(*line)) - ++line; - for(temp=line;*line && !isspace(*line);++line) - ; - if(temp==line) - return; - - ctemp=*line; - *line='\0'; - - e.wildCard=xstrdup(temp); - *line=ctemp; - - while(*line){ - /* Search for the option */ - while(*line && *line!='-') - ++line; - if(!*line) - break; - ++line; - if(!*line) - break; - opt=*line; - - /* Search for the filter commandline */ - for(++line;*line && *line!='\'';++line); - if(!*line) - break; - - for(temp=++line;*line && (*line!='\'' || line[-1]=='\\');++line) - ; - - if(line==temp+1) - break; - - ctemp=*line; - *line='\0'; - switch(opt){ - case 'f': - if(e.fromcvsFilter) - free(e.fromcvsFilter); - 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=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=expand_path (temp); - if (!e.conflictHook) - error (1, 0, - "Invalid environmental variable string '%s'",temp); - break; - case 'm': - if(*temp=='C' || *temp=='c') - e.mergeMethod=WRAP_COPY; - else - e.mergeMethod=WRAP_MERGE; - break; - default: - break; - } - *line=ctemp; - if(!*line)break; - ++line; - } - - wrap_add_entry(&e, isTemp); -} - -void -wrap_add_entry(e, temp) - WrapperEntry *e; - int temp; -{ - int x; - if(wrap_count+wrap_tempcount>=wrap_size){ - wrap_size += WRAPPER_GROW; - wrap_list = (WrapperEntry **) xrealloc ((char *) wrap_list, - wrap_size * - sizeof (WrapperEntry *)); - } - - if(!temp && wrap_tempcount){ - for(x=wrap_count+wrap_tempcount-1;x>=wrap_count;--x) - wrap_list[x+1]=wrap_list[x]; - } - - x=(temp ? wrap_count+(wrap_tempcount++):(wrap_count++)); - wrap_list[x]=(WrapperEntry *)xmalloc(sizeof(WrapperEntry)); - wrap_list[x]->wildCard=e->wildCard; - wrap_list[x]->fromcvsFilter=e->fromcvsFilter; - wrap_list[x]->tocvsFilter=e->tocvsFilter; - wrap_list[x]->conflictHook=e->conflictHook; - wrap_list[x]->mergeMethod=e->mergeMethod; -} - -/* Return 1 if the given filename is a wrapper filename */ -int -wrap_name_has (name,has) - const char *name; - WrapMergeHas has; -{ - int x,count=wrap_count+wrap_saved_count; - char *temp; - - for(x=0;x<count;++x) - if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0){ - switch(has){ - case WRAP_TOCVS: - temp=wrap_list[x]->tocvsFilter; - break; - case WRAP_FROMCVS: - temp=wrap_list[x]->fromcvsFilter; - break; - case WRAP_CONFLICT: - temp=wrap_list[x]->conflictHook; - break; - default: - abort (); - } - if(temp==NULL) - return (0); - else - return (1); - } - return (0); -} - -WrapperEntry * -wrap_matching_entry (name) - const char *name; -{ - int x,count=wrap_count+wrap_saved_count; - - for(x=0;x<count;++x) - if (fnmatch (wrap_list[x]->wildCard, name, 0) == 0) - return wrap_list[x]; - return (WrapperEntry *)NULL; -} - -char * -wrap_tocvs_process_file(fileName) - const char *fileName; -{ - WrapperEntry *e=wrap_matching_entry(fileName); - static char buf[L_tmpnam+1]; - - if(e==NULL || e->tocvsFilter==NULL) - return NULL; - - tmpnam(buf); - - run_setup(e->tocvsFilter,fileName,buf); - run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY ); - - return buf; -} - -int -wrap_merge_is_copy (fileName) - const char *fileName; -{ - WrapperEntry *e=wrap_matching_entry(fileName); - if(e==NULL || e->mergeMethod==WRAP_MERGE) - return 0; - - return 1; -} - -char * -wrap_fromcvs_process_file(fileName) - const char *fileName; -{ - WrapperEntry *e=wrap_matching_entry(fileName); - static char buf[PATH_MAX]; - - if(e==NULL || e->fromcvsFilter==NULL) - return NULL; - - run_setup(e->fromcvsFilter,fileName); - run_exec(RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL ); - return buf; -} diff --git a/gnu/usr.bin/cvs/cvsbug/Makefile b/gnu/usr.bin/cvs/cvsbug/Makefile index 336fd13..dea1d63 100644 --- a/gnu/usr.bin/cvs/cvsbug/Makefile +++ b/gnu/usr.bin/cvs/cvsbug/Makefile @@ -1,4 +1,9 @@ -# $Id: Makefile,v 1.2 1995/12/11 01:58:51 peter Exp $ +# $Id: Makefile,v 1.3 1995/12/11 04:24:06 peter Exp $ + +.include "${.CURDIR}/../Makefile.inc" + +.PATH: ${CVSDIR}/src +.PATH: ${CVSDIR}/man MAN8= cvsbug.8 @@ -9,17 +14,15 @@ CLEANFILES+= cvsbug ver all: cvsbug .sh: - echo > ver cvs-`sed < ${.CURDIR}/../lib/version.c \ + echo > ver cvs-`sed < ${CVSDIR}/src/version.c \ -e '/version_string/!d' \ -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \ -e q` - sed -e "s,xVERSIONx,`cat ver`,g" ${.CURDIR}/$@.sh > $@ + sed -e "s,xVERSIONx,`cat ver`,g" $> > $@ beforeinstall: ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ cvsbug ${DESTDIR}${BINDIR}/cvsbug -.include "../../Makefile.inc" .include <bsd.prog.mk> - diff --git a/gnu/usr.bin/cvs/cvsbug/cvsbug.8 b/gnu/usr.bin/cvs/cvsbug/cvsbug.8 deleted file mode 100644 index 496ef14..0000000 --- a/gnu/usr.bin/cvs/cvsbug/cvsbug.8 +++ /dev/null @@ -1,269 +0,0 @@ -.\" -*- nroff -*- -.\" --------------------------------------------------------------------------- -.\" man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com) -.\" updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com -.\" -.\" This file is part of the Problem Report Management System (GNATS) -.\" Copyright 1992 Cygnus Support -.\" -.\" 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 Library General Public -.\" License along with this program; if not, write to the Free -.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA -.\" -.\" --------------------------------------------------------------------------- -.nh -.TH CVSBUG 1 xVERSIONx "February 1993" -.SH NAME -cvsbug \- send problem report (PR) about CVS to a central support site -.SH SYNOPSIS -.B cvsbug -[ -.I site -] -[ -.B \-f -.I problem-report -] -[ -.B \-t -.I mail-address -] -.br -.in +0.8i -[ -.B \-P -] -[ -.B \-L -] -[ -.B \-\-request-id -] -[ -.B \-v -] -.SH DESCRIPTION -.B cvsbug -is a tool used to submit -.I problem reports -.\" SITE ADMINISTRATORS - change this if you use a local default -(PRs) to a central support site. In most cases the correct -.I site -will be the default. This argument indicates the support site which -is responsible for the category of problem involved. Some sites may -use a local address as a default. -.I site -values are defined by using the -.BR aliases (5). -.LP -.B cvsbug -invokes an editor on a problem report template (after trying to fill -in some fields with reasonable default values). When you exit the -editor, -.B cvsbug -sends the completed form to the -.I Problem Report Management System -(\fBGNATS\fR) at a central support site. At the support site, the PR -is assigned a unique number and is stored in the \fBGNATS\fR database -according to its category and submitter-id. \fBGNATS\fR automatically -replies with an acknowledgement, citing the category and the PR -number. -.LP -To ensure that a PR is handled promptly, it should contain your (unique) -\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the -problem area. (Use -.B `cvsbug -L' -to see a list of categories.) -.LP -The -.B cvsbug -template at your site should already be customized with your -submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to -accomplish this is part of the installation procedures for -.BR cvsbug ). -If this hasn't been done, see your system administrator for your -submitter-id, or request one from your support site by invoking -.B `cvsbug \-\-request\-id'. -If your site does not distinguish between different user sites, or if -you are not affiliated with the support site, use -.B `net' -for this field. -.LP -The more precise your problem description and the more complete your -information, the faster your support team can solve your problems. -.SH OPTIONS -.TP -.BI \-f " problem-report" -specify a file (\fIproblem-report\fR) which already contains a -complete problem report. -.B cvsbug -sends the contents of the file without invoking the editor. If -the value for -.I problem-report -is -.BR `\|\-\|' , -then -.B cvsbug -reads from standard input. -.TP -.BI \-t " mail-address" -Change mail address at the support site for problem reports. The -default -.I mail-address -is the address used for the default -.IR site . -Use the -.I site -argument rather than this option in nearly all cases. -.TP -.B \-P -print the form specified by the environment variable -.B PR_FORM -on standard output. If -.B PR_FORM -is not set, print the standard blank PR template. No mail is sent. -.TP -.B -L -print the list of available categories. No mail is sent. -.TP -.B \-\-request\-id -sends mail to the default support site, or -.I site -if specified, with a request for your -.IR submitter-id . -If you are -not affiliated with -.IR site , -use a -.I submitter-id -of -.BR net \|'. -.TP -.B \-v -Display the -.B cvsbug -version number. -.LP -Note: use -.B cvsbug -to submit problem reports rather than mailing them directly. Using -both the template and -.B cvsbug -itself will help ensure all necessary information will reach the -support site. -.SH ENVIRONMENT -The environment variable -.B EDITOR -specifies the editor to invoke on the template. -.br -default: -.B vi -.sp -If the environment variable -.B PR_FORM -is set, then its value is used as the file name of the template for -your problem-report editing session. You can use this to start with a -partially completed form (for example, a form with the identification -fields already completed). -.SH "HOW TO FILL OUT A PROBLEM REPORT" -Problem reports have to be in a particular form so that a program can -easily manage them. Please remember the following guidelines: -.IP \(bu 3m -describe only -.B one problem -with each problem report. -.IP \(bu 3m -For follow-up mail, use the same subject line as the one in the automatic -acknowledgent. It consists of category, PR number and the original synopsis -line. This allows the support site to relate several mail messages to a -particular PR and to record them automatically. -.IP \(bu 3m -Please try to be as accurate as possible in the subject and/or synopsis line. -.IP \(bu 3m -The subject and the synopsis line are not confidential. This is -because open-bugs lists are compiled from them. Avoid confidential -information there. -.LP -See the GNU -.B Info -file -.B cvsbug.info -or the document \fIReporting Problems With cvsbug\fR\ for detailed -information on reporting problems -.SH "HOW TO SUBMIT TEST CASES, CODE, ETC." -Submit small code samples with the PR. Contact the support site for -instructions on submitting larger test cases and problematic source -code. -.SH FILES -.ta \w'/tmp/pbad$$ 'u -/tmp/p$$ copy of PR used in editing session -.br -/tmp/pf$$ copy of empty PR form, for testing purposes -.br -/tmp/pbad$$ file for rejected PRs -.SH EMACS USER INTERFACE -An Emacs user interface for -.B cvsbug -with completion of field values is part of the -.B cvsbug -distribution (invoked with -.BR "M-x cvsbug" ). -See the file -.B cvsbug.info -or the ASCII file -.B INSTALL -in the top level directory of the distribution for configuration and -installation information. The Emacs LISP template file is -.B cvsbug-el.in -and is installed as -.BR cvsbug.el . -.SH INSTALLATION AND CONFIGURATION -See -.B cvsbug.info -or -.B INSTALL -for installation instructions. -.SH SEE ALSO -.I Reporting Problems Using cvsbug -(also installed as the GNU Info file -.BR cvsbug.info ). -.LP -.BR gnats (l), -.BR query-pr (1), -.BR edit-pr (1), -.BR gnats (8), -.BR queue-pr (8), -.BR at-pr (8), -.BR mkcat (8), -.BR mkdist (8). -.SH AUTHORS -Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus -Support) -.SH COPYING -Copyright (c) 1992, 1993 Free Software Foundation, Inc. -.PP -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. -.PP -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. -.PP -Permission is granted to copy and distribute translations of this -manual into another language, under the above conditions for modified -versions, except that this permission notice may be included in -translations approved by the Free Software Foundation instead of in -the original English. - diff --git a/gnu/usr.bin/cvs/cvsbug/cvsbug.sh b/gnu/usr.bin/cvs/cvsbug/cvsbug.sh deleted file mode 100644 index ab26cfc..0000000 --- a/gnu/usr.bin/cvs/cvsbug/cvsbug.sh +++ /dev/null @@ -1,528 +0,0 @@ -#! /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 -# version written by Heinz G. Seidl (hgs@ide.com). -# -# This file is part of GNU GNATS. -# Modified by Berliner for CVS. -# -#ident "@(#)cvs/src:$Name: $:$Id: cvsbug.sh,v 1.10 1995/11/15 00:18:00 woods 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 -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# GNU GNATS 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 GNU GNATS; see the file COPYING. If not, write to -# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -# The version of this send-pr. -VERSION=3.2 - -# The submitter-id for your site. -SUBMITTER=net - -## # Where the GNATS directory lives, if at all. -## [ -z "$GNATS_ROOT" ] && -## GNATS_ROOT=/usr/local/lib/gnats/gnats-db - -# The default mail address for PR submissions. -GNATS_ADDR=bug-cvs@prep.ai.mit.edu - -## # Where the gnats category tree lives. -## DATADIR=/usr/local/lib - -## # If we've been moved around, try using GCC_EXEC_PREFIX. -## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}.. - -# The default release for this host. -DEFAULT_RELEASE="xVERSIONx" - -# The default organization. -DEFAULT_ORGANIZATION="net" - -## # The default site to look for. -## GNATS_SITE=unknown - -## # Newer config information? -## [ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config - -# What mailer to use. This must come after the config file, since it is -# host-dependent. -if [ -f /usr/sbin/sendmail ]; then - MAIL_AGENT="/usr/sbin/sendmail -oi -t" -else - MAIL_AGENT="/usr/lib/sendmail -oi -t" -fi -MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'` -if [ ! -f "$MAILER" ] ; then - echo "$COMMAND: Cannot file mail program \"$MAILER\"." - echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file." - exit 1 -fi - -if test "`echo -n foo`" = foo ; then - ECHON=bsd -elif test "`echo 'foo\c'`" = foo ; then - ECHON=sysv -else - ECHON=none -fi - -if [ $ECHON = bsd ] ; then - ECHON1="echo -n" - ECHON2= -elif [ $ECHON = sysv ] ; then - ECHON1=echo - ECHON2='\c' -else - ECHON1=echo - ECHON2= -fi - -# - -[ -z "$TMPDIR" ] && TMPDIR=/tmp - -TEMP=$TMPDIR/p$$ -BAD=$TMPDIR/pbad$$ -REF=$TMPDIR/pf$$ - -if [ -z "$LOGNAME" -a -n "$USER" ]; then - LOGNAME=$USER -fi - -FROM="$LOGNAME" -REPLY_TO="$LOGNAME" - -# Find out the name of the originator of this PR. -if [ -n "$NAME" ]; then - ORIGINATOR="$NAME" -elif [ -f $HOME/.fullname ]; then - ORIGINATOR="`sed -e '1q' $HOME/.fullname`" -elif [ -f /bin/domainname ]; then - if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then - # Must use temp file due to incompatibilities in quoting behavior - # and to protect shell metacharacters in the expansion of $LOGNAME - /usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" | - cut -f5 -d':' | sed -e 's/,.*//' > $TEMP - ORIGINATOR="`cat $TEMP`" - rm -f $TEMP - fi -fi - -if [ "$ORIGINATOR" = "" ]; then - grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP - ORIGINATOR="`cat $TEMP`" - rm -f $TEMP -fi - -if [ -n "$ORGANIZATION" ]; then - if [ -f "$ORGANIZATION" ]; then - ORGANIZATION="`cat $ORGANIZATION`" - fi -else - if [ -n "$DEFAULT_ORGANIZATION" ]; then - ORGANIZATION="$DEFAULT_ORGANIZATION" - elif [ -f $HOME/.organization ]; then - ORGANIZATION="`cat $HOME/.organization`" - elif [ -f $HOME/.signature ]; then - ORGANIZATION="`cat $HOME/.signature`" - fi -fi - -# If they don't have a preferred editor set, then use -if [ -z "$VISUAL" ]; then - if [ -z "$EDITOR" ]; then - EDIT=vi - else - EDIT="$EDITOR" - fi -else - EDIT="$VISUAL" -fi - -# Find out some information. -SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \ - ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""` -ARCH=`[ -f /bin/arch ] && /bin/arch` -MACHINE=`[ -f /bin/machine ] && /bin/machine` - -COMMAND=`echo $0 | sed -e 's,.*/,,'` -## USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id] -USAGE="Usage: $COMMAND [-PVL] -[--version]" -REMOVE= -BATCH= - -while [ $# -gt 0 ]; do - case "$1" in - -r) ;; # Ignore for backward compat. -## -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi -## shift ; GNATS_ADDR="$1" -## EXPLICIT_GNATS_ADDR=true -## ;; -## -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi -## shift ; IN_FILE="$1" -## if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then -## echo "$COMMAND: cannot read $IN_FILE" -## exit 1 -## fi -## ;; - -b | --batch) BATCH=true ;; - -p | -P | --print) PRINT=true ;; - -L | --list) FORMAT=norm ;; - -l | -CL | --lisp) FORMAT=lisp ;; -## --request-id) REQUEST_ID=true ;; - -h | --help) echo "$USAGE"; exit 0 ;; - -V | --version) echo "$VERSION"; exit 0 ;; - -*) echo "$USAGE" ; exit 1 ;; - *) echo "$USAGE" ; exit 1 -## if [ -z "$USER_GNATS_SITE" ]; then -## if [ ! -r "$DATADIR/gnats/$1" ]; then -## echo "$COMMAND: the GNATS site $1 does not have a categories list." -## exit 1 -## else -## # The site name is the alias they'll have to have created. -## USER_GNATS_SITE=$1 -## fi -## else -## echo "$USAGE" ; exit 1 -## fi - ;; - esac - shift -done - -if [ -n "$USER_GNATS_SITE" ]; then - GNATS_SITE=$USER_GNATS_SITE - GNATS_ADDR=$USER_GNATS_SITE-gnats -fi - -if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then - cat << '__EOF__' -It seems that send-pr is not installed with your unique submitter-id. -You need to run - - install-sid YOUR-SID - -where YOUR-SID is the identification code you received with `send-pr'. -`send-pr' will automatically insert this value into the template field -`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net' -for this value. If you do not know your id, run `send-pr --request-id' to -get one from your support site. -__EOF__ - exit 1 -fi - -## if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then -## CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort` -## else -## echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list." -## exit 1 -## fi -CATEGORIES="contrib cvs doc pcl-cvs portability" - -if [ -z "$CATEGORIES" ]; then - echo "$COMMAND: the categories list for $GNATS_SITE was empty!" - exit 1 -fi - -case "$FORMAT" in - lisp) echo "$CATEGORIES" | \ - awk 'BEGIN {printf "( "} {printf "(\"%s\") ",$0} END {printf ")\n"}' - exit 0 - ;; - norm) l=`echo "$CATEGORIES" | \ - awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } } - END {print max + 1;}'` - c=`expr 70 / $l` - if [ $c -eq 0 ]; then c=1; fi - echo "$CATEGORIES" | \ - awk 'BEGIN {print "Known categories:"; i = 0 } - { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } } - END { print ""; }' - exit 0 - ;; -esac - -ORIGINATOR_C='<name of the PR author (one line)>' -ORGANIZATION_C='<organization of PR author (multiple lines)>' -CONFIDENTIAL_C='<[ yes | no ] (one line)>' -SYNOPSIS_C='<synopsis of the problem (one line)>' -SEVERITY_C='<[ non-critical | serious | critical ] (one line)>' -PRIORITY_C='<[ low | medium | high ] (one line)>' -CATEGORY_C='<name of the product (one line)>' -CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>' -RELEASE_C='<release number or tag (one line)>' -ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>' -DESCRIPTION_C='<precise description of the problem (multiple lines)>' -HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>' -FIX_C='<how to correct or work around the problem, if known (multiple lines)>' - -# Catch some signals. ($xs kludge needed by Sun /bin/sh) -xs=0 -trap 'rm -f $REF $TEMP; exit $xs' 0 -trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15 - -# If they told us to use a specific file, then do so. -if [ -n "$IN_FILE" ]; then - if [ "$IN_FILE" = "-" ]; then - # The PR is coming from the standard input. - if [ -n "$EXPLICIT_GNATS_ADDR" ]; then - sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP - else - cat > $TEMP - fi - else - # Use the file they named. - if [ -n "$EXPLICIT_GNATS_ADDR" ]; then - sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP - else - cat $IN_FILE > $TEMP - fi - fi -else - - if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then - # If their PR_FORM points to a bogus entry, then bail. - if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then - echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM" - sleep 1 - PRINT_INTERN=bad_prform - fi - fi - - if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then - cp $PR_FORM $TEMP || - ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit ) - else - for file in $TEMP $REF ; do - cat > $file << '__EOF__' -SEND-PR: -*- send-pr -*- -SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as -SEND-PR: will all comments (text enclosed in `<' and `>'). -SEND-PR: -SEND-PR: Choose from the following categories: -SEND-PR: -__EOF__ - - # Format the categories so they fit onto lines. - l=`echo "$CATEGORIES" | \ - awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } } - END {print max + 1;}'` - c=`expr 61 / $l` - if [ $c -eq 0 ]; then c=1; fi - echo "$CATEGORIES" | \ - awk 'BEGIN {printf "SEND-PR: "; i = 0 } - { printf ("%-'$l'.'$l's", $0); - if ((++i % '$c') == 0) { printf "\nSEND-PR: " } } - END { printf "\nSEND-PR:\n"; }' >> $file - - cat >> $file << __EOF__ -To: $GNATS_ADDR -Subject: -From: $FROM -Reply-To: $REPLY_TO -X-send-pr-version: $VERSION - - ->Submitter-Id: $SUBMITTER ->Originator: $ORIGINATOR ->Organization: -${ORGANIZATION-$ORGANIZATION_C} ->Confidential: $CONFIDENTIAL_C ->Synopsis: $SYNOPSIS_C ->Severity: $SEVERITY_C ->Priority: $PRIORITY_C ->Category: $CATEGORY_C ->Class: $CLASS_C ->Release: ${DEFAULT_RELEASE-$RELEASE_C} ->Environment: - $ENVIRONMENT_C -`[ -n "$SYSTEM" ] && echo System: $SYSTEM` -`[ -n "$ARCH" ] && echo Architecture: $ARCH` -`[ -n "$MACHINE" ] && echo Machine: $MACHINE` ->Description: - $DESCRIPTION_C ->How-To-Repeat: - $HOW_TO_REPEAT_C ->Fix: - $FIX_C -__EOF__ - done - fi - - if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then - cat $TEMP - xs=0; exit - fi - - chmod u+w $TEMP - if [ -z "$REQUEST_ID" ]; then - eval $EDIT $TEMP - else - ed -s $TEMP << '__EOF__' -/^Subject/s/^Subject:.*/Subject: request for a customer id/ -/^>Category/s/^>Category:.*/>Category: send-pr/ -w -q -__EOF__ - fi - - if cmp -s $REF $TEMP ; then - echo "$COMMAND: problem report not filled out, therefore not sent" - xs=1; exit - fi -fi - -# -# Check the enumeration fields - -# This is a "sed-subroutine" with one keyword parameter -# (with workaround for Sun sed bug) -# -SED_CMD=' -/$PATTERN/{ -s||| -s|<.*>|| -s|^[ ]*|| -s|[ ]*$|| -p -q -}' - - -while [ -z "$REQUEST_ID" ]; do - CNT=0 - - # 1) Confidential - # - PATTERN=">Confidential:" - CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$CONFIDENTIAL" in - ""|yes|no) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;; - esac - # - # 2) Severity - # - PATTERN=">Severity:" - SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$SEVERITY" in - ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'." - esac - # - # 3) Priority - # - PATTERN=">Priority:" - PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$PRIORITY" in - ""|low|medium|high) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'." - esac - # - # 4) Category - # - PATTERN=">Category:" - CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - FOUND= - for C in $CATEGORIES - do - if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi - done - if [ -n "$FOUND" ]; then - CNT=`expr $CNT + 1` - else - if [ -z "$CATEGORY" ]; then - echo "$COMMAND: you must include a Category: field in your report." - else - echo "$COMMAND: \`$CATEGORY' is not a known category." - fi - fi - # - # 5) Class - # - PATTERN=">Class:" - CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$CLASS" in - ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'." - esac - - [ $CNT -lt 5 -a -z "$BATCH" ] && - echo "Errors were found with the problem report." - - while true; do - if [ -z "$BATCH" ]; then - $ECHON1 "a)bort, e)dit or s)end? $ECHON2" - read input - else - if [ $CNT -eq 5 ]; then - input=s - else - input=a - fi - fi - case "$input" in - a*) - if [ -z "$BATCH" ]; then - echo "$COMMAND: the problem report remains in $BAD and is not sent." - mv $TEMP $BAD - else - echo "$COMMAND: the problem report is not sent." - fi - xs=1; exit - ;; - e*) - eval $EDIT $TEMP - continue 2 - ;; - s*) - break 2 - ;; - esac - done -done -# -# Remove comments and send the problem report -# (we have to use patterns, where the comment contains regex chars) -# -# /^>Originator:/s;$ORIGINATOR;; -sed -e " -/^SEND-PR:/d -/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;; -/^>Confidential:/s;<.*>;; -/^>Synopsis:/s;$SYNOPSIS_C;; -/^>Severity:/s;<.*>;; -/^>Priority:/s;<.*>;; -/^>Category:/s;$CATEGORY_C;; -/^>Class:/s;<.*>;; -/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;; -/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;; -/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;; -/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;; -/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;; -" $TEMP > $REF - -if $MAIL_AGENT < $REF; then - echo "$COMMAND: problem report sent" - xs=0; exit -else - echo "$COMMAND: mysterious mail failure." - if [ -z "$BATCH" ]; then - echo "$COMMAND: the problem report remains in $BAD and is not sent." - mv $REF $BAD - else - echo "$COMMAND: the problem report is not sent." - fi - xs=1; exit -fi diff --git a/gnu/usr.bin/cvs/cvsinit/Makefile b/gnu/usr.bin/cvs/cvsinit/Makefile deleted file mode 100644 index 7392114..0000000 --- a/gnu/usr.bin/cvs/cvsinit/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# $Id: Makefile,v 1.4 1995/12/11 01:58:53 peter Exp $ - -MAN8= cvsinit.8 - -EXAMPDIR= /usr/share/examples/cvs -CLEANFILES+= cvsinit ver - -.SUFFIXES: .sh - -all: cvsinit - -.sh: - echo > ver \ - cvs-`sed < ${.CURDIR}/../lib/version.c \ - -e '/version_string/!d' \ - -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \ - -e q` - sed -e 's,xLIBDIRx,$(EXAMPDIR),g' \ - -e "s,xVERSIONx,`cat ver`,g" ${.CURDIR}/$@.sh > $@ - -beforeinstall: - ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ - cvsinit ${DESTDIR}${BINDIR}/cvsinit - -.include "../../Makefile.inc" -.include <bsd.prog.mk> - diff --git a/gnu/usr.bin/cvs/cvsinit/cvsinit.8 b/gnu/usr.bin/cvs/cvsinit/cvsinit.8 deleted file mode 100644 index 1012d62..0000000 --- a/gnu/usr.bin/cvs/cvsinit/cvsinit.8 +++ /dev/null @@ -1,142 +0,0 @@ -.de Id -.ds Rv \\$4 -.ds Dt \\$5 -.. -.Id @(#)ccvs/man:$Name: $:$Id: cvsinit.8,v 1.2 1995/11/14 20:48:54 woods Exp $ -.TH CVSINIT 8 "\*(Dt" -.\" Full space in nroff; half space in troff -.de SP -.if n .sp -.if t .sp .5 -.. -.\" quoted command -.de ` -.RB ` "\|\\$1\|" '\\$2 -.. -.\" -.SH "NAME" -cvsinit \- Concurrent Versions System repository initialization script -.SH "SYNOPSIS" -.TP -.B cvsinit -.\" -.SH "DESCRIPTION" -.\" -The -.B cvsinit -script initializes a repository in the location specified by the -.SM CVSROOT -environment variable. -.SH "FILES" -For more detailed information on -.B cvs -supporting files, see -.BR cvs ( 5 ). -.LP -Files in source repositories (created by -.BR cvsinit ): -.TP -$CVSROOT/CVSROOT -Directory of global administrative files for repository. -.TP -$CVSROOT/commitinfo,v -Records programs for filtering -.` "cvs commit" -requests. -.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/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/log -Sample logging script for use in -.IR loginfo . -.TP -$CVSROOT/commit_prep -Sample logging script for use in -.I commitinfo -with the -.I log_accum -script -.TP -$CVSROOT/log_accum -Sample loggin script for use in -.I loginfo -with the -.I commit_prep -script -.\" -.SH "ENVIRONMENT VARIABLES" -.TP -.SM CVSROOT -Should contain the full pathname to the root of the -.B cvs -source repository (where the -.SM RCS -files are kept). This information must be available to \fBcvs\fP for -most commands to execute; if -.SM CVSROOT -is not set, or if you wish to override it for one invocation, you can -supply it on the command line: -.` "cvs \-d \fIcvsroot cvs_command\fP\|.\|.\|." -You may not need to set -.SM CVSROOT -if your \fBcvs\fP binary has the right path compiled in; use -.` "cvs \-v" -to display all compiled-in paths. -.\" -.SH "AUTHORS" -.TP -Dick Grune -Original author of the -.B cvs -shell script version posted to -.B comp.sources.unix -in the volume6 release of December, 1986. -Credited with much of the -.B cvs -conflict resolution algorithms. -.TP -Brian Berliner -Coder and designer of the -.B cvs -program itself in April, 1989, based on the original work done by Dick. -.TP -Jeff Polk -Helped Brian with the design of the -.B cvs -module and vendor branch support and author of the -.BR checkin ( 1 ) -shell script (the ancestor of -.` "cvs import"). -.SH "SEE ALSO" -.BR ci ( 1 ), -.BR co ( 1 ), -.BR cvs ( 5 ), -.BR diff ( 1 ), -.BR grep ( 1 ), -.BR mkmodules ( 1 ), -.BR patch ( 1 ), -.BR rcs ( 1 ), -.BR rcsdiff ( 1 ), -.BR rcsmerge ( 1 ), -.BR rlog ( 1 ), -.BR rm ( 1 ), -.BR sort ( 1 ). diff --git a/gnu/usr.bin/cvs/cvsinit/cvsinit.sh b/gnu/usr.bin/cvs/cvsinit/cvsinit.sh deleted file mode 100644 index 3fa58ad..0000000 --- a/gnu/usr.bin/cvs/cvsinit/cvsinit.sh +++ /dev/null @@ -1,162 +0,0 @@ -#! /bin/sh -: -# -#ident "@(#)cvs:$Name: $:$Id: cvsinit.sh,v 1.4 1995/12/10 23:06:51 peter 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. - -# 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" - -CVS_VERSION="xVERSIONx" - -# All purpose usage message, also suffices for --help and --version. -if test $# -gt 0; then - echo "cvsinit version $CVS_VERSION" - echo "usage: $0" - echo "(set CVSROOT to the repository that you want to initialize)" - exit 0 -fi - -# Make sure that the CVSROOT variable is set -if [ "x$CVSROOT" = x ]; then - echo "The CVSROOT environment variable is not set." - echo "" - echo "You should choose a location for your source repository" - echo "that can be shared by many developers. It also helps to" - echo "place the source repository on a file system that has" - echo "plenty of free space." - echo "" - echo "Please enter the full path for your CVSROOT source repository:" - read CVSROOT junk - unset junk - remind_cvsroot=yes -else - remind_cvsroot=no -fi - -# Now, create the $CVSROOT if it is not already there -if [ ! -d $CVSROOT ]; then - echo "Creating $CVSROOT..." - path= - for comp in `echo $CVSROOT | sed -e 's,/, ,g'`; do - path=$path/$comp - if [ ! -d $path ]; then - mkdir $path - fi - done -else - true -fi - -# Next, check for $CVSROOT/CVSROOT -if [ ! -d $CVSROOT/CVSROOT ]; then - if [ -d $CVSROOT/CVSROOT.adm ]; then - echo "You have the old $CVSROOT/CVSROOT.adm directory." - echo "I will rename it to $CVSROOT/CVSROOT for you..." - mv $CVSROOT/CVSROOT.adm $CVSROOT/CVSROOT - else - echo "Creating the $CVSROOT/CVSROOT directory..." - mkdir $CVSROOT/CVSROOT - fi -else - true -fi -if [ ! -d $CVSROOT/CVSROOT ]; then - echo "Unable to create $CVSROOT/CVSROOT." - echo "I give up." - exit 1 -fi - -# Create the special control files and templates within $CVSROOT/CVSROOT - -EXAMPLES="checkoutlist commitinfo cvswrappers editinfo loginfo modules -rcsinfo rcstemplate taginfo wrap unwrap" - -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" - echo " from $CVSROOT/CVSROOT/${info},v..." - (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 sample $CVSROOT/CVSROOT/$info file..." - case $info in - modules) - sed -n -e '/END_REQUIRED_CONTENT/q' \ - -e p $CVSLIB/examples/modules | \ - sed -e 's@/usr/local/bin@/usr/bin@' > $CVSROOT/CVSROOT/modules - ;; - rcstemplate) - cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info - ;; - wrap|unwrap) - cp $CVSLIB/examples/$info $CVSROOT/CVSROOT/$info - chmod +x $CVSROOT/CVSROOT/$info - ;; - *) - # comment out everything in all the other examples.... - sed -e 's/^\([^#]\)/#\1/' $CVSLIB/examples/$info > $CVSROOT/CVSROOT/$info - ;; - esac - fi - (cd $CVSROOT/CVSROOT; ci -q -u -t/dev/null -m"initial checkin of $info" $info) - 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" - echo " contains references to the old CVSROOT.adm directory" - echo " You should really change these to the new CVSROOT directory" - echo "" -fi - -# These files are generated from the contrib files. -# 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 -done - -# XXX - also add a stub for the cvsignore file - -# Turn on history logging by default -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 -echo "All done! Running 'mkmodules' as my final step..." -mkmodules $CVSROOT/CVSROOT - -exit 0 diff --git a/gnu/usr.bin/cvs/doc/Makefile b/gnu/usr.bin/cvs/doc/Makefile index 874cc46..a479fe9 100644 --- a/gnu/usr.bin/cvs/doc/Makefile +++ b/gnu/usr.bin/cvs/doc/Makefile @@ -1,5 +1,21 @@ -# $Id$ +# $Id: Makefile,v 1.2 1995/12/10 23:07:16 peter Exp $ -INFO = cvs cvsclient +.include "${.CURDIR}/../Makefile.inc" + +.PATH: ${CVSDIR}/doc + +MAKEINFOFLAGS+= -I ${CVSDIR}/doc + +INFO= cvs cvsclient + +cvs.texinfo cvsclient.texi: CVSvn.texi + +CLEANFILES+= CVSvn.texi + +CVSvn.texi: ${CVSDIR}/src/version.c + echo "@set CVSVN `sed < ${CVSDIR}/src/version.c \ + -e '/version_string/!d' \ + -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \ + -e q`" > $@ .include <bsd.info.mk> diff --git a/gnu/usr.bin/cvs/doc/cvs-paper.ms b/gnu/usr.bin/cvs/doc/cvs-paper.ms deleted file mode 100644 index 567179b..0000000 --- a/gnu/usr.bin/cvs/doc/cvs-paper.ms +++ /dev/null @@ -1,1073 +0,0 @@ -.\" soelim cvs.ms | pic | tbl | troff -ms -.\" @(#)cvs.ms 1.2 92/01/30 -.\" -.\" troff source to the cvs USENIX article, Winter 1990, Washington, D.C. -.\" Copyright (c) 1989, Brian Berliner -.\" -.\" 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. -.\" -.\" The author can be reached at: berliner@prisma.com -.\" -.de SP -.if n .sp -.if t .sp .5 -.. -.de hl -.br -.in +0.5i -\l'\\n(LLu-1i' -.in -0.5i -.sp -.. -.OH "" -.nr PS 11 -.nr PO 1.25i -.pl -0.2i -.TL -.ps 14 -.ft B -.nf -CVS II: -Parallelizing Software Development -.fi -.ft -.ps -.AU -.ps 12 -.ft I -Brian Berliner -.ft -.ps -.AI -.ps 12 -.ft I -Prisma, Inc. -5465 Mark Dabling Blvd. -Colorado Springs, CO 80918 -berliner@prisma.com -.ft -.ps -.AB -The program described in this paper fills a need in the UNIX -community for a freely available tool to manage software revision and -release control in a multi-developer, multi-directory, multi-group -environment. -This tool also addresses the increasing need for tracking third-party vendor -source distributions while trying to maintain local modifications to -earlier releases. -.AE -.NH -Background -.PP -In large software development projects, it is usually necessary for more -than one software developer to be modifying (usually different) modules of the -code at the same time. -Some of these code modifications are done in an -experimental sense, at least until the code functions correctly, and some -testing of the entire program is usually necessary. -Then, the modifications are returned to a master source repository -so that others in the project can -enjoy the new bug-fix or functionality. -In order to manage such a project, some sort of revision control system is -necessary. -.PP -Specifically, UNIX\** -.FS -UNIX is a registered trademark of AT&T. -.FE -kernel development is an excellent example of the -problems that an adequate revision control system must address. -The SunOS\** -.FS -SunOS is a trademark of Sun Microsystems, Inc. -.FE -kernel is composed of over a thousand files spread across a -hierarchy of dozens of directories.\** -.FS -Yes, the SunOS 4.0 kernel is composed of over a \fIthousand\fP files! -.FE -Pieces of the kernel must be edited -by many software developers within an organization. -While undesirable in -theory, it is not uncommon to have two or more people making -modifications to the same file within the kernel sources in -order to facilitate a desired change. -Existing revision control systems like -.SM -RCS -.LG -[Tichy] or -.SM -SCCS -.LG -[Bell] serialize file modifications by -allowing only one developer to have a writable copy of a particular file at -any one point in time. -That developer is said to -have \*Qlocked\*U the file for his exclusive use, and no other developer is -allowed to check out a writable copy of the file until the locking -developer has finished impeding others' productivity. -Development pressures of productivity and deadlines -often force organizations to require that multiple developers be able to -simultaneously edit -copies of the same revision controlled file. -.PP -The necessity for multiple developers to modify the same file concurrently -questions the value of serialization-based policies in traditional revision -control. -This paper discusses the approach that -Prisma took in adapting a standard revision control system, -.SM -RCS\c -.LG -, along with an existing public-domain collection of shell scripts that sits -atop -.SM -RCS -.LG -and provides the basic conflict-resolution algorithms. -The resulting -program, \fBcvs\fP, addresses not only the issue of conflict-resolution in -a multi-developer open-editing environment, but also the issues of -software release control and vendor source support and integration. -.NH -The CVS Program -.PP -\fBcvs\fP -(Concurrent Versions System) -is a front end to the -.SM -RCS -.LG -revision control system which extends -the notion of revision control from a collection of files in a single -directory to a hierarchical collection of directories each containing -revision controlled files. -Directories and files in the \fBcvs\fP system can be combined together in -many ways to form a software release. -\fBcvs\fP -provides the functions necessary to manage these software releases and to -control the concurrent editing of source files among multiple software -developers. -.PP -The six major features of \fBcvs\fP are listed below, and will be -described in more detail in the following sections: -.RS -.IP 1. -Concurrent access and conflict-resolution algorithms to guarantee that -source changes are not \*Qlost.\*U -.IP 2. -Support for tracking third-party vendor source distributions while -maintaining the local modifications made to those sources. -.IP 3. -A flexible module database that provides a symbolic mapping of names to -components of a larger software distribution. -This symbolic mapping provides for location independence within the software -release and, for example, allows one to check out a copy of the \*Qdiff\*U -program without ever knowing that the sources to \*Qdiff\*U actually reside -in the \*Qbin/diff\*U directory. -.IP 4. -Configurable logging support allows all \*Qcommitted\*U source file changes -to be logged using an arbitrary program to save the log messages in a file, -notesfile, or news database. -.IP 5. -A software release can be symbolically tagged and checked out at any time -based on that tag. -An exact copy of a previous software release can be checked out at -any time, \fIregardless\fP of whether files or directories have been -added/removed from the \*Qcurrent\*U software release. -As well, -a \*Qdate\*U can be used to check out the \fIexact\fP version of the software -release as of the specified date. -.IP 6. -A \*Qpatch\*U format file [Wall] can be produced between two software -releases, even if the releases span multiple directories. -.RE -.PP -The sources maintained by \fBcvs\fP are kept within a single directory -hierarchy known as the \*Qsource repository.\*U -This \*Qsource repository\*U holds the actual -.SM -RCS -.LG -\*Q,v\*U files directly, as well as a special per-repository directory -(\c -.SM -CVSROOT.adm\c -.LG -) which contains a small number of administrative files that describe the -repository and how it can be accessed. -See Figure 1 for a picture of the \fBcvs\fP tree. -.KF -.hl -.DS B -.PS -line from 4.112,9.200 to 5.550,8.887 -line from 5.447,8.884 to 5.550,8.887 to 5.458,8.933 -line from 4.112,9.200 to 4.550,8.950 -line from 4.451,8.978 to 4.550,8.950 to 4.476,9.021 -line from 4.112,9.200 to 3.737,8.887 -line from 3.798,8.971 to 3.737,8.887 to 3.830,8.932 -line from 3.612,8.762 to 4.737,8.137 -line from 4.638,8.164 to 4.737,8.137 to 4.662,8.208 -line from 3.612,8.762 to 3.737,8.137 -line from 3.693,8.231 to 3.737,8.137 to 3.742,8.240 -line from 3.612,8.762 to 2.612,8.200 -line from 2.687,8.271 to 2.612,8.200 to 2.712,8.227 -line from 2.362,9.262 to 2.737,8.950 -line from 2.645,8.995 to 2.737,8.950 to 2.677,9.033 -line from 2.362,9.262 to 1.925,8.950 -line from 1.992,9.028 to 1.925,8.950 to 2.021,8.988 -line from 3.362,9.762 to 4.050,9.387 -line from 3.950,9.413 to 4.050,9.387 to 3.974,9.457 -line from 3.362,9.762 to 2.487,9.387 -line from 2.570,9.450 to 2.487,9.387 to 2.589,9.404 -.ps 11 -"newfs.c,v" at 4.487,8.043 ljust -.ps 11 -"mkfs.c,v" at 3.487,8.043 ljust -.ps 11 -"Makefile,v" at 2.237,8.043 ljust -.ps 11 -"newfs" at 3.487,8.793 ljust -.ps 11 -"halt.c,v" at 5.487,8.793 ljust -.ps 11 -"Makefile,v" at 4.237,8.793 ljust -.ps 11 -"modules,v" at 2.487,8.793 ljust -.ps 11 -"loginfo,v" at 1.488,8.793 ljust -.ps 11 -"etc" at 3.987,9.293 ljust -.ps 11 -"CVSROOT.adm" at 1.988,9.293 ljust -.ps 11 -"/src/master" at 2.987,9.793 ljust -.PE -.DE -.hl -.ce 100 -.LG -\fBFigure 1.\fP -.SM -\fBcvs\fP Source Repository -.ce 0 -.sp -.KE -.NH 2 -Software Conflict Resolution\** -.FS -The basic conflict-resolution algorithms -used in the \fBcvs\fP program find their roots -in the original work done by Dick Grune at Vrije Universiteit in Amsterdam -and posted to \fBcomp.sources.unix\fP in the volume 6 release sometime in 1986. -This original version of \fBcvs\fP was a collection of shell scripts that -combined to form a front end to the -.SM -RCS -.LG -programs. -.FE -.PP -\fBcvs\fP allows several software developers to edit personal copies of a -revision controlled file concurrently. -The revision number of each checked out file is maintained independently -for each user, and \fBcvs\fP forces the checked out file to be current with -the \*Qhead\*U revision before it can be \*Qcommitted\*U as a permanent change. -A checked out file is brought up-to-date with the \*Qhead\*U revision using -the \*Qupdate\*U command of \fBcvs\fP. -This command compares the \*Qhead\*U revision number with that of the user's -file and performs an -.SM -RCS -.LG -merge operation if they are not the same. -The result of the merge is a file that contains the user's modifications -and those modifications that were \*Qcommitted\*U after the user -checked out his version of the file (as well as a backup copy of the -user's original file). -\fBcvs\fP points out any conflicts during the merge. -It is the user's responsibility to resolve these conflicts -and to \*Qcommit\*U his/her changes when ready. -.PP -Although the \fBcvs\fP conflict-resolution algorithm was defined in 1986, -it is remarkably similar to the \*QCopy-Modify-Merge\*U scenario included -with NSE\** -.FS -NSE is the Network Software Environment, a product of Sun Microsystems, Inc. -.FE -and described in [Honda] and [Courington]. -The following explanation from [Honda] also applies to \fBcvs\fP: -.QP -Simply stated, a developer copies an object without locking it, modifies -the copy, and then merges the modified copy with the original. -This paradigm allows developers to work in isolation from one another since -changes are made to copies of objects. -Because locks are not used, development is not serialized and can proceed -in parallel. -Developers, however, must merge objects after the changes have been made. -In particular, a developer must resolve conflicts when the same object has -been modified by someone else. -.PP -In practice, Prisma has found that conflicts that occur when the same -object has been modified by someone else are quite rare. -When they do happen, the changes made by the other developer are usually -easily resolved. -This practical use has shown that the \*QCopy-Modify-Merge\*U paradigm is a -correct and useful one. -.NH 2 -Tracking Third-Party Source Distributions -.PP -Currently, a large amount of software is based on source -distributions from a third-party distributor. -It is often the case that local modifications are to be made to this -distribution, \fIand\fP that the vendor's future releases should be -tracked. -Rolling your local modifications forward into the new vendor release is a -time-consuming task, but \fBcvs\fP can ease this burden somewhat. -The \fBcheckin\fP program of \fBcvs\fP initially sets up a source -repository by integrating the source modules directly from the vendor's -release, preserving the directory hierarchy of the vendor's distribution. -The branch support of -.SM -RCS -.LG -is used to build this vendor release as a branch of the main -.SM -RCS -.LG -trunk. -Figure 2 shows how the \*Qhead\*U tracks a sample vendor -branch when no local modifications have been made to the file. -.KF -.hl -.DS B -.PS -ellipse at 3.237,6.763 wid 1.000 ht 0.500 -dashwid = 0.050i -line dashed from 3.237,7.513 to 3.737,7.513 to 3.737,9.762 to 4.237,9.762 -line from 4.138,9.737 to 4.237,9.762 to 4.138,9.787 -line dashed from 2.237,8.262 to 3.237,8.262 to 3.237,7.013 -line from 3.212,7.112 to 3.237,7.013 to 3.262,7.112 -line from 3.737,6.763 to 4.237,6.763 -line from 4.138,6.737 to 4.237,6.763 to 4.138,6.788 -line from 2.237,6.763 to 2.737,6.763 -line from 2.637,6.737 to 2.737,6.763 to 2.637,6.788 -line from 1.738,6.013 to 1.738,6.513 -line from 1.762,6.413 to 1.738,6.513 to 1.713,6.413 -line from 1.238,7.013 to 2.237,7.013 to 2.237,6.513 to 1.238,6.513 to 1.238,7.013 -line from 4.237,9.012 to 5.237,9.012 to 5.237,8.512 to 4.237,8.512 to 4.237,9.012 -line from 4.237,8.012 to 5.237,8.012 to 5.237,7.513 to 4.237,7.513 to 4.237,8.012 -line from 4.237,7.013 to 5.237,7.013 to 5.237,6.513 to 4.237,6.513 to 4.237,7.013 -line from 4.737,7.013 to 4.737,7.513 -line from 4.763,7.413 to 4.737,7.513 to 4.712,7.413 -line from 4.737,8.012 to 4.737,8.512 -line from 4.763,8.412 to 4.737,8.512 to 4.712,8.412 -line from 4.237,10.012 to 5.237,10.012 to 5.237,9.512 to 4.237,9.512 to 4.237,10.012 -line from 4.737,9.012 to 4.737,9.512 -line from 4.763,9.412 to 4.737,9.512 to 4.712,9.412 -line from 5.987,5.013 to 5.987,6.013 to 0.988,6.013 to 0.988,5.013 to 5.987,5.013 -.ps 11 -"\"HEAD\"" at 1.550,8.231 ljust -.ps 11 -"'SunOS'" at 2.987,6.293 ljust -.ps 11 -"1.1.1" at 3.050,6.793 ljust -.ps 11 -"1.1" at 1.613,6.793 ljust -.ps 11 -"1.1.1.1" at 4.487,6.793 ljust -.ps 11 -"1.1.1.2" at 4.487,7.793 ljust -.ps 11 -"1.1.1.3" at 4.487,8.793 ljust -.ps 11 -"1.1.1.4" at 4.487,9.793 ljust -.ps 11 -"'SunOS_4_0'" at 5.487,6.793 ljust -.ps 11 -"'SunOS_4_0_1'" at 5.487,7.793 ljust -.ps 11 -"'YAPT_5_5C'" at 5.487,8.793 ljust -.ps 11 -"'SunOS_4_0_3'" at 5.487,9.793 ljust -.ps 11 -"rcsfile.c,v" at 2.987,5.543 ljust -.PE -.DE -.hl -.ce 100 -.LG -\fBFigure 2.\fP -.SM -\fBcvs\fP Vendor Branch Example -.ce 0 -.sp .3 -.KE -Once this is done, developers can check out files and make local changes to -the vendor's source distribution. -These local changes form a new branch to the tree which is then used as the -source for future check outs. -Figure 3 shows how the \*Qhead\*U moves to the main -.SM -RCS -.LG -trunk when a local modification is made. -.KF -.hl -.DS B -.PS -ellipse at 3.237,6.763 wid 1.000 ht 0.500 -dashwid = 0.050i -line dashed from 2.800,9.075 to 1.738,9.075 to 1.738,8.012 -line from 1.713,8.112 to 1.738,8.012 to 1.762,8.112 -line from 1.738,7.013 to 1.738,7.513 -line from 1.762,7.413 to 1.738,7.513 to 1.713,7.413 -line from 1.238,8.012 to 2.237,8.012 to 2.237,7.513 to 1.238,7.513 to 1.238,8.012 -line from 3.737,6.763 to 4.237,6.763 -line from 4.138,6.737 to 4.237,6.763 to 4.138,6.788 -line from 2.237,6.763 to 2.737,6.763 -line from 2.637,6.737 to 2.737,6.763 to 2.637,6.788 -line from 1.738,6.013 to 1.738,6.513 -line from 1.762,6.413 to 1.738,6.513 to 1.713,6.413 -line from 1.238,7.013 to 2.237,7.013 to 2.237,6.513 to 1.238,6.513 to 1.238,7.013 -line from 4.237,9.012 to 5.237,9.012 to 5.237,8.512 to 4.237,8.512 to 4.237,9.012 -line from 4.237,8.012 to 5.237,8.012 to 5.237,7.513 to 4.237,7.513 to 4.237,8.012 -line from 4.237,7.013 to 5.237,7.013 to 5.237,6.513 to 4.237,6.513 to 4.237,7.013 -line from 4.737,7.013 to 4.737,7.513 -line from 4.763,7.413 to 4.737,7.513 to 4.712,7.413 -line from 4.737,8.012 to 4.737,8.512 -line from 4.763,8.412 to 4.737,8.512 to 4.712,8.412 -line from 4.237,10.012 to 5.237,10.012 to 5.237,9.512 to 4.237,9.512 to 4.237,10.012 -line from 4.737,9.012 to 4.737,9.512 -line from 4.763,9.412 to 4.737,9.512 to 4.712,9.412 -line from 5.987,5.013 to 5.987,6.013 to 0.988,6.013 to 0.988,5.013 to 5.987,5.013 -.ps 11 -"1.2" at 1.613,7.793 ljust -.ps 11 -"\"HEAD\"" at 2.862,9.043 ljust -.ps 11 -"'SunOS'" at 2.987,6.293 ljust -.ps 11 -"1.1.1" at 3.050,6.793 ljust -.ps 11 -"1.1" at 1.613,6.793 ljust -.ps 11 -"1.1.1.1" at 4.487,6.793 ljust -.ps 11 -"1.1.1.2" at 4.487,7.793 ljust -.ps 11 -"1.1.1.3" at 4.487,8.793 ljust -.ps 11 -"1.1.1.4" at 4.487,9.793 ljust -.ps 11 -"'SunOS_4_0'" at 5.487,6.793 ljust -.ps 11 -"'SunOS_4_0_1'" at 5.487,7.793 ljust -.ps 11 -"'YAPT_5_5C'" at 5.487,8.793 ljust -.ps 11 -"'SunOS_4_0_3'" at 5.487,9.793 ljust -.ps 11 -"rcsfile.c,v" at 2.987,5.543 ljust -.PE -.DE -.hl -.ce 100 -.LG -\fBFigure 3.\fP -.SM -\fBcvs\fP Local Modification to Vendor Branch -.ce 0 -.sp -.KE -.PP -When a new version of the vendor's source distribution arrives, the -\fBcheckin\fP program adds the new and changed vendor's files to the -already existing source repository. -For files that have not been changed locally, the new file from the -vendor becomes the current \*Qhead\*U revision. -For files that have been modified locally, \fBcheckin\fP warns that the -file must be merged with the new vendor release. -The \fBcvs\fP \*Qjoin\*U command is a useful tool that aids this process by -performing the necessary -.SM -RCS -.LG -merge, as is done above when performing an \*Qupdate.\*U -.PP -There is also limited support for \*Qdual\*U derivations for source files. -See Figure 4 for a sample dual-derived file. -.KF -.hl -.DS B -.PS -ellipse at 2.337,8.575 wid 0.700 ht 0.375 -ellipse at 2.312,9.137 wid 0.700 ht 0.375 -line from 1.225,9.012 to 1.225,9.363 -line from 1.250,9.263 to 1.225,9.363 to 1.200,9.263 -line from 0.875,9.725 to 1.600,9.725 to 1.600,9.363 to 0.875,9.363 to 0.875,9.725 -line from 0.875,9.012 to 1.600,9.012 to 1.600,8.650 to 0.875,8.650 to 0.875,9.012 -line from 4.050,10.200 to 4.775,10.200 to 4.775,9.850 to 4.050,9.850 to 4.050,10.200 -line from 4.050,9.475 to 4.775,9.475 to 4.775,9.113 to 4.050,9.113 to 4.050,9.475 -line from 4.050,8.762 to 4.775,8.762 to 4.775,8.400 to 4.050,8.400 to 4.050,8.762 -line from 4.425,8.762 to 4.425,9.113 -line from 4.450,9.013 to 4.425,9.113 to 4.400,9.013 -line from 4.425,9.475 to 4.425,9.850 -line from 4.450,9.750 to 4.425,9.850 to 4.400,9.750 -line from 3.050,10.000 to 3.775,10.000 to 3.775,9.637 to 3.050,9.637 to 3.050,10.000 -line from 3.050,9.312 to 3.775,9.312 to 3.775,8.950 to 3.050,8.950 to 3.050,9.312 -line from 0.713,7.325 to 0.713,8.075 to 4.925,8.075 to 4.925,7.325 to 0.713,7.325 -line from 1.238,8.075 to 1.238,8.637 -line from 1.262,8.537 to 1.238,8.637 to 1.213,8.537 -line from 1.613,8.825 to 1.975,8.575 -line from 1.878,8.611 to 1.975,8.575 to 1.907,8.652 -line from 2.675,8.575 to 4.050,8.575 -line from 3.950,8.550 to 4.050,8.575 to 3.950,8.600 -line from 2.675,9.137 to 3.050,9.137 -line from 2.950,9.112 to 3.050,9.137 to 2.950,9.162 -line from 3.425,9.325 to 3.425,9.637 -line from 3.450,9.537 to 3.425,9.637 to 3.400,9.537 -line from 1.613,8.825 to 1.925,9.137 -line from 1.872,9.049 to 1.925,9.137 to 1.837,9.084 -.ps 11 -"'BSD'" at 2.138,9.481 ljust -.ps 11 -"1.2" at 1.113,9.543 ljust -.ps 11 -"1.1" at 1.125,8.831 ljust -.ps 11 -"1.1.1.1" at 4.175,8.543 ljust -.ps 11 -"1.1.1.2" at 4.175,9.281 ljust -.ps 11 -"1.1.1.3" at 4.175,9.993 ljust -.ps 11 -"1.1.2.2" at 3.175,9.793 ljust -.ps 11 -"1.1.2.1" at 3.175,9.106 ljust -.ps 11 -"rcsfile.c,v" at 2.425,7.706 ljust -.ps 11 -"1.1.1" at 2.175,8.568 ljust -.ps 11 -"'SunOS'" at 2.125,8.243 ljust -.ps 11 -"1.1.2" at 2.163,9.131 ljust -.PE -.DE -.hl -.ce 100 -.LG -\fBFigure 4.\fP -.SM -\fBcvs\fP Support For \*QDual\*U Derivations -.ce 0 -.sp -.KE -This example tracks the SunOS distribution but includes major changes from -Berkeley. -These BSD files are saved directly in the -.SM -RCS -.LG -file off a new branch. -.NH 2 -Location Independent Module Database -.PP -\fBcvs\fP contains support for a simple, yet powerful, \*Qmodule\*U database. -For reasons of efficiency, this database is stored in \fBndbm\fP\|(3) format. -The module database is used to apply names to collections of directories -and files as a matter of convenience for checking out pieces of a large -software distribution. -The database records the physical location of the sources as a form of -information hiding, allowing one to check out whole directory hierarchies -or individual files without regard for their actual location within the -global source distribution. -.PP -Consider the following small sample of a module database, which must be -tailored manually to each specific source repository environment: -.DS -\f(CW #key [-option argument] directory [files...] - diff bin/diff - libc lib/libc - sys -o sys/tools/make_links sys - modules -i mkmodules CVSROOT.adm modules - kernel -a sys lang/adb - ps bin Makefile ps.c\fP -.DE -.PP -The \*Qdiff\*U and \*Qlibc\*U modules refer to whole directory hierarchies that -are extracted on check out. -The \*Qsys\*U module extracts the \*Qsys\*U hierarchy, and runs the -\*Qmake_links\*U program at the end of the check out process (the \fI-o\fP -option specifies a program to run on check\fIo\fPut). -The \*Qmodules\*U module allows one to edit the module database file and -runs the \*Qmkmodules\*U program on check\fIi\fPn to regenerate the -\fBndbm\fP database that \fBcvs\fP uses. -The \*Qkernel\*U module is an alias (as the \fI-a\fP option specifies) -which causes the remaining arguments after the \fI-a\fP to be interpreted -exactly as if they had been specified on the command line. -This is useful for objects that require shared pieces of code from far away -places to be compiled (as is the case with the kernel debugger, \fBkadb\fP, -which shares code with the standard \fBadb\fP debugger). -The \*Qps\*U module shows that the source for \*Qps\*U lives in the \*Qbin\*U -directory, but only \fIMakefile\fP and \fIps.c\fP are required to build the -object. -.PP -The module database at Prisma is now populated for the entire UNIX -distribution and thereby allows us to issue the -following convenient commands to check out components of the UNIX -distribution without regard for their actual location within the master source -repository: -.DS -\f(CW example% cvs checkout diff - example% cvs checkout libc ps - example% cd diff; make\fP -.DE -.PP -In building the module database file, it is quite possible to have name -conflicts within a global software distribution. -For example, SunOS provides two \fBcat\fP programs: -one for the standard environment, \fI/bin/cat\fP, and one for the System V -environment, \fI/usr/5bin/cat\fP. -We resolved this conflict by naming the standard \fBcat\fP module -\*Qcat\*U, and the System V \fBcat\fP module \*Q5cat\*U. -Similar name modifications must be applied to other conflicting names, as -might be found between a utility program and a library function, though -Prisma chose not to include individual library functions within the module -database at this time. -.NH 2 -Configurable Logging Support -.PP -The \fBcvs\fP \*Qcommit\*U command is used to make a permanent change to the -master source repository (where the -.SM -RCS -.LG -\*Q,v\*U files live). -Whenever a \*Qcommit\*U is done, the log message for the change is carefully -logged by an arbitrary program (in a file, notesfile, news database, or -mail). -For example, a collection of these updates can be used to produce release -notices. -\fBcvs\fP can be configured to send log updates through one or more filter -programs, based on a regular expression match on the directory that is -being changed. -This allows multiple related or unrelated projects to exist within a single -\fBcvs\fP source repository tree, with each different project sending its -\*Qcommit\*U reports to a unique log device. -.PP -A sample logging configuration file might look as follows: -.DS -\f(CW #regex filter-program - DEFAULT /usr/local/bin/nfpipe -t %s utils.updates - ^diag /usr/local/bin/nfpipe -t %s diag.updates - ^local /usr/local/bin/nfpipe -t %s local.updates - ^perf /usr/local/bin/nfpipe -t %s perf.updates - ^sys /usr/local/bin/nfpipe -t %s kernel.updates\fP -.DE -.PP -This sample allows the diagnostics and performance groups to -share the same source repository with the kernel and utilities groups. -Changes that they make are sent directly to their own notesfile [Essick] -through the \*Qnfpipe\*U program. -A sufficiently simple title is substituted for the \*Q%s\*U argument before -the filter program is executed. -This logging configuration file is tailored manually to each specific -source repository environment. -.NH 2 -Tagged Releases and Dates -.PP -Any release can be given a symbolic tag name that is stored directly in the -.SM -RCS -.LG -files. -This tag can be used at any time to get an exact copy of any previous -release. -With equal ease, one can also extract an exact copy of the source files as -of any arbitrary date in the past as well. -Thus, all that's required to tag the current kernel, and to tag the kernel -as of the Fourth of July is: -.DS -\f(CW example% cvs tag TEST_KERNEL kernel - example% cvs tag -D 'July 4' PATRIOTIC_KERNEL kernel\fP -.DE -The following command would retrieve an exact copy of the test kernel at -some later date: -.DS -\f(CW example% cvs checkout -fp -rTEST_KERNEL kernel\fP -.DE -The \fI-f\fP option causes only files that match the specified tag to be -extracted, while the \fI-p\fP option automatically prunes empty directories. -Consequently, directories added to the kernel after the test kernel was -tagged are not included in the newly extracted copy of the test kernel. -.PP -The \fBcvs\fP date support has exactly the same interface as that provided -with -.SM -RCS\c -.LG -, however \fBcvs\fP must process the \*Q,v\*U files directly due to the -special handling required by the vendor branch support. -The standard -.SM -RCS -.LG -date handling only processes one branch (or the main trunk) when checking -out based on a date specification. -\fBcvs\fP must instead process the current \*Qhead\*U branch and, if a -match is not found, proceed to look for a match on the vendor branch. -This, combined with reasons of performance, is why \fBcvs\fP processes -revision (symbolic and numeric) and date specifications directly from the -\*Q,v\*U files. -.NH 2 -Building \*Qpatch\*U Source Distributions -.PP -\fBcvs\fP can produce a \*Qpatch\*U format [Wall] output file which can be -used to bring a previously released software distribution current with the -newest release. -This patch file supports an entire directory hierarchy within a single -patch, as well as being able to add whole new files to the previous -release. -One can combine symbolic revisions and dates together to display changes in -a very generic way: -.DS -\f(CW example% cvs patch -D 'December 1, 1988' \e - -D 'January 1, 1989' sys\fP -.DE -This example displays the kernel changes made in the month of December, -1988. -To release a patch file, for example, to take the \fBcvs\fP distribution -from version 1.0 to version 1.4 might be done as follows: -.DS -\f(CW example% cvs patch -rCVS_1_0 -rCVS_1_4 cvs\fP -.DE -.NH -CVS Experience -.NH 2 -Statistics -.PP -A quick summary of the scale that \fBcvs\fP is addressing today -can be found in Table 1. -.KF -.TS -box center tab(:); -c s -c s -c | c -l | n . -\fB\s+2Revision Control Statistics at Prisma -as of 11/11/89\fP\s-2 -_ -How Many...:Total -= -Files:17243 -Directories:1005 -Lines of code:3927255 -Removed files:131 -Software developers:14 -Software groups:6 -Megabytes of source:128 -.TE -.ce 100 -.LG -\fBTable 1.\fP -.SM -\fBcvs\fP Statistics -.ce 0 -.sp .3 -.KE -Table 2 shows the history of files changed or added and the number -of source lines affected by the change at Prisma. -Only changes made to the kernel sources are included. -.KF -.TS -box center tab(:); -c s s s s -c s s s s -c || c | c || c | c -c || c | c || c | c -l || n | n || n | n. -\fB\s+2Prisma Kernel Source File Changes -By Month, 1988-1989\fP\s-2 -_ -Month:# Changed:# Lines:# Added:# Lines -\^:Files:Changed:Files:Added -= -Dec:87:3619:68:9266 -Jan:39:4324:0:0 -Feb:73:1578:5:3550 -Mar:99:5301:18:11461 -Apr:112:7333:11:5759 -May:138:5371:17:13986 -Jun:65:2261:27:12875 -Jul:34:2000:1:58 -Aug:65:6378:8:4724 -Sep:266:23410:113:39965 -Oct:22:621:1:155 -Total:1000:62196:269:101799 -.TE -.ce 100 -.LG -\fBTable 2.\fP -.SM -\fBcvs\fP Usage History for the Kernel -.ce 0 -.sp -.KE -The large number of source file changes made in September are the result of -merging the SunOS 4.0.3 sources into the kernel. -This merge process is described in section 3.3. -.NH 2 -Performance -.PP -The performance of \fBcvs\fP is currently quite reasonable. -Little effort has been expended on tuning \fBcvs\fP, although performance -related decisions were made during the \fBcvs\fP design. -For example, \fBcvs\fP parses the -.SM -RCS -.LG -\*Q,v\*U files directly instead of running an -.SM -RCS -.LG -process. -This includes following branches as well as integrating with the vendor -source branches and the main trunk when checking out files based on a date. -.PP -Checking out the entire kernel source tree (1223 files/59 directories) -currently takes 16 wall clock minutes on a Sun-4/280. -However, bringing the tree up-to-date with the current kernel sources, once -it has been checked out, takes only 1.5 wall clock minutes. -Updating the \fIcomplete\fP 128 MByte source tree under \fBcvs\fP control -(17243 files/1005 directories) takes roughly 28 wall clock minutes and -utilizes one-third of the machine. -For now this is entirely acceptable; improvements on these numbers will -possibly be made in the future. -.NH 2 -The SunOS 4.0.3 Merge -.PP -The true test of the \fBcvs\fP vendor branch support came with the arrival -of the SunOS 4.0.3 source upgrade tape. -As described above, the \fBcheckin\fP program was used to install the new -sources and the resulting output file listed the files that had been -locally modified, needing to be merged manually. -For the kernel, there were 94 files in conflict. -The \fBcvs\fP \*Qjoin\*U command was used on each of the 94 conflicting -files, and the remaining conflicts were resolved. -.PP -The \*Qjoin\*U command performs an \fBrcsmerge\fP operation. -This in turn uses \fI/usr/lib/diff3\fP to produce a three-way diff file. -As it happens, the \fBdiff3\fP program has a hard-coded limit of 200 -source-file changes maximum. -This proved to be too small for a few of the kernel files that needed -merging by hand, due to the large number of local changes that Prisma had -made. -The \fBdiff3\fP problem was solved by increasing the hard-coded limit by an -order of magnitude. -.PP -The SunOS 4.0.3 kernel source upgrade distribution contained -346 files, 233 of which were modifications to previously released files, -and 113 of which were newly added files. -\fBcheckin\fP added the 113 new files to the source repository -without intervention. -Of the 233 modified files, 139 dropped in cleanly by \fBcheckin\fP, since -Prisma had not made any local changes to them, and 94 required manual -merging due to local modifications. -The 233 modified files consisted of 20,766 lines of differences. -It took one developer two days to manually merge the 94 files using the -\*Qjoin\*U command and resolving conflicts manually. -An additional day was required for kernel debugging. -The entire process of merging over 20,000 lines of differences was -completed in less than a week. -This one time-savings alone was justification enough for the \fBcvs\fP -development effort; we expect to gain even more when tracking future SunOS -releases. -.NH -Future Enhancements and Current Bugs -.PP -Since \fBcvs\fP was designed to be incomplete, for reasons of design -simplicity, there are naturally a good -number of enhancements that can be made to make it more useful. -As well, some nuisances exist in the current implementation. -.RS -.IP \(bu 3 -\fBcvs\fP does not currently \*Qremember\*U who has a checked out a copy of a -module. -As a result, it is impossible to know who might be working on the same -module that you are. -A simple-minded database that is updated nightly would likely suffice. -.IP \(bu 3 -Signal processing, keyboard interrupt handling in particular, is currently -somewhat weak. -This is due to the heavy use of the \fBsystem\fP\|(3) library -function to execute -.SM -RCS -.LG -programs like \fBco\fP and \fBci\fP. -It sometimes takes multiple interrupts to make \fBcvs\fP quit. -This can be fixed by using a home-grown \fBsystem\fP\|() replacement. -.IP \(bu 3 -Security of the source repository is currently not dealt with directly. -The usual UNIX approach of user-group-other security permissions through -the file system is utilized, but nothing else. -\fBcvs\fP could likely be a set-group-id executable that checks a -protected database to verify user access permissions for particular objects -before allowing any operations to affect those objects. -.IP \(bu 3 -With every checked-out directory, \fBcvs\fP maintains some administrative -files that record the current revision numbers of the checked-out files as -well as the location of the respective source repository. -\fBcvs\fP does not recover nicely at all if these administrative files are -removed. -.IP \(bu 3 -The source code for \fBcvs\fP has been tested extensively on Sun-3 and -Sun-4 systems, all running SunOS 4.0 or later versions of the operating -system. -Since the code has not yet been compiled under other platforms, the overall -portability of the code is still questionable. -.IP \(bu 3 -As witnessed in the previous section, the \fBcvs\fP method for tracking -third party vendor source distributions can work quite nicely. -However, if the vendor changes the directory structure or the file names -within the source distribution, \fBcvs\fP has no way of matching the old -release with the new one. -It is currently unclear as to how to solve this, though it is certain to -happen in practice. -.RE -.NH -Availability -.PP -The \fBcvs\fP program sources can be found in a recent posting to the -\fBcomp.sources.unix\fP newsgroup. -It is also currently available via anonymous ftp from \*Qprisma.com\*U. -Copying rights for \fBcvs\fP will be covered by the GNU General Public -License. -.NH -Summary -.PP -Prisma has used \fBcvs\fP since December, 1988. -It has evolved to meet our specific needs of revision and release control. -We will make our code freely available so that others can -benefit from our work, and can enhance \fBcvs\fP to meet broader needs yet. -.PP -Many of the other software release and revision control systems, like the -one described in [Glew], appear to use a collection of tools that are -geared toward specific environments \(em one set of tools for the kernel, -one set for \*Qgeneric\*U software, one set for utilities, and one set for -kernel and utilities. -Each of these tool sets apparently handle some specific aspect of the -problem uniquely. -\fBcvs\fP took a somewhat different approach. -File sharing through symbolic or hard links is not addressed; instead, the -disk space is simply burned since it is \*Qcheap.\*U -Support for producing objects for multiple architectures is not addressed; -instead, a parallel checked-out source tree must be used for each -architecture, again wasting disk space to simplify complexity and ease of -use \(em punting on this issue allowed \fIMakefile\fPs to remain -unchanged, unlike the approach taken in [Mahler], thereby maintaining closer -compatibility with the third-party vendor sources. -\fBcvs\fP is essentially a source-file server, making no assumptions or -special handling of the sources that it controls. -To \fBcvs\fP: -.QP -A source is a source, of course, of course, unless of course the source is -Mr. Ed.\** -.FS -\fBcvs\fP, of course, does not really discriminate against Mr. Ed.\** -.FE -.FS -Yet. -.FE -.LP -Sources are maintained, saved, and retrievable at any time based on -symbolic or numeric revision or date in the past. -It is entirely up to \fBcvs\fP wrapper programs to provide for release -environments and such. -.PP -The major advantage of \fBcvs\fP over the -many other similar systems that have already been designed is the -simplicity of \fBcvs\fP. -\fBcvs\fP contains only three programs that do all the work of release -and revision control, and two manually-maintained administrative -files for each source repository. -Of course, the deciding factor of any tool is whether people use it, and if -they even \fIlike\fP to use it. -At Prisma, \fBcvs\fP prevented members of the kernel -group from killing each other. -.NH -Acknowledgements -.PP -Many thanks to Dick Grune at Vrije Universiteit in Amsterdam for his work -on the original version of \fBcvs\fP and for making it available to the -world. -Thanks to Jeff Polk of Prisma for helping with the design of the module -database, vendor branch support, and for writing the \fBcheckin\fP shell -script. -Thanks also to the entire software group at Prisma for taking the -time to review the paper and correct my grammar. -.NH -References -.IP [Bell] 12 -Bell Telephone Laboratories. -\*QSource Code Control System User's Guide.\*U -\fIUNIX System III Programmer's Manual\fP, October 1981. -.IP [Courington] 12 -Courington, W. -\fIThe Network Software Environment\fP, -Sun Technical Report FE197-0, Sun Microsystems Inc, February 1989. -.IP [Essick] 12 -Essick, Raymond B. and Robert Bruce Kolstad. -\fINotesfile Reference Manual\fP, -Department of Computer Science Technical Report #1081, -University of Illinois at Urbana-Champaign, Urbana, Illinois, -1982, p. 26. -.IP [Glew] 12 -Glew, Andy. -\*QBoxes, Links, and Parallel Trees: -Elements of a Configuration Management System.\*U -\fIWorkshop Proceedings of the Software Management Conference\fP, USENIX, -New Orleans, April 1989. -.IP [Grune] 12 -Grune, Dick. -Distributed the original shell script version of \fBcvs\fP in the -\fBcomp.sources.unix\fP volume 6 release in 1986. -.IP [Honda] 12 -Honda, Masahiro and Terrence Miller. -\*QSoftware Management Using a CASE Environment.\*U -\fIWorkshop Proceedings of the Software Management Conference\fP, USENIX, -New Orleans, April 1989. -.IP [Mahler] 12 -Mahler, Alex and Andreas Lampen. -\*QAn Integrated Toolset for Engineering Software Configurations.\*U -\fIProceedings of the ACM SIGSOFT/SIGPLAN Software Engineering Symposium on -Practical Software Development Environments\fP, ACM, Boston, November 1988. -Described is the \fBshape\fP toolkit posted to the -\fBcomp.sources.unix\fP newsgroup in the volume 19 release. -.IP [Tichy] 12 -Tichy, Walter F. -\*QDesign, Implementation, and Evaluation of a Revision Control System.\*U -\fIProceedings of the 6th International Conference on Software -Engineering\fP, IEEE, Tokyo, September 1982. -.IP [Wall] 12 -Wall, Larry. -The \fBpatch\fP program is an indispensable tool for applying a diff file -to an original. -Can be found on uunet.uu.net in ~ftp/pub/patch.tar. diff --git a/gnu/usr.bin/cvs/doc/cvs.texinfo b/gnu/usr.bin/cvs/doc/cvs.texinfo deleted file mode 100644 index ef125f5..0000000 --- a/gnu/usr.bin/cvs/doc/cvs.texinfo +++ /dev/null @@ -1,6931 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@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. - -@comment This file is part of the CVS distribution. - -@comment CVS is free software; you can redistribute it and/or modify -@comment it under the terms of the GNU General Public License as published by -@comment the Free Software Foundation; either version 1, or (at your option) -@comment any later version. - -@comment CVS is distributed in the hope that it will be useful, -@comment but WITHOUT ANY WARRANTY; without even the implied warranty of -@comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -@comment GNU General Public License for more details. - -@comment You should have received a copy of the GNU General Public License -@comment along with CVS; see the file COPYING. If not, write to -@comment the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - -@afourpaper -@setfilename cvs.info -@settitle CVS---Concurrent Versions System -@setchapternewpage odd - -@c -- TODO list: -@c -- Fix all lines that match "^@c -- " -@c -- Document how CVS finds the binaries it executes. -@c Things to include in the index: -@c Finding RCS binaries -@c Path to RCS binaries -@c RCS, how CVS finds them -@c s/RCS/diff/ -@c -- More on binary files - -@ifinfo -Copyright @copyright{} 1992, 1993 Signum Support AB -Copyright @copyright{} 1993, 1994 Free Software Foundation, Inc. - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -@ignore -Permission is granted to process this file through Tex and print the -results, provided the printed document carries copying permission -notice identical to this one except for the removal of this paragraph -(this paragraph not being relevant to the printed manual). - -@end ignore -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -section entitled ``GNU General Public License'' is included exactly as -in the original, and provided that the entire resulting derived work is -distributed under the terms of a permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions, -except that the section entitled ``GNU General Public License'' and -this permission notice may be included in translations approved by the -Free Software Foundation instead of in the original English. -@end ifinfo - -@comment The titlepage section does not appear in the Info file. -@titlepage -@sp 4 -@comment The title is printed in a large font. -@center @titlefont{Version Management} -@sp -@center @titlefont{with} -@sp -@center @titlefont{CVS} -@sp 2 -@center for @sc{cvs} 1.6+ -@comment -release- -@sp 3 -@center Per Cederqvist -@sp 3 -@center last updated 12 Oct 1995 -@comment -date- - -@comment The following two commands start the copyright page -@comment for the printed manual. This will not appear in the Info file. -@page -@vskip 0pt plus 1filll -Copyright @copyright{} 1992, 1993 Signum Support AB - -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided also that the -section entitled ``GNU General Public License'' is included exactly as -in the original, and provided that the entire resulting derived work is -distributed under the terms of a permission notice identical to this one. - -Permission is granted to copy and distribute translations of this manual -into another language, under the above conditions for modified versions, -except that the section entitled ``GNU General Public License'' and -this permission notice may be included in translations approved by the -Free Software Foundation instead of in the original English. -@end titlepage - -@comment ================================================================ -@comment The real text starts here -@comment ================================================================ - -@ifinfo -@c --------------------------------------------------------------------- -@node Top -@top - -This info manual describes how to use and administer -@sc{cvs} and is updated to release 1.4 or something -similar. -@end ifinfo - -@menu -* Preface:: About this manual -* What is CVS?:: What is CVS? -* Basic concepts:: Basic concepts of revision management -* A sample session:: A tour of basic CVS usage -* Repository:: Where all your sources are stored -* Starting a new project:: Starting a project with CVS -* Multiple developers:: How CVS helps a group of developers -* Branches:: Parallel development explained -* Merging:: How to move changes between branches -* Recursive behavior:: CVS descends directories -* Adding files:: Adding files to a module -* Removing files:: Removing files from a module -* Tracking sources:: Tracking third-party sources -* Moving files:: Moving and renaming files -* Moving directories:: Moving and renaming directories -* Keyword substitution:: CVS can include the revision inside the file -* Revision management:: Policy questions for revision management -* Invoking CVS:: Reference manual for CVS commands -* Administrative files:: Reference manual for the Administrative files -* Environment variables:: All environment variables which affect CVS -* Troubleshooting:: Some tips when nothing works -* Copying:: GNU GENERAL PUBLIC LICENSE -* Index:: Index -@end menu - -@c --------------------------------------------------------------------- -@node Preface -@unnumbered About this manual -@cindex Preface -@cindex About this manual - -Up to this point, one of the weakest parts of @sc{cvs} -has been the documentation. @sc{cvs} is a complex -program. Previous versions of the manual were written -in the manual page format, which is not really well -suited for such a complex program. - -When writing this manual, I had several goals in mind: - -@itemize @bullet -@item -No knowledge of @sc{rcs} should be necessary. - -@item -No previous knowledge of revision control software -should be necessary. All terms, such as @dfn{revision -numbers}, @dfn{revision trees} and @dfn{merging} are -explained as they are introduced. - -@item -The manual should concentrate on the things @sc{cvs} users -want to do, instead of what the @sc{cvs} commands can do. -The first part of this manual leads you through things -you might want to do while doing development, and -introduces the relevant @sc{cvs} commands as they are -needed. - -@item -Information should be easy to find. In the reference -manual in the appendices almost all information about -every @sc{cvs} command is gathered together. There is also -an extensive index, and a lot of cross references. -@end itemize - -@cindex Signum Support -@cindex Support, getting CVS support -This manual was contributed by Signum Support AB in -Sweden. Signum is yet another in the growing list of -companies that support free software. You are free to -copy both this manual and the @sc{cvs} program. -@xref{Copying}, for the details. Signum Support offers -@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 -more information. - -@example -Signum Support AB -Box 2044 -S-580 02 Linkoping -Sweden - -Email: info@@signum.se -Phone: +46 (0)13 - 21 46 00 -Fax: +46 (0)13 - 21 47 00 -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@menu -* Checklist:: -* Credits:: -* BUGS:: -@end menu - -@node Checklist -@unnumberedsec Checklist for the impatient reader - -@sc{cvs} is a complex system. You will need to read -the manual to be able to use all of its capabilities. -There are dangers that can easily be avoided if you -know about them, and this manual tries to warn you -about them. This checklist is intended to help you -avoid the dangers without reading the entire manual. -If you intend to read the entire manual you can skip -this table. - -@table @asis -@item Binary files -@sc{cvs} can handle binary files, but -you must have @sc{rcs} release 5.5 or later and -a release of @sc{gnu} diff that supports the @samp{-a} -flag (release 1.15 and later are OK). You must also -configure both @sc{rcs} and @sc{cvs} to handle binary -files when you install them. - -Keword substitution can be a source of trouble with -binary files. @xref{Keyword substitution}, for -solutions. - -@item The @code{admin} command -Uncareful use of the @code{admin} command can cause -@sc{cvs} to cease working. @xref{admin}, before trying -to use it. -@end table - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Credits -@unnumberedsec Credits - -@cindex Contributors (manual) -@cindex Credits (manual) -Roland Pesch, Cygnus Support <@t{pesch@@cygnus.com}> -wrote the manual pages which were distributed with -@sc{cvs} 1.3. Appendix A and B contain much text that -was extracted from them. He also read an early draft -of this manual and contributed many ideas and -corrections. - -The mailing-list @code{info-cvs} is sometimes -informative. I have included information from postings -made by the following persons: -David G. Grubbs <@t{dgg@@think.com}>. - -Some text has been extracted from the man pages for -@sc{rcs}. - -The @sc{cvs} @sc{faq} (@pxref{What is CVS?}) by David -G. Grubbs has been used as a check-list to make sure -that this manual is as complete as possible. (This -manual does however not include all of the material in -the @sc{faq}). The @sc{faq} contains a lot of useful -information. - -In addition, the following persons have helped by -telling me about mistakes I've made: -Roxanne Brunskill <@t{rbrunski@@datap.ca}>, -Kathy Dyer <@t{dyer@@phoenix.ocf.llnl.gov}>, -Karl Pingle <@t{pingle@@acuson.com}>, -Thomas A Peterson <@t{tap@@src.honeywell.com}>, -Inge Wallin <@t{ingwa@@signum.se}>, -Dirk Koschuetzki <@t{koschuet@@fmi.uni-passau.de}> -and Michael Brown <@t{brown@@wi.extrel.com}>. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node BUGS -@unnumberedsec BUGS - -@cindex Bugs, known in this manual -@cindex Known bugs in this manual -This manual is known to have room for improvement. -Here is a list of known deficiencies: - -@itemize @bullet -@item -In the examples, the output from @sc{cvs} is sometimes -displayed, sometimes not. - -@item -The input that you are supposed to type in the examples -should have a different font than the output from the -computer. - -@item -This manual should be clearer about what file -permissions you should set up in the repository, and -about setuid/setgid. - -@item -Some of the chapters are not yet complete. They are -noted by comments in the @file{cvs.texinfo} file. - -@item -@cindex Reporting bugs (manual) -@cindex Bugs, reporting (manual) -@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{bug-cvs@@prep.ai.mit.edu}. -@end itemize - -I hope that you will find this manual useful, despite -the above-mentioned shortcomings. - -@flushright - -Linkoping, October 1993 -Per Cederqvist -@end flushright - -@c --------------------------------------------------------------------- -@node What is CVS? -@chapter What is CVS? -@cindex What is CVS? -@cindex Introduction to CVS -@cindex CVS, introduction to - -@sc{cvs} is a version control system. Using it, you can -record the history of your source files. - -@c -- /// -@c -- ///Those who cannot remember the past are condemned to repeat it. -@c -- /// -- George Santayana -@c -- ////// - -@c -- Insert history quote here! -For example, bugs sometimes creep in when -software is modified, and you might not detect the bug -until a long time after you make the modification. -With @sc{cvs}, you can easily retrieve old versions to see -exactly which change caused the bug. This can -sometimes be a big help. - -You could of course save every version of every file -you have ever created. This would -however waste an enormous amount of disk space. @sc{cvs} -stores all the versions of a file in a single file in a -clever way that only stores the differences between -versions. - -@sc{cvs} also helps you if you are part of a group of people working -on the same project. It is all too easy to overwrite -each others' changes unless you are extremely careful. -Some editors, like @sc{gnu} Emacs, try to make sure that -the same file is never modified by two people at the -same time. Unfortunately, if someone is using another -editor, that safeguard will not work. @sc{cvs} solves this problem -by insulating the different developers from each other. Every -developer works in his own directory, and @sc{cvs} merges -the work when each developer is done. - -@cindex History of CVS -@cindex CVS, history of -@cindex Credits (CVS program) -@cindex Contributors (CVS program) -@sc{cvs} started out as a bunch of shell scripts written by -Dick Grune, posted to @code{comp.sources.unix} in the volume 6 -release of December, 1986. While no actual code from -these shell scripts is present in the current version -of @sc{cvs} much of the @sc{cvs} conflict resolution algorithms -come from them. - -In April, 1989, Brian Berliner designed and coded @sc{cvs}. -Jeff Polk later helped Brian with the design of the @sc{cvs} -module and vendor branch support. - -@cindex Source, getting CVS source -You can get @sc{cvs} via anonymous ftp from a number of -sites, for instance @t{prep.ai.mit.edu} in -@file{pub/gnu}. - -@cindex Mailing list -@cindex List, mailing list -There is a mailing list for @sc{cvs} where bug reports -can be sent, questions can be asked, an FAQ is posted, -and discussion about future enhancements to @sc{cvs} -take place. To submit a message to the list, write to -<@t{info-cvs@@prep.ai.mit.edu}>. To subscribe or -unsubscribe, write to -<@t{info-cvs-request@@prep.ai.mit.edu}>. Please be -specific about your email address. - -Work is in progress on creating a newsgroup for -@sc{cvs}-related topics. It will appear somewhere -under the @samp{gnu.} hierarchy. Gateways to and from -the mailing list will be set up. -@c -- Newsgroup? gnu.cvs.info? - -@cindex FTP site -@cindex Patches to CVS -@cindex CVS FTP site -@cindex Fixes to CVS -@cindex FAQ -@cindex CVS FAQ -The @sc{ftp} site @t{think.com} has some @sc{cvs} -material in the @file{/pub/cvs} subdirectory. -Currently (late summer 1993) it contains an excellent -@sc{faq} (Frequently Asked Questions, with answers), -and an improved (but unofficial) version of @sc{cvs}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@unnumberedsec CVS is not@dots{} - -@sc{cvs} can do a lot of things for you, but it does -not try to be everything for everyone. - -@table @asis -@item @sc{cvs} is not a build system. - -Though the structure of your repository and modules -file interact with your build system -(e.g. @file{Makefile}s), they are essentially -independent. - -@sc{cvs} does not dictate how you build anything. It -merely stores files for retrieval in a tree structure -you devise. - -@sc{cvs} does not dictate how to use disk space in the -checked out working directories. If you write your -@file{Makefile}s or scripts in every directory so they -have 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, -@code{VPATH} in @file{Makefile}s, etc.), you can -arrange your disk usage however you like. - -But you have to remember that @emph{any} such system is -a lot of work to construct and maintain. @sc{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 place the tools created to -support such a build system (scripts, @file{Makefile}s, -etc) under @sc{cvs}. - -@item @sc{cvs} is not a substitute for management. - -Your managers and project leaders are expected to talk -to you frequently enough to make certain you are aware -of schedules, merge points, branch names and release -dates. If they don't, @sc{cvs} can't help. - -@sc{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. - -@item @sc{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. - -@sc{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 @dfn{conflict} is purely textual, arising -when two changes to the same base file are near enough -to spook the merge (i.e. @code{diff3}) command. - -@sc{cvs} does not claim to help at all in figuring out -non-textual or distributed conflicts in program logic. - -For example: Say you change the arguments to function -@code{X} defined in file @file{A}. At the same time, -someone edits file @file{B}, adding new calls to -function @code{X} using the old arguments. You are -outside the realm of @sc{cvs}'s competence. - -Acquire the habit of reading specs and talking to your -peers. - - -@item @sc{cvs} is not a configuration management system. - -@sc{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: - -@itemize @bullet -@item Source control. -@item Dependency tracking. -@item Build systems (i.e. What to build and how to find -things during a build. What is shared? What is local?) -@item Bug tracking. -@item Automated Testing procedures. -@item Release Engineering documentation and procedures. -@item Tape Construction. -@item Customer Installation. -@item A way for users to run different versions of the same -software on the same host at the same time. -@end itemize - -@sc{cvs} provides only the first. -@end table - -This section is taken from release 2.3 of the @sc{cvs} -@sc{faq}. - -@c --------------------------------------------------------------------- -@node Basic concepts -@chapter Basic concepts -@cindex Modules (intro) -@cindex Repository (intro) - -@sc{cvs} stores all files in a centralized -@dfn{repository}: a directory (such as -@file{/usr/local/cvsroot} or -@file{user@@remotehost:/usr/local/cvsroot}) which is -populated with a hierarchy of files and directories. -(@pxref{Remote repositories} for information about -keeping the repository on a remote machine.) - -Normally, you never access any of the files in the -repository directly. Instead, you use @sc{cvs} -commands to get your own copy of the files, and then -work on that copy. When you've finished a set of -changes, you check (or @dfn{commit}) them back into the -repository. - -The files in the repository are organized in -@dfn{modules}. Each module is made up of one or more -files, and can include files from several directories. -A typical usage is to define one module per project. - -@menu -* Revision numbers:: The meaning of a revision number -* Versions revisions releases:: Terminology used in this manual -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Revision numbers -@section Revision numbers -@cindex Revision numbers -@cindex Revision tree -@cindex Linear development -@cindex Number, revision- -@cindex Decimal revision number -@cindex Main trunk (intro) -@cindex Branch number -@cindex Number, branch - -Each version of a file has a unique @dfn{revision -number}. Revision numbers look like @samp{1.1}, -@samp{1.2}, @samp{1.3.2.2} or even @samp{1.3.2.2.4.5}. -A revision number always has an even number of -period-separated decimal integers. By default revision -1.1 is the first revision of a file. Each successive -revision is given a new number by increasing the -rightmost number by one. The following figure displays -a few revisions, with newer revisions to the right. - -@example - +-----+ +-----+ +-----+ +-----+ +-----+ - ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! - +-----+ +-----+ +-----+ +-----+ +-----+ -@end example - -@sc{cvs} is not limited to linear development. The -@dfn{revision tree} can be split into @dfn{branches}, -where each branch is a self-maintained line of -development. Changes made on one branch can easily be -moved back to the main trunk. - -Each branch has a @dfn{branch number}, consisting of an -odd number of period-separated decimal integers. The -branch number is created by appending an integer to the -revision number where the corresponding branch forked -off. Having branch numbers allows more than one branch -to be forked off from a certain revision. - -@need 3500 -All revisions on a branch have revision numbers formed -by appending an ordinal number to the branch number. -The following figure illustrates branching with an -example. - -@example -@group - +-------------+ - Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 ! - / +-------------+ - / - / - +---------+ +---------+ +---------+ +---------+ -Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 !----! 1.2.2.4 ! - / +---------+ +---------+ +---------+ +---------+ - / - / -+-----+ +-----+ +-----+ +-----+ +-----+ -! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk -+-----+ +-----+ +-----+ +-----+ +-----+ - ! - ! - ! +---------+ +---------+ +---------+ -Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 ! - +---------+ +---------+ +---------+ - -@end group -@end example - -@c -- However, at least for me the figure is not enough. I suggest more -@c -- text to accompany it. "A picture is worth a thousand words", so you -@c -- have to make sure the reader notices the couple of hundred words -@c -- *you* had in mind more than the others! - -@c -- Why an even number of segments? This section implies that this is -@c -- how the main trunk is distinguished from branch roots, but you never -@c -- explicitly say that this is the purpose of the [by itself rather -@c -- surprising] restriction to an even number of segments. - -The exact details of how the branch number is -constructed is not something you normally need to be -concerned about, but here is how it works: When -@sc{cvs} creates a branch number it picks the first -unused even integer, starting with 2. So when you want -to create a branch from revision 6.4 it will be -numbered 6.4.2. All branch numbers ending in a zero -(such as 6.4.0) are used internally by @sc{cvs} -(@pxref{Magic branch numbers}). The branch 1.1.1 has a -special meaning. @xref{Tracking sources}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Versions revisions releases -@section Versions, revisions and releases -@cindex Revisions, versions and releases -@cindex Versions, revisions and releases -@cindex Releases, revisions and versions - -A file can have several versions, as described above. -Likewise, a software product can have several versions. -A software product is often given a version number such -as @samp{4.1.1}. - -Versions in the first sense are called @dfn{revisions} -in this document, and versions in the second sense are -called @dfn{releases}. To avoid confusion, the word -@dfn{version} is almost never used in this document. - -@c --------------------------------------------------------------------- -@node A sample session -@chapter A sample session -@cindex A sample session -@cindex Example of a work-session -@cindex Getting started -@cindex Work-session, example of -@cindex tc, Trivial Compiler (example) -@cindex Trivial Compiler (example) - -This section describes a typical work-session using -@sc{cvs}. It assumes that a repository is set up -(@pxref{Repository}). - -Suppose you are working on a simple compiler. The source -consists of a handful of C files and a @file{Makefile}. -The compiler is called @samp{tc} (Trivial Compiler), -and the repository is set up so that there is a module -called @samp{tc}. - -@menu -* Getting the source:: Creating a workspace -* Committing your changes:: Making your work available to others -* Cleaning up:: Cleaning up -* Viewing differences:: Viewing differences -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Getting the source -@section Getting the source -@cindex Getting the source -@cindex Checking out source -@cindex Fetching source -@cindex Source, getting from CVS -@cindex Checkout, example - -The first thing you must do is to get your own working copy of the -source for @samp{tc}. For this, you use the @code{checkout} command: - -@example -$ cvs checkout tc -@end example - -@noindent -This will create a new directory called @file{tc} and populate it with -the source files. - -@example -$ cd tc -$ ls tc -CVS Makefile backend.c driver.c frontend.c parser.c -@end example - -The @file{CVS} directory is used internally by -@sc{cvs}. Normally, you should not modify or remove -any of the files in it. - -You start your favorite editor, hack away at @file{backend.c}, and a couple -of hours later you have added an optimization pass to the compiler. -A note to @sc{rcs} and @sc{sccs} users: There is no need to lock the files that -you want to edit. @xref{Multiple developers} for an explanation. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Committing your changes -@section Committing your changes -@cindex Committing changes -@cindex Log message entry -@cindex CVSEDITOR, environment variable -@cindex EDITOR, environment variable - -When you have checked that the compiler is still compilable you decide -to make a new version of @file{backend.c}. - -@example -$ cvs commit backend.c -@end example - -@noindent -@sc{cvs} starts an editor, to allow you to enter a log -message. You type in ``Added an optimization pass.'', -save the temporary file, and exit the editor. - -The environment variable @code{$CVSEDITOR} determines -which editor is started. If @code{$CVSEDITOR} is not -set, then if the environment variable @code{$EDITOR} is -set, it will be used. If both @code{$CVSEDITOR} and -@code{$EDITOR} are not set then the editor defaults to -@code{vi}. If you want to avoid the overhead of -starting an editor you can specify the log message on -the command line using the @samp{-m} flag instead, like -this: - -@example -$ cvs commit -m "Added an optimization pass" backend.c -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Cleaning up -@section Cleaning up -@cindex Cleaning up -@cindex Working copy, removing -@cindex Removing your working copy -@cindex Releasing your working copy - -Before you turn to other tasks you decide to remove your working copy of -tc. One acceptable way to do that is of course - -@example -$ cd .. -$ rm -r tc -@end example - -@noindent -but a better way is to use the @code{release} command (@pxref{release}): - -@example -$ cd .. -$ cvs release -d tc -M driver.c -? tc -You have [1] altered files in this repository. -Are you sure you want to release (and delete) module `tc': n -** `release' aborted by user choice. -@end example - -The @code{release} command checks that all your modifications have been -committed. If history logging is enabled it also makes a note in the -history file. @xref{history file}. - -When you use the @samp{-d} flag with @code{release}, it -also removes your working copy. - -In the example above, the @code{release} command wrote a couple of lines -of output. @samp{? tc} means that the file @file{tc} is unknown to @sc{cvs}. -That is nothing to worry about: @file{tc} is the executable compiler, -and it should not be stored in the repository. @xref{cvsignore}, -for information about how to make that warning go away. -@xref{release output}, for a complete explanation of -all possible output from @code{release}. - -@samp{M driver.c} is more serious. It means that the -file @file{driver.c} has been modified since it was -checked out. - -The @code{release} command always finishes by telling -you how many modified files you have in your working -copy of the sources, and then asks you for confirmation -before deleting any files or making any note in the -history file. - -You decide to play it safe and answer @kbd{n @key{RET}} -when @code{release} asks for confirmation. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Viewing differences -@section Viewing differences -@cindex Viewing differences -@cindex Diff - -You do not remember modifying @file{driver.c}, so you want to see what -has happened to that file. - -@example -$ cd tc -$ cvs diff driver.c -@end example - -This command runs @code{diff} to compare the version of @file{driver.c} -that you checked out with your working copy. When you see the output -you remember that you added a command line option that enabled the -optimization pass. You check it in, and release the module. - -@example -$ cvs commit -m "Added an optimization pass" driver.c -Checking in driver.c; -/usr/local/cvsroot/tc/driver.c,v <-- driver.c -new revision: 1.2; previous revision: 1.1 -done -$ cd .. -$ cvs release -d tc -? tc -You have [0] altered files in this repository. -Are you sure you want to release (and delete) module `tc': y -@end example - -@c --------------------------------------------------------------------- -@node Repository -@chapter The Repository -@cindex Repository, example -@cindex Layout of repository -@cindex Typical repository -@cindex CVSROOT, environment variable -@cindex .profile -@cindex .cshrc -@cindex .tcshrc -@cindex .bashrc -@cindex /usr/local/cvsroot -@cindex cvsroot - -Figure 3 below shows a typical setup of a repository. -Only directories are shown below. - -@example -@t{/usr} - | - +--@t{local} - | | - | +--@t{cvsroot} - | | | - | | +--@t{CVSROOT} - | (administrative files) - | - +--@t{gnu} - | | - | +--@t{diff} - | | (source code to @sc{gnu} diff) - | | - | +--@t{rcs} - | | (source code to @sc{rcs}) - | | - | +--@t{cvs} - | (source code to @sc{cvs}) - | - +--@t{yoyodyne} - | - +--@t{tc} - | | - | +--@t{man} - | | - | +--@t{testing} - | - +--(other Yoyodyne software) -@end example - - -There are a couple of different ways to tell @sc{cvs} -where to find the repository. You can name the -repository on the command line explicitly, with the -@code{-d} (for "directory") option: - -@example -cvs -d /usr/local/cvsroot checkout yoyodyne/tc -@end example - - Or you can set the @code{$CVSROOT} environment -variable to an absolute path to the root of the -repository, @file{/usr/local/cvsroot} in this example. -To set @code{$CVSROOT}, all @code{csh} and @code{tcsh} -users should have this line in their @file{.cshrc} or -@file{.tcshrc} files: - -@example -setenv CVSROOT /usr/local/cvsroot -@end example - -@noindent -@code{sh} and @code{bash} users should instead have these lines in their -@file{.profile} or @file{.bashrc}: - -@example -CVSROOT=/usr/local/cvsroot -export CVSROOT -@end example - - A repository specified with @code{-d} will -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{CVS/Root} file in the working copy). - -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{CVS/Root} file disagree. - -There is nothing magical about the name -@file{/usr/local/cvsroot}. You can choose to place the -repository anywhere you like. -@xref{Remote repositories} to learn how the repository can be on a -different machine than your working copy of the sources. - -The repository is split in two parts. @file{$CVSROOT/CVSROOT} contains -administrative files for @sc{cvs}. The other directories contain the actual -user-defined modules. - -@menu -* User modules:: The structure of the repository -* Intro administrative files:: Defining modules -* Multiple repositories:: Multiple repositories -* Creating a repository:: Creating a repository -* Remote repositories:: Accessing repositories on remote machines -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node User modules -@section User modules -@cindex User modules -@cindex Repository, user parts - -@example - @code{$CVSROOT} - | - +--@t{yoyodyne} - | | - | +--@t{tc} - | | | - +--@t{Makefile,v} - +--@t{backend.c,v} - +--@t{driver.c,v} - +--@t{frontend.c,v} - +--@t{parser.c,v} - +--@t{man} - | | - | +--@t{tc.1,v} - | - +--@t{testing} - | - +--@t{testpgm.t,v} - +--@t{test2.t,v} -@end example - -@cindex History files -@cindex RCS history files -@cindex RCS, CVS uses RCS -The figure above shows the contents of the @samp{tc} -module inside the repository. As you can see all file -names end in @samp{,v}. The files are @dfn{history -files}. They contain, among other things, enough -information to recreate any revision of the file, a log -of all commit messages and the user-name of the person -who committed the revision. @sc{cvs} uses the -facilities of @sc{rcs}, a simpler version control -system, to maintain these files. For a full -description of the file format, see the @code{man} page -@cite{rcsfile(5)}. -@c -- Use this format for all references to man pages, -@c -- or use something better! - -@menu -* File permissions:: File permissions -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node File permissions -@subsection File permissions -@c -- Move this to @node Setting up -@cindex Security -@cindex File permissions -@cindex Group -All @samp{,v} files are created read-only, and you -should not change the permission of those files. The -directories inside the repository should be writable by -the persons that have permission to modify the files in -each directory. This normally means that you must -create a UNIX group (see group(5)) consisting of the -persons that are to edit the files in a project, and -set up the repository so that it is that group that -owns the directory. - -This means that you can only control access to files on -a per-directory basis. - -@sc{cvs} tries to set up reasonable file permissions -for new directories that are added inside the tree, but -you must fix the permissions manually when a new -directory should have different permissions than its -parent directory. - -@cindex setuid -@cindex setgid -Since @sc{cvs} was not written to be run setuid, it is -unsafe to try to run it setuid. You cannot use the -setuid features of @sc{rcs} together with @sc{cvs}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Intro administrative files -@section The administrative files -@cindex Administrative files (intro) -@cindex Modules file -@cindex CVSROOT, module name -@cindex Defining modules (intro) - -The directory @file{$CVSROOT/CVSROOT} contains some @dfn{administrative -files}. @xref{Administrative files}, for a complete description. -You can use @sc{cvs} without any of these files, but -some commands work better when at least the -@file{modules} file is properly set up. - -The most important of these files is the @file{modules} -file. It defines all modules in the repository. This -is a sample @file{modules} file. - -@example -CVSROOT -i mkmodules CVSROOT -modules -i mkmodules CVSROOT modules -cvs gnu/cvs -rcs gnu/rcs -diff gnu/diff -tc yoyodyne/tc -@end example - -The @file{modules} file is line oriented. In its simplest form each -line contains the name of the module, whitespace, and the directory -where the module resides. The directory is a path relative to -@code{$CVSROOT}. The last for lines in the example -above are examples of such lines. - -@cindex mkmodules -Each module definition can contain options. The @samp{-i mkmodules} is -an example of an option. It arranges for @sc{cvs} to run the -@code{mkmodules} program whenever any file in the module CVSROOT is -committed. That program is responsible for checking out read-only -copies from the @sc{rcs} @dfn{history files} of all the administrative files. -These read-only copies are used internally by @sc{cvs}. You -should never edit them directly. - -The line that defines the module called @samp{modules} -uses features that are not explained here. -@xref{modules}, for a full explanation of all the -available features. - -@subsection Editing administrative files -@cindex Editing administrative files -@cindex Administrative files, editing them - -You edit the administrative files in the same way that you would edit -any other module. Use @samp{cvs checkout CVSROOT} to get a working -copy, edit it, and commit your changes in the normal way. - -It is possible to commit an erroneous administrative -file. You can often fix the error and check in a new -revision, but sometimes a particularly bad error in the -administrative file makes it impossible to commit new -revisions. -@c @xref{Bad administrative files} for a hint -@c about how to solve such situations. -@c -- administrative file checking-- - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Multiple repositories -@section Multiple repositories -@cindex Multiple repositories -@cindex Repositories, multiple -@cindex Many repositories -@cindex Parallel repositories -@cindex Disjoint repositories -@cindex CVSROOT, multiple repositories - -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 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. - -None of the examples in this manual show multiple -repositories. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Creating a repository -@section Creating a repository -@c -- Well, how do you do? - -See the instructions in the @file{INSTALL} file in the -@sc{cvs} distribution. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Remote repositories -@section Remote repositories -@cindex Repositories, remote -@cindex Remote repositories -@cindex Client/Server Operation - -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: - -@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 depends -on how you are connecting to the server. - -@menu -* Connecting via rsh:: Using the rsh program to connect -* 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}, 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 - -Then test that rsh is working with - -@example -rsh -l bach chainsaw.brickyard.com echo $PATH -@end example - -@cindex CVS_SERVER -Next you have to make sure that rsh will be able to -find the server. Make sure that the path which 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 -cvs -d bach@@chainsaw.brickyard.com:/user/local/cvsroot checkout foo -@end example - -@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 -@chapter Starting a project with CVS -@cindex Starting a project with CVS -@cindex Creating a project - -@comment --moduledb-- -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. -@xref{Moving files}. - -What to do next depends on the situation at hand. - -@menu -* Setting up the files:: Getting the files into the repository -* Defining the module:: How to make a module of the files -@end menu -@c -- File permissions! - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Setting up the files -@section Setting up the files - -The first step is to create the files inside the repository. This can -be done in a couple of different ways. - -@c -- The contributed scripts -@menu -* From files:: This method is useful with old projects - where files already exists. - -* From scratch:: Creating a module from scratch. -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node From files -@subsection Creating a module from a number of files -@cindex Importing files - -When you begin using @sc{cvs}, you will probably already have several -projects that can be -put under @sc{cvs} control. In these cases the easiest way is to use the -@code{import} command. An example is probably the easiest way to -explain how to use it. If the files you want to install in -@sc{cvs} reside in @file{@var{dir}}, and you want them to appear in the -repository as @file{$CVSROOT/yoyodyne/@var{dir}}, you can do this: - -@example -$ cd @var{dir} -$ cvs import -m "Imported sources" yoyodyne/@var{dir} yoyo start -@end example - -Unless you supply a log message with the @samp{-m} -flag, @sc{cvs} starts an editor and prompts for a -message. The string @samp{yoyo} is a @dfn{vendor tag}, -and @samp{start} is a @dfn{release tag}. They may fill -no purpose in this context, but since @sc{cvs} requires -them they must be present. @xref{Tracking sources}, for -more information about them. - -You can now verify that it worked, and remove your -original source directory. - -@example -$ cd .. -$ mv @var{dir} @var{dir}.orig -$ cvs checkout yoyodyne/@var{dir} # @r{Explanation below} -$ ls -R yoyodyne -$ rm -r @var{dir}.orig -@end example - -@noindent -Erasing the original sources is a good idea, to make sure that you do -not accidentally edit them in @var{dir}, bypassing @sc{cvs}. -Of course, it would be wise to make sure that you have -a backup of the sources before you remove them. - -The @code{checkout} command can either take a module -name as argument (as it has done in all previous -examples) or a path name relative to @code{$CVSROOT}, -as it did in the example above. - -It is a good idea to check that the permissions -@sc{cvs} sets on the directories inside @samp{$CVSROOT} -are reasonable, and that they belong to the proper -groups. @xref{File permissions}. - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node From scratch -@subsection Creating a module from scratch - -For a new project, the easiest thing to do is probably -to create an empty directory structure, like this: - -@example -$ mkdir tc -$ mkdir tc/man -$ mkdir tc/testing -@end example - -After that, you use the @code{import} command to create -the corresponding (empty) directory structure inside -the repository: - -@example -$ cd tc -$ cvs import -m "Created directory structure" yoyodyne/@var{dir} yoyo start -@end example - -Then, use @code{add} to add files (and new directories) -as they appear. - -Check that the permissions @sc{cvs} sets on the -directories inside @samp{$CVSROOT} are reasonable. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Defining the module -@section Defining the module -@cindex Defining a module -@cindex Editing the modules file -@cindex Module, defining -@cindex Modules file, changing - -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. - -@enumerate -@item -Get a working copy of the modules file. - -@example -$ cvs checkout modules -$ cd modules -@end example - -@item -Edit the file and insert a line that defines the module. @xref{Intro -administrative files}, for an introduction. @xref{modules}, for a full -description of the modules file. You can use the -following line to define the module @samp{tc}: - -@example -tc yoyodyne/tc -@end example - -@item -Commit your changes to the modules file. - -@example -$ cvs commit -m "Added the tc module." modules -@end example - -@item -Release the modules module. - -@example -$ cd .. -$ cvs release -d modules -@end example -@end enumerate - -@c --------------------------------------------------------------------- -@node Multiple developers -@chapter Multiple developers -@cindex Multiple developers -@cindex Team of developers -@cindex File locking -@cindex Locking files -@cindex Working copy - -When more than one person works on a software project -things often get complicated. Often, two people try to -edit the same file simultaneously. Some other version -control systems (including @sc{rcs} and @sc{sccs}) -try to solve that particular problem by introducing -@dfn{file locking}, so that only one person can edit -each file at a time. Unfortunately, file locking can -be very counter-productive. If two persons want -to edit different parts of a file, there may be no -reason to prevent either of them from doing so. - -@sc{cvs} does not use file locking. Instead, it allows many -people to edit their own @dfn{working copy} of a file -simultaneously. The first person that commits his -changes has no automatic way of knowing that another has started to -edit it. Others will get an error message when they -try to commit the file. They must then use @sc{cvs} -commands to bring their working copy up to date with -the repository revision. This process is almost -automatic, and explained in this chapter. - -There are many ways to organize a team of developers. -@sc{cvs} does not try to enforce a certain -organization. It is a tool that can be used in several -ways. It is often useful to inform the group of -commits you have done. @sc{cvs} has several ways of -automating that process. @xref{Informing others}. -@xref{Revision management}, for more tips on how to use -@sc{cvs}. - -@menu -* File status:: A file can be in several states -* 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 -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node File status -@section File status -@cindex File status -@cindex Status of a file -@cindex Four states of a file - -After you have checked out a file out from @sc{cvs}, it is in -one of these four states: - -@table @asis -@cindex Up-to-date -@item Up-to-date -The file is identical with the latest revision in the -repository. -@c -- The above is not always true if branching is used. - -@item Locally modified -@cindex Locally modified -You have edited the file, and not yet committed your changes. - -@item Needing update -@cindex Needing update -Someone else has committed a newer revision to the repository. - -@item Needing merge -@cindex Needing merge -Someone else have committed a newer revision to the repository, and you -have also made modifications to the file. -@c -- What about "added" "removed" and so on? -@end table - -You can use the @code{status} command to find out the status of a given -file. @xref{status}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Updating a file -@section Bringing a file up to date -@cindex Bringing a file up to date -@cindex Updating a file -@cindex Merging a file -@cindex update, introduction - -When you want to update or merge a file, use the @code{update} -command. For files that are not up to date this is roughly equivalent -to a @code{checkout} command: the newest revision of the file is -extracted from the repository and put in your working copy of the -module. - -Your modifications to a file are never lost when you -use @code{update}. If no newer revision exists, -running @code{update} has no effect. If you have -edited the file, and a newer revision is available, -@sc{cvs} will merge all changes into your working copy. - -For instance, imagine that you checked out revision 1.4 and started -editing it. In the meantime someone else committed revision 1.5, and -shortly after that revision 1.6. If you run @code{update} on the file -now, @sc{cvs} will incorporate all changes between revision 1.4 and 1.6 into -your file. - -@cindex Overlap -If any of the changes between 1.4 and 1.6 were made too -close to any of the changes you have made, an -@dfn{overlap} occurs. In such cases a warning is -printed, and the resulting file includes both -versions of the lines that overlap, delimited by -special markers. -@xref{update}, for a complete description of the -@code{update} command. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Conflicts example -@section Conflicts example -@cindex Merge, an example -@cindex Example of merge -@cindex driver.c (merge example) - -Suppose revision 1.4 of @file{driver.c} contains this: - -@example -#include <stdio.h> - -void main() -@{ - parse(); - if (nerr == 0) - gencode(); - else - fprintf(stderr, "No code generated.\n"); - exit(nerr == 0 ? 0 : 1); -@} -@end example - -@noindent -Revision 1.6 of @file{driver.c} contains this: - -@example -#include <stdio.h> - -int main(int argc, - char **argv) -@{ - parse(); - if (argc != 1) - @{ - fprintf(stderr, "tc: No args expected.\n"); - exit(1); - @} - if (nerr == 0) - gencode(); - else - fprintf(stderr, "No code generated.\n"); - exit(!!nerr); -@} -@end example - -@noindent -Your working copy of @file{driver.c}, based on revision -1.4, contains this before you run @samp{cvs update}: -@c -- Really include "cvs"? - -@example -#include <stdlib.h> -#include <stdio.h> - -void main() -@{ - init_scanner(); - parse(); - if (nerr == 0) - gencode(); - else - fprintf(stderr, "No code generated.\n"); - exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE); -@} -@end example - -@noindent -You run @samp{cvs update}: -@c -- Really include "cvs"? - -@example -$ cvs update driver.c -RCS file: /usr/local/cvsroot/yoyodyne/tc/driver.c,v -retrieving revision 1.4 -retrieving revision 1.6 -Merging differences between 1.4 and 1.6 into driver.c -rcsmerge warning: overlaps during merge -cvs update: conflicts found in driver.c -C driver.c -@end example - -@noindent -@cindex Conflicts (merge example) -@sc{cvs} tells you that there were some conflicts. -Your original working file is saved unmodified in -@file{.#driver.c.1.4}. The new version of -@file{driver.c} contains this: - -@example -#include <stdlib.h> -#include <stdio.h> - -int main(int argc, - char **argv) -@{ - init_scanner(); - parse(); - if (argc != 1) - @{ - fprintf(stderr, "tc: No args expected.\n"); - exit(1); - @} - if (nerr == 0) - gencode(); - else - fprintf(stderr, "No code generated.\n"); -<<<<<<< driver.c - exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE); -======= - exit(!!nerr); ->>>>>>> 1.6 -@} -@end example - -@noindent -@cindex Markers, conflict -@cindex Conflict markers -@cindex <<<<<<< -@cindex >>>>>>> -@cindex ======= - -Note how all non-overlapping modifications are incorporated in your working -copy, and that the overlapping section is clearly marked with -@samp{<<<<<<<}, @samp{=======} and @samp{>>>>>>>}. - -@cindex Resolving a conflict -@cindex Conflict resolution -You resolve the conflict by editing the file, removing the markers and -the erroneous line. Suppose you end up with this file: -@c -- Add xref to the pcl-cvs manual when it talks -@c -- about this. -@example -#include <stdlib.h> -#include <stdio.h> - -int main(int argc, - char **argv) -@{ - init_scanner(); - parse(); - if (argc != 1) - @{ - fprintf(stderr, "tc: No args expected.\n"); - exit(1); - @} - if (nerr == 0) - gencode(); - else - fprintf(stderr, "No code generated.\n"); - exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE); -@} -@end example - -@noindent -You can now go ahead and commit this as revision 1.7. - -@example -$ cvs commit -m "Initialize scanner. Use symbolic exit values." driver.c -Checking in driver.c; -/usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c -new revision: 1.7; previous revision: 1.6 -done -@end example - -@cindex emerge -If you use release 1.04 or later of pcl-cvs (a @sc{gnu} -Emacs front-end for @sc{cvs}) you can use an Emacs -package called emerge to help you resolve conflicts. -See the documentation for pcl-cvs. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Informing others -@section Informing others about commits -@cindex Informing others -@cindex Spreading information -@cindex Mail, automatic mail on commit - -It is often useful to inform others when you commit a -new revision of a file. The @samp{-i} option of the -@file{modules} file, or the @file{loginfo} file, can be -used to automate this process. @xref{modules}. -@xref{loginfo}. You can use these features of @sc{cvs} -to, for instance, instruct @sc{cvs} to mail a -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. - -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}, the person -running update might get only the change to -@file{b/three.c} and not the change to @file{a/two.c}. - -@c --------------------------------------------------------------------- -@node Branches -@chapter Branches -@cindex Branches -@cindex Main trunk and branches -@cindex Revision tree, making branches - -So far, all revisions shown in this manual have been on -the @dfn{main trunk} -of the revision tree, i.e., all revision numbers -have been of the form @var{x}.@var{y}. One useful -feature, especially when maintaining several releases -of a software product at once, is the ability to make -branches on the revision tree. @dfn{Tags}, symbolic -names for revisions, will also be -introduced in this chapter. - -@menu -* Tags:: Tags--Symbolic revisions -* Branches motivation:: What branches are good for -* Creating a branch:: Creating a branch -* Sticky tags:: Sticky tags -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Tags -@section Tags--Symbolic revisions -@cindex Tags - -The revision numbers live a life of their own. They -need not have anything at all to do with the release -numbers of your software product. Depending -on how you use @sc{cvs} the revision numbers might change several times -between two releases. As an example, some of the -source files that make up @sc{rcs} 5.6 have the following -revision numbers: -@cindex RCS revision numbers - -@example -ci.c 5.21 -co.c 5.9 -ident.c 5.3 -rcs.c 5.12 -rcsbase.h 5.11 -rcsdiff.c 5.10 -rcsedit.c 5.11 -rcsfcmp.c 5.9 -rcsgen.c 5.10 -rcslex.c 5.11 -rcsmap.c 5.2 -rcsutil.c 5.10 -@end example - -@cindex tag, command, introduction -@cindex Tag, symbolic name -@cindex Symbolic name (tag) -@cindex Name, symbolic (tag) -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. - -@cindex Adding a tag -@cindex tag, example -The following example shows how you can add a tag to a -file. The commands must be issued inside your working -copy of the module. That is, you should issue the -command in the directory where @file{backend.c} -resides. - -@example -$ cvs tag release-0-4 backend.c -T backend.c -$ cvs status -v backend.c -=================================================================== -File: backend.c Status: Up-to-date - - Version: 1.4 Tue Dec 1 14:39:01 1992 - RCS Version: 1.4 /usr/local/cvsroot/yoyodyne/tc/backend.c,v - Sticky Tag: (none) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - release-0-4 (revision: 1.4) - -@end example - -There is seldom reason to tag a file in isolation. A more common use is -to tag all the files that constitute a module with the same tag at -strategic points in the development life-cycle, such as when a release -is made. - -@example -$ cvs tag release-1-0 . -cvs tag: Tagging . -T Makefile -T backend.c -T driver.c -T frontend.c -T parser.c -@end example - -(When you give @sc{cvs} a directory as argument, it generally applies the -operation to all the files in that directory, and (recursively), to any -subdirectories that it may contain. @xref{Recursive behavior}.) - -@cindex Retrieving an old revision using tags -@cindex Tag, retrieving old revisions -The @code{checkout} command has a flag, @samp{-r}, that lets you check out -a certain revision of a module. This flag makes it easy to -retrieve the sources that make up release 1.0 of the module @samp{tc} at -any time in the future: - -@example -$ cvs checkout -r release-1-0 tc -@end example - -@noindent -This is useful, for instance, if someone claims that there is a bug in -that release, but you cannot find the bug in the current working copy. - -You can also check out a module as it was at any given date. -@xref{checkout options}. - -When you tag more than one file with the same tag you -can think about the tag as "a curve drawn through a -matrix of filename vs. revision number." Say we have 5 -files with the following revisions: - -@example -@group - file1 file2 file3 file4 file5 - - 1.1 1.1 1.1 1.1 /--1.1* <-*- TAG - 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 -@end group -@end example - -At some time in the past, the @code{*} versions were tagged. -You can think of the tag 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 "sight" through a set of -revisions that is "flat" along the tagged revisions, -like this: - -@example -@group - 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 -@end group -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Branches motivation -@section What branches are good for -@cindex Branches motivation -@cindex What branches are good for -@cindex Motivation for branches - -Suppose that release 1.0 of tc has been made. You are continuing to -develop tc, planning to create release 1.1 in a couple of months. After a -while your customers start to complain about a fatal bug. You check -out release 1.0 (@pxref{Tags}) and find the bug -(which turns out to have a trivial fix). However, the current revision -of the sources are in a state of flux and are not expected to be stable -for at least another month. There is no way to make a -bugfix release based on the newest sources. - -The thing to do in a situation like this is to create a @dfn{branch} on -the revision trees for all the files that make up -release 1.0 of tc. You can then make -modifications to the branch without disturbing the main trunk. When the -modifications are finished you can select to either incorporate them on -the main trunk, or leave them on the branch. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Creating a branch -@section Creating a branch -@cindex Creating a branch -@cindex Branch, creating a -@cindex rtag, creating a branch using - -The @code{rtag} command can be used to create a branch. -The @code{rtag} command is much like @code{tag}, but it -does not require that you have a working copy of the -module. @xref{rtag}. (You can also use the @code{tag} -command; @pxref{tag}). - -@example -$ cvs rtag -b -r release-1-0 release-1-0-patches tc -@end example - -The @samp{-b} flag makes @code{rtag} create a branch -(rather than just a symbolic revision name). @samp{-r -release-1-0} says that this branch should be rooted at the node (in -the revision tree) that corresponds to the tag -@samp{release-1-0}. Note that the numeric revision number that matches -@samp{release-1-0} will probably be different from file to file. The -name of the new branch is @samp{release-1-0-patches}, and the -module affected is @samp{tc}. - -To fix the problem in release 1.0, you need a working -copy of the branch you just created. - -@example -$ cvs checkout -r release-1-0-patches tc -$ cvs status -v driver.c backend.c -=================================================================== -File: driver.c Status: Up-to-date - - Version: 1.7 Sat Dec 5 18:25:54 1992 - RCS Version: 1.7 /usr/local/cvsroot/yoyodyne/tc/driver.c,v - Sticky Tag: release-1-0-patches (branch: 1.7.2) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - release-1-0-patches (branch: 1.7.2) - release-1-0 (revision: 1.7) - -=================================================================== -File: backend.c Status: Up-to-date - - Version: 1.4 Tue Dec 1 14:39:01 1992 - RCS Version: 1.4 /usr/local/cvsroot/yoyodyne/tc/backend.c,v - Sticky Tag: release-1-0-patches (branch: 1.4.2) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - release-1-0-patches (branch: 1.4.2) - release-1-0 (revision: 1.4) - release-0-4 (revision: 1.4) - -@end example - -@cindex Branch numbers -As the output from the @code{status} command shows the branch -number is created by adding a digit at the tail of the revision number -it is based on. (If @samp{release-1-0} corresponds to revision 1.4, the -branch's revision number will be 1.4.2. For obscure reasons @sc{cvs} always -gives branches even numbers, starting at 2. -@xref{Revision numbers}). - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Sticky tags -@section Sticky tags -@cindex Sticky tags -@cindex Tags, sticky -@cindex Branches, sticky - -The @samp{-r release-1-0-patches} flag that was given to @code{checkout} -is @dfn{sticky}, that is, it will apply to subsequent commands -in this directory. If you commit any modifications, they are -committed on the branch. You can later merge the modifications into -the main trunk. @xref{Merging}. - -@example -$ vi driver.c # @r{Fix the bugs} -$ cvs commit -m "Fixed initialization bug" driver.c -Checking in driver.c; -/usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c -new revision: 1.7.2.1; previous revision: 1.7 -done -$ cvs status -v driver.c -=================================================================== -File: driver.c Status: Up-to-date - - Version: 1.7.2.1 Sat Dec 5 19:35:03 1992 - RCS Version: 1.7.2.1 /usr/local/cvsroot/yoyodyne/tc/driver.c,v - Sticky Tag: release-1-0-patches (branch: 1.7.2) - Sticky Date: (none) - Sticky Options: (none) - - Existing Tags: - release-1-0-patches (branch: 1.7.2) - release-1-0 (revision: 1.7) - -@end example - -@cindex Resetting sticky tags -@cindex Sticky tags, resetting -@cindex Deleting sticky tags -The sticky tags will remain on your working files until -you delete them with @samp{cvs update -A}. @xref{update}. - -Sticky tags are not just for branches. If you check -out a certain revision (such as 1.4) it will also -become sticky. Subsequent @samp{cvs update} will not -retrieve the latest revision until you reset the tag -with @samp{cvs update -A}. - -See the descriptions in Appendix A for more information -about sticky tags. Dates and some other options can -also be sticky. Again, see Appendix A for details. -@c -- xref to relevant part of App A. -@c -- Re-evaluate this node. - -@c --------------------------------------------------------------------- -@node Merging -@chapter Merging -@cindex Merging -@cindex Copying changes -@cindex Branches, copying changes between -@cindex Changes, copying between branches -@cindex Modifications, copying between branches - -You can include the changes made between any two -revisions into your working copy, by @dfn{merging}. -You can then commit that revision, and thus effectively -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 - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Merging a branch -@section Merging an entire branch -@cindex Merging a branch -@cindex -j (merging branches) - -You can merge changes made on a branch into your working copy by giving -the @samp{-j @var{branch}} flag to the @code{update} command. With one -@samp{-j @var{branch}} option it merges the changes made between the -point where the branch forked and newest revision on that branch (into -your working copy). - -@cindex Join -The @samp{-j} stands for ``join''. - -@cindex Branch merge example -@cindex Example, branch merge -@cindex Merge, branch example -Consider this revision tree: - -@example -+-----+ +-----+ +-----+ +-----+ -! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 ! <- The main trunk -+-----+ +-----+ +-----+ +-----+ - ! - ! - ! +---------+ +---------+ -Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 ! - +---------+ +---------+ -@end example - -@noindent -The branch 1.2.2 has been given the tag (symbolic name) @samp{R1fix}. The -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.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.2, into your working copy} - # @r{of the file.} - -$ cvs commit -m "Included R1fix" # @r{Create revision 1.5.} -@end example - -A conflict can result from a merge operation. If that -happens, you should resolve it before committing the -new revision. @xref{Conflicts example}. - -The @code{checkout} command also supports the @samp{-j @var{branch}} flag. The -same effect as above could be achieved with this: - -@example -$ 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 -@cindex Merging two revisions -@cindex Revisions, merging differences between -@cindex Differences, merging - -With two @samp{-j @var{revision}} flags, the @code{update} -(and @code{checkout}) command can merge the differences -between any two revisions into your working file. - -@cindex Undoing a change -@cindex Removing a change -@example -$ cvs update -j 1.5 -j 1.3 backend.c -@end example - -@noindent -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 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 when operating on -multiple files. - -@c --------------------------------------------------------------------- -@node Recursive behavior -@chapter Recursive behavior -@cindex Recursive (directory descending) -@cindex Directory, descending -@cindex Descending directories -@cindex Subdirectories - -Almost all of the subcommands of @sc{cvs} work -recursively when you specify a directory as an -argument. For instance, consider this directory -structure: - -@example - @code{$HOME} - | - +--@t{tc} - | | - +--@t{CVS} - | (internal @sc{cvs} files) - +--@t{Makefile} - +--@t{backend.c} - +--@t{driver.c} - +--@t{frontend.c} - +--@t{parser.c} - +--@t{man} - | | - | +--@t{CVS} - | | (internal @sc{cvs} files) - | +--@t{tc.1} - | - +--@t{testing} - | - +--@t{CVS} - | (internal @sc{cvs} files) - +--@t{testpgm.t} - +--@t{test2.t} -@end example - -@noindent -If @file{tc} is the current working directory, the -following is true: - -@itemize @bullet -@item -@samp{cvs update testing} is equivalent to @samp{cvs -update testing/testpgm.t testing/test2.t} - -@item -@samp{cvs update testing man} updates all files in the -subdirectories - -@item -@samp{cvs update .} or just @samp{cvs update} updates -all files in the @code{tc} module -@end itemize - -If no arguments are given to @code{update} it will -update all files in the current working directory and -all its subdirectories. In other words, @file{.} is a -default argument to @code{update}. This is also true -for most of the @sc{cvs} subcommands, not only the -@code{update} command. - -The recursive behavior of the @sc{cvs} subcommands can be -turned off with the @samp{-l} option. - -@example -$ cvs update -l # @r{Don't update files in subdirectories} -@end example - -@c --------------------------------------------------------------------- -@node Adding files -@chapter Adding files to a module -@cindex Adding files - -To add a new file to a module, follow these steps. - -@itemize @bullet -@item -You must have a working copy of the module. -@xref{Getting the source}. - -@item -Create the new file inside your working copy of the module. - -@item -Use @samp{cvs add @var{filename}} to tell @sc{cvs} that you -want to version control the file. - -@item -Use @samp{cvs commit @var{filename}} to actually check -in the file into the repository. Other developers -cannot see the file until you perform this step. - -@item -If the file contains binary data it might be necessary -to change the default keyword substitution. -@xref{Keyword substitution}. @xref{admin examples}. -@end itemize - -You can also use the @code{add} command to add a new -directory inside a module. - -Unlike most other commands, the @code{add} command is -not recursive. You cannot even type @samp{cvs add -foo/bar}! Instead, you have to - -@example -$ cd foo -$ cvs add bar -@end example - -@xref{add}, for a more complete description of the @code{add} -command. - -@c --------------------------------------------------------------------- -@node Removing files -@chapter Removing files from a module -@cindex Removing files -@cindex Deleting files - -Modules change. New files are added, and old files -disappear. Still, you want to be able to retrieve an -exact copy of old releases of the module. - -Here is what you can do to remove a file from a module, -but remain able to retrieve old revisions: - -@itemize @bullet -@item -Make sure that you have not made any uncommitted -modifications to the file. @xref{Viewing differences}, -for one way to do that. You can also use the -@code{status} or @code{update} command. If you remove -the file without committing your changes, you will of -course not be able to retrieve the file as it was -immediately before you deleted it. - -@item -Remove the file from your working copy of the module. -You can for instance use @code{rm}. - -@item -Use @samp{cvs remove @var{filename}} to tell @sc{cvs} that -you really want to delete the file. - -@item -Use @samp{cvs commit @var{filename}} to actually -perform the removal of the file from the repository. -@end itemize - -What happens when you commit the removal of the file is -that inside the source repository, it is moved into a -subdirectory called @file{Attic}. @sc{cvs} normally doesn't -look in that directory when you run e.g. -@code{checkout}. However, if you are retrieving a -certain revision via e.g. @samp{cvs checkout -r -@var{some-tag}}, it will look at the files inside the -@file{Attic} and include any files that contain the -specified tag. - -@c --------------------------------------------------------------------- -@node Tracking sources -@chapter Tracking third-party sources -@cindex Third-party sources -@cindex Tracking sources - -If you modify a program to better fit your site, you -probably want to include your modifications when the next -release of the program arrives. @sc{cvs} can help you with -this task. - -@cindex Vendor -@cindex Vendor branch -@cindex Branch, vendor- -In the terminology used in @sc{cvs}, the supplier of the -program is called a @dfn{vendor}. The unmodified -distribution from the vendor is checked in on its own -branch, the @dfn{vendor branch}. @sc{cvs} reserves branch -1.1.1 for this use. - -When you modify the source and commit it, your revision -will end up on the main trunk. When a new release is -made by the vendor, you commit it on the vendor branch -and copy the modifications onto the main trunk. - -Use the @code{import} command to create and update -the vendor branch. After a successful @code{import} -the vendor branch is made the `head' revision, so -anyone that checks out a copy of the file gets that -revision. When a local modification is committed it is -placed on the main trunk, and made the `head' -revision. - -@menu -* First import:: Importing a module for the first time -* Update imports:: Updating a module with the import command -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node First import -@section Importing a module for the first time -@cindex Importing modules - -Use the @code{import} command to check in the sources -for the first time. When you use the @code{import} -command to track third-party sources, the @dfn{vendor -tag} and @dfn{release tags} are useful. The -@dfn{vendor tag} is a symbolic name for the branch -(which is always 1.1.1, unless you use the @samp{-b -@var{branch}} flag---@xref{import options}). The -@dfn{release tags} are symbolic names for a particular -release, such as @samp{FSF_0_04}. - -@cindex Wdiff (import example) -Suppose you use @code{wdiff} (a variant of @code{diff} -that ignores changes that only involve whitespace), and -are going to make private modifications that you want -to be able to use even when new releases are made in -the future. You start by importing the source to your -repository: - -@example -$ tar xfz wdiff-0.04.tar.gz -$ cd wdiff-0.04 -$ cvs import -m "Import of FSF v. 0.04" fsf/wdiff FSF WDIFF_0_04 -@end example - -The vendor tag is named @samp{FSF} in the above -example, and the only release tag assigned is -@samp{WDIFF_0_04}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Update imports -@section Updating a module with the import command - -When a new release of the source arrives, you import it into the -repository with the same @code{import} command that you used to set up -the repository in the first place. The only difference is that you -specify a different release tag this time. - -@example -$ tar xfz wdiff-0.05.tar.gz -$ cd wdiff-0.05 -$ cvs import -m "Import of FSF v. 0.05" fsf/wdiff FSF WDIFF_0_05 -@end example - -For files that have not been modified locally, the newly created -revision becomes the head revision. If you have made local -changes, @code{import} will warn you that you must merge the changes -into the main trunk, and tell you to use @samp{checkout -j} to do so. - -@example -$ cvs checkout -jFSF:yesterday -jFSF wdiff -@end example - -@noindent -The above command will check out the latest revision of -@samp{wdiff}, merging the changes made on the vendor branch @samp{FSF} -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. - -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 -@end example - -@noindent -In this case, the two above commands are equivalent. - -@c --------------------------------------------------------------------- -@node Moving files -@chapter Moving and renaming files -@cindex Moving files -@cindex Renaming files -@cindex Files, moving - -Moving files to a different directory or renaming them -is not difficult, but some of the ways in which this -works may be non-obvious. (Moving or renaming a -directory is even harder. @xref{Moving directories}). - -The examples below assume that the file @var{old} is renamed to -@var{new}. - -@menu -* Outside:: The normal way to Rename -* Inside:: A tricky, alternative way -* Rename by copying:: Another tricky, alternative way -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Outside -@section The Normal way to Rename - -The normal way to move a file is to copy @var{old} to -@var{new}, and then issue the normal @sc{cvs} commands -to remove @var{old} from the repository, and add -@var{new} to it. (Both @var{old} and @var{new} could -contain relative paths, for example @file{foo/bar.c}). - -@example -$ mv @var{old} @var{new} -$ cvs remove @var{old} -$ cvs add @var{new} -$ cvs commit -m "Renamed @var{old} to @var{new}" @var{old} @var{new} -@end example - -This is the simplest way to move a file, it is not -error-prone, and it preserves the history of what was -done. Note that to access the history of the file you -must specify the old or the new name, depending on what -portion of the history you are accessing. For example, -@code{cvs log @var{old}} will give the log up until the -time of the rename. - -When @var{new} is committed its revision numbers will -start at 1.0 again, so if that bothers you, use the -@samp{-r rev} option to commit (@pxref{commit options}) - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Inside -@section Moving the history file - -This method is more dangerous, since it involves moving -files inside the repository. Read this entire section -before trying it out! - -@example -$ cd $CVSROOT/@var{module} -$ mv @var{old},v @var{new},v -@end example - -@noindent -Advantages: - -@itemize @bullet -@item -The log of changes is maintained intact. - -@item -The revision numbers are not affected. -@end itemize - -@noindent -Disadvantages: - -@itemize @bullet -@item -Old releases of the module cannot easily be fetched from the -repository. (The file will show up as @var{new} even -in revisions from the time before it was renamed). - -@item -There is no log information of when the file was renamed. - -@item -Nasty things might happen if someone accesses the history file -while you are moving it. Make sure no one else runs any of the @sc{cvs} -commands while you move it. -@end itemize - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Rename by copying -@section Copying the history file - -This way also involves direct modifications to the -repository. It is safe, but not without drawbacks. - -@example -# @r{Copy the @sc{rcs} file inside the repository} -$ cd $CVSROOT/@var{module} -$ cp @var{old},v @var{new},v -# @r{Remove the old file} -$ cd ~/@var{module} -$ rm @var{old} -$ cvs remove @var{old} -$ cvs commit @var{old} -# @r{Remove all tags from @var{new}} -$ cvs update @var{new} -$ cvs log @var{new} # @r{Remember the tag names} -$ cvs tag -d @var{tag1} -$ cvs tag -d @var{tag2} -@dots{} -@end example - -By removing the tags you will be able to check out old -revisions of the module. - -@noindent -Advantages: - -@itemize @bullet -@item -@c FIXME: Is this true about -D now that we have death -@c support? See 5B.3 in the FAQ. -Checking out old revisions works correctly, as long as -you use @samp{-r@var{tag}} and not @samp{-D@var{date}} -to retrieve the revisions. - -@item -The log of changes is maintained intact. - -@item -The revision numbers are not affected. -@end itemize - -@noindent -Disadvantages: - -@itemize @bullet -@item -You cannot easily see the history of the file across the rename. - -@item -Unless you use the @samp{-r rev} (@pxref{commit -options}) flag when @var{new} is committed its revision -numbers will start at 1.0 again. -@end itemize - -@c --------------------------------------------------------------------- -@node Moving directories -@chapter Moving and renaming directories -@cindex Moving directories -@cindex Renaming directories -@cindex Directories, moving - -If you want to be able to retrieve old versions of the -module, you must move each file in the directory -with the @sc{cvs} commands. @xref{Outside}. The old, empty -directory will remain inside the repository, but it -will not appear in your workspace when you check out -the module in the future. -@c -- rephrase - -If you really want to rename or delete a directory, you -can do it like this: - -@enumerate -@item -Inform everyone who has a copy of the module that the -directory will be renamed. They should commit all -their changes, and remove their working copies of the -module, before you take the steps below. - -@item -Rename the directory inside the repository. - -@example -$ cd $CVSROOT/@var{module} -$ mv @var{old-dir} @var{new-dir} -@end example - -@item -Fix the @sc{cvs} administrative files, if necessary (for -instance if you renamed an entire module). - -@item -Tell everyone that they can check out the module and continue -working. - -@end enumerate - -If someone had a working copy of the module the @sc{cvs} commands will -cease to work for him, until he removes the directory -that disappeared inside the repository. - -It is almost always better to move the files in the -directory instead of moving the directory. If you move the -directory you are unlikely to be able to retrieve old -releases correctly, since they probably depend on the -name of the directories. - -@ignore -@c --------------------------------------------------------------------- -@c @node History browsing -@chapter History browsing -@cindex History browsing -@cindex Traceability -@cindex Isolation - -@c -- @quote{To lose ones history is to lose ones soul.} -@c -- /// -@c -- ///Those who cannot remember the past are condemned to repeat it. -@c -- /// -- George Santayana -@c -- /// - -@sc{cvs} tries to make it easy for a group of people to work -together. This is done in two ways: - -@itemize @bullet -@item -Isolation---You have your own working copy of the -source. You are not affected by modifications made by -others until you decide to incorporate those changes -(via the @code{update} command---@pxref{update}). - -@item -Traceability---When something has changed, you can -always see @emph{exactly} what changed. -@end itemize - -There are several features of @sc{cvs} that together lead -to traceability: - -@itemize @bullet -@item -Each revision of a file has an accompanying log -message. - -@item -All commits are optionally logged to a central history -database. - -@item -Logging information can be sent to a user-defined -program (@pxref{loginfo}). -@end itemize - -@c -- More text here. - -This chapter should talk about the history file, the -@code{log} command, the usefulness of ChangeLogs -even when you run @sc{cvs}, and things like that. - -@menu -* log messages:: Log messages -* history database:: The history database -* user-defined logging:: User-defined logging -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node log messages -@section Log messages - -Whenever you commit a file you specify a log message. /// -@c -- - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node history database -@section The history database - -/// - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node user-defined logging -@section User-defined logging - -/// - -@end ignore - -@c --------------------------------------------------------------------- -@node Keyword substitution -@chapter Keyword substitution -@cindex Keyword substitution -@cindex Keyword expansion -@cindex Identifying files - -@comment Be careful when editing this chapter. -@comment Remember that this file is kept under -@comment version control, so we must not accidentally -@comment include a valid keyword in the running text. - -As long as you edit source files inside your working -copy of a module you can always find out the state of -your files via @samp{cvs status} and @samp{cvs log}. -But as soon as you export the files from your -development environment it becomes harder to identify -which revisions they are. - -@sc{Rcs} uses a mechanism known as @dfn{keyword -substitution} (or @dfn{keyword expansion}) to help -identifying the files. Embedded strings of the form -@code{$@var{keyword}$} and -@code{$@var{keyword}:@dots{}$} in a file are replaced -with strings of the form -@code{$@var{keyword}:@var{value}$} whenever you obtain -a new revision of the file. - -@menu -* Keyword list:: RCS Keywords -* Using keywords:: Using keywords -* Avoiding substitution:: Avoiding substitution -* Substitution modes:: Substitution modes -* Log keyword:: Problems with the $@asis{}Log$ keyword. -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Keyword list -@section RCS Keywords -@cindex RCS keywords - -This is a list of the keywords that @sc{rcs} currently -(in release 5.6.0.1) supports: - -@table @code -@cindex Author keyword -@item $@asis{Author}$ -The login name of the user who checked in the revision. - -@cindex Date keyword -@item $@asis{Date}$ -The date and time (UTC) the revision was checked in. - -@cindex Header keyword -@item $@asis{Header}$ -A standard header containing the full pathname of the -@sc{rcs} file, the revision number, the date (UTC), the -author, the state, and the locker (if locked). Files -will normally never be locked when you use @sc{cvs}. - -@cindex Id keyword -@item $@asis{Id}$ -Same as @code{$@asis{Header}$}, except that the @sc{rcs} -filename is without a path. - -@cindex Locker keyword -@item $@asis{Locker}$ -The login name of the user who locked the revision -(empty if not locked, and thus almost always useless -when you are using @sc{cvs}). - -@cindex Log keyword -@item $@asis{Log}$ -The log message supplied during commit, preceded by a -header containing the @sc{rcs} filename, the revision -number, the author, and the date (UTC). Existing log -messages are @emph{not} replaced. Instead, the new log -message is inserted after @code{$@asis{Log:@dots{}}$}. -Each new line is prefixed with a @dfn{comment leader} -which @sc{rcs} guesses from the file name extension. -It can be changed with @code{cvs admin -c}. -@xref{admin options}. This keyword is useful for -accumulating a complete change log in a source file, -but for several reasons it can be problematic. -@xref{Log keyword}. - -@cindex RCSfile keyword -@item $@asis{RCSfile}$ -The name of the RCS file without a path. - -@cindex Revision keyword -@item $@asis{Revision}$ -The revision number assigned to the revision. - -@cindex Source keyword -@item $@asis{Source}$ -The full pathname of the RCS file. - -@cindex State keyword -@item $@asis{State}$ -The state assigned to the revision. States can be -assigned with @code{cvs admin -s}---@xref{admin options}. - -@end table - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Using keywords -@section Using keywords - -To include a keyword string you simply include the -relevant text string, such as @code{$@asis{Id}$}, inside the -file, and commit the file. @sc{cvs} will automatically -expand the string as part of the commit operation. - -@need 800 -It is common to embed @code{$@asis{}Id$} string in the -C source code. This example shows the first few lines -of a typical file, after keyword substitution has been -performed: - -@example -static char *rcsid="$@asis{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $"; -/* @r{The following lines will prevent @code{gcc} version 2.@var{x}} - @r{from issuing an "unused variable" warning}. */ -#if __GNUC__ == 2 -#define USE(var) static void * use_##var = (&use_##var, (void *) &var) -USE (rcsid); -#endif -@end example - -Even though a clever optimizing compiler could remove -the unused variable @code{rcsid}, most compilers tend -to include the string in the binary. Some compilers -have a @code{#pragma} directive to include literal text -in the binary. - -@cindex Ident (shell command) -The @code{ident} command (which is part of the @sc{rcs} -package) can be used to extract keywords and their -values from a file. This can be handy for text files, -but it is even more useful for extracting keywords from -binary files. - -@example -$ ident samp.c -samp.c: - $@asis{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $ -$ gcc samp.c -$ ident a.out -a.out: - $@asis{}Id: samp.c,v 1.5 1993/10/19 14:57:32 ceder Exp $ -@end example - -@cindex What (shell command) -S@sc{ccs} is another popular revision control system. -It has a command, @code{what}, which is very similar to -@code{ident} and used for the same purpose. Many sites -without @sc{rcs} have @sc{sccs}. Since @code{what} -looks for the character sequence @code{@@(#)} it is -easy to include keywords that are detected by either -command. Simply prefix the @sc{rcs} keyword with the -magic @sc{sccs} phrase, like this: - -@example -static char *id="@@(#) $@asis{}Id: ab.c,v 1.5 1993/10/19 14:57:32 ceder Exp $"; -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Avoiding substitution -@section Avoiding substitution - -Keyword substitution has its disadvantages. Sometimes -you might want the literal text string -@samp{$@asis{}Author$} to appear inside a file without -@sc{rcs} interpreting it as a keyword and expanding it -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). - -In many cases you can avoid using @sc{rcs} keywords in -the source, even though they appear in the final -product. For example, the source for this manual -contains @samp{$@@asis@{@}Author$} whenever the text -@samp{$@asis{}Author$} should appear. In @code{nroff} -and @code{troff} you can embed the null-character -@code{\&} inside the keyword for a similar effect. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Substitution modes -@section Substitution modes -@cindex -k (RCS kflags) -@cindex Kflag - -You can control how @sc{rcs} expands keywords -through the use of the @samp{-k} option (@pxref{Common -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: - -@table @samp -@item -kkv -Generate keyword strings using the default form, e.g. -@code{$@asis{}Revision: 5.7 $} for the @code{Revision} -keyword. - -@item -kkvl -Like @samp{-kkv}, except that a locker's name is always -inserted if the given revision is currently locked. -This option is normally not useful when @sc{cvs} is used. - -@item -kk -Generate only keyword names in keyword strings; omit -their values. For example, for the @code{Revision} -keyword, generate the string @code{$@asis{}Revision$} -instead of @code{$@asis{}Revision: 5.7 $}. This option -is useful to ignore differences due to keyword -substitution when comparing different revisions of a -file. - -@item -ko -Generate the old keyword string, present in the working -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. - -@item -kv -Generate only keyword values for keyword strings. For -example, for the @code{Revision} keyword, generate the string -@code{5.7} instead of @code{$@asis{}Revision: 5.7 $}. -This can help generate files in programming languages -where it is hard to strip keyword delimiters like -@code{$@asis{}Revision: $} from a string. However, -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}. - -@end table - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Log keyword -@section Problems with the $@asis{}Log$ keyword. - -The @code{$@asis{}Log$} keyword is somewhat -controversial. As long as you are working on your -development system the information is easily accessible -even if you do not use the @code{$@asis{}Log$} -keyword---just do a @code{cvs log}. Once you export -the file the history information might be useless -anyhow. - -A more serious concern is that @sc{rcs} is not good at -handling @code{$@asis{}Log$} entries when a branch is -merged onto the main trunk. Conflicts often result -from the merging operation. - -People also tend to "fix" the log entries in the file -(correcting spelling mistakes and maybe even factual -errors). If that is done the information from -@code{cvs log} will not be consistent with the -information inside the file. This may or may not be a -problem in real life. - -It has been suggested that the @code{$@asis{}Log$} -keyword should be inserted @emph{last} in the file, and -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 Revision management -@chapter Revision management -@cindex Revision management - -@c -- This chapter could be expanded a lot. -@c -- Experiences are very welcome! - -If you have read this far, you probably have a pretty -good grasp on what @sc{cvs} can do for you. This -chapter talks a little about things that you still have -to decide. - -If you are doing development on your own using @sc{cvs} -you could probably skip this chapter. The questions -this chapter takes up become more important when more -than one person is working in a repository. - -@menu -* When to commit:: Some discussion on the subject -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node When to commit -@section When to commit? -@cindex When to commit -@cindex Commit, when to -@cindex Policy - -Your group should decide which policy to use regarding -commits. Several policies are possible, and as your -experience with @sc{cvs} grows you will probably find -out what works for you. - -If you commit files too quickly you might commit files -that do not even compile. If your partner updates his -working sources to include your buggy file, he will be -unable to compile the code. On the other hand, other -persons will not be able to benefit from the -improvements you make to the code if you commit very -seldom, and conflicts will probably be more common. - -It is common to only commit files after making sure -that they can be compiled. Some sites require that the -files pass a test suite. Policies like this can be -enforced using the commitinfo file -(@pxref{commitinfo}), but you should think twice before -you enforce such a convention. By making the -development environment too controlled it might become -too regimented and thus counter-productive to the real -goal, which is to get software written. - -@c --------------------------------------------------------------------- -@node Invoking CVS -@appendix Reference manual for CVS commands -@cindex Command reference -@cindex Reference, commands -@cindex Invoking CVS - -This appendix describes every subcommand of @sc{cvs} in -detail. It also describes how to invoke CVS. - -@menu -* Structure:: Overall structure of CVS commands -* ~/.cvsrc:: Default options with the ~/.csvrc file -* Global options:: Options you give to the left of cvs_command -* Common options:: Options you give to the right of cvs_command -* add:: Add a new file/directory to the repository -* admin:: Administration front end for rcs -* checkout:: Checkout sources for editing -* commit:: Check files into the repository -* diff:: Run diffs between revisions -* export:: Export sources from CVS, similar to checkout -* history:: Show status of files and users -* import:: Import sources into CVS, using vendor branches -* log:: Print out 'rlog' information for files -* rdiff:: 'patch' format diffs between releases -* release:: Indicate that a Module is no longer in use -* remove:: Remove an entry from the repository -* rtag:: Add a tag to a module -* status:: Status info on the revisions -* tag:: Add a tag to checked out version -* update:: Bring work tree in sync with repository -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Structure -@appendixsec Overall structure of CVS commands -@cindex Structure -@cindex CVS command structure -@cindex Command structure -@cindex Format of CVS commands - -The first release of @sc{cvs} consisted of a number of shell-scripts. -Today @sc{cvs} is implemented as a single program that is a front-end -to @sc{rcs} and @code{diff}. The overall format of all -@sc{cvs} commands is: - -@example -cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ] -@end example - -@table @code -@item cvs -The program that is a front-end to @sc{rcs}. - -@item cvs_options -Some options that affect all sub-commands of @sc{cvs}. These are -described below. - -@item cvs_command -One of several different sub-commands. Some of the commands have -aliases that can be used instead; those aliases are noted in the -reference manual for that command. There are only two situations -where you may omit @samp{cvs_command}: @samp{cvs -H} elicits a -list of available commands, and @samp{cvs -v} displays version -information on @sc{cvs} itself. - -@item command_options -Options that are specific for the command. - -@item command_args -Arguments to the commands. -@end table - -There is unfortunately some confusion between -@code{cvs_options} and @code{command_options}. -@samp{-l}, when given as a @code{cvs_option}, only -affects some of the commands. When it is given as a -@code{command_option} is has a different meaning, and -is accepted by more commands. In other words, do not -take the above categorization too seriously. Look at -the documentation instead. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node ~/.cvsrc -@appendixsec Default options and the ~/.cvsrc file -@cindex .cvsrc file -@cindex option defaults - -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 (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, -instead of relying on aliases or other shell scripts. - -The format of the @file{~/.cvsrc} file is simple. The -file is searched for a line that begins with the same -name as the @code{cvs_command} being executed. If a -match is found, then the remainder of the line is split -up (at whitespace characters) into separate options and -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}), 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 -diff -u -update -P -co -P -@end example - -@noindent -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. -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}. - - - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Global options -@appendixsec Global options -@cindex Options, global -@cindex Global options -@cindex Left-hand options - -The available @samp{cvs_options} (that are given to the -left of @samp{cvs_command}) are: - -@table @code -@cindex RCSBIN, overriding -@cindex Overriding RCSBIN -@item -b @var{bindir} -Use @var{bindir} as the directory where @sc{rcs} programs are -located. Overrides the setting of the @code{$RCSBIN} environment -variable and any precompiled directory. This parameter should be -specified as an absolute pathname. - -@cindex CVSROOT, overriding -@cindex Overriding CVSROOT -@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. @xref{Repository}. - -@cindex EDITOR, overriding -@cindex Overriding EDITOR -@item -e @var{editor} -Use @var{editor} to enter revision log information. Overrides the -setting of the @code{$CVSEDITOR} and @code{$EDITOR} environment variables. - -@item -f -Do not read the @file{~/.cvsrc} file. This -option is most often used because of the -non-orthogonality of the @sc{cvs} option set. For -example, the @samp{cvs log} option @samp{-N} (turn off -display of tag names) does not have a corresponding -option to turn the display on. So if you have -@samp{-N} in the @file{~/.cvsrc} entry for @samp{diff}, -you may need to use @samp{-f} to show the tag names. -@footnote{Yes, this really should be fixed, and it's -being worked on} - -@item -H -Display usage information about the specified @samp{cvs_command} -(but do not actually execute the command). If you don't specify -a command name, @samp{cvs -H} displays a summary of all the -commands available. - -@item -l -Do not log the cvs_command in the command history (but execute it -anyway). @xref{history}, for information on command history. - -@cindex Read-only mode -@item -n -Do not change any files. Attempt to execute the -@samp{cvs_command}, but only to issue reports; do not remove, -update, or merge any existing files, or create any new files. - -@item -Q -Cause the command to be really quiet; the command will only -generate output for serious problems. - -@item -q -Cause the command to be somewhat quiet; informational messages, -such as reports of recursion through subdirectories, are -suppressed. - -@cindex Read-only files -@item -r -Make new working files files read-only. Same effect -as if the @code{$CVSREAD} environment variable is set -(@pxref{Environment variables}). The default is to -make working files writable. - -@cindex Trace -@item -t -Trace program execution; display messages showing the steps of -@sc{cvs} activity. Particularly useful with @samp{-n} to explore the -potential impact of an unfamiliar command. - -@item -v -Display version and copyright information for @sc{cvs}. - -@cindex CVSREAD, overriding -@cindex Overriding CVSREAD -@item -w -Make new working files read-write. Overrides the -setting of the @code{$CVSREAD} environment variable. -Files are created read-write by default, unless @code{$CVSREAD} is -set or @samp{-r} is given. - -@end table - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Common options -@appendixsec Common command options -@cindex Common options -@cindex Right-hand options - -This section describes the @samp{command_options} that -are available across several @sc{cvs} commands. These -options are always given to the right of -@samp{cvs_command}. Not all -commands support all of these options; each option is -only supported for commands where it makes sense. -However, when a command has one of these options you -can almost always count on the same behavior of the -option as in other commands. (Other command options, -which are listed with the individual commands, may have -different behavior from one @sc{cvs} command to the other). - -@strong{Warning:} the @samp{history} command is an exception; it supports -many options that conflict even with these standard options. - -@table @code -@cindex Dates -@cindex Time -@cindex Specifying dates -@item -D @var{date_spec} -Use the most recent revision no later than @var{date_spec}. -@var{date_spec} is a single argument, a date description -specifying a date in the past. - -The specification is @dfn{sticky} when you use it to make a -private copy of a source file; that is, when you get a working -file using @samp{-D}, @sc{cvs} records the date you specified, so that -further updates in the same directory will use the same date -(unless you explicitly override it; @pxref{update}). - -A wide variety of date formats are supported by the underlying -@sc{rcs} facilities, similar to those described in co(1), but not -exactly the same. The @var{date_spec} is interpreted as being -in the local timezone, unless a specific timezone is specified. -Examples of valid date specifications include: - -@example - 1 month ago - 2 hours ago - 400000 seconds ago - last year - last Monday - yesterday - a fortnight ago - 3/31/92 10:00:07 PST - January 23, 1987 10:05pm - 22:00 GMT -@end example - -@samp{-D} is available with the @code{checkout}, -@code{diff}, @code{export}, @code{history}, -@code{rdiff}, @code{rtag}, and @code{update} commands. -(The @code{history} command uses this option in a -slightly different way; @pxref{history options}). - -Remember to quote the argument to the @samp{-D} -flag so that your shell doesn't interpret spaces as -argument separators. A command using the @samp{-D} -flag can look like this: - -@example -$ cvs diff -D "1 hour ago" cvs.texinfo -@end example - -@cindex Forcing a tag match -@item -f -When you specify a particular date or tag to @sc{cvs} commands, they -normally ignore files that do not contain the tag (or did not -exist prior to the date) that you specified. Use the @samp{-f} option -if you want files retrieved even when there is no match for the -tag or date. (The most recent revision of the file -will be used). - -@need 800 -@samp{-f} is available with these commands: @code{checkout}, -@code{export}, @code{rdiff}, @code{rtag}, and @code{update}. - -@strong{Warning:} The @code{commit} command also has a -@samp{-f} option, but it has a different behavior for -that command. @xref{commit options}. - -@item -H -Help; describe the options available for this command. This is -the only option supported for all @sc{cvs} commands. - -@item -k @var{kflag} -Alter the default @sc{rcs} processing of keywords. -@xref{Keyword substitution}, for the meaning of -@var{kflag}. Your @var{kflag} specification is -@dfn{sticky} when you use it to create a private copy -of a source file; that is, when you use this option -with the @code{checkout} or @code{update} commands, -@sc{cvs} associates your selected @var{kflag} with the -file, and continues to use it with future update -commands on the same file until you specify otherwise. - -The @samp{-k} option is available with the @code{add}, -@code{checkout}, @code{diff} and -@code{update} commands. - -@item -l -Local; run only in current working directory, rather than -recursing through subdirectories. - -@strong{Warning:} this is not the same -as the overall @samp{cvs -l} option, which you can specify to the -left of a cvs command! - -Available with the following commands: @code{checkout}, -@code{commit}, @code{diff}, @code{export}, @code{log}, -@code{remove}, @code{rdiff}, @code{rtag}, -@code{status}, @code{tag}, and @code{update}. - -@cindex Editor, avoiding invocation of -@cindex Avoiding editor invocation -@item -m @var{message} -Use @var{message} as log information, instead of -invoking an editor. - -Available with the following commands: @code{add}, -@code{commit} and @code{import}. - -@item -n -Do not run any checkout/commit/tag program. (A program can be -specified to run on each of these activities, in the modules -database (@pxref{modules}); this option bypasses it). - -@strong{Warning:} this is not the same as the overall @samp{cvs -n} -option, which you can specify to the left of a cvs command! - -Available with the @code{checkout}, @code{commit}, @code{export}, -and @code{rtag} commands. - -@item -P -Prune (remove) directories that are empty after being updated, on -@code{checkout}, or @code{update}. Normally, an empty directory -(one that is void of revision-controlled files) is left alone. -Specifying @samp{-P} will cause these directories to be silently -removed from your checked-out sources. This does not remove the -directory from the repository, only from your checked out copy. -Note that this option is implied by the @samp{-r} or @samp{-D} -options of @code{checkout} and @code{export}. -@c -- implied-- - -@item -p -Pipe the files retrieved from the repository to standard output, -rather than writing them in the current directory. Available -with the @code{checkout} and @code{update} commands. - -@item -W -Specify file names that should be filtered. You can -use this option repeatedly. The spec can be a file -name pattern of the same type that you can specify in -the @file{.cvswrappers} file. -Avaliable with the following commands: @code{import}, -and @code{update}. - -@item -r @var{tag} -Use the revision specified by the @var{tag} argument instead of the -default @dfn{head} revision. As well as arbitrary tags defined -with the @code{tag} or @code{rtag} command, two special tags are -always available: @samp{HEAD} refers to the most recent version -available in the repository, and @samp{BASE} refers to the -revision you last checked out into the current working directory. - -The tag specification is sticky when you use this option -with @code{checkout} or @code{update} to make your own -copy of a file: @sc{cvs} remembers the tag and continues to use it on -future update commands, until you specify otherwise. The -tag can be either a symbolic or numeric tag. -@xref{Tags}. - -Specifying the @samp{-q} global option along with the -@samp{-r} command option is often useful, to suppress -the warning messages when the @sc{rcs} history file -does not contain the specified tag. - -@strong{Warning:} this is not the same as the overall `cvs -r' option, -which you can specify to the left of a cvs command! - -@samp{-r} is available with the @code{checkout}, @code{commit}, -@code{diff}, @code{history}, @code{export}, @code{rdiff}, -@code{rtag}, and @code{update} commands. - -@end table - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node add -@appendixsec add---Add a new file/directory to the repository -@cindex Add (subcommand) - -@itemize @bullet -@item -Synopsis: add [-k kflag] [-m 'message'] files@dots{} -@item -Requires: repository, working directory. -@item -Changes: working directory. -@item -Synonym: new -@end itemize - -Use the @code{add} command to create a new file or directory in the -source repository. The files or directories specified with @code{add} -must already exist in the current directory (which must have been -created with the @code{checkout} command). To add a whole new directory -hierarchy to the source repository (for example, files received -from a third-party vendor), use the @code{import} command -instead. @xref{import}. - -If the argument to @code{add} refers to an immediate -sub-directory, the directory is created at the correct place in -the source repository, and the necessary @sc{cvs} administration -files are created in your working directory. If the directory -already exists in the source repository, @code{add} still creates -the administration files in your version of the directory. -This allows you to use @code{add} to add a particular directory -to your private sources even if someone else created that -directory after your checkout of the sources. You can do the -following: - -@example -$ mkdir new_directory -$ cvs add new_directory -$ cvs update new_directory -@end example - -An alternate approach using @code{update} might be: - -@example -$ cvs update -d new_directory -@end example - -(To add any available new directories to your working directory, -it's probably simpler to use @code{checkout} (@pxref{checkout}) -or @samp{update -d} (@pxref{update})). - -The added files are not placed in the source repository until you -use @code{commit} to make the change permanent. Doing an -@code{add} on a file that was removed with the @code{remove} -command will resurrect the file, unless a @code{commit} command -intervened. -@xref{remove examples} for an example. - - -Unlike most other commands @code{add} never recurses down -directories. It cannot yet handle relative paths. Instead of - -@example -$ cvs add foo/bar.c -@end example - -you have to do - -@example -$ cd foo -$ cvs add bar.c -@end example - -@menu -* add options:: add options -* add examples:: add examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node add options -@appendixsubsec add options -@cindex Add options - -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-- - -@item -m @var{description} -Using this option, you can give a description for the file. This -description appears in the history log (if it is enabled, -@pxref{history file}). It will also be saved in the @sc{rcs} history -file inside the repository when the file is committed. The -@code{log} command displays this description. - -The description can be changed using @samp{admin -t}. -@xref{admin}. - -If you omit the @samp{-m @var{description}} flag, an empty string will be -used. You will not be prompted for a description. -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node add examples -@appendixsubsec add examples - -To add the file @file{backend.c} to the repository, with a -description, the following can be used. - -@example -$ cvs add -m "Optimizer and code generation passes." backend.c -$ cvs commit -m "Early version. Not yet compilable." backend.c -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node admin -@appendixsec admin---Administration front end for rcs -@cindex Admin (subcommand) - -@itemize @bullet -@item -Requires: repository, working directory. -@item -Changes: repository. -@item -Synonym: rcs -@end itemize - -This is the @sc{cvs} interface to assorted administrative @sc{rcs} -facilities, documented in rcs(1). @code{admin} simply passes -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 -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node admin options -@appendixsubsec admin options - -Not all valid @code{rcs} options are useful together -with @sc{cvs}. Some even makes it impossible to use -@sc{cvs} until you undo the effect! - -This description of the available options is based on -the @samp{rcs(1)} man page, but modified to suit -readers that are more interrested in @sc{cvs} than -@sc{rcs}. - -@table @code -@item -A@var{oldfile} -Might not work together with @sc{cvs}. Append the -access list of @var{oldfile} to the access list of the -@sc{rcs} file. - -@item -a@var{logins} -Might not work together with @sc{cvs}. Append the -login names appearing in the comma-separated list -@var{logins} to the access list of the @sc{rcs} file. - -@item -b[@var{rev}] -Breaks @sc{cvs}. When used with bare @sc{rcs}, this -option sets the default branch to @var{rev}. -If @var{rev} is omitted, the default branch is reset to -the (dynamically) highest branch on the trunk. Use -sticky tags instead, as in @code{cvs co -r}. -@xref{Sticky tags}. - -@item -c@var{string} -Useful with @sc{cvs}. Sets the comment leader to -@var{string}. The comment leader is printed before -every log message line generated by the keyword -@code{$@asis{}Log$} (@pxref{Keyword substitution}). -This is useful for programming languages without -multi-line comments. @sc{Rcs} initially guesses the -value of the comment leader from the file name -extension when the file is first committed. - -@item -e[@var{logins}] -Might not work together with @sc{cvs}. Erase the login -names appearing in the comma-separated list -@var{logins} from the access list of the RCS file. If -@var{logins} is omitted, erase the entire access list. - -@item -I -Run interactively, even if the standard input is not a -terminal. - -@item -i -Useless with @sc{cvs}. When using bare @sc{rcs}, this -is used to create and initialize a new @sc{rcs} file, -without depositing a revision. - -@item -k@var{subst} -Useful with @sc{cvs}. Set the default keyword -substitution to @var{subst}. @xref{Keyword -substitution}. Giving an explicit @samp{-k} option to -@code{cvs update} or @code{cvs checkout} overrides this -default. @code{cvs export} always uses @code{-kv}, -regardless of which keyword substitution is set with -@code{cvs admin}. - -@item -l[@var{rev}] -Probably useless with @sc{cvs}. With bare @sc{rcs}, -this option can be used to lock the revision with -number @var{rev}. If a branch is given, lock the -latest revision on that branch. If @var{rev} is -omitted, lock the latest revision on the default -branch. - -@item -L -Probably useless with @sc{cvs}. Used with bare -@sc{rcs} to set locking to strict. Strict -locking means that the owner of an RCS file is not -exempt from locking for checkin. - -@cindex Changing a log message -@cindex Replacing a log message -@cindex Correcting a log message -@cindex Fixing a log message -@cindex Log message, correcting -@item -m@var{rev}:@var{msg} -Replace the log message of revision @var{rev} with -@var{msg}. - -@item -N@var{name}[:[@var{rev}]] -Act like @samp{-n}, except override any previous -assignment of @var{name}. - -@item -n@var{name}[:[@var{rev}]] -Associate the symbolic name @var{name} with the branch -or revision @var{rev}. It is normally better to use -@samp{cvs tag} or @samp{cvs rtag} instead. Delete the -symbolic name if both @samp{:} and @var{rev} are -omitted; otherwise, print an error message if -@var{name} is already associated with another number. -If @var{rev} is symbolic, it is expanded before -association. A @var{rev} consisting of a branch number -followed by a @samp{.} stands for the current latest -revision in the branch. A @samp{:} with an empty -@var{rev} stands for the current latest revision on the -default branch, normally the trunk. For example, -@samp{rcs -n@var{name}: RCS/*} associates @var{name} with the -current latest revision of all the named RCS files; -this contrasts with @samp{rcs -n@var{name}:$ RCS/*} which -associates @var{name} with the revision numbers -extracted from keyword strings in the corresponding -working files. - -@cindex Deleting revisions -@cindex Outdating revisions -@cindex Saving space -@item -o@var{range} -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 -branch number means the latest revision on that branch. -A range of the form @samp{@var{rev1}:@var{rev2}} means -revisions @var{rev1} to @var{rev2} on the same branch, -@samp{:@var{rev}} means from the beginning of the -branch containing @var{rev} up to and including -@var{rev}, and @samp{@var{rev}:} means from revision -@var{rev} to the end of the branch containing -@var{rev}. None of the outdated revisions may have -branches or locks. - -Due to the way @sc{cvs} handles branches @var{rev} -cannot be specified symbolically if it is a branch. -@xref{Magic branch numbers}, for an explanation. - -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, 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. - -@item -s@var{state}[:@var{rev}] -Useful with @sc{cvs}. Set the state attribute of the -revision @var{rev} to @var{state}. If @var{rev} is a -branch number, assume the latest revision on that -branch. If @var{rev} is omitted, assume the latest -revision on the default branch. Any identifier is -acceptable for @var{state}. A useful set of states is -@samp{Exp} (for experimental), @samp{Stab} (for -stable), and @samp{Rel} (for released). By default, -the state of a new revision is set to @samp{Exp} when -it is created. The state is visible in the output from -@var{cvs log} (@pxref{log}), and in the -@samp{$@asis{}Log$} and @samp{$@asis{}State$} keywords -(@pxref{Keyword substitution}). - -@item -t[@var{file}] -Useful with @sc{cvs}. Write descriptive text from the -contents of the named @var{file} into the RCS file, -deleting the existing text. The @var{file} pathname -may not begin with @samp{-}. If @var{file} is omitted, -obtain the text from standard input, terminated by -end-of-file or by a line containing @samp{.} by itself. -Prompt for the text if interaction is possible; see -@samp{-I}. The descriptive text can be seen in the -output from @samp{cvs log} (@pxref{log}). - -@item -t-@var{string} -Similar to @samp{-t@var{file}}. Write descriptive text -from the @var{string} into the @sc{rcs} file, deleting -the existing text. - -@item -U -Probably useless with @sc{cvs}. Used with bare -@sc{rcs} to set locking to non-strict. Non-strict -locking means that the owner of a file need not lock a -revision for checkin. - -@item -u[@var{rev}] -Probably useless with @sc{cvs}. With bare @sc{rcs}, -unlock the revision with number @var{rev}. If a branch -is given, unlock the latest revision on that branch. -If @var{rev} is omitted, remove the latest lock held by -the caller. Normally, only the locker of a revision -may unlock it. Somebody else unlocking a revision -breaks the lock. This causes a mail message to be sent -to the original locker. The message contains a -commentary solicited from the breaker. The commentary -is terminated by end-of-file or by a line containing -@code{.} by itself. - -@item -V@var{n} -Emulate @sc{rcs} version @var{n}. Use -V@var{n} to make -an @sc{rcs} file acceptable to @sc{rcs} version @var{n} -by discarding information that would confuse version -@var{n}. - -@item -x@var{suffixes} -Useless with @sc{cvs}. Use @var{suffixes} to -characterize RCS files. -@end table - - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node admin examples -@appendixsubsec admin examples - -@appendixsubsubsec Outdating is dangerous - -First, an example of how @emph{not} to use the -@code{admin} command. It is included to stress the -fact that this command can be quite dangerous unless -you know @emph{exactly} what you are doing. - -The @samp{-o} option can be used to @dfn{outdate} old revisions -from the history file. If you are short on disc this option -might help you. But think twice before using it---there is no -way short of restoring the latest backup to undo this command! - -The next line is an example of a command that you would -@emph{not} like to execute. - -@example -$ cvs admin -o:R_1_02 . -@end example - -The above command will delete all revisions up to, and -including, the revision that corresponds to the tag -R_1_02. But beware! If there are files that have not -changed between R_1_02 and R_1_03 the file will have -@emph{the same} numerical revision number assigned to -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 -@cindex Nroff (selecting comment leader) - -If you use the @code{$@asis{}Log$} keyword and you do -not agree with the guess for comment leader that -@sc{cvs} has done, you can enforce your will with -@code{cvs admin -c}. This might be suitable for -@code{nroff} source: - -@example -$ cvs admin -c'.\" ' *.man -$ rm *.man -$ cvs update -@end example - -The two last steps are to make sure that you get the -versions with correct comment leaders in your working -files. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node checkout -@appendixsec checkout---Check out sources for editing -@cindex Checkout (subcommand) -@cindex Co (subcommand) - -@itemize @bullet -@item -Synopsis: checkout [options] modules@dots{} -@item -Requires: repository. -@item -Changes: working directory. -@item -Synonyms: co, get -@end itemize - -Make a working directory containing copies of the -source files specified by @var{modules}. You must execute -@code{checkout} before using most of the other @sc{cvs} -commands, since most of them operate on your working -directory. - -The @var{modules} part of the command are either -symbolic names for some -collection of source directories and files, or paths to -directories or files in the repository. The symbolic -names are defined in the @samp{modules} file. -@xref{modules}. - -Depending on the modules you specify, @code{checkout} may -recursively create directories and populate them with -the appropriate source files. You can then edit these -source files at any time (regardless of whether other -software developers are editing their own copies of the -sources); update them to include new changes applied by -others to the source repository; or commit your work as -a permanent change to the source repository. - -Note that @code{checkout} is used to create -directories. The top-level directory created is always -added to the directory where @code{checkout} is -invoked, and usually has the same name as the specified -module. In the case of a module alias, the created -sub-directory may have a different name, but you can be -sure that it will be a sub-directory, and that -@code{checkout} will show the relative path leading to -each file as it is extracted into your private work -area (unless you specify the @samp{-Q} global option). - -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 -to the @code{update} command, that is, any new -directories that have been created in the repository -will appear in your work area. @xref{update}. - -@menu -* checkout options:: checkout options -* checkout examples:: checkout examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node checkout options -@appendixsubsec checkout options - -These standard options are supported by @code{checkout} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -D @var{date} -Use the most recent revision no later than @var{date}. -This option is sticky, and implies @samp{-P}. - -@item -f -Only useful with the @samp{-D @var{date}} or @samp{-r -@var{tag}} flags. If no matching revision is found, -retrieve the most recent revision (instead of ignoring -the file). - -@item -k @var{kflag} -Process @sc{rcs} keywords according to @var{kflag}. See -co(1). This option is sticky; future updates of -this file in this working directory will use the same -@var{kflag}. The @code{status} command can be viewed -to see the sticky options. @xref{status}. - -@item -l -Local; run only in current working directory. - -@item -n -Do not run any checkout program (as specified -with the @samp{-o} option in the modules file; -@pxref{modules}). - -@item -P -Prune empty directories. - -@item -p -Pipe files to the standard output. - -@item -r @var{tag} -Use revision @var{tag}. This option is sticky, and implies @samp{-P}. -@end table - -In addition to those, you can use these special command -options with @code{checkout}: - -@table @code -@item -A -Reset any sticky tags, dates, or @samp{-k} options. -(If you get a working file using one of the @samp{-r}, -@samp{-D}, or @samp{-k} options, @sc{cvs} remembers the -corresponding tag, date, or @var{kflag} and continues using -it for future updates; use the @samp{-A} option to make -@sc{cvs} forget these specifications, and retrieve the -`head' revision of the file). - -@item -c -Copy the module file, sorted, to the standard output, -instead of creating or modifying any files or -directories in your working directory. - -@item -d @var{dir} -Create a directory called @var{dir} for the working -files, instead of using the module name. Unless you -also use @samp{-N}, the paths created under @var{dir} -will be as short as possible. - -@item -j @var{tag} -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: -@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}. - -@xref{Merging}. - -@item -N -Only useful together with @samp{-d @var{dir}}. With this -option, @sc{cvs} will not shorten module paths in your -working directory. (Normally, @sc{cvs} shortens paths as -much as possible when you specify an explicit target -directory). - -@item -s -Like @samp{-c}, but include the status of all modules, -and sort it by the status string. @xref{modules}, for -info about the @samp{-s} option that is used inside the -modules file to set the module status. -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node checkout examples -@appendixsubsec checkout examples - -Get a copy of the module @samp{tc}: - -@example -$ cvs checkout tc -@end example - -Get a copy of the module @samp{tc} as it looked one day -ago: - -@example -$ cvs checkout -D yesterday tc -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node commit -@appendixsec commit---Check files into the repository -@cindex Commit (subcommand) - -@itemize @bullet -@item -Version 1.3 Synopsis: commit [-lnR] [-m 'log_message' | --f file] [-r revision] [files@dots{}] -@item -Version 1.3.1 Synopsis: commit [-lnRf] [-m 'log_message' | --F file] [-r revision] [files@dots{}] -@c -- rename-f-F-- -@item -Requires: working directory, repository. -@item -Changes: repository. -@item -Synonym: ci -@end itemize - -@strong{Warning:} The @samp{-f @var{file}} option will -probably be renamed to @samp{-F @var{file}}, and @samp{-f} -will be given a new behavior in future releases of @sc{cvs}. -@c -- rename-f-F-- - -Use @code{commit} when you want to incorporate changes -from your working source files into the source -repository. - -If you don't specify particular files to commit, all of -the files in your working current directory are -examined. @code{commit} is careful to change in the -repository only those files that you have really -changed. By default (or if you explicitly specify the -@samp{-R} option), files in subdirectories are also -examined and committed if they have changed; you can -use the @samp{-l} option to limit @code{commit} to the -current directory only. - -@code{commit} verifies that the selected files are up -to date with the current revisions in the source -repository; it will notify you, and exit without -committing, if any of the specified files must be made -current first with @code{update} (@pxref{update}). -@code{commit} does not call the @code{update} command -for you, but rather leaves that for you to do when the -time is right. - -When all is well, an editor is invoked to allow you to -enter a log message that will be written to one or more -logging programs (@pxref{modules}, and @pxref{loginfo}) -and placed in the @sc{rcs} history file inside the -repository. This log message can be retrieved with the -@code{log} command; @xref{log}. You can specify the -log message on the command line with the @samp{-m -@var{message}} option, and thus avoid the editor invocation, -or use the @samp{-f @var{file}} option to specify -@c -- rename-f-F-- -that the argument file contains the log message. - -@menu -* commit options:: commit options -* commit examples:: commit examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node commit options -@appendixsubsec commit options - -These standard options are supported by @code{commit} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -l -Local; run only in current working directory. - -@item -n -Do not run any module program. - -@item -R -Commit directories recursively. This is on by default. - -@item -r @var{revision} -Commit to @var{revision}. @var{revision} must be -either a branch, or a revision on the main trunk that -is higher than any existing revision number. You -cannot commit to a specific revision on a branch. -@end table - -@code{commit} also supports these options: - -@table @code -@item -F @var{file} -This option is present in @sc{cvs} releases 1.3-s3 and -later. Read the log message from @var{file}, instead -of invoking an editor. - -@item -f -@c -- rename-f-F-- -This option is present in @sc{cvs} 1.3-s3 and later releases -of @sc{cvs}. Note that this is not the standard behavior of -the @samp{-f} option as defined in @xref{Common options}. - -Force @sc{cvs} to commit a new revision even if you haven't -made any changes to the file. If the current revision -of @var{file} is 1.7, then the following two commands -are equivalent: - -@example -$ cvs commit -f @var{file} -$ cvs commit -r 1.8 @var{file} -@end example - -@item -f @var{file} -@c -- rename-f-F-- -This option is present in @sc{cvs} releases 1.3, 1.3-s1 and -1.3-s2. Note that this is not the standard behavior of -the @samp{-f} option as defined in @xref{Common options}. - -Read the log message from @var{file}, instead -of invoking an editor. - -@item -m @var{message} -Use @var{message} as the log message, instead of -invoking an editor. -@end table - -@need 2000 -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node commit examples -@appendixsubsec commit examples - -@appendixsubsubsec New major release number - -When you make a major release of your product, you -might want the revision numbers to track your major -release number. You should normally not care about -the revision numbers, but this is a thing that many -people want to do, and it can be done without doing any -harm. - -To bring all your files up to the @sc{rcs} revision 3.0 -(including those that haven't changed), you might do: - -@example -$ cvs commit -r 3.0 -@end example - -Note that it is generally a bad idea to try to make the -@sc{rcs} revision number equal to the current release number -of your product. You should think of the revision -number as an internal number that the @sc{cvs} package -maintains, and that you generally never need to care -much about. Using the @code{tag} and @code{rtag} -commands you can give symbolic names to the releases -instead. @xref{tag} and @xref{rtag}. - -Note that the number you specify with @samp{-r} must be -larger than any existing revision number. That is, if -revision 3.0 exists, you cannot @samp{cvs commit --r 1.3}. - -@appendixsubsubsec Committing to a branch - -You can commit to a branch revision (one that has an -even number of dots) with the @samp{-r} option. To -create a branch revision, use the @samp{-b} option -of the @code{rtag} or @code{tag} commands (@pxref{tag} -or @pxref{rtag}). Then, either @code{checkout} or -@code{update} can be used to base your sources on the -newly created branch. From that point on, all -@code{commit} changes made within these working sources -will be automatically added to a branch revision, -thereby not disturbing main-line development in any -way. For example, if you had to create a patch to the -1.2 version of the product, even though the 2.0 version -is already under development, you might do: - -@example -$ cvs rtag -b -r FCS1_2 FCS1_2_Patch product_module -$ cvs checkout -r FCS1_2_Patch product_module -$ cd product_module -[[ hack away ]] -$ cvs commit -@end example - -@noindent -This works automatically since the @samp{-r} option is -sticky. - -@appendixsubsubsec Creating the branch after editing - -Say you have been working on some extremely -experimental software, based on whatever revision you -happened to checkout last week. If others in your -group would like to work on this software with you, but -without disturbing main-line development, you could -commit your change to a new branch. Others can then -checkout your experimental stuff and utilize the full -benefit of @sc{cvs} conflict resolution. The scenario might -look like: - -@example -[[ hacked sources are present ]] -$ cvs tag -b EXPR1 -$ cvs update -r EXPR1 -$ cvs commit -@end example - -The @code{update} command will make the @samp{-r -EXPR1} option sticky on all files. Note that your -changes to the files will never be removed by the -@code{update} command. The @code{commit} will -automatically commit to the correct branch, because the -@samp{-r} is sticky. You could also do like this: - -@example -[[ hacked sources are present ]] -$ cvs tag -b EXPR1 -$ cvs commit -r EXPR1 -@end example - -@noindent -but then, only those files that were changed by you -will have the @samp{-r EXPR1} sticky flag. If you hack -away, and commit without specifying the @samp{-r EXPR1} -flag, some files may accidentally end up on the main -trunk. - -To work with you on the experimental change, others -would simply do - -@example -$ cvs checkout -r EXPR1 whatever_module -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node diff -@appendixsec diff---Run diffs between revisions -@cindex Diff (subcommand) - -@itemize @bullet -@item -Synopsis: diff [-l] [rcsdiff_options] [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files@dots{}] -@item -Requires: working directory, repository. -@item -Changes: nothing. -@end itemize - -The @code{diff} command is used to compare different -revisions of files. The default action is to compare -your working files with the revisions they were based -on, and report any differences that are found. - -If any file names are given, only those files are -compared. If any directories are given, all files -under them will be compared. - -The exit status will be 0 if no differences were found, -1 if some differences were found, and 2 if any error -occurred. - -@menu -* diff options:: diff options -* diff examples:: diff examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node diff options -@appendixsubsec diff options - -These standard options are supported by @code{diff} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -D @var{date} -Use the most recent revision no later than @var{date}. -See @samp{-r} for how this affects the comparison. - -@sc{cvs} can be configured to pass the @samp{-D} option -through to @code{rcsdiff} (which in turn passes it on -to @code{diff}. @sc{Gnu} diff uses @samp{-D} as a way to -put @code{cpp}-style @samp{#define} statements around the output -differences. There is no way short of testing to -figure out how @sc{cvs} was configured. In the default -configuration @sc{cvs} will use the @samp{-D @var{date}} option. - -@item -k @var{kflag} -Process @sc{rcs} keywords according to @var{kflag}. See -co(1). - -@item -l -Local; run only in current working directory. - -@item -R -Examine directories recursively. This option is on by -default. - -@item -r @var{tag} -Compare with revision @var{tag}. Zero, one or two -@samp{-r} options can be present. With no @samp{-r} -option, the working file will be compared with the -revision it was based on. With one @samp{-r}, that -revision will be compared to your current working file. -With two @samp{-r} options those two revisions will be -compared (and your working file will not affect the -outcome in any way). - -One or both @samp{-r} options can be replaced by a -@samp{-D @var{date}} option, described above. -@end table - -Any other options that are found are passed through to -@code{rcsdiff}, which in turn passes them to -@code{diff}. The exact meaning of the options depends -on which @code{diff} you are using. The long options -introduced in @sc{gnu} diff 2.0 are not yet supported in -@sc{cvs}. See the documentation for your @code{diff} to see -which options are supported. - -@c -- Document some common useful diff options, such as -@c -u and -c. -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node diff examples -@appendixsubsec diff examples - -The following line produces a Unidiff (@samp{-u} flag) -between revision 1.14 and 1.19 of -@file{backend.c}. Due to the @samp{-kk} flag no -keywords are substituted, so differences that only depend -on keyword substitution are ignored. - -@example -$ cvs diff -kk -u -r 1.14 -r 1.19 backend.c -@end example - -Suppose the experimental branch EXPR1 was based on a -set of files tagged RELEASE_1_0. To see what has -happened on that branch, the following can be used: - -@example -$ cvs diff -r RELEASE_1_0 -r EXPR1 -@end example - -A command like this can be used to produce a context -diff between two releases: - -@example -$ cvs diff -c -r RELEASE_1_0 -r RELEASE_1_1 > diffs -@end example - -If you are maintaining ChangeLogs, a command like the following -just before you commit your changes may help you write -the ChangeLog entry. All local modifications that have -not yet been committed will be printed. - -@example -$ cvs diff -u | less -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node export -@appendixsec export---Export sources from CVS, similar to checkout -@cindex Export (subcommand) - -@itemize @bullet -@item -Synopsis: export [-flNn] -r rev|-D date [-d dir] module@dots{} -@item -Requires: repository. -@item -Changes: current directory. -@end itemize - -This command is a variant of @code{checkout}; use it -when you want a copy of the source for module without -the @sc{cvs} administrative directories. For example, you -might use @code{export} to prepare source for shipment -off-site. This command requires that you specify a -date or tag (with @samp{-D} or @samp{-r}), so that you -can count on reproducing the source you ship to others. - -The keyword substitution option @samp{-kv} is always set when -export is used. This causes any @sc{rcs} keywords to be -expanded such that an import done at some other site -will not lose the keyword revision information. There -is no way to override this. Note that this breaks the -@code{ident} command (which is part of the @sc{rcs} -suite---see ident(1)) which looks for @sc{rcs} keyword -strings. If you want to be able to use @code{ident} -you must use @code{checkout} instead. - -@menu -* export options:: export options -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node export options -@appendixsubsec export options - -These standard options are supported by @code{export} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -D @var{date} -Use the most recent revision no later than @var{date}. - -@item -f -If no matching revision is found, retrieve the most -recent revision (instead of ignoring the file). - -@item -l -Local; run only in current working directory. - -@item -n -Do not run any checkout program. - -@item -R -Export directories recursively. This is on by default. - -@item -r @var{tag} -Use revision @var{tag}. -@end table - -In addition, these options (that are common to -@code{checkout} and @code{export}) are also supported: - -@table @code -@item -d @var{dir} -Create a directory called @var{dir} for the working -files, instead of using the module name. Unless you -also use @samp{-N}, the paths created under @var{dir} -will be as short as possible. - -@item -N -Only useful together with @samp{-d @var{dir}}. With this -option, @sc{cvs} will not shorten module paths in your -working directory. (Normally, @sc{cvs} shortens paths as -much as possible when you specify an explicit target -directory.) -@end table - -@ignore -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@c @node export examples -@appendixsubsec export examples - -Contributed examples are gratefully accepted. -@c -- Examples here!! -@end ignore - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node history -@appendixsec history---Show status of files and users -@cindex History (subcommand) - -@itemize @bullet -@item -Synopsis: history [-report] [-flags] [-options args] [files@dots{}] -@item -Requires: the file @file{$CVSROOT/CVSROOT/history} -@item -Changes: nothing. -@end itemize - -@sc{cvs} can keep a history file that tracks each use of the -@code{checkout}, @code{commit}, @code{rtag}, -@code{update}, and @code{release} commands. You can -use @code{history} to display this information in -various formats. - -Logging must be enabled by creating the file -@file{$CVSROOT/CVSROOT/history}. - -@strong{Warning:} @code{history} uses @samp{-f}, @samp{-l}, -@samp{-n}, and @samp{-p} in ways that conflict with the -normal use inside @sc{cvs} (@pxref{Common options}). - -@menu -* history options:: history options -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node history options -@appendixsubsec history options - -Several options (shown above as @samp{-report}) control what -kind of report is generated: - -@table @code -@item -c -Report on each time commit was used (i.e., each time -the repository was modified). - -@item -e -Everything (all record types); equivalent to specifying -@samp{-xMACFROGWUT}. - -@item -m @var{module} -Report on a particular module. (You can meaningfully -use @samp{-m} more than once on the command line.) - -@item -o -Report on checked-out modules. - -@item -T -Report on all tags. - -@item -x @var{type} -Extract a particular set of record types @var{type} from the @sc{cvs} -history. The types are indicated by single letters, -which you may specify in combination. - -Certain commands have a single record type: - -@table @code -@item F -release -@item O -checkout -@item T -rtag -@end table - -@noindent -One of four record types may result from an update: - -@table @code -@item C -A merge was necessary but collisions were -detected (requiring manual merging). -@item G -A merge was necessary and it succeeded. -@item U -A working file was copied from the repository. -@item W -The working copy of a file was deleted during -update (because it was gone from the repository). -@end table - -@noindent -One of three record types results from commit: - -@table @code -@item A -A file was added for the first time. -@item M -A file was modified. -@item R -A file was removed. -@end table -@end table - -The options shown as @samp{-flags} constrain or expand -the report without requiring option arguments: - -@table @code -@item -a -Show data for all users (the default is to show data -only for the user executing @code{history}). - -@item -l -Show last modification only. - -@item -w -Show only the records for modifications done from the -same working directory where @code{history} is -executing. -@end table - -The options shown as @samp{-options @var{args}} constrain the report -based on an argument: - -@table @code -@item -b @var{str} -Show data back to a record containing the string -@var{str} in either the module name, the file name, or -the repository path. - -@item -D @var{date} -Show data since @var{date}. This is slightly different -from the normal use of @samp{-D @var{date}}, which -selects the newest revision older than @var{date}. - -@item -p @var{repository} -Show data for a particular source repository (you -can specify several @samp{-p} options on the same command -line). - -@item -r @var{rev} -Show records referring to revisions since the revision -or tag named @var{rev} appears in individual @sc{rcs} -files. Each @sc{rcs} file is searched for the revision or -tag. - -@item -t @var{tag} -Show records since tag @var{tag} was last added to the the -history file. This differs from the @samp{-r} flag -above in that it reads only the history file, not the -@sc{rcs} files, and is much faster. - -@item -u @var{name} -Show records for user @var{name}. -@end table - -@ignore -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@c @node history examples -@appendixsubsec history examples - -Contributed examples will gratefully be accepted. -@c -- Examples here! -@end ignore - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node import -@appendixsec import---Import sources into CVS, using vendor branches -@cindex Import (subcommand) - -@itemize @bullet -@item -Synopsis: import [-options] repository vendortag releasetag@dots{} -@item -Requires: Repository, source distribution directory. -@item -Changes: repository. -@end itemize - -Use @code{import} to incorporate an entire source -distribution from an outside source (e.g., a source -vendor) into your source repository directory. You can -use this command both for initial creation of a -repository, and for wholesale updates to the module -from the outside source. @xref{Tracking sources}, for -a discussion on this subject. - -The @var{repository} argument gives a directory name -(or a path to a directory) under the @sc{cvs} root directory -for repositories; if the directory did not exist, -import creates it. - -When you use import for updates to source that has been -modified in your source repository (since a prior -import), it will notify you of any files that conflict -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 the file @file{$CVSROOT/CVSROOT/cvswrappers} exists, -any file whose names match the specifications in that -file will be treated as packages and the appropriate -filtering will be performed on the file/directory -before being imported, @xref{Wrappers}. - -The outside source is saved in a first-level @sc{rcs} -branch, by default 1.1.1. Updates are leaves of this -branch; for example, files from the first imported -collection of source will be revision 1.1.1.1, then -files from the first imported update will be revision -1.1.1.2, and so on. - -At least three arguments are required. -@var{repository} is needed to identify the collection -of source. @var{vendortag} is a tag for the entire -branch (e.g., for 1.1.1). You must also specify at -least one @var{releasetag} to identify the files at -the leaves created each time you execute @code{import}. - -@menu -* import options:: import options -* import examples:: import examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node import options -@appendixsubsec import options - -This standard option is supported by @code{import} -(@pxref{Common options}, for a complete description): - -@table @code -@item -m @var{message} -Use @var{message} as log information, instead of -invoking an editor. -@end table - -There are three additional special options. - -@table @code -@item -b @var{branch} -Specify a first-level branch other than 1.1.1. Unless -the @samp{-b @var{branch}} flag is given, revisions will -@emph{always} be made to the branch 1.1.1---even if a -@var{vendortag} that matches another branch is given! -What happens in that case, is that the tag will be -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. - -@item -I @var{name} -Specify file names that should be ignored during -import. You can use this option repeatedly. To avoid -ignoring any files at all (even those ignored by -default), specify `-I !'. - -@var{name} can be a file name pattern of the same type -that you can specify in the @file{.cvsignore} file. -@xref{cvsignore}. -@c -- Is this really true? - -@item -W @var{spec} -Specify file names that should be filtered during -import. You can use this option repeatedly. - -@var{spec} can be a file name pattern of the same type -that you can specify in the @file{.cvswrappers} -file. @xref{Wrappers}. -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node import examples -@appendixsubsec import examples - -@xref{Tracking sources}, and @xref{From files}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node log -@appendixsec log---Print out 'rlog' information for files -@cindex Log (subcommand) - -@itemize @bullet -@item -Synopsis: log [-l] rlog-options [files@dots{}] -@item -Requires: repository, working directory. -@item -Changes: nothing. -@item -Synonym: rlog -@end itemize - -Display log information for files. @code{log} calls -the @sc{rcs} utility @code{rlog}, which prints all available -information about the @sc{rcs} history file. This includes -the location of the @sc{rcs} file, the @dfn{head} revision -(the latest revision on the trunk), all symbolic names (tags) -and some other things. For each revision, the revision -number, the author, the number of lines added/deleted and -the log message are printed. All times are displayed in -Coordinated Universal Time (UTC). (Other parts of @sc{cvs} -print times in the local timezone). -@c -- timezone-- - -@menu -* log options:: log options -* log examples:: log examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node log options -@appendixsubsec log options - -Only one option is interpreted by @sc{cvs} and not passed on to @code{rlog}: - -@table @code -@item -l -Local; run only in current working directory. (Default -is to run recursively). -@end table - -By default, @code{rlog} prints all information that is -available. All other options (including those that -normally behave differently) are passed through to -@code{rlog} and restrict the output. See rlog(1) for a -complete description of options. This incomplete list -(which is a slightly edited extract from rlog(1)) lists -all options that are useful in conjunction with @sc{cvs}. - -@strong{Please note:} There can be no space between the option -and its argument, since @code{rlog} parses its options -in a different way than @sc{cvs}. - -@table @code -@item -b -Print information about the revisions on the default -branch, normally the highest branch on the trunk. - -@item -d@var{dates} -Print information about revisions with a checkin -date/time in the range given by the -semicolon-separated list of dates. The following table -explains the available range formats: - -@table @code -@item @var{d1}<@var{d2} -@itemx @var{d2}>@var{d1} -Select the revisions that were deposited between -@var{d1} and @var{d2} inclusive. - -@item <@var{d} -@itemx @var{d}> -Select all revisions dated @var{d} or earlier. - -@item @var{d}< -@itemx >@var{d} -Select all revisions dated @var{d} or later. - -@item @var{d} -Select the single, latest revision dated @var{d} or -earlier. -@end table - -The date/time strings @var{d}, @var{d1}, and @var{d2} -are in the free format explained in co(1). Quoting is -normally necessary, especially for < and >. Note that -the separator is a semicolon (;). - -@item -h -Print only the @sc{rcs} pathname, working pathname, head, -default branch, access list, locks, symbolic names, and -suffix. - -@item -N -Do not print the list of tags for this file. This -option can be very useful when your site uses a lot of -tags, so rather than "more"'ing over 3 pages of tag -information, the log information is presented without -tags at all. - -@item -R -Print only the name of the @sc{rcs} history file. - -@item -r@var{revisions} -Print information about revisions given in the -comma-separated list @var{revisions} of revisions and -ranges. The following table explains the available -range formats: - -@table @code -@item @var{rev1}:@var{rev2} -Revisions @var{rev1} to @var{rev2} (which must be on -the same branch). - -@item :@var{rev} -Revisions from the beginning of the branch up to -and including @var{rev}. - -@item @var{rev}: -Revisions starting with @var{rev} to the end of the -branch containing @var{rev}. - -@item @var{branch} -An argument that is a branch means all revisions on -that branch. You can unfortunately not specify a -symbolic branch here. You must specify the numeric -branch number. @xref{Magic branch numbers}, for an -explanation. - -@item @var{branch1}:@var{branch2} -A range of branches means all revisions -on the branches in that range. - -@item @var{branch}. -The latest revision in @var{branch}. -@end table - -A bare @samp{-r} with no revisions means the latest -revision on the default branch, normally the trunk. - -@item -s@var{states} -Print information about revisions whose state -attributes match one of the states given in the -comma-separated list @var{states}. - -@item -t -Print the same as @samp{-h}, plus the descriptive text. - -@item -w@var{logins} -Print information about revisions checked in by users -with login names appearing in the comma-separated list -@var{logins}. If @var{logins} is omitted, the user's -login is assumed. -@end table - -@code{rlog} prints the intersection of the revisions -selected with the options @samp{-d}, @samp{-l}, -@samp{-s}, and @samp{-w}, intersected with the union of -the revisions selected by @samp{-b} and @samp{-r}. - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node log examples -@appendixsubsec log examples - -Contributed examples are gratefully accepted. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node rdiff -@appendixsec rdiff---'patch' format diffs between releases -@cindex Rdiff (subcommand) - -@itemize @bullet -@item -rdiff [-flags] [-V vn] [-r t|-D d [-r t2|-D d2]] modules@dots{} -@item -Requires: repository. -@item -Changes: nothing. -@item -Synonym: patch -@end itemize - -Builds a Larry Wall format patch(1) file between two -releases, that can be fed directly into the patch -program to bring an old release up-to-date with the new -release. (This is one of the few @sc{cvs} commands that -operates directly from the repository, and doesn't -require a prior checkout.) The diff output is sent to -the standard output device. - -You can specify (using the standard @samp{-r} and -@samp{-D} options) any combination of one or two -revisions or dates. If only one revision or date is -specified, the patch file reflects differences between -that revision or date and the current head revisions in -the @sc{rcs} file. - -Note that if the software release affected is contained -in more than one directory, then it may be necessary to -specify the @samp{-p} option to the patch command when -patching the old sources, so that patch is able to find -the files that are located in other directories. - -@menu -* rdiff options:: rdiff options -* rdiff examples:: rdiff examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node rdiff options -@appendixsubsec rdiff options - -These standard options are supported by @code{rdiff} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -D @var{date} -Use the most recent revision no later than @var{date}. - -@item -f -If no matching revision is found, retrieve the most -recent revision (instead of ignoring the file). - -@item -l -Local; don't descend subdirectories. - -@item -r @var{tag} -Use revision @var{tag}. -@end table - -In addition to the above, these options are available: - -@table @code -@item -c -Use the context diff format. This is the default format. - -@item -s -Create a summary change report instead of a patch. The -summary includes information about files that were -changed or added between the releases. It is sent to -the standard output device. This is useful for finding -out, for example, which files have changed between two -dates or revisions. - -@item -t -A diff of the top two revisions is sent to the standard -output device. This is most useful for seeing what the -last change to a file was. - -@item -u -Use the unidiff format for the context diffs. -This option is not available if your diff does not -support the unidiff format. Remember that old versions -of the @code{patch} program can't handle the unidiff -format, so if you plan to post this patch to the net -you should probably not use @samp{-u}. - -@item -V @var{vn} -Expand @sc{rcs} keywords according to the rules current in -@sc{rcs} version @var{vn} (the expansion format changed with -@sc{rcs} version 5). -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node rdiff examples -@appendixsubsec rdiff examples - -Suppose you receive mail from @t{foo@@bar.com} asking for an -update from release 1.2 to 1.4 of the tc compiler. You -have no such patches on hand, but with @sc{cvs} that can -easily be fixed with a command such as this: - -@example -$ cvs rdiff -c -r FOO1_2 -r FOO1_4 tc | \ -$$ Mail -s 'The patches you asked for' foo@@bar.com -@end example - -Suppose you have made release 1.3, and forked a branch -called @samp{R_1_3fix} for bugfixes. @samp{R_1_3_1} -corresponds to release 1.3.1, which was made some time -ago. Now, you want to see how much development has been -done on the branch. This command can be used: - -@example -$ cvs patch -s -r R_1_3_1 -r R_1_3fix module-name -cvs rdiff: Diffing module-name -File ChangeLog,v changed from revision 1.52.2.5 to 1.52.2.6 -File foo.c,v changed from revision 1.52.2.3 to 1.52.2.4 -File bar.h,v changed from revision 1.29.2.1 to 1.2 -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node release -@appendixsec release---Indicate that a Module is no longer in use -@cindex Release (subcommand) - -@itemize @bullet -@item -release [-d] modules@dots{} -@item -Requires: Working directory. -@item -Changes: Working directory, history log. -@end itemize - -This command is meant to safely cancel the effect of -@samp{cvs checkout}. Since @sc{cvs} doesn't lock files, it -isn't strictly necessary to use this command. You can -always simply delete your working directory, if you -like; but you risk losing changes you may have -forgotten, and you leave no trace in the @sc{cvs} history -file (@pxref{history file}) that you've abandoned your -checkout. - -Use @samp{cvs release} to avoid these problems. This -command checks that no uncommitted changes are -present; that you are executing it from immediately -above a @sc{cvs} working directory; and that the repository -recorded for your files is the same as the repository -defined in the module database. - -If all these conditions are true, @samp{cvs release} -leaves a record of its execution (attesting to your -intentionally abandoning your checkout) in the @sc{cvs} -history log. - -@menu -* release options:: release options -* release output:: release options -* release examples:: release examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node release options -@appendixsubsec release options - -The @code{release} command supports one command option: - -@table @code -@item -d -Delete your working copy of the file if the release -succeeds. If this flag is not given your files will -remain in your working directory. - -@strong{Warning:} The @code{release} command uses -@samp{rm -r @file{module}} to delete your file. This -has the very serious side-effect that any directory -that you have created inside your checked-out sources, -and not added to the repository (using the @code{add} -command; @pxref{add}) will be silently deleted---even -if it is non-empty! -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node release output -@appendixsubsec release output - -Before @code{release} releases your sources it will -print a one-line message for any file that is not -up-to-date. - -@strong{Warning:} Any new directories that you have -created, but not added to the @sc{cvs} directory hierarchy -with the @code{add} command (@pxref{add}) will be -silently ignored (and deleted, if @samp{-d} is -specified), even if they contain files. - -@table @code -@item U @var{file} -There exists a newer revision of this file in the -repository, and you have not modified your local copy -of the file. - -@item A @var{file} -The file has been added to your private copy of the -sources, but has not yet been committed to the -repository. If you delete your copy of the sources -this file will be lost. - -@item R @var{file} -The file has been removed from your private copy of the -sources, but has not yet been removed from the -repository, since you have not yet committed the -removal. @xref{commit}. - -@item M @var{file} -The file is modified in your working directory. There -might also be a newer revision inside the repository. - -@item ? @var{file} -@var{file} is in your working directory, but does not -correspond to anything in the source repository, and is -not in the list of files for @sc{cvs} to ignore (see the -description of the @samp{-I} option, and -@pxref{cvsignore}). If you remove your working -sources, this file will be lost. - -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 -- CVS should be fixed to print "? foo" for -@c such spurious directories -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node release examples -@appendixsubsec release examples - -Release the module, and delete your local working copy -of the files. - -@example -$ cd .. # @r{You must stand immediately above the} - # @r{sources when you issue @samp{cvs release}.} -$ cvs release -d tc -You have [0] altered files in this repository. -Are you sure you want to release (and delete) module `tc': y -$ -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node remove -@appendixsec remove---Remove an entry from the repository -@cindex Remove (subcommand) - -@itemize @bullet -@item -remove [-lR] [files@dots{}] -@item -Requires: Working directory. -@item -Changes: Working directory. -@item -Synonyms: rm, delete -@end itemize - -Use this command to declare that you wish to remove -files from the source repository. Like most @sc{cvs} -commands, @samp{cvs remove} works on files in your working -directory, not directly on the repository. As a -safeguard, it also requires that you first erase the -specified files from your working directory. - -The files are not actually removed until you apply your -changes to the repository with @code{commit}; at that -point, the corresponding @sc{rcs} files in the source -repository are moved into the @file{Attic} directory -(also within the source repository). - -This command is recursive by default, scheduling all -physically removed files that it finds for removal by -the next commit. Use the @samp{-l} option to avoid -this recursion, or just specify the actual files that -you wish removed. - - -@menu -* remove options:: remove options -* remove examples:: remove examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node remove options -@appendixsubsec remove options - -Two of the standard options are the only options -supported by @code{remove}. - -@table @code -@item -l -Local; run only in current working directory. - -@item -R -Commit directories recursively. This is on by default. -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node remove examples -@appendixsubsec remove examples - -@appendixsubsubsec Remove a couple of files. - -@example -$ cd test -$ rm ?.c -$ cvs remove -cvs remove: Removing . -cvs remove: scheduling a.c for removal -cvs remove: scheduling b.c for removal -cvs remove: use 'cvs commit' to remove these files permanently -$ cvs ci -m "Removed unneeded files" -cvs commit: Examining . -cvs commit: Committing . -@end example - -@appendixsubsubsec Resurrecting removed files - -If you change your mind you can easily resurrect the -file before you commit it, using the @code{add} -command. - -@example -$ ls -CVS ja.h oj.c -$ rm oj.c -$ cvs remove oj.c -cvs remove: scheduling oj.c for removal -cvs remove: use 'cvs commit' to remove this file permanently -$ cvs add oj.c -U oj.c -cvs add: oj.c, version 1.1.1.1, resurrected -@end example - -If you realize your mistake before you run the -@code{remove} command you can use @code{update} to -resurrect the file: - -@example -$ rm oj.c -$ cvs update oj.c -cvs update: warning: oj.c was lost -U oj.c -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node rtag -@appendixsec rtag---Add a tag to the RCS file -@cindex Rtag (subcommand) - -@itemize @bullet -@item -rtag [-falnR] [-b] [-d] [-r tag | -Ddate] symbolic_tag modules@dots{} -@item -Requires: repository. -@item -Changes: repository. -@item -Synonym: rfreeze -@end itemize - -You can use this command to assign symbolic tags to -particular, explicitly specified source revisions in -the repository. @code{rtag} works directly on the -repository contents (and requires no prior checkout). -Use @code{tag} instead (@pxref{tag}), to base the -selection of revisions on the contents of your -working directory. - -If you attempt to use a tag name that already exists, -@sc{cvs} will complain and not overwrite that tag. Use -the @samp{-F} option to force the new tag value. - -@menu -* rtag options:: rtag options -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node rtag options -@appendixsubsec rtag options - -These standard options are supported by @code{rtag} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -D @var{date} -Tag the most recent revision no later than @var{date}. - -@item -f -Only useful with the @samp{-D @var{date}} or @samp{-r @var{tag}} -flags. If no matching revision is found, use the most -recent revision (instead of ignoring the file). - -@item -F -Overwrite an existing tag of the same name on a -different revision. This option is new in @sc{cvs} -1.4. The old behavior is matched by @samp{cvs tag -F}. - -@item -l -Local; run only in current working directory. - -@item -n -Do not run any tag program that was specified with the -@samp{-t} flag inside the @file{modules} file. -(@pxref{modules}). - -@item -R -Commit directories recursively. This is on by default. - -@item -r @var{tag} -Only tag those files that contain @var{tag}. This can -be used to rename a tag: tag only the files identified -by the old tag, then delete the old tag, leaving the -new tag on exactly the same files as the old tag. -@end table - -In addition to the above common options, these options -are available: - -@table @code -@item -a -Use the @samp{-a} option to have @code{rtag} look in the -@file{Attic} (@pxref{Removing files}) for removed files -that contain the specified tag. The tag is removed from -these files, which makes it convenient to re-use a -symbolic tag as development continues (and files get -removed from the up-coming distribution). - -@item -b -Make the tag a branch tag. @xref{Branches}. - -@item -d -Delete the tag instead of creating it. - -In general, tags (often the symbolic names of software -distributions) should not be removed, but the @samp{-d} -option is available as a means to remove completely -obsolete symbolic names if necessary (as might be the -case for an Alpha release, or if you mistagged a -module). -@end table - -@ignore -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@c @node rtag examples -@appendixsubsec rtag examples - -@c -- Examples here! -@end ignore - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node status -@appendixsec status---Status info on the revisions -@cindex Status (subcommand) - -@itemize @bullet -@item -status [-lR] [-v] [files@dots{}] -@item -Requires: working directory, repository. -@item -Changes: nothing. -@end itemize - -Display a brief report on the current status of files -with respect to the source repository, including any -sticky tags, dates, or @samp{-k} options. - -You can also use this command to determine the -potential impact of a @samp{cvs update} on your working -source directory---but remember that things might -change in the repository before you run @code{update}. - -@menu -* status options:: status options -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node status options -@appendixsubsec status options - -These standard options are supported by @code{status} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -l -Local; run only in current working directory. - -@item -R -Commit directories recursively. This is on by default. -@end table - -There is one additional option: - -@table @code -@item -v -Verbose. In addition to the information normally -displayed, print all symbolic tags, together with the -numerical value of the revision or branch they refer -to. -@end table - -@ignore -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@c @node status examples -@appendixsubsec status examples - -@c -- FIXME -@end ignore - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node tag -@appendixsec tag---Add a symbolic tag to checked out version of RCS file -@c -- //////// - unnecessary. Also -@c -- in a lot of other -@c -- places. -@cindex Tag (subcommand) - -@itemize @bullet -@item -tag [-lR] [-b] [-d] symbolic_tag [files@dots{}] -@item -Requires: working directory, repository. -@item -Changes: repository. -@item -Synonym: freeze -@end itemize - -Use this command to assign symbolic tags to the nearest -repository versions to your working sources. The tags -are applied immediately to the repository, as with -@code{rtag}, but the versions are supplied implicitly by the -@sc{cvs} records of your working files' history rather than -applied explicitly. - -One use for tags is to record a snapshot of the -current sources when the software freeze date of a -project arrives. As bugs are fixed after the freeze -date, only those changed sources that are to be part of -the release need be re-tagged. - -The symbolic tags are meant to permanently record which -revisions of which files were used in creating a -software distribution. The @code{checkout} and -@code{update} commands allow you to extract an exact -copy of a tagged release at any time in the future, -regardless of whether files have been changed, added, -or removed since the release was tagged. - -This command can also be used to delete a symbolic tag, -or to create a branch. See the options section below. - -If you attempt to use a tag name that already exists, -@sc{cvs} will complain and not overwrite that tag. Use -the @samp{-F} option to force the new tag value. - - -@menu -* tag options:: tag options -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node tag options -@appendixsubsec tag options - -These standard options are supported by @code{tag} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -F -Overwrite an existing tag of the same name on a -different revision. This option is new in @sc{cvs} -1.4. The old behavior is matched by @samp{cvs tag -F}. - -@item -l -Local; run only in current working directory. - -@item -R -Commit directories recursively. This is on by default. -@end table - -Two special options are available: - -@table @code -@item -b -The -b option makes the tag a branch tag -(@pxref{Branches}), allowing concurrent, isolated -development. This is most useful for creating a patch -to a previously released software distribution. - -@item -d -Delete a tag. - -If you use @samp{cvs tag -d symbolic_tag}, the symbolic -tag you specify is deleted instead of being added. -Warning: Be very certain of your ground before you -delete a tag; doing this permanently discards some -historical information, which may later turn out to -be valuable. -@end table - -@ignore -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@c @node tag examples -@appendixsubsec tag examples - -@c -- FIXME -@end ignore - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node update -@appendixsec update---Bring work tree in sync with repository -@cindex Update (subcommand) - -@itemize @bullet -@item -update [-AdflPpR] [-d] [-r tag|-D date] files@dots{} -@item -Requires: repository, working directory. -@item -Changes: working directory. -@end itemize - -After you've run checkout to create your private copy -of source from the common repository, other developers -will continue changing the central source. From time -to time, when it is convenient in your development -process, you can use the @code{update} command from -within your working directory to reconcile your work -with any revisions applied to the source repository -since your last checkout or update. - -@menu -* update options:: update options -* update output:: update output -* update examples:: update examples -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node update options -@appendixsubsec update options - -These standard options are available with @code{update} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -D date -Use the most recent revision no later than @var{date}. -This option is sticky, and implies @samp{-P}. - -@item -f -Only useful with the @samp{-D @var{date}} or @samp{-r -@var{tag}} flags. If no matching revision is found, -retrieve the most recent revision (instead of ignoring -the file). - -@item -k @var{kflag} -Process @sc{rcs} keywords according to @var{kflag}. See -co(1). This option is sticky; future updates of -this file in this working directory will use the same -@var{kflag}. The @code{status} command can be viewed -to see the sticky options. @xref{status}. - -@item -l -Local; run only in current working directory. @xref{Recursive behavior}. - -@item -P -Prune empty directories. - -@item -p -Pipe files to the standard output. - -@item -R -Operate recursively. This is on by default. -@xref{Recursive behavior}. - -@item -r tag -Retrieve revision @var{tag}. This option is sticky, -and implies @samp{-P}. -@end table - -@need 800 -These special options are also available with -@code{update}. - -@table @code -@item -A -Reset any sticky tags, dates, or @samp{-k} options. -(If you get a working copy of a file by using one of -the @samp{-r}, @samp{-D}, or @samp{-k} options, @sc{cvs} -remembers the corresponding tag, date, or @var{kflag} and -continues using it on future updates; use the @samp{-A} -option to make @sc{cvs} forget these specifications, and -retrieve the head revision of the file). - -@item -d -Create any directories that exist in the repository if -they're missing from the working directory. Normally, -@code{update} acts only on directories and files that -were already enrolled in your working directory. - -This is useful for updating directories that were -created in the repository since the initial checkout; -but it has an unfortunate side effect. If you -deliberately avoided certain directories in the -repository when you created your working directory -(either through use of a module name or by listing -explicitly the files and directories you wanted on the -command line), then updating with @samp{-d} will create -those directories, which may not be what you want. - -@item -I @var{name} -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. - -@item -W@var{spec} -Specify file names that should be filtered during -update. You can use this option repeatedly. - -@var{spec} can be a file name pattern of the same type -that you can specify in the @file{.cvswrappers} -file. @xref{Wrappers}. - -@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 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: -@samp{-j@var{Symbolic_Tag}:@var{Date_Specifier}}. - -@xref{Merging}. - -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node update output -@appendixsubsec update output - -@code{update} keeps you informed of its progress by -printing a line for each file, preceded by one -character indicating the status of the file: - -@table @code -@item U @var{file} -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. - -@item A @var{file} -The file has been added to your private copy of the -sources, and will be added to the source repository -when you run @code{commit} on the file. This is a -reminder to you that the file needs to be committed. - -@item R @var{file} -The file has been removed from your private copy of the -sources, and will be removed from the source repository -when you run @code{commit} on the file. This is a -reminder to you that the file needs to be committed. - -@item M @var{file} -The file is modified in your working directory. - -@samp{M} can indicate one of two states for a file -you're working on: either there were no modifications -to the same file in the repository, so that your file -remains as you last saw it; or there were modifications -in the repository as well as in your copy, but they -were merged successfully, without conflict, in your -working directory. - -@sc{cvs} will print some messages if it merges your work, -and a backup copy of your working file (as it looked -before you ran @code{update}) will be made. The exact -name of that file is printed while @code{update} runs. - -@item C @var{file} -A conflict was detected while trying to merge your -changes to @var{file} with changes from the source -repository. @var{file} (the copy in your working -directory) is now the output of the rcsmerge(1) command -on the two revisions; an unmodified copy of your file -is also in your working directory, with the name -@file{.#@var{file}.@var{revision}} where @var{revision} -is the @sc{rcs} revision that your modified file started -from. (Note that some systems automatically purge -files that begin with @file{.#} if they have not been -accessed for a few days. If you intend to keep a copy -of your original file, it is a very good idea to rename -it.) - -@item ? @var{file} -@var{file} is in your working directory, but does not -correspond to anything in the source repository, and is -not in the list of files for @sc{cvs} to ignore (see the -description of the @samp{-I} option, and -@pxref{cvsignore}). - -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. -@end table - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node update examples -@appendixsubsec update examples - -The following line will display all files which are not -up-to-date without actually change anything in your -working directory. It can be used to check what has -been going on with the project. - -@example -$ cvs -n -q update -@end example - -@c --------------------------------------------------------------------- -@node Administrative files -@appendix Reference manual for the Administrative files -@cindex Administrative files (reference) -@cindex Files, reference manual -@cindex Reference manual (files) -@cindex CVSROOT (file) - -Inside the repository, in the directory -@file{$CVSROOT/CVSROOT}, there are a number of -supportive files for @sc{cvs}. You can use @sc{cvs} in a limited -fashion without any of them, but if they are set up -properly they can help make life easier. - -The most important of these files is the @file{modules} -file, which defines the modules inside the repository. - -@menu -* modules:: Defining modules -* Wrappers:: Treat directories as files -* commit files:: The commit support files -* commitinfo:: Pre-commit checking -* editinfo:: Specifying how log messages are created -* loginfo:: Where should log messages be sent? -* rcsinfo:: Templates for the log messages -* cvsignore:: Ignoring files via cvsignore -* history file:: History information -* Setting up:: Setting up the repository -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node modules -@appendixsec The modules file -@cindex Modules (admin file) -@cindex Defining modules (reference manual) - -The @file{modules} file records your definitions of -names for collections of source code. @sc{cvs} will use -these definitions if you create a file with the right -format in @file{$CVSROOT/CVSROOT/modules,v}. The -mkmodules(1) command should be run whenever the modules -file changes, so that the appropriate files can be -generated (depending on how you have configured @sc{cvs} -operation). - -To allow convenient editing of the @file{modules} file -itself, the file should include an entry like the -following (where @var{localbin} represents the -directory where your site installs programs like -mkmodules(1)): - -@example -modules -i /@var{localbin}/mkmodules CVSROOT modules -@end example - -@noindent -This defines the name @samp{modules} as the module name -for the file itself, so that you can use - -@example -$ cvs checkout modules -@end example - -@noindent -to get a copy of the file that you can edit. You should define -similar module entries for the other configuration -files described in this appendix, except -@file{history}). - -The @file{modules} file may contain blank lines and -comments (lines beginning with @samp{#}) as well as -module definitions. Long lines can be continued on the -next line by specifying a backslash (@samp{\}) as the -last character on the line. - -A module definition is a single line of the -@file{modules} file, in either of two formats. In both -cases, @var{mname} represents the symbolic module name, -and the remainder of the line is its definition. - -@table @code -@item @var{mname} -a @var{aliases}@dots{} -This represents the simplest way of defining a module -@var{mname}. The @samp{-a} flags the definition as a -simple alias: @sc{cvs} will treat any use of @var{mname} (as -a command argument) as if the list of names -@var{aliases} had been specified instead. -@var{aliases} may contain either other module names or -paths. When you use paths in aliases, @code{checkout} -creates all intermediate directories in the working -directory, just as if the path had been specified -explicitly in the @sc{cvs} arguments. - -@item @var{mname} [ options ] @var{dir} [ @var{files}@dots{} ] [ &@var{module}@dots{} ] -In the simplest case, this form of module definition -reduces to @samp{@var{mname} @var{dir}}. This defines -all the files in directory @var{dir} as module mname. -@var{dir} is a relative path (from @code{$CVSROOT}) to a -directory of source in the source repository. In this -case, on checkout, a single directory called -@var{mname} is created as a working directory; no -intermediate directory levels are used by default, even -if @var{dir} was a path involving several directory -levels. - -By explicitly specifying files in the module definition -after @var{dir}, you can select particular files from -directory @var{dir}. The sample definition for -@samp{modules} is an example of a module defined with a -single file from a particular directory. Here is -another example: - -@example -m4test unsupported/gnu/m4 foreach.m4 forloop.m4 -@end example - -@noindent -With this definition, executing @samp{cvs checkout -m4test} will create a single working directory -@file{m4test} containing the two files listed, which -both come from a common directory several levels deep -in the @sc{cvs} source repository. - -A module definition can refer to other modules by -including @samp{&@var{module}} in its definition. -@code{checkout} creates a subdirectory for each such -module, in your working directory. -@c -- Nope. "in your working directory" is wrong. What -@c -- is right? - -@table @code -@item -d @var{name} -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 -module are committed. @var{prog} runs with a single -argument, the full pathname of the affected directory -in a source repository. The @file{commitinfo}, -@file{loginfo}, and @file{editinfo} files provide other -ways to call a program on commit. - -@cindex Checkout program -@item -o @var{prog} -Specify a program @var{prog} to run whenever files in a -module are checked out. @var{prog} runs with a single -argument, the module name. - -@cindex Status of a module -@cindex Module status -@item -s @var{status} -Assign a status to the module. When the module file is -printed with @samp{cvs checkout -s} the modules are -sorted according to primarily module status, and -secondarily according to the module name. This option -has no other meaning. You can use this option for -several things besides status: for instance, list the -person that is responsible for this module. - -@cindex Tag program -@item -t @var{prog} -Specify a program @var{prog} to run whenever files in a -module are tagged with @code{rtag}. @var{prog} runs -with two arguments: the module name and the symbolic -tag specified to @code{rtag}. There is no way to -specify a program to run when @code{tag} is executed. - -@cindex Update program -@item -u @var{prog} -Specify a program @var{prog} to run whenever @samp{cvs -update} is executed from the top-level directory of the -checked-out module. @var{prog} runs with a single -argument, the full path to the source repository for -this module. -@end table -@end table - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Wrappers -@appendixsec The cvswrappers file -@cindex cvswrappers (admin file) -@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. - -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. - -The @file{cvswrappers} also specifies the merge -methodology that should be used when the file is -updated, that is should a MERGE or a straight COPY of -the diferences be used when checking into the -repository. - -The basic format of the file @file{cvswrappers} is given as -such: - -@example -wildcard [option value][option value]... - -where option is one of --f from cvs filter value: path tofilter --t to cvs filter value: path to filter --m update methodology value: MERGE or COPY - -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' -@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 -checking the file into the repository. The file should -be filtered though the @file{uncom} 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). - -@noindent -The @file{comb} 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, -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. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node commit files -@appendixsec The commit support files -@cindex Commit files - -The @samp{-i} flag in the @file{modules} file can be -used to run a certain program whenever files are -committed (@pxref{modules}). The files described in -this section provide other, more flexible, ways to run -programs whenever something is committed. - -There are three kind of programs that can be run on -commit. They are specified in files in the repository, -as described below. The following table summarizes the -file names and the purpose of the corresponding -programs. - -@table @file -@item commitinfo -The program is responsible for checking that the commit -is allowed. If it exits with a non-zero exit status -the commit will be aborted. - -@item editinfo -The specified program is used to edit the log message, -and possibly verify that it contains all required -fields. This is most useful in combination with the -@file{rcsinfo} file, which can hold a log message -template (@pxref{rcsinfo}). - -@item loginfo -The specified program is called when the commit is -complete. It receives the log message and some -additional information and can store the log message in -a file, or mail it to appropriate persons, or maybe -post it to a local newsgroup, or@dots{} Your -imagination is the limit! -@end table - -@menu -* syntax:: The common syntax -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node syntax -@appendixsubsec The common syntax -@cindex Info files (syntax) -@cindex Syntax of info files -@cindex Common syntax of info files - -The four files @file{commitinfo}, @file{loginfo}, -@file{rcsinfo} and @file{editinfo} all have a common -format. The purpose of the files are described later -on. The common syntax is described here. - -Each line contains the following: -@itemize @bullet -@item -A regular expression - -@item -A whitespace separator---one or more spaces and/or tabs. - -@item -A file name or command-line template. -@end itemize - -@noindent -Blank lines are ignored. Lines that start with the -character @samp{#} are treated as comments. Long lines -unfortunately can @emph{not} be broken in two parts in -any way. - -The first regular expression that matches the current -directory name in the repository is used. The rest of the line -is used as a file name or command-line as appropriate. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node commitinfo -@appendixsec Commitinfo -@cindex Commitinfo -@cindex Checking commits -@cindex Precommit checking - -The @file{commitinfo} file defines programs to execute -whenever @samp{cvs commit} is about to execute. These -programs are used for pre-commit checking to verify -that the modified, added and removed files are really -ready to be committed. This could be used, for -instance, to verify that the changed files conform to -to your site's standards for coding practice. - -As mentioned earlier, each line in the -@file{commitinfo} file consists of a regular expression -and a command-line template. The template can include -a program name and any number of arguments you wish to -supply to it. The full path to the current source -repository is appended to the template, followed by the -file names of any files involved in the commit (added, -removed, and modified files). - -The first line with a regular expression matching the -relative path to the module will be used. If the -command returns a non-zero exit status the commit will -be aborted. - -@cindex DEFAULT in commitinfo -If the repository name does not match any of the -regular expressions in this file, the @samp{DEFAULT} -line is used, if it is specified. - -@cindex ALL in commitinfo -All occurances of the name @samp{ALL} appearing as a -regular expression are used in addition to the first -matching regular expression or the name @samp{DEFAULT}. - -Note: when @sc{CVS} is accessing a remote repository, -@file{commitinfo} will be run on the @emph{remote} -(i.e., server) side, not the client side (@pxref{Remote -repositories}). - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node editinfo -@appendixsec Editinfo -@cindex Editinfo -@cindex Editor, specifying per module -@cindex Per-module editor -@cindex Log messages, editing - -If you want to make sure that all log messages look the -same way, you can use the @file{editinfo} file to -specify a program that is used to edit the log message. -This program could be a custom-made editor that always -enforces a certain style of the log message, or maybe a -simple shell script that calls an editor, and checks -that the entered message contains the required fields. - -If no matching line is found in the @file{editinfo} -file, the editor specified in the environment variable -@code{$CVSEDITOR} is used instead. If that variable is -not set, then the environment variable @code{$EDITOR} -is used instead. If that variable is not -set a precompiled default, normally @code{vi}, will be -used. - -The @file{editinfo} file is often most useful together -with the @file{rcsinfo} file, which can be used to -specify a log message template. - -Each line in the @file{editinfo} file consists of a -regular expression and a command-line template. The -template must include a program name, and can include -any number of arguments. The full path to the current -log message template file is appended to the template. - -One thing that should be noted is that the @samp{ALL} -keyword is not supported. If more than one matching -line is found, the first one is used. This can be -useful for specifying a default edit script in a -module, and then overriding it in a subdirectory. - -@cindex DEFAULT in editinfo -If the repository name does not match any of the -regular expressions in this file, the @samp{DEFAULT} -line is used, if it is specified. - -If the edit script exits with a non-zero exit status, -the commit is aborted. - -Note: when @sc{CVS} is accessing a remote repository, -@file{editinfo} will be run on the @emph{remote} -(i.e., server) side, not the client side (@pxref{Remote -repositories}). - -@menu -* editinfo example:: Editinfo example -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node editinfo example -@appendixsubsec Editinfo example - -The following is a little silly example of a -@file{editinfo} file, together with the corresponding -@file{rcsinfo} file, the log message template and an -editor script. We begin with the log message template. -We want to always record a bug-id number on the first -line of the log message. The rest of log message is -free text. The following template is found in the file -@file{/usr/cvssupport/tc.template}. - -@example -BugId: -@end example - -The script @file{/usr/cvssupport/bugid.edit} is used to -edit the log message. - -@example -#!/bin/sh -# -# bugid.edit filename -# -# Call $EDITOR on FILENAME, and verify that the -# resulting file contains a valid bugid on the first -# line. -if [ "x$EDITOR" = "x" ]; then EDITOR=vi; fi -if [ "x$CVSEDITOR" = "x" ]; then CVSEDITOR=$EDITOR; fi -$CVSEDITOR $1 -until head -1|grep '^BugId:[ ]*[0-9][0-9]*$' < $1 -do echo -n "No BugId found. Edit again? ([y]/n)" - read ans - case $@{ans@} in - n*) exit 1;; - esac - $CVSEDITOR $1 -done -@end example - -The @file{editinfo} file contains this line: - -@example -^tc /usr/cvssupport/bugid.edit -@end example - -The @file{rcsinfo} file contains this line: - -@example -^tc /usr/cvssupport/tc.template -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node loginfo -@appendixsec Loginfo -@cindex Loginfo -@cindex Storing log messages -@cindex Mailing log messages -@cindex Distributing log messages -@cindex Log messages - -The @file{loginfo} file is used to control where -@samp{cvs commit} log information is 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 @code{$CVSROOT}. If a match is found, then -the remainder of the line is a filter program that -should expect log information on its standard input. - -The filter program may use one and only one % modifier -(a la printf). If @samp{%s} is specified in the filter -program, a brief title is included (enclosed in single -quotes) showing the modified file names. - -If the repository name does not match any of the -regular expressions in this file, the @samp{DEFAULT} -line is used, if it is specified. - -All occurances of the name @samp{ALL} appearing as a -regular expression are used in addition to the first -matching regular expression or @samp{DEFAULT}. - -The first matching regular expression is used. - -@xref{commit files}, for a description of the syntax of -the @file{loginfo} file. - -Note: when @sc{CVS} is accessing a remote repository, -@file{loginfo} will be run on the @emph{remote} -(i.e., server) side, not the client side (@pxref{Remote -repositories}). - -@menu -* loginfo example:: Loginfo example -@end menu - -@c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -@node loginfo example -@appendixsubsec Loginfo example - -The following @file{loginfo} file, together with the -tiny shell-script below, appends all log messages -to the file @file{$CVSROOT/CVSROOT/commitlog}, -and any commits to the administrative files (inside -the @file{CVSROOT} directory) are also logged in -@file{/usr/adm/cvsroot-log} and mailed to @t{ceder}. - -@example -ALL /usr/local/bin/cvs-log $CVSROOT/CVSROOT/commitlog -^CVSROOT Mail -s %s ceder -^CVSROOT /usr/local/bin/cvs-log /usr/adm/cvsroot-log -@end example - -The shell-script @file{/usr/local/bin/cvs-log} looks -like this: - -@example -#!/bin/sh -(echo "-----------------------------------------------------------------"; - echo -n $USER" "; - date; - echo; - sed '1s+'$@{CVSROOT@}'++') >> $1 -@end example - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node rcsinfo -@appendixsec Rcsinfo -@cindex Rcsinfo -@cindex Form for log message -@cindex Log message template -@cindex Template for log message - -The @file{rcsinfo} file can be used to specify a form to -edit when filling out the commit log. The -@file{rcsinfo} file has a syntax similar to the -@file{editinfo}, @file{commitinfo} and @file{loginfo} -files. @xref{syntax}. Unlike the other files the second -part is @emph{not} a command-line template. Instead, -the part after the regular expression should be a full pathname to -a file containing the log message template. - -If the repository name does not match any of the -regular expressions in this file, the @samp{DEFAULT} -line is used, if it is specified. - -All occurances of the name @samp{ALL} appearing as a -regular expression are used in addition to the first -matching regular expression or @samp{DEFAULT}. - -The log message template will be used as a default log -message. If you specify a log message with @samp{cvs -commit -m @var{message}} or @samp{cvs commit -f -@var{file}} that log message will override the -template. - -@xref{editinfo example}, for an example @file{rcsinfo} -file. - -Note: when @sc{CVS} is accessing a remote repository, -@file{rcsinfo} will be run on the @emph{remote} -(i.e., server) side, not the client side (@pxref{Remote -repositories}). - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node cvsignore -@appendixsec Ignoring files via cvsignore -@cindex Cvsignore, global -@cindex Global cvsignore -@cindex Ignoring files -@c -- This chapter should maybe be moved to the -@c tutorial part of the manual? - -There are certain file names that frequently occur -inside your working copy, but that you don't want to -put under @sc{cvs} control. Examples are all the object -files that you get while you compile your sources. -Normally, when you run @samp{cvs update}, it prints a -line for each file it encounters that it doesn't know -about (@pxref{update output}). - -@sc{cvs} has a list of files (or sh(1) file name patterns) -that it should ignore while running @code{update}, -@code{import} and @code{release}. -@c -- Are those the only three commands affected? -This list is constructed in the following way. - -@itemize @bullet -@item -The list is initialized to the following file name -patterns: - -@cindex Ignored files -@cindex Automatically ignored files -@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 - -@item -The per-repository list in -@file{$CVSROOT/CVSROOT/cvsignore} is appended to -the list, if that file exists. - -@item -The per-user list in @file{.cvsignore} in your home -directory is appended to the list, if it exists. - -@item -Any entries in the environment variable -@code{$CVSIGNORE} is appended to the list. - -@item -Any @samp{-I} options given to @sc{cvs} is appended. - -@item -As @sc{cvs} traverses through your directories, the contents -of any @file{.cvsignore} will be appended to the list. -The patterns found in @file{.cvsignore} are only valid -for the directory that contains them, not for -any sub-directories. -@end itemize - -In any of the 5 places listed above, a single -exclamation mark (@samp{!}) clears the ignore list. -This can be used if you want to store any file which -normally is ignored by @sc{cvs}. - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node history file -@appendixsec The history file -@cindex History file -@cindex Log information, saving - -The file @file{$CVSROOT/CVSROOT/history} is used -to log information for the @code{history} command -(@pxref{history}). This file must be created to turn -on logging. This is done automatically if the -@code{cvsinit} script is used to set up the repository. - -The file format of the @file{history} file is -unfortunately not yet documented anywhere, but it is -fairly easy to understand most of it. -@c -- document it here? - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Setting up -@appendixsec Setting up the repository -@cindex Repository, setting up -@cindex Creating a repository -@cindex Setting up a repository - -When you install @sc{cvs} for the first time, you should -follow the instructions in the @file{INSTALL} file to -set up the repository. - -If you want to set up another repository, the easiest -way to get a reasonable set of working administrative -files is to run the @code{cvsinit} shell script. It -will set up an empty repository in the directory -defined by the environment variable @code{$CVSROOT}. -(@code{cvsinit} is careful to never overwrite any -existing files in the repository, so no harm is done if -you run @code{cvsinit} on an already set-up -repository. In fact, running it on an already set-up -repository is the best way to update the various -scripts from the @samp{contrib} directory.) - -@c --------------------------------------------------------------------- -@node Environment variables -@appendix All environment variables which affect CVS -@cindex Environment variables -@cindex Reference manual for variables - -This is a complete list of all environment variables -that affect @sc{cvs}. - -@table @code -@cindex CVSIGNORE -@item $CVSIGNORE -A whitespace-separated list of file name patterns that -@sc{cvs} should ignore. @xref{cvsignore}. - -@item $CVSWRAPPERS -A whitespace-separated list of file name patterns that -@sc{cvs} should treat as wrappers. @xref{Wrappers}. - -@cindex CVSREAD -@item $CVSREAD -If this is set, @code{checkout} and @code{update} will -try hard to make the files in your working directory -read-only. When this is not set, the default behavior -is to permit modification of your working files. - -@cindex CVSROOT -@item $CVSROOT -Should contain the full pathname to the root of the @sc{cvs} -source repository (where the @sc{rcs} history files are -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{}} 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 -@item $EDITOR -@itemx $CVSEDITOR -Specifies the program to use for recording log messages -during commit. If not set, the default is -@samp{/usr/ucb/vi}. @code{$CVSEDITOR} overrides -@code{$EDITOR}. @code{$CVSEDITOR} does not exist in -@sc{cvs} 1.3, but the next release will probably -include it. - -@cindex PATH -@item $PATH -If @code{$RCSBIN} is not set, and no path is compiled -into @sc{cvs}, it will use @code{$PATH} to try to find all -programs it uses. - -@cindex RCSBIN -@item $RCSBIN -Specifies the full pathname of the location of @sc{rcs} programs, -such as co(1) and ci(1). If not set, a compiled-in -value is used, or your @code{$PATH} is searched. -@end table - -@sc{cvs} is a front-end to @sc{rcs}. The following environment -variables affect @sc{rcs}: - -@table @code -@cindex LOGNAME -@item $LOGNAME -@cindex USER -@itemx $USER -If set, they affect who @sc{rcs} thinks you are. If you -have trouble checking in files it might be because your -login name differs from the setting of e.g. -@code{$LOGNAME}. - -@cindex RCSINIT -@item $RCSINIT -Options prepended to the argument list, separated by -spaces. A backslash escapes spaces within an option. -The @code{$RCSINIT} options are prepended to the -argument lists of most @sc{rcs} commands. - -@cindex TMPDIR -@item $TMPDIR -@cindex TMP -@itemx $TMP -@cindex TEMP -@itemx $TEMP -Name of the temporary directory. The environment -variables are inspected in the order they appear above -and the first value found is taken; if none of them are -set, a host-dependent default is used, typically -@file{/tmp}. -@end table - -@c --------------------------------------------------------------------- -@node Troubleshooting -@appendix Troubleshooting - -@menu -* Magic branch numbers:: Magic branch numbers -@end menu - -@ignore -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@c @node Bad administrative files -@appendixsec Bad administrative files - -@c -- Give hints on how to fix them -@end ignore - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Magic branch numbers -@appendixsec Magic branch numbers - -Externally, branch numbers consist of an odd number of -dot-separated decimal integers. @xref{Revision -numbers}. That is not the whole truth, however. For -efficiency reasons @sc{cvs} sometimes inserts an extra 0 -in the second rightmost position (1.2.3 becomes -1.2.0.3, 8.9.10.11.12 becomes 8.9.10.11.0.12 and so -on). - -@sc{cvs} does a pretty good job at hiding these so -called magic branches, but in at least four places the -hiding is incomplete. - -@itemize @bullet -@item -The magic branch can appear in the output from -@code{cvs status} in vanilla @sc{cvs} 1.3. This is -fixed in @sc{cvs} 1.3-s2. - -@item -The magic branch number appears in the output from -@code{cvs log}. This is much harder to fix, since -@code{cvs log} runs @code{rlog} (which is part of the -@sc{rcs} distribution), and modifying @code{rlog} to -know about magic branches would probably break someone's -habits (if they use branch 0 for their own purposes). - -@item -You cannot specify a symbolic branch name to @code{cvs log}. - -@item -You cannot specify a symbolic branch name to @code{cvs -admin}. - -@end itemize - -You can use the @code{admin} command to reassign a -symbolic name to a branch the way @sc{rcs} expects it -to be. If @code{R4patches} is assigned to the branch -1.4.2 (magic branch number 1.4.0.2) in file -@file{numbers.c} you can do this: - -@example -$ cvs admin -NR4patches:1.4.2 numbers.c -@end example - -It only works if at least one revision is already -committed on the branch. Be very careful so that you -do not assign the tag to the wrong number. (There is -no way to see how the tag was assigned yesterday). - -@c --------------------------------------------------------------------- -@node Copying -@appendix GNU GENERAL PUBLIC LICENSE -@c @include gpl.texinfo - -@c --------------------------------------------------------------------- -@node Index -@unnumbered Index -@cindex Index - -@printindex cp - -@summarycontents - -@contents - -@bye - -Local Variables: -fill-column: 55 -End: diff --git a/gnu/usr.bin/cvs/doc/cvsclient.texi b/gnu/usr.bin/cvs/doc/cvsclient.texi deleted file mode 100644 index 9c8f326..0000000 --- a/gnu/usr.bin/cvs/doc/cvsclient.texi +++ /dev/null @@ -1,673 +0,0 @@ -\input texinfo - -@setfilename cvsclient.info - -@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 - -@node Goals -@chapter Goals - -@itemize @bullet -@item -Do not assume any access to the repository other than via this protocol. -It does not depend on NFS, rdist, etc. - -@item -Providing a reliable transport is outside this protocol. It is expected -that it runs over TCP, UUCP, etc. - -@item -Security and authentication are handled outside this protocol (but see -below about @samp{cvs kserver}). - -@item -This might be a first step towards adding transactions to CVS (i.e. a -set of operations is either executed atomically or none of them is -executed), improving the locking, or other features. The current server -implementation is a long way from being able to do any of these -things. The protocol, however, is not known to contain any defects -which would preclude them. - -@item -The server never has to have any CVS locks in place while it is waiting -for communication with the client. This makes things robust in the face -of flaky networks. - -@item -Data is transferred in large chunks, which is necessary for good -performance. In fact, currently the client uploads all the data -(without waiting for server responses), and then waits for one server -response (which consists of a massive download of all the data). There -may be cases in which it is better to have a richer interraction, but -the need for the server to release all locks whenever it waits for the -client makes it complicated. -@end itemize - -@node Notes -@chapter Notes on the Current Implementation - -The client is built in to the normal @code{cvs} program, triggered by a -@code{CVSROOT} variable containing a colon, for example -@code{cygnus.com:/rel/cvsfiles}. - -The client stores what is stored in checked-out directories (including -@file{CVS}). The way these are stored is totally compatible with -standard CVS. The server requires no storage other than the repository, -which also is totally compatible with standard CVS. - -The server is started by @code{cvs server}. There is no particularly -compelling reason for this rather than making it a separate program -which shares a lot of sources with cvs. - -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 over a slow link (i.e. the network is -slower than the server can generate the data). Avoiding this is -tricky because of the goal of not having the server block on the -network when it has locks open (this could lock the repository for -hours if things are running smoothly or longer if not). 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. The two-pass design appears to be the more elegant of the -two (it actually reduces the amount of time that locks need to be in -place), but people have expressed concerns about whether it would be -slower (because it traverses the repository twice). It is not clear -whether this is a real problem (looking for whether a file needs to be -updated and actually checking it out are done separately already), but -I don't think anyone has investigated carefully. One hybrid approach -which avoids the problem with merges would be to start out in one-pass -mode and switch to two-pass mode if data is backing up--but this -complicates the code and should be undertaken only if the pure -two-pass design is shown to be flawed. - -@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. - -@node Protocol Notes -@chapter Notes on the Protocol - -A number of enhancements are possible: - -@itemize @bullet -@item -The @code{Modified} request could be speeded up by sending diffs rather -than entire files. The client would need some way to keep the version -of the file which was originally checked out, which would double client -disk space requirements or require coordination with editors (e.g. maybe -it could use emacs numbered backups). This would also allow local -operation of @code{cvs diff} without arguments. - -@item -Have the client keep a copy of some part of the repository. This allows -all of @code{cvs diff} and large parts of @code{cvs update} and -@code{cvs ci} to be local. The local copy could be made consistent with -the master copy at night (but if the master copy has been updated since -the latest nightly re-sync, then it would read what it needs to from the -master). - -@item -Provide encryption using kerberos. - -@item -The current procedure for @code{cvs update} is highly sub-optimal if -there are many modified files. One possible alternative would be to -have the client send a first request without the contents of every -modified file, then have the server tell it what files it needs. Note -the server needs to do the what-needs-to-be-updated check twice (or -more, if changes in the repository mean it has to ask the client for -more files), because it can't keep locks open while waiting for the -network. Perhaps this whole thing is irrelevant if client-side -repositories are implemented, and the rcsmerge is done by the client. -@end itemize - -@node Protocol -@chapter The CVS client/server protocol - -@menu -* Entries Lines:: -* Modes:: -* Requests:: -* Responses:: -* Example:: -@end menu - -@node Entries Lines -@section Entries Lines - -Entries lines are transmitted as: - -@example -/ @var{name} / @var{version} / @var{conflict} / @var{options} / @var{tag_or_date} -@end example - -@var{tag_or_date} is either @samp{T} @var{tag} or @samp{D} @var{date} -or empty. If it is followed by a slash, anything after the slash -shall be silently ignored. - -@var{version} can be empty, or start with @samp{0} or @samp{-}, for no -user file, new user file, or user file to be removed, respectively. - -@var{conflict}, if it starts with @samp{+}, indicates that the file had -conflicts in it. The rest of @var{conflict} is @samp{=} if the -timestamp matches the file, or anything else if it doesn't. If -@var{conflict} does not start with a @samp{+}, it is silently ignored. - -@node Modes -@section Modes - -A mode is any number of repetitions of - -@example -@var{mode-type} = @var{data} -@end example - -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. - -@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 -consists of alphanumeric characters, where @samp{r} means read, @samp{w} -means write, @samp{x} means execute, and unrecognized letters are -silently ignored. - -@node Requests -@section Requests - -File contents (noted below as @var{file transmission}) can be sent in -one of two forms. The simpler form is a number of bytes, followed by a -newline, followed by the specified number of bytes of file contents. -These are the entire contents of the specified file. Second, if both -client and server support @samp{gzip-file-contents}, a @samp{z} may -precede the length, and the `file contents' sent are actually compressed -with @samp{gzip}. The length specified is that of the compressed -version of the file. - -In neither case are the file content followed by any additional data. -The transmission of a file will end with a newline iff that file (or its -compressed form) ends with a newline. - -@table @code -@item Root @var{pathname} \n -Response expected: no. -Tell the server which @code{CVSROOT} to use. - -@item Valid-responses @var{request-list} \n -Response expected: no. -Tell the server what responses the client will accept. -request-list is a space separated list of tokens. - -@item valid-requests \n -Response expected: yes. -Ask the server to send back a @code{Valid-requests} response. - -@item Repository @var{repository} \n -Response expected: no. Tell the server what repository to use. This -should be a directory name from a previous server response. Note that -this both gives a default for @code{Entry } and @code{Modified } and -also for @code{ci} and the other commands; normal usage is to send a -@code{Repository } for each directory in which there will be an -@code{Entry } or @code{Modified }, and then a final @code{Repository } -for the original directory, then the command. - -@item Directory @var{local-directory} \n -Additional data: @var{repository} \n. This is like @code{Repository}, -but the local name of the directory may differ from the repository name. -If the client uses this request, it affects the way the server returns -pathnames; see @ref{Responses}. @var{local-directory} is relative to -the top level at which the command is occurring (i.e. the last -@code{Directory} or @code{Repository} which is sent before the command). - -@item Max-dotdot @var{level} \n -Tell the server that @var{level} levels of directories above the -directory which @code{Directory} requests are relative to will be -needed. For example, if the client is planning to use a -@code{Directory} request for @file{../../foo}, it must send a -@code{Max-dotdot} request with a @var{level} of at least 2. -@code{Max-dotdot} must be sent before the first @code{Directory} -request. - -@item Static-directory \n -Response expected: no. Tell the server that the directory most recently -specified with @code{Repository} or @code{Directory} should not have -additional files checked out unless explicitly requested. The client -sends this if the @code{Entries.Static} flag is set, which is controlled -by the @code{Set-static-directory} and @code{Clear-static-directory} -responses. - -@item Sticky @var{tagspec} \n -Response expected: no. Tell the server that the directory most recently -specified with @code{Repository} has a sticky tag or date @var{tagspec}. -The first character of @var{tagspec} is @samp{T} for a tag, or @samp{D} -for a date. The remainder of @var{tagspec} contains the actual tag or -date. - -@item Checkin-prog @var{program} \n -Response expected: no. Tell the server that the directory most recently -specified with @code{Directory} has a checkin program @var{program}. -Such a program would have been previously set with the -@code{Set-checkin-prog} response. - -@item Update-prog @var{program} \n -Response expected: no. Tell the server that the directory most recently -specified with @code{Directory} has an update program @var{program}. -Such a program would have been previously set with the -@code{Set-update-prog} response. - -@item Entry @var{entry-line} \n -Response expected: no. Tell the server what version of a file is on the -local machine. The name in @var{entry-line} is a name relative to the -directory most recently specified with @code{Repository}. If the user -is operating on only some files in a directory, @code{Entry} requests -for only those files need be included. If an @code{Entry} request is -sent without @code{Modified}, @code{Unchanged}, or @code{Lost} for that -file the meaning depends on whether @code{UseUnchanged} has been sent; -if it has been it means the file is lost, if not it means the file is -unchanged. - -@item Modified @var{filename} \n -Response expected: no. Additional data: mode, \n, file transmission. -Send the server a copy of one locally modified file. @var{filename} is -relative to the most recent repository sent with @code{Repository}. If -the user is operating on only some files in a directory, only those -files need to be included. This can also be sent without @code{Entry}, -if there is no entry for the file. - -@item Lost @var{filename} \n -Response expected: no. Tell the server that @var{filename} no longer -exists. The name is relative to the most recent repository sent with -@code{Repository}. This is used for any case in which @code{Entry} is -being sent but the file no longer exists. If the client has issued the -@code{UseUnchanged} request, then this request is not used. - -@item Unchanged @var{filename} \n -Response expected: no. Tell the server that @var{filename} has not been -modified in the checked out directory. The name is relative to the most -recent repository sent with @code{Repository}. This request can only be -issued if @code{UseUnchanged} has been sent. - -@item UseUnchanged \n -Response expected: no. Tell the server that the client will be -indicating unmodified files with @code{Unchanged}, and that files for -which no information is sent are nonexistent on the client side, not -unchanged. This is necessary for correct behavior since only the server -knows what possible files may exist, and thus what files are -nonexistent. - -@item Argument @var{text} \n -Response expected: no. -Save argument for use in a subsequent command. Arguments -accumulate until an argument-using command is given, at which point -they are forgotten. - -@item Argumentx @var{text} \n -Response expected: no. Append \n followed by text to the current -argument being saved. - -@item Global_option @var{option} \n -Transmit one of the global options @samp{-q}, @samp{-Q}, @samp{-l}, -@samp{-t}, @samp{-r}, or @samp{-n}. @var{option} must be one of those -strings, no variations (such as combining of options) are allowed. For -graceful handling of @code{valid-requests}, it is probably better to -make new global options separate requests, rather than trying to add -them to this request. - -@item expand-modules \n -Response expected: yes. Expand the modules which are specified in the -arguments. Returns the data in @code{Module-expansion} responses. Note -that the server can assume that this is checkout or export, not rtag or -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 -@itemx status \n -@itemx log \n -@itemx add \n -@itemx remove \n -@itemx rdiff \n -@itemx rtag \n -@itemx import \n -@itemx admin \n -@itemx export \n -@itemx history \n -@itemx release \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 -last @code{Repository} sent specifies the working directory at the time -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. - -@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} -request. The client must issue the @code{-u} argument to @code{update} -in order to receive patches. - -@item gzip-file-contents @var{level} \n -This request asks the server to filter files it sends to the client -through the @samp{gzip} program, using the specified level of -compression. If this request is not made, the server must not do any -compression. - -This is only a hint to the server. It may still decide (for example, in -the case of very small files, or files that already appear to be -compressed) not to do the compression. Compression is indicated by a -@samp{z} preceding the file length. - -Availability of this request in the server indicates to the client that -it may compress files sent to the server, regardless of whether the -client actually uses this request. - -@item @var{other-request} @var{text} \n -Response expected: yes. -Any unrecognized request expects a response, and does not -contain any additional data. The response will normally be something like -@samp{error unrecognized request}, but it could be a different error if -a previous command which doesn't expect a response produced an error. -@end table - -When the client is done, it drops the connection. - -@node Responses -@section Responses - -After a command which expects a response, the server sends however many -of the following responses are appropriate. Pathnames are of the actual -files operated on (i.e. they do not contain @samp{,v} endings), and are -suitable for use in a subsequent @code{Repository} request. However, if -the client has used the @code{Directory} request, then it is instead a -local directory name relative to the directory in which the command was -given (i.e. the last @code{Directory} before the command). Then a -newline and a repository name (the pathname which is sent if -@code{Directory} is not used). Then the slash and the filename. For -example, for a file @file{i386.mh} which is in the local directory -@file{gas.clean/config} and for which the repository is -@file{/rel/cvsfiles/devo/gas/config}: - -@example -gas.clean/config/ -/rel/cvsfiles/devo/gas/config/i386.mh -@end example - -Any response always ends with @samp{error} or @samp{ok}. This indicates -that the response is over. - -@table @code -@item Valid-requests @var{request-list} \n -Indicate what requests the server will accept. @var{request-list} -is a space separated list of tokens. If the server supports sending -patches, it will include @samp{update-patches} in this list. The -@samp{update-patches} request does not actually do anything. - -@item Checked-in @var{pathname} \n -Additional data: New Entries line, \n. This means a file @var{pathname} -has been successfully operated on (checked in, added, etc.). name in -the Entries line is the same as the last component of @var{pathname}. - -@item New-entry @var{pathname} \n -Additional data: New Entries line, \n. Like @code{Checked-in}, but the -file is not up to date. - -@item Updated @var{pathname} \n -Additional data: New Entries line, \n, mode, \n, file transmission. A -new copy of the file is enclosed. This is used for a new revision of an -existing file, or for a new file, or for any other case in which the -local (client-side) copy of the file needs to be updated, and after -being updated it will be up to date. If any directory in pathname does -not exist, create it. - -@item Merged @var{pathname} \n -This is just like @code{Updated} and takes the same additional data, -with the one difference that after the new copy of the file is enclosed, -it will still not be up to date. Used for the results of a merge, with -or without conflicts. - -@item Patched @var{pathname} \n -This is just like @code{Updated} and takes the same additional data, -with the one difference that instead of sending a new copy of the file, -the server sends a patch produced by @samp{diff -u}. This client must -apply this patch, using the @samp{patch} program, to the existing file. -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 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 -@code{Patched}, the checksum applies to the file after being patched, -not to the patch itself. The client should compute the checksum itself, -after receiving the file or patch, and signal an error if the checksums -do not match. The checksum is the 128 bit MD5 checksum represented as -32 hex digits. This response is optional, and is only used if the -client supports it (as judged by the @code{Valid-responses} request). - -@item Copy-file @var{pathname} \n -Additional data: @var{newname} \n. Copy file @var{pathname} to -@var{newname} in the same directory where it already is. This does not -affect @code{CVS/Entries}. - -@item Removed @var{pathname} \n -The file has been removed from the repository (this is the case where -cvs prints @samp{file foobar.c is no longer pertinent}). - -@item Remove-entry @var{pathname} \n -The file needs its entry removed from @code{CVS/Entries}, but the file -itself is already gone (this happens in response to a @code{ci} request -which involves committing the removal of a file). - -@item Set-static-directory @var{pathname} \n -This instructs the client to set the @code{Entries.Static} flag, which -it should then send back to the server in a @code{Static-directory} -request whenever the directory is operated on. @var{pathname} ends in a -slash; its purpose is to specify a directory, not a file within a -directory. - -@item Clear-static-directory @var{pathname} \n -Like @code{Set-static-directory}, but clear, not set, the flag. - -@item Set-sticky @var{pathname} \n -Additional data: @var{tagspec} \n. Tell the client to set a sticky tag -or date, which should be supplied with the @code{Sticky} request for -future operations. @var{pathname} ends in a slash; its purpose is to -specify a directory, not a file within a directory. The first character -of @var{tagspec} is @samp{T} for a tag, or @samp{D} for a date. The -remainder of @var{tagspec} contains the actual tag or date. - -@item Clear-sticky @var{pathname} \n -Clear any sticky tag or date set by @code{Set-sticky}. - -@item Set-checkin-prog @var{dir} \n -Additional data: @var{prog} \n. Tell the client to set a checkin -program, which should be supplied with the @code{Checkin-prog} request -for future operations. - -@item Set-update-prog @var{dir} \n -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 M @var{text} \n -A one-line message for the user. - -@item E @var{text} \n -Same as @code{M} but send to stderr not stdout. - -@item error @var{errno-code} @samp{ } @var{text} \n -The command completed with an error. @var{errno-code} is a symbolic -error code (e.g. @code{ENOENT}); if the server doesn't support this -feature, or if it's not appropriate for this particular message, it just -omits the errno-code (in that case there are two spaces after -@samp{error}). Text is an error message such as that provided by -strerror(), or any other message the server wants to use. - -@item ok \n -The command completed successfully. -@end table - -@node Example -@section Example - -Lines beginning with @samp{c>} are sent by the client; lines beginning -with @samp{s>} are sent by the server; lines beginning with @samp{#} are -not part of the actual exchange. - -@example -c> Root /rel/cvsfiles -# In actual practice the lists of valid responses and requests would -# be longer -c> Valid-responses Updated Checked-in M ok error -c> valid-requests -s> Valid-requests Root co Modified Entry Repository ci Argument Argumentx -s> ok -# cvs co devo/foo -c> Argument devo/foo -c> co -s> Updated /rel/cvsfiles/devo/foo/foo.c -s> /foo.c/1.4/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993// -s> 26 -s> int mein () @{ abort (); @} -s> Updated /rel/cvsfiles/devo/foo/Makefile -s> /Makefile/1.2/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993// -s> 28 -s> foo: foo.c -s> $(CC) -o foo $< -s> ok -# In actual practice the next part would be a separate connection. -# Here it is shown as part of the same one. -c> Repository /rel/cvsfiles/devo/foo -# foo.c relative to devo/foo just set as Repository. -c> Entry /foo.c/1.4/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993// -c> Entry /Makefile/1.2/Mon Apr 19 15:36:47 1993 Mon Apr 19 15:36:47 1993// -c> Modified foo.c -c> 26 -c> int main () @{ abort (); @} -# cvs ci -m <log message> foo.c -c> Argument -m -c> Argument Well, you see, it took me hours and hours to find this typo and I -c> Argumentx searched and searched and eventually had to ask John for help. -c> Argument foo.c -c> ci -s> Checked-in /rel/cvsfiles/devo/foo/foo.c -s> /foo.c/1.5/ Mon Apr 19 15:54:22 CDT 1993// -s> M Checking in foo.c; -s> M /cygint/rel/cvsfiles/devo/foo/foo.c,v <-- foo.c -s> M new revision: 1.5; previous revision: 1.4 -s> M done -s> ok -@end example -@bye diff --git a/gnu/usr.bin/cvs/examples/Makefile b/gnu/usr.bin/cvs/examples/Makefile deleted file mode 100644 index 1855b78..0000000 --- a/gnu/usr.bin/cvs/examples/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# $Id: Makefile,v 1.2 1995/07/25 00:31:56 bde Exp $ - -CVSFILES= checkoutlist commitinfo cvswrappers editinfo loginfo modules \ - rcsinfo rcstemplate taginfo unwrap wrap - -EXAMPDIR = /usr/share/examples/cvs - -NOMAN = noman -NOOBJ = noobj - -all clean: - @echo -n - -install: - ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${CVSFILES} \ - ${DESTDIR}${EXAMPDIR}/examples - -.include <bsd.prog.mk> diff --git a/gnu/usr.bin/cvs/examples/checkoutlist b/gnu/usr.bin/cvs/examples/checkoutlist deleted file mode 100644 index 45ee6dc..0000000 --- a/gnu/usr.bin/cvs/examples/checkoutlist +++ /dev/null @@ -1,20 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: checkoutlist,v 1.2 1995/11/14 23:24:49 woods Exp $" -# -# The "checkoutlist" file is used to support additional version controlled -# administrative files in $CVSROOT/CVSROOT, such as template files. -# -# The first entry on a line is a filename which will be checked out from -# the corresponding RCS file in the $CVSROOT/CVSROOT directory. -# The remainder of the line is an error message to use if the file cannot -# be checked out. -# -# File format: -# -# [<whitespace>]<filename><whitespace><error message><end-of-line> -# -# comment lines begin with '#' -# -rcstemplate -wrap -unwrap diff --git a/gnu/usr.bin/cvs/examples/commitinfo b/gnu/usr.bin/cvs/examples/commitinfo deleted file mode 100644 index 3964798..0000000 --- a/gnu/usr.bin/cvs/examples/commitinfo +++ /dev/null @@ -1,27 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: commitinfo,v 1.3 1995/11/14 23:30:05 woods Exp $" -# -# The "commitinfo" file is used to control pre-commit checks. -# The filter on the right is invoked with the repository and a list -# of files to check. A non-zero exit of the filter program will -# cause the commit to be aborted. -# -# The first entry on a line is a regular expression which is tested -# against the directory that the change is being committed to, relative -# to the $CVSROOT. For the first match that is found, then the remainder -# of the line is the name of the filter to run. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# If the name "ALL" appears as a regular expression it is always used -# in addition to the first matching regex or "DEFAULT". -# -# NOTE: contrib/commit_prep usage: -# -r - record directories affected by commit for use with contrib/log_accum -# -c - check for things like "$Id" near head of file, no "$Log", etc. -# -^apc $CVSROOT/CVSROOT/commit_prep -r -c -^misc $CVSROOT/CVSROOT/commit_prep -r -CVSROOT $CVSROOT/CVSROOT/commit_prep -r -c -DEFAULT $CVSROOT/CVSROOT/commit_prep diff --git a/gnu/usr.bin/cvs/examples/cvswrappers b/gnu/usr.bin/cvs/examples/cvswrappers deleted file mode 100644 index c666292..0000000 --- a/gnu/usr.bin/cvs/examples/cvswrappers +++ /dev/null @@ -1,29 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: cvswrappers,v 1.3 1995/11/14 23:23:11 woods 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) -# -# wildcard [option value][option value]... -# -# where option is one of -# -f from cvs filter value: path to filter -# -t to cvs filter value: path to filter -# -m update methodology value: MERGE or COPY -# -# and value is a single-quote delimited value. -# -# -*.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 deleted file mode 100644 index 976a986..0000000 --- a/gnu/usr.bin/cvs/examples/editinfo +++ /dev/null @@ -1,32 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: editinfo,v 1.2 1995/11/14 23:30:07 woods Exp $" -# -# The "editinfo" file is used to allow verification of logging -# information. It works best when a template (as specified in the -# rcsinfo file) is provided for the logging procedure. Given a -# template with locations for, a bug-id number, a list of people who -# reviewed the code before it can be checked in, and an external -# process to catalog the differences that were code reviewed, the -# following test can be applied to the code: -# -# Making sure that the entered bug-id number is correct. -# Validating that the code that was reviewed is indeed the code being -# checked in (using the bug-id number or a seperate review -# number to identify this particular code set.). -# -# If any of the above test failed, then the commit would be aborted. -# -# Actions such as mailing a copy of the report to each reviewer are -# better handled by an entry in the loginfo file. -# -# Although these test could be handled by an interactive script being -# called via an entry in commitinfo, The information reported in -# such a script can't be easily merged into the report. -# -# One thing that should be noted is the the ALL keyword is not -# 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 deleted file mode 100644 index 1d68e7d..0000000 --- a/gnu/usr.bin/cvs/examples/loginfo +++ /dev/null @@ -1,39 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: loginfo,v 1.4 1995/11/14 23:30:08 woods 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 -# against the directory that the change is being made to, relative to the -# $CVSROOT. For the first match that is found, then the remainder of the -# line is a filter program that should expect log information on its standard -# input. -# -# If the repository name does not match any of the regular expressions in the -# first field of this file, the "DEFAULT" line is used, if it is specified. -# -# If the name "ALL" appears as a regular expression it is always used -# in addition to the first matching regex or "DEFAULT". -# -# The filter program may use one and only one "%s" modifier (ala printf). If -# such a "%s" is specified in the filter program, a brief title is included -# (as one argument, enclosed in single quotes) showing the relative directory -# name and listing the modified file names. -# -# NOTE: contrib/log usage: (currently requires perl) -# -d - turn debugging on.... -# -m mailto - send mail to "mailto" (multiple -m's permitted) -# -f logfile - required arg: save messages to logfile -# %s - may follow other options at the end of the line -# -# NOTE: contrib/log_accum usage: (currently requires perl) -# (must have 'commit_prep -r' in commitinfo) -# -d - turn debugging on.... -# -M modulename - use this as the module name (necessary for sub-dirs) -# -m mailto - send mail to "mailto" (multiple -m's permitted) [optional] -# -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 deleted file mode 100644 index ac8cd4d..0000000 --- a/gnu/usr.bin/cvs/examples/modules +++ /dev/null @@ -1,581 +0,0 @@ -# -# The CVS Modules File -# -#ident "@(#)cvs/examples:$Name: $:$Id: modules,v 1.4 1995/11/14 23:28:48 woods Exp $" -# -# Three different line formats are valid: -# key -a aliases... -# key [options] directory -# key [options] directory files... -# -# 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. -# -l Top-level directory only -- do not recurse. -# -# And "directory" is a path to a directory relative to $CVSROOT. -# -# The "-a" option specifies an alias. An alias is interpreted as if -# everything on the right of the "-a" had been typed on the command line. -# -# You can encode a module within a module by using the special '&' -# character to interpose another module into the current module. This -# can be useful for creating a module that consists of many directories -# spread out over the entire source repository. -# - -# Convenient aliases -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 -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 -# -# END_REQUIRED_CONTENT (this comment for cvsinit) -# -# The remainder was for the Prisma OS sources -# - -# another convenient alias -kernel -a sys lang/adb sparcsim - -# The "sys" entry exists only to make symbolic links after checkout -sys -o sys/tools/make_links sys - -# Sub-directories of "bin" -awk bin/awk -csh bin/csh -diff bin/diff -make bin/make -sed bin/sed -sh bin/sh - -# Programs that live in "bin" -cat bin Makefile cat.c -chgrp bin Makefile chgrp.c -chmod bin Makefile chmod.c -cmp bin Makefile cmp.c -cp bin Makefile cp.c -date bin Makefile date.c -dd bin Makefile dd.c -df bin Makefile df.c -domainname bin Makefile domainname.c -du bin Makefile du.c -echo bin Makefile echo.c -ed bin Makefile ed.c -env bin Makefile env.c -expr bin Makefile expr.c -grep bin Makefile grep.c -hostid bin Makefile hostid.c -hostname bin Makefile hostname.c -kill bin Makefile kill.c -ldd bin Makefile ldd.c -line bin Makefile line.c -ln bin Makefile ln.c -login bin Makefile login.c -ls bin Makefile ls.c -mail bin Makefile mail.c -mkdir bin Makefile mkdir.c -mt bin Makefile mt.c -mv bin Makefile mv.c -newgrp bin Makefile newgrp.c -nice bin Makefile nice.c -od bin Makefile od.c -pagesize bin Makefile pagesize.c -passwd bin Makefile passwd.c -pr bin Makefile pr.c -ps bin Makefile ps.c -pwd bin Makefile pwd.c -rm bin Makefile rm.c -rmail bin Makefile rmail.c -rmdir bin Makefile rmdir.c -stty bin Makefile stty.c -su bin Makefile su.c -sync bin Makefile sync.c -tar bin Makefile tar.c -tee bin Makefile tee.c -test bin Makefile test.c -time bin Makefile time.c -wall bin Makefile wall.c -who bin Makefile who.c -write bin Makefile write.c - -# Sub-directories of "etc" -dump etc/dump -files etc/files -fsck etc/fsck -getty etc/getty -in.routed etc/in.routed -restore etc/restore -rpc.lockd etc/rpc.lockd -rpc.statd etc/rpc.statd - -# Programs that live in "etc" -arp etc Makefile arp.c -biod etc Makefile biod.c -chown etc Makefile chown.c -clri etc Makefile clri.c -dkinfo etc Makefile dkinfo.c -dmesg etc Makefile dmesg.c -fsirand etc Makefile fsirand.c -halt etc Makefile halt.c -ifconfig etc Makefile ifconfig.c -in.rlogind etc Makefile in.rlogind.c -in.rshd etc Makefile in.rshd.c -inetd etc Makefile inetd.c -init etc Makefile init.c -mkfs etc Makefile mkfs.c -mknod etc Makefile mknod.c -mount etc Makefile mount.c -newfs etc Makefile newfs.c -nfsd etc Makefile nfsd.c -portmap etc Makefile portmap.c -pstat etc Makefile pstat.c -reboot etc Makefile reboot.c -renice etc Makefile renice.c -rmt etc Makefile rmt.c -shutdown etc Makefile shutdown.c -syslogd etc Makefile syslogd.c -umount etc Makefile umount.c -update etc Makefile update.c -vipw etc Makefile vipw.c -ypbind etc Makefile ypbind.c - -# Sub-directories of "games" -adventure games/adventure -backgammon games/backgammon -battlestar games/battlestar -boggle games/boggle -chess games/chess -ching games/ching -cribbage games/cribbage -fortune games/fortune -hack games/hack -hangman games/hangman -hunt games/hunt -life games/life -mille games/mille -monop games/monop -quiz games/quiz -robots games/robots -sail games/sail -snake games/snake -trek games/trek - -# Programs that live in "games" -arithmetic games Makefile arithmetic.c -banner games Makefile banner.c -bcd games Makefile bcd.c -bj games Makefile bj.c -btlgammon games Makefile btlgammon.c -canfield games Makefile canfield.c -cfscores games Makefile cfscores.c -craps games Makefile craps.c -factor games Makefile factor.c -fish games Makefile fish.c -moo games Makefile moo.c -number games Makefile number.c -primes games Makefile primes.c -rain games Makefile rain.c -random games Makefile random.c -worm games Makefile worm.c -worms games Makefile worms.c -wump games Makefile wump.c - -# Sub-directories of "lang" -adb lang/adb -as lang/as -boot lang/boot -c2 lang/c2 -cgrdr lang/cgrdr -compile lang/compile -cpp lang/cpp -dbx lang/dbx -f77 lang/f77 -inline lang/inline -iropt lang/iropt -ld lang/ld -lint lang/lint -m4 lang/m4 -pascal lang/pascal -pcc lang/pcc -ratfor lang/ratfor -rtld lang/rtld -tcov lang/tcov -vroot lang/vroot - -# Programs that live in "lang" -ar lang Makefile ar.c -nm lang Makefile nm.c -ranlib lang Makefile ranlib.c -size lang Makefile size.c -strip lang Makefile strip.c -symorder lang Makefile symorder.c - -# Sub-directories of "lib" -csu lib/csu -libc lib/libc - -# Programs that live in "lib" -# NONE - -# Sub-directories of "lib/libc" -libc_compat lib/libc/compat -libc_crt lib/libc/crt -libc_des lib/libc/des -libc_gen lib/libc/gen -libc_net lib/libc/net -libc_inet lib/libc/inet -libc_rpc lib/libc/rpc -libc_stdio lib/libc/stdio -libc_sun lib/libc/sun -libc_sys lib/libc/sys -libc_yp lib/libc/yp - -# Programs that live in "lib/libc" -# NONE - -#Sub-directories of "local" -notes local/notes - -# Sub-directories of "man" -man1 man/man1 -man2 man/man2 -man3 man/man3 -man4 man/man4 -man5 man/man5 -man6 man/man6 -man7 man/man7 -man8 man/man8 -manl man/manl - -# Programs that live in "man" -# NONE - -# Sub-directories of "old" -old_compact old/compact -old_eyacc old/eyacc -old_filemerge old/filemerge -old_make old/make - -# Programs that live in "old" -old_analyze old Makefile analyze.c -old_prmail old Makefile prmail.c -old_pti old Makefile pti.c -old_syslog old Makefile syslog.c - -# Sub-directories of "ucb" -Mail ucb/Mail -compress ucb/compress -error ucb/error -ex ucb/ex -ftp ucb/ftp -gprof ucb/gprof -indent ucb/indent -lpr ucb/lpr -more ucb/more -msgs ucb/msgs -netstat ucb/netstat -rdist ucb/rdist -talk ucb/talk -tftp ucb/tftp -tset ucb/tset -vgrind ucb/vgrind - -# Programs that live in "ucb" -biff ucb Makefile biff.c -checknr ucb Makefile checknr.c -clear ucb Makefile clear.c -colcrt ucb Makefile colcrt.c -colrm ucb Makefile colrm.c -ctags ucb Makefile ctags.c -expand ucb Makefile expand.c -finger ucb Makefile finger.c -fold ucb Makefile fold.c -from ucb Makefile from.c -fsplit ucb Makefile fsplit.c -gcore ucb Makefile gcore.c -groups ucb Makefile groups.c -head ucb Makefile head.c -last ucb Makefile last.c -lastcomm ucb Makefile lastcomm.c -leave ucb Makefile leave.c -logger ucb Makefile logger.c -man_prog ucb Makefile man.c -mkstr ucb Makefile mkstr.c -printenv ucb Makefile printenv.c -quota ucb Makefile quota.c -rcp ucb Makefile rcp.c -rdate ucb Makefile rdate.c -rlogin ucb Makefile rlogin.c -rsh ucb Makefile rsh.c -rup ucb Makefile rup.c -ruptime ucb Makefile ruptime.c -rusers ucb Makefile rusers.c -rwho ucb Makefile rwho.c -sccs ucb Makefile sccs.c -script ucb Makefile script.c -soelim ucb Makefile soelim.c -strings ucb Makefile strings.c -tail ucb Makefile tail.c -tcopy ucb Makefile tcopy.c -telnet ucb Makefile telnet.c -ul ucb Makefile ul.c -unexpand ucb Makefile unexpand.c -unifdef ucb Makefile unifdef.c -users ucb Makefile users.c -vmstat ucb Makefile vmstat.c -w ucb Makefile w.c -wc ucb Makefile wc.c -what ucb Makefile what.c -whatis ucb Makefile whatis.c -whereis ucb Makefile whereis.c -whoami ucb Makefile whoami.c -whois ucb Makefile whois.c -xstr ucb Makefile xstr.c -yes ucb Makefile yes.c - -# Sub-directories of "usr.bin" -calendar usr.bin/calendar -cflow usr.bin/cflow -ctrace usr.bin/ctrace -cxref usr.bin/cxref -dc usr.bin/dc -des usr.bin/des -diff3 usr.bin/diff3 -sun_eqn usr.bin/eqn -file usr.bin/file -find usr.bin/find -graph usr.bin/graph -lex usr.bin/lex -sun_neqn usr.bin/neqn -sun_nroff usr.bin/nroff -sun_plot usr.bin/plot -prof usr.bin/prof -refer usr.bin/refer -rpcgen usr.bin/rpcgen -spell usr.bin/spell -sun_tbl usr.bin/tbl -tip usr.bin/tip -trace usr.bin/trace -sun_troff usr.bin/troff -uucp usr.bin/uucp -xsend usr.bin/xsend -yacc usr.bin/yacc - -# Programs that live in "usr.bin" -basename usr.bin Makefile basename.c -bc usr.bin Makefile bc.c -cal usr.bin Makefile cal.c -cb usr.bin Makefile cb.c -checkeq usr.bin Makefile checkeq.c -chkey usr.bin Makefile chkey.c -click usr.bin Makefile click.c -col usr.bin Makefile col.c -comm usr.bin Makefile comm.c -cpio usr.bin Makefile cpio.c -crypt usr.bin Makefile crypt.c -csplit usr.bin Makefile csplit.c -cut usr.bin Makefile cut.c -deroff usr.bin Makefile deroff.c -egrep usr.bin Makefile egrep.c -fgrep usr.bin Makefile fgrep.c -getopt usr.bin Makefile getopt.c -id usr.bin Makefile id.c -installcmd usr.bin Makefile installcmd.c -iostat usr.bin Makefile iostat.c -ipcrm usr.bin Makefile ipcrm.c -ipcs usr.bin Makefile ipcs.c -join usr.bin Makefile join.c -keylogin usr.bin Makefile keylogin.c -logname usr.bin Makefile logname.c -look usr.bin Makefile look.c -mesg usr.bin Makefile mesg.c -nl usr.bin Makefile nl.c -pack usr.bin Makefile pack.c -paste usr.bin Makefile paste.c -ptx usr.bin Makefile ptx.c -rev usr.bin Makefile rev.c -screenblank usr.bin Makefile screenblank.c -sdiff usr.bin Makefile sdiff.c -sleep usr.bin Makefile sleep.c -sort usr.bin Makefile sort.c -spline usr.bin Makefile spline.c -split usr.bin Makefile split.c -sum usr.bin Makefile sum.c -touch usr.bin Makefile touch.c -tr usr.bin Makefile tr.c -tsort usr.bin Makefile tsort.c -tty usr.bin Makefile tty.c -uniq usr.bin Makefile uniq.c -units usr.bin Makefile units.c -unpack usr.bin Makefile unpack.c -xargs usr.bin Makefile xargs.c -ypcat usr.bin Makefile ypcat.c -ypmatch usr.bin Makefile ypmatch.c -yppasswd usr.bin Makefile yppasswd.c -ypwhich usr.bin Makefile ypwhich.c - -# Sub-directories of "usr.etc" -automount usr.etc/automount -c2convert usr.etc/c2convert -config usr.etc/config -cron usr.etc/cron -eeprom usr.etc/eeprom -etherfind usr.etc/etherfind -format usr.etc/format -htable usr.etc/htable -implog usr.etc/implog -in.ftpd -a usr.etc/in.ftpd ucb/ftp -in.named usr.etc/in.named -in.rwhod usr.etc/in.rwhod -keyserv usr.etc/keyserv -ndbootd usr.etc/ndbootd -praudit usr.etc/praudit -rexd usr.etc/rexd -rpc.bootparamd usr.etc/rpc.bootparamd -termcap usr.etc/termcap -upgrade usr.etc/upgrade -yp usr.etc/yp -zic usr.etc/zic - -# Programs that live in "usr.etc" -ac usr.etc Makefile ac.c -accton usr.etc Makefile accton.c -audit usr.etc Makefile audit.c -auditd usr.etc Makefile auditd.c -catman usr.etc Makefile catman.c -chroot usr.etc Makefile chroot.c -dcheck usr.etc Makefile dcheck.c -devnm usr.etc Makefile devnm.c -dumpfs usr.etc Makefile dumpfs.c -edquota usr.etc Makefile edquota.c -exportfs usr.etc Makefile exportfs.c -foption usr.etc Makefile foption.c -gettable usr.etc Makefile gettable.c -grpck usr.etc Makefile grpck.c -icheck usr.etc Makefile icheck.c -in.comsat usr.etc Makefile in.comsat.c -in.fingerd usr.etc Makefile in.fingerd.c -in.rexecd usr.etc Makefile in.rexecd.c -in.telnetd usr.etc Makefile in.telnetd.c -in.tnamed usr.etc Makefile in.tnamed.c -kgmon usr.etc Makefile kgmon.c -link usr.etc Makefile link.c -mkfile usr.etc Makefile mkfile.c -mkproto usr.etc Makefile mkproto.c -mount_lo usr.etc Makefile mount_lo.c -ncheck usr.etc Makefile ncheck.c -nfsstat usr.etc Makefile nfsstat.c -ping usr.etc Makefile ping.c -pwck usr.etc Makefile pwck.c -quot usr.etc Makefile quot.c -quotacheck usr.etc Makefile quotacheck.c -quotaon usr.etc Makefile quotaon.c -rarpd usr.etc Makefile rarpd.c -repquota usr.etc Makefile repquota.c -route usr.etc Makefile route.c -rpc.etherd usr.etc Makefile rpc.etherd.c -rpc.mountd usr.etc Makefile rpc.mountd.c -rpc.pwdauthd usr.etc Makefile rpc.pwdauthd.c -rpc.rquotad usr.etc Makefile rpc.rquotad.c -rpc.rstatd usr.etc Makefile rpc.rstatd.c -rpc.rusersd usr.etc Makefile rpc.rusersd.c -rpc.rwalld usr.etc Makefile rpc.rwalld.c -rpc.sprayd usr.etc Makefile rpc.sprayd.c -rpc.yppasswdd usr.etc Makefile rpc.yppasswdd.c -rpc.ypupdated usr.etc Makefile rpc.ypupdated.c -rpcinfo usr.etc Makefile rpcinfo.c -rwall usr.etc Makefile rwall.c -sa usr.etc Makefile sa.c -savecore usr.etc Makefile savecore.c -showmount usr.etc Makefile showmount.c -spray usr.etc Makefile spray.c -swapon usr.etc Makefile swapon.c -trpt usr.etc Makefile trpt.c -tunefs usr.etc Makefile tunefs.c -unlink usr.etc Makefile unlink.c - -# Sub-directories of "usr.lib" -bb_count usr.lib/bb_count -fixedwidthfonts usr.lib/fixedwidthfonts -libcurses usr.lib/libcurses -libdbm usr.lib/libdbm -libg usr.lib/libg -libkvm usr.lib/libkvm -libln usr.lib/libln -liblwp usr.lib/liblwp -libm usr.lib/libm -libmp usr.lib/libmp -libpixrect usr.lib/libpixrect -libplot usr.lib/libplot -libresolv usr.lib/libresolv -librpcsvc usr.lib/librpcsvc -libtermlib usr.lib/libtermlib -liby usr.lib/liby -me usr.lib/me -ms usr.lib/ms -sendmail usr.lib/sendmail -sun_tmac usr.lib/tmac -vfont usr.lib/vfont - -# Programs that live in "usr.lib" -getNAME usr.lib Makefile getNAME -makekey usr.lib Makefile makekey - -# Sub-directories of "5bin" -5diff3 5bin/diff3 -5m4 5bin/m4 - -# Sub-directories of "5bin", but use sources from other places -5cxref -a 5bin/cxref usr.bin/cxref -5sed -a 5bin/sed bin/sed -5lint -a 5bin/lint lang/pcc lang/lint - -# Programs that live in "5bin" -5banner 5bin Makefile banner.c -5cat 5bin Makefile cat.c -5du 5bin Makefile du.c -5echo 5bin Makefile echo.c -5expr 5bin Makefile expr.c -5ls 5bin Makefile ls.c -5nohup 5bin Makefile nohup.c -5od 5bin Makefile od.c -5pg 5bin Makefile pg.c -5pr 5bin Makefile pr.c -5sum 5bin Makefile sum.c -5tabs 5bin Makefile tabs.c -5time 5bin Makefile time.c -5tr 5bin Makefile tr.c -5uname 5bin Makefile uname.c - -# Programs that live in "5bin", but use sources from other places -5chmod -a 5bin/Makefile bin/chmod.c -5date -a 5bin/Makefile bin/date.c -5grep -a 5bin/Makefile bin/grep.c -5stty -a 5bin/Makefile bin/stty.c -5col -a 5bin/Makefile usr.bin/col.c -5sort -a 5bin/Makefile usr.bin/sort.c -5touch -a 5bin/Makefile usr.bin/touch.c - -# Sub-directories of "5lib" -5compile 5lib/compile -5libcurses 5lib/libcurses -5liby 5lib/liby -5terminfo 5lib/terminfo - -# Programs that live in "5lib" -# NONE diff --git a/gnu/usr.bin/cvs/examples/rcsinfo b/gnu/usr.bin/cvs/examples/rcsinfo deleted file mode 100644 index c90e9e0..0000000 --- a/gnu/usr.bin/cvs/examples/rcsinfo +++ /dev/null @@ -1,18 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: rcsinfo,v 1.3 1995/11/14 23:30:10 woods Exp $" -# -# The "rcsinfo" file is used to control templates with which the editor -# is invoked on commit and import. -# -# 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. For the first match that is found, then the remainder of the -# line is the name of the file that contains the template. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# 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/rcstemplate diff --git a/gnu/usr.bin/cvs/examples/rcstemplate b/gnu/usr.bin/cvs/examples/rcstemplate deleted file mode 100644 index c9a2d1e..0000000 --- a/gnu/usr.bin/cvs/examples/rcstemplate +++ /dev/null @@ -1,7 +0,0 @@ -CVS: -CVS: WARNING: You are commiting a change to the main source repository. -CVS: -CVS: This change will be immediately available to all other users -CVS: of this repository! Please be sure your changes have been -CVS: adequately tested. -CVS: diff --git a/gnu/usr.bin/cvs/examples/taginfo b/gnu/usr.bin/cvs/examples/taginfo deleted file mode 100644 index 02de62b..0000000 --- a/gnu/usr.bin/cvs/examples/taginfo +++ /dev/null @@ -1,25 +0,0 @@ -# -#ident "@(#)cvs/examples:$Name: $:$Id: taginfo,v 1.3 1995/11/14 23:27:52 woods 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, "mov" for tag -F, and "del" for tag -d -# $3 -- repository -# $4-> file revision [file revision ...] -# -# A non-zero exit of the filter program will cause the tag to be aborted. -# -# The first entry on a line is a regular expression which is tested -# against the directory that the change is being committed to, relative -# to the $CVSROOT. For the first match that is found, then the remainder -# of the line is the name of the filter to run. -# -# If the repository name does not match any of the regular expressions in this -# file, the "DEFAULT" line is used, if it is specified. -# -# 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 diff --git a/gnu/usr.bin/cvs/examples/unwrap b/gnu/usr.bin/cvs/examples/unwrap deleted file mode 100644 index def0561..0000000 --- a/gnu/usr.bin/cvs/examples/unwrap +++ /dev/null @@ -1,21 +0,0 @@ -#! /bin/sh -# -# unwrap - extract the combined package (created with wrap) -# -#ident "@(#)cvs/examples:$Name: $:$Id: unwrap,v 1.1 1995/11/14 23:20:30 woods 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 deleted file mode 100644 index b6a6a77..0000000 --- a/gnu/usr.bin/cvs/examples/wrap +++ /dev/null @@ -1,21 +0,0 @@ -#! /bin/sh -# -# wrap - Combine a directory into a single tar package. -# -#ident "@(#)cvs/examples:$Name: $:$Id: wrap,v 1.1 1995/11/14 23:20:32 woods 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/ChangeLog b/gnu/usr.bin/cvs/lib/ChangeLog deleted file mode 100644 index c8aa4a4..0000000 --- a/gnu/usr.bin/cvs/lib/ChangeLog +++ /dev/null @@ -1,335 +0,0 @@ -Mon Dec 4 10:54:04 1995 Jim Kingdon <kingdon@harvey.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * system.h (NEED_DECOY_PERMISSIONS): moved this section to where - it belongs, duh. - - * getdate.c: if STDC_HEADERS, then just include <stdlib.h> 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 <kfogel@floss.cyclic.com> - - * 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 <woods@most.weird.com> - - * 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 <kfogel@floss.cyclic.com> - - * fnmatch.c: conform to 80 column standard (yes, I'm a pedant). - -Wed Nov 8 11:10:59 1995 Karl Fogel <kfogel@floss.cyclic.com> - - * 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 <sys/utime.h>. Only OS/2 - defines this right now. - -Wed Nov 8 13:18:51 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * valloc.c: omit malloc declaration (it's already in system.h - which is included and conflicts with <stdlib.h> on some - systems). - -Tue Nov 7 19:38:48 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <kfogel@floss.cyclic.com> - - * 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 <ctype.h> 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 <nk@col.sw-ley.de> - - * wait.h: include sys/resource.h if available. This is needed at - least under AIX-3.2 where <sys/wait.h> doesn't include it. - -Mon Oct 23 17:39:11 1995 Norbert Kiesel <nk@col.sw-ley.de> - - * 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 <kfogel@totoro.cyclic.com> - - * 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 <peter@haywire.DIALix.COM> - - * 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 <jimb@totoro.cyclic.com> - - * system.h: Doc fix. - -Mon Oct 2 18:10:35 1995 Larry Jones <larry.jones@sdrc.com> - - * regex.c: compile 4.2 BSD compatible functions even when - _POSIX_SOURCE is defined since we need them and we wouldn't be - compiling this file unless they don't exist. - -Mon Oct 2 10:32:20 1995 Michael Finken <finken@conware.de> - - * strstr.c (strstr): new file and func. - - * Makefile.in (SOURCES): added strstr.c. - -Sun Oct 1 21:03:40 1995 Karl Fogel <kfogel@totoro.cyclic.com> - - * regex.c: reverted below change. - -Thu Sep 28 13:37:04 1995 Larry Jones <larry.jones@sdrc.com> - - * regexp.c: check for ISC. - -Thu Sep 7 19:18:00 1995 Jim Blandy <jimb@cyclic.com> - - * save-cwd.c: #include <direct.h> and <io.h>, on systems that - have them. - - * getopt.c (_getopt_internal): Cast the return value of strlen, - which is unsigned, before comparing it with the difference between - two pointers, which is unsigned. - -Thu Aug 31 11:31:42 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * getdate.y [STDC_HEADERS]: #include <stdlib.h>, for abort. - [HAVE_ALLOCA_H]: #include <alloca.h>, for alloca on Windows NT. - -Wed Aug 30 18:48:44 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * system.h [HAVE_IO_H]: #include <io.h>, for Windows NT. - [HAVE_DIRECT_H]: #include <direct.h>, for Windows NT. - (CVS_MKDIR, FOLD_FN_CHAR, fnfold, fncmp, ISDIRSEP, OPEN_BINARY, - FOPEN_BINARY_READ, FOPEN_BINARY_WRITE): New macros/functions, for - use in system-sensitive code. - - * regex.c (re_set_registers): start and end are pointers, not - integers. Cast the initializing value appropriately. - - * getopt.c [HAVE_STRING_H]: #include <string.h>, to avoid - warnings. - - * fnmatch.c (FOLD_FN_CHAR): Give this a dummy #definition if - config.h didn't #define it. - (fnmatch): Pass filename characters through FOLD_FN_CHAR before - comparing them. - - * argmatch.c: #include <sys/types.h>. - (argmatch): Declare arglen to be a size_t, rather than an int, - to avoid signed/unsigned comparison "problems". - - * .cvsignore: Remove getdate.c from this file. We want to - distribute it, for systems that don't have a Yacc-equivalent - installed (like Windows NT). - -Sat Aug 19 22:00:51 1995 Jim Blandy <jimb@totoro.cyclic.com> - - * error.c: Don't #define CVS_SUPPORT here. config.h takes care of - that for us. - [CVS_SUPPORT] (error_use_protocol): New variable, with apology. - (error): If error_use_protocol is set, report errors using the - client/server protocol. - * error.h [CVS_SUPPORT]: Extern decl for error_use_protocol. - -Fri Aug 4 00:01:24 1995 Jim Meyering (meyering@comco.com) - - * xgetwd.c: Don't declare free. A K&R style declaration gets - a conflict on some Sun systems when compiling with acc. - - * save-cwd.c: New file. - * save-cwd.h: New file. - * Makefile.in (SOURCES): Add save-cwd.c - (OBJECTS): Add save-cwd.o. - (HEADERS): Add save-cwd.h. - -Thu Aug 3 00:55:54 1995 Jim Meyering (meyering@comco.com) - - * error.h: New file. - * Makefile.in (HEADERS): Add error.h. - -Sat Jul 29 15:53:55 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * Makefile.in (SOURCES): Add getdate.c. - -Thu Jul 27 09:11:41 1995 Robert Lipe <robertl@rjlhome.arnet.com> - - * system.h: Check for PATHSIZE before falling back to _POSIX_PATH_MAX. - -Thu Jul 20 12:38:03 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * error.c: Instead of calling cvs functions to clean up, allow cvs - to register a callback via error_set_cleanup. Avoids hassles with - include files and SERVER_SUPPORT and so on. - -Tue Jul 18 21:18:00 1995 Jim Blandy <jimb@cyclic.com> - - * system.h: Include <sys/param.h> only if HAVE_SYS_PARAM_H - is #defined. We've added a test to configure.in to #define this - on most systems. - -Thu Jul 13 11:22:21 1995 Jim Meyering (meyering@comco.com) - - * xgetwd.c: New file. - * Makefile.in (SOURCES): Add xgetwd.c - (OBJECTS): Add xgetwd.o. - -Wed Jul 12 09:18:49 1995 Jim Meyering (meyering@comco.com) - - * Makefile.in (OBJECTS): Remove fnmatch.o. Now configure adds it - to LIBOBJS when necessary. - -Fri Jun 30 16:27:18 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * rename.c (rename): If MVDIR is not defined, just give an error - on attempt to rename a directory. - -Thu Jun 29 00:46:31 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * system.h: Check HAVE_SYS_TIMEB_H not non-existent HAVE_TIMEB_H. - - * system.h: Don't define alloca if it is already defined. - -Wed Jun 28 15:24:51 1995 James Kingdon <kingdon@harvey.cyclic.com> - - * system.h: If NeXT, define utimbuf ourself. - -Mon May 29 22:32:40 1995 J.T. Conklin <jtc@rtl.cygnus.com> - - * system.h: Handle time and directory headers as recommended in - the autoconf manual. - Undefine the S_FOO() macros if STAT_MACROS_BROKEN is set. - Don't define mode_t, as it is handled by config.h. - -Sat May 27 08:46:00 1995 Jim Meyering (meyering@comco.com) - - * Makefile.in (Makefile): Regenerate only Makefile in current - directory when Makefile.in is out of date. Depend on ../config.status. - -Fri Apr 28 22:49:25 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * Makefile.in (SOURCES, OBJECTS): Updated. - (HEADERS): New variable. - (DISTFILES): Updated. - (dist-dir): Renamed from dist; changed to work with DISTDIR - variable passed from parent. - -Wed Feb 8 06:37:53 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * system.h (S_IRUSR et al): Define if not already defined. - - * waitpid.c [HAVE_CONFIG_H]: Include "config.h". - (ualloc): Return OLDPTR rather than running off the end. - -Mon Aug 22 22:48:19 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * error.c (strerror): Replaced conditional static definition - (always used, since the condition variable was never set) with an - extern declaration, since it's provided by libc or strerror.c. - -Wed Aug 10 14:54:25 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * Makefile.in (SOURCES): Add waitpid.c. - * waitpid.c: New file. - -Tue Aug 9 16:00:12 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * md5.h (uint32): If SIZEOF_LONG isn't 4, don't define this to be - "unsigned long"; try SIZEOF_INT and "unsigned int", otherwise - complain. - - * md5.c: Include config.h. - (const): Don't bother defining here, config.h should take care of - it. - - * valloc.c (malloc): Declare. - -Fri Jul 15 12:57:20 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * getopt.c: Do not include <stdlib.h> unless __GNU_LIBRARY__ is - defined. On Irix 5.2, <stdlib.h> includes <getopt.h>, which - causes a multiple definition of struct option. - -Fri Jul 8 10:04:59 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * md5.h, md5.c: Remove ANSI-isms. - -Thu Jul 7 20:24:18 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * md5.h, md5.c: New files. - * Makefile.in (SOURCES): Add md5.c. - (OBJECTS): Add md5.o. - (DISTFILES): Add md5.h. - (md5.o): New target; depend upon md5.h. - -Fri May 27 18:15:34 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * valloc.c: New file. - -Tue May 17 08:18:26 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * error.c (error, fperror): If server_active, call server_cleanup - as well as Lock_Cleanup. - -Thu Jan 6 13:45:04 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * system.h: Fix Dec 27 change to work correctly. Makes Sep 9 - change unnecessary, so backed that one out. Never define PATH_MAX - in terms of pathconf, because that doesn't produce a constant, and - PATH_MAX is used to set array sizes. - -Mon Dec 27 14:22:07 1993 Mark Eichin (eichin@cygnus.com) - - * system.h: don't touch PATH_MAX or MAXPATHLEN if *both* of them - are already defined, as one may be defined in terms of the other. diff --git a/gnu/usr.bin/cvs/lib/Makefile b/gnu/usr.bin/cvs/lib/Makefile index f61d748..78d96a4 100644 --- a/gnu/usr.bin/cvs/lib/Makefile +++ b/gnu/usr.bin/cvs/lib/Makefile @@ -1,11 +1,21 @@ -# $Id: Makefile,v 1.9 1995/12/10 23:09:19 peter Exp $ - -LIB = cvs -NOPROFILE= yes -CFLAGS += -I${.CURDIR} -I${.CURDIR}/../cvs -DHAVE_CONFIG_H -SRCS = argmatch.c error.c filesubr.c getdate.y getline.c \ - getopt.c getopt1.c hash.c myndbm.c run.c save-cwd.c \ - sighandle.c strippath.c stripslash.c subr.c version.c \ +# $Id: Makefile,v 1.10 1995/12/11 02:22:30 peter Exp $ + +.include "${.CURDIR}/../Makefile.inc" + +.PATH: ${CVSDIR}/src +.PATH: ${CVSDIR}/lib +.PATH: ${CVSDIR}/man + +LIB= cvs + +NOPROFILE= yes +NOPIC= yes + +CFLAGS+= -I${.CURDIR} -I${CVSDIR}/src -DHAVE_CONFIG_H + +SRCS = argmatch.c getdate.y getline.c \ + getopt.c getopt1.c savecwd.c \ + sighandle.c strippath.c stripslash.c \ xgetwd.c yesno.c CLEANFILES+= getdate.c y.tab.h @@ -14,4 +24,3 @@ install: @echo -n .include <bsd.lib.mk> - diff --git a/gnu/usr.bin/cvs/lib/argmatch.c b/gnu/usr.bin/cvs/lib/argmatch.c deleted file mode 100644 index cc360ee..0000000 --- a/gnu/usr.bin/cvs/lib/argmatch.c +++ /dev/null @@ -1,89 +0,0 @@ -/* argmatch.c -- find a match for a string in an array - 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. */ - -/* Written by David MacKenzie <djm@ai.mit.edu> */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> - -#include <stdio.h> -#ifdef STDC_HEADERS -#include <string.h> -#endif - -extern char *program_name; - -/* If ARG is an unambiguous match for an element of the - null-terminated array OPTLIST, return the index in OPTLIST - of the matched element, else -1 if it does not match any element - or -2 if it is ambiguous (is a prefix of more than one element). */ - -int -argmatch (arg, optlist) - char *arg; - char **optlist; -{ - int i; /* Temporary index in OPTLIST. */ - size_t arglen; /* Length of ARG. */ - int matchind = -1; /* Index of first nonexact match. */ - int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */ - - arglen = strlen (arg); - - /* Test all elements for either exact match or abbreviated matches. */ - for (i = 0; optlist[i]; i++) - { - if (!strncmp (optlist[i], arg, arglen)) - { - if (strlen (optlist[i]) == arglen) - /* Exact match found. */ - return i; - else if (matchind == -1) - /* First nonexact match found. */ - matchind = i; - else - /* Second nonexact match found. */ - ambiguous = 1; - } - } - if (ambiguous) - return -2; - else - return matchind; -} - -/* Error reporting for argmatch. - KIND is a description of the type of entity that was being matched. - VALUE is the invalid value that was given. - PROBLEM is the return value from argmatch. */ - -void -invalid_arg (kind, value, problem) - char *kind; - char *value; - int problem; -{ - fprintf (stderr, "%s: ", program_name); - if (problem == -1) - fprintf (stderr, "invalid"); - else /* Assume -2. */ - fprintf (stderr, "ambiguous"); - fprintf (stderr, " %s `%s'\n", kind, value); -} diff --git a/gnu/usr.bin/cvs/lib/config.h b/gnu/usr.bin/cvs/lib/config.h index ce06c62..9f03a47 100644 --- a/gnu/usr.bin/cvs/lib/config.h +++ b/gnu/usr.bin/cvs/lib/config.h @@ -8,9 +8,6 @@ /* #undef _ALL_SOURCE */ #endif -/* Define if using alloca.c. */ -/* #undef C_ALLOCA */ - /* Define if type char is unsigned and you are not using gcc. */ #ifndef __CHAR_UNSIGNED__ /* #undef __CHAR_UNSIGNED__ */ @@ -19,19 +16,9 @@ /* Define to empty if the keyword does not work. */ /* #undef const */ -/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. - This function is required for alloca.c support on those systems. */ -/* #undef CRAY_STACKSEG_END */ - /* Define to `int' if <sys/types.h> doesn't define. */ /* #undef gid_t */ -/* Define if you have alloca, as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ -/* #undef HAVE_ALLOCA_H */ - /* Define if you support file names longer than 14 characters. */ #define HAVE_LONG_FILE_NAMES 1 @@ -66,15 +53,6 @@ /* Define to `unsigned' if <sys/types.h> doesn't define. */ /* #undef size_t */ -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown - */ -/* #undef STACK_DIRECTION */ - /* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ /* #undef STAT_MACROS_BROKEN */ @@ -97,8 +75,8 @@ clients. */ #define SERVER_SUPPORT 1 -/* the path to the gnu diff program on your system */ -#define DIFF "/usr/bin/diff -a" +/* Define if you want to use the password authenticated server. */ +#define AUTH_SERVER_SUPPORT 1 /* The number of bytes in a int. */ #define SIZEOF_INT 4 diff --git a/gnu/usr.bin/cvs/lib/config.h.proto b/gnu/usr.bin/cvs/lib/config.h.proto index ce06c62..9f03a47 100644 --- a/gnu/usr.bin/cvs/lib/config.h.proto +++ b/gnu/usr.bin/cvs/lib/config.h.proto @@ -8,9 +8,6 @@ /* #undef _ALL_SOURCE */ #endif -/* Define if using alloca.c. */ -/* #undef C_ALLOCA */ - /* Define if type char is unsigned and you are not using gcc. */ #ifndef __CHAR_UNSIGNED__ /* #undef __CHAR_UNSIGNED__ */ @@ -19,19 +16,9 @@ /* Define to empty if the keyword does not work. */ /* #undef const */ -/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. - This function is required for alloca.c support on those systems. */ -/* #undef CRAY_STACKSEG_END */ - /* Define to `int' if <sys/types.h> doesn't define. */ /* #undef gid_t */ -/* Define if you have alloca, as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ -/* #undef HAVE_ALLOCA_H */ - /* Define if you support file names longer than 14 characters. */ #define HAVE_LONG_FILE_NAMES 1 @@ -66,15 +53,6 @@ /* Define to `unsigned' if <sys/types.h> doesn't define. */ /* #undef size_t */ -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown - */ -/* #undef STACK_DIRECTION */ - /* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ /* #undef STAT_MACROS_BROKEN */ @@ -97,8 +75,8 @@ clients. */ #define SERVER_SUPPORT 1 -/* the path to the gnu diff program on your system */ -#define DIFF "/usr/bin/diff -a" +/* Define if you want to use the password authenticated server. */ +#define AUTH_SERVER_SUPPORT 1 /* The number of bytes in a int. */ #define SIZEOF_INT 4 diff --git a/gnu/usr.bin/cvs/lib/error.c b/gnu/usr.bin/cvs/lib/error.c deleted file mode 100644 index 0398103..0000000 --- a/gnu/usr.bin/cvs/lib/error.c +++ /dev/null @@ -1,188 +0,0 @@ -/* 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 <stdio.h> - -/* 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 <stdarg.h> -#define VA_START(args, lastarg) va_start(args, lastarg) -#else -#include <varargs.h> -#define VA_START(args, lastarg) va_start(args) -#endif - -#else - -#ifdef HAVE_DOPRNT -#define va_alist args -#define va_dcl int args; -#else -#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 -#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; -#endif - -#endif - -#if STDC_HEADERS -#include <stdlib.h> -#include <string.h> -#else -#if __STDC__ -void exit(int status); -#else -void exit (); -#endif /* __STDC__ */ -#endif - -extern char *strerror (); - -typedef void (*fn_returning_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/lib/error.h b/gnu/usr.bin/cvs/lib/error.h deleted file mode 100644 index 7d4f535..0000000 --- a/gnu/usr.bin/cvs/lib/error.h +++ /dev/null @@ -1,47 +0,0 @@ -/* 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/lib/filesubr.c b/gnu/usr.bin/cvs/lib/filesubr.c deleted file mode 100644 index 3a52691..0000000 --- a/gnu/usr.bin/cvs/lib/filesubr.c +++ /dev/null @@ -1,640 +0,0 @@ -/* filesubr.c --- subroutines for dealing with files - Jim Blandy <jimb@cyclic.com> - - 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 "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. - */ -#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)) < 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) - { - 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); -} - -/* 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; -{ - return isaccessible(file, F_OK); -} - -/* - * Returns non-zero if the argument file is readable. - */ -int -isreadable (file) - const char *file; -{ - return isaccessible(file, R_OK); -} - -/* - * Returns non-zero if the argument file is writable. - */ -int -iswritable (file) - const char *file; -{ - 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 -} - -/* - * 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 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); -} - -/* - * 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, 0777) == 0 || errno == EEXIST) - 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, 0777); -} - -/* - * Change the mode of a file, either adding write permissions, or removing - * all write permissions. Either change honors the current umask setting. - */ -void -xchmod (fname, writable) - char *fname; - int writable; -{ - struct stat sb; - mode_t mode, oumask; - - if (stat (fname, &sb) < 0) - { - if (!noexec) - error (0, errno, "cannot stat %s", fname); - return; - } - oumask = umask (0); - (void) umask (oumask); - if (writable) - { - 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) & ~oumask; - } - - if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> chmod(%s,%o)\n", - (server_active) ? 'S' : ' ', fname, mode); -#else - (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode); -#endif - if (noexec) - return; - - if (chmod (fname, mode) < 0) - error (0, errno, "cannot change mode of file %s", fname); -} - -/* - * 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; - - if (rename (from, to) < 0) - error (1, errno, "cannot rename file %s to %s", from, to); -} - -/* - * link a file, if possible. - */ -int -link_file (from, to) - const char *from; - const char *to; -{ - if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> link(%s,%s)\n", - (server_active) ? 'S' : ' ', from, to); -#else - (void) fprintf (stderr, "-> link(%s,%s)\n", from, to); -#endif - if (noexec) - return (0); - - return (link (from, to)); -} - -/* - * 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); - - 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 (f) != 0) - { - /* under NEXTSTEP errno is set to return EPERM if - * the file is a directory,or if the user is not - * allowed to read or write to the file. - * [This is probably a bug in the O/S] - * other systems will return EISDIR to indicate - * that the path is a directory. - */ - if (errno == EISDIR || errno == EPERM) - return deep_remove_dir (f); - else - /* The file wasn't a directory and some other - * error occured - */ - return -1; - } - /* 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 == ENOTEMPTY ) - { - 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 (buf) != 0 ) - { - if (errno == EISDIR || errno == EPERM) - { - 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; -} - -/* 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)) < 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) - 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); -} - -#ifdef LOSING_TMPNAM_FUNCTION -char *tmpnam(char *s) -{ - static char value[L_tmpnam+1]; - - if (s){ - strcpy(s,"/tmp/cvsXXXXXX"); - mktemp(s); - return s; - }else{ - strcpy(value,"/tmp/cvsXXXXXX"); - mktemp(s); - return value; - } -} -#endif - -/* Return non-zero iff FILENAME is absolute. - Trivial under Unix, but more complicated under other systems. */ -int -isabsolute (filename) - const char *filename; -{ - return filename[0] == '/'; -} - - -/* Return a pointer into PATH's last component. */ -char * -last_component (path) - char *path; -{ - char *last = strrchr (path, '/'); - - if (last) - return last + 1; - else - return path; -} diff --git a/gnu/usr.bin/cvs/lib/getdate.y b/gnu/usr.bin/cvs/lib/getdate.y deleted file mode 100644 index baa1731..0000000 --- a/gnu/usr.bin/cvs/lib/getdate.y +++ /dev/null @@ -1,996 +0,0 @@ -%{ -/* -** Originally written by Steven M. Bellovin <smb@research.att.com> while -** at the University of North Carolina at Chapel Hill. Later tweaked by -** a couple of people on Usenet. Completely overhauled by Rich $alz -** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; -** send any email to Rich. -** -** This grammar has 10 shift/reduce conflicts. -** -** This code is in the public domain and has no copyright. -*/ -/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ -/* SUPPRESS 288 on yyerrlab *//* Label unused */ - -#ifdef HAVE_CONFIG_H -#if defined (emacs) || defined (CONFIG_BROKETS) -#include <config.h> -#else -#include "config.h" -#endif -#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 - wouldn't do any harm to #undef it here; this will only cause - problems if we try to write to a static variable, which I don't - think this code needs to do. */ -#ifdef emacs -#undef static -#endif - -#include <stdio.h> -#include <ctype.h> - -/* 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 <sys/time.h> if that will be used. */ - -#if defined(vms) - -#include <types.h> -#include <time.h> - -#else - -#include <sys/types.h> - -#ifdef TIME_WITH_SYS_TIME -#include <sys/time.h> -#include <time.h> -#else -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <time.h> -#endif -#endif - -#ifdef timezone -#undef timezone /* needed for sgi */ -#endif - -#if defined(HAVE_SYS_TIMEB_H) -#include <sys/timeb.h> -#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 <string.h> -#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 <stdlib.h> -#endif - -#if defined (HAVE_ALLOCA_H) -#include <alloca.h> -#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; - -%} - -%union { - time_t Number; - enum _MERIDIAN Meridian; -} - -%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT -%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST - -%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT -%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE -%type <Meridian> tMERIDIAN o_merid - -%% - -spec : /* NULL */ - | spec item - ; - -item : time { - yyHaveTime++; - } - | zone { - yyHaveZone++; - } - | date { - yyHaveDate++; - } - | day { - yyHaveDay++; - } - | rel { - yyHaveRel++; - } - | number - ; - -time : tUNUMBER tMERIDIAN { - yyHour = $1; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = $2; - } - | tUNUMBER ':' tUNUMBER o_merid { - yyHour = $1; - yyMinutes = $3; - yySeconds = 0; - yyMeridian = $4; - } - | tUNUMBER ':' tUNUMBER tSNUMBER { - yyHour = $1; - yyMinutes = $3; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - ($4 % 100 + ($4 / 100) * 60); - } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { - yyHour = $1; - yyMinutes = $3; - yySeconds = $5; - yyMeridian = $6; - } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { - yyHour = $1; - yyMinutes = $3; - yySeconds = $5; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - ($6 % 100 + ($6 / 100) * 60); - } - ; - -zone : tZONE { - yyTimezone = $1; - yyDSTmode = DSToff; - } - | tDAYZONE { - yyTimezone = $1; - yyDSTmode = DSTon; - } - | - tZONE tDST { - yyTimezone = $1; - yyDSTmode = DSTon; - } - ; - -day : tDAY { - yyDayOrdinal = 1; - yyDayNumber = $1; - } - | tDAY ',' { - yyDayOrdinal = 1; - yyDayNumber = $1; - } - | tUNUMBER tDAY { - yyDayOrdinal = $1; - yyDayNumber = $2; - } - ; - -date : tUNUMBER '/' tUNUMBER { - yyMonth = $1; - yyDay = $3; - } - | tUNUMBER '/' tUNUMBER '/' tUNUMBER { - yyMonth = $1; - yyDay = $3; - yyYear = $5; - } - | tUNUMBER tSNUMBER tSNUMBER { - /* ISO 8601 format. yyyy-mm-dd. */ - yyYear = $1; - yyMonth = -$2; - yyDay = -$3; - } - | tUNUMBER tMONTH tSNUMBER { - /* e.g. 17-JUN-1992. */ - yyDay = $1; - yyMonth = $2; - yyYear = -$3; - } - | tMONTH tUNUMBER { - yyMonth = $1; - yyDay = $2; - } - | tMONTH tUNUMBER ',' tUNUMBER { - yyMonth = $1; - yyDay = $2; - yyYear = $4; - } - | tUNUMBER tMONTH { - yyMonth = $2; - yyDay = $1; - } - | tUNUMBER tMONTH tUNUMBER { - yyMonth = $2; - yyDay = $1; - yyYear = $3; - } - ; - -rel : relunit tAGO { - yyRelSeconds = -yyRelSeconds; - yyRelMonth = -yyRelMonth; - } - | relunit - ; - -relunit : tUNUMBER tMINUTE_UNIT { - yyRelSeconds += $1 * $2 * 60L; - } - | tSNUMBER tMINUTE_UNIT { - yyRelSeconds += $1 * $2 * 60L; - } - | tMINUTE_UNIT { - yyRelSeconds += $1 * 60L; - } - | tSNUMBER tSEC_UNIT { - yyRelSeconds += $1; - } - | tUNUMBER tSEC_UNIT { - yyRelSeconds += $1; - } - | tSEC_UNIT { - yyRelSeconds++; - } - | tSNUMBER tMONTH_UNIT { - yyRelMonth += $1 * $2; - } - | tUNUMBER tMONTH_UNIT { - yyRelMonth += $1 * $2; - } - | tMONTH_UNIT { - yyRelMonth += $1; - } - ; - -number : tUNUMBER { - if (yyHaveTime && yyHaveDate && !yyHaveRel) - yyYear = $1; - else { - if($1>10000) { - yyHaveDate++; - yyDay= ($1)%100; - yyMonth= ($1/100)%100; - yyYear = $1/10000; - } - else { - yyHaveTime++; - if ($1 < 100) { - yyHour = $1; - yyMinutes = 0; - } - else { - yyHour = $1 / 100; - yyMinutes = $1 % 100; - } - yySeconds = 0; - yyMeridian = MER24; - } - } - } - ; - -o_merid : /* NULL */ { - $$ = MER24; - } - | tMERIDIAN { - $$ = $1; - } - ; - -%% - -/* 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) */ diff --git a/gnu/usr.bin/cvs/lib/getline.c b/gnu/usr.bin/cvs/lib/getline.c deleted file mode 100644 index c699461..0000000 --- a/gnu/usr.bin/cvs/lib/getline.c +++ /dev/null @@ -1,126 +0,0 @@ -/* 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 <config.h> -#endif - -#include <sys/types.h> -#include <stdio.h> -#define NDEBUG -#include <assert.h> - -#if STDC_HEADERS -#include <stdlib.h> -#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 deleted file mode 100644 index 30bcc25..0000000 --- a/gnu/usr.bin/cvs/lib/getline.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _getline_h_ -#define _getline_h_ 1 - -#include <stdio.h> - -#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/getopt.c b/gnu/usr.bin/cvs/lib/getopt.c deleted file mode 100644 index f1d8dfa..0000000 --- a/gnu/usr.bin/cvs/lib/getopt.c +++ /dev/null @@ -1,763 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 - 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. - Ditto for AIX 3.2 and <stdlib.h>. */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -#if defined (emacs) || defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ -#include <config.h> -#else -#include "config.h" -#endif -#endif - -#ifndef __STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include <stdio.h> - -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include <stdlib.h> -#endif /* GNU C library. */ - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#ifndef lint -static char rcsid[] = "$CVSid: @(#)getopt.c 1.10 94/09/21 $"; -#endif - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = NULL; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* XXX 1003.2 says this must be 1 before any call. */ -int optind = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return EOF with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include <string.h> -#define my_index strchr -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -char *getenv (); - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -#ifndef __STDC__ -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -#endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -static const char * -_getopt_initialize (optstring) - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns `EOF'. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - optarg = NULL; - - if (optind == 0) - optstring = _getopt_initialize (optstring); - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc - && (argv[optind][0] != '-' || argv[optind][1] == '\0')) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return EOF; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) - { - if (ordering == REQUIRE_ORDER) - return EOF; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if (nameend - nextchar == (int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous\n", - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[optind - 1][0], pfound->name); - } - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, "%s: unrecognized option `--%s'\n", - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, "%s: unrecognized option `%c%s'\n", - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); - else - fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); - } - optopt = c; - return '?'; - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: option requires an argument -- %c\n", - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == EOF) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/gnu/usr.bin/cvs/lib/getopt.h b/gnu/usr.bin/cvs/lib/getopt.h deleted file mode 100644 index f644aa1..0000000 --- a/gnu/usr.bin/cvs/lib/getopt.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989, 1990, 1991, 1992, 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, 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. */ - -/* $CVSid: @(#)getopt.h 1.7 94/09/21 $ */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if __STDC__ -#if defined(__GNU_LIBRARY__) -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* not __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff --git a/gnu/usr.bin/cvs/lib/getopt1.c b/gnu/usr.bin/cvs/lib/getopt1.c deleted file mode 100644 index f784b57..0000000 --- a/gnu/usr.bin/cvs/lib/getopt1.c +++ /dev/null @@ -1,187 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987, 88, 89, 90, 91, 92, 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, 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. */ - -#ifdef HAVE_CONFIG_H -#if defined (emacs) || defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ -#include <config.h> -#else -#include "config.h" -#endif -#endif - -#include "getopt.h" - -#ifndef __STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include <stdio.h> - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include <stdlib.h> -#else -char *getenv (); -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -#include <stdio.h> - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == EOF) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/gnu/usr.bin/cvs/lib/hash.c b/gnu/usr.bin/cvs/lib/hash.c deleted file mode 100644 index 8ac9323..0000000 --- a/gnu/usr.bin/cvs/lib/hash.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c) 1992, Brian Berliner and Jeff Polk - * - * 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. - * - * Polk's hash list manager. So cool. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)hash.c 1.19 94/09/23 $"; -USE(rcsid); -#endif - -/* global caches */ -static List *listcache = NULL; -static Node *nodecache = NULL; - -static void freenode_mem PROTO((Node * p)); - -/* hash function */ -static int -hashp (key) - const char *key; -{ - unsigned int h = 0; - unsigned int g; - - while (*key != 0) - { - h = (h << 4) + *key++; - if ((g = h & 0xf0000000) != 0) - h = (h ^ (g >> 24)) ^ g; - } - - return (h % HASHSIZE); -} - -/* - * create a new list (or get an old one from the cache) - */ -List * -getlist () -{ - int i; - List *list; - Node *node; - - if (listcache != NULL) - { - /* get a list from the cache and clear it */ - list = listcache; - listcache = listcache->next; - list->next = (List *) NULL; - for (i = 0; i < HASHSIZE; i++) - list->hasharray[i] = (Node *) NULL; - } - else - { - /* make a new list from scratch */ - list = (List *) xmalloc (sizeof (List)); - memset ((char *) list, 0, sizeof (List)); - node = getnode (); - list->list = node; - node->type = HEADER; - node->next = node->prev = node; - } - return (list); -} - -/* - * free up a list - */ -void -dellist (listp) - List **listp; -{ - int i; - Node *p; - - if (*listp == (List *) NULL) - return; - - p = (*listp)->list; - - /* free each node in the list (except header) */ - while (p->next != p) - delnode (p->next); - - /* free any list-private data, without freeing the actual header */ - freenode_mem (p); - - /* free up the header nodes for hash lists (if any) */ - for (i = 0; i < HASHSIZE; i++) - { - if ((p = (*listp)->hasharray[i]) != (Node *) NULL) - { - /* put the nodes into the cache */ - p->type = UNKNOWN; - p->next = nodecache; - nodecache = p; - } - } - - /* put it on the cache */ - (*listp)->next = listcache; - listcache = *listp; - *listp = (List *) NULL; -} - -/* - * get a new list node - */ -Node * -getnode () -{ - Node *p; - - if (nodecache != (Node *) NULL) - { - /* get one from the cache */ - p = nodecache; - nodecache = p->next; - } - else - { - /* make a new one */ - p = (Node *) xmalloc (sizeof (Node)); - } - - /* always make it clean */ - memset ((char *) p, 0, sizeof (Node)); - p->type = UNKNOWN; - - return (p); -} - -/* - * remove a node from it's list (maybe hash list too) and free it - */ -void -delnode (p) - Node *p; -{ - if (p == (Node *) NULL) - return; - - /* take it out of the list */ - p->next->prev = p->prev; - p->prev->next = p->next; - - /* if it was hashed, remove it from there too */ - if (p->hashnext != (Node *) NULL) - { - p->hashnext->hashprev = p->hashprev; - p->hashprev->hashnext = p->hashnext; - } - - /* free up the storage */ - freenode (p); -} - -/* - * free up the storage associated with a node - */ -static void -freenode_mem (p) - Node *p; -{ - if (p->delproc != (void (*) ()) NULL) - p->delproc (p); /* call the specified delproc */ - else - { - if (p->data != NULL) /* otherwise free() it if necessary */ - free (p->data); - } - if (p->key != NULL) /* free the key if necessary */ - free (p->key); - - /* to be safe, re-initialize these */ - p->key = p->data = (char *) NULL; - p->delproc = (void (*) ()) NULL; -} - -/* - * free up the storage associated with a node and recycle it - */ -void -freenode (p) - Node *p; -{ - /* first free the memory */ - freenode_mem (p); - - /* then put it in the cache */ - p->type = UNKNOWN; - p->next = nodecache; - nodecache = p; -} - -/* - * insert item p at end of list "list" (maybe hash it too) if hashing and it - * already exists, return -1 and don't actually put it in the list - * - * return 0 on success - */ -int -addnode (list, p) - List *list; - Node *p; -{ - int hashval; - Node *q; - - if (p->key != NULL) /* hash it too? */ - { - hashval = hashp (p->key); - if (list->hasharray[hashval] == NULL) /* make a header for list? */ - { - q = getnode (); - q->type = HEADER; - list->hasharray[hashval] = q->hashnext = q->hashprev = q; - } - - /* put it into the hash list if it's not already there */ - for (q = list->hasharray[hashval]->hashnext; - q != list->hasharray[hashval]; q = q->hashnext) - { - if (strcmp (p->key, q->key) == 0) - return (-1); - } - q = list->hasharray[hashval]; - p->hashprev = q->hashprev; - p->hashnext = q; - p->hashprev->hashnext = p; - q->hashprev = p; - } - - /* put it into the regular list */ - p->prev = list->list->prev; - p->next = list->list; - list->list->prev->next = p; - list->list->prev = p; - - return (0); -} - -/* - * look up an entry in hash list table and return a pointer to the - * node. Return NULL on error or not found. - */ -Node * -findnode (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 (strcmp (p->key, key) == 0) - return (p); - return ((Node *) NULL); -} - -/* - * walk a list with a specific proc - */ -int -walklist (list, proc, closure) - List *list; - int (*proc) PROTO ((Node *, void *)); - void *closure; -{ - Node *head, *p; - int err = 0; - - if (list == NULL) - return (0); - - head = list->list; - for (p = head->next; p != head; p = p->next) - err += proc (p, closure); - return (err); -} - -/* - * sort the elements of a list (in place) - */ -void -sortlist (list, comp) - List *list; - int (*comp) PROTO ((const Node *, const Node *)); -{ - Node *head, *remain, *p, *q; - - /* save the old first element of the list */ - head = list->list; - remain = head->next; - - /* make the header node into a null list of it's own */ - head->next = head->prev = head; - - /* while there are nodes remaining, do insert sort */ - while (remain != head) - { - /* take one from the list */ - p = remain; - remain = remain->next; - - /* traverse the sorted list looking for the place to insert it */ - for (q = head->next; q != head; q = q->next) - { - if (comp (p, q) < 0) - { - /* p comes before q */ - p->next = q; - p->prev = q->prev; - p->prev->next = p; - q->prev = p; - break; - } - } - if (q == head) - { - /* it belongs at the end of the list */ - p->next = head; - p->prev = head->prev; - p->prev->next = p; - head->prev = p; - } - } -} - -/* Debugging functions. Quite useful to call from within gdb. */ - -char * -nodetypestring (type) - Ntype type; -{ - switch (type) { - case UNKNOWN: return("UNKNOWN"); - case HEADER: return("HEADER"); - case ENTRIES: return("ENTRIES"); - case FILES: return("FILES"); - case LIST: return("LIST"); - case RCSNODE: return("RCSNODE"); - case RCSVERS: return("RCSVERS"); - case DIRS: return("DIRS"); - case UPDATE: return("UPDATE"); - case LOCK: return("LOCK"); - case NDBMNODE: return("NDBMNODE"); - } - - return("<trash>"); -} - -static int printnode PROTO ((Node *, void *)); -static int -printnode (node, closure) - Node *node; - void *closure; -{ - if (node == NULL) - { - (void) printf("NULL node.\n"); - return(0); - } - - (void) printf("Node at 0x%p: type = %s, key = 0x%p = \"%s\", data = 0x%p, next = 0x%p, prev = 0x%p\n", - node, nodetypestring(node->type), node->key, node->key, node->data, node->next, node->prev); - - return(0); -} - -void -printlist (list) - List *list; -{ - if (list == NULL) - { - (void) printf("NULL list.\n"); - return; - } - - (void) printf("List at 0x%p: list = 0x%p, HASHSIZE = %d, next = 0x%p\n", - list, list->list, HASHSIZE, list->next); - - (void) walklist(list, printnode, NULL); - - return; -} diff --git a/gnu/usr.bin/cvs/lib/hash.h b/gnu/usr.bin/cvs/lib/hash.h deleted file mode 100644 index e30511a..0000000 --- a/gnu/usr.bin/cvs/lib/hash.h +++ /dev/null @@ -1,55 +0,0 @@ -/* $CVSid: @(#)hash.h 1.23 94/10/07 $ */ - -/* - * Copyright (c) 1992, Brian Berliner and Jeff Polk - * - * 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. - */ - -/* - * The number of buckets for the hash table contained in each list. This - * should probably be prime. - */ -#define HASHSIZE 151 - -/* - * Types of nodes - */ -enum ntype -{ - UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE, - RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE -}; -typedef enum ntype Ntype; - -struct node -{ - Ntype type; - struct node *next; - struct node *prev; - struct node *hashnext; - struct node *hashprev; - char *key; - char *data; - void (*delproc) (); -}; -typedef struct node Node; - -struct list -{ - Node *list; - Node *hasharray[HASHSIZE]; - struct list *next; -}; -typedef struct list List; - -List *getlist PROTO((void)); -Node *findnode 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)); -void dellist PROTO((List ** listp)); -void delnode PROTO((Node * p)); -void freenode PROTO((Node * p)); -void sortlist PROTO((List * list, int (*)(const Node *, const Node *))); diff --git a/gnu/usr.bin/cvs/lib/myndbm.c b/gnu/usr.bin/cvs/lib/myndbm.c deleted file mode 100644 index fef3265..0000000 --- a/gnu/usr.bin/cvs/lib/myndbm.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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. - * - * A simple ndbm-emulator for CVS. It parses a text file of the format: - * - * key value - * - * at dbm_open time, and loads the entire file into memory. As such, it is - * probably only good for fairly small modules files. Ours is about 30K in - * size, and this code works fine. - */ - -#include "cvs.h" - -#ifdef MY_NDBM - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)myndbm.c 1.7 94/09/23 $"; -USE(rcsid); -#endif - -static void mydbm_load_file (); - -/* ARGSUSED */ -DBM * -mydbm_open (file, flags, mode) - char *file; - int flags; - int mode; -{ - FILE *fp; - DBM *db; - - if ((fp = fopen (file, "r")) == NULL) - return ((DBM *) 0); - - db = (DBM *) xmalloc (sizeof (*db)); - db->dbm_list = getlist (); - - mydbm_load_file (fp, db->dbm_list); - (void) fclose (fp); - return (db); -} - -void -mydbm_close (db) - DBM *db; -{ - dellist (&db->dbm_list); - free ((char *) db); -} - -datum -mydbm_fetch (db, key) - DBM *db; - datum key; -{ - Node *p; - char *s; - datum val; - - /* make sure it's null-terminated */ - s = xmalloc (key.dsize + 1); - (void) strncpy (s, key.dptr, key.dsize); - s[key.dsize] = '\0'; - - p = findnode (db->dbm_list, s); - if (p) - { - val.dptr = p->data; - val.dsize = strlen (p->data); - } - else - { - val.dptr = (char *) NULL; - val.dsize = 0; - } - free (s); - return (val); -} - -datum -mydbm_firstkey (db) - DBM *db; -{ - Node *head, *p; - datum key; - - head = db->dbm_list->list; - p = head->next; - if (p != head) - { - key.dptr = p->key; - key.dsize = strlen (p->key); - } - else - { - key.dptr = (char *) NULL; - key.dsize = 0; - } - db->dbm_next = p->next; - return (key); -} - -datum -mydbm_nextkey (db) - DBM *db; -{ - Node *head, *p; - datum key; - - head = db->dbm_list->list; - p = db->dbm_next; - if (p != head) - { - key.dptr = p->key; - key.dsize = strlen (p->key); - } - else - { - key.dptr = (char *) NULL; - key.dsize = 0; - } - db->dbm_next = p->next; - return (key); -} - -static void -mydbm_load_file (fp, list) - FILE *fp; - List *list; -{ - char line[MAXLINELEN], value[MAXLINELEN]; - char *cp, *vp; - int len, cont; - - for (cont = 0; fgets (line, sizeof (line), fp) != NULL;) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * Add the line to the value, at the end if this is a continuation - * line; otherwise at the beginning, but only after any trailing - * backslash is removed. - */ - vp = value; - if (cont) - vp += strlen (value); - - /* - * See if the line we read is a continuation line, and strip the - * backslash if so. - */ - len = strlen (line); - if (len > 0) - cp = &line[len - 1]; - else - cp = line; - if (*cp == '\\') - { - cont = 1; - *cp = '\0'; - } - else - { - cont = 0; - } - (void) strcpy (vp, line); - if (value[0] == '#') - continue; /* comment line */ - vp = value; - while (*vp && isspace (*vp)) - vp++; - if (*vp == '\0') - continue; /* empty line */ - - /* - * If this was not a continuation line, add the entry to the database - */ - if (!cont) - { - Node *p = getnode (); - char *kp; - - kp = vp; - while (*vp && !isspace (*vp)) - vp++; - *vp++ = '\0'; /* NULL terminate the key */ - p->type = NDBMNODE; - p->key = xstrdup (kp); - while (*vp && isspace (*vp)) - vp++; /* skip whitespace to value */ - if (*vp == '\0') - { - error (0, 0, "warning: NULL value for key `%s'", p->key); - freenode (p); - continue; - } - p->data = xstrdup (vp); - if (addnode (list, p) == -1) - { - error (0, 0, "duplicate key found for `%s'", p->key); - freenode (p); - } - } - } -} - -#endif /* MY_NDBM */ diff --git a/gnu/usr.bin/cvs/lib/myndbm.h b/gnu/usr.bin/cvs/lib/myndbm.h deleted file mode 100644 index 3af31305..0000000 --- a/gnu/usr.bin/cvs/lib/myndbm.h +++ /dev/null @@ -1,36 +0,0 @@ -/* $CVSid: @(#)myndbm.h 1.4 94/09/21 $ */ - -#ifdef MY_NDBM - -#define DBLKSIZ 4096 - -typedef struct -{ - List *dbm_list; /* cached database */ - Node *dbm_next; /* next key to return for nextkey() */ -} DBM; - -typedef struct -{ - char *dptr; - int dsize; -} datum; - -/* - * So as not to conflict with other dbm_open, etc., routines that may - * be included by someone's libc, all of my emulation routines are prefixed - * by "my" and we define the "standard" ones to be "my" ones here. - */ -#define dbm_open mydbm_open -#define dbm_close mydbm_close -#define dbm_fetch mydbm_fetch -#define dbm_firstkey mydbm_firstkey -#define dbm_nextkey mydbm_nextkey - -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)); - -#endif /* MY_NDBM */ diff --git a/gnu/usr.bin/cvs/lib/run.c b/gnu/usr.bin/cvs/lib/run.c deleted file mode 100644 index 6a06a38..0000000 --- a/gnu/usr.bin/cvs/lib/run.c +++ /dev/null @@ -1,533 +0,0 @@ -/* run.c --- routines for executing subprocesses. - - 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" - -#ifdef HAVE_VPRINTF -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -#include <stdarg.h> -#define VA_START(args, lastarg) va_start(args, lastarg) -#else -#include <varargs.h> -#define VA_START(args, lastarg) va_start(args) -#endif -#else -#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 -#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; -#endif - -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; - -/* VARARGS */ -#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)) -void -run_setup (const char *fmt,...) -#else -void -run_setup (fmt, va_alist) - char *fmt; - va_dcl -#endif -{ -#ifdef HAVE_VPRINTF - va_list args; -#endif - 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 */ -#ifdef HAVE_VPRINTF - VA_START (args, fmt); - (void) vsprintf (run_prog, fmt, args); - va_end (args); -#else - (void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8); -#endif - - /* 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); -} - -/* VARARGS */ -#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)) -void -run_args (const char *fmt,...) -#else -void -run_args (fmt, va_alist) - char *fmt; - va_dcl -#endif -{ -#ifdef HAVE_VPRINTF - va_list args; -#endif - - run_init_prog (); - - /* process the varargs into run_prog */ -#ifdef HAVE_VPRINTF - VA_START (args, fmt); - (void) vsprintf (run_prog, fmt, args); - va_end (args); -#else - (void) sprintf (run_prog, fmt, a1, a2, a3, a4, a5, a6, a7, a8); -#endif - - /* and add the (single) argument to the run_argv list */ - run_add_arg (run_prog); -} - -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++] = xstrdup (s); - else - run_argv[run_argc] = (char *) 0; /* not post-incremented on purpose! */ -} - -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 mode_out, mode_err; - int status; - int rc = -1; - int rerrno = 0; - int pid, w; - -#ifdef POSIX_SIGNALS - sigset_t sigset_mask, sigset_omask; - struct sigaction act, iact, qact; - -#else -#ifdef BSD_SIGNALS - int mask; - struct sigvec vec, ivec, qvec; - -#else - RETSIGTYPE (*istat) (), (*qstat) (); -#endif -#endif - - if (trace) - { -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> system(", (server_active) ? 'S' : ' '); -#else - (void) fprintf (stderr, "-> system("); -#endif - run_print (stderr); - (void) fprintf (stderr, ")\n"); - } - if (noexec && (flags & RUN_REALLY) == 0) - return (0); - - /* 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); - - 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; - } - } - - /* Make sure we don't flush this twice, once in the subprocess. */ - fflush (stdout); - fflush (stderr); - - /* The output files, if any, are now created. Do the fork and dups */ -#ifdef HAVE_VFORK - pid = vfork (); -#else - pid = fork (); -#endif - if (pid == 0) - { - 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); - } - - /* dup'ing is done. try to run it now */ - (void) execvp (run_argv[0], run_argv); - error (0, errno, "cannot exec %s", run_argv[0]); - _exit (127); - } - else if (pid == -1) - { - rerrno = errno; - goto out; - } - - /* the parent. Ignore some signals for now */ -#ifdef POSIX_SIGNALS - if (flags & RUN_SIGIGNORE) - { - act.sa_handler = SIG_IGN; - (void) sigemptyset (&act.sa_mask); - act.sa_flags = 0; - (void) sigaction (SIGINT, &act, &iact); - (void) sigaction (SIGQUIT, &act, &qact); - } - else - { - (void) sigemptyset (&sigset_mask); - (void) sigaddset (&sigset_mask, SIGINT); - (void) sigaddset (&sigset_mask, SIGQUIT); - (void) sigprocmask (SIG_SETMASK, &sigset_mask, &sigset_omask); - } -#else -#ifdef BSD_SIGNALS - if (flags & RUN_SIGIGNORE) - { - memset ((char *) &vec, 0, sizeof (vec)); - vec.sv_handler = SIG_IGN; - (void) sigvec (SIGINT, &vec, &ivec); - (void) sigvec (SIGQUIT, &vec, &qvec); - } - else - mask = sigblock (sigmask (SIGINT) | sigmask (SIGQUIT)); -#else - istat = signal (SIGINT, SIG_IGN); - qstat = signal (SIGQUIT, SIG_IGN); -#endif -#endif - - /* wait for our process to die and munge return status */ -#ifdef POSIX_SIGNALS - while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) - ; -#else - while ((w = wait (&status)) != pid) - { - if (w == -1 && errno != EINTR) - break; - } -#endif - if (w == -1) - { - rc = -1; - rerrno = errno; - } - else if (WIFEXITED (status)) - rc = WEXITSTATUS (status); - else if (WIFSIGNALED (status)) - { - if (WTERMSIG (status) == SIGPIPE) - error (1, 0, "broken pipe"); - rc = 2; - } - else - rc = 1; - - /* restore the signals */ -#ifdef POSIX_SIGNALS - if (flags & RUN_SIGIGNORE) - { - (void) sigaction (SIGINT, &iact, (struct sigaction *) NULL); - (void) sigaction (SIGQUIT, &qact, (struct sigaction *) NULL); - } - else - (void) sigprocmask (SIG_SETMASK, &sigset_omask, (sigset_t *) NULL); -#else -#ifdef BSD_SIGNALS - if (flags & RUN_SIGIGNORE) - { - (void) sigvec (SIGINT, &ivec, (struct sigvec *) NULL); - (void) sigvec (SIGQUIT, &qvec, (struct sigvec *) NULL); - } - else - (void) sigsetmask (mask); -#else - (void) signal (SIGINT, istat); - (void) signal (SIGQUIT, qstat); -#endif -#endif - - /* cleanup the open file descriptors */ - out: - if (sterr) - (void) close (sherr); - out2: - if (stout) - (void) close (shout); - out1: - if (stin) - (void) close (shin); - - out0: - if (rerrno) - errno = rerrno; - return (rc); -} - -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, " "); - } -} - -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); - - return (popen (cmd, mode)); -} - -extern int evecvp PROTO((char *file, char **argv)); - -int -piped_child (command, tofdp, fromfdp) - char **command; - int *tofdp; - int *fromfdp; -{ - int pid; - int to_child_pipe[2]; - int from_child_pipe[2]; - - if (pipe (to_child_pipe) < 0) - error (1, errno, "cannot create pipe"); - if (pipe (from_child_pipe) < 0) - error (1, errno, "cannot create pipe"); - - pid = fork (); - if (pid < 0) - error (1, errno, "cannot fork"); - if (pid == 0) - { - if (dup2 (to_child_pipe[0], STDIN_FILENO) < 0) - error (1, errno, "cannot dup2"); - if (close (to_child_pipe[1]) < 0) - error (1, errno, "cannot close"); - if (close (from_child_pipe[0]) < 0) - error (1, errno, "cannot close"); - if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) - error (1, errno, "cannot dup2"); - - execvp (command[0], command); - error (1, errno, "cannot exec"); - } - if (close (to_child_pipe[0]) < 0) - error (1, errno, "cannot close"); - if (close (from_child_pipe[1]) < 0) - error (1, errno, "cannot close"); - - *tofdp = to_child_pipe[1]; - *fromfdp = from_child_pipe[0]; - return pid; -} - - -void -close_on_exec (fd) - int fd; -{ -#if defined (FD_CLOEXEC) && defined (F_SETFD) - if (fcntl (fd, F_SETFD, 1)) - error (1, errno, "can't set close-on-exec flag on %d", fd); -#endif -} - -/* - * dir = 0 : main proc writes to new proc, which writes to oldfd - * dir = 1 : main proc reads from new proc, which reads from oldfd - */ - -int -filter_stream_through_program (oldfd, dir, prog, pidp) - int oldfd, dir; - char **prog; - pid_t *pidp; -{ - int p[2], newfd; - pid_t newpid; - - if (pipe (p)) - error (1, errno, "cannot create pipe"); - newpid = fork (); - if (pidp) - *pidp = newpid; - switch (newpid) - { - case -1: - error (1, errno, "cannot fork"); - case 0: - /* child */ - if (dir) - { - /* write to new pipe */ - close (p[0]); - dup2 (oldfd, 0); - dup2 (p[1], 1); - } - else - { - /* read from new pipe */ - close (p[1]); - dup2 (p[0], 0); - dup2 (oldfd, 1); - } - /* Should I be blocking some signals here? */ - execvp (prog[0], prog); - error (1, errno, "couldn't exec %s", prog[0]); - default: - /* parent */ - close (oldfd); - if (dir) - { - /* read from new pipe */ - close (p[1]); - newfd = p[0]; - } - else - { - /* write to new pipe */ - close (p[0]); - newfd = p[1]; - } - close_on_exec (newfd); - return newfd; - } -} diff --git a/gnu/usr.bin/cvs/lib/save-cwd.c b/gnu/usr.bin/cvs/lib/save-cwd.c deleted file mode 100644 index 1bdf791..0000000 --- a/gnu/usr.bin/cvs/lib/save-cwd.c +++ /dev/null @@ -1,141 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <stdio.h> - -#ifdef STDC_HEADERS -# include <stdlib.h> -#endif - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#ifdef HAVE_FCNTL_H -# include <fcntl.h> -#else -# include <sys/file.h> -#endif - -#ifdef HAVE_DIRECT_H -# include <direct.h> -#endif - -#ifdef HAVE_IO_H -# include <io.h> -#endif - -#include <errno.h> -# ifndef errno -extern int errno; -#endif - -#include "save-cwd.h" -#include "error.h" - -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 - to return to the recorded location. This function may allocate - space using malloc (via xgetwd) or leave a file descriptor open; - use free_cwd to perform the necessary free or close. Upon failure, - no memory is allocated, any locally opened file descriptors are - closed; return non-zero -- in that case, free_cwd need not be - called, but doing so is ok. Otherwise, return zero. */ - -int -save_cwd (cwd) - struct saved_cwd *cwd; -{ - static int have_working_fchdir = 1; - - cwd->desc = -1; - cwd->name = NULL; - - if (have_working_fchdir) - { -#ifdef HAVE_FCHDIR - cwd->desc = open (".", O_RDONLY); - if (cwd->desc < 0) - { - error (0, errno, "cannot open current directory"); - return 1; - } - -# if __sun__ || sun - /* On SunOS 4, fchdir returns EINVAL if accounting is enabled, - so we have to fall back to chdir. */ - if (fchdir (cwd->desc)) - { - if (errno == EINVAL) - { - close (cwd->desc); - cwd->desc = -1; - have_working_fchdir = 0; - } - else - { - error (0, errno, "current directory"); - close (cwd->desc); - cwd->desc = -1; - return 1; - } - } -# endif /* __sun__ || sun */ -#else -#define fchdir(x) (abort (), 0) - have_working_fchdir = 0; -#endif - } - - if (!have_working_fchdir) - { - cwd->name = xgetwd (); - if (cwd->name == NULL) - { - error (0, errno, "cannot get current directory"); - return 1; - } - } - return 0; -} - -/* Change to recorded location, CWD, in directory hierarchy. - If "saved working directory", NULL)) - */ - -int -restore_cwd (cwd, dest) - const struct saved_cwd *cwd; - const char *dest; -{ - int fail = 0; - if (cwd->desc >= 0) - { - if (fchdir (cwd->desc)) - { - error (0, errno, "cannot return to %s", - (dest ? dest : "saved working directory")); - fail = 1; - } - } - else if (chdir (cwd->name) < 0) - { - error (0, errno, "%s", cwd->name); - fail = 1; - } - return fail; -} - -void -free_cwd (cwd) - struct saved_cwd *cwd; -{ - if (cwd->desc >= 0) - close (cwd->desc); - if (cwd->name) - free (cwd->name); -} - diff --git a/gnu/usr.bin/cvs/lib/save-cwd.h b/gnu/usr.bin/cvs/lib/save-cwd.h deleted file mode 100644 index f9802f8..0000000 --- a/gnu/usr.bin/cvs/lib/save-cwd.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SAVE_CWD_H -#define SAVE_CWD_H 1 - -struct saved_cwd - { - int desc; - char *name; - }; - -#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) -#define __PROTO(args) args -#else -#define __PROTO(args) () -#endif /* GCC. */ - -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 deleted file mode 100644 index a225983..0000000 --- a/gnu/usr.bin/cvs/lib/sighandle.c +++ /dev/null @@ -1,405 +0,0 @@ -/* sighandle.c -- Library routines for manipulating chains of signal handlers - 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. */ - -/* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com> - Brian Berliner <berliner@Sun.COM> added POSIX support */ - -/************************************************************************* - * - * signal.c -- This file contains code that manipulates chains of signal - * handlers. - * - * Facilities are provided to register a signal handler for - * any specific signal. When a signal is received, all of the - * registered signal handlers are invoked in the reverse order - * in which they are registered. Note that the signal handlers - * must not themselves make calls to the signal handling - * facilities. - * - * $CVSid: @(#)sighandle.c 1.13 94/10/07 $ - * - *************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "system.h" - -#include <sys/types.h> -#include <stdio.h> -#include <signal.h> - -#ifdef STDC_HEADERS -#include <stdlib.h> -#else -#if __STDC__ -char *calloc(unsigned nelem, unsigned size); -char *malloc(unsigned size); -#else -char *calloc(); -char *malloc(); -#endif /* __STDC__ */ -#endif /* STDC_HEADERS */ - -/* Define the highest signal number (usually) */ -#ifndef SIGMAX -#define SIGMAX 64 -#endif - -/* Define linked list of signal handlers structure */ -struct SIG_hlist { - RETSIGTYPE (*handler)(); - struct SIG_hlist *next; -}; - -/* - * Define array of lists of signal handlers. Note that this depends on - * the implementation to initialize each element to a null pointer. - */ - -static struct SIG_hlist **SIG_handlers; - -/* Define array of default signal vectors */ - -#ifdef POSIX_SIGNALS -static struct sigaction *SIG_defaults; -#else -#ifdef BSD_SIGNALS -static struct sigvec *SIG_defaults; -#else -static RETSIGTYPE (**SIG_defaults)(); -#endif -#endif - -/* Critical section housekeeping */ -static int SIG_crSectNest = 0; /* Nesting level */ -#ifdef POSIX_SIGNALS -static sigset_t SIG_crSectMask; /* Signal mask */ -#else -static int SIG_crSectMask; /* Signal mask */ -#endif - -/* - * Initialize the signal handler arrays - */ - -static int SIG_init() -{ - int i; -#ifdef POSIX_SIGNALS - sigset_t sigset_test; -#endif - - if (SIG_defaults && SIG_handlers) /* already allocated */ - return (0); - -#ifdef POSIX_SIGNALS - (void) sigfillset(&sigset_test); - for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++) - ; - if (i < SIGMAX) - i = SIGMAX; - i++; - if (!SIG_defaults) - SIG_defaults = (struct sigaction *) - calloc(i, sizeof(struct sigaction)); - (void) sigemptyset(&SIG_crSectMask); -#else - i = SIGMAX+1; -#ifdef BSD_SIGNALS - if (!SIG_defaults) - SIG_defaults = (struct sigvec *) - calloc(i, sizeof(struct sigvec)); -#else - if (!SIG_defaults) - SIG_defaults = (RETSIGTYPE (**)()) - calloc(i, sizeof(RETSIGTYPE (**)())); -#endif - SIG_crSectMask = 0; -#endif - if (!SIG_handlers) - SIG_handlers = (struct SIG_hlist **) - calloc(i, sizeof(struct SIG_hlist *)); - return (!SIG_defaults || !SIG_handlers); -} - -/* - * The following invokes each signal handler in the reverse order in which - * they were registered. - */ - -static RETSIGTYPE SIG_handle(sig) -int sig; -{ - struct SIG_hlist *this; - - /* Dispatch signal handlers */ - this = SIG_handlers[sig]; - while (this != (struct SIG_hlist *) NULL) - { - (*this->handler)(sig); - this = this->next; - } - - return; -} - -/* - * The following registers a signal handler. If the handler is already - * registered, it is not registered twice, nor is the order in which signal - * handlers are invoked changed. If this is the first signal handler - * registered for a given signal, the old sigvec structure is saved for - * restoration later. - */ - -int SIG_register(sig,fn) -int sig; -RETSIGTYPE (*fn)(); -{ - int val; - struct SIG_hlist *this; -#ifdef POSIX_SIGNALS - struct sigaction act; - sigset_t sigset_mask, sigset_omask; -#else -#ifdef BSD_SIGNALS - struct sigvec vec; - int mask; -#endif -#endif - - /* Initialize */ - if (SIG_init() != 0) - return (-1); - val = 0; - - /* Block this signal while we look at handler chain */ -#ifdef POSIX_SIGNALS - (void) sigemptyset(&sigset_mask); - (void) sigaddset(&sigset_mask, sig); - (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); -#else -#ifdef BSD_SIGNALS - mask = sigblock(sigmask(sig)); -#endif -#endif - - /* See if this handler was already registered */ - this = SIG_handlers[sig]; - while (this != (struct SIG_hlist *) NULL) - { - if (this->handler == fn) break; - this = this->next; - } - - /* Register the new handler only if it is not already registered. */ - if (this == (struct SIG_hlist *) NULL) - { - - /* - * If this is the first handler registered for this signal, - * set up the signal handler dispatcher - */ - - if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) - { -#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)); - vec.sv_handler = SIG_handle; - val = sigvec(sig, &vec, &SIG_defaults[sig]); -#else - if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == - (RETSIGTYPE (*)()) -1) - val = -1; -#endif -#endif - } - - /* If not, register it */ - if ((val == 0) && (this == (struct SIG_hlist *) NULL)) - { - this = (struct SIG_hlist *) - malloc(sizeof(struct SIG_hlist)); - if (this == NULL) - { - val = -1; - } - else - { - this->handler = fn; - this->next = SIG_handlers[sig]; - SIG_handlers[sig] = this; - } - } - } - - /* Unblock the signal */ -#ifdef POSIX_SIGNALS - (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); -#else -#ifdef BSD_SIGNALS - (void) sigsetmask(mask); -#endif -#endif - - return val; -} - -/* - * The following deregisters a signal handler. If the last signal handler for - * a given signal is deregistered, the default sigvec information is restored. - */ - -int SIG_deregister(sig,fn) -int sig; -RETSIGTYPE (*fn)(); -{ - int val; - struct SIG_hlist *this; - struct SIG_hlist *last; -#ifdef POSIX_SIGNALS - sigset_t sigset_mask, sigset_omask; -#else -#ifdef BSD_SIGNALS - int mask; -#endif -#endif - - /* Initialize */ - if (SIG_init() != 0) - return (-1); - val = 0; - last = (struct SIG_hlist *) NULL; - - /* Block this signal while we look at handler chain */ -#ifdef POSIX_SIGNALS - (void) sigemptyset(&sigset_mask); - (void) sigaddset(&sigset_mask, sig); - (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask); -#else -#ifdef BSD_SIGNALS - mask = sigblock(sigmask(sig)); -#endif -#endif - - /* Search for the signal handler */ - this = SIG_handlers[sig]; - while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn)) - { - last = this; - this = this->next; - } - - /* If it was registered, remove it */ - if (this != (struct SIG_hlist *) NULL) - { - if (last == (struct SIG_hlist *) NULL) - { - SIG_handlers[sig] = this->next; - } - else - { - last->next = this->next; - } - free((char *) this); - } - - /* Restore default behavior if there are no registered handlers */ - if (SIG_handlers[sig] == (struct SIG_hlist *) NULL) - { -#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) - val = -1; -#endif -#endif - } - - /* Unblock the signal */ -#ifdef POSIX_SIGNALS - (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL); -#else -#ifdef BSD_SIGNALS - (void) sigsetmask(mask); -#endif -#endif - - return val; -} - -/* - * The following begins a critical section. - */ - -void SIG_beginCrSect() -{ - if (SIG_init() == 0) - { - if (SIG_crSectNest == 0) - { -#ifdef POSIX_SIGNALS - sigset_t sigset_mask; - - (void) sigfillset(&sigset_mask); - (void) sigprocmask(SIG_SETMASK, - &sigset_mask, &SIG_crSectMask); -#else -#ifdef BSD_SIGNALS - SIG_crSectMask = sigblock(~0); -#else - /* TBD */ -#endif -#endif - } - SIG_crSectNest++; - } -} - -/* - * The following ends a critical section. - */ - -void SIG_endCrSect() -{ - if (SIG_init() == 0) - { - SIG_crSectNest--; - if (SIG_crSectNest == 0) - { -#ifdef POSIX_SIGNALS - (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL); -#else -#ifdef BSD_SIGNALS - (void) sigsetmask(SIG_crSectMask); -#else - /* TBD */ -#endif -#endif - } - } -} diff --git a/gnu/usr.bin/cvs/lib/strippath.c b/gnu/usr.bin/cvs/lib/strippath.c deleted file mode 100644 index 39687f9..0000000 --- a/gnu/usr.bin/cvs/lib/strippath.c +++ /dev/null @@ -1,80 +0,0 @@ -/* 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. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if STDC_HEADERS || HAVE_STRING_H -#include <string.h> -/* An ANSI string.h and pre-ANSI memory.h might conflict. */ -#if !STDC_HEADERS && HAVE_MEMORY_H -#include <memory.h> -#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ -#else /* not STDC_HJEADERS and not HAVE_STRING_H */ -#include <strings.h> -/* memory.h and strings.h conflict on some systems. */ -#endif /* not STDC_HEADERS and not HAVE_STRING_H */ - -#include <stdio.h> - -#if __STDC__ -static void remove_component(char *beginc, char *endc); -void strip_trailing_slashes(char *path); -#else -static void remove_component(); -void strip_trailing_slashes(); -#endif /* __STDC__ */ - -/* Remove unnecessary components from PATH. */ - -void -strip_path (path) - char *path; -{ - int stripped = 0; - char *cp, *slash; - - for (cp = path; (slash = strchr(cp, '/')) != NULL; 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/lib/stripslash.c b/gnu/usr.bin/cvs/lib/stripslash.c deleted file mode 100644 index 265950e..0000000 --- a/gnu/usr.bin/cvs/lib/stripslash.c +++ /dev/null @@ -1,44 +0,0 @@ -/* 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. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if STDC_HEADERS || HAVE_STRING_H -#include <string.h> -/* An ANSI string.h and pre-ANSI memory.h might conflict. */ -#if !STDC_HEADERS && HAVE_MEMORY_H -#include <memory.h> -#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ -#else /* not STDC_HJEADERS and not HAVE_STRING_H */ -#include <strings.h> -/* memory.h and strings.h conflict on some systems. */ -#endif /* not STDC_HEADERS and not HAVE_STRING_H */ - -/* 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--] = '\0'; -} diff --git a/gnu/usr.bin/cvs/lib/subr.c b/gnu/usr.bin/cvs/lib/subr.c deleted file mode 100644 index 228581c..0000000 --- a/gnu/usr.bin/cvs/lib/subr.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * 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. - * - * Various useful functions for the CVS support code. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)subr.c 1.64 94/10/07 $"; -USE(rcsid); -#endif - -extern char *getlogin (); - -/* - * malloc some data and die if it fails - */ -char * -xmalloc (bytes) - size_t bytes; -{ - char *cp; - - /* Parts of CVS try to xmalloc zero bytes and then free it. Some - systems have a malloc which returns NULL for zero byte - allocations but a free which can't handle NULL, so compensate. */ - if (bytes == 0) - bytes = 1; - - cp = malloc (bytes); - if (cp == NULL) - error (1, 0, "can not allocate %lu bytes", (unsigned long) bytes); - return (cp); -} - -/* - * realloc data and die if it fails [I've always wanted to have "realloc" do - * a "malloc" if the argument is NULL, but you can't depend on it. Here, I - * can *force* it. - */ -char * -xrealloc (ptr, bytes) - char *ptr; - size_t bytes; -{ - char *cp; - - if (!ptr) - cp = malloc (bytes); - else - cp = realloc (ptr, bytes); - - if (cp == NULL) - error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes); - return (cp); -} - -/* - * Duplicate a string, calling xmalloc to allocate some dynamic space - */ -char * -xstrdup (str) - const char *str; -{ - char *s; - - if (str == NULL) - return ((char *) NULL); - s = xmalloc (strlen (str) + 1); - (void) strcpy (s, 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() - */ -void -free_names (pargc, argv) - int *pargc; - char **argv; -{ - register int i; - - for (i = 0; i < *pargc; i++) - { /* only do through *pargc */ - free (argv[i]); - } - *pargc = 0; /* and set it to zero when done */ -} - -/* - * Convert a line into argc/argv components and return the result in the - * arguments as passed. Use free_names() to return the memory allocated here - * back to the free pool. - */ -void -line2argv (pargc, argv, line) - int *pargc; - char **argv; - char *line; -{ - char *cp; - - *pargc = 0; - for (cp = strtok (line, " \t"); cp; cp = strtok ((char *) NULL, " \t")) - { - argv[*pargc] = xstrdup (cp); - (*pargc)++; - } -} - -/* - * Returns the number of dots ('.') found in an RCS revision number - */ -int -numdots (s) - const char *s; -{ - int dots = 0; - - for (; *s; s++) - { - if (*s == '.') - dots++; - } - return (dots); -} - -/* - * Get the caller's login from his uid. If the real uid is "root" try LOGNAME - * USER or getlogin(). If getlogin() and getpwuid() both fail, return - * the uid as a string. - */ -char * -getcaller () -{ - static char uidname[20]; - struct passwd *pw; - char *name; - uid_t uid; - - uid = getuid (); - if (uid == (uid_t) 0) - { - /* super-user; try getlogin() to distinguish */ - if (((name = getlogin ()) || (name = getenv("LOGNAME")) || - (name = getenv("USER"))) && *name) - return (name); - } - if ((pw = (struct passwd *) getpwuid (uid)) == NULL) - { - (void) sprintf (uidname, "uid%lu", (unsigned long) uid); - return (uidname); - } - return (pw->pw_name); -} - -#ifdef lint -#ifndef __GNUC__ -/* ARGSUSED */ -time_t -get_date (date, now) - char *date; - struct timeb *now; -{ - time_t foo = 0; - - return (foo); -} -#endif -#endif - -/* Given two revisions, find their greatest common ancestor. If the - two input revisions exist, then rcs guarantees that the gca will - exist. */ - -char * -gca (rev1, rev2) - char *rev1; - char *rev2; -{ - int dots; - char gca[PATH_MAX]; - char *p[2]; - int j[2]; - - if (rev1 == NULL || rev2 == NULL) - { - error (0, 0, "sanity failure in gca"); - abort(); - } - - /* walk the strings, reading the common parts. */ - gca[0] = '\0'; - p[0] = rev1; - p[1] = rev2; - do - { - int i; - char c[2]; - char *s[2]; - - for (i = 0; i < 2; ++i) - { - /* swap out the dot */ - s[i] = strchr (p[i], '.'); - if (s[i] != NULL) { - c[i] = *s[i]; - } - - /* read an int */ - j[i] = atoi (p[i]); - - /* swap back the dot... */ - if (s[i] != NULL) { - *s[i] = c[i]; - p[i] = s[i] + 1; - } - else - { - /* or mark us at the end */ - p[i] = NULL; - } - - } - - /* use the lowest. */ - (void) sprintf (gca + strlen (gca), "%d.", - j[0] < j[1] ? j[0] : j[1]); - - } while (j[0] == j[1] - && p[0] != NULL - && p[1] != NULL); - - /* back up over that last dot. */ - gca[strlen(gca) - 1] = '\0'; - - /* numbers differ, or we ran out of strings. we're done with the - common parts. */ - - dots = numdots (gca); - if (dots == 0) - { - /* revisions differ in trunk major number. */ - - char *q; - char *s; - - s = (j[0] < j[1]) ? p[0] : p[1]; - - if (s == NULL) - { - /* we only got one number. this is strange. */ - error (0, 0, "bad revisions %s or %s", rev1, rev2); - abort(); - } - else - { - /* we have a minor number. use it. */ - q = gca + strlen (gca); - - *q++ = '.'; - for ( ; *s != '.' && *s != '\0'; ) - *q++ = *s++; - - *q = '\0'; - } - } - else if ((dots & 1) == 0) - { - /* if we have an even number of dots, then we have a branch. - remove the last number in order to make it a revision. */ - - char *s; - - s = strrchr(gca, '.'); - *s = '\0'; - } - - return (xstrdup (gca)); -} - -/* - * Sanity checks and any required fix-up on message passed to RCS via '-m'. - * RCS 5.7 requires that a non-total-whitespace, non-null message be provided - * with '-m'. - */ -char * -make_message_rcslegal (message) - char *message; -{ - if ((message == NULL) || (*message == '\0') || isspace (*message)) - { - char *t; - - if (message) - for (t = message; *t; t++) - if (!isspace (*t)) - return message; - - return "*** empty log message ***\n"; - } - - return message; -} diff --git a/gnu/usr.bin/cvs/lib/system.h b/gnu/usr.bin/cvs/lib/system.h deleted file mode 100644 index 20539de..0000000 --- a/gnu/usr.bin/cvs/lib/system.h +++ /dev/null @@ -1,496 +0,0 @@ -/* system-dependent definitions for CVS. - Copyright (C) 1989-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. */ - -/* $CVSid: @(#)system.h 1.18 94/09/25 $ */ - -#ifdef __GNUC__ -#ifndef alloca -#define alloca __builtin_alloca -#endif -#else -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#else -#ifdef _AIX -/* 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__ */ - -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef STAT_MACROS_BROKEN -#undef S_ISBLK -#undef S_ISCHR -#undef S_ISDIR -#undef S_ISREG -#undef S_ISFIFO -#undef S_ISLNK -#undef S_ISSOCK -#undef S_ISMPB -#undef S_ISMPC -#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) -# 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) -# 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) -# 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) -# 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) -# 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) -# 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) -# 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 */ -# 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 */ -# 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 -#define S_IXUSR 0100 -/* Read, write, and execute by owner. */ -#define S_IRWXU (S_IRUSR|S_IWUSR|S_IXUSR) - -#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */ -#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */ -#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */ -/* Read, write, and execute by group. */ -#define S_IRWXG (S_IRWXU >> 3) - -#define S_IROTH (S_IRGRP >> 3) /* Read by others. */ -#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */ -#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */ -/* Read, write, and execute by others. */ -#define S_IRWXO (S_IRWXG >> 3) -#endif /* !def S_IRUSR */ -#endif /* NEED_DECOY_PERMISSIONS */ - -#if defined(POSIX) || defined(HAVE_UNISTD_H) -#include <unistd.h> -#include <limits.h> -#else -off_t lseek (); -#endif - -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif -#endif - -#ifdef HAVE_IO_H -#include <io.h> -#endif - -#ifdef HAVE_DIRECT_H -#include <direct.h> -#endif - -#ifdef timezone -#undef timezone /* needed for sgi */ -#endif - -#ifdef HAVE_SYS_TIMEB_H -#include <sys/timeb.h> -#else -struct timeb { - time_t time; /* Seconds since the epoch */ - unsigned short millitm; /* Field not used */ - short timezone; - short dstflag; /* Field not used */ -}; -#endif - -#if !defined(HAVE_FTIME) && !defined(HAVE_TIMEZONE) -#if !defined(timezone) -extern long timezone; -#endif -#endif - - -/* -** MAXPATHLEN and PATH_MAX -** -** On most systems MAXPATHLEN is defined in sys/param.h to be 1024. Of -** those that this is not true, again most define PATH_MAX in limits.h -** or sys/limits.h which usually gets included by limits.h. On the few -** remaining systems that neither statement is true, _POSIX_PATH_MAX -** is defined. -** -** So: -** 1. If PATH_MAX is defined just use it. -** 2. If MAXPATHLEN is defined but not PATH_MAX, then define -** PATH_MAX in terms of MAXPATHLEN. -** 3. If neither is defined, include limits.h and check for -** PATH_MAX again. -** 3.1 If we now have PATHSIZE, define PATH_MAX in terms of that. -** and ignore the rest. Since _POSIX_PATH_MAX (checked for -** next) is the *most* restrictive (smallest) value, if we -** trust _POSIX_PATH_MAX, several of our buffers are too small. -** 4. If PATH_MAX is still not defined but _POSIX_PATH_MAX is, -** then define PATH_MAX in terms of _POSIX_PATH_MAX. -** 5. And if even _POSIX_PATH_MAX doesn't exist just put in -** a reasonable value. -** *. All in all, this is an excellent argument for using pathconf() -** when at all possible. Or better yet, dynamically allocate -** our buffers and use getcwd() not getwd(). -** -** This works on: -** Sun Sparc 10 SunOS 4.1.3 & Solaris 1.2 -** HP 9000/700 HP/UX 8.07 & HP/UX 9.01 -** Tektronix XD88/10 UTekV 3.2e -** IBM RS6000 AIX 3.2 -** Dec Alpha OSF 1 ???? -** Intel 386 BSDI BSD/386 -** Intel 386 SCO OpenServer Release 5 -** Apollo Domain 10.4 -** NEC SVR4 -*/ - -/* On MOST systems this will get you MAXPATHLEN. - Windows NT doesn't have this file, tho. */ -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif - -#ifndef PATH_MAX -# ifdef MAXPATHLEN -# define PATH_MAX MAXPATHLEN -# else -# include <limits.h> -# ifndef PATH_MAX -# ifdef PATHSIZE -# define PATH_MAX PATHSIZE -# else /* no PATHSIZE */ -# ifdef _POSIX_PATH_MAX -# define PATH_MAX _POSIX_PATH_MAX -# else -# define PATH_MAX 1024 -# endif /* no _POSIX_PATH_MAX */ -# endif /* no PATHSIZE */ -# endif /* no PATH_MAX */ -# endif /* MAXPATHLEN */ -#endif /* PATH_MAX */ - - -/* The NeXT (without _POSIX_SOURCE, which we don't want) has a utime.h - which doesn't define anything. It would be cleaner to have configure - check for struct utimbuf, but for now I'm checking NeXT here (so I don't - have to debug the configure check across all the machines). */ -#if defined (HAVE_UTIME_H) && !defined (NeXT) -#include <utime.h> -#elif defined (HAVE_SYS_UTIME_H) -# include <sys/utime.h> -#else -#ifndef ALTOS -struct utimbuf -{ - long actime; - long modtime; -}; -#endif -int utime (); -#endif - -#if STDC_HEADERS || HAVE_STRING_H -#include <string.h> -/* An ANSI string.h and pre-ANSI memory.h might conflict. */ -#if !STDC_HEADERS && HAVE_MEMORY_H -#include <memory.h> -#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ - -#ifndef index -#define index strchr -#endif /* index */ - -#ifndef rindex -#define rindex strrchr -#endif /* rindex */ - -#ifndef bcmp -#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) -#endif /* bcmp */ - -#ifndef bzero -#define bzero(s, n) memset ((s), 0, (n)) -#endif /* bzero */ - -#else /* not STDC_HEADERS and not HAVE_STRING_H */ -#include <strings.h> -/* memory.h and strings.h conflict on some systems. */ -#endif /* not STDC_HEADERS and not HAVE_STRING_H */ - -#include <errno.h> - -/* 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. */ - -#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 - - -#ifdef STDC_HEADERS -#include <stdlib.h> -#else -char *getenv (); -char *malloc (); -char *realloc (); -char *calloc (); -extern int errno; -#endif - -#if defined(USG) || defined(POSIX) -char *getcwd (); -#else -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 <fcntl.h> -#else -#include <sys/file.h> -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -#endif - -#ifndef F_OK -#define F_OK 0 -#define X_OK 1 -#define W_OK 2 -#define R_OK 4 -#endif - -#if HAVE_DIRENT_H -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -#endif - -/* Convert B 512-byte blocks to kilobytes if K is nonzero, - otherwise return it unchanged. */ -#define convert_blocks(b, k) ((k) ? ((b) + 1) / 2 : (b)) - -#ifndef S_ISLNK -#define lstat stat -#endif - -/* - * Some UNIX distributions don't include these in their stat.h Defined here - * because "config.h" is always included last. - */ -#ifndef S_IWRITE -#define S_IWRITE 0000200 /* write permission, owner */ -#endif -#ifndef S_IWGRP -#define S_IWGRP 0000020 /* write permission, grougroup */ -#endif -#ifndef S_IWOTH -#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 - own definitions. */ -#ifndef CVS_MKDIR -#define CVS_MKDIR mkdir -#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 /. */ -#ifndef FOLD_FN_CHAR -#define FOLD_FN_CHAR(c) (c) -#define fnfold(filename) (filename) -#define fncmp strcmp -#endif - -/* Different file systems have different path component separators. - For the VMS port we might need to abstract further back than this. */ -#ifndef ISDIRSEP -#define ISDIRSEP(c) ((c) == '/') -#endif - - -/* On some systems, lines in text files should be terminated with CRLF, - not just LF, and the read and write routines do this translation - for you. LINES_CRLF_TERMINATED is #defined on such systems. - - OPEN_BINARY is the flag to pass to the open function for - untranslated I/O. - - FOPEN_BINARY_READ is the string to pass to fopen to get - untranslated reading. - - FOPEN_BINARY_WRITE is the string to pass to fopen to get - untranslated writing. */ -#if LINES_CRLF_TERMINATED -#define OPEN_BINARY (O_BINARY) -#define FOPEN_BINARY_READ ("rb") -#define FOPEN_BINARY_WRITE ("wb") -#else -#define OPEN_BINARY (0) -#define FOPEN_BINARY_READ ("r") -#define FOPEN_BINARY_WRITE ("w") -#endif diff --git a/gnu/usr.bin/cvs/lib/version.c b/gnu/usr.bin/cvs/lib/version.c deleted file mode 100644 index 2eb66cd..0000000 --- a/gnu/usr.bin/cvs/lib/version.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 1994 david d `zoo' zuhn - * Copyright (c) 1994 Free Software Foundation, Inc. - * 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 this CVS source distribution. - * - * version.c - the CVS version number - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)version.c 1.15 94/10/03 $"; -USE(rcsid); -#endif - -char *version_string = "\nConcurrent Versions System (CVS) 1.6.3"; - -#ifdef CLIENT_SUPPORT -#ifdef SERVER_SUPPORT -char *config_string = " (client/server)\n"; -#else -char *config_string = " (client)\n"; -#endif -#else -#ifdef SERVER_SUPPORT -char *config_string = " (server)\n"; -#else -char *config_string = "\n"; -#endif -#endif diff --git a/gnu/usr.bin/cvs/lib/wait.h b/gnu/usr.bin/cvs/lib/wait.h deleted file mode 100644 index db60434..0000000 --- a/gnu/usr.bin/cvs/lib/wait.h +++ /dev/null @@ -1,32 +0,0 @@ -/* wait.h -- POSIX macros for evaluating exit statuses - 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. */ - -#ifdef HAVE_SYS_WAIT_H -#include <sys/types.h> /* For pid_t. */ -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> /* for rusage */ -#endif -#include <sys/wait.h> -#else -#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f) -#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0) -#define WIFEXITED(w) (((w) & 0xff) == 0) - -#define WSTOPSIG(w) (((w) >> 8) & 0xff) -#define WTERMSIG(w) ((w) & 0x7f) -#define WEXITSTATUS(w) (((w) >> 8) & 0xff) -#endif diff --git a/gnu/usr.bin/cvs/lib/xgetwd.c b/gnu/usr.bin/cvs/lib/xgetwd.c deleted file mode 100644 index 8fe4ec1..0000000 --- a/gnu/usr.bin/cvs/lib/xgetwd.c +++ /dev/null @@ -1,79 +0,0 @@ -/* xgetwd.c -- return current directory with unlimited length - 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. */ - -/* Derived from xgetcwd.c in e.g. the GNU sh-utils. */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "system.h" - -#include <stdio.h> -#include <errno.h> -#ifndef errno -extern int errno; -#endif -#include <sys/types.h> - -#ifndef HAVE_GETWD -char *getwd (); -#define GETWD(buf, max) getwd (buf) -#else -char *getcwd (); -#define GETWD(buf, max) getcwd (buf, max) -#endif - -/* Amount by which to increase buffer size when allocating more space. */ -#define PATH_INCR 32 - -char *xmalloc (); -char *xrealloc (); - -/* Return the current directory, newly allocated, arbitrarily long. - Return NULL and set errno on error. */ - -char * -xgetwd () -{ - char *cwd; - char *ret; - unsigned path_max; - - errno = 0; - path_max = (unsigned) PATH_MAX; - path_max += 2; /* The getcwd docs say to do this. */ - - cwd = xmalloc (path_max); - - errno = 0; - while ((ret = GETWD (cwd, path_max)) == NULL && errno == ERANGE) - { - path_max += PATH_INCR; - cwd = xrealloc (cwd, path_max); - errno = 0; - } - - if (ret == NULL) - { - int save_errno = errno; - free (cwd); - errno = save_errno; - return NULL; - } - return cwd; -} diff --git a/gnu/usr.bin/cvs/lib/yesno.c b/gnu/usr.bin/cvs/lib/yesno.c deleted file mode 100644 index 7014803..0000000 --- a/gnu/usr.bin/cvs/lib/yesno.c +++ /dev/null @@ -1,41 +0,0 @@ -/* yesno.c -- read a yes/no response from stdin - 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. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> - -/* Read one line from standard input - and return nonzero if that line begins with y or Y, - otherwise return 0. */ - -int -yesno () -{ - int c; - int rv; - - fflush (stderr); - c = getchar (); - rv = (c == 'y') || (c == 'Y'); - while (c != EOF && c != '\n') - c = getchar (); - - return rv; -} diff --git a/gnu/usr.bin/cvs/mkmodules/Makefile b/gnu/usr.bin/cvs/mkmodules/Makefile deleted file mode 100644 index 78c2bb9..0000000 --- a/gnu/usr.bin/cvs/mkmodules/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# $Id: Makefile,v 1.5 1995/03/31 07:55:30 nate Exp $ - -PROG = mkmodules -SRCS = mkmodules.c -CFLAGS+= -I${.CURDIR}/../cvs -I${.CURDIR}/../lib -DHAVE_CONFIG_H -DPADD+= ${LIBCVS} -LDADD+= -lcvs - -.include "../../Makefile.inc" -.include <bsd.prog.mk> diff --git a/gnu/usr.bin/cvs/mkmodules/mkmodules.1 b/gnu/usr.bin/cvs/mkmodules/mkmodules.1 deleted file mode 100644 index ff446ab..0000000 --- a/gnu/usr.bin/cvs/mkmodules/mkmodules.1 +++ /dev/null @@ -1,65 +0,0 @@ -.\" -.\" $CVSid: @(#)mkmodules.1 1.3 92/01/30 $ -.\" -.TH MKMODULES 1 "12 October 1991" -.SH "NAME" -mkmodules \- Rebuild modules database for CVS -.SH "SYNOPSIS" -.B mkmodules -.I directory -.SH "DESCRIPTION" -.B mkmodules -rebuilds the modules database that -.BR cvs (1) -uses. -The -.I directory -specified is expected to contain the -.BR modules,v " and " loginfo,v -files. -.B mkmodules -carefully checks out the current head revisions of each of these files and -reuilds the -.BR ndbm (3) -format modules database. -A warning is generated if the modules file contains a duplicate key. -.SH "FILES" -.TP -modules,v -The modules -.SM RCS -file. -.TP -modules -The checked out modules file. -.TP -loginfo,v -The loginfo -.SM RCS -file. -.TP -loginfo -The checked out loginfo file. -.TP -modules.dir, modules.pag -The -.BR ndbm (1) -format modules database. -.SH "ENVIRONMENT VARIABLES" -.TP -.SM RCSBIN -Specifies the full pathname where to find -.SM RCS -programs, such as -.BR co (1) -and -.BR ci (1). -If not set, the default is -.BR /usr/local/bin . -.SH "SEE ALSO" -.BR ci (1), -.BR co (1), -.BR cvs (1), -.\" .BR ndbm (3), -.BR rcs (1), -.SH "BUGS" diff --git a/gnu/usr.bin/cvs/mkmodules/mkmodules.c b/gnu/usr.bin/cvs/mkmodules/mkmodules.c deleted file mode 100644 index 9b0e7bd..0000000 --- a/gnu/usr.bin/cvs/mkmodules/mkmodules.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * 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. - * - * mkmodules - * - * Re-build the modules database for the CVS system. Accepts one argument, - * which is the directory that the modules,v file lives in. - */ - -#include "cvs.h" - -#ifndef lint -static const char rcsid[] = "$CVSid: @(#)mkmodules.c 1.45 94/09/30 $"; -USE(rcsid); -#endif - -#ifndef DBLKSIZ -#define DBLKSIZ 4096 /* since GNU ndbm doesn't define it */ -#endif - -char *program_name, *command_name; - -char *Rcsbin = RCSBIN_DFLT; -char *CVSroot = CVSROOT_DFLT; -int noexec = 0; /* Here only to satisfy use in subr.c */ -int trace = 0; /* Here only to satisfy use in subr.c */ - -static int checkout_file PROTO((char *file, char *temp)); -static void make_tempfile PROTO((char *temp)); -static void mkmodules_usage PROTO((void)); -static void rename_rcsfile PROTO((char *temp, char *real)); - -#ifndef MY_NDBM -static void rename_dbmfile PROTO((char *temp)); -static void write_dbmfile PROTO((char *temp)); -#endif /* !MY_NDBM */ - - -int -main (argc, argv) - int argc; - char **argv; -{ - char temp[PATH_MAX]; - char *cp, *last, *fname; -#ifdef MY_NDBM - DBM *db; -#endif - FILE *fp; - char line[512]; - static struct _checkout_file { - char *filename; - char *errormsg; - } *fileptr, filelist[] = { - {CVSROOTADM_LOGINFO, - "no logging of 'cvs commit' messages is done without a %s file"}, - {CVSROOTADM_RCSINFO, - "a %s file can be used to configure 'cvs commit' templates"}, - {CVSROOTADM_EDITINFO, - "a %s file can be used to validate log messages"}, - {CVSROOTADM_COMMITINFO, - "a %s file can be used to configure 'cvs commit' checking"}, - {CVSROOTADM_TAGINFO, - "a %s file can be used to configure 'cvs tag' checking"}, - {CVSROOTADM_IGNORE, - "a %s file can be used to specify files to ignore"}, - {CVSROOTADM_CHECKOUTLIST, - "a %s file can specify extra CVSROOT files to auto-checkout"}, - {CVSROOTADM_WRAPPER, - "a %s file can be used to specify files to treat as wrappers"}, - {NULL, NULL}}; - - /* - * Just save the last component of the path for error messages - */ - program_name = last_component (argv[0]); - - if (argc != 2) - mkmodules_usage (); - - if ((cp = getenv (RCSBIN_ENV)) != NULL) - Rcsbin = cp; - - /* - * If Rcsbin is set to something, make sure it is terminated with a slash - * character. If not, add one. - */ - if (Rcsbin[0] != '\0') - { - int len = strlen (Rcsbin); - char *rcsbin; - - if (Rcsbin[len - 1] != '/') - { - rcsbin = Rcsbin; - Rcsbin = xmalloc (len + 2); /* one for '/', one for NULL */ - (void) strcpy (Rcsbin, rcsbin); - (void) strcat (Rcsbin, "/"); - } - } - - if (chdir (argv[1]) < 0) - error (1, errno, "cannot chdir to %s", argv[1]); - - /* - * First, do the work necessary to update the "modules" database. - */ - make_tempfile (temp); - switch (checkout_file (CVSROOTADM_MODULES, temp)) - { - - case 0: /* everything ok */ -#ifdef MY_NDBM - /* open it, to generate any duplicate errors */ - if ((db = dbm_open (temp, O_RDONLY, 0666)) != NULL) - dbm_close (db); -#else - write_dbmfile (temp); - rename_dbmfile (temp); -#endif - rename_rcsfile (temp, CVSROOTADM_MODULES); - break; - - case -1: /* fork failed */ - (void) unlink_file (temp); - exit (1); - /* NOTREACHED */ - - default: - error (0, 0, - "'cvs checkout' is less functional without a %s file", - CVSROOTADM_MODULES); - break; - } /* switch on checkout_file() */ - - (void) unlink_file (temp); - - /* Checkout the files that need it in CVSROOT dir */ - for (fileptr = filelist; fileptr && fileptr->filename; fileptr++) { - make_tempfile (temp); - if (checkout_file (fileptr->filename, temp) == 0) - rename_rcsfile (temp, fileptr->filename); -#if 0 - /* - * If there was some problem other than the file not existing, - * checkout_file already printed a real error message. If the - * file does not exist, it is harmless--it probably just means - * that the repository was created with an old version of CVS - * which didn't have so many files in CVSROOT. - */ - else if (fileptr->errormsg) - error (0, 0, fileptr->errormsg, fileptr->filename); -#endif - (void) unlink_file (temp); - } - - /* Use 'fopen' instead of 'open_file' because we want to ignore error */ - fp = fopen (CVSROOTADM_CHECKOUTLIST, "r"); - if (fp) - { - /* - * File format: - * [<whitespace>]<filename><whitespace><error message><end-of-line> - * - * comment lines begin with '#' - */ - while (fgets (line, sizeof (line), fp) != NULL) - { - /* skip lines starting with # */ - if (line[0] == '#') - continue; - - if ((last = strrchr (line, '\n')) != NULL) - *last = '\0'; /* strip the newline */ - - /* Skip leading white space. */ - for (fname = line; *fname && isspace(*fname); fname++) - ; - - /* Find end of filename. */ - for (cp = fname; *cp && !isspace(*cp); cp++) - ; - *cp = '\0'; - - make_tempfile (temp); - if (checkout_file (fname, temp) == 0) - { - rename_rcsfile (temp, fname); - } - else - { - for (cp++; cp < last && *last && isspace(*last); cp++) - ; - if (cp < last && *cp) - error (0, 0, cp, fname); - } - } - (void) fclose (fp); - } - - return (0); -} - -/* - * Yeah, I know, there are NFS race conditions here. - */ -static void -make_tempfile (temp) - char *temp; -{ - static int seed = 0; - int fd; - - if (seed == 0) - seed = getpid (); - while (1) - { - (void) sprintf (temp, "%s%d", BAKPREFIX, seed++); - if ((fd = open (temp, O_CREAT|O_EXCL|O_RDWR, 0666)) != -1) - break; - if (errno != EEXIST) - error (1, errno, "cannot create temporary file %s", temp); - } - if (close(fd) < 0) - error(1, errno, "cannot close temporary file %s", temp); -} - -static int -checkout_file (file, temp) - char *file; - char *temp; -{ - char rcs[PATH_MAX]; - int retcode = 0; - - (void) sprintf (rcs, "%s%s", file, RCSEXT); - if (!isfile (rcs)) - return (1); - run_setup ("%s%s -q -p", Rcsbin, RCS_CO); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, temp, RUN_TTY, RUN_NORMAL)) != 0) - { - error (0, retcode == -1 ? errno : 0, "failed to check out %s file", file); - } - return (retcode); -} - -#ifndef MY_NDBM - -static void -write_dbmfile (temp) - char *temp; -{ - char line[DBLKSIZ], value[DBLKSIZ]; - FILE *fp; - DBM *db; - char *cp, *vp; - datum key, val; - int len, cont, err = 0; - - fp = open_file (temp, "r"); - if ((db = dbm_open (temp, O_RDWR | O_CREAT | O_TRUNC, 0666)) == NULL) - error (1, errno, "cannot open dbm file %s for creation", temp); - for (cont = 0; fgets (line, sizeof (line), fp) != NULL;) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; /* strip the newline */ - - /* - * Add the line to the value, at the end if this is a continuation - * line; otherwise at the beginning, but only after any trailing - * backslash is removed. - */ - vp = value; - if (cont) - vp += strlen (value); - - /* - * See if the line we read is a continuation line, and strip the - * backslash if so. - */ - len = strlen (line); - if (len > 0) - cp = &line[len - 1]; - else - cp = line; - if (*cp == '\\') - { - cont = 1; - *cp = '\0'; - } - else - { - cont = 0; - } - (void) strcpy (vp, line); - if (value[0] == '#') - continue; /* comment line */ - vp = value; - while (*vp && isspace (*vp)) - vp++; - if (*vp == '\0') - continue; /* empty line */ - - /* - * If this was not a continuation line, add the entry to the database - */ - if (!cont) - { - key.dptr = vp; - while (*vp && !isspace (*vp)) - vp++; - key.dsize = vp - key.dptr; - *vp++ = '\0'; /* NULL terminate the key */ - while (*vp && isspace (*vp)) - vp++; /* skip whitespace to value */ - if (*vp == '\0') - { - error (0, 0, "warning: NULL value for key `%s'", key.dptr); - continue; - } - val.dptr = vp; - val.dsize = strlen (vp); - if (dbm_store (db, key, val, DBM_INSERT) == 1) - { - error (0, 0, "duplicate key found for `%s'", key.dptr); - err++; - } - } - } - dbm_close (db); - (void) fclose (fp); - if (err) - { - char dotdir[50], dotpag[50], dotdb[50]; - - (void) sprintf (dotdir, "%s.dir", temp); - (void) sprintf (dotpag, "%s.pag", temp); - (void) sprintf (dotdb, "%s.db", temp); - (void) unlink_file (dotdir); - (void) unlink_file (dotpag); - (void) unlink_file (dotdb); - error (1, 0, "DBM creation failed; correct above errors"); - } -} - -static void -rename_dbmfile (temp) - char *temp; -{ - char newdir[50], newpag[50], newdb[50]; - char dotdir[50], dotpag[50], dotdb[50]; - char bakdir[50], bakpag[50], bakdb[50]; - - (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES); - (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES); - (void) sprintf (dotdb, "%s.db", CVSROOTADM_MODULES); - (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakdb, "%s%s.db", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (newdir, "%s.dir", temp); - (void) sprintf (newpag, "%s.pag", temp); - (void) sprintf (newdb, "%s.db", temp); - - (void) chmod (newdir, 0666); - (void) chmod (newpag, 0666); - (void) chmod (newdb, 0666); - - /* don't mess with me */ - SIG_beginCrSect (); - - (void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */ - (void) unlink_file (bakpag); - (void) unlink_file (bakdb); - (void) rename (dotdir, bakdir); /* mv modules.dir .#modules.dir */ - (void) rename (dotpag, bakpag); /* mv modules.pag .#modules.pag */ - (void) rename (dotdb, bakdb); /* mv modules.db .#modules.db */ - (void) rename (newdir, dotdir); /* mv "temp".dir modules.dir */ - (void) rename (newpag, dotpag); /* mv "temp".pag modules.pag */ - (void) rename (newdb, dotdb); /* mv "temp".db modules.db */ - - /* OK -- make my day */ - SIG_endCrSect (); -} - -#endif /* !MY_NDBM */ - -static void -rename_rcsfile (temp, real) - char *temp; - char *real; -{ - char bak[50]; - struct stat statbuf; - char rcs[PATH_MAX]; - - /* Set "x" bits if set in original. */ - (void) sprintf (rcs, "%s%s", real, RCSEXT); - statbuf.st_mode = 0; /* in case rcs file doesn't exist, but it should... */ - (void) stat (rcs, &statbuf); - - if (chmod (temp, 0444 | (statbuf.st_mode & 0111)) < 0) - error (0, errno, "warning: cannot chmod %s", temp); - (void) sprintf (bak, "%s%s", BAKPREFIX, real); - (void) unlink_file (bak); /* rm .#loginfo */ - (void) rename (real, bak); /* mv loginfo .#loginfo */ - (void) rename (temp, real); /* mv "temp" loginfo */ -} - -/* - * For error() only - */ -void -Lock_Cleanup () -{ -} - -int server_active = 0; - -void -server_cleanup (sig) - int sig; -{ -} - -static void -mkmodules_usage () -{ - (void) fprintf (stderr, "Usage: %s modules-directory\n", program_name); - exit (1); -} |