diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index 61e83f1b95c1df6c79c7dba0cb86657c442ea749..0000000000000000000000000000000000000000 --- a/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -Makefile -config.status -config.log -config.cache -config.h -stamp-h -cvsinit diff --git a/BUGS b/BUGS deleted file mode 100644 index a7fe3982548de0efbf12056cb495bc7c4eec9e31..0000000000000000000000000000000000000000 --- a/BUGS +++ /dev/null @@ -1,410 +0,0 @@ -* 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). - -* If patch fails, CCVS tries to transfer the whole file, but it - doesn't seem to handle this correctly: - - cvs server: Updating . - patch: **** malformed patch at line 98: 28978/socket: File name too long - cvs update: could not patch BUGS; will refetch - cvs server: Updating contrib - cvs server: Updating contrib/pcl-cvs - cvs server: Updating doc - cvs server: Updating examples - cvs server: Updating lib - cvs server: Updating man - cvs server: Updating src - P BUGS - cvs client: refetching unpatchable files - ? .//.new.BUGS - Is a directory - -* The build process isn't configure, make. The stuff in options.h - could be derived by autoconf, couldn't it? - -* 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? - - -* We don't understand the relationship between modules and subdirs - very well. However, it is certainly the case that - - CVSROOT=<local-cvs-repository> cvs checkout cvs - - and - - CVSROOT=<remote-cvs-repository> cvs checkout cvs - - ought to produce the same dir tree, and they don't. On floss, - checking out cvs gets cygnus/cvs/..., whereas on totoro it gets - cvs/... bad, bad, bad, Bad, BAD. Charles Hannum has noticed this too, - see immediately below: - - -* From: "Charles M. Hannum" <mycroft@ai.mit.edu> - To: remote-cvs@cyclic.com - Subject: Yet another bug - Date: Thu, 23 Feb 1995 21:28:31 -0500 - - Modules don't work correctly remotely. e.g. If I have a module `foo' - that points to `src/bin/foo', and I type `cvs get foo': - - 1) Locally, CVS checks it out into a directory named `foo'. - 2) Remotely, CVS checks it out into a directory named `src/bin/foo'. - - The latter is incorrect. - - -* Is it still the case that cvs tries to use Perl and fails, so that - installers need to fix by hand the line in - $repository/CVSROOT/loginfo to read: - - DEFAULT (echo ""; echo $USER; date; cat) >> $CVSROOT/CVSROOT/commitlog - - If so, we ought to either make it work as intended or take out the - attempted Perl entirely. - - -* (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'. - - 4) This isn't specific to remote CVS, but apparently the times stored - in the Entries files are not GMT. I have a checked out tree copied - from another machine in a different time zone, and when I try to - update it, CVS thinks that all the files are modified and sends them - to the server for comparison. (That's why I noticed #1.) - [ See his followup below, though. -K ] - - -* (Charles Hannum <mycroft@ai.mit.edu>) - It turns out that the old version of CVS I was using wrote the time - stamps in local time, but the new one writes and expects them in GMT. - I have *no idea* how the old version actually read and compared the - time stamps, and managed to deal with DST correctly, but I have time - stamps that were in DST and ones that weren't, and it seemed to deal - correctly. I'm afraid to look any further. - [ So shall we assume that this is fixed in rcvs? -K ] - - Anyway, the path of least resistance seems to be to suffer an - expensive update once. - - I still need to fix the relative path problem, though... - - -* 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: Another bug - Date: Thu, 23 Feb 1995 21:26:19 -0500 - - `cvs add' doesn't work correctly remotely. The ,t and ,p files are - not created. This causes the server to dump core because it tries to - fclose(NULL) in checkaddfile(). - - - From: "Charles M. Hannum" <mycroft@ai.mit.edu> - To: jimb@totoro.bio.indiana.edu - Cc: remote-cvs@cyclic.com - Subject: Regarding `rcsmerge -E' - Date: Thu, 23 Feb 1995 23:02:00 -0500 - - - Can you post more exact reproduction instructions? - - It happens every time I try to `cvs add' remotely. The client does - not create CVS/foo,p and CVS/foo,t files locally. There are none - created in the shadow tree on the server when I run `cvs commit'. - When the server tries to commit the file, it core dumps trying to - fclose(NULL) from checkaddfile(). - - On some systems, fclose(NULL) is a noop, so CVS won't core dump. In - that case, the server just ignores the fact that the ,p file doesn't - exist. However, on some systems it does lose. - - For now, just having it not try to fclose() in that case is enough. - Here's a patch: - -Index: commit.c -=================================================================== -RCS file: /b/source/CVS/othersrc/cvs/src/commit.c,v -retrieving revision 1.1.1.1 -diff -c -2 -r1.1.1.1 commit.c -*** commit.c 1995/02/22 05:48:43 1.1.1.1 ---- commit.c 1995/02/24 03:44:25 -*************** -*** 1493,1506 **** - /* If the file does not exist, no big deal. In particular, the - server does not (yet at least) create CVSEXT_OPT files. */ -! if (fp == NULL && errno != ENOENT) -! error (1, errno, "cannot open %s", fname); -! while (fp != NULL && fgets (fname, sizeof (fname), fp) != NULL) - { -! if ((cp = strrchr (fname, '\n')) != NULL) -! *cp = '\0'; -! if (*fname) -! run_arg (fname); - } -- (void) fclose (fp); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) ---- 1493,1512 ---- - /* If the file does not exist, no big deal. In particular, the - server does not (yet at least) create CVSEXT_OPT files. */ -! if (fp == NULL) - { -! if (errno != ENOENT) -! error (1, errno, "cannot open %s", fname); -! } -! else -! { -! while (fgets (fname, sizeof (fname), fp) != NULL) -! { -! if ((cp = strrchr (fname, '\n')) != NULL) -! *cp = '\0'; -! if (*fname) -! run_arg (fname); -! } -! (void) fclose (fp); - } - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) - - -* Somewhere in the documentation we should warn users to avoid RCS -versions 5.6.[5-7] beta because rcsmerge uses -A by default instead of --E (-E is correct). CVS can't just pass -E unless it tests at runtime -whether RCS supports it (configure time is not good enough, the -version of RCS might change, CVS might be copied to a different -machine, etc.). RCS 5.6.0.1 does not support -E. We also might -supply an RCS patch. - - -* 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/COPYING b/COPYING deleted file mode 100644 index 9a170375811150e8f01ab7b88513aeeee5e527d1..0000000000000000000000000000000000000000 --- a/COPYING +++ /dev/null @@ -1,249 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 - - Copyright (C) 1989 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. - - Preamble - - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our 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. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, 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 a 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 tell them 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. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement 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 work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. 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 -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual 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 General - Public License. - - d) 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. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying 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. - - 6. 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. - - 7. 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 the 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 -the license, you may choose any version ever published by the Free Software -Foundation. - - 8. 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. - - NO WARRANTY - - 9. 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. - - 10. 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 OF TERMS AND CONDITIONS - - 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 humanity, 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. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <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 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. - -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: - - Gnomovision version 69, Copyright (C) 19xx 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. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `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 a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/COPYING.LIB b/COPYING.LIB deleted file mode 100644 index eb685a5ec981b949faa391ad3fc395cd42932510..0000000000000000000000000000000000000000 --- a/COPYING.LIB +++ /dev/null @@ -1,481 +0,0 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 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. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, 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 library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, 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 companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, 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 library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete 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 distribute a copy of this License along with the -Library. - - 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. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -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 Library, 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 Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you 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. - - If distribution of 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 satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. 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. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library 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. - - 9. 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 Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -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. - - 11. 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 Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library 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 Library. - -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. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library 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. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library 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 Library -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 Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -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. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. 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 LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. 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. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 33867211604d0ae18f0800c543c9a4ed7b759e2b..0000000000000000000000000000000000000000 --- a/ChangeLog +++ /dev/null @@ -1,119 +0,0 @@ -Wed Feb 8 06:49:49 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * Makefile.in (stamp-h): Pass CONFIG_FILES=$@ to config.status so - the target is created. - * configure.in: Applied `autoupdate' from Autoconf 2.1 to - modernize macro usage. - (AC_RSH): Call removed. It was obsolete and not doing anything useful. - (AC_OUTPUT): Write stamp-h as the Makefile rules expect we will. - (AC_TYPE_PID_T): Add this check. - -Tue Nov 8 06:26:54 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Add stamp-h.in. Remove it from .cvsignore. - -Fri Oct 28 11:50:51 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in: Comment out autoconf and autoheader rules. - -Tue Oct 25 17:44:13 1994 Ken Raeburn <raeburn@cujo.cygnus.com> - - * Makefile.in (all, install, uninstall): Fail if make in - subdirectory fails. - -Tue Oct 18 13:26:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in (FLAGS_TO_PASS): Pass INSTALL*. Add comment about - why we need to. - -Tue Sep 27 08:27:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * Makefile.in (SUBDIRS): Reinstate "contrib". - * configure.in (AC_OUTPUT): Add contrib/Makefile. - * configure: Regenerated. - -Tue Sep 27 01:03:59 1994 John Gilmore (gnu@cygnus.com) - - * Makefile.in (SUBDIRS): Comment out "contrib". Since we don't - bother to configure it, we shouldn't make it either. - -Wed Aug 10 14:52:57 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * Makefile.in (FLAGS_TO_PASS): Don't include LIBS or CFLAGS twice. - - * configure.in: Include waitpid and memmove in AC_REPLACE_FUNCS - list. Don't check for memmove separately. - * configure: Regenerated. - * config.h.in: Regenerated for Mark's change. - -Wed Aug 10 14:32:24 1994 Mark Eichin (eichin@cygnus.com) - - * configure.in (KRB4): recognize --with-krb4=path. Also test for - krb_get_err_text so src/main.c and src/client.c can deal - appropriately. - -Tue Aug 9 15:49:07 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * configure.in: Check sizes of `long' and `int', needed for md5 - code. - * acconfig.h: New file. Mention HAVE_KERBEROS, to keep autoheader - happy. - * configure, config.h.in: Regenerated. - -Tue Jul 19 11:23:21 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * configure.in: Check not only that krb.h exists, but that it will - actually compile correctly. - * configure: Regenerated. - -Mon Jul 11 07:04:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * configure.in: Add comment re autoheader. - -Tue Jun 28 22:09:23 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * configure.in: Only look for -lsocket and -lnsl if we don't - already have connect. - * configure: Regenerated. - -Mon Jun 27 17:21:48 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * configure.in: Correct "krb_libdir" to "${krb_libdir}". - * configure: Regenerated. - -Fri Jun 3 10:15:24 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * configure.in: Check for -lsocket and -lnsl. - * configure: Regenerated. - -Fri May 27 18:12:43 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * configure.in: Add valloc to AC_REPLACE_FUNCS. Add getpagesize - to AC_HAVE_FUNCS. Check for krb.h and -lkrb. If not found, look - in /usr/kerberos if native. If found somewhere, define - HAVE_KERBEROS and also look for -ldes. Substitute includeopt. - * configure: Regenerated. - -Fri Mar 11 13:11:51 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * configure.in: Check for <sys/select.h>; used by src/server.c. - * configure: Regenerated. - -Sun Jan 9 12:04:15 1994 Ken Raeburn (raeburn@kr-pc.cygnus.com) - - * configure.in: Check for timezone function, for NetBSD support. - * configure: Regenerated. - -Wed Dec 15 18:05:21 1993 david d `zoo' zuhn (zoo@andros.cygnus.com) - - * Makefile.in: add MAKEINFO to MDEFINES, pass down MDEFINES on all - recursive make invocations that require it; define - INSTALL_PROGRAM and use it; reorganize MDEFINES; set infodir and - add to MDEFINES; use YACC instead of BISON - - -Mon Dec 6 17:02:18 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * src/diff.c (diff_fileproc): add support for "cvs diff -N" which - allows for adding or removing files via patches. - diff --git a/ChangeLog.zoo b/ChangeLog.zoo deleted file mode 100644 index a1e1d0ed9191be845f1a06edbce1f20f848042b2..0000000000000000000000000000000000000000 --- a/ChangeLog.zoo +++ /dev/null @@ -1,700 +0,0 @@ -Thu Sep 15 14:19:21 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * Makefile.in: define TEXI2DVI, add it to FLAGS_TO_PASS; remove - old comments about parameters for DEFS - -Wed Jul 13 21:54:46 1994 david d `zoo' zuhn (zoo@monad.armadillo.com) - - * contrib/rcs-to-cvs: rewritten for Bourne shell (thanks to David - MacKenzie <djm@cygnus.com>) - -Wed Jul 13 21:48:38 1994 Ken Raeburn (raeburn@cujo.cygnus.com) - - * Makefile.in: Deleted line consisting of only whitespace; it - confuses some versions of make. - -Mon Jan 24 12:26:47 1994 david d zuhn (zoo@monad.armadillo.com) - - * configure.in: check for <sys/select.h> and <ndbm.h> - - * Makefile.in: define YACC and not BISON - -Sat Dec 18 00:52:04 1993 david d zuhn (zoo@monad.armadillo.com) - - * config.h.in: handle HAVE_SYS_WAIT_H, HAVE_ERRNO_H - - * configure.in: check for memmove, <errno.h> - - * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead - - * configure.in (AC_HAVE_HEADERS): check for <sys/wait.h> - -Mon Nov 29 15:05:43 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * lib/Makefile.in, src/Makefile.in (CFLAGS): default to -g. - - * src/log.c (log_fileproc): if a file has been added, but not - committed, then say so rather than reporting that nothing is - known. - - * src/sanity.el: update for emacs-19. - - * src/RCS-patches, src/README-rm-add: update for rcs-5.6.6. - - * src/Makefile.in: removed some gratuitous diffs from cvs-1.3. - - * src/cvsrc.c: strdup -> xstrdup, malloc -> xmalloc, comment about - fgets lossage. - - * configure, configure.in, Makefile.in: support man and doc - directories and info and dvi targets. - - * doc/cvs.texinfo: comment out include of gpl.texinfo. - - * doc/Makefile.in: added dvi & info targets. - - * doc/cvsclient.texi: added @setfilename. - - * lib/Makefile.in: remove some extraneous diffs against the - patched cvs-1.3. - - * doc/Makefile.in, man/Makefile.in: update for autoconf. - -Fri Nov 19 12:56:34 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * Many files: added configure.in, updated configure based on - autoconf. - -Tue Jun 1 17:02:41 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * configure: add support for alloca and sys/select.h - -Wed May 19 19:34:48 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvs-format.el: Don't set c-tab-always-indent. - -Mon Mar 22 23:25:33 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in: installcheck: recurse into src directory to run tests - -Mon Jan 18 17:21:16 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * Makefile.in (check): recur into src directory in order to pick - up the sanity check. - -Thu Dec 17 19:41:22 1992 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in: added blank 'dvi' target - -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@ksr.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. - -@(#)ChangeLog 1.17 92/04/10 diff --git a/FAQ b/FAQ deleted file mode 100644 index 325a342ff6bf3c0cf3020a5471b23bd626961db4..0000000000000000000000000000000000000000 --- a/FAQ +++ /dev/null @@ -1,7826 +0,0 @@ - -Archive-name: cvs-faq -$Revision: 1.1.1.1 $ <<== Include this in your comments -$Date: 1994/12/03 06:09:14 $ - -=========================================================================== -== 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: - - Though every 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@think.com> - - - To help readers of previous versions of this document, I will annotate - each question with a change marker - - 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. - - - The markers indicate significant changes in content between major - revision numbers. Trivial changes, such as question reordering or - spelling and grammar corrections are not marked. If I need to delete - a question, I'll move it to a "Deleted" section for a few revisions. - Deletions will arise when new versions of CVS are released. In the - long run, any question that can be answered by "get the latest - release" will be deleted. - - The minor revision number will change frequently. If a minor revision - change is large enough, I'll add a change marker. At major revision - changes the markers will be cleared and set again, based on the latest - minor revision of the previous major revision. - - - - Editorial comments are delimited by pairs of "[[" & "]]". They - contain either references to the (usually unfinished) nature of the - FAQ entry itself or version-specific comments to be removed (or - altered) when new revisions of CVS are released. - - You may redistribute this as long as you don't take statements out - of context. Keep it together along with the revision number. - - -============================================ -== 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 - D. Tricks of the Trade - E. Weirdness - F. Related Software - G. Other Systems - - 5. Past & Future - A. Contributors. - B. Bugs and Patches - C. Development - - 6. Table of Contents - - -Final note: - - Except for the "Past & Future" section, all answers in this - document refer to the latest released version of CVS: 1.3. - - -============================================ -== 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? -=1A.6 Why isn't it called OSCO (Online Source COntrol)? - - - **** 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 changes to files 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 stores its files 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 the "checkout" command, handing it - a module or directory you want to work on. CVS copies each file - in the specified module or directory out of the Repository and - into a sub-directory created in your current directory. - - You may then modify files in the new sub-directory, building them - into output files and testing 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" - can produce 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 be useful for three major activities: - - 1. Multiple developers - - The major advantage of using CVS over the older and 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 point 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. Vendor releases - - If you are making changes to a product distributed by someone - else, the CVS feature, called the Vendor Branch, allows you - to combine local modifications with 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 require medium amounts of - work. (e.g. GNU programs, X, etc.) - - - 3. Branches - - 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.) - - Although, at this writing, CVS's branch support is a bit - primitive, CVS was designed to allow you to create branches, - work on them for while and merge them back into the main - line of development. 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. 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 write your Makefiles 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, 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 place the tools created to support such - a build system (scripts, Makefiles, etc) under CVS. - - - 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, CVS can't help. - - 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 (i.e. "diff3") command. - - 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 X - defined in file A. At the same time, someone edits 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. - - -=1A.6 Why isn't it called OSCO (Online Source COntrol)? - - Better discount? CVS is shorter? (The international audience - requires an explanation: Both CVS and OSCO are the names of large - chains of Pharmacies (drug stores) in the U.S.) - - - ----------------- --- 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 a copy of the latest version of CVS? - 1B.4 Is there any other documentation? How about tutorials? - 1B.5 Is there a mailing list devoted to CVS? How do I get on it? - 1B.6 What prayers are appropriate for each of the major denominations - (e.g. 20's, 50's, 100's) when issuing complex CVS commands? -+1B.7 How do I get files out of the archive if I don't have FTP? - - - **** Answers: - -=1B.1 How do I get more information about CVS? - - 1. The first thing you should do is read the man page. - - 2. Type "cvs -H" for general help or "cvs -H command" for - command-specific help. - - 3. Read the original CVS paper (in the source tree, under "doc"). - It describes the purpose of CVS and some of its workings. Note - that some of the emphasis (especially on multiple vendors - providing the same sources) is out of date. - - 4. Read the man pages for RCS. - - 5. Read the source code. - - 6. Look in the "doc" directory in the FTP archive described - below. - - 7. Read the gnu.cvs.info newsgroup. - - 8. If you don't get the newsgroup, you can 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 documentation, patches and - the latest release. - - ftp think.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. - - -+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. To use DEC's ftpmail service, type - - echo 'send help' | mail ftpmail@decwrl.dec.com - - which will send you a message telling you how to use Email to - retrieve files from FTP archives. - - - 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@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 is - another archive at UUNET and other large Internet sites. - - Program(s) Latest revision - ----------- ----------------------- - CVS 1.3 - RCS 5.6.0.1 - GNU diff 2.3 - - The GNU version of diff is suggested by both the RCS and CVS - configuration instructions because it works better than the - standard version. If you plan to use dbm in the modules file, you - might also want to pick up the GNU dbm library. - - 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 probably want. - - 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 any other documentation? How about tutorials? - - Take a look at the "doc" sub-directory in the FTP archive. - You should find a growing collection of additional CVS - documentation there. - - Other sources: - - 1. Per Cederqvist's Texinfo manual. - - The latest version of the Texinfo manual written by Per - Cederqvist is included in the "doc" area mentioned - above. - - - 2. Gray Watson's cvs_tutorial. - - There is a version of this document in the "doc" area. - - 3. Apparently there is at least one project at O'Reilly (on - RCS/SCCS) that will include some info about CVS. - - - [[Anything else?]] - - -#1B.6 Is there a mailing list or Usenet newsgroup devoted to CVS? - How do I find them? - - 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. An - associated Usenet newsgroup named "gnu.cvs.info" was created in - August, 1993. - - The newsgroup and the mailing list are bidirectionally gatewayed, - meaning that you only need access to one of them. Anything sent - to the mailing list will be automatically posted to "gnu.cvs.info" - and anything posted to the newsgroup will be automatically mailed - to "info-cvs". - - First try the newsgroup, since it is generally easier to read (and - manage) than a mailing list. Ask your system administrator - whether you get the "gnu" hierarchy. If so, select a newsreader - and dive in. - - If you don't get any form of Usenet News (or don't get the "gnu" - hierarchy), 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 and the newsgroup might appear - someday in the CVS FTP archive. - - - 1B.7 What prayers are appropriate for each of the major denominations - (e.g. 20's, 50's, 100's) when issuing complex CVS commands? - - Only what the traffic will allow, in small, unmarked bills - delivered to me, Ralph Icebag, in a plain brown wrapper, by a - brown-shoed square, in the dead of night. (Apologies to - Firesign Theater.) - - - ----------------- --- 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? - 1C.5 How does CVS differ from SunPro? - 1C.6 How does CVS differ from Aegis? - 1C.7 How does CVS differ from Shapetools? -+1C.8 How does CVS differ from TeamNet? -+1C.9 How does CVS differ from ProFrame? -+1C.10 How does CVS differ from CaseWare/CM? -+1C.11 How does CVS differ from Sublime? - - - **** 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 - whole sets of files on the command line, but groups are - manipulated by iterating over those files. There is no pretense - of combined interaction between the 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 client-server CASE tool for version management, - configuration management, and process management. ClearCase - is an evolution of the popular DSEE tools, formerly available - on HP/Apollo platforms. ClearCase includes an X/Motif GUI, - command-line interface, and C programmer API, and is currently - available on Sun, HP, and SGI platforms. - - ClearCase uses a special Unix filesystem type, called "mfs" - for "multi-version file system". Conceptually, mfs adds - another dimension to the regular Unix filesystem. The new - axis is used to store the different versions of files. Each - user makes a "view" into the file database by creating a - special mfs mountpoint on their machine. Each view has a set - of flexible selection rules that specify the particular - version of each file to make visible in that view. You can - think of a "view" as a workarea in CVS, except that the files - don't really exist on your local disk until you modify them. - This type of filesystem is sometimes called "copy-on-write" - and conserves disk space for files that are read-only. - Another advantage is that a view is "tranparent" 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 and - the checkin/checkout development model with file locking. - Directories are versionable objects as well as files. A - graphical n-way merge tool is provided. Like CVS, 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 Makefiles 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. Hyperlinks between versioned 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) - - Contributed by Steve Turner - [extracted from the ClearCase 1.1.1 documentation] - - -=1C.4 How does CVS differ from TeamWare? - - TeamWare is a configuration management tool from Sun - Microsystems. - - For more information, contact: - - SunExpress, Inc. - P.O. Box 4426 - Bridgeton, MO 63044-9863 - (800)873-7869 - - - 1C.5 How does CVS differ from SunPro? - - SunPro is advertised as the successor to "SCCS". - - [[Need more info here.]] - - - 1C.6 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.7 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 versioned 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.8 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.9 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 RS600, 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.10 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.11 How does CVS differ from Sublime? - - Produced by AT&T. - - [[Need more info here.]] - - ----------------- --- 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. - - - 1D.2 What is an RCS file? - - A file, usually ending in ",v", 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. - - - 1D.3 What is a working file? - - 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)? - - The "checkout" command creates a tree of working directories, - filling them with working files. A working directory always - contains a sub-directory named ./CVS containing information - about working files and the location of the directory within the - Repository that was used to create the working directory. - - A working directory is the place where you work and the place - from which you "commit" files. - - - 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. See the "checkout" command in Section 3C. - - -=1D.6 What is a revision? - - A "revision" is a version of a file that was "committed" (or - "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" (or 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. - - -=1D.8 What are "HEAD" and "BASE"? - - BASE and HEAD 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 - become different for two reasons: - - 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 by executing "update -A". - - -=1D.9 What is a Branch? - - Any mechanism that allows one or more developers to modify a - physically separate copy of a file without affecting anyone other - than those working on the branch. - - There are four kinds of branches CVS deals with: - - 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 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, the - purpose and the way it is managed are different. The major - difference is that the branch is 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 the 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 must be *files*. - No directories, no relative pathnames. To checkout more - than one directory by a single name, use an alias as - described in #5 below. - - - 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 /emacs.helper gnu/emacs - - The files checked out are exactly the same as the files you - would get 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 /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. - - Example: - - my_work -a emacs gnu/bison unix/bin/ls.c - - - 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. - - - As an example, say you want to keep track of three programs, and - want to be allowed to check out any combination of one, two or all - three at a time. Here are most of the combinations I can think - of. Experiment and choose what you want -- you won't need every - possibility. - - - # All directories in "world", even ones added later. - world world - - # All three programs by name. They checkout into local dir. - prog123 -a prog1 prog2 prog3 - - # All three programs by name. They checkout into "world" subdir. - wprog123 -a wprog1 wprog2 wprog3 - - # Individual progs checkout into dirs named "prog1", etc. - prog1 world/prog1 - prog2 world/prog2 - prog3 world/prog3 - - # Individual progs checkout into dirs named "world/prog1", etc. - wprog1 -a world/prog1 - wprog2 -a world/prog2 - wprog3 -a world/prog3 - - # Pairs that checkout into local dir. - prog12 -a prog1 prog2 - prog13 -a prog1 prog3 - prog23 -a prog2 prog3 - - # Pairs that checkout into world subdir. - # Instead of using the wprog aliases, we could use "world/prog9" - wprog12 -a wprog1 wprog2 - wprog13 -a wprog1 wprog3 - wprog23 -a wprog2 wprog3 - - -+1D.12 What does "merge" mean? - - A merge is a way of combining changes made in two independent - copies of the same "base" file. There are always three files - involved in a merge: the original, or "base", file and two - copies of that base file modified in different ways. - - 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>" command merges a whole branch into - your working file, which is presumed to be on the Main line of - development. - - See 4C.6 - - 3. The "update -j <rev> -j <rev>" merges the difference between - two specific revisions on some other branch (though the two - revisions are usually on the same branch) into your working - directory. - - 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 assigned one or more persons to understand, - baby-sit and administer both the CVS programs and the data - Repository. I call these persons Repository Administrators. - They will 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 installation set the RCSBIN directory - to null (""), 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. - [Note: This is not in 1.3 -- It should appear in - the next release.] - - 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. - - - 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? - - 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: - - add, checkout, commit, diff, log, status, tag, update - - -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 directory that "checkout" created? -=2B.4 How do I find out what has changed? -=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'll find out that the - module name is named <module>. Then type: - - cvs checkout <module> - cd <module> - emacs <file> # Isn't Emacs a synonym for editor? - 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 check out a single file, you'll have to change the "cd - <module>" to "cd to the parent of the file named in <module>". - - -=2B.2 If I edit multiple files, must I type "commit" for each one? - - No. You can do them all at once by name or by directory. - See 3D.2. - - - 2B.3 How do I get rid of the directory that "checkout" created? - - Change your directory to be the same as when you executed the - "checkout" command and type: - - cvs release -d <module> - - - The current version of CVS does not detect foreign directories - (i.e. ones that weren't created by CVS) in your working - directory and will destroy them. - - If you don't care about keeping "history", and you don't care to - plan ahead to a more completely implemented "release" command, you - can just remove it. That's "rm -rf <module>" under Unix. - - -=2B.4 How do I find out what has changed? - - There are many ways to answer this. - - To find out what you've changed in your current working directory - since your last 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 display files CVS doesn't know about in - your working directory marked with a '?' indicator. - - ? <file> - - To add <file> to the Repository, type: - - cvs add <file> - cvs commit <file> - - -=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 five possible results when you type - the "update" command: - - 1. If neither you nor others have made changes to <file>, "update" - will print nothing. - - 2. If you have made no changes to a file, but others have, CVS - will replace your working file with a copy of the latest - revision of that file in the Repository. You will see: - - 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. - - 3. If you have made changes, but others have not, you will see: - - M <file> - - Nothing happened except you were told that you have a modified - file in your directory. - - 4. If both you and others have made changes to a file, 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. You will see: - - 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. This is one of the few times the - otherwise nonsensical phrase "same difference" means something. - - - 5. If both you and others have made changes to the same section of - a file, CVS will merge the changes into your file as in #4 - above, but it will leave conflict indicators in the file. - You will see: - - 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 strange-looking - text marking the overlapping text. - - You must examine the overlaps with care and resolve the - problem without removing all previous work. - - - - 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, 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 branch might have been abandoned in the past. - - 6. An explicit revision number. 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. - - 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.17. - - ----------------- --- 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 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 sub-directories in my working directory? - - Yes, but the "update" command will traverse them, wasting a lot - of time. You can't currently ignore directories but if a - directory has no ./CVS administrative directory, nothing will - happen to it during an "update". - - On the other hand "release -d" will delete it without warning. - - - 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: - - Add directory /Repos/<dir> to the Repository (y/n) [n] ? - - If you type a 'y', you will create both a 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 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 - - 2. Remove the old file using CVS. - - 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". - - cd <working-dir>/<odir> - rm <ofile> - cvs remove <ofile> - cvs commit <ofile> - - 3. Retrieve <newfile> and remove all the Tags from it. - - By stripping off all the old Tags, the "checkout -r" and - "update -r" commands 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 the build system (e.g. Makefile) in - your <working-dir> to know about the name change. - - - 2C.5 How do I make sure that all the files and directories in my - working directory are really in the Repository? - - Normally, you only need to be notified of files you forgot to - "add". A simple "update", or "cvs -n update" (which won't modify - your working directory) will display non-added files preceded by a - '?' indicator. To recover, "add" and "commit" them. - - To verify that all your directories are in the Repository, you - have to go look. Though CVS traverses all directories, it - produces no output for directories not backed up by a Repository - directory. - - 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 'M'odified, - 'U'pdate and 'C'onflict indicators 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 use the provided template for the "modules" file, both the - CVSROOT and the "modules" module will have the "mkmodules" program - as a "commit helper". - - After a file is committed in these modules the "mkmodules" - command will convert all the files CVSROOT directory within 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 all the new files. - - 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 and commit all three copies of the same file into three - distinct files. This is a hand-editing job, not something - CVS can handle. [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. - - Also, as in the "rename" case, you can apply this idea to - directories too, by changing <path> to <pathA>, <pathB> and - <pathC> in the example. - - Of course, you have to change your build system (e.g. Makefile). - - - ----------------- --- 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" stuff? - 2D.11 Why does .cvsignore not ignore directories? - 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" command that will display all system - calls as they happen. This is a *very* low-level interface, but - it can be useful. - - The most complete answer is to read the source, compile it - with the '-g' option and execute 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, which 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. (In - the future, "commit" might set a sticky branch tag on a newly - added file.) 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 doesn't pay attention to anything -- it just - registers the desire to add a new file. When a newly added file - is `committed", CVS *should* use the "directory tag" to determine - what branch to commit it to and set the corresponding sticky tag. - Unfortunately, it doesn't work correctly in CVS 1.3. See 4C.8. - - -=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 virtual branches of development contained in your working - directories. When one of you decides to commit the file, the - other may not commit the same file until "update" has merged the - two together. - - Say you both check out rev 1.2 of <file>. 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. - - After you resolve any overlaps caused by the merging process, you - may then commit the file. - - Yes, the first one who commits can cause the other some work. - - Yes, between the time you execute "update" and "commit", someone - else may have committed a later 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. - - - 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 who - has what 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, #4 - and #5 will be the same. But you might then make 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 - rat's nest 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. - - 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" stuff? - - The "update" and "import" commands use collections of Unix - wildcards to skip over files matching any of those patterns. - - You may add to the built-in ignore list by adding 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 in the X tree 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 files without known suffix patterns. - - In any of the 5 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. - - - 2D.11 Why does .cvsignore not ignore directories? - - Ignore lists are intended to be per-directory wildcards matching - various patterns. They are matched against file names, not - directory names or relative paths ('/' is an invalid character in - an ignore list). I suppose it could be extended, but as it - stands, it only works on files. - - This might change in the future. - - - 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 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. - - First, you 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 applying a raw "rcs -n" to - 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. - - Halting "update" half-way will give you some strange collection - of files and revisions. You'll have to examine the output from - the command and take a look at each file that was modified. 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 is a script called "cvs_acls.pl" that implements - a form of access control. - - -======================================== -== 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 newly added file end up in the Attic? - 3A.4 How do I put a new file on the Main Branch and branch off from - there onto my default branch? - - - **** 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, after verification, 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? - - See 4C.8 - - - 3A.3 Why did my newly added file end up in the Attic? - - Your new file is placed in the Attic if it is added onto a side - branch without ever showing up on the trunk. - - If the file were in the main Repository area, it would show up - when the Main branch is checked out. You didn't commit it onto - the Main branch -- only onto the side branch. - - - 3A.4 How do I put a new file on the Main Branch and branch off from - there onto my default branch? - - See 4C.8 - - - ----------------- --- 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 - - - 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 also use the '-o' (for "outdate") option to remove - revisions you don't care about. This has its own problems, such - as leaving dangling Tags and confusing the "update" command. - - -=3B.4 What should I avoid when using "admin"? - - 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. - - Don't try to use the '-l' option, which will lock RCS files. - See 4D.7 for a cautionary scenario. - - 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 on checkout 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" 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" 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 ./CVS administrative directory. - - 4. The two commands generate completely different types of records - in the "history" file. - - The two commands are equivalent in nearly all other respects. - - - 3C.5 Why can't I check out a file from within my working directory? - - You normally check out a module or directory, not a file. 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 names for both 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 "module". - - 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. - - I consider it unfortunate that CVS sprouted the ability to check - out relative pathnames without more extensive and flexible - support for "modules." - - - 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 on checkout the way RCS does? - - Think about why you want that ability. RCS locking is there to - keep people from breaking individual files. CVS does the same - task a different way. If you are only looking for the consistency - aspect, then you should just forget about locking. For normal - development, there is no need for CVS to lock anything. - - If you want to restrict access to parts of the Repository, see - the question in Section 4B on "Limiting Access". - - -+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). - - [[CVS 1.3 fails to handle all the flags you can put into the - modules file. The '-l' switch in particular causes "checkout -c" - to dump core on some systems.]] - - ----------------- --- 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 <branch_tag>" put new files in the attic? -+3D.8 Why does "commit -r <rev>" ignore <rev> on an added file? - - - **** 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 on the - command line and commit them all with the same log message. - If the file is unchanged, 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 second checkin of minor changes from 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 simultaneous 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 for being - 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 remembers any "-r <tag/rev>" arguments handed to the - "checkout" or "update" commands. This is the "sticky" part. 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 {optional files, default is whole directory} - - - 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, 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: - - 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 details. - - -=3D.7 Why does "commit -r <branch_tag>" put new files in the attic? - - This was a design choice. The Attic is a way to keep track of - files that are no longer on the Main Branch, or ones that were - *never* on the Main Branch. - - If the file doesn't already exist on the Main branch, committing - it directly to the BRANCH will stuff it into the Attic. Such - files are skipped over when checking out the Main Branch because - the file isn't on that branch. - - If it didn't go into the Attic, you would be committing the new - file to the Main branch in addition to the Branch you are working - on. This is an undesirable side-effect. - - The file can be retrieved by using the "-r <branch_tag>" option on - a "checkout" or "update" command. - - See Section 4C, on Branching, for many more details. - - -+3D.8 Why does "commit -r <rev>" ignore <rev> on an added file? - - The sequence - - cvs add <file> - cvs commit -r <rev> <file> - - does not commit the new file <file> with revision <rev> as you - might expect. For newly added files (for which "update" would - display an 'A') the '-r' option is assumed to be a branch tag. If - <rev> is numeric, it is ignored. This might or might not be - changed in future revisions of CVS, but for now, the following - commands will allow you to set the revision of the file: (with - some restrictions) - - cvs add <file> - cvs commit <file> - cvs commit -r <rev> <file> - - The first commit causes CVS to look for the highest main branch - major number in all files in the directory. 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. - - As long as <rev> is higher than the initial (calculated as in the - above) revision, the second commit will work as expected and force - a second commit even if the file hasn't changed, setting the file - revision to <rev>. - - ----------------- --- 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 the --unified option to "diff"? - - - **** Answers: - - 3E.1 What is "diff" for? - - To display the difference between your working file and a - committed revision: - - cvs diff -r <tag/rev> <file> - - or between two committed revisions: - - cvs diff -r <tag1/rev1> -r <tag2/rev2> <file> - - Without explicit file names, it "diffs" the whole directory. - - Without explicit revision numbers, it "diffs" your working file - against the BASE revision, which is the one last checked out, - updated or committed. - - 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 the --unified option to "diff"? - - There are a few reasons: - - 1. CVS passes through only arguments it knows about, because a few - arguments are captured and interpreted. - - 2. CVS only parses single character '-X' arguments, not the FSF - long options. - - 3. 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 the hell not? - 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 in CVS 1.3. Maybe later. - - -=3F.4 Why the hell not? - - Export is intended for a specific purpose -- to remove all trace - of revision control on the way *out* of CVS. Maybe in the future - CVS will allow the -kv default to be overridden. - - - 3F.5 Why does "export -D" check out every file in the Attic? - - See the explanation of the same problem with "update -D" - contained in section 5B. - - - ----------------- --- 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? - - - **** 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? - - In later versions of CVS, you can use the '-f' option which - forcibly adds a "release" record to the history file. If your - version of "release" doesn't have the '-f' option, 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". - - - 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 - - ----------------- --- 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 you put it on - the Main Trunk and let me work on a 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 keep "import" from expanding all the $\Revision$ strings - to be 1.1.1.1? -#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 didn't "import" ignore the directories I told it to? - 3H.10 Why can't I "import" 3 releases on different branches? - 3H.11 What do I do if the Vendor adds or deletes files between releases? - 3H.12 What about if the Vendor changes the names of files or - directories, or rearranges the whole structure between releases? - 3H.13 I thought "import" was for Vendor releases, why would I use it - for code of my own? Do I have to use import? -=3H.14 How do I import a large Vendor release? -+3H.15 Explain: ERROR: cannot create link to <file>: Permission denied - - - **** 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. - - "cd" into your source directory and type: - - cvs import -m "Message" <repos> <Vendor-Tag> <Release-Tag> - - - where <repos> is a relative directory pathname within the - Repository. - - 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.14 for more details. - - -=3H.3 Why does import put files on a branch? Why can't you put it on - the Main Trunk and let me work on a branch? - - Design choice. If you don't like the Vendor branch, you can use - the RCS "ci" command to generate all the RCS (",v") files and move - them into the Repository directly. - - 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. - - - 3H.4 Is there any way to import binary files? - - 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> - - See 4D.1 on Binary files. - - - 3H.6 How do I keep "import" from expanding all the $\Revision$ strings - to be 1.1.1.1? - - If you want to leave old RCS keywords as they are, you can use the - '-ko' trick described above. In the future, "import" might - sprout a '-ko' option of its own, so you don't have to execute two - commands. - - -#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 {} ';') - 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? - - In the released CVS 1.3, there is no way. In the coming patch - release, there will supposedly be a '-d' option to save the dates - of the files rather than the current date. - - See 4D.8 for more details. - - - 3H.9 Why didn't "import" ignore the directories I told it to? - - See 2D.11. - - - 3H.10 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.11 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 "remove" (followed by "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]". - - - 3H.12 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.9 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.13 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. It is not necessary. You can just as easily - checkin all the files using the RCS "ci" command and move the - resulting ",v" files into the Repository. - - See Section 4B, on Setting up and Managing the Repository. - - -=3H.14 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. - - - 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. - - 4. If they renamed any files, see 4B.9 on renaming files. - - 5. When you have dealt with removed and renamed files, then you - can execute the import: - - cd <new source> - cvs import -m "Message" <repos> <VendorTag> <ReleaseTag> - - Where - - 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 '-'.) - - 6. *SAVE* the output from the import command. - - 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. Alternatively, you can examine every file in the - "find" at the beginning and use the "import -I !" - option to avoid ignoring anything. - - - 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. - - - 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> - - 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. - - -+3H.15 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. - - ----------------- --- 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 (what RCS calls "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: - - cvs log -r<rev1>:<rev2> <file> - - If either <rev1> or <rev2> contain '-' characters, it will - complain and fail due to RCS's continued support of '-' as an - alternate range character. - - <rev1> and <rev2> can be tag/symbol names, but they have to be - on the same branch, whether they are numeric or symbolic. - - -=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. - - - 3I.4 How do I generate ChangeLogs from RCS logs? - - A program called rcs2log is distributed as part of GNU Emacs 19. - This program should also appear in the CVS FTP archive. - - -=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 the version of "diff" you are using supports the '-u' option, - to produce the more compact "Unidiff" format, the latest - revisions of the patch command understand that too. - - - ----------------- --- Section 3K -- "release", "re", "rel" ----------------- - - - **** Questions: - - 3K.1 What is "release" for? - 3K.2 Why does release -d delete directories within my directory that - weren't ever in the CVS Repository? - 3K.3 Why can't I reverse a "cvs checkout path/name/subdir" with a - "cvs release path/name/subdir" without an "unknown module name"? - 3K.4 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.5 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.6 Why doesn't "release -d module" reverse a "checkout module"? - 3K.7 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 does release -d delete directories within my directory that - weren't ever in the CVS Repository? - - A simplistic implementation. (I can say this -- I wrote it.) - - The "release" function was written under the assumptions that the - "module name" is a first class, unavoidable interface to the - Repository, allowing no way to retrieve anything other than by - module name and a module is a self-contained entity with no - foreign directories allowed. 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 those - assumptions. It will be upgraded slightly in the next release and - rewritten in the future. - - - 3K.3 Why can't I reverse a "cvs checkout path/name/subdir" with a - "cvs release path/name/subdir" without an "unknown module name"? - - Again, "release" is too primitive. It believes, truly - *believes* in modules, not relative paths. I can't *believe* - how many times I've been asked this. It was a hack of the - moment with a particular use in mind. I had no idea it was - going to cause so much trouble. I'll *fix* it already! :-) - - - 3K.4 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. - - Again, "release" believes in modules. Breaking it into bits - wasn't part of the plan. In the future, "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.5 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.6 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.7 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: - cvs remove: no files removed; use `rm' to remove the file first - - - **** 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: - cvs remove: no files removed; use `rm' to remove the file first - - 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. - - Future versions of CVS might contain a '-f' switch that deletes - the existing file without complaining. - - ----------------- --- Section 3M -- "rtag", "rt", "rfreeze" ----------------- - -(See the "tag" section below for questions in common with "rtag".) - - - **** Questions: - - 3M.1 What is "rtag" for? - 3M.2 Why would you use "rtag"? It assumes a static Repository. - - - **** 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 would you use "rtag"? It assumes a static 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. - - - ----------------- --- 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 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 Shouldn't the status "Needs Checkout" be "Needs Update"? - - Probably. Maybe in future revisions. - - - ----------------- --- 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 "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 copy of my current files? -#3O.8 Why doesn't "tag" write a history record the way "rtag" does? - - - **** 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 particular revision 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. - - "tag" works on files and directories in the current working - directory. - - 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. - - 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? - - Design decision. 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. See 4C.3 on Creating a Branch. - - --3O.4 So "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 copy 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 more useful than "rtag", so the model - has changed. Future revisions of CVS will probably store both - kinds of tags in the history file. - - - ----------------- --- 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 After a merge ("update" or "update -j"), why doesn't CVS remember - the conflict and not allow you to commit the result until the - conflict is resolved? - 3P.7 Is there a feature to tell me what I have changed, added and - removed without changing anything? -=3P.8 Why does "cvs update" not flag directories that are not in the - Repository as it does with new files? - 3P.9 Why are all my files deleted when I execute "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 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 by - other people into your working files, type: - - cvs update {optional list of files} - - - 3. To merge changes made to 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/rev1> -j <tag2/rev2> {optional files} - - (If you are working with a single file, the Tags could also be - revisions numbers. Unless you take really unusual care to - match revision numbers across different files (a waste of time - given the way Tags work), using revision numbers in places 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} - - - 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. - - You will need to remove the conflicts by editing the file. - Conflicts are surrounded by <<<<< and >>>>> markers. - - - "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 and 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". - - And now your disk caches are furiously being flushed by - multiple update daemons, destroying performance and proving to - management that you need more CPU power. :-) - - 6. Someone backed out 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 the - revision CVS thinks you already have. 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 the - normal cycle of "emacs" (a synonym for "edit" in most of the - civilized world) and "commit". - - -=3P.6 After a merge ("update" or "update -j"), why doesn't CVS remember - the conflict and not allow you to commit the result until the - conflict is resolved? - - Maybe in a future release. There is a "sticky_conflict" patch you - might want to look at in the CVS FTP archive. - - - 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 does "cvs update" not flag directories that are not in the - Repository as it does with new files? - - Design choice or oversight, take your pick. Directories are - handled specially. You can aim "update" at any random directory - and "update" will traverse the whole directory tree beneath it, - looking for CVS administrative directories. When it finds one, - "update" will perform its "normal" function. - - Maybe a future release will notice a directory not under CVS, - print a '?' and skip over it. - - - 3P.9 Why are all my files deleted when I execute "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 files 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 4D.14. - - 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.3 for - suggestions. - - 4. Make sure you have versions of all the programs mentioned in - the "cvs/src/config.h" file. - - 5. 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 Makefiles and "cvsinit" program. - - 2. Edit the "config.h" file in the "src" directory. - - Read it carefully. - - You will need to specify a number of site-specific pieces of - information including the names of a number of functions. - - Hint1: You really 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.5 or greater and set the - "HAVE_RCS5" macro. - - 3. Execute the ./configure command. - - 4. Type "make". - - -=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.) - - 2. Make sure you have versions of all the programs mentioned in - the config.h file, most of which are included in a standard - Unix system. - - 3. Unless you plan to reimplement RCS [:-)], you must install RCS. - - 4. 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 4D.11. - - ----------------- --- 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 How do I manage the modules file? - 4B.8 Why would anyone use "modules"? They are too restrictive. I - want to be able to select just the files I want to edit. -=4B.9 How do I rename a file or directory? What are the consequences? -=4B.10 What are "Attic" directories? - 4B.11 Is it OK to remove anything from the Repository? - 4B.12 Can I convert to CVS from RCS without losing my revision history? -=4B.13 Can I move RCS files with branches in them into the Repository? -=4B.14 Can I use raw RCS commands on the Repository? - 4B.15 How do I convert from SCCS to RCS? -=4B.16 How do I limit access to the Repository? -=4B.17 What are the Repository Administrator's responsibilities? - 4B.18 How do I move the whole Repository? -+4B.19 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". Execute: - - cvs checkout CVSROOT - - and read the information stored in 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, in order 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 seven Repository control (or "database") files of - interest in the CVSROOT directory: - - 1. 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. - - 2. 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. - - 3. 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. - - 4. 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. - - 5. cvsignore contains "ignore" patterns that are added to the - built-in ignore list. See 2D.10. - - 6. 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. - - 7. modules contains the "modules" database. See 1D.11, 2C.7, - 4B.7 and 4B.8 for more details. - - - 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, - one at a time. - - 3. You can move RCS files directly into the Repository. - - It would probably be a good idea to create directories to hold - them. - - -=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. It 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.) - - - 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. - - - 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 - - [[Future versions of CVS might sprout a "umask" configuration - variable.]] - - -=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 different - 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 How do I manage the modules file? - - An equivalent question might be, "How do I structure my sources?" - This can be a difficult question in that it is not purely - technical. - - Generally you want to think about what pieces of your system need - to be checked out together, built as one system or tagged - consistently. You should certainly make 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 containing files that will usually - be worked on at the same time by the same person. - - 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. - - - 4B.8 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.9 How do I rename a file or directory? What are the consequences? - - In CVS 1.3 there is no single CVS "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, "remove" - the old file and "add" the new one. Since there is no way (in - CVS 1.3) 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.10 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.11 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 Outer Space. - - 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.12 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.13 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.14 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.15 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.16 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. You can: - - 1. Set Unix groups and permissions. See 4B.5. - - 2. Try the "setgid" trick described in 4D.16. - - 3. Catch every commit using the "commitinfo" file. - - 4. Try to use the RCS access control lists, though I don't - think CVS will handle them cleanly. - - 5. Edit the source code to CVS. - - -=4B.17 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, everything in the Repository - should be "under" CVS. - - 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. Maintaining the other Repository control files: commitinfo, - loginfo, rcsinfo and editinfo files. - - 4. Storing site-specific ignore patterns in the "cvsignore" file. - - 5. Pruning the history file every once in a while. (Try the - "cln_hist.pl" script in the "contrib" directory.) - - 6. Staying aware of developments on the info-cvs mailing list and - what is available in the FTP archive. - - 7. Run "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. - - 8. 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.18 How do I move the whole Repository? - - The Repository itself contains pathnames only within the files in - the CVSROOT directory. If helper functions in the modules file or - logging programs executed out of the loginfo file point into the - Repository, you'll have to change the pathnames to point to the - new Repository location. - - The main change you'll have to make is to all the ./CVS/Repository - files in the checked-out working directories. - - You have four choices: - - 1. If you can avoid changing $CVSROOT by using a symbolic link or - mount point you don't have to do anything else. - - If you must change $CVSROOT, you must also tell everyone to - change the CVSROOT environment variable in all running shells - and in their '.' files where it is set. Then pick one of the - other three options that follow: - - 2. If all ./CVS/Repository files in all working directories - contain relative pathnames, you don't have to do anything else. - - 3. 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. - - 4. Use a PERL or shell script to run through all the - ./CVS/Repository files and edit the values in the files. - - -+4B.19 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 other than by changing the Repository file - directly. - - 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 ----------------- - - **** 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 add a new file to a branch? -=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 Why do I get the latest files on the branch when I tried to - "update -r <tag>"? - - - **** 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 "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 should create a branch are when: - - 1. You expect to take a long enough time or make a large enough - set of changes that the merging process will be difficult. - - 2. 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. 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. 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 short form: - - 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 move your working directory to the branch. - - - Suggested short form using modules: - - A1. cvs rtag <branch_point_tag> module - A2. cvs rtag -b -r <branch_point_tag> <branch_tag> module - A3. cvs checkout -r <branch_tag> module - - - Suggested short form using your working directory, which contains - the revisions of your working files you want to branch from: - - B1. cvs tag <branch_point_tag> - B2. cvs rtag -b -r <branch_point_tag> <branch_tag> module - B3. cvs update -r <branch_tag> - - - 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). - - 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 files and the result is the - 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 B2 has two important 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. If you have trouble figuring out what "module" to use, - remember that "module" can also mean "relative path within - the Repository." If that doesn't help, you can aim it at - whatever parent directories you believe will cover all - your files. 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. - - - Step 3 may occur any time after step 2. Unless you explicitly - remove them with "tag -d", the Tags are permanent. - - - There are two obvious ways of to choose the <branch_point_tag> and - <branch_tag> names. Since 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 what ever 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: - - - The "-r <tag>" option 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 precise. - - Check out or "update" the files you want to merge into. - - Identify the two tags on the branch you want to merge from. - (Revisions don't work too well because the same revision doesn't - mean the same thing in different files.) Then type: - - cvs update -j <tag1> -j <tag2> - - You can use a <branch_tag> to refer to the latest revision on the - branch, but there is no built-in way to refer to the branch point. - - - An alternative to merging is to identify a single revision you - want, grab it by using "update -p" and commit it. If you do - merges later, you'll get overlaps, but you get your file. - - - In the future, (but not yet) merging from the main branch will - look something like this: - - cvs update -j MAIN - cvs commit -m "Log message" - - - 4C.8 How do I add a new file to a branch? - - The obvious technique is broken in CVS 1.3. This is the way it is - supposed to work: - - You are in a directory checked out (or updated) with the "-r - <branch_tag>" option. To add <file> to the branch named - <branch_tag> you type: - - cvs add <file> - cvs commit <file> - - - Until the next release appears, you must explicitly specify the - branch_tag: - - cvs add <file> - cvs commit -r <branch_tag> <file> - - One not so obvious side-effect is that the file ends up in the - Attic. It wasn't added to the Main Branch so it doesn't show up - in the main part of the Repository, only in the Attic. - - You can add it to the Main Branch and branch off from there onto - the side-branch this way: - - 1. Move the working file back to the main branch: - - cvs update -A <file> - - 2. Add the file "normally": - - cvs add <file> - cvs commit <file> - - 3. Branch-tag the file using the same <branch_tag> as you did on - all the other files in your directory: - - cvs tag -b <branch_tag> <file> - - 4. And move the file back onto the branch: - - cvs update -r <branch_tag> <file> - - -=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 should be added to the Tag stored - in ./CVS/Tag, but they are not. See the above question on adding - a new file to a branch. - - 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 there aren't 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 $CVSROOT/CVSROOT. - - You tell "checkout" or "update", via the "-r <tag>" option, - what branch you want to check out. 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 make a "merge" 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. - - 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 "cvs checkout -j <branch_tag> <module>". - - - 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-magic 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* holds all the changes on the branch. - *2* cvs diff -r <branch_point_tag> -r HEAD - >>> *2* holds 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 - and overlaps. - 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. - - - 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 the - Vendor branch. Think about it. How does revision - 1.2.4.2.4.2.2.1 grab you?) - - -+4C.17 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 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. - - You *can* branch off a branch, but it is rarely needed. - - - ----------------- --- 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 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 Why does the merge occasionally resurrect lines of code? -=4D.11 Why does the merge fail when my "rcsmerge" program is - configured to use GNU diff version 2.1 or later? - 4D.12 What the hell is Entries.Static? -=4D.13 Why did I get the wrong Repository in the loginfo message? -=4D.14 Can I have multiple source repositories, one for each project? - 4D.15 How do I run CVS setuid so I can only allow access through the - CVS program itself? - 4D.16 How about using groups and setgid() then? - 4D.17 How do I use the "commitinfo" file? - 4D.18 How do I use the "loginfo" files? - - - **** 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 also need to apply the '-ko' flag to the files to avoid - expanding RCS keywords, which can be done via: - - cvs admin -ko filename - - (You should be able to do it by handing "import" the -ko option, - but that isn't yet in the official release.) - - 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. - - [[I know of no solution to this other than to keep binaries in - some text form as "source" (real binaries could be uuencoded, - documents could be stored in "exported" (something like SGML) - form.]] - - - 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 had never realized how much help CVS/RCS 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 filename, by typing: - - cvs admin -N<tag> <file> - - 2. Retrieve the outdated revision. - - Using CVS and RCS, there is no way to reconstruct an outdated - revision. You will have to resort to backups. - - 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 a magic branch tag? - - If the <branch_tag> refers to a physical branch within an RCS - file, renaming a tag will make the existing branch in the file - seem to disappear. This is not a good idea. - - If the magic branch has never had a revision committed to it, you - can move the branch by re-executing the "tag" or "rtag" command - that created it. The <branch_tag> will be moved to the place - where it would have appeared if you were tagging the file for the - first time. - - - 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 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. - - 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. - - 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. - - -=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: I commit a source file at 5PM. You commit the same file - at 6PM. At 7PM, I compile my file. Then I execute "update". If - CVS sets the date to the one in the RCS file, the file would be - given a timestamp of 6PM and my 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. - - -#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 given the promise offered by '-n' not to alter - anything. The "diff", "log" and "stat" commands all provide the - same information 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 this is "cvs -n <command>". The visually similar - command "cvs <command> -n" has no relation to the former 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 entirely reliably. - - - 4D.10 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. - - If you plan to upgrade to the latest GNU diff program, see the - next question. - - -=4D.11 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. - - To get consistent rcsmerge behavior, you have four choices: - - 1. Go back to using GNU diff 1.15 or 2.0. 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. - - - 4D.12 What the hell is Entries.Static? - - Each ./CVS administrative directory contains an Entries file, - listing the files under CVS in the directory above it. If a new - file is added to the Repository, an "update" command copies it - out of the Repository and adds it to the Entries file. - - If your ./CVS directory has an Entries.Static file in it, CVS - checks it before bringing new files out of the Repository. If a - new file is *not* in Entries.Static, it is not checked out. - - The Entries.Static file is created by checking out something that - doesn't include all files in a directory. Without an - Entries.Static file, the first "update" would bring more files - out of the Repository. - - Examples: - - - A multi-module checkout renamed with the "checkout -d" option. - - - Checking out a module specified with directory and filenames. - - The Entries.Static file is removed by an "update" with the - '-A', '-r' or '-D' option. - - -=4D.13 Why did I get the wrong Repository in the loginfo message? - - You probably: - - - Use multiple Repositories. - - - Configured CVS to use absolute pathnames in the - ./CVS/Repository file. - - - Typed the "commit" command in one Repository with your - $CVSROOT pointing at the other. - - - "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. - - -=4D.14 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. - - One monster of an unexpected result can happen when you have - two modules or directories by the same name at the same - relative path inside the Repository, in two different - Repositories. You can 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. - - - 4D.15 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.16 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", for example. Name it as you wish. - - 2. Put *no* users in the "cvsg" group. You can put Repository - administrators in this group, if you really 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 {} \; - - 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 allow the world - execute bit (octal 001) on directories, 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 the "admin" problem with the - setuid() method. - - - 4D.17 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 the function 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. - - - 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. - - - 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 as many times as you like. - - - 4D.18 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") 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 - - - ----------------- --- Section 4E -- Weirdness ----------------- - - **** 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 I don't want a Vendor branch. Why can't I work on the main trunk? - 4E.4 Merges can't work. I don't trust them. If you won't change it to - something I can understand, I won't use CVS. - 4E.5 Explain: "co error, line 2: Missing access list" -+4E.6 Explain: "error: RCS file name `xyz .c' contains white space" -+4E.7 Explain: cvs checkout: warning: <X> is not (any longer) pertinent - - - **** 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. - - -=4E.3 I don't want a Vendor branch. Why can't I work on the main trunk? - - The Vendor branch is the way "import" deals with a Vendor - release. If you do it any other way, you are wasting your time. - CVS was designed to work this way. - - If you are not working with 3rd party (i.e. Vendor) sources, you - can skip the "import" and either move pre-existing RCS files into - the Repository, or apply the RCS "ci" command to your source files - by hand (creating ",v" files) and move them into the Repository. - - - 4E.4 Merges can't work. I don't trust them. If you won't change it to - something I can understand, I won't use CVS. - - Some developers have the feeling that three-way merging doesn't - work. They don't trust 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 obliterate. - - 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. - - - 4E.5 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. - - You should upgrade to the latest version of RCS, which is Version - 5.6.0.1 as I write this. - - -+4E.6 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.7 Explain: cvs checkout: warning: <X> is not (any longer) pertinent - - This message occurs in two 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. - - ----------------- --- 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 1.3 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'), - 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 is a window interface to CVS written in Tcl/Tk, which attempts - to hide the normal CVS command line options from novice users. - - GIC works only in a single directory at a time, but it offers most - of the CVS commands you would normally use. - - GIC can be obtained by anonymous ftp to - - ftp.cpsc.ucalgary.ca:/pub/marwood/gic-1.0b5.tar.Z - - contact - David Marwood - marwood@cpsc.ucalgary.ca - - [[Does someone want to try to describe this better?]] - - -+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 llnl.gov [128.115.18.253] as - gnu/caveman_vX.Y.Z.tar.gz (The numbers X, Y, & Z vary with time.) - - contact - Kathleen Dyer kdyer@llnl.gov - (510)423-6803 - (510)423-5112 FAX - - - [[Does someone want to try to describe this better?]] - - - ----------------- --- Section 4G -- Other Systems ----------------- - - **** Questions: - - 4G.1 I use a NeXT. Is there anything I need to know? - 4G.2 I use OS/2. Is there anything I need to know? - 4G.3 I use SCO Unix. Is there anything I need to know? - 4G.4 I use AIX. Is there anything I need to know? -=4G.5 I use IRIX. Is there anything I need to know? -=4G.6 I use an HP system. 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. - - 4G.1 I use a NeXT. Is there anything I need to know? - - Under NeXTSTEP 2.2, the tmpnam() function always returns the - same filename, which breaks "cvs patch". Apparently the - "mktemp()" function works OK, but you'll have to hack it up to - build something that acts like "tmpnam()". - - NeXTSTEP 3.0's Interface Builder uses "nib" directories, - rather than files 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. - - [[Anything else?]] - - - 4G.2 I use OS/2. Is there anything I need to know? - - [[Well?]] - - - 4G.3 I use SCO Unix. Is there anything I need to know? - - [[Well?]] - - - 4G.4 I use AIX. Is there anything I need to know? - - [[Well?]] - - -=4G.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. - - -=4G.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.16, 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 - - -============================================= -== 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. - - Take a look at the README and the ChangeLog files in the CVS - sources for more details. - - -=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. 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. - - Unless a name is included in the answer itself, I didn't use - anyone else's answers verbatim. On the other hand, I did use - ideas and information provided by many. 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): - - Donald Amby <amby@mixcom.mixcom.com> - Tom Cunningham <tomc@bouwsma,sps.mot.com> - Don Dwiggins <dwig@markv.com> - Dan Franklin <dan@diamond.bbn.com> - Jeffrey M Loomis <jml@world.std.com> - Barry Margolin <barmar@think.com> - Mark K. Mellis <mkm@ncd.com> - Chris Moore <Chris.Moore@src.bae.co.uk> - Gary Oberbrunner <garyo@think.com> - Steve Turner <stevet@carrier.sps.mot.com> - Dave Wolfe <dwolfe@pffft.sps.mot.com> - Dale Woolridge <dwoolridge@cid.aes.doe.ca> - - Plus a myriad Thinking Machines people who posed hundreds of - questions. - - - 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 Why does "checkout" recurse indefinitely if an alias contains - its own name? - 5B.4 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.5 When I typed "cvs update -D <date>" in my branch, why did it - screw up all my files? - 5B.6 When I executed "checkout" into an existing directory I got "No - such file or directory" errors. Why? - 5B.7 Why does "update" send all output to the terminal after 26 files - have been updated? -+5B.8 Why doesn't the "-I !" option work in update and import? - - - **** 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.9 and 2C.4. - - -=5B.3 Why does "checkout" recurse indefinitely if an alias contains - its own name? - - A bug in the handling of aliases. [[I'll remove this one when - the bug is fixed.]] - - - 5B.4 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. - - - 5B.5 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. - - - 5B.6 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.7 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.8 Why doesn't the "-I !" option work in update and import? - - A bug. See the patch named "unoff/import_ignore" in the CVS FTP - archive - - - [[Section 5B needs more, but should probably wait until the - patch release comes out. Then we can document them for real and - provide pointers to patches in the FTP area.]] - - ----------------- --- Section 5C -- Development ----------------- - - I hope to record three types of information here: - - 1. Plans (with the developer's name attached) for fixing larger - bugs. (Smaller bugs should just show up, with a patch or a - reference to a patch stored in the FTP archive, in the - "Bugs" section above.) - - 2. Plans for new development, with the developer's name attached. - (If the developer is particularly gonzo, it might also show a - completion date.) - - 3. Requests for ideas and code to fix unresolved issues. - - - **** 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 fixing bugs? -=5C.5 What plans are there for new features? -=5C.6 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. - - If careful testing reveals an RCS bug rather than a CVS bug, you - can sendbug reports to: rcs-bugs@cs.purdue.edu - - -=5C.2 Where do I send fixes and patches? - - First make sure the "fix" does something useful. Have someone to - review your fix. It is better to spend a bit of one person's - thinking time than to waste the time of thousands of people trying - to understand your fix. - - 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, send it to the maintainer of the - FTP archive (currently the author of this FAQ) for inclusion in - the CVS FTP archive and to Brian Berliner, the maintainer of CVS. - - - 5C.3 Where do I send ideas for future development? - - [[Brian?]] - - - 5C.4 What plans are there for fixing bugs? - - David G. Grubbs <dgg@think.com> plans/hopes to: - - - Fix the release command to be more sophisticated about - foreign directories, renaming and to allow the release of - anything in the working directory. - - - Fix the history command to track changes made in the - underlying layers since I originally wrote it, including - making "tag" work with history. - - - - [[Brian?]] - [[Others?]] - - -=5C.5 What plans are there for new features? - - David G. Grubbs <dgg@think.com> plans/hopes to: - - - Implement the design described in the Branching spec - distributed to this list in January, 93. It attempts to - address the problem of merging between arbitrary branches - and to fully support the idea of "branching". - - - Add a feature to "cvs add" (Maybe a '-a' switch.) to - add a file by the same name as one in the Attic, by - dragging it back out of the Attic. (This connects to the - branching code, since a way has to be added to drag a - file out of the Attic that is merged onto the Main branch - from being only on a side-branch.) - - - If no one else wants to deal with it, I would like to - enhance the whole "modules" concept to cover more of - the naming problem and to allow more complicated access - control. (Optional, of course.) - - - Create a set of configuration files (in addition to or to - supersede the cvsignore files) to allow the setting of - a wide variety of site-specific options. - - - Brian Berliner <berliner@sun.com> plans/hopes to: - - - [[Rename database?]] - - [[Brian? Any plans?]] - - - Paul F. Kunz <pfkeb@slac.stanford.edu> has produced a version of - CVS (RCVS) that runs remotely. - - On the host "ftp.slac.stanford.edu", you can find: - Sources: pub/sources/rcvs-0.5.0.tar.Z - Paper: pub/preprints/slac-pub-5923.ps - - - [[Others?]] - - -=5C.6 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 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 - D. Tricks of the Trade - E. Weirdness - F. Related Software - G. Other Systems - - 5. Past & Future - A. Contributors. - B. Bugs and Patches - C. Development - - 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? -=1A.6 Why isn't it called OSCO (Online Source COntrol)? - ----------------- --- 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 a copy of the latest version of CVS? - 1B.4 Is there any other documentation? How about tutorials? - 1B.5 Is there a mailing list devoted to CVS? How do I get on it? - 1B.6 What prayers are appropriate for each of the major denominations - (e.g. 20's, 50's, 100's) when issuing complex CVS commands? -+1B.7 How do I get files out of the archive if I don't have FTP? - ----------------- --- 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? - 1C.5 How does CVS differ from SunPro? - 1C.6 How does CVS differ from Aegis? - 1C.7 How does CVS differ from Shapetools? -+1C.8 How does CVS differ from TeamNet? -+1C.9 How does CVS differ from ProFrame? -+1C.10 How does CVS differ from CaseWare/CM? -+1C.11 How does CVS differ from Sublime? - ----------------- --- Section 1D -- What do you mean by . . .? (Definitions) ----------------- -#1D.1 What are "The Repository", "$CVSROOT" and "CVSROOT"? - 1D.2 What is an RCS file? - 1D.3 What is a working file? - 1D.4 What is a working directory (or working area)? - 1D.5 What is "checking out"? -=1D.6 What is a revision? - 1D.7 What is a "Tag"? -=1D.8 What are "HEAD" and "BASE"? -=1D.9 What is a Branch? -=1D.10 What is "the trunk"? -=1D.11 What is a module? -+1D.12 What does "merge" mean? - - -========================================== -== Section 2 ==== User Tasks ==== -========================================== - ----------------- --- Section 2A -- Getting Started ----------------- - 2A.1 What is the first thing I have to know? - 2A.2 Where do I work? -=2A.3 What does CVS use from my environment? - 2A.4 OK, I've been told that CVS is set up, my module is named - "ralph" and I have to start editing. What do I type? - 2A.5 I have been using RCS for a while. Can I convert to CVS without - losing my revision history? How about converting from SCCS? - ----------------- --- Section 2B -- Common User Tasks ----------------- -#2B.1 What is the absolute minimum I have to do to edit a file? -=2B.2 If I edit multiple files, must I type "commit" for each one? - 2B.3 How do I get rid of the directory that "checkout" created? -=2B.4 How do I find out what has changed? -=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 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" stuff? - 2D.11 Why does .cvsignore not ignore directories? - 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 newly added file end up in the Attic? - 3A.4 How do I put a new file on the Main Branch and branch off from - there onto my default branch? - ----------------- --- 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 on checkout 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 <branch_tag>" put new files in the attic? -+3D.8 Why does "commit -r <rev>" ignore <rev> on an added file? - ----------------- --- 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 the --unified option 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 the hell not? - 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? - ----------------- --- 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 you put it on - the Main Trunk and let me work on a 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 keep "import" from expanding all the $\Revision$ strings - to be 1.1.1.1? -#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 didn't "import" ignore the directories I told it to? - 3H.10 Why can't I "import" 3 releases on different branches? - 3H.11 What do I do if the Vendor adds or deletes files between releases? - 3H.12 What about if the Vendor changes the names of files or - directories, or rearranges the whole structure between releases? - 3H.13 I thought "import" was for Vendor releases, why would I use it - for code of my own? Do I have to use import? -=3H.14 How do I import a large Vendor release? -+3H.15 Explain: ERROR: cannot create link to <file>: Permission denied - ----------------- --- 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 does release -d delete directories within my directory that - weren't ever in the CVS Repository? - 3K.3 Why can't I reverse a "cvs checkout path/name/subdir" with a - "cvs release path/name/subdir" without an "unknown module name"? - 3K.4 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.5 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.6 Why doesn't "release -d module" reverse a "checkout module"? - 3K.7 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: - cvs remove: no files removed; use `rm' to remove the file first - ----------------- --- Section 3M -- "rtag", "rt", "rfreeze" ----------------- - 3M.1 What is "rtag" for? - 3M.2 Why would you use "rtag"? It assumes a static Repository. - ----------------- --- 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 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 "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 copy of my current files? -#3O.8 Why doesn't "tag" write a history record the way "rtag" does? - ----------------- --- 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 After a merge ("update" or "update -j"), why doesn't CVS remember - the conflict and not allow you to commit the result until the - conflict is resolved? - 3P.7 Is there a feature to tell me what I have changed, added and - removed without changing anything? -=3P.8 Why does "cvs update" not flag directories that are not in the - Repository as it does with new files? - 3P.9 Why are all my files deleted when I execute "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 get around the bugs I've heard of GNU diff version 2.2? - ----------------- --- 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 How do I manage the modules file? - 4B.8 Why would anyone use "modules"? They are too restrictive. I - want to be able to select just the files I want to edit. -=4B.9 How do I rename a file or directory? What are the consequences? -=4B.10 What are "Attic" directories? - 4B.11 Is it OK to remove anything from the Repository? - 4B.12 Can I convert to CVS from RCS without losing my revision history? -=4B.13 Can I move RCS files with branches in them into the Repository? -=4B.14 Can I use raw RCS commands on the Repository? - 4B.15 How do I convert from SCCS to RCS? -=4B.16 How do I limit access to the Repository? -=4B.17 What are the Repository Administrator's responsibilities? - 4B.18 How do I move the whole Repository? -+4B.19 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 ----------------- - 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 add a new file to a branch? -=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 Why do I get the latest files on the branch when I tried to - "update -r <tag>"? - ----------------- --- 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 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 Why does the merge occasionally resurrect lines of code? - 4D.11 Why does the merge fail when my "rcsmerge" program is - configured to use GNU diff version 2.1 or later? - 4D.12 What the hell is Entries.Static? -=4D.13 Why did I get the wrong Repository in the loginfo message? -=4D.14 Can I have multiple source repositories, one for each project? - 4D.15 How do I run CVS setuid so I can only allow access through the - CVS program itself? - 4D.16 How about using groups and setgid() then? - 4D.17 How do I use the "commitinfo" file? - 4D.18 How do I use the "loginfo" files? - ----------------- --- Section 4E -- Weirdness ----------------- - 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 I don't want a Vendor branch. Why can't I work on the main trunk? - 4E.4 Merges can't work. I don't trust them. If you won't change it to - something I can understand, I won't use CVS. - 4E.5 Explain: "co error, line 2: Missing access list" -+4E.6 Explain: "error: RCS file name `xyz .c' contains white space" -+4E.7 Explain: cvs checkout: warning: <X> is not (any longer) pertinent - ----------------- --- Section 4G -- Other Systems ----------------- - 4G.1 I use a NeXT. Is there anything I need to know? - 4G.2 I use OS/2. Is there anything I need to know? - 4G.3 I use SCO Unix. Is there anything I need to know? - 4G.4 I use AIX. Is there anything I need to know? -=4G.5 I use IRIX. Is there anything I need to know? - 4G.6 I use an HP system. 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 Why does "checkout" recurse indefinitely if an alias contains - its own name? - 5B.4 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.5 When I typed "cvs update -D <date>" in my branch, why did it - screw up all my files? - 5B.6 When I executed "checkout" into an existing directory I got "No - such file or directory" errors. Why? - 5B.7 Why does "update" send all output to the terminal after 26 files - have been updated? -+5B.8 Why doesn't the "-I !" option work in update and import? - ----------------- --- 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 fixing bugs? -=5C.5 What plans are there for new features? -=5C.6 I have some time and I'd like to help. What can I do for you? - - -================================================= -== 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/INSTALL b/INSTALL deleted file mode 100644 index afe3c8ac8d34844bf79b9a06812963f091b547c8..0000000000000000000000000000000000000000 --- a/INSTALL +++ /dev/null @@ -1,236 +0,0 @@ -First, read the README file. If you're still happy... - -The CVS 1.4 Alpha release has been tested on the following platforms. Your -mileage may vary. Please send updates to this list using the "cvsbug" -program, specifying the "portability" category. If your installation -failed, you may need to run "cvsbug" directly from the "src" directory as -"src/cvsbug.sh". - - DEC Alpha running OSF/1 version 1.3 using cc - DEC Alpha running OSF/1 version 2.1 - HP 9000/710 running HP-UX 8.07A using gcc - HP 9000/715 running HP-UX 9.01 using gcc - Gateway P5-66 (pentium) running Solaris 2.4 using gcc - IBM RS/6000 running AIX 3.2.5 using gcc and cc - IBM RS/6000 running AIX 4.1 using gcc and cc (*) - PC Clone running UnixWare v1.1.1 using gcc - PC Clone running Linux 1.1.48 using gcc - SGI Indigo 2 running Irix 4.0.5H using gcc and cc (**) - Sun SPARCstation 1+ running SunOS 4.1.3 using gcc and cc - Sun SPARCstation 10 running Solaris 2.3 using gcc and cc - Sun SPARCstation 10 running Solaris 2.4 using gcc - Sun SPARCstation 10 running SunOS 4.1.3_U1 using gcc and cc - -NOTE: CVS relies on having some form of the opendir/readdir/closedir - functions being available. Some older systems do not support these - calls. CVS will not work with these systems unless a suitable - readdir implementation is installed on the system. Take a look at - the file "contrib/dirfns", which contains some code that might add - this support to your system. - -(*) 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. - -(**) 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. - -------------------------------------------------------------------------------- - -Installation: - -1) Edit the src/options.h header file. 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 (which is strongly recommended). - -2) 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.6 (or later) version of RCS, available from - prep.ai.mit.edu in the file pub/gnu/rcs-5.6.tar.Z. Along with RCS, you - will want to run GNU diff. This will allow revision control of files - with binary data (a real nice feature). You will need at least version - 1.15 of GNU diff for this to work. Be sure that you configure RCS to - work correctly with GNU diff to avoid other configuration problems. - - 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. - - 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 DEFS=-fpcc-struct-return ./configure - - for sh, bash, and ksh users and: - - % setenv CC gcc - % setenv DEFS -fpcc-struct-return - % ./configure - - for csh and tcsh users. - - END OF NOTE FOR NDBM GUNK. - -3) Try to build it: - - $ make - - This will (hopefully) make the needed CVS binaries within the "src" - directory. Send me your "config.status" file with your host type, - operating system information, and make output if something fails for - your system. - -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, or ~/.login file: - - CVSROOT=/src/master; export CVSROOT - - for sh/bash/ksh users, or - - 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.4 distribution' cvs CVS CVS1_4 - -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 ChangeLog file to see what's new. REALLY! I use the - ChangeLog file as the Release Notes. - -12) Hack away. - -------------------------------------------------------------------------------- - -Detailed info about your interaction with "configure": - -The "configure" script and its interaction with its options and the -environment is described here. - -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. - -The following environment variables override configure's default -behaviour: - CC If not set, tries to use gcc first, - then cc. Also tries to use "-g -O" - as options, backing down to -g - alone if that doesn't work. - INSTALL If not set, tries to use "install", then - "cp" as a final choice. - 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. - -------------------------------------------------------------------------------- diff --git a/MINOR-BUGS b/MINOR-BUGS deleted file mode 100644 index faff51c99c78a3ae58ec24fa3712985944fa0a9e..0000000000000000000000000000000000000000 --- a/MINOR-BUGS +++ /dev/null @@ -1,14 +0,0 @@ -Low-priority bugs go here. We don't have any yet -- everything is -high-priority at the moment. :-) - - -* 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. diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index 101f6631bda904059cf086c562ce1217dd71237d..0000000000000000000000000000000000000000 --- a/Makefile.in +++ /dev/null @@ -1,239 +0,0 @@ -# Master Makefile for the GNU Concurrent Versions System. -# Copyright (C) 1986, 1988-1992, 1994 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: @(#)Makefile.in 1.30 94/10/22 $ - -SHELL = /bin/sh - -#### Start of system configuration section. #### - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -# If you use gcc, you should either run the fixincludes script that -# comes with it or else use gcc with the -traditional option. Otherwise -# ioctl calls will be compiled incorrectly on some systems. -CC = @CC@ -AR = ar -# Older makes don't set $(MAKE), so we set it for them. -MAKE = make -# Set RANLIB = echo if your system doesn't have or need ranlib. -RANLIB = @RANLIB@ -# Set YACC = bison or yacc, depending on which you have on your system -YACC = @YACC@ -# Use cp if you don't have install. -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ - -DEFS = @DEFS@ -LIBS = @LIBS@ - -INCLUDES = -I. -I../lib @includeopt@ -CFLAGS = -g -LDFLAGS = $(CDEBUG) - -MAKEINFO = makeinfo -TEXI2DVI = texi2dvi - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -# Where to install the executables. -bindir = $(exec_prefix)/bin - -# Where to put the system-wide .cvsrc file -libdir = $(prefix)/lib - -# Where to put the Info files -infodir = $(prefix)/info - -# Where to put the manual pages. -mandir = $(prefix)/man - -#### End of system configuration section. #### - -# CYGNUS LOCAL--pass INSTALL to sub-makes. This works for Cygnus -# builds (in which the top-level makefile sets install to something -# containing `pwd') but loses if autoconf has set install to something -# like "../../install.sh". Relying on autoconf 1.11 to edit the -# sub-makefiles loses, it has a bug and doesn't add a leading "../" in -# the case where it is needed. Autoconf 1.122 fixes this, but in its -# infinite wisdom has chosen not to support AC_RSH, so we can't just -# use 1.122. Sigh. - -FLAGS_TO_PASS = \ - AR='$(AR)' \ - CC='$(CC)' \ - CFLAGS='$(CFLAGS)' \ - INSTALL='$(INSTALL)' \ - INSTALL_DATA='$(INSTALL_DATA)' \ - INSTALL_PROGRAM='$(INSTALL_PROGRAM)' \ - LDFLAGS='$(LDFLAGS)' \ - LIBPROGS='$(LIBPROGS)' \ - LIBS='$(LIBS)' \ - MAKE='$(MAKE)' \ - MAKEINFO='$(MAKEINFO)' \ - RANLIB='$(RANLIB)' \ - TEXI2DVI='$(TEXI2DVI)' \ - YACC='$(YACC)' \ - bindir='$(bindir)' \ - infodir='$(infodir)' \ - libdir='$(libdir)' \ - mandir='$(mandir)' \ - prefix='$(prefix)' \ - exec_prefix='$(exec_prefix)' - -DISTFILES = COPYING COPYING.LIB ChangeLog INSTALL README TODO \ - cvs-format.el mkinstalldirs install-sh cvsinit.sh \ - configure configure.in stamp-h.in config.h.in Makefile.in - -PROGS = cvsinit - -# Subdirectories to run make in for the primary targets. -SUBDIRS = lib src man doc contrib examples -# Only make TAGS/tags files in these directories, in this order -TSUBDIRS= src lib - -.PHONY: all install uninstall -all install uninstall: config.h Makefile all-local - @for subdir in $(SUBDIRS); do \ - echo "making $@ in $$subdir"; \ - ( cd $$subdir; $(MAKE) $(FLAGS_TO_PASS) $@ ) || exit 1; \ - done - -install: all install-local - -.PHONY: all-local -all-local: $(PROGS) - -cvsinit: cvsinit.sh - sed -e 's,xLIBDIRx,$(libdir)/cvs,g' \ - -e 's,xVERSIONx,$(VERSION),g' $(srcdir)/cvsinit.sh > $@-t - mv $@-t $@ - chmod a+x $@ - -.PHONY: info dvi clean-info install-info -info dvi clean-info install-info: - cd doc ; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1 - -.PHONY: install-local -install-local: all-local - @for prog in $(PROGS); do \ - echo Installing $$prog in $(bindir); \ - $(INSTALL) $$prog $(bindir)/$$prog ; \ - done - -.PHONY: tags -tags: - @for dir in $(TSUBDIRS); do echo making $@ in $$dir; cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1; cd ..; done - @echo making $@ in . - @ctags `for i in \`$(MAKE) SUBDIRS="$(TSUBDIRS)" ls\` ; do echo $(srcdir)/$$i ; done` - -.PHONY: TAGS -TAGS: - @for dir in $(TSUBDIRS); do echo making $@ in $$dir; cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1; cd ..; done - @echo making $@ in . - @etags `for i in \`$(MAKE) SUBDIRS="$(TSUBDIRS)" ls\` ; do echo $(srcdir)/$$i ; done` - -.PHONY: ls -ls: - @echo $(DISTFILES) - @for dir in $(SUBDIRS); do \ - for i in `cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@` ; do \ - echo $$dir/$$i ; \ - done ; \ - done - -.PHONY: clean -clean: clean-local - @for dir in $(SUBDIRS); do echo making $@ in $$dir; cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1; cd ..; done - -.PHONY: distclean -distclean: distclean-local - @for dir in $(SUBDIRS); do echo making $@ in $$dir; cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1; cd ..; done - -.PHONY: realclean -realclean: realclean-local - @for dir in $(SUBDIRS); do echo making $@ in $$dir; cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1; cd ..; done - -.PHONY: mostlyclean-local -mostlyclean-local: - rm -f *~ - -.PHONY: clean-local -clean-local: mostlyclean-local - -.PHONY: distclean-local -distclean-local: clean-local - rm -f Makefile config.cache config.h config.log config.status stamp-h - rm -f tags TAGS - -.PHONY: realclean-local -realclean-local: distclean-local - -.PHONY: saber -saber: - @for dir in $(SUBDIRS); do cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@ || exit 1; cd ..; done - -.PHONY: check -check: - cd src ; $(MAKE) $(FLAGS_TO_PASS) check - -.PHONY: installcheck -installcheck: - cd src ; $(MAKE) $(FLAGS_TO_PASS) installcheck - -.PHONY: lint -lint: - @for dir in $(SUBDIRS); do cd $$dir; $(MAKE) $(FLAGS_TO_PASS) xlint || exit 1; cd ..; done - -.PHONY: dist -dist: - echo ccvs-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q src/version.c` > .fname - rm -rf `cat .fname` - mkdir `cat .fname` - ln $(DISTFILES) `cat .fname` - for dir in $(SUBDIRS); do mkdir `cat .fname`/$$dir; cd $$dir; $(MAKE) $@; cd ..; done - tar chzf `cat .fname`.tar.gz `cat .fname` - rm -rf `cat .fname` .fname - -# For the justification of the following Makefile rules, see node -# `Automatic Remaking' in GNU Autoconf documentation. -Makefile: Makefile.in config.status - CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status -config.status: configure - ./config.status --recheck -# The rules to run autoconf and autoheader are commented out. This is because -# when the user unpacks a tarfile, configure.in might end up newer than -# configure, but the user might not have (and does not need to have) autoconf -# installed. -#configure: configure.in #aclocal.m4 -# cd $(srcdir); autoconf - -config.h: stamp-h -stamp-h: config.h.in config.status - CONFIG_FILES=$@ CONFIG_HEADERS=config.h ./config.status -#config.h.in: stamp-h.in -#stamp-h.in: configure.in #aclocal.m4 acconfig.h -# cd $(srcdir); autoheader -# date > $(srcdir)/stamp-h.in - -# Tell versions [3.59,3.63) of GNU make not to export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/README b/README deleted file mode 100644 index 9f29c414b1e75b02d203d13f32d9d4079270c445..0000000000000000000000000000000000000000 --- a/README +++ /dev/null @@ -1,223 +0,0 @@ -$CVSid: @(#)README 1.32 94/10/22 $ - - Cyclic CVS Kit, Version C1.4 Alpha - - 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 the CVS 1.4 Alpha release! We thank you for taking the -time to test this (potentially unstable) release and report bugs -(ideally, with fixes). To report bugs, 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". - -While we cannot promise to be responsive to said bugs, we do appreciate -your support through this Alpha process. 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 Alpha 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. - -This version of CVS can access repositories on a remote machine. See -CYCLIC-CVS-FAQ for more information. - -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 ChangeLog file in this directory to find out what has changed from -CVS 1.3. - -Some files have been renamed from the CVS 1.3 distribution. If you're not -careful, this can cause your build of CVS 1.4 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 install - $ cvsinit - -------------------------------------------------------------------------------- - -Mailing Lists: - -I have setup the following mailing list for Cyclic CVS users and other -interested parties. I have no idea what kind of volume will be -generated on this list. Nor can I guarantee to personally respond to -questions posted to the list. Anyway, the mailing lists are: - - cyclic-cvs-request@cyclic.com - Requests for addition to or removal from the - cyclic-cvs mailing list must be sent to this address. - Problems with the list (like bounced mail) should also - be sent here. Please be specific about your email - address. - - cyclic-cvs@cyclic.com - Questions, bugs, porting problems, hints, or whatever - can be sent to this address. A Frequently Asked - Questions (FAQ) file for Cyclic CVS is in the file - CYCLIC-CVS-FAQ in this directory. A full FAQ on CVS - may be available from host "think.com" in the - "/pub/cvs" directory. Please consult the FAQ before - sending questions to cyclic-cvs. DO NOT SEND ADDITION - AND REMOVAL REQUESTS TO THIS ALIAS. - -Cyclic CVS is based on a version of CVS distributed by the Free -Software Foundation. The mailing list for that parent package is -info-cvs@prep.ai.mit.edu. Send subscription and removal requests for -that list to info-cvs-requests@prep.ai.mit.edu. Please don't bother -that list with questions or bug reports in Cyclic CVS. - -------------------------------------------------------------------------------- - -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 of Cygnus Support <kingdon@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. - -------------------------------------------------------------------------------- - - Brian Berliner <berliner@sun.com> - Updated by: Jim Blandy <jimb@cyclic.com> diff --git a/TODO b/TODO deleted file mode 100644 index 90795c4e393d8d852cbcffdddcac318eca721b3e..0000000000000000000000000000000000000000 --- a/TODO +++ /dev/null @@ -1,610 +0,0 @@ -$CVSid: @(#)TODO 1.26 94/09/21 $ - -01. testing. An automated testing enviroment would be a big win. - -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 ]] - -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. - -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 ci foo/bar.c. This complicates things - a bit because one might specify files in different directories, but you - could just bucket sort them and do everything for each directory - together. Other than that, it's just a matter of using the adm - directory from the directory containing the file rather than the cwd. - [[ 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. - -56. There should be a .cvsrc file that is sourced to customize various - variables. Perhaps there should be a system-wide .cvsrc file that is - sourced, then the one in one's home directory, then the environment - variables are checked for overriding values. - -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. - -87. Consider renaming directories and files. - -88. Consider using mmap to read files on Sun systems and using a smaller - buffer to read files on other systems. A patch has been supplied. - -89. Study the new Dick Grune version of CVS and port any new interesting - features to my version of CVS. - -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. - -94. Need to think hard about remote source control and environments - together. - [[ a contributor has this working over Internet TCP links! ]] - -97. Think about some way to undo a change. This looks hard given the - current framework of CVS. - -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. - -106. Need to figure out how to delete and rename directories from a release - and yet have old releases still be accessible. - -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? - -112. When merging in changes (Glist) and the file ends up exactly as the - RCS revision, an "M" is displayed as the "cvs update" output. This - should really just be a "U". Just an optimization. - -113. The "cvs update" command should tee its output to a log file in ".". - -114. I wanted to check in my metapreen code tonight, which I had put into - a new file called preen.c. So, recalling your excellent instructions, - I typed "cvs add preen.c". However, cvs complained that there was - already a preen.c in /master/etc/fsck/Attic and therefore it wouldn't - take mine. Now what? - -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. - -116. The first thing import did was to complain about a missing CVSROOT.adm. - How about having "import()" copy some "CVSROOT.adm/{loginfo,modules}" - templates into place if it discovers none pointed to by $CVSROOT? As it - stands, one has to hand-craft them. It would be real nice to have it - happen automatically. - [[ I hope to add a "cvsinit" command to the installation instructions ]] - -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 ]] - -136. Is it possible to specify a command to be run on each file when it is - checked out and another command to be run before it is checked in? - My idea of how this feature would be used: - On checkout: - run indent with user's preferred style - On checkin: - run indent with space-saving, style-free for checkin - -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. - -139. murf@dingus.sps.mot.com (Steve Murphy) suggests adding a mode where - CVS can work across e-mail to a single repository located at some - "known" mail address. The update/commit operations would work through - email aliases, causing them to be slow, but would work nonetheless. - This could allow for very cheap remote development sites. - [[ We may get to TCP connections over the Internet for the next - release, but probably won't do an e-mail linkup right away ]] - -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. - -148. It would be nice if cvs import (and perhaps commit when the rcs file - is created) would set the comment leader automagically to the prefix - string of $Log entry, if some option is given. For example, if a file - has a line `%*&# $Log...' the comment leader would be set to `%*&# '. - It would help a lot for unknown files with unknown suffix, and if the - comment leader is not standard. Perhaps for cvs 1.4. - -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. - -162. We have had a number of cases where some idiot does a "cd" into $CVSROOT - and tries to run checkout. I suggest you make it impossible for someone - to check out anything directly into $CVSROOT. This works (though there - is no error checking): - - getwd(curdir); - chdir(getenv("CVSROOT")); - getwd(cvsrootdir); - strcat(cvsrootdir, "/"); - chdir(curdir); - - if (!strncmp (curdir, cvsrootdir, strlen(cvsrootdir))) { - abort with a nasty message about writing into the repository. - } - - (In other words, if the real path where $CVSROOT is stored is a parent of - the real pathname of your current directory, die horribly.) - -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 rcsinfo file should be able to expand environment variables to - find the pathname to the template file. Perhaps it should just - popen("cat <line>"); and read the resulting output, to let the shell - do the dirty work. - -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. - -168. After making changes to a set of files, some of which were in - sub-directories, I wanted to build a patch file for the whole works: - - cvs diff -c -rPROD-REL . - - However, any diffs for files in sub-directories did not have relative - pathnames. For example, with local changes to perl's hints/aix_rs.sh: - - =================================================================== - RCS file: /local/src-CVS/misc/perl/hints/aix_rs.sh,v - retrieving revision 1.1.1.1 - diff -c -r1.1.1.1 aix_rs.sh - *** 1.1.1.1 1992/12/17 19:43:32 - --- aix_rs.sh 1993/01/05 21:33:12 - *************** - *** 1,3 **** - - It was easy enough to fix in this case, but I'd suggest that the file - name have the relative directory prepended and a proper patch "Index:" - line be added, such as this: - - =================================================================== - RCS file: /local/src-CVS/misc/perl/hints/aix_rs.sh,v - retrieving revision 1.1.1.1 - diff -c -r1.1.1.1 hints/aix_rs.sh - Index: hints/aix_rs.sh - *** 1.1.1.1 1992/12/17 19:43:32 - --- hints/aix_rs.sh 1993/01/05 21:33:12 - *************** - *** 1,3 **** - -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. - -171. We have been actively using CVS since September, and we still have the - opinion that automerge is dangerous. We have been burned by it a - couple of times so far, when people missed the notification of a - conflict during an update, and then they committed the files with the - >>>>>>> and <<<<<<< reports in them. This kind of problem usually gets - noticed before commit in compiled files when the compiler croaks, but - we also maintain many documentation files in CVS, and in one case the - problem was not noticed until months later. - -172. "cvs add foo/bar" doesn't work, but "cvs remove foo/bar" works. Maybe - "cvs add" should be rewritten to use the recursive directory code that - most of CVS uses. - -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. - -178. At our site we tag all releases of the sw with - product name and version number, the tag is pretty - long and if you by accident write an old tag which - was in use on an old release, the default behaviour - of cvs is to change the old tag!!! - - Could the CVS system reject to reuse an old tag? - You have the possibility to manually remove it, - but you will not have to be afraid of one tag - silently changing. - -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/acconfig.h b/acconfig.h deleted file mode 100644 index 43bfa2c670889c7dbc4d48785fdc5d30eda6dd29..0000000000000000000000000000000000000000 --- a/acconfig.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Define if you have MIT Kerberos version 4 available. */ -#undef HAVE_KERBEROS diff --git a/config.h.in b/config.h.in deleted file mode 100644 index 86c09fa54d72e240ae52597df793abe8ba85de10..0000000000000000000000000000000000000000 --- a/config.h.in +++ /dev/null @@ -1,165 +0,0 @@ -/* config.h.in. Generated automatically from configure.in by autoheader. */ - -/* Define if using alloca.c. */ -#undef C_ALLOCA - -/* Define if type char is unsigned and you are not using gcc. */ -#undef __CHAR_UNSIGNED__ - -/* 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 if you have <dirent.h>. */ -#undef DIRENT - -/* Define to `int' if <sys/types.h> doesn't define. */ -#undef gid_t - -/* Define if you have alloca, as a function or macro. */ -#undef HAVE_ALLOCA - -/* 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. */ -#undef HAVE_LONG_FILE_NAMES - -/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ -#undef HAVE_SYS_WAIT_H - -/* Define if utime(file, NULL) sets file's timestamp to the present. */ -#undef HAVE_UTIME_NULL - -/* Define if on MINIX. */ -#undef _MINIX - -/* Define to `int' if <sys/types.h> doesn't define. */ -#undef mode_t - -/* Define if you don't have <dirent.h>, but have <ndir.h>. */ -#undef NDIR - -/* Define to `int' if <sys/types.h> doesn't define. */ -#undef pid_t - -/* Define if the system does not provide POSIX.1 features except - with this defined. */ -#undef _POSIX_1_SOURCE - -/* Define if you need to in order for stat and other things to work. */ -#undef _POSIX_SOURCE - -/* Define as the return type of signal handlers (int or void). */ -#undef RETSIGTYPE - -/* 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 you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define if you don't have <dirent.h>, but have <sys/dir.h>. */ -#undef SYSDIR - -/* Define if you don't have <dirent.h>, but have <sys/ndir.h>. */ -#undef SYSNDIR - -/* Define if your <sys/time.h> declares struct tm. */ -#undef TM_IN_SYS_TIME - -/* Define to `int' if <sys/types.h> doesn't define. */ -#undef uid_t - -/* Define if the closedir function returns void instead of int. */ -#undef VOID_CLOSEDIR - -/* Define if you have MIT Kerberos version 4 available. */ -#undef HAVE_KERBEROS - -/* The number of bytes in a int. */ -#undef SIZEOF_INT - -/* The number of bytes in a long. */ -#undef SIZEOF_LONG - -/* Define if you have the fchmod function. */ -#undef HAVE_FCHMOD - -/* Define if you have the fsync function. */ -#undef HAVE_FSYNC - -/* Define if you have the ftime function. */ -#undef HAVE_FTIME - -/* Define if you have the ftruncate function. */ -#undef HAVE_FTRUNCATE - -/* Define if you have the getpagesize function. */ -#undef HAVE_GETPAGESIZE - -/* Define if you have the krb_get_err_text function. */ -#undef HAVE_KRB_GET_ERR_TEXT - -/* Define if you have the mkfifo function. */ -#undef HAVE_MKFIFO - -/* Define if you have the putenv function. */ -#undef HAVE_PUTENV - -/* Define if you have the setvbuf function. */ -#undef HAVE_SETVBUF - -/* Define if you have the timezone function. */ -#undef HAVE_TIMEZONE - -/* Define if you have the vfork function. */ -#undef HAVE_VFORK - -/* Define if you have the vprintf function. */ -#undef HAVE_VPRINTF - -/* Define if you have the <errno.h> header file. */ -#undef HAVE_ERRNO_H - -/* Define if you have the <fcntl.h> header file. */ -#undef HAVE_FCNTL_H - -/* Define if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H - -/* Define if you have the <ndbm.h> header file. */ -#undef HAVE_NDBM_H - -/* Define if you have the <string.h> header file. */ -#undef HAVE_STRING_H - -/* Define if you have the <sys/select.h> header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define if you have the <sys/timeb.h> header file. */ -#undef HAVE_SYS_TIMEB_H - -/* Define if you have the <unistd.h> header file. */ -#undef HAVE_UNISTD_H - -/* Define if you have the <utime.h> header file. */ -#undef HAVE_UTIME_H - -/* Define if you have the nsl library (-lnsl). */ -#undef HAVE_LIBNSL - -/* Define if you have the socket library (-lsocket). */ -#undef HAVE_LIBSOCKET diff --git a/configure b/configure deleted file mode 100755 index 5dcb737b7e5d6c69dd32aba653a6d7aa1cab05df..0000000000000000000000000000000000000000 --- a/configure +++ /dev/null @@ -1,2525 +0,0 @@ -#!/bin/sh - -# Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.1 -# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. - -# Defaults: -ac_help= -ac_default_prefix=/usr/local -# Any additions from configure.in: -ac_help="$ac_help - --with-krb4" - -# Initialize some variables set by options. -# The variables have the same names as the options, with -# dashes changed to underlines. -build=NONE -cache_file=./config.cache -exec_prefix=NONE -host=NONE -no_create= -nonopt=NONE -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -target=NONE -verbose= -x_includes=NONE -x_libraries=NONE - -# Initialize some other variables. -subdirs= - -ac_prev= -for ac_option -do - - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval "$ac_prev=\$ac_option" - ac_prev= - continue - fi - - case "$ac_option" in - -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) ac_optarg= ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case "$ac_option" in - - -build | --build | --buil | --bui | --bu | --b) - ac_prev=build ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) - build="$ac_optarg" ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file="$ac_optarg" ;; - - -disable-* | --disable-*) - ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - eval "enable_${ac_feature}=no" ;; - - -enable-* | --enable-*) - ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } - fi - ac_feature=`echo $ac_feature| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "enable_${ac_feature}='$ac_optarg'" ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix="$ac_optarg" ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he) - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat << EOF -Usage: configure [options] [host] -Options: [defaults in brackets after descriptions] -Configuration: - --cache-file=FILE cache test results in FILE - --help print this message - --no-create do not create output files - --quiet, --silent do not print \`checking...' messages - --version print the version of autoconf that created configure -Directory and file names: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=PREFIX install architecture-dependent files in PREFIX - [same as prefix] - --srcdir=DIR find the sources in DIR [configure dir or ..] - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names -Host type: - --build=BUILD configure for building on BUILD [BUILD=HOST] - --host=HOST configure for HOST [guessed] - --target=TARGET configure for TARGET [TARGET=HOST] -Features and packages: - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --x-includes=DIR X include files are in DIR - --x-libraries=DIR X library files are in DIR ---enable and --with options recognized:$ac_help -EOF - exit 0 ;; - - -host | --host | --hos | --ho) - ac_prev=host ;; - -host=* | --host=* | --hos=* | --ho=*) - host="$ac_optarg" ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix="$ac_optarg" ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix="$ac_optarg" ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix="$ac_optarg" ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name="$ac_optarg" ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site="$ac_optarg" ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir="$ac_optarg" ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target="$ac_optarg" ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.1" - exit 0 ;; - - -with-* | --with-*) - ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - case "$ac_option" in - *=*) ;; - *) ac_optarg=yes ;; - esac - eval "with_${ac_package}='$ac_optarg'" ;; - - -without-* | --without-*) - ac_package=`echo $ac_option|sed -e 's/-*without-//'` - # Reject names that are not valid shell variable names. - if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then - { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } - fi - ac_package=`echo $ac_package| sed 's/-/_/g'` - eval "with_${ac_package}=no" ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes="$ac_optarg" ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries="$ac_optarg" ;; - - -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } - ;; - - *) - if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then - echo "configure: warning: $ac_option: invalid host type" 1>&2 - fi - if test "x$nonopt" != xNONE; then - { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } - fi - nonopt="$ac_option" - ;; - - esac -done - -if test -n "$ac_prev"; then - { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } -fi - -trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15 - -# File descriptor usage: -# 0 unused; standard input -# 1 file creation -# 2 errors and warnings -# 3 unused; some systems may open it to /dev/tty -# 4 checking for... messages and results -# 5 compiler messages saved in config.log -if test "$silent" = yes; then - exec 4>/dev/null -else - exec 4>&1 -fi -exec 5>./config.log - -echo "\ -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. -" 1>&5 - -# Strip out --no-create and --no-recursion so they do not pile up. -# Also quote any args containing shell metacharacters. -ac_configure_args= -for ac_arg -do - case "$ac_arg" in - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c) ;; - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) - ac_configure_args="$ac_configure_args '$ac_arg'" ;; - *) ac_configure_args="$ac_configure_args $ac_arg" ;; - esac -done - -# NLS nuisances. -# Only set LANG and LC_ALL to C if already set. -# These must not be set unconditionally because not all systems understand -# e.g. LANG=C (notably SCO). -if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi -if test "${LANG+set}" = set; then LANG=C; export LANG; fi - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -rf conftest* confdefs.h -# AIX cpp loses on an empty file, so make sure it contains at least a newline. -echo > confdefs.h - -# A filename unique to this package, relative to the directory that -# configure is in, which we can look for to find out if srcdir is correct. -ac_unique_file=src/cvs.h - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then its parent. - ac_prog=$0 - ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` - test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. - srcdir=$ac_confdir - if test ! -r $srcdir/$ac_unique_file; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r $srcdir/$ac_unique_file; then - if test "$ac_srcdir_defaulted" = yes; then - { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } - else - { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } - fi -fi -srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` - -# Prefer explicitly selected file to automatically selected ones. -if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" - fi -fi -for ac_site_file in $CONFIG_SITE; do - if test -r "$ac_site_file"; then - echo "loading site script $ac_site_file" - . "$ac_site_file" - fi -done - -if test -r "$cache_file"; then - echo "loading cache $cache_file" - . $cache_file -else - echo "creating cache $cache_file" - > $cache_file -fi - -ac_ext=c -# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. -ac_cpp='$CPP $CPPFLAGS' -ac_compile='${CC-cc} $CFLAGS $CPPFLAGS conftest.$ac_ext -c 1>&5 2>&5' -ac_link='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext -o conftest $LIBS 1>&5 2>&5' - -if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then - # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. - if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then - ac_n= ac_c=' -' ac_t=' ' - else - ac_n=-n ac_c= ac_t= - fi -else - ac_n= ac_c='\c' ac_t= -fi - - - -# Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_prog_CC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_CC="gcc" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc" -fi -fi -CC="$ac_cv_prog_CC" -if test -n "$CC"; then - echo "$ac_t""$CC" 1>&4 -else - echo "$ac_t""no" 1>&4 -fi - - -echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_prog_gcc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.c <<EOF -#ifdef __GNUC__ - yes; -#endif -EOF -if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then - ac_cv_prog_gcc=yes -else - ac_cv_prog_gcc=no -fi -fi -echo "$ac_t""$ac_cv_prog_gcc" 1>&4 -if test $ac_cv_prog_gcc = yes; then - GCC=yes - if test "${CFLAGS+set}" != set; then - echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_prog_gcc_g'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - echo 'void f(){}' > conftest.c -if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then - ac_cv_prog_gcc_g=yes -else - ac_cv_prog_gcc_g=no -fi -rm -f conftest* - -fi - echo "$ac_t""$ac_cv_prog_gcc_g" 1>&4 - if test $ac_cv_prog_gcc_g = yes; then - CFLAGS="-g -O" - else - CFLAGS="-O" - fi - fi -else - GCC= - test "${CFLAGS+set}" = set || CFLAGS="-g" -fi - -ac_aux_dir= -for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do - if test -f $ac_dir/install-sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f $ac_dir/install.sh; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - fi -done -if test -z "$ac_aux_dir"; then - { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } -fi -ac_config_guess=$ac_aux_dir/config.guess -ac_config_sub=$ac_aux_dir/config.sub -ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# ./install, which can be erroneously created by make from ./install.sh. -echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&4 -if test -z "$INSTALL"; then -if eval "test \"`echo '${'ac_cv_path_install'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - case "$ac_dir" in - ''|.|/etc|/usr/sbin|/usr/etc|/sbin|/usr/afsws/bin|/usr/ucb) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - for ac_prog in ginstall installbsd scoinst install; do - if test -f $ac_dir/$ac_prog; then - if test $ac_prog = install && - grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - # OSF/1 installbsd also uses dspmsg, but is usable. - : - else - ac_cv_path_install="$ac_dir/$ac_prog -c" - break 2 - fi - fi - done - ;; - esac - done - IFS="$ac_save_ifs" - # As a last resort, use the slow shell script. - test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" -fi - INSTALL="$ac_cv_path_install" -fi -echo "$ac_t""$INSTALL" 1>&4 - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -# Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_prog_RANLIB'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_RANLIB="ranlib" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" -fi -fi -RANLIB="$ac_cv_prog_RANLIB" -if test -n "$RANLIB"; then - echo "$ac_t""$RANLIB" 1>&4 -else - echo "$ac_t""no" 1>&4 -fi - -for ac_prog in 'bison -y' byacc -do -# Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_prog_YACC'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test -n "$YACC"; then - ac_cv_prog_YACC="$YACC" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_YACC="$ac_prog" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -YACC="$ac_cv_prog_YACC" -if test -n "$YACC"; then - echo "$ac_t""$YACC" 1>&4 -else - echo "$ac_t""no" 1>&4 -fi - -test -n "$YACC" && break -done -test -n "$YACC" || YACC="yacc" - -echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&4 -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then -if eval "test \"`echo '${'ac_cv_prog_CPP'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - # This must be in double quotes, not single quotes, because CPP may get - # substituted into the Makefile and "${CC-cc}" will confuse make. - CPP="${CC-cc} -E" - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. - cat > conftest.$ac_ext <<EOF -#line 623 "configure" -#include "confdefs.h" -#include <assert.h> -Syntax Error -EOF -eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - rm -rf conftest* - CPP="${CC-cc} -E -traditional-cpp" - cat > conftest.$ac_ext <<EOF -#line 637 "configure" -#include "confdefs.h" -#include <assert.h> -Syntax Error -EOF -eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - : -else - echo "$ac_err" >&5 - rm -rf conftest* - CPP=/lib/cpp -fi -rm -f conftest* -fi -rm -f conftest* - ac_cv_prog_CPP="$CPP" -fi -fi -CPP="$ac_cv_prog_CPP" -echo "$ac_t""$CPP" 1>&4 - -ac_safe=`echo "minix/config.h" | tr './\055' '___'` -echo $ac_n "checking for minix/config.h""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 666 "configure" -#include "confdefs.h" -#include <minix/config.h> -EOF -eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&4 - MINIX=yes -else - echo "$ac_t""no" 1>&4 -MINIX= -fi - -if test "$MINIX" = yes; then - cat >> confdefs.h <<\EOF -#define _POSIX_SOURCE 1 -EOF - - cat >> confdefs.h <<\EOF -#define _POSIX_1_SOURCE 2 -EOF - - cat >> confdefs.h <<\EOF -#define _MINIX 1 -EOF - -fi - -echo $ac_n "checking for working const""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_c_const'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 710 "configure" -#include "confdefs.h" - -int main() { return 0; } -int t() { - -/* Ultrix mips cc rejects this. */ -typedef int charset[2]; const charset x; -/* SunOS 4.1.1 cc rejects this. */ -char const *const *ccp; -char **p; -/* NEC SVR4.0.2 mips cc rejects this. */ -struct point {int x, y;}; -static struct point const zero; -/* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in an arm - of an if-expression whose if-part is not a constant expression */ -const char *g = "string"; -ccp = &g + (g ? g-g : 0); -/* HPUX 7.0 cc rejects these. */ -++ccp; -p = (char**) ccp; -ccp = (char const *const *) p; -{ /* SCO 3.2v4 cc rejects this. */ - char *t; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; -} -{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; -} -{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; -} -{ /* AIX XL C 1.02.0.0 rejects this saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; }; - struct s *b; b->j = 5; -} -{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; -} - -; return 0; } -EOF -if eval $ac_compile; then - rm -rf conftest* - ac_cv_c_const=yes -else - rm -rf conftest* - ac_cv_c_const=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_c_const" 1>&4 -if test $ac_cv_c_const = no; then - cat >> confdefs.h <<\EOF -#define const -EOF - -fi - -# If we cannot run a trivial program, we must be cross compiling. -echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_c_cross'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$cross_compiling" = yes; then - ac_cv_cross=yes -else -cat > conftest.$ac_ext <<EOF -#line 787 "configure" -#include "confdefs.h" -main(){return(0);} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_c_cross=no -else - ac_cv_c_cross=yes -fi -fi -rm -fr conftest* -fi -cross_compiling=$ac_cv_c_cross -echo "$ac_t""$ac_cv_c_cross" 1>&4 - -echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_header_stdc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 808 "configure" -#include "confdefs.h" -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <float.h> -EOF -eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - rm -rf conftest* - ac_cv_header_stdc=yes -else - echo "$ac_err" >&5 - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. -cat > conftest.$ac_ext <<EOF -#line 830 "configure" -#include "confdefs.h" -#include <string.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "memchr" >/dev/null 2>&1; then - : -else - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. -cat > conftest.$ac_ext <<EOF -#line 848 "configure" -#include "confdefs.h" -#include <stdlib.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "free" >/dev/null 2>&1; then - : -else - rm -rf conftest* - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. -if test "$cross_compiling" = yes; then - ac_cv_header_stdc=no -else -cat > conftest.$ac_ext <<EOF -#line 869 "configure" -#include "confdefs.h" -#include <ctype.h> -#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int main () { int i; for (i = 0; i < 256; i++) -if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); -exit (0); } - -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - : -else - ac_cv_header_stdc=no -fi -fi -rm -fr conftest* -fi -fi -echo "$ac_t""$ac_cv_header_stdc" 1>&4 -if test $ac_cv_header_stdc = yes; then - cat >> confdefs.h <<\EOF -#define STDC_HEADERS 1 -EOF - -fi - -for ac_hdr in errno.h unistd.h string.h memory.h utime.h fcntl.h ndbm.h sys/select.h sys/timeb.h -do -ac_safe=`echo "$ac_hdr" | tr './\055' '___'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 906 "configure" -#include "confdefs.h" -#include <$ac_hdr> -EOF -eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -ac_err=`grep -v '^ *+' conftest.out` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&4 - ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` - cat >> confdefs.h <<EOF -#define $ac_tr_hdr 1 -EOF - -else - echo "$ac_t""no" 1>&4 -fi -done - -echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_header_sys_wait_h'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 939 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <sys/wait.h> -#ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#endif -#ifndef WIFEXITED -#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -#endif -int main() { return 0; } -int t() { -int s; -wait (&s); -s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; -; return 0; } -EOF -if eval $ac_compile; then - rm -rf conftest* - ac_cv_header_sys_wait_h=yes -else - rm -rf conftest* - ac_cv_header_sys_wait_h=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&4 -if test $ac_cv_header_sys_wait_h = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_SYS_WAIT_H 1 -EOF - -fi - -echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_type_signal'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 979 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <signal.h> -#ifdef signal -#undef signal -#endif -extern void (*signal ()) (); -int main() { return 0; } -int t() { -int i; -; return 0; } -EOF -if eval $ac_compile; then - rm -rf conftest* - ac_cv_type_signal=void -else - rm -rf conftest* - ac_cv_type_signal=int -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_signal" 1>&4 -cat >> confdefs.h <<EOF -#define RETSIGTYPE $ac_cv_type_signal -EOF - - -ac_header_dirent=no -for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do - ac_safe=`echo "$ac_hdr" | tr './\055' '___'` -echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1016 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <$ac_hdr> -int main() { return 0; } -int t() { -DIR *dirp = 0; -; return 0; } -EOF -if eval $ac_compile; then - rm -rf conftest* - eval "ac_cv_header_dirent_$ac_safe=yes" -else - rm -rf conftest* - eval "ac_cv_header_dirent_$ac_safe=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&4 - ac_header_dirent=$ac_hdr; break -else - echo "$ac_t""no" 1>&4 -fi - -done - -case "$ac_header_dirent" in -dirent.h) cat >> confdefs.h <<\EOF -#define DIRENT 1 -EOF - ;; -sys/ndir.h) cat >> confdefs.h <<\EOF -#define SYSNDIR 1 -EOF - ;; -sys/dir.h) cat >> confdefs.h <<\EOF -#define SYSDIR 1 -EOF - ;; -ndir.h) cat >> confdefs.h <<\EOF -#define NDIR 1 -EOF - ;; -esac - -echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_closedir_void'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else -cat > conftest.$ac_ext <<EOF -#line 1071 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <$ac_header_dirent> -int closedir(); main() { exit(closedir(opendir(".")) != 0); } -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_func_closedir_void=no -else - ac_cv_func_closedir_void=yes -fi -fi -rm -fr conftest* -fi -echo "$ac_t""$ac_cv_func_closedir_void" 1>&4 -if test $ac_cv_func_closedir_void = yes; then - cat >> confdefs.h <<\EOF -#define VOID_CLOSEDIR 1 -EOF - -fi - -echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_type_uid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1099 "configure" -#include "confdefs.h" -#include <sys/types.h> -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "uid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_uid_t=yes -else - rm -rf conftest* - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_uid_t" 1>&4 -if test $ac_cv_type_uid_t = no; then - cat >> confdefs.h <<\EOF -#define uid_t int -EOF - - cat >> confdefs.h <<\EOF -#define gid_t int -EOF - -fi - -echo $ac_n "checking for mode_t""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_type_mode_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1131 "configure" -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -#include <stdlib.h> -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "mode_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_mode_t=yes -else - rm -rf conftest* - ac_cv_type_mode_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_mode_t" 1>&4 -if test $ac_cv_type_mode_t = no; then - cat >> confdefs.h <<\EOF -#define mode_t int -EOF - -fi - -echo $ac_n "checking for size_t""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_type_size_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1162 "configure" -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -#include <stdlib.h> -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "size_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_size_t=yes -else - rm -rf conftest* - ac_cv_type_size_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_size_t" 1>&4 -if test $ac_cv_type_size_t = no; then - cat >> confdefs.h <<\EOF -#define size_t unsigned -EOF - -fi - -echo $ac_n "checking for pid_t""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_type_pid_t'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1193 "configure" -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -#include <stdlib.h> -#endif -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pid_t" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_type_pid_t=yes -else - rm -rf conftest* - ac_cv_type_pid_t=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_type_pid_t" 1>&4 -if test $ac_cv_type_pid_t = no; then - cat >> confdefs.h <<\EOF -#define pid_t int -EOF - -fi - -echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_c_char_unsigned'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$GCC" = yes; then - # GCC predefines this symbol on systems where it applies. -cat > conftest.$ac_ext <<EOF -#line 1226 "configure" -#include "confdefs.h" -#ifdef __CHAR_UNSIGNED__ - yes -#endif - -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "yes" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_c_char_unsigned=yes -else - rm -rf conftest* - ac_cv_c_char_unsigned=no -fi -rm -f conftest* - -else -if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else -cat > conftest.$ac_ext <<EOF -#line 1248 "configure" -#include "confdefs.h" -/* volatile prevents gcc2 from optimizing the test away on sparcs. */ -#if !defined(__STDC__) || __STDC__ != 1 -#define volatile -#endif -main() { - volatile char c = 255; exit(c < 0); -} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_c_char_unsigned=yes -else - ac_cv_c_char_unsigned=no -fi -fi -rm -fr conftest* -fi -fi -echo "$ac_t""$ac_cv_c_char_unsigned" 1>&4 -if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then - cat >> confdefs.h <<\EOF -#define __CHAR_UNSIGNED__ 1 -EOF - -fi - -echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_struct_tm'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1281 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <time.h> -int main() { return 0; } -int t() { -struct tm *tp; tp->tm_sec; -; return 0; } -EOF -if eval $ac_compile; then - rm -rf conftest* - ac_cv_struct_tm=time.h -else - rm -rf conftest* - ac_cv_struct_tm=sys/time.h -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_struct_tm" 1>&4 -if test $ac_cv_struct_tm = sys/time.h; then - cat >> confdefs.h <<\EOF -#define TM_IN_SYS_TIME 1 -EOF - -fi - -for ac_func in fnmatch getwd mkdir rename strdup dup2 strerror valloc waitpid memmove -do -echo $ac_n "checking for $ac_func""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_$ac_func'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1315 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char $ac_func(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_$ac_func) || defined (__stub___$ac_func) -choke me -#else -$ac_func(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_$ac_func=yes" -else - rm -rf conftest* - eval "ac_cv_func_$ac_func=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then - echo "$ac_t""yes" 1>&4 - : -else - echo "$ac_t""no" 1>&4 -LIBOBJS="$LIBOBJS ${ac_func}.o" -fi - -done - -for ac_func in fchmod fsync ftime mkfifo putenv setvbuf vfork vprintf ftruncate timezone getpagesize -do -echo $ac_n "checking for $ac_func""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_$ac_func'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1362 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char $ac_func(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_$ac_func) || defined (__stub___$ac_func) -choke me -#else -$ac_func(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_$ac_func=yes" -else - rm -rf conftest* - eval "ac_cv_func_$ac_func=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then - echo "$ac_t""yes" 1>&4 - ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` - cat >> confdefs.h <<EOF -#define $ac_tr_func 1 -EOF - -else - echo "$ac_t""no" 1>&4 -fi -done - -echo $ac_n "checking for re_exec""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_re_exec'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1409 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char re_exec(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_re_exec) || defined (__stub___re_exec) -choke me -#else -re_exec(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_re_exec=yes" -else - rm -rf conftest* - eval "ac_cv_func_re_exec=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'re_exec`\" = yes"; then - echo "$ac_t""yes" 1>&4 - : -else - echo "$ac_t""no" 1>&4 -LIBOBJS="$LIBOBJS regex.o" -fi - -echo $ac_n "checking for gethostname""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_gethostname'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1452 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char gethostname(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_gethostname) || defined (__stub___gethostname) -choke me -#else -gethostname(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_gethostname=yes" -else - rm -rf conftest* - eval "ac_cv_func_gethostname=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'gethostname`\" = yes"; then - echo "$ac_t""yes" 1>&4 - : -else - echo "$ac_t""no" 1>&4 -LIBOBJS="$LIBOBJS hostname.o" -fi - -echo $ac_n "checking whether utime accepts a null argument""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_utime_null'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - rm -f conftestdata; > conftestdata -# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. -if test "$cross_compiling" = yes; then - ac_cv_func_utime_null=no -else -cat > conftest.$ac_ext <<EOF -#line 1500 "configure" -#include "confdefs.h" -#include <sys/types.h> -#include <sys/stat.h> -main() { -struct stat s, t; -exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0 -&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime -&& t.st_mtime - s.st_mtime < 120)); -} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_func_utime_null=yes -else - ac_cv_func_utime_null=no -fi -fi -rm -fr conftest* -rm -f core -fi -echo "$ac_t""$ac_cv_func_utime_null" 1>&4 -if test $ac_cv_func_utime_null = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_UTIME_NULL 1 -EOF - -fi - -# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works -# for constant arguments. Useless! -echo $ac_n "checking for working alloca.h""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_header_alloca_h'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1536 "configure" -#include "confdefs.h" -#include <alloca.h> -int main() { return 0; } -int t() { -char *p = alloca(2 * sizeof(int)); -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - ac_cv_header_alloca_h=yes -else - rm -rf conftest* - ac_cv_header_alloca_h=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_header_alloca_h" 1>&4 -if test $ac_cv_header_alloca_h = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_ALLOCA_H 1 -EOF - -fi - -echo $ac_n "checking for alloca""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_alloca'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1567 "configure" -#include "confdefs.h" - -#ifdef __GNUC__ -# define alloca __builtin_alloca -#else -# if HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -char *alloca (); -# endif -# endif -# endif -#endif - -int main() { return 0; } -int t() { -char *p = (char *) alloca(1); -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - ac_cv_func_alloca=yes -else - rm -rf conftest* - ac_cv_func_alloca=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_func_alloca" 1>&4 -if test $ac_cv_func_alloca = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_ALLOCA 1 -EOF - -fi - -if test $ac_cv_func_alloca = no; then - # The SVR3 libPW and SVR4 libucb both contain incompatible functions - # that cause trouble. Some versions do not even contain alloca or - # contain a buggy version. If you still want to use their alloca, - # use ar to extract alloca.o from them instead of compiling alloca.c. - ALLOCA=alloca.o - cat >> confdefs.h <<\EOF -#define C_ALLOCA 1 -EOF - - -echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_os_cray'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1625 "configure" -#include "confdefs.h" -#if defined(CRAY) && ! defined(CRAY2) -webecray -#else -wenotbecray -#endif - -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "webecray" >/dev/null 2>&1; then - rm -rf conftest* - ac_cv_os_cray=yes -else - rm -rf conftest* - ac_cv_os_cray=no -fi -rm -f conftest* - -fi -echo "$ac_t""$ac_cv_os_cray" 1>&4 -if test $ac_cv_os_cray = yes; then -echo $ac_n "checking for _getb67""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func__getb67'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1652 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char _getb67(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub__getb67) || defined (__stub____getb67) -choke me -#else -_getb67(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func__getb67=yes" -else - rm -rf conftest* - eval "ac_cv_func__getb67=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'_getb67`\" = yes"; then - echo "$ac_t""yes" 1>&4 - cat >> confdefs.h <<\EOF -#define CRAY_STACKSEG_END _getb67 -EOF - -else - echo "$ac_t""no" 1>&4 -echo $ac_n "checking for GETB67""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_GETB67'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1695 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char GETB67(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_GETB67) || defined (__stub___GETB67) -choke me -#else -GETB67(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_GETB67=yes" -else - rm -rf conftest* - eval "ac_cv_func_GETB67=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'GETB67`\" = yes"; then - echo "$ac_t""yes" 1>&4 - cat >> confdefs.h <<\EOF -#define CRAY_STACKSEG_END GETB67 -EOF - -else - echo "$ac_t""no" 1>&4 -echo $ac_n "checking for getb67""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_getb67'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 1738 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char getb67(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_getb67) || defined (__stub___getb67) -choke me -#else -getb67(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_getb67=yes" -else - rm -rf conftest* - eval "ac_cv_func_getb67=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'getb67`\" = yes"; then - echo "$ac_t""yes" 1>&4 - cat >> confdefs.h <<\EOF -#define CRAY_STACKSEG_END getb67 -EOF - -else - echo "$ac_t""no" 1>&4 -fi - -fi - -fi - -fi - -echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_c_stack_direction'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$cross_compiling" = yes; then - ac_cv_c_stack_direction=0 -else -cat > conftest.$ac_ext <<EOF -#line 1792 "configure" -#include "confdefs.h" -find_stack_direction () -{ - static char *addr = 0; - auto char dummy; - if (addr == 0) - { - addr = &dummy; - return find_stack_direction (); - } - else - return (&dummy > addr) ? 1 : -1; -} -main () -{ - exit (find_stack_direction() < 0); -} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_c_stack_direction=1 -else - ac_cv_c_stack_direction=-1 -fi -fi -rm -fr conftest* -fi -echo "$ac_t""$ac_cv_c_stack_direction" 1>&4 -cat >> confdefs.h <<EOF -#define STACK_DIRECTION $ac_cv_c_stack_direction -EOF - -fi - -echo $ac_n "checking for long file names""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_sys_long_file_names'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - ac_cv_sys_long_file_names=yes -# Test for long file names in all the places we know might matter: -# . the current directory, where building will happen -# /tmp where it might want to write temporary files -# /var/tmp likewise -# /usr/tmp likewise -# $prefix/lib where we will be installing things -# $exec_prefix/lib likewise -# eval it to expand exec_prefix. -for ac_dir in `eval echo . /tmp /var/tmp /usr/tmp $prefix/lib $exec_prefix/lib` ; do - test -d $ac_dir || continue - test -w $ac_dir || continue # It is less confusing to not echo anything here. - (echo 1 > $ac_dir/conftest9012345) 2>/dev/null - (echo 2 > $ac_dir/conftest9012346) 2>/dev/null - val=`cat $ac_dir/conftest9012345 2>/dev/null` - if test ! -f $ac_dir/conftest9012345 || test "$val" != 1; then - ac_cv_sys_long_file_names=no - rm -f $ac_dir/conftest9012345 $ac_dir/conftest9012346 2>/dev/null - break - fi - rm -f $ac_dir/conftest9012345 $ac_dir/conftest9012346 2>/dev/null -done -fi -echo "$ac_t""$ac_cv_sys_long_file_names" 1>&4 -if test $ac_cv_sys_long_file_names = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_LONG_FILE_NAMES 1 -EOF - -fi - - -# Check whether --with-krb4 or --without-krb4 was given. -withval="$with_krb4" -if test -n "$withval"; then - KRB4=$withval -else - KRB4=/usr/kerberos - -fi -echo "default place for krb4 is $KRB4" - - -echo $ac_n "checking size of long""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_sizeof_long'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else -cat > conftest.$ac_ext <<EOF -#line 1882 "configure" -#include "confdefs.h" -#include <stdio.h> -main() -{ - FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof(long)); - exit(0); -} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_sizeof_long=`cat conftestval` -fi -fi -rm -fr conftest* -fi -echo "$ac_t""$ac_cv_sizeof_long" 1>&4 -cat >> confdefs.h <<EOF -#define SIZEOF_LONG $ac_cv_sizeof_long -EOF - - -echo $ac_n "checking size of int""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_sizeof_int'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else -cat > conftest.$ac_ext <<EOF -#line 1914 "configure" -#include "confdefs.h" -#include <stdio.h> -main() -{ - FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof(int)); - exit(0); -} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_sizeof_int=`cat conftestval` -fi -fi -rm -fr conftest* -fi -echo "$ac_t""$ac_cv_sizeof_int" 1>&4 -cat >> confdefs.h <<EOF -#define SIZEOF_INT $ac_cv_sizeof_int -EOF - - - - -krb_h= -# If we cannot run a trivial program, we must be cross compiling. -echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_c_cross'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - if test "$cross_compiling" = yes; then - ac_cv_cross=yes -else -cat > conftest.$ac_ext <<EOF -#line 1950 "configure" -#include "confdefs.h" -main(){return(0);} -EOF -eval $ac_link -if test -s conftest && (./conftest; exit) 2>/dev/null; then - ac_cv_c_cross=no -else - ac_cv_c_cross=yes -fi -fi -rm -fr conftest* -fi -cross_compiling=$ac_cv_c_cross -echo "$ac_t""$ac_cv_c_cross" 1>&4 - -echo "checking for krb.h" 1>&4 -cat > conftest.$ac_ext <<EOF -#line 1968 "configure" -#include "confdefs.h" -#include <krb.h> -int main() { return 0; } -int t() { -int i; -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - krb_h=yes krb_incdir= -else - rm -rf conftest* - if test -z "$cross_compiling" && test -r $KRB4/include/krb.h; then - hold_cflags=$CFLAGS - CFLAGS="$CFLAGS -I$KRB4/include" - echo "checking for krb.h in $KRB4/include" 1>&4 -cat > conftest.$ac_ext <<EOF -#line 1986 "configure" -#include "confdefs.h" -#include <krb.h> -int main() { return 0; } -int t() { -int i; -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - krb_h=yes krb_incdir=$KRB4/include -fi -rm -f conftest* - - CFLAGS=$hold_cflags - fi -fi -rm -f conftest* - -if test -n "$krb_h"; then - krb_lib= - echo $ac_n "checking for -lkrb""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_lib_krb'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - ac_save_LIBS="$LIBS" -LIBS="$LIBS -lkrb " -cat > conftest.$ac_ext <<EOF -#line 2014 "configure" -#include "confdefs.h" - -int main() { return 0; } -int t() { -main() -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - ac_cv_lib_krb=yes -else - rm -rf conftest* - ac_cv_lib_krb=no -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -echo "$ac_t""$ac_cv_lib_krb" 1>&4 -if test "$ac_cv_lib_krb" = yes; then - krb_lib=yes krb_libdir= -else - if test -z "$cross_compiling" && test -r $KRB4/lib/libkrb.a; then - krb_lib=yes krb_libdir=$KRB4/lib - fi -fi - - if test -n "$krb_lib"; then - cat >> confdefs.h <<\EOF -#define HAVE_KERBEROS 1 -EOF - - test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}" - LIBS="${LIBS} -lkrb" - echo $ac_n "checking for -ldes""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_lib_des'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - ac_save_LIBS="$LIBS" -LIBS="$LIBS -ldes " -cat > conftest.$ac_ext <<EOF -#line 2056 "configure" -#include "confdefs.h" - -int main() { return 0; } -int t() { -main() -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - ac_cv_lib_des=yes -else - rm -rf conftest* - ac_cv_lib_des=no -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -echo "$ac_t""$ac_cv_lib_des" 1>&4 -if test "$ac_cv_lib_des" = yes; then - LIBS="${LIBS} -ldes" -fi - - if test -n "$krb_incdir"; then - includeopt="${includeopt} -I$krb_incdir" - - fi - fi -fi -for ac_func in krb_get_err_text -do -echo $ac_n "checking for $ac_func""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_$ac_func'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 2093 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char $ac_func(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_$ac_func) || defined (__stub___$ac_func) -choke me -#else -$ac_func(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_$ac_func=yes" -else - rm -rf conftest* - eval "ac_cv_func_$ac_func=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then - echo "$ac_t""yes" 1>&4 - ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` - cat >> confdefs.h <<EOF -#define $ac_tr_func 1 -EOF - -else - echo "$ac_t""no" 1>&4 -fi -done - -# If we can't find connect, try looking in -lsocket and -lnsl. The -# Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has -# libsocket.so which has a bad implementation of gethostbyname (it -# only looks in /etc/hosts), so we only look for -lsocket if we need -# it. -echo $ac_n "checking for connect""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_func_connect'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - cat > conftest.$ac_ext <<EOF -#line 2145 "configure" -#include "confdefs.h" -#include <ctype.h> /* Arbitrary system header to define __stub macros. */ -/* Override any gcc2 internal prototype to avoid an error. */ -char connect(); - -int main() { return 0; } -int t() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_connect) || defined (__stub___connect) -choke me -#else -connect(); -#endif - -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - eval "ac_cv_func_connect=yes" -else - rm -rf conftest* - eval "ac_cv_func_connect=no" -fi -rm -f conftest* - -fi -if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then - echo "$ac_t""yes" 1>&4 - : -else - echo "$ac_t""no" 1>&4 -echo $ac_n "checking for -lsocket""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_lib_socket'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - ac_save_LIBS="$LIBS" -LIBS="$LIBS -lsocket " -cat > conftest.$ac_ext <<EOF -#line 2187 "configure" -#include "confdefs.h" - -int main() { return 0; } -int t() { -main() -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - ac_cv_lib_socket=yes -else - rm -rf conftest* - ac_cv_lib_socket=no -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -echo "$ac_t""$ac_cv_lib_socket" 1>&4 -if test "$ac_cv_lib_socket" = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_LIBSOCKET 1 -EOF - - LIBS="$LIBS -lsocket" - -fi - echo $ac_n "checking for -lnsl""... $ac_c" 1>&4 -if eval "test \"`echo '${'ac_cv_lib_nsl'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&4 -else - ac_save_LIBS="$LIBS" -LIBS="$LIBS -lnsl " -cat > conftest.$ac_ext <<EOF -#line 2222 "configure" -#include "confdefs.h" - -int main() { return 0; } -int t() { -main() -; return 0; } -EOF -if eval $ac_link; then - rm -rf conftest* - ac_cv_lib_nsl=yes -else - rm -rf conftest* - ac_cv_lib_nsl=no -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -echo "$ac_t""$ac_cv_lib_nsl" 1>&4 -if test "$ac_cv_lib_nsl" = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_LIBNSL 1 -EOF - - LIBS="$LIBS -lnsl" - -fi - -fi - - -trap '' 1 2 15 -if test -w $cache_file; then -echo "updating cache $cache_file" -cat > $cache_file <<\EOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs. It is not useful on other systems. -# If it contains results you don't want to keep, you may remove or edit it. -# -# By default, configure uses ./config.cache as the cache file, -# creating it if it does not exist already. You can give configure -# the --cache-file=FILE option to use a different cache file; that is -# what configure does when it calls configure scripts in -# subdirectories, so they share the cache. -# Giving --cache-file=/dev/null disables caching, for debugging configure. -# config.status only pays attention to the cache file if you give it the -# --recheck option to rerun configure. -# -EOF -# Ultrix sh set writes to stderr and can't be redirected directly. -(set) 2>&1 | - sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/: \${\1='\2'}/p" \ - >> $cache_file -else -echo "not updating unwritable cache $cache_file" -fi - -trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15 - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Any assignment to VPATH causes Sun make to only execute -# the first set of double-colon rules, so remove it if not needed. -# If there is a colon in the path, we need to keep it. -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' -fi - -trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 - -DEFS=-DHAVE_CONFIG_H - -# Without the "./", some shells look in PATH for config.status. -: ${CONFIG_STATUS=./config.status} - -echo creating $CONFIG_STATUS -rm -f $CONFIG_STATUS -cat > $CONFIG_STATUS <<EOF -#!/bin/sh -# Generated automatically by configure. -# Run this file to recreate the current configuration. -# This directory was configured as follows, -# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# -# $0 $ac_configure_args -# -# Compiler output produced by configure, useful for debugging -# configure, is in ./config.log if it exists. - -ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" -for ac_option -do - case "\$ac_option" in - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" - exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; - -version | --version | --versio | --versi | --vers | --ver | --ve | --v) - echo "$CONFIG_STATUS generated by autoconf version 2.1" - exit 0 ;; - -help | --help | --hel | --he | --h) - echo "\$ac_cs_usage"; exit 0 ;; - *) echo "\$ac_cs_usage"; exit 1 ;; - esac -done - -ac_given_srcdir=$srcdir -ac_given_INSTALL="$INSTALL" - -trap 'rm -fr Makefile lib/Makefile src/Makefile doc/Makefile man/Makefile \ - contrib/Makefile examples/Makefile stamp-h config.h conftest*; exit 1' 1 2 15 - -# Protect against being on the right side of a sed subst in config.status. -sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; - s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF -$ac_vpsub -$extrasub -s%@CFLAGS@%$CFLAGS%g -s%@CPPFLAGS@%$CPPFLAGS%g -s%@CXXFLAGS@%$CXXFLAGS%g -s%@DEFS@%$DEFS%g -s%@LDFLAGS@%$LDFLAGS%g -s%@LIBS@%$LIBS%g -s%@exec_prefix@%$exec_prefix%g -s%@prefix@%$prefix%g -s%@program_transform_name@%$program_transform_name%g -s%@CC@%$CC%g -s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g -s%@INSTALL_DATA@%$INSTALL_DATA%g -s%@RANLIB@%$RANLIB%g -s%@YACC@%$YACC%g -s%@CPP@%$CPP%g -s%@LIBOBJS@%$LIBOBJS%g -s%@ALLOCA@%$ALLOCA%g -s%@KRB4@%$KRB4%g -s%@includeopt@%$includeopt%g - -CEOF -EOF -cat >> $CONFIG_STATUS <<EOF - -CONFIG_FILES=\${CONFIG_FILES-"Makefile lib/Makefile src/Makefile doc/Makefile man/Makefile \ - contrib/Makefile examples/Makefile stamp-h"} -EOF -cat >> $CONFIG_STATUS <<\EOF -for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then - # Support "outfile[:infile]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - # Adjust relative srcdir, etc. for subdirectories. - - # Remove last slash and all that follows it. Not all systems have dirname. - ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` - if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then - # The file is in a subdirectory. - test ! -d "$ac_dir" && mkdir "$ac_dir" - ac_dir_suffix="/$ac_dir" - # A "../" for each directory in $ac_dir_suffix. - ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` - else - ac_dir_suffix= ac_dots= - fi - - case "$ac_given_srcdir" in - .) srcdir=. - if test -z "$ac_dots"; then top_srcdir=. - else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; - /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; - *) # Relative path. - srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" - top_srcdir="$ac_dots$ac_given_srcdir" ;; - esac - - case "$ac_given_INSTALL" in - [/$]*) INSTALL="$ac_given_INSTALL" ;; - *) INSTALL="$ac_dots$ac_given_INSTALL" ;; - esac - echo creating "$ac_file" - rm -f "$ac_file" - configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." - case "$ac_file" in - *Makefile*) ac_comsub="1i\\ -# $configure_input" ;; - *) ac_comsub= ;; - esac - sed -e "$ac_comsub -s%@configure_input@%$configure_input%g -s%@srcdir@%$srcdir%g -s%@top_srcdir@%$top_srcdir%g -s%@INSTALL@%$INSTALL%g -" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file -fi; done -rm -f conftest.subs - -# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where -# NAME is the cpp macro being defined and VALUE is the value it is being given. -# -# ac_d sets the value in "#define NAME VALUE" lines. -ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' -ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' -ac_dC='\3' -ac_dD='%g' -# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". -ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_uB='\([ ]\)%\1#\2define\3' -ac_uC=' ' -ac_uD='\4%g' -# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". -ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' -ac_eB='$%\1#\2define\3' -ac_eC=' ' -ac_eD='%g' - -CONFIG_HEADERS=${CONFIG_HEADERS-"config.h"} -for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then - # Support "outfile[:infile]", defaulting infile="outfile.in". - case "$ac_file" in - *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` - ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; - *) ac_file_in="${ac_file}.in" ;; - esac - - echo creating $ac_file - - rm -f conftest.frag conftest.in conftest.out - cp $ac_given_srcdir/$ac_file_in conftest.in - -EOF - -# Transform confdefs.h into a sed script conftest.vals that substitutes -# the proper values into config.h.in to produce config.h. And first: -# Protect against being on the right side of a sed subst in config.status. -# Protect against being in an unquoted here document in config.status. -rm -f conftest.vals -cat > conftest.hdr <<\EOF -s/[\\&%]/\\&/g -s%[\\$`]%\\&%g -s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp -s%ac_d%ac_u%gp -s%ac_u%ac_e%gp -EOF -sed -n -f conftest.hdr confdefs.h > conftest.vals -rm -f conftest.hdr - -# This sed command replaces #undef with comments. This is necessary, for -# example, in the case of _POSIX_SOURCE, which is predefined and required -# on some systems where configure will not decide to define it. -cat >> conftest.vals <<\EOF -s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% -EOF - -# Break up conftest.vals because some shells have a limit on -# the size of here documents, and old seds have small limits too. -# Maximum number of lines to put in a single here document. -ac_max_here_lines=12 - -rm -f conftest.tail -while : -do - ac_lines=`grep -c . conftest.vals` - # grep -c gives empty output for an empty file on some AIX systems. - if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi - # Write a limited-size here document to conftest.frag. - echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS - sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS - echo 'CEOF - sed -f conftest.frag conftest.in > conftest.out - rm -f conftest.in - mv conftest.out conftest.in -' >> $CONFIG_STATUS - sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail - rm -f conftest.vals - mv conftest.tail conftest.vals -done -rm -f conftest.vals - -cat >> $CONFIG_STATUS <<\EOF - rm -f conftest.frag conftest.h - echo "/* $ac_file. Generated automatically by configure. */" > conftest.h - cat conftest.in >> conftest.h - rm -f conftest.in - if cmp -s $ac_file conftest.h 2>/dev/null; then - echo "$ac_file is unchanged" - rm -f conftest.h - else - rm -f $ac_file - mv conftest.h $ac_file - fi -fi; done - - - -exit 0 -EOF -chmod +x $CONFIG_STATUS -rm -fr confdefs* $ac_clean_files -test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS - diff --git a/configure.in b/configure.in deleted file mode 100644 index 51efbccd88c663dd81b2ae4be4e32f5ffd3e325b..0000000000000000000000000000000000000000 --- a/configure.in +++ /dev/null @@ -1,82 +0,0 @@ -dnl configure.in for cvs -AC_INIT(src/cvs.h) -AC_PREREQ(2.1)dnl Required Autoconf version. -AC_CONFIG_HEADER(config.h) -AC_PROG_CC -AC_PROG_INSTALL -AC_PROG_RANLIB -AC_PROG_YACC -AC_MINIX -AC_C_CONST -AC_HEADER_STDC -AC_CHECK_HEADERS(errno.h unistd.h string.h memory.h utime.h fcntl.h ndbm.h sys/select.h sys/timeb.h) -AC_HEADER_SYS_WAIT -AC_TYPE_SIGNAL -AC_DIR_HEADER -AC_TYPE_UID_T -AC_TYPE_MODE_T -AC_TYPE_SIZE_T -AC_TYPE_PID_T -AC_C_CHAR_UNSIGNED -AC_STRUCT_TM -AC_REPLACE_FUNCS(fnmatch getwd mkdir rename strdup dup2 strerror valloc waitpid memmove) -AC_CHECK_FUNCS(fchmod fsync ftime mkfifo putenv setvbuf vfork vprintf ftruncate timezone getpagesize) -AC_CHECK_FUNC(re_exec, :, LIBOBJS="$LIBOBJS regex.o") -AC_CHECK_FUNC(gethostname, :, LIBOBJS="$LIBOBJS hostname.o") -AC_FUNC_UTIME_NULL -AC_FUNC_ALLOCA -AC_SYS_LONG_FILE_NAMES -dnl -dnl set $(KRB4) from --with-krb4=value -- WITH_KRB4 -dnl -define(WITH_KRB4,[ -AC_WITH([krb4], -KRB4=$withval, -KRB4=/usr/kerberos -)dnl -echo "default place for krb4 is $KRB4" -AC_SUBST(KRB4)])dnl -WITH_KRB4 - -AC_CHECK_SIZEOF(long) -AC_CHECK_SIZEOF(int) - -AC_REQUIRE([AC_CROSS_CHECK]) -krb_h= -AC_COMPILE_CHECK(krb.h,[#include <krb.h>],[int i;], - [krb_h=yes krb_incdir=], - [if test -z "$cross_compiling" && test -r $KRB4/include/krb.h; then - hold_cflags=$CFLAGS - CFLAGS="$CFLAGS -I$KRB4/include" - AC_COMPILE_CHECK(krb.h in $KRB4/include, - [#include <krb.h>],[int i;], - [krb_h=yes krb_incdir=$KRB4/include]) - CFLAGS=$hold_cflags - fi]) -if test -n "$krb_h"; then - krb_lib= - AC_HAVE_LIBRARY(-lkrb,[krb_lib=yes krb_libdir=], - [if test -z "$cross_compiling" && test -r $KRB4/lib/libkrb.a; then - krb_lib=yes krb_libdir=$KRB4/lib - fi]) - if test -n "$krb_lib"; then - AC_DEFINE(HAVE_KERBEROS) - test -n "${krb_libdir}" && LIBS="${LIBS} -L${krb_libdir}" - LIBS="${LIBS} -lkrb" - AC_HAVE_LIBRARY(-ldes,[LIBS="${LIBS} -ldes"]) - if test -n "$krb_incdir"; then - includeopt="${includeopt} -I$krb_incdir" - AC_SUBST(includeopt) - fi - fi -fi -AC_CHECK_FUNCS(krb_get_err_text) -# If we can't find connect, try looking in -lsocket and -lnsl. The -# Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has -# libsocket.so which has a bad implementation of gethostbyname (it -# only looks in /etc/hosts), so we only look for -lsocket if we need -# it. -AC_CHECK_FUNC(connect, :, [AC_HAVE_LIBRARY(-lsocket) AC_HAVE_LIBRARY(-lnsl)]) - -AC_OUTPUT(Makefile lib/Makefile src/Makefile doc/Makefile man/Makefile \ - contrib/Makefile examples/Makefile stamp-h) diff --git a/contrib/.cvsignore b/contrib/.cvsignore deleted file mode 100644 index f3c7a7c5da68804a1bdf391127ba34aed33c3cca..0000000000000000000000000000000000000000 --- a/contrib/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/contrib/ChangeLog b/contrib/ChangeLog deleted file mode 100644 index 86d40b89170d4e1e93ae415255719deed8e44e0c..0000000000000000000000000000000000000000 --- a/contrib/ChangeLog +++ /dev/null @@ -1,22 +0,0 @@ -Mon Feb 13 13:32:07 1995 Jim Blandy <jimb@totoro.bio.indiana.edu> - - * rcs2log: rcs2log was originally in this tree; how did it get - deleted? Anyway, this is the version distributed with Emacs - 19.28, hacked to support CVS and Remote CVS. - -Mon Jul 26 13:18:23 1993 David J. Mackenzie (djm@thepub.cygnus.com) - - * rcs-to-cvs: Rewrite in sh. - -Wed Jul 14 21:16:40 1993 David J. Mackenzie (djm@thepub.cygnus.com) - - * rcs-to-cvs: Don't source .cshrc or hardcode paths. - Make respository dir if needed. Don't suppress errors - (such as prompts) from co. - -Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) - - * Makefile.in, configure.in: removed traces of namesubdir, - -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced - copyrights to '92, changed some from Cygnus to FSF. - diff --git a/contrib/Makefile.in b/contrib/Makefile.in deleted file mode 100644 index ddf198528d915117c6b69f67596597bcf8d04c73..0000000000000000000000000000000000000000 --- a/contrib/Makefile.in +++ /dev/null @@ -1,90 +0,0 @@ -# Makefile for GNU CVS contributed sources. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986, 1988-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. - -# $CVSid: @(#)Makefile.in 1.6 94/10/22 $ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -# Where to install the executables. -bindir = $(exec_prefix)/bin - -# Where to put the system-wide .cvsrc file -libdir = $(prefix)/lib - -# Where to put the manual pages. -mandir = $(prefix)/man - -# Use cp if you don't have install. -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ - -DISTFILES = Makefile.in README clmerge cln_hist.pl commit_prep.pl cvs_acls.pl \ - cvscheck cvscheck.man cvshelp.man descend descend.man dirfns \ - log.pl log_accum.pl mfpipe.pl rcs-to-cvs rcslock.pl sccs2rcs -# intro.doc used to be in the above list, but wasn't in the disty I got. - -CONTRIB_FILES = README cln_hist.pl commit_prep.pl cvs_acls.pl cvscheck cvscheck.man \ - cvshelp.man intro.doc log.pl log_accum.pl mfpipe.pl rcs-to-cvs rcslock.pl sccs2rcs - -all: Makefile -.PHONY: all - -install: all $(libdir)/cvs/contrib - for f in $(CONTRIB_FILES) ; do\ - $(INSTALL_DATA) $(srcdir)/$$f $(libdir)/cvs/contrib/$$f; \ - done -.PHONY: install - -$(libdir)/cvs/contrib: - $(top_srcdir)/mkinstalldirs $(libdir)/cvs/contrib - -tags: -.PHONY: tags - -TAGS: -.PHONY: TAGS - -ls: - @echo $(DISTFILES) -.PHONY: ls - -clean: - /bin/rm -f *.o core -.PHONY: clean - -distclean: clean - rm -f Makefile -.PHONY: distclean - -realclean: distclean -.PHONY: realclean - -dist: - ln $(DISTFILES) ../`cat ../.fname`/contrib -.PHONY: dist - -Makefile: Makefile.in - cd ..; $(SHELL) config.status diff --git a/contrib/README b/contrib/README deleted file mode 100644 index 8d90180d7c78c5618e6fbf4f8d09cf6d45116830..0000000000000000000000000000000000000000 --- a/contrib/README +++ /dev/null @@ -1,87 +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 READM file will be kept -up-to-date from release to release. BUT, I must point out that these -contributions are really, REALLY UNSSUPPORTED. In fact, I probably -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.pl 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.pl A perl script, to be combined with log_accum.pl, to - log_accum.pl provide for a way to combine the individual log - messages of a multi-directory "commit" into a - single log message, and mail the result somewhere. - Also does other checks for $Id and that you are - committing the correct revision of the file. - Read the comments carefully. - Contributed by David Hampton <hampton@cisco.com>. - mfpipe.pl 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.pl 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>. - cvs_acls.pl 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.pl 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>. diff --git a/contrib/cln_hist.pl b/contrib/cln_hist.pl deleted file mode 100644 index a61ac578e7092aa8504520656bdcc9e0d7c533e8..0000000000000000000000000000000000000000 --- a/contrib/cln_hist.pl +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/perl -- # -*-Perl-*- -# -# $Id: cln_hist.pl,v 1.1.1.1 1994/12/03 06:09:17 jimb 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/contrib/commit_prep.pl b/contrib/commit_prep.pl deleted file mode 100644 index b3f7e9aa9f9648b055c6c6b39f5e43d65151c2fc..0000000000000000000000000000000000000000 --- a/contrib/commit_prep.pl +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/local/bin/perl -w -# -# -# 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_accumulate script. For new file, it forcing 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. -# -# Contributed by David Hampton <hampton@cisco.com> -# - -############################################################ -# -# Configurable options -# -############################################################ -# -# Check each file (except dot files) for an RCS "Id" keyword. -# -$check_id = 1; - -# -# Record the directory for later use by the log_accumulate stript. -# -$record_directory = 1; - -############################################################ -# -# Constants -# -############################################################ -$LAST_FILE = "/tmp/#cvs.lastdir"; -$ENTRIES = "CVS/Entries"; - -$NoId = " -%s - Does not contain a line with the keyword \"Id:\". - Please see the template files for an example.\n"; - -# Protect string from substitution by RCS. -$NoName = " -%s - The ID line should contain only \"\$\I\d\:\ \$\" 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.\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) || die("Cannot open $filename, stopped"); - for ($i = 1; $i < 10; $i++) { - $pos = -1; - last if eof(FILE); - $line = <FILE>; - $pos = index($line, "Id: "); - last if ($pos >= 0); - } - - if ($pos == -1) { - printf($NoId, $filename); - return(1); - } - - ($id, $rname, $version) = split(' ', substr($line, $pos)); - if ($cvsversion{$filename} == 0) { - if ($rname ne "\$") { - printf($NoName, $filename); - return(1); - } - return(0); - } - - if ($rname ne "$filename,v") { - printf($BadName, $filename, substr($rname, 0, length($rname)-2)); - return(1); - } - if ($cvsversion{$filename} < $version) { - printf($BadVersion, $filename, $filename, $cvsversion{$filename}, - "newer", $version, $filename); - return(1); - } - if ($cvsversion{$filename} > $version) { - printf($BadVersion, $filename, $filename, $cvsversion{$filename}, - "older", $version, $filename); - return(1); - } - return(0); -} - -############################################################# -# -# Main Body -# -############################################################ - -$id = getpgrp(); -#print("ARGV - ", join(":", @ARGV), "\n"); -#print("id - ", id, "\n"); - -# -# Suck in the 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; - $directory = $ARGV[0]; - shift @ARGV; - foreach $arg (@ARGV) { - next if (index($arg, ".") == 0); - $failed += &check_version($arg); - } - if ($failed) { - print "\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/contrib/cvs_acls.pl b/contrib/cvs_acls.pl deleted file mode 100644 index 6722224a1a2e6feb26c6d078e577902a00887cfa..0000000000000000000000000000000000000000 --- a/contrib/cvs_acls.pl +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/perl -- # -*-Perl-*- -# -# $Id: cvs_acls.pl,v 1.1.1.1 1994/12/03 06:09:17 jimb 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/contrib/cvscheck.man b/contrib/cvscheck.man deleted file mode 100644 index 4053b578d05c174502d2ae76ac9084db8bde581e..0000000000000000000000000000000000000000 --- a/contrib/cvscheck.man +++ /dev/null @@ -1,53 +0,0 @@ -.\" $Id: cvscheck.man,v 1.1.1.1 1994/12/03 06:09:17 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/contrib/cvshelp.man b/contrib/cvshelp.man deleted file mode 100644 index 8178740bf38f9c4bc0c304eedd1c159034e784a9..0000000000000000000000000000000000000000 --- a/contrib/cvshelp.man +++ /dev/null @@ -1,562 +0,0 @@ -.\" $Id: cvshelp.man,v 1.1.1.1 1994/12/03 06:09:18 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/contrib/descend.man b/contrib/descend.man deleted file mode 100644 index 5385325f108f59edf23da5c5738659dec1e9a634..0000000000000000000000000000000000000000 --- a/contrib/descend.man +++ /dev/null @@ -1,115 +0,0 @@ -.\" $Id: descend.man,v 1.1.1.1 1994/12/03 06:09:18 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/contrib/log.pl b/contrib/log.pl deleted file mode 100644 index d68cc823a1556dda4e3f6d1a299dcaae8830d9a7..0000000000000000000000000000000000000000 --- a/contrib/log.pl +++ /dev/null @@ -1,148 +0,0 @@ -#! /local/bin/perl - -# Modified by woods@web.apc.org to add support for mailing 3/29/93 -# use '-m user' for each user to receive cvs log reports -# and use '-f logfile' for the logfile to append to -# -# Modified by berliner@Sun.COM to add support for CVS 1.3 2/27/92 -# -# Date: Tue, 6 Aug 91 13:27 EDT -# From: samborn@sunrise.com (Kevin Samborn) -# -# I revised the perl script I sent you yesterday to use the info you -# send in on stdin. (I am appending the newer script to the end) -# -# now the output looks like this: -# -# ************************************** -# Date: Tuesday, August 6, 1991 @ 13:17 -# Author: samborn -# -# Update of /elmer/cvs/CVSROOT.adm -# In directory astro:/home/samborn/CVSROOT.adm -# -# Modified Files: -# test3 -# Added Files: -# test6 -# Removed Files: -# test4 -# Log Message: -# wow, what a test -# -# File: test.3 Status: Up-to-date -# Version: 1.4 Thu Apr 29 14:47:07 EDT 1993 -# File: test6 Status: Up-to-date -# Version: 1.1 Thu Apr 29 14:47:33 EDT 1993 -# File: test4 Status: Up-to-date -# Version: 1.1 Thu Apr 29 14:47:46 EDT 1993 -# - -$cvsroot = $ENV{'CVSROOT'}; - -# turn off setgid -# -$) = $(; - -# 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; - } else { - ($donefiles) && die "Too many arguments!\n"; - $donefiles = 1; - @files = split(/ /, $arg); - } -} - -$srepos = shift @files; -$mailcmd = "| Mail -s 'CVS update: $srepos'"; - -# 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 login name -# -$login = getlogin || (getpwuid($<))[0] || "nobody"; - -# open log file for appending -# -open(OUT, ">>" . $logfile) || die "Could not open(" . $logfile . "): $!\n"; -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 -Qn status' on each file in the arguments. -# -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', '-Qn', 'status', $file; - - while (<RCS>) { - if (/^[ \t]*Version/ || /^File:/) { - print OUT; - if (MAIL) { - print MAIL; - } - } - } - close(RCS); -} - -close(OUT); -die "Write to $logfile failed" if $?; - -close(MAIL); -die "Pipe to $mailcmd failed" if $?; - -exit 0; - -### Local Variables: -### eval: (fundamental-mode) -### End: diff --git a/contrib/log_accum.pl b/contrib/log_accum.pl deleted file mode 100644 index 798e25f1f0e120f5d9f86421c70f1873d57289bd..0000000000000000000000000000000000000000 --- a/contrib/log_accum.pl +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/local/bin/perl -w -# -# 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> -# - -############################################################ -# -# Configurable options -# -############################################################ -# -# Do cisco Systems, Inc. specific nonsense. -# -$cisco_systems = 1; - -# -# Recipient of all mail messages -# -$mailto = "sw-notification@cisco.com"; - -############################################################ -# -# Constants -# -############################################################ -$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"; - -$VERSION_FILE = "version"; -$TRUNKREV_FILE = "TrunkRev"; -$CHANGES_FILE = "Changes"; -$CHANGES_TEMP = "Changes.tmp"; - -############################################################ -# -# Subroutines -# -############################################################ - -sub format_names { - local($dir, @files) = @_; - local(@lines); - $lines[0] = sprintf(" %-08s", $dir); - foreach $file (@files) { - if (length($lines[$#lines]) + length($file) > 60) { - $lines[++$#lines] = sprintf(" %8s", " "); - } - $lines[$#lines] .= " ".$file; - } - @lines; -} - -sub cleanup_tmpfiles { - local($all) = @_; - local($wd, @files); - - $wd = `pwd`; - chdir("/tmp"); - opendir(DIR, "."); - if ($all == 1) { - push(@files, grep(/$id$/, readdir(DIR))); - } else { - push(@files, grep(/^$FILE_PREFIX.*$id$/, readdir(DIR))); - } - closedir(DIR); - foreach (@files) { - unlink $_; - } - 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_file { - local($filename, $dir, @files) = @_; - if (@files) { - local(@lines) = &format_names($dir, @files); - open(FILE, ">>$filename") || die ("Cannot open file $filename.\n"); - print(FILE join("\n", @lines), "\n"); - close(FILE); - } -} - -sub write_line { - local($filename, $line) = @_; - open(FILE, ">$filename") || die("Cannot open file $filename.\n"); - print(FILE $line, "\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_file { - local(@text); - local($filename, $leader) = @_; - open(FILE, "<$filename") || return (); - while (<FILE>) { - chop; - push(@text, sprintf(" %-10s %s", $leader, $_)); - $leader = ""; - } - close(FILE); - @text; -} - -sub read_logfile { - local(@text); - local($filename, $leader) = @_; - open(FILE, "<$filename") || die ("Cannot open log file $filename.\n"); - while (<FILE>) { - chop; - push(@text, $leader.$_); - } - close(FILE); - @text; -} - -sub bump_version { - local($trunkrev, $editnum, $version); - - $trunkrev = &read_line("$ENV{'CVSROOT'}/$repository/$TRUNKREV_FILE"); - $editnum = &read_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE"); - &write_line("$ENV{'CVSROOT'}/$repository/$VERSION_FILE", $editnum+1); - $version = $trunkrev . "(" . $editnum . ")"; -} - -sub build_header { - local($version) = @_; - local($header); - local($sec,$min,$hour,$mday,$mon,$year) = localtime(time); - $header = sprintf("%-8s %s %02d/%02d/%02d %02d:%02d:%02d", - $login, $version, $year%100, $mon+1, $mday, - $hour, $min, $sec); -} - -sub do_changes_file { - local($changes, $tmpchanges); - local(@text) = @_; - - $changes = "$ENV{'CVSROOT'}/$repository/$CHANGES_FILE"; - $tmpchanges = "$ENV{'CVSROOT'}/$repository/$CHANGES_TEMP"; - if (rename($changes, $tmpchanges) != 1) { - die("Cannot rename $changes to $tmpchanges.\n"); - } - open(CHANGES, ">$changes") || die("Cannot open $changes.\n"); - open(TMPCHANGES, "<$tmpchanges") || die("Cannot open $tmpchanges.\n"); - print(CHANGES join("\n", @text), "\n\n"); - print(CHANGES <TMPCHANGES>); - close(CHANGES); - close(TMPCHANGES); - unlink($tmpchanges); -} - -sub mail_notification { - local($name, @text) = @_; - open(MAIL, "| mail -s \"Source Repository Modification\" $name"); - print(MAIL join("\n", @text)); - close(MAIL); -} - -############################################################# -# -# Main Body -# -############################################################ - -# -# Initialize basic variables -# -$id = getpgrp(); -$state = $STATE_NONE; -$login = getlogin || (getpwuid($<))[0] || die("Unknown user $<.\n"); -@files = split(' ', $ARGV[0]); -@path = split('/', $files[0]); -$repository = @path[0]; -if ($#path == 0) { - $dir = "."; -} else { - $dir = join('/', @path[1..$#path]); -} -#print("ARGV - ", join(":", @ARGV), "\n"); -#print("files - ", join(":", @files), "\n"); -#print("path - ", join(":", @path), "\n"); -#print("dir - ", $dir, "\n"); -#print("id - ", $id, "\n"); - -# -# Check for a new directory first. This will always appear as a -# single item in the argument list, and an empty log message. -# -if ($ARGV[0] =~ /New directory/) { - $version = &bump_version if ($cisco_systems != 0); - $header = &build_header($version); - @text = (); - push(@text, $header); - push(@text, ""); - push(@text, " ".$ARGV[0]); - &do_changes_file(@text) if ($cisco_systems != 0); - &mail_notification($mailto, @text); - exit 0; -} - -# -# Iterate over the body of the message collecting information. -# -while (<STDIN>) { - chop; # Drop the newline - 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 space - s/[ \t\n]+$//; # delete trailing space - - push (@changed_files, split) if ($state == $STATE_CHANGED); - push (@added_files, split) if ($state == $STATE_ADDED); - push (@removed_files, split) if ($state == $STATE_REMOVED); - push (@log_lines, $_) if ($state == $STATE_LOG); -} - -# -# 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); - } -} - -# -# Find the log file that matches this log message -# -for ($i = 0; ; $i++) { - last if (! -e "$LOG_FILE.$i.$id"); - @text = &read_logfile("$LOG_FILE.$i.$id", ""); - last if ($#text == -1); - last if (join(" ", @log_lines) eq join(" ", @text)); -} - -# -# Spit out the information gathered in this pass. -# -&write_logfile("$LOG_FILE.$i.$id", @log_lines); -&append_to_file("$ADDED_FILE.$i.$id", $dir, @added_files); -&append_to_file("$CHANGED_FILE.$i.$id", $dir, @changed_files); -&append_to_file("$REMOVED_FILE.$i.$id", $dir, @removed_files); - -# -# Check whether this is the last directory. If not, quit. -# -$_ = &read_line("$LAST_FILE.$id"); -exit 0 if (! grep(/$files[0]$/, $_)); - -# -# 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. -# -# Get the full version number -# -$version = &bump_version if ($cisco_systems != 0); -$header = &build_header($version); - -# -# Produce the final compilation of the log messages -# -@text = (); -push(@text, $header); -push(@text, ""); -for ($i = 0; ; $i++) { - last if (! -e "$LOG_FILE.$i.$id"); - push(@text, &read_file("$CHANGED_FILE.$i.$id", "Modified:")); - push(@text, &read_file("$ADDED_FILE.$i.$id", "Added:")); - push(@text, &read_file("$REMOVED_FILE.$i.$id", "Removed:")); - push(@text, " Log:"); - push(@text, &read_logfile("$LOG_FILE.$i.$id", " ")); - push(@text, ""); -} -if ($cisco_systems != 0) { - @ddts = grep(/^CSCdi/, split(' ', join(" ", @text))); - $text[0] .= " " . join(" ", @ddts); -} -# -# Put the log message at the beginning of the Changes file and mail -# out the notification. -# -&do_changes_file(@text) if ($cisco_systems != 0); -&mail_notification($mailto, @text); -&cleanup_tmpfiles(1); -exit 0; diff --git a/contrib/mfpipe.pl b/contrib/mfpipe.pl deleted file mode 100644 index 213b1482c94dc738777891ffe6f5357c8b211287..0000000000000000000000000000000000000000 --- a/contrib/mfpipe.pl +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/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.1.1.1 1994/12/03 06:09:19 jimb 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/contrib/pcl-cvs/.cvsignore b/contrib/pcl-cvs/.cvsignore deleted file mode 100644 index dbaa4e2c36d486253ddc3529d83325c73bcbdb6a..0000000000000000000000000000000000000000 --- a/contrib/pcl-cvs/.cvsignore +++ /dev/null @@ -1,16 +0,0 @@ -pcl-cvs.aux -pcl-cvs.cp -pcl-cvs.cps -pcl-cvs.dvi -pcl-cvs.fn -pcl-cvs.fns -pcl-cvs.ky -pcl-cvs.kys -pcl-cvs.log -pcl-cvs.pg -pcl-cvs.pgs -pcl-cvs.toc -pcl-cvs.tp -pcl-cvs.tps -pcl-cvs.vr -pcl-cvs.vrs diff --git a/contrib/pcl-cvs/ChangeLog b/contrib/pcl-cvs/ChangeLog deleted file mode 100644 index 7dc1c0efb0b6d69ea1ee11de545c5084634401cf..0000000000000000000000000000000000000000 --- a/contrib/pcl-cvs/ChangeLog +++ /dev/null @@ -1,700 +0,0 @@ -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. - - * pcl-cvs.el, Makefile: - * 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/contrib/pcl-cvs/INSTALL b/contrib/pcl-cvs/INSTALL deleted file mode 100644 index f3c4480d56f4a0f1bfb0cecdd15356ab9c9fe5bd..0000000000000000000000000000000000000000 --- a/contrib/pcl-cvs/INSTALL +++ /dev/null @@ -1,86 +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. Create the info file `pcl-cvs' 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), or you could use the preformatted - info file `pcl-cvs.info' that is included in the distribution - (type `cp pcl-cvs.info pcl-cvs'). - - 2. Move the info file `pcl-cvs' to your standard info directory. - This might be called something like `/usr/gnu/emacs/info'. - - 3. Edit the file `dir' in the info directory and enter one line to - contain a pointer to the info file `pcl-cvs'. The line can, for - instance, look like this: - - * Pcl-cvs: (pcl-cvs). An Emacs front-end to CVS. - - -How to make typeset documentation from pcl-cvs.texinfo -====================================================== - - If you have TeX installed at your site, you can make a typeset -manual from `pcl-cvs.texinfo'. - - 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/contrib/pcl-cvs/NEWS b/contrib/pcl-cvs/NEWS deleted file mode 100644 index 4f563ffc5019815a5f423fbfcc1f48a6dc136278..0000000000000000000000000000000000000000 --- a/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/contrib/pcl-cvs/README b/contrib/pcl-cvs/README deleted file mode 100644 index 779617fd5fd65f9a947df1a8cb1277f0bb9548ef..0000000000000000000000000000000000000000 --- a/contrib/pcl-cvs/README +++ /dev/null @@ -1,28 +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.10 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. We are -trying to find a solution to that problem. In the mean time, there is -instructions in Elib 0.07 for how to work around the problem. - - Per Cederqvist diff --git a/contrib/pcl-cvs/compile-all.el b/contrib/pcl-cvs/compile-all.el deleted file mode 100644 index 656327750859365d37887f081ae82f519cfd1013..0000000000000000000000000000000000000000 --- a/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/contrib/pcl-cvs/pcl-cvs-lucid.el b/contrib/pcl-cvs/pcl-cvs-lucid.el deleted file mode 100644 index d1f69e313d4aa9d93587e66b365738c5857f7b89..0000000000000000000000000000000000000000 --- a/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/contrib/pcl-cvs/pcl-cvs-startup.el b/contrib/pcl-cvs/pcl-cvs-startup.el deleted file mode 100644 index f9b2de0418a4bee1b48254c53db3674d2a97a9ef..0000000000000000000000000000000000000000 --- a/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/contrib/pcl-cvs/pcl-cvs.el b/contrib/pcl-cvs/pcl-cvs.el deleted file mode 100644 index ef7bd2375606883e4ff903251f8ad4b26ec440c8..0000000000000000000000000000000000000000 --- a/contrib/pcl-cvs/pcl-cvs.el +++ /dev/null @@ -1,2229 +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 "/usr/local/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-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 Cygnus's Remote 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 Cygnus's Remote 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 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\\|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 Cygnus remote 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 "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))) diff --git a/contrib/pcl-cvs/pcl-cvs.texinfo b/contrib/pcl-cvs/pcl-cvs.texinfo deleted file mode 100644 index 0b51f778a4dd083281fd0260964cdce3603da14e..0000000000000000000000000000000000000000 --- a/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 -@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/contrib/pcl-cvs/texinfo.tex b/contrib/pcl-cvs/texinfo.tex deleted file mode 100644 index de11a7ffca0098b5d71fe01da2b21aa3d6143f34..0000000000000000000000000000000000000000 --- a/contrib/pcl-cvs/texinfo.tex +++ /dev/null @@ -1,4381 +0,0 @@ -%% TeX macros to handle texinfo files - -% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 Free Software Foundation, Inc. - -%This texinfo.tex file 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 texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write -%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, -%USA. - - -%In other words, you are welcome to use, share and improve this program. -%You are forbidden to forbid anyone else to use, share and improve -%what you give them. Help stamp out software-hoarding! - -% This automatically updates the version number based on RCS. -\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} -\deftexinfoversion$fixed-revision: 2.137 $ -\message{Loading texinfo package [Version \texinfoversion]:} - -% Print the version number if in a .fmt file. -\everyjob{\message{[Texinfo version \texinfoversion]}\message{}} - -% Save some parts of plain tex whose names we will redefine. - -\let\ptextilde=\~ -\let\ptexlbrace=\{ -\let\ptexrbrace=\} -\let\ptexdots=\dots -\let\ptexdot=\. -\let\ptexstar=\* -\let\ptexend=\end -\let\ptexbullet=\bullet -\let\ptexb=\b -\let\ptexc=\c -\let\ptexi=\i -\let\ptext=\t -\let\ptexl=\l -\let\ptexL=\L - -% Be sure we're in horizontal mode when doing a tie, since we make space -% equivalent to this in @example-like environments. Otherwise, a space -% at the beginning of a line will start with \penalty -- and -% since \penalty is valid in vertical mode, we'd end up putting the -% penalty on the vertical list instead of in the new paragraph. -{\catcode`@ = 11 - \gdef\tie{\leavevmode\penalty\@M\ } -} -\let\~ = \tie % And make it available as @~. - -\message{Basics,} -\chardef\other=12 - -% If this character appears in an error message or help string, it -% starts a new line in the output. -\newlinechar = `^^J - -% Set up fixed words for English. -\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% -\def\putwordInfo{Info}% -\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% -\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% -\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% -\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% -\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% -\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% -\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% -\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% -\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% - -% Ignore a token. -% -\def\gobble#1{} - -\hyphenation{ap-pen-dix} -\hyphenation{mini-buf-fer mini-buf-fers} -\hyphenation{eshell} - -% Margin to add to right of even pages, to left of odd pages. -\newdimen \bindingoffset \bindingoffset=0pt -\newdimen \normaloffset \normaloffset=\hoffset -\newdimen\pagewidth \newdimen\pageheight -\pagewidth=\hsize \pageheight=\vsize - -% Sometimes it is convenient to have everything in the transcript file -% and nothing on the terminal. We don't just call \tracingall here, -% since that produces some useless output on the terminal. -% -\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% -\def\loggingall{\tracingcommands2 \tracingstats2 - \tracingpages1 \tracingoutput1 \tracinglostchars1 - \tracingmacros2 \tracingparagraphs1 \tracingrestores1 - \showboxbreadth\maxdimen\showboxdepth\maxdimen -}% - -%---------------------Begin change----------------------- -% -%%%% For @cropmarks command. -% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 -% -\newdimen\cornerlong \newdimen\cornerthick -\newdimen \topandbottommargin -\newdimen \outerhsize \newdimen \outervsize -\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks -\outerhsize=7in -%\outervsize=9.5in -% Alternative @smallbook page size is 9.25in -\outervsize=9.25in -\topandbottommargin=.75in -% -%---------------------End change----------------------- - -% \onepageout takes a vbox as an argument. Note that \pagecontents -% does insertions itself, but you have to call it yourself. -\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} -\def\onepageout#1{\hoffset=\normaloffset -\ifodd\pageno \advance\hoffset by \bindingoffset -\else \advance\hoffset by -\bindingoffset\fi -{\escapechar=`\\\relax % makes sure backslash is used in output files. -\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}% -{\let\hsize=\pagewidth \makefootline}}}% -\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} - -%%%% For @cropmarks command %%%% - -% Here is a modification of the main output routine for Near East Publications -% This provides right-angle cropmarks at all four corners. -% The contents of the page are centerlined into the cropmarks, -% and any desired binding offset is added as an \hskip on either -% site of the centerlined box. (P. A. MacKay, 12 November, 1986) -% -\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up -{\escapechar=`\\\relax % makes sure backslash is used in output files. - \shipout - \vbox to \outervsize{\hsize=\outerhsize - \vbox{\line{\ewtop\hfill\ewtop}} - \nointerlineskip - \line{\vbox{\moveleft\cornerthick\nstop} - \hfill - \vbox{\moveright\cornerthick\nstop}} - \vskip \topandbottommargin - \centerline{\ifodd\pageno\hskip\bindingoffset\fi - \vbox{ - {\let\hsize=\pagewidth \makeheadline} - \pagebody{#1} - {\let\hsize=\pagewidth \makefootline}} - \ifodd\pageno\else\hskip\bindingoffset\fi} - \vskip \topandbottommargin plus1fill minus1fill - \boxmaxdepth\cornerthick - \line{\vbox{\moveleft\cornerthick\nsbot} - \hfill - \vbox{\moveright\cornerthick\nsbot}} - \nointerlineskip - \vbox{\line{\ewbot\hfill\ewbot}} - }} - \advancepageno - \ifnum\outputpenalty>-20000 \else\dosupereject\fi} -% -% Do @cropmarks to get crop marks -\def\cropmarks{\let\onepageout=\croppageout } - -\newinsert\margin \dimen\margin=\maxdimen - -\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} -{\catcode`\@ =11 -\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi -% marginal hacks, juha@viisa.uucp (Juha Takala) -\ifvoid\margin\else % marginal info is present - \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi -\dimen@=\dp#1 \unvbox#1 -\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi -\ifr@ggedbottom \kern-\dimen@ \vfil \fi} -} - -% -% Here are the rules for the cropmarks. Note that they are -% offset so that the space between them is truly \outerhsize or \outervsize -% (P. A. MacKay, 12 November, 1986) -% -\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} -\def\nstop{\vbox - {\hrule height\cornerthick depth\cornerlong width\cornerthick}} -\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} -\def\nsbot{\vbox - {\hrule height\cornerlong depth\cornerthick width\cornerthick}} - -% Parse an argument, then pass it to #1. The argument is the rest of -% the input line (except we remove a trailing comment). #1 should be a -% macro which expects an ordinary undelimited TeX argument. -% -\def\parsearg#1{% - \let\next = #1% - \begingroup - \obeylines - \futurelet\temp\parseargx -} - -% If the next token is an obeyed space (from an @example environment or -% the like), remove it and recurse. Otherwise, we're done. -\def\parseargx{% - % \obeyedspace is defined far below, after the definition of \sepspaces. - \ifx\obeyedspace\temp - \expandafter\parseargdiscardspace - \else - \expandafter\parseargline - \fi -} - -% Remove a single space (as the delimiter token to the macro call). -{\obeyspaces % - \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} - -{\obeylines % - \gdef\parseargline#1^^M{% - \endgroup % End of the group started in \parsearg. - % - % First remove any @c comment, then any @comment. - % Result of each macro is put in \toks0. - \argremovec #1\c\relax % - \expandafter\argremovecomment \the\toks0 \comment\relax % - % - % Call the caller's macro, saved as \next in \parsearg. - \expandafter\next\expandafter{\the\toks0}% - }% -} - -% Since all \c{,omment} does is throw away the argument, we can let TeX -% do that for us. The \relax here is matched by the \relax in the call -% in \parseargline; it could be more or less anything, its purpose is -% just to delimit the argument to the \c. -\def\argremovec#1\c#2\relax{\toks0 = {#1}} -\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} - -% \argremovec{,omment} might leave us with trailing spaces, though; e.g., -% @end itemize @c foo -% will have two active spaces as part of the argument with the -% `itemize'. Here we remove all active spaces from #1, and assign the -% result to \toks0. -% -% This loses if there are any *other* active characters besides spaces -% in the argument -- _ ^ +, for example -- since they get expanded. -% Fortunately, Texinfo does not define any such commands. (If it ever -% does, the catcode of the characters in questionwill have to be changed -% here.) But this means we cannot call \removeactivespaces as part of -% \argremovec{,omment}, since @c uses \parsearg, and thus the argument -% that \parsearg gets might well have any character at all in it. -% -\def\removeactivespaces#1{% - \begingroup - \ignoreactivespaces - \edef\temp{#1}% - \global\toks0 = \expandafter{\temp}% - \endgroup -} - -% Change the active space to expand to nothing. -% -\begingroup - \obeyspaces - \gdef\ignoreactivespaces{\obeyspaces\let =\empty} -\endgroup - - -\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} - -%% These are used to keep @begin/@end levels from running away -%% Call \inENV within environments (after a \begingroup) -\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} -\def\ENVcheck{% -\ifENV\errmessage{Still within an environment. Type Return to continue.} -\endgroup\fi} % This is not perfect, but it should reduce lossage - -% @begin foo is the same as @foo, for now. -\newhelp\EMsimple{Type <Return> to continue.} - -\outer\def\begin{\parsearg\beginxxx} - -\def\beginxxx #1{% -\expandafter\ifx\csname #1\endcsname\relax -{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else -\csname #1\endcsname\fi} - -% @end foo executes the definition of \Efoo. -% -\def\end{\parsearg\endxxx} -\def\endxxx #1{% - \removeactivespaces{#1}% - \edef\endthing{\the\toks0}% - % - \expandafter\ifx\csname E\endthing\endcsname\relax - \expandafter\ifx\csname \endthing\endcsname\relax - % There's no \foo, i.e., no ``environment'' foo. - \errhelp = \EMsimple - \errmessage{Undefined command `@end \endthing'}% - \else - \unmatchedenderror\endthing - \fi - \else - % Everything's ok; the right environment has been started. - \csname E\endthing\endcsname - \fi -} - -% There is an environment #1, but it hasn't been started. Give an error. -% -\def\unmatchedenderror#1{% - \errhelp = \EMsimple - \errmessage{This `@end #1' doesn't have a matching `@#1'}% -} - -% Define the control sequence \E#1 to give an unmatched @end error. -% -\def\defineunmatchedend#1{% - \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% -} - - -% Single-spacing is done by various environments (specifically, in -% \nonfillstart and \quotations). -\newskip\singlespaceskip \singlespaceskip = 12.5pt -\def\singlespace{% - % Why was this kern here? It messes up equalizing space above and below - % environments. --karl, 6may93 - %{\advance \baselineskip by -\singlespaceskip - %\kern \baselineskip}% - \setleading \singlespaceskip -} - -%% Simple single-character @ commands - -% @@ prints an @ -% Kludge this until the fonts are right (grr). -\def\@{{\tt \char '100}} - -% This is turned off because it was never documented -% and you can use @w{...} around a quote to suppress ligatures. -%% Define @` and @' to be the same as ` and ' -%% but suppressing ligatures. -%\def\`{{`}} -%\def\'{{'}} - -% Used to generate quoted braces. - -\def\mylbrace {{\tt \char '173}} -\def\myrbrace {{\tt \char '175}} -\let\{=\mylbrace -\let\}=\myrbrace - -% @: forces normal size whitespace following. -\def\:{\spacefactor=1000 } - -% @* forces a line break. -\def\*{\hfil\break\hbox{}\ignorespaces} - -% @. is an end-of-sentence period. -\def\.{.\spacefactor=3000 } - -% @enddots{} is an end-of-sentence ellipsis. -\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} - -% @! is an end-of-sentence bang. -\gdef\!{!\spacefactor=3000 } - -% @? is an end-of-sentence query. -\gdef\?{?\spacefactor=3000 } - -% @w prevents a word break. Without the \leavevmode, @w at the -% beginning of a paragraph, when TeX is still in vertical mode, would -% produce a whole line of output instead of starting the paragraph. -\def\w#1{\leavevmode\hbox{#1}} - -% @group ... @end group forces ... to be all on one page, by enclosing -% it in a TeX vbox. We use \vtop instead of \vbox to construct the box -% to keep its height that of a normal line. According to the rules for -% \topskip (p.114 of the TeXbook), the glue inserted is -% max (\topskip - \ht (first item), 0). If that height is large, -% therefore, no glue is inserted, and the space between the headline and -% the text is small, which looks bad. -% -\def\group{\begingroup - \ifnum\catcode13=\active \else - \errhelp = \groupinvalidhelp - \errmessage{@group invalid in context where filling is enabled}% - \fi - % - % The \vtop we start below produces a box with normal height and large - % depth; thus, TeX puts \baselineskip glue before it, and (when the - % next line of text is done) \lineskip glue after it. (See p.82 of - % the TeXbook.) Thus, space below is not quite equal to space - % above. But it's pretty close. - \def\Egroup{% - \egroup % End the \vtop. - \endgroup % End the \group. - }% - % - \vtop\bgroup - % We have to put a strut on the last line in case the @group is in - % the midst of an example, rather than completely enclosing it. - % Otherwise, the interline space between the last line of the group - % and the first line afterwards is too small. But we can't put the - % strut in \Egroup, since there it would be on a line by itself. - % Hence this just inserts a strut at the beginning of each line. - \everypar = {\strut}% - % - % Since we have a strut on every line, we don't need any of TeX's - % normal interline spacing. - \offinterlineskip - % - % OK, but now we have to do something about blank - % lines in the input in @example-like environments, which normally - % just turn into \lisppar, which will insert no space now that we've - % turned off the interline space. Simplest is to make them be an - % empty paragraph. - \ifx\par\lisppar - \edef\par{\leavevmode \par}% - % - % Reset ^^M's definition to new definition of \par. - \obeylines - \fi - % - % Do @comment since we are called inside an environment such as - % @example, where each end-of-line in the input causes an - % end-of-line in the output. We don't want the end-of-line after - % the `@group' to put extra space in the output. Since @group - % should appear on a line by itself (according to the Texinfo - % manual), we don't worry about eating any user text. - \comment -} -% -% TeX puts in an \escapechar (i.e., `@') at the beginning of the help -% message, so this ends up printing `@group can only ...'. -% -\newhelp\groupinvalidhelp{% -group can only be used in environments such as @example,^^J% -where each line of input produces a line of output.} - -% @need space-in-mils -% forces a page break if there is not space-in-mils remaining. - -\newdimen\mil \mil=0.001in - -\def\need{\parsearg\needx} - -% Old definition--didn't work. -%\def\needx #1{\par % -%% This method tries to make TeX break the page naturally -%% if the depth of the box does not fit. -%{\baselineskip=0pt% -%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 -%\prevdepth=-1000pt -%}} - -\def\needx#1{% - % Go into vertical mode, so we don't make a big box in the middle of a - % paragraph. - \par - % - % Don't add any leading before our big empty box, but allow a page - % break, since the best break might be right here. - \allowbreak - \nointerlineskip - \vtop to #1\mil{\vfil}% - % - % TeX does not even consider page breaks if a penalty added to the - % main vertical list is 10000 or more. But in order to see if the - % empty box we just added fits on the page, we must make it consider - % page breaks. On the other hand, we don't want to actually break the - % page after the empty box. So we use a penalty of 9999. - % - % There is an extremely small chance that TeX will actually break the - % page at this \penalty, if there are no other feasible breakpoints in - % sight. (If the user is using lots of big @group commands, which - % almost-but-not-quite fill up a page, TeX will have a hard time doing - % good page breaking, for example.) However, I could not construct an - % example where a page broke at this \penalty; if it happens in a real - % document, then we can reconsider our strategy. - \penalty9999 - % - % Back up by the size of the box, whether we did a page break or not. - \kern -#1\mil - % - % Do not allow a page break right after this kern. - \nobreak -} - -% @br forces paragraph break - -\let\br = \par - -% @dots{} output some dots - -\def\dots{$\ldots$} - -% @page forces the start of a new page - -\def\page{\par\vfill\supereject} - -% @exdent text.... -% outputs text on separate line in roman font, starting at standard page margin - -% This records the amount of indent in the innermost environment. -% That's how much \exdent should take out. -\newskip\exdentamount - -% This defn is used inside fill environments such as @defun. -\def\exdent{\parsearg\exdentyyy} -\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} - -% This defn is used inside nofill environments such as @example. -\def\nofillexdent{\parsearg\nofillexdentyyy} -\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount -\leftline{\hskip\leftskip{\rm#1}}}} - -%\hbox{{\rm#1}}\hfil\break}} - -% @include file insert text of that file as input. - -\def\include{\parsearg\includezzz} -%Use \input\thisfile to avoid blank after \input, which may be an active -%char (in which case the blank would become the \input argument). -%The grouping keeps the value of \thisfile correct even when @include -%is nested. -\def\includezzz #1{\begingroup -\def\thisfile{#1}\input\thisfile -\endgroup} - -\def\thisfile{} - -% @center line outputs that line, centered - -\def\center{\parsearg\centerzzz} -\def\centerzzz #1{{\advance\hsize by -\leftskip -\advance\hsize by -\rightskip -\centerline{#1}}} - -% @sp n outputs n lines of vertical space - -\def\sp{\parsearg\spxxx} -\def\spxxx #1{\par \vskip #1\baselineskip} - -% @comment ...line which is ignored... -% @c is the same as @comment -% @ignore ... @end ignore is another way to write a comment - -\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% -\parsearg \commentxxx} - -\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } - -\let\c=\comment - -% Prevent errors for section commands. -% Used in @ignore and in failing conditionals. -\def\ignoresections{% -\let\chapter=\relax -\let\unnumbered=\relax -\let\top=\relax -\let\unnumberedsec=\relax -\let\unnumberedsection=\relax -\let\unnumberedsubsec=\relax -\let\unnumberedsubsection=\relax -\let\unnumberedsubsubsec=\relax -\let\unnumberedsubsubsection=\relax -\let\section=\relax -\let\subsec=\relax -\let\subsubsec=\relax -\let\subsection=\relax -\let\subsubsection=\relax -\let\appendix=\relax -\let\appendixsec=\relax -\let\appendixsection=\relax -\let\appendixsubsec=\relax -\let\appendixsubsection=\relax -\let\appendixsubsubsec=\relax -\let\appendixsubsubsection=\relax -\let\contents=\relax -\let\smallbook=\relax -\let\titlepage=\relax -} - -% Used in nested conditionals, where we have to parse the Texinfo source -% and so want to turn off most commands, in case they are used -% incorrectly. -% -\def\ignoremorecommands{% - \let\defcv = \relax - \let\deffn = \relax - \let\deffnx = \relax - \let\defindex = \relax - \let\defivar = \relax - \let\defmac = \relax - \let\defmethod = \relax - \let\defop = \relax - \let\defopt = \relax - \let\defspec = \relax - \let\deftp = \relax - \let\deftypefn = \relax - \let\deftypefun = \relax - \let\deftypevar = \relax - \let\deftypevr = \relax - \let\defun = \relax - \let\defvar = \relax - \let\defvr = \relax - \let\ref = \relax - \let\xref = \relax - \let\printindex = \relax - \let\pxref = \relax - \let\settitle = \relax - \let\include = \relax - \let\lowersections = \relax - \let\down = \relax - \let\raisesections = \relax - \let\up = \relax - \let\set = \relax - \let\clear = \relax - \let\item = \relax - \let\message = \relax -} - -% Ignore @ignore ... @end ignore. -% -\def\ignore{\doignore{ignore}} - -% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. -% -\def\ifinfo{\doignore{ifinfo}} -\def\ifhtml{\doignore{ifhtml}} -\def\html{\doignore{html}} -\def\menu{\doignore{menu}} -\def\direntry{\doignore{direntry}} - -% Ignore text until a line `@end #1'. -% -\def\doignore#1{\begingroup - % Don't complain about control sequences we have declared \outer. - \ignoresections - % - % Define a command to swallow text until we reach `@end #1'. - \long\def\doignoretext##1\end #1{\enddoignore}% - % - % Make sure that spaces turn into tokens that match what \doignoretext wants. - \catcode32 = 10 - % - % And now expand that command. - \doignoretext -} - -% What we do to finish off ignored text. -% -\def\enddoignore{\endgroup\ignorespaces}% - -\newif\ifwarnedobs\warnedobsfalse -\def\obstexwarn{% - \ifwarnedobs\relax\else - % We need to warn folks that they may have trouble with TeX 3.0. - % This uses \immediate\write16 rather than \message to get newlines. - \immediate\write16{} - \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} - \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} - \immediate\write16{If you are running another version of TeX, relax.} - \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} - \immediate\write16{ Then upgrade your TeX installation if you can.} - \immediate\write16{If you are stuck with version 3.0, run the} - \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} - \immediate\write16{ to use a workaround.} - \immediate\write16{} - \warnedobstrue - \fi -} - -% **In TeX 3.0, setting text in \nullfont hangs tex. For a -% workaround (which requires the file ``dummy.tfm'' to be installed), -% uncomment the following line: -%%%%%\font\nullfont=dummy\let\obstexwarn=\relax - -% Ignore text, except that we keep track of conditional commands for -% purposes of nesting, up to an `@end #1' command. -% -\def\nestedignore#1{% - \obstexwarn - % We must actually expand the ignored text to look for the @end - % command, so that nested ignore constructs work. Thus, we put the - % text into a \vbox and then do nothing with the result. To minimize - % the change of memory overflow, we follow the approach outlined on - % page 401 of the TeXbook: make the current font be a dummy font. - % - \setbox0 = \vbox\bgroup - % Don't complain about control sequences we have declared \outer. - \ignoresections - % - % Define `@end #1' to end the box, which will in turn undefine the - % @end command again. - \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% - % - % We are going to be parsing Texinfo commands. Most cause no - % trouble when they are used incorrectly, but some commands do - % complicated argument parsing or otherwise get confused, so we - % undefine them. - % - % We can't do anything about stray @-signs, unfortunately; - % they'll produce `undefined control sequence' errors. - \ignoremorecommands - % - % Set the current font to be \nullfont, a TeX primitive, and define - % all the font commands to also use \nullfont. We don't use - % dummy.tfm, as suggested in the TeXbook, because not all sites - % might have that installed. Therefore, math mode will still - % produce output, but that should be an extremely small amount of - % stuff compared to the main input. - % - \nullfont - \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont - \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont - \let\tensf = \nullfont - % Similarly for index fonts (mostly for their use in - % smallexample) - \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont - \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont - \let\indsf = \nullfont - % - % Don't complain when characters are missing from the fonts. - \tracinglostchars = 0 - % - % Don't bother to do space factor calculations. - \frenchspacing - % - % Don't report underfull hboxes. - \hbadness = 10000 - % - % Do minimal line-breaking. - \pretolerance = 10000 - % - % Do not execute instructions in @tex - \def\tex{\doignore{tex}} -} - -% @set VAR sets the variable VAR to an empty value. -% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. -% -% Since we want to separate VAR from REST-OF-LINE (which might be -% empty), we can't just use \parsearg; we have to insert a space of our -% own to delimit the rest of the line, and then take it out again if we -% didn't need it. -% -\def\set{\parsearg\setxxx} -\def\setxxx#1{\setyyy#1 \endsetyyy} -\def\setyyy#1 #2\endsetyyy{% - \def\temp{#2}% - \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty - \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. - \fi -} -\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} - -% @clear VAR clears (i.e., unsets) the variable VAR. -% -\def\clear{\parsearg\clearxxx} -\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} - -% @value{foo} gets the text saved in variable foo. -% -\def\value#1{\expandafter - \ifx\csname SET#1\endcsname\relax - {\{No value for ``#1''\}} - \else \csname SET#1\endcsname \fi} - -% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined -% with @set. -% -\def\ifset{\parsearg\ifsetxxx} -\def\ifsetxxx #1{% - \expandafter\ifx\csname SET#1\endcsname\relax - \expandafter\ifsetfail - \else - \expandafter\ifsetsucceed - \fi -} -\def\ifsetsucceed{\conditionalsucceed{ifset}} -\def\ifsetfail{\nestedignore{ifset}} -\defineunmatchedend{ifset} - -% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been -% defined with @set, or has been undefined with @clear. -% -\def\ifclear{\parsearg\ifclearxxx} -\def\ifclearxxx #1{% - \expandafter\ifx\csname SET#1\endcsname\relax - \expandafter\ifclearsucceed - \else - \expandafter\ifclearfail - \fi -} -\def\ifclearsucceed{\conditionalsucceed{ifclear}} -\def\ifclearfail{\nestedignore{ifclear}} -\defineunmatchedend{ifclear} - -% @iftex always succeeds; we read the text following, through @end -% iftex). But `@end iftex' should be valid only after an @iftex. -% -\def\iftex{\conditionalsucceed{iftex}} -\defineunmatchedend{iftex} - -% We can't just want to start a group at @iftex (for example) and end it -% at @end iftex, since then @set commands inside the conditional have no -% effect (they'd get reverted at the end of the group). So we must -% define \Eiftex to redefine itself to be its previous value. (We can't -% just define it to fail again with an ``unmatched end'' error, since -% the @ifset might be nested.) -% -\def\conditionalsucceed#1{% - \edef\temp{% - % Remember the current value of \E#1. - \let\nece{prevE#1} = \nece{E#1}% - % - % At the `@end #1', redefine \E#1 to be its previous value. - \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% - }% - \temp -} - -% We need to expand lots of \csname's, but we don't want to expand the -% control sequences after we've constructed them. -% -\def\nece#1{\expandafter\noexpand\csname#1\endcsname} - -% @asis just yields its argument. Used with @table, for example. -% -\def\asis#1{#1} - -% @math means output in math mode. -% We don't use $'s directly in the definition of \math because control -% sequences like \math are expanded when the toc file is written. Then, -% we read the toc file back, the $'s will be normal characters (as they -% should be, according to the definition of Texinfo). So we must use a -% control sequence to switch into and out of math mode. -% -% This isn't quite enough for @math to work properly in indices, but it -% seems unlikely it will ever be needed there. -% -\let\implicitmath = $ -\def\math#1{\implicitmath #1\implicitmath} - -% @bullet and @minus need the same treatment as @math, just above. -\def\bullet{\implicitmath\ptexbullet\implicitmath} -\def\minus{\implicitmath-\implicitmath} - -\def\node{\ENVcheck\parsearg\nodezzz} -\def\nodezzz#1{\nodexxx [#1,]} -\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} -\let\nwnode=\node -\let\lastnode=\relax - -\def\donoderef{\ifx\lastnode\relax\else -\expandafter\expandafter\expandafter\setref{\lastnode}\fi -\global\let\lastnode=\relax} - -\def\unnumbnoderef{\ifx\lastnode\relax\else -\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi -\global\let\lastnode=\relax} - -\def\appendixnoderef{\ifx\lastnode\relax\else -\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi -\global\let\lastnode=\relax} - -\let\refill=\relax - -% @setfilename is done at the beginning of every texinfo file. -% So open here the files we need to have open while reading the input. -% This makes it possible to make a .fmt file for texinfo. -\def\setfilename{% - \readauxfile - \opencontents - \openindices - \fixbackslash % Turn off hack to swallow `\input texinfo'. - \global\let\setfilename=\comment % Ignore extra @setfilename cmds. - \comment % Ignore the actual filename. -} - -\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} - -\def\inforef #1{\inforefzzz #1,,,,**} -\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, - node \samp{\ignorespaces#1{}}} - -\message{fonts,} - -% Font-change commands. - -% Texinfo supports the sans serif font style, which plain TeX does not. -% So we set up a \sf analogous to plain's \rm, etc. -\newfam\sffam -\def\sf{\fam=\sffam \tensf} -\let\li = \sf % Sometimes we call it \li, not \sf. - -%% Try out Computer Modern fonts at \magstephalf -\let\mainmagstep=\magstephalf - -% Set the font macro #1 to the font named #2, adding on the -% specified font prefix (normally `cm'). -\def\setfont#1#2{\font#1=\fontprefix#2} - -% Use cm as the default font prefix. -% To specify the font prefix, you must define \fontprefix -% before you read in texinfo.tex. -\ifx\fontprefix\undefined -\def\fontprefix{cm} -\fi - -\ifx\bigger\relax -\let\mainmagstep=\magstep1 -\setfont\textrm{r12} -\setfont\texttt{tt12} -\else -\setfont\textrm{r10 scaled \mainmagstep} -\setfont\texttt{tt10 scaled \mainmagstep} -\fi -% Instead of cmb10, you many want to use cmbx10. -% cmbx10 is a prettier font on its own, but cmb10 -% looks better when embedded in a line with cmr10. -\setfont\textbf{b10 scaled \mainmagstep} -\setfont\textit{ti10 scaled \mainmagstep} -\setfont\textsl{sl10 scaled \mainmagstep} -\setfont\textsf{ss10 scaled \mainmagstep} -\setfont\textsc{csc10 scaled \mainmagstep} -\font\texti=cmmi10 scaled \mainmagstep -\font\textsy=cmsy10 scaled \mainmagstep - -% A few fonts for @defun, etc. -\setfont\defbf{bx10 scaled \magstep1} %was 1314 -\setfont\deftt{tt10 scaled \magstep1} -\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} - -% Fonts for indices and small examples. -% We actually use the slanted font rather than the italic, -% because texinfo normally uses the slanted fonts for that. -% Do not make many font distinctions in general in the index, since they -% aren't very useful. -\setfont\ninett{tt9} -\setfont\indrm{r9} -\setfont\indit{sl9} -\let\indsl=\indit -\let\indtt=\ninett -\let\indsf=\indrm -\let\indbf=\indrm -\let\indsc=\indrm -\font\indi=cmmi9 -\font\indsy=cmsy9 - -% Fonts for headings -\setfont\chaprm{bx12 scaled \magstep2} -\setfont\chapit{ti12 scaled \magstep2} -\setfont\chapsl{sl12 scaled \magstep2} -\setfont\chaptt{tt12 scaled \magstep2} -\setfont\chapsf{ss12 scaled \magstep2} -\let\chapbf=\chaprm -\setfont\chapsc{csc10 scaled\magstep3} -\font\chapi=cmmi12 scaled \magstep2 -\font\chapsy=cmsy10 scaled \magstep3 - -\setfont\secrm{bx12 scaled \magstep1} -\setfont\secit{ti12 scaled \magstep1} -\setfont\secsl{sl12 scaled \magstep1} -\setfont\sectt{tt12 scaled \magstep1} -\setfont\secsf{ss12 scaled \magstep1} -\setfont\secbf{bx12 scaled \magstep1} -\setfont\secsc{csc10 scaled\magstep2} -\font\seci=cmmi12 scaled \magstep1 -\font\secsy=cmsy10 scaled \magstep2 - -% \setfont\ssecrm{bx10 scaled \magstep1} % This size an font looked bad. -% \setfont\ssecit{cmti10 scaled \magstep1} % The letters were too crowded. -% \setfont\ssecsl{sl10 scaled \magstep1} -% \setfont\ssectt{tt10 scaled \magstep1} -% \setfont\ssecsf{ss10 scaled \magstep1} - -%\setfont\ssecrm{b10 scaled 1315} % Note the use of cmb rather than cmbx. -%\setfont\ssecit{ti10 scaled 1315} % Also, the size is a little larger than -%\setfont\ssecsl{sl10 scaled 1315} % being scaled magstep1. -%\setfont\ssectt{tt10 scaled 1315} -%\setfont\ssecsf{ss10 scaled 1315} - -%\let\ssecbf=\ssecrm - -\setfont\ssecrm{bx12 scaled \magstephalf} -\setfont\ssecit{ti12 scaled \magstephalf} -\setfont\ssecsl{sl12 scaled \magstephalf} -\setfont\ssectt{tt12 scaled \magstephalf} -\setfont\ssecsf{ss12 scaled \magstephalf} -\setfont\ssecbf{bx12 scaled \magstephalf} -\setfont\ssecsc{csc10 scaled \magstep1} -\font\sseci=cmmi12 scaled \magstephalf -\font\ssecsy=cmsy10 scaled \magstep1 -% The smallcaps and symbol fonts should actually be scaled \magstep1.5, -% but that is not a standard magnification. - -% Fonts for title page: -\setfont\titlerm{bx12 scaled \magstep3} -\let\authorrm = \secrm - -% In order for the font changes to affect most math symbols and letters, -% we have to define the \textfont of the standard families. Since -% texinfo doesn't allow for producing subscripts and superscripts, we -% don't bother to reset \scriptfont and \scriptscriptfont (which would -% also require loading a lot more fonts). -% -\def\resetmathfonts{% - \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy - \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf - \textfont\ttfam = \tentt \textfont\sffam = \tensf -} - - -% The font-changing commands redefine the meanings of \tenSTYLE, instead -% of just \STYLE. We do this so that font changes will continue to work -% in math mode, where it is the current \fam that is relevant in most -% cases, not the current. Plain TeX does, for example, -% \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need -% to redefine \bf itself. -\def\textfonts{% - \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl - \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc - \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy - \resetmathfonts} -\def\chapfonts{% - \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl - \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc - \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy - \resetmathfonts} -\def\secfonts{% - \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl - \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc - \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy - \resetmathfonts} -\def\subsecfonts{% - \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl - \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc - \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy - \resetmathfonts} -\def\indexfonts{% - \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl - \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc - \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy - \resetmathfonts} - -% Set up the default fonts, so we can use them for creating boxes. -% -\textfonts - -% Count depth in font-changes, for error checks -\newcount\fontdepth \fontdepth=0 - -% Fonts for short table of contents. -\setfont\shortcontrm{r12} -\setfont\shortcontbf{bx12} -\setfont\shortcontsl{sl12} - -%% Add scribe-like font environments, plus @l for inline lisp (usually sans -%% serif) and @ii for TeX italic - -% \smartitalic{ARG} outputs arg in italics, followed by an italic correction -% unless the following character is such as not to need one. -\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} -\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} - -\let\i=\smartitalic -\let\var=\smartitalic -\let\dfn=\smartitalic -\let\emph=\smartitalic -\let\cite=\smartitalic - -\def\b#1{{\bf #1}} -\let\strong=\b - -% We can't just use \exhyphenpenalty, because that only has effect at -% the end of a paragraph. Restore normal hyphenation at the end of the -% group within which \nohyphenation is presumably called. -% -\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} -\def\restorehyphenation{\hyphenchar\font = `- } - -\def\t#1{% - {\tt \nohyphenation \rawbackslash \frenchspacing #1}% - \null -} -\let\ttfont = \t -%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null} -\def\samp #1{`\tclose{#1}'\null} -\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null} -\def\ctrl #1{{\tt \rawbackslash \hat}#1} - -\let\file=\samp - -% @code is a modification of @t, -% which makes spaces the same size as normal in the surrounding text. -\def\tclose#1{% - {% - % Change normal interword space to be same as for the current font. - \spaceskip = \fontdimen2\font - % - % Switch to typewriter. - \tt - % - % But `\ ' produces the large typewriter interword space. - \def\ {{\spaceskip = 0pt{} }}% - % - % Turn off hyphenation. - \nohyphenation - % - \rawbackslash - \frenchspacing - #1% - }% - \null -} - -% We *must* turn on hyphenation at `-' and `_' in \code. -% Otherwise, it is too hard to avoid overful hboxes -% in the Emacs manual, the Library manual, etc. - -% Unfortunately, TeX uses one parameter (\hyphenchar) to control -% both hyphenation at - and hyphenation within words. -% We must therefore turn them both off (\tclose does that) -% and arrange explicitly to hyphenate an a dash. -% -- rms. -{ -\catcode`\-=\active -\catcode`\_=\active -\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} -% The following is used by \doprintindex to insure that long function names -% wrap around. It is necessary for - and _ to be active before the index is -% read from the file, as \entry parses the arguments long before \code is -% ever called. -- mycroft -\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} -} -\def\realdash{-} -\def\realunder{_} -\def\codedash{-\discretionary{}{}{}} -\def\codeunder{\normalunderscore\discretionary{}{}{}} -\def\codex #1{\tclose{#1}\endgroup} - -%\let\exp=\tclose %Was temporary - -% @kbd is like @code, except that if the argument is just one @key command, -% then @kbd has no effect. - -\def\xkey{\key} -\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% -\ifx\one\xkey\ifx\threex\three \key{#2}% -\else\tclose{\look}\fi -\else\tclose{\look}\fi} - -% Typeset a dimension, e.g., `in' or `pt'. The only reason for the -% argument is to make the input look right: @dmn{pt} instead of -% @dmn{}pt. -% -\def\dmn#1{\thinspace #1} - -\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} - -\def\l#1{{\li #1}\null} % - -\def\r#1{{\rm #1}} % roman font -% Use of \lowercase was suggested. -\def\sc#1{{\smallcaps#1}} % smallcaps font -\def\ii#1{{\it #1}} % italic font - -\message{page headings,} - -\newskip\titlepagetopglue \titlepagetopglue = 1.5in -\newskip\titlepagebottomglue \titlepagebottomglue = 2pc - -% First the title page. Must do @settitle before @titlepage. -\def\titlefont#1{{\titlerm #1}} - -\newif\ifseenauthor -\newif\iffinishedtitlepage - -\def\shorttitlepage{\parsearg\shorttitlepagezzz} -\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% - \endgroup\page\hbox{}\page} - -\def\titlepage{\begingroup \parindent=0pt \textfonts - \let\subtitlerm=\tenrm -% I deinstalled the following change because \cmr12 is undefined. -% This change was not in the ChangeLog anyway. --rms. -% \let\subtitlerm=\cmr12 - \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% - % - \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% - % - % Leave some space at the very top of the page. - \vglue\titlepagetopglue - % - % Now you can print the title using @title. - \def\title{\parsearg\titlezzz}% - \def\titlezzz##1{\leftline{\titlefont{##1}} - % print a rule at the page bottom also. - \finishedtitlepagefalse - \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% - % No rule at page bottom unless we print one at the top with @title. - \finishedtitlepagetrue - % - % Now you can put text using @subtitle. - \def\subtitle{\parsearg\subtitlezzz}% - \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% - % - % @author should come last, but may come many times. - \def\author{\parsearg\authorzzz}% - \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi - {\authorfont \leftline{##1}}}% - % - % Most title ``pages'' are actually two pages long, with space - % at the top of the second. We don't want the ragged left on the second. - \let\oldpage = \page - \def\page{% - \iffinishedtitlepage\else - \finishtitlepage - \fi - \oldpage - \let\page = \oldpage - \hbox{}}% -% \def\page{\oldpage \hbox{}} -} - -\def\Etitlepage{% - \iffinishedtitlepage\else - \finishtitlepage - \fi - % It is important to do the page break before ending the group, - % because the headline and footline are only empty inside the group. - % If we use the new definition of \page, we always get a blank page - % after the title page, which we certainly don't want. - \oldpage - \endgroup - \HEADINGSon -} - -\def\finishtitlepage{% - \vskip4pt \hrule height 2pt width \hsize - \vskip\titlepagebottomglue - \finishedtitlepagetrue -} - -%%% Set up page headings and footings. - -\let\thispage=\folio - -\newtoks \evenheadline % Token sequence for heading line of even pages -\newtoks \oddheadline % Token sequence for heading line of odd pages -\newtoks \evenfootline % Token sequence for footing line of even pages -\newtoks \oddfootline % Token sequence for footing line of odd pages - -% Now make Tex use those variables -\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline - \else \the\evenheadline \fi}} -\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline - \else \the\evenfootline \fi}\HEADINGShook} -\let\HEADINGShook=\relax - -% Commands to set those variables. -% For example, this is what @headings on does -% @evenheading @thistitle|@thispage|@thischapter -% @oddheading @thischapter|@thispage|@thistitle -% @evenfooting @thisfile|| -% @oddfooting ||@thisfile - -\def\evenheading{\parsearg\evenheadingxxx} -\def\oddheading{\parsearg\oddheadingxxx} -\def\everyheading{\parsearg\everyheadingxxx} - -\def\evenfooting{\parsearg\evenfootingxxx} -\def\oddfooting{\parsearg\oddfootingxxx} -\def\everyfooting{\parsearg\everyfootingxxx} - -{\catcode`\@=0 % - -\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} -\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% -\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} - -\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} -\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% -\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} - -\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} -\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% -\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} -\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} - -\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} -\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% -\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} - -\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} -\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% -\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} - -\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} -\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% -\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} -\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} -% -}% unbind the catcode of @. - -% @headings double turns headings on for double-sided printing. -% @headings single turns headings on for single-sided printing. -% @headings off turns them off. -% @headings on same as @headings double, retained for compatibility. -% @headings after turns on double-sided headings after this page. -% @headings doubleafter turns on double-sided headings after this page. -% @headings singleafter turns on single-sided headings after this page. -% By default, they are off. - -\def\headings #1 {\csname HEADINGS#1\endcsname} - -\def\HEADINGSoff{ -\global\evenheadline={\hfil} \global\evenfootline={\hfil} -\global\oddheadline={\hfil} \global\oddfootline={\hfil}} -\HEADINGSoff -% When we turn headings on, set the page number to 1. -% For double-sided printing, put current file name in lower left corner, -% chapter name on inside top of right hand pages, document -% title on inside top of left hand pages, and page numbers on outside top -% edge of all pages. -\def\HEADINGSdouble{ -%\pagealignmacro -\global\pageno=1 -\global\evenfootline={\hfil} -\global\oddfootline={\hfil} -\global\evenheadline={\line{\folio\hfil\thistitle}} -\global\oddheadline={\line{\thischapter\hfil\folio}} -} -% For single-sided printing, chapter title goes across top left of page, -% page number on top right. -\def\HEADINGSsingle{ -%\pagealignmacro -\global\pageno=1 -\global\evenfootline={\hfil} -\global\oddfootline={\hfil} -\global\evenheadline={\line{\thischapter\hfil\folio}} -\global\oddheadline={\line{\thischapter\hfil\folio}} -} -\def\HEADINGSon{\HEADINGSdouble} - -\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} -\let\HEADINGSdoubleafter=\HEADINGSafter -\def\HEADINGSdoublex{% -\global\evenfootline={\hfil} -\global\oddfootline={\hfil} -\global\evenheadline={\line{\folio\hfil\thistitle}} -\global\oddheadline={\line{\thischapter\hfil\folio}} -} - -\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} -\def\HEADINGSsinglex{% -\global\evenfootline={\hfil} -\global\oddfootline={\hfil} -\global\evenheadline={\line{\thischapter\hfil\folio}} -\global\oddheadline={\line{\thischapter\hfil\folio}} -} - -% Subroutines used in generating headings -% Produces Day Month Year style of output. -\def\today{\number\day\space -\ifcase\month\or -January\or February\or March\or April\or May\or June\or -July\or August\or September\or October\or November\or December\fi -\space\number\year} - -% Use this if you want the Month Day, Year style of output. -%\def\today{\ifcase\month\or -%January\or February\or March\or April\or May\or June\or -%July\or August\or September\or October\or November\or December\fi -%\space\number\day, \number\year} - -% @settitle line... specifies the title of the document, for headings -% It generates no output of its own - -\def\thistitle{No Title} -\def\settitle{\parsearg\settitlezzz} -\def\settitlezzz #1{\gdef\thistitle{#1}} - -\message{tables,} - -% @tabs -- simple alignment - -% These don't work. For one thing, \+ is defined as outer. -% So these macros cannot even be defined. - -%\def\tabs{\parsearg\tabszzz} -%\def\tabszzz #1{\settabs\+#1\cr} -%\def\tabline{\parsearg\tablinezzz} -%\def\tablinezzz #1{\+#1\cr} -%\def\&{&} - -% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). - -% default indentation of table text -\newdimen\tableindent \tableindent=.8in -% default indentation of @itemize and @enumerate text -\newdimen\itemindent \itemindent=.3in -% margin between end of table item and start of table text. -\newdimen\itemmargin \itemmargin=.1in - -% used internally for \itemindent minus \itemmargin -\newdimen\itemmax - -% Note @table, @vtable, and @vtable define @item, @itemx, etc., with -% these defs. -% They also define \itemindex -% to index the item name in whatever manner is desired (perhaps none). - -\newif\ifitemxneedsnegativevskip - -\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi} - -\def\internalBitem{\smallbreak \parsearg\itemzzz} -\def\internalBitemx{\itemxpar \parsearg\itemzzz} - -\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} -\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} - -\def\internalBkitem{\smallbreak \parsearg\kitemzzz} -\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} - -\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% - \itemzzz {#1}} - -\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% - \itemzzz {#1}} - -\def\itemzzz #1{\begingroup % - \advance\hsize by -\rightskip - \advance\hsize by -\tableindent - \setbox0=\hbox{\itemfont{#1}}% - \itemindex{#1}% - \nobreak % This prevents a break before @itemx. - % - % Be sure we are not still in the middle of a paragraph. - %{\parskip = 0in - %\par - %}% - % - % If the item text does not fit in the space we have, put it on a line - % by itself, and do not allow a page break either before or after that - % line. We do not start a paragraph here because then if the next - % command is, e.g., @kindex, the whatsit would get put into the - % horizontal list on a line by itself, resulting in extra blank space. - \ifdim \wd0>\itemmax - % - % Make this a paragraph so we get the \parskip glue and wrapping, - % but leave it ragged-right. - \begingroup - \advance\leftskip by-\tableindent - \advance\hsize by\tableindent - \advance\rightskip by0pt plus1fil - \leavevmode\unhbox0\par - \endgroup - % - % We're going to be starting a paragraph, but we don't want the - % \parskip glue -- logically it's part of the @item we just started. - \nobreak \vskip-\parskip - % - % Stop a page break at the \parskip glue coming up. Unfortunately - % we can't prevent a possible page break at the following - % \baselineskip glue. - \nobreak - \endgroup - \itemxneedsnegativevskipfalse - \else - % The item text fits into the space. Start a paragraph, so that the - % following text (if any) will end up on the same line. Since that - % text will be indented by \tableindent, we make the item text be in - % a zero-width box. - \noindent - \rlap{\hskip -\tableindent\box0}\ignorespaces% - \endgroup% - \itemxneedsnegativevskiptrue% - \fi -} - -\def\item{\errmessage{@item while not in a table}} -\def\itemx{\errmessage{@itemx while not in a table}} -\def\kitem{\errmessage{@kitem while not in a table}} -\def\kitemx{\errmessage{@kitemx while not in a table}} -\def\xitem{\errmessage{@xitem while not in a table}} -\def\xitemx{\errmessage{@xitemx while not in a table}} - -%% Contains a kludge to get @end[description] to work -\def\description{\tablez{\dontindex}{1}{}{}{}{}} - -\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} -{\obeylines\obeyspaces% -\gdef\tablex #1^^M{% -\tabley\dontindex#1 \endtabley}} - -\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} -{\obeylines\obeyspaces% -\gdef\ftablex #1^^M{% -\tabley\fnitemindex#1 \endtabley -\def\Eftable{\endgraf\afterenvbreak\endgroup}% -\let\Etable=\relax}} - -\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} -{\obeylines\obeyspaces% -\gdef\vtablex #1^^M{% -\tabley\vritemindex#1 \endtabley -\def\Evtable{\endgraf\afterenvbreak\endgroup}% -\let\Etable=\relax}} - -\def\dontindex #1{} -\def\fnitemindex #1{\doind {fn}{\code{#1}}}% -\def\vritemindex #1{\doind {vr}{\code{#1}}}% - -{\obeyspaces % -\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% -\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} - -\def\tablez #1#2#3#4#5#6{% -\aboveenvbreak % -\begingroup % -\def\Edescription{\Etable}% Neccessary kludge. -\let\itemindex=#1% -\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % -\ifnum 0#4>0 \tableindent=#4\mil \fi % -\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % -\def\itemfont{#2}% -\itemmax=\tableindent % -\advance \itemmax by -\itemmargin % -\advance \leftskip by \tableindent % -\exdentamount=\tableindent -\parindent = 0pt -\parskip = \smallskipamount -\ifdim \parskip=0pt \parskip=2pt \fi% -\def\Etable{\endgraf\afterenvbreak\endgroup}% -\let\item = \internalBitem % -\let\itemx = \internalBitemx % -\let\kitem = \internalBkitem % -\let\kitemx = \internalBkitemx % -\let\xitem = \internalBxitem % -\let\xitemx = \internalBxitemx % -} - -% This is the counter used by @enumerate, which is really @itemize - -\newcount \itemno - -\def\itemize{\parsearg\itemizezzz} - -\def\itemizezzz #1{% - \begingroup % ended by the @end itemsize - \itemizey {#1}{\Eitemize} -} - -\def\itemizey #1#2{% -\aboveenvbreak % -\itemmax=\itemindent % -\advance \itemmax by -\itemmargin % -\advance \leftskip by \itemindent % -\exdentamount=\itemindent -\parindent = 0pt % -\parskip = \smallskipamount % -\ifdim \parskip=0pt \parskip=2pt \fi% -\def#2{\endgraf\afterenvbreak\endgroup}% -\def\itemcontents{#1}% -\let\item=\itemizeitem} - -% Set sfcode to normal for the chars that usually have another value. -% These are `.?!:;,' -\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 - \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } - -% \splitoff TOKENS\endmark defines \first to be the first token in -% TOKENS, and \rest to be the remainder. -% -\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% - -% Allow an optional argument of an uppercase letter, lowercase letter, -% or number, to specify the first label in the enumerated list. No -% argument is the same as `1'. -% -\def\enumerate{\parsearg\enumeratezzz} -\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} -\def\enumeratey #1 #2\endenumeratey{% - \begingroup % ended by the @end enumerate - % - % If we were given no argument, pretend we were given `1'. - \def\thearg{#1}% - \ifx\thearg\empty \def\thearg{1}\fi - % - % Detect if the argument is a single token. If so, it might be a - % letter. Otherwise, the only valid thing it can be is a number. - % (We will always have one token, because of the test we just made. - % This is a good thing, since \splitoff doesn't work given nothing at - % all -- the first parameter is undelimited.) - \expandafter\splitoff\thearg\endmark - \ifx\rest\empty - % Only one token in the argument. It could still be anything. - % A ``lowercase letter'' is one whose \lccode is nonzero. - % An ``uppercase letter'' is one whose \lccode is both nonzero, and - % not equal to itself. - % Otherwise, we assume it's a number. - % - % We need the \relax at the end of the \ifnum lines to stop TeX from - % continuing to look for a <number>. - % - \ifnum\lccode\expandafter`\thearg=0\relax - \numericenumerate % a number (we hope) - \else - % It's a letter. - \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax - \lowercaseenumerate % lowercase letter - \else - \uppercaseenumerate % uppercase letter - \fi - \fi - \else - % Multiple tokens in the argument. We hope it's a number. - \numericenumerate - \fi -} - -% An @enumerate whose labels are integers. The starting integer is -% given in \thearg. -% -\def\numericenumerate{% - \itemno = \thearg - \startenumeration{\the\itemno}% -} - -% The starting (lowercase) letter is in \thearg. -\def\lowercaseenumerate{% - \itemno = \expandafter`\thearg - \startenumeration{% - % Be sure we're not beyond the end of the alphabet. - \ifnum\itemno=0 - \errmessage{No more lowercase letters in @enumerate; get a bigger - alphabet}% - \fi - \char\lccode\itemno - }% -} - -% The starting (uppercase) letter is in \thearg. -\def\uppercaseenumerate{% - \itemno = \expandafter`\thearg - \startenumeration{% - % Be sure we're not beyond the end of the alphabet. - \ifnum\itemno=0 - \errmessage{No more uppercase letters in @enumerate; get a bigger - alphabet} - \fi - \char\uccode\itemno - }% -} - -% Call itemizey, adding a period to the first argument and supplying the -% common last two arguments. Also subtract one from the initial value in -% \itemno, since @item increments \itemno. -% -\def\startenumeration#1{% - \advance\itemno by -1 - \itemizey{#1.}\Eenumerate\flushcr -} - -% @alphaenumerate and @capsenumerate are abbreviations for giving an arg -% to @enumerate. -% -\def\alphaenumerate{\enumerate{a}} -\def\capsenumerate{\enumerate{A}} -\def\Ealphaenumerate{\Eenumerate} -\def\Ecapsenumerate{\Eenumerate} - -% Definition of @item while inside @itemize. - -\def\itemizeitem{% -\advance\itemno by 1 -{\let\par=\endgraf \smallbreak}% -\ifhmode \errmessage{\in hmode at itemizeitem}\fi -{\parskip=0in \hskip 0pt -\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% -\vadjust{\penalty 1200}}% -\flushcr} - -% @multitable macros -% Amy Hendrickson, 8/18/94 -% -% @multitable ... @endmultitable will make as many columns as desired. -% Contents of each column will wrap at width given in preamble. Width -% can be specified either with sample text given in a template line, -% or in percent of \hsize, the current width of text on page. - -% Table can continue over pages but will only break between lines. - -% To make preamble: -% -% Either define widths of columns in terms of percent of \hsize: -% @multitable @percentofhsize .2 .3 .5 -% @item ... -% -% Numbers following @percentofhsize are the percent of the total -% current hsize to be used for each column. You may use as many -% columns as desired. - -% Or use a template: -% @multitable {Column 1 template} {Column 2 template} {Column 3 template} -% @item ... -% using the widest term desired in each column. - - -% Each new table line starts with @item, each subsequent new column -% starts with @tab. Empty columns may be produced by supplying @tab's -% with nothing between them for as many times as empty columns are needed, -% ie, @tab@tab@tab will produce two empty columns. - -% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their -% own lines, but it will not hurt if they are. - -% Sample multitable: - -% @multitable {Column 1 template} {Column 2 template} {Column 3 template} -% @item first col stuff @tab second col stuff @tab third col -% @item -% first col stuff -% @tab -% second col stuff -% @tab -% third col -% @item first col stuff @tab second col stuff -% @tab Many paragraphs of text may be used in any column. -% -% They will wrap at the width determined by the template. -% @item@tab@tab This will be in third column. -% @endmultitable - -% Default dimensions may be reset by user. -% @intableparskip will set vertical space between paragraphs in table. -% @intableparindent will set paragraph indent in table. -% @spacebetweencols will set horizontal space to be left between columns. -% @spacebetweenlines will set vertical space to be left between lines. - -%%%% -% Dimensions - -\newdimen\intableparskip -\newdimen\intableparindent -\newdimen\spacebetweencols -\newdimen\spacebetweenlines -\intableparskip=0pt -\intableparindent=6pt -\spacebetweencols=12pt -\spacebetweenlines=12pt - -%%%% -% Macros used to set up halign preamble: -\let\endsetuptable\relax -\def\xendsetuptable{\endsetuptable} -\let\percentofhsize\relax -\def\xpercentofhsize{\percentofhsize} -\newif\ifsetpercent - -\newcount\colcount -\def\setuptable#1{\def\firstarg{#1}% -\ifx\firstarg\xendsetuptable\let\go\relax% -\else - \ifx\firstarg\xpercentofhsize\global\setpercenttrue% - \else - \ifsetpercent - \if#1.\else% - \global\advance\colcount by1 % - \expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% - \fi - \else - \global\advance\colcount by1 - \setbox0=\hbox{#1}% - \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% - \fi% - \fi% - \let\go\setuptable% -\fi\go} -%%%% -% multitable syntax -\def\tab{&} - -%%%% -% @multitable ... @endmultitable definitions: - -\def\multitable#1\item{\bgroup -\let\item\cr -\tolerance=9500 -\hbadness=9500 -\parskip=\intableparskip -\parindent=\intableparindent -\overfullrule=0pt -\global\colcount=0\relax% -\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% - % To parse everything between @multitable and @item : -\def\one{#1}\expandafter\setuptable\one\endsetuptable - % Need to reset this to 0 after \setuptable. -\global\colcount=0\relax% - % - % This preamble sets up a generic column definition, which will - % be used as many times as user calls for columns. - % \vtop will set a single line and will also let text wrap and - % continue for many paragraphs if desired. -\halign\bgroup&\global\advance\colcount by 1\relax% -\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname - % In order to keep entries from bumping into each other - % we will add a \leftskip of \spacebetweencols to all columns after - % the first one. - % If a template has been used, we will add \spacebetweencols - % to the width of each template entry. - % If user has set preamble in terms of percent of \hsize - % we will use that dimension as the width of the column, and - % the \leftskip will keep entries from bumping into each other. - % Table will start at left margin and final column will justify at - % right margin. -\ifnum\colcount=1 -\else - \ifsetpercent - \else - % If user has <not> set preamble in terms of percent of \hsize - % we will advance \hsize by \spacebetweencols - \advance\hsize by \spacebetweencols - \fi - % In either case we will make \leftskip=\spacebetweencols: -\leftskip=\spacebetweencols -\fi -\noindent##}\cr% - % \everycr will reset column counter, \colcount, at the end of - % each line. Every column entry will cause \colcount to advance by one. - % The table preamble - % looks at the current \colcount to find the correct column width. -\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines -\filbreak%% keeps underfull box messages off when table breaks over pages. -\global\colcount=0\relax}}} - -\message{indexing,} -% Index generation facilities - -% Define \newwrite to be identical to plain tex's \newwrite -% except not \outer, so it can be used within \newindex. -{\catcode`\@=11 -\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} - -% \newindex {foo} defines an index named foo. -% It automatically defines \fooindex such that -% \fooindex ...rest of line... puts an entry in the index foo. -% It also defines \fooindfile to be the number of the output channel for -% the file that accumulates this index. The file's extension is foo. -% The name of an index should be no more than 2 characters long -% for the sake of vms. - -\def\newindex #1{ -\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file -\openout \csname#1indfile\endcsname \jobname.#1 % Open the file -\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex -\noexpand\doindex {#1}} -} - -% @defindex foo == \newindex{foo} - -\def\defindex{\parsearg\newindex} - -% Define @defcodeindex, like @defindex except put all entries in @code. - -\def\newcodeindex #1{ -\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file -\openout \csname#1indfile\endcsname \jobname.#1 % Open the file -\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex -\noexpand\docodeindex {#1}} -} - -\def\defcodeindex{\parsearg\newcodeindex} - -% @synindex foo bar makes index foo feed into index bar. -% Do this instead of @defindex foo if you don't want it as a separate index. -\def\synindex #1 #2 {% -\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname -\expandafter\let\csname#1indfile\endcsname=\synindexfoo -\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex -\noexpand\doindex {#2}}% -} - -% @syncodeindex foo bar similar, but put all entries made for index foo -% inside @code. -\def\syncodeindex #1 #2 {% -\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname -\expandafter\let\csname#1indfile\endcsname=\synindexfoo -\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex -\noexpand\docodeindex {#2}}% -} - -% Define \doindex, the driver for all \fooindex macros. -% Argument #1 is generated by the calling \fooindex macro, -% and it is "foo", the name of the index. - -% \doindex just uses \parsearg; it calls \doind for the actual work. -% This is because \doind is more useful to call from other macros. - -% There is also \dosubind {index}{topic}{subtopic} -% which makes an entry in a two-level index such as the operation index. - -\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} -\def\singleindexer #1{\doind{\indexname}{#1}} - -% like the previous two, but they put @code around the argument. -\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} -\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} - -\def\indexdummies{% -% Take care of the plain tex accent commands. -\def\"{\realbackslash "}% -\def\`{\realbackslash `}% -\def\'{\realbackslash '}% -\def\^{\realbackslash ^}% -\def\~{\realbackslash ~}% -\def\={\realbackslash =}% -\def\b{\realbackslash b}% -\def\c{\realbackslash c}% -\def\d{\realbackslash d}% -\def\u{\realbackslash u}% -\def\v{\realbackslash v}% -\def\H{\realbackslash H}% -% Take care of the plain tex special European modified letters. -\def\oe{\realbackslash oe}% -\def\ae{\realbackslash ae}% -\def\aa{\realbackslash aa}% -\def\OE{\realbackslash OE}% -\def\AE{\realbackslash AE}% -\def\AA{\realbackslash AA}% -\def\o{\realbackslash o}% -\def\O{\realbackslash O}% -\def\l{\realbackslash l}% -\def\L{\realbackslash L}% -\def\ss{\realbackslash ss}% -% Take care of texinfo commands likely to appear in an index entry. -\def\_{{\realbackslash _}}% -\def\w{\realbackslash w }% -\def\bf{\realbackslash bf }% -\def\rm{\realbackslash rm }% -\def\sl{\realbackslash sl }% -\def\sf{\realbackslash sf}% -\def\tt{\realbackslash tt}% -\def\gtr{\realbackslash gtr}% -\def\less{\realbackslash less}% -\def\hat{\realbackslash hat}% -\def\char{\realbackslash char}% -\def\TeX{\realbackslash TeX}% -\def\dots{\realbackslash dots }% -\def\copyright{\realbackslash copyright }% -\def\tclose##1{\realbackslash tclose {##1}}% -\def\code##1{\realbackslash code {##1}}% -\def\samp##1{\realbackslash samp {##1}}% -\def\t##1{\realbackslash r {##1}}% -\def\r##1{\realbackslash r {##1}}% -\def\i##1{\realbackslash i {##1}}% -\def\b##1{\realbackslash b {##1}}% -\def\cite##1{\realbackslash cite {##1}}% -\def\key##1{\realbackslash key {##1}}% -\def\file##1{\realbackslash file {##1}}% -\def\var##1{\realbackslash var {##1}}% -\def\kbd##1{\realbackslash kbd {##1}}% -\def\dfn##1{\realbackslash dfn {##1}}% -\def\emph##1{\realbackslash emph {##1}}% -} - -% \indexnofonts no-ops all font-change commands. -% This is used when outputting the strings to sort the index by. -\def\indexdummyfont#1{#1} -\def\indexdummytex{TeX} -\def\indexdummydots{...} - -\def\indexnofonts{% -% Just ignore accents. -\let\"=\indexdummyfont -\let\`=\indexdummyfont -\let\'=\indexdummyfont -\let\^=\indexdummyfont -\let\~=\indexdummyfont -\let\==\indexdummyfont -\let\b=\indexdummyfont -\let\c=\indexdummyfont -\let\d=\indexdummyfont -\let\u=\indexdummyfont -\let\v=\indexdummyfont -\let\H=\indexdummyfont -% Take care of the plain tex special European modified letters. -\def\oe{oe}% -\def\ae{ae}% -\def\aa{aa}% -\def\OE{OE}% -\def\AE{AE}% -\def\AA{AA}% -\def\o{o}% -\def\O{O}% -\def\l{l}% -\def\L{L}% -\def\ss{ss}% -\let\w=\indexdummyfont -\let\t=\indexdummyfont -\let\r=\indexdummyfont -\let\i=\indexdummyfont -\let\b=\indexdummyfont -\let\emph=\indexdummyfont -\let\strong=\indexdummyfont -\let\cite=\indexdummyfont -\let\sc=\indexdummyfont -%Don't no-op \tt, since it isn't a user-level command -% and is used in the definitions of the active chars like <, >, |... -%\let\tt=\indexdummyfont -\let\tclose=\indexdummyfont -\let\code=\indexdummyfont -\let\file=\indexdummyfont -\let\samp=\indexdummyfont -\let\kbd=\indexdummyfont -\let\key=\indexdummyfont -\let\var=\indexdummyfont -\let\TeX=\indexdummytex -\let\dots=\indexdummydots -} - -% To define \realbackslash, we must make \ not be an escape. -% We must first make another character (@) an escape -% so we do not become unable to do a definition. - -{\catcode`\@=0 \catcode`\\=\other -@gdef@realbackslash{\}} - -\let\indexbackslash=0 %overridden during \printindex. - -\let\SETmarginindex=\relax %initialize! -% workhorse for all \fooindexes -% #1 is name of index, #2 is stuff to put there -\def\doind #1#2{% -% Put the index entry in the margin if desired. -\ifx\SETmarginindex\relax\else% -\insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% -\fi% -{\count10=\lastpenalty % -{\indexdummies % Must do this here, since \bf, etc expand at this stage -\escapechar=`\\% -{\let\folio=0% Expand all macros now EXCEPT \folio -\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now -% so it will be output as is; and it will print as backslash in the indx. -% -% Now process the index-string once, with all font commands turned off, -% to get the string to sort the index by. -{\indexnofonts -\xdef\temp1{#2}% -}% -% Now produce the complete index entry. We process the index-string again, -% this time with font commands expanded, to get what to print in the index. -\edef\temp{% -\write \csname#1indfile\endcsname{% -\realbackslash entry {\temp1}{\folio}{#2}}}% -\temp }% -}\penalty\count10}} - -\def\dosubind #1#2#3{% -{\count10=\lastpenalty % -{\indexdummies % Must do this here, since \bf, etc expand at this stage -\escapechar=`\\% -{\let\folio=0% -\def\rawbackslashxx{\indexbackslash}% -% -% Now process the index-string once, with all font commands turned off, -% to get the string to sort the index by. -{\indexnofonts -\xdef\temp1{#2 #3}% -}% -% Now produce the complete index entry. We process the index-string again, -% this time with font commands expanded, to get what to print in the index. -\edef\temp{% -\write \csname#1indfile\endcsname{% -\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% -\temp }% -}\penalty\count10}} - -% The index entry written in the file actually looks like -% \entry {sortstring}{page}{topic} -% or -% \entry {sortstring}{page}{topic}{subtopic} -% The texindex program reads in these files and writes files -% containing these kinds of lines: -% \initial {c} -% before the first topic whose initial is c -% \entry {topic}{pagelist} -% for a topic that is used without subtopics -% \primary {topic} -% for the beginning of a topic that is used with subtopics -% \secondary {subtopic}{pagelist} -% for each subtopic. - -% Define the user-accessible indexing commands -% @findex, @vindex, @kindex, @cindex. - -\def\findex {\fnindex} -\def\kindex {\kyindex} -\def\cindex {\cpindex} -\def\vindex {\vrindex} -\def\tindex {\tpindex} -\def\pindex {\pgindex} - -\def\cindexsub {\begingroup\obeylines\cindexsub} -{\obeylines % -\gdef\cindexsub "#1" #2^^M{\endgroup % -\dosubind{cp}{#2}{#1}}} - -% Define the macros used in formatting output of the sorted index material. - -% This is what you call to cause a particular index to get printed. -% Write -% @unnumbered Function Index -% @printindex fn - -\def\printindex{\parsearg\doprintindex} - -\def\doprintindex#1{% - \tex - \dobreak \chapheadingskip {10000} - \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other - \catcode`\$=\other - \catcode`\~=\other - \indexbreaks - % - % The following don't help, since the chars were translated - % when the raw index was written, and their fonts were discarded - % due to \indexnofonts. - %\catcode`\"=\active - %\catcode`\^=\active - %\catcode`\_=\active - %\catcode`\|=\active - %\catcode`\<=\active - %\catcode`\>=\active - % % - \def\indexbackslash{\rawbackslashxx} - \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt - \begindoublecolumns - % - % See if the index file exists and is nonempty. - \openin 1 \jobname.#1s - \ifeof 1 - % \enddoublecolumns gets confused if there is no text in the index, - % and it loses the chapter title and the aux file entries for the - % index. The easiest way to prevent this problem is to make sure - % there is some text. - (Index is nonexistent) - \else - % - % If the index file exists but is empty, then \openin leaves \ifeof - % false. We have to make TeX try to read something from the file, so - % it can discover if there is anything in it. - \read 1 to \temp - \ifeof 1 - (Index is empty) - \else - \input \jobname.#1s - \fi - \fi - \closein 1 - \enddoublecolumns - \Etex -} - -% These macros are used by the sorted index file itself. -% Change them to control the appearance of the index. - -% Same as \bigskipamount except no shrink. -% \balancecolumns gets confused if there is any shrink. -\newskip\initialskipamount \initialskipamount 12pt plus4pt - -\def\initial #1{% -{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt -\ifdim\lastskip<\initialskipamount -\removelastskip \penalty-200 \vskip \initialskipamount\fi -\line{\secbf#1\hfill}\kern 2pt\penalty10000}} - -% This typesets a paragraph consisting of #1, dot leaders, and then #2 -% flush to the right margin. It is used for index and table of contents -% entries. The paragraph is indented by \leftskip. -% -\def\entry #1#2{\begingroup - % - % Start a new paragraph if necessary, so our assignments below can't - % affect previous text. - \par - % - % Do not fill out the last line with white space. - \parfillskip = 0in - % - % No extra space above this paragraph. - \parskip = 0in - % - % Do not prefer a separate line ending with a hyphen to fewer lines. - \finalhyphendemerits = 0 - % - % \hangindent is only relevant when the entry text and page number - % don't both fit on one line. In that case, bob suggests starting the - % dots pretty far over on the line. Unfortunately, a large - % indentation looks wrong when the entry text itself is broken across - % lines. So we use a small indentation and put up with long leaders. - % - % \hangafter is reset to 1 (which is the value we want) at the start - % of each paragraph, so we need not do anything with that. - \hangindent=2em - % - % When the entry text needs to be broken, just fill out the first line - % with blank space. - \rightskip = 0pt plus1fil - % - % Start a ``paragraph'' for the index entry so the line breaking - % parameters we've set above will have an effect. - \noindent - % - % Insert the text of the index entry. TeX will do line-breaking on it. - #1% - % The following is kluged to not output a line of dots in the index if - % there are no page numbers. The next person who breaks this will be - % cursed by a Unix daemon. - \def\tempa{{\rm }}% - \def\tempb{#2}% - \edef\tempc{\tempa}% - \edef\tempd{\tempb}% - \ifx\tempc\tempd\ \else% - % - % If we must, put the page number on a line of its own, and fill out - % this line with blank space. (The \hfil is overwhelmed with the - % fill leaders glue in \indexdotfill if the page number does fit.) - \hfil\penalty50 - \null\nobreak\indexdotfill % Have leaders before the page number. - % - % The `\ ' here is removed by the implicit \unskip that TeX does as - % part of (the primitive) \par. Without it, a spurious underfull - % \hbox ensues. - \ #2% The page number ends the paragraph. - \fi% - \par -\endgroup} - -% Like \dotfill except takes at least 1 em. -\def\indexdotfill{\cleaders - \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} - -\def\primary #1{\line{#1\hfil}} - -\newskip\secondaryindent \secondaryindent=0.5cm - -\def\secondary #1#2{ -{\parfillskip=0in \parskip=0in -\hangindent =1in \hangafter=1 -\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par -}} - -%% Define two-column mode, which is used in indexes. -%% Adapted from the TeXbook, page 416. -\catcode `\@=11 - -\newbox\partialpage - -\newdimen\doublecolumnhsize - -\def\begindoublecolumns{\begingroup - % Grab any single-column material above us. - \output = {\global\setbox\partialpage - =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% - \eject - % - % Now switch to the double-column output routine. - \output={\doublecolumnout}% - % - % Change the page size parameters. We could do this once outside this - % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 - % format, but then we repeat the same computation. Repeating a couple - % of assignments once per index is clearly meaningless for the - % execution time, so we may as well do it once. - % - % First we halve the line length, less a little for the gutter between - % the columns. We compute the gutter based on the line length, so it - % changes automatically with the paper format. The magic constant - % below is chosen so that the gutter has the same value (well, +- < - % 1pt) as it did when we hard-coded it. - % - % We put the result in a separate register, \doublecolumhsize, so we - % can restore it in \pagesofar, after \hsize itself has (potentially) - % been clobbered. - % - \doublecolumnhsize = \hsize - \advance\doublecolumnhsize by -.04154\hsize - \divide\doublecolumnhsize by 2 - \hsize = \doublecolumnhsize - % - % Double the \vsize as well. (We don't need a separate register here, - % since nobody clobbers \vsize.) - \vsize = 2\vsize - \doublecolumnpagegoal -} - -\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage} - -\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth - \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage - \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1} - \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3} - \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi - \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi -} -\def\doublecolumnpagegoal{% - \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@ -} -\def\pagesofar{\unvbox\partialpage % - \hsize=\doublecolumnhsize % have to restore this since output routine - \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}} -\def\doublecolumnout{% - \setbox5=\copy255 - {\vbadness=10000 \doublecolumnsplit} - \ifvbox255 - \setbox0=\vtop to\dimen@{\unvbox0} - \setbox2=\vtop to\dimen@{\unvbox2} - \onepageout\pagesofar \unvbox255 \penalty\outputpenalty - \else - \setbox0=\vbox{\unvbox5} - \ifvbox0 - \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip - \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth - {\vbadness=10000 - \loop \global\setbox5=\copy0 - \setbox1=\vsplit5 to\dimen@ - \setbox3=\vsplit5 to\dimen@ - \ifvbox5 \global\advance\dimen@ by1pt \repeat - \setbox0=\vbox to\dimen@{\unvbox1} - \setbox2=\vbox to\dimen@{\unvbox3} - \global\setbox\partialpage=\vbox{\pagesofar} - \doublecolumnpagegoal - } - \fi - \fi -} - -\catcode `\@=\other -\message{sectioning,} -% Define chapters, sections, etc. - -\newcount \chapno -\newcount \secno \secno=0 -\newcount \subsecno \subsecno=0 -\newcount \subsubsecno \subsubsecno=0 - -% This counter is funny since it counts through charcodes of letters A, B, ... -\newcount \appendixno \appendixno = `\@ -\def\appendixletter{\char\the\appendixno} - -\newwrite \contentsfile -% This is called from \setfilename. -\def\opencontents{\openout \contentsfile = \jobname.toc} - -% Each @chapter defines this as the name of the chapter. -% page headings and footings can use it. @section does likewise - -\def\thischapter{} \def\thissection{} -\def\seccheck#1{\if \pageno<0 % -\errmessage{@#1 not allowed after generating table of contents}\fi -% -} - -\def\chapternofonts{% -\let\rawbackslash=\relax% -\let\frenchspacing=\relax% -\def\result{\realbackslash result} -\def\equiv{\realbackslash equiv} -\def\expansion{\realbackslash expansion} -\def\print{\realbackslash print} -\def\TeX{\realbackslash TeX} -\def\dots{\realbackslash dots} -\def\copyright{\realbackslash copyright} -\def\tt{\realbackslash tt} -\def\bf{\realbackslash bf } -\def\w{\realbackslash w} -\def\less{\realbackslash less} -\def\gtr{\realbackslash gtr} -\def\hat{\realbackslash hat} -\def\char{\realbackslash char} -\def\tclose##1{\realbackslash tclose {##1}} -\def\code##1{\realbackslash code {##1}} -\def\samp##1{\realbackslash samp {##1}} -\def\r##1{\realbackslash r {##1}} -\def\b##1{\realbackslash b {##1}} -\def\key##1{\realbackslash key {##1}} -\def\file##1{\realbackslash file {##1}} -\def\kbd##1{\realbackslash kbd {##1}} -% These are redefined because @smartitalic wouldn't work inside xdef. -\def\i##1{\realbackslash i {##1}} -\def\cite##1{\realbackslash cite {##1}} -\def\var##1{\realbackslash var {##1}} -\def\emph##1{\realbackslash emph {##1}} -\def\dfn##1{\realbackslash dfn {##1}} -} - -\newcount\absseclevel % used to calculate proper heading level -\newcount\secbase\secbase=0 % @raise/lowersections modify this count - -% @raisesections: treat @section as chapter, @subsection as section, etc. -\def\raisesections{\global\advance\secbase by -1} -\let\up=\raisesections % original BFox name - -% @lowersections: treat @chapter as section, @section as subsection, etc. -\def\lowersections{\global\advance\secbase by 1} -\let\down=\lowersections % original BFox name - -% Choose a numbered-heading macro -% #1 is heading level if unmodified by @raisesections or @lowersections -% #2 is text for heading -\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 -\ifcase\absseclevel - \chapterzzz{#2} -\or - \seczzz{#2} -\or - \numberedsubseczzz{#2} -\or - \numberedsubsubseczzz{#2} -\else - \ifnum \absseclevel<0 - \chapterzzz{#2} - \else - \numberedsubsubseczzz{#2} - \fi -\fi -} - -% like \numhead, but chooses appendix heading levels -\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 -\ifcase\absseclevel - \appendixzzz{#2} -\or - \appendixsectionzzz{#2} -\or - \appendixsubseczzz{#2} -\or - \appendixsubsubseczzz{#2} -\else - \ifnum \absseclevel<0 - \appendixzzz{#2} - \else - \appendixsubsubseczzz{#2} - \fi -\fi -} - -% like \numhead, but chooses numberless heading levels -\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 -\ifcase\absseclevel - \unnumberedzzz{#2} -\or - \unnumberedseczzz{#2} -\or - \unnumberedsubseczzz{#2} -\or - \unnumberedsubsubseczzz{#2} -\else - \ifnum \absseclevel<0 - \unnumberedzzz{#2} - \else - \unnumberedsubsubseczzz{#2} - \fi -\fi -} - - -\def\thischaptername{No Chapter Title} -\outer\def\chapter{\parsearg\chapteryyy} -\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz -\def\chapterzzz #1{\seccheck{chapter}% -\secno=0 \subsecno=0 \subsubsecno=0 -\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% -\chapmacro {#1}{\the\chapno}% -\gdef\thissection{#1}% -\gdef\thischaptername{#1}% -% We don't substitute the actual chapter name into \thischapter -% because we don't want its macros evaluated now. -\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% -{\chapternofonts% -\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\donoderef % -\global\let\section = \numberedsec -\global\let\subsection = \numberedsubsec -\global\let\subsubsection = \numberedsubsubsec -}} - -\outer\def\appendix{\parsearg\appendixyyy} -\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz -\def\appendixzzz #1{\seccheck{appendix}% -\secno=0 \subsecno=0 \subsubsecno=0 -\global\advance \appendixno by 1 \message{Appendix \appendixletter}% -\chapmacro {#1}{\putwordAppendix{} \appendixletter}% -\gdef\thissection{#1}% -\gdef\thischaptername{#1}% -\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% -{\chapternofonts% -\edef\temp{{\realbackslash chapentry - {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\appendixnoderef % -\global\let\section = \appendixsec -\global\let\subsection = \appendixsubsec -\global\let\subsubsection = \appendixsubsubsec -}} - -\outer\def\top{\parsearg\unnumberedyyy} -\outer\def\unnumbered{\parsearg\unnumberedyyy} -\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz -\def\unnumberedzzz #1{\seccheck{unnumbered}% -\secno=0 \subsecno=0 \subsubsecno=0 -% -% This used to be simply \message{#1}, but TeX fully expands the -% argument to \message. Therefore, if #1 contained @-commands, TeX -% expanded them. For example, in `@unnumbered The @cite{Book}', TeX -% expanded @cite (which turns out to cause errors because \cite is meant -% to be executed, not expanded). -% -% Anyway, we don't want the fully-expanded definition of @cite to appear -% as a result of the \message, we just want `@cite' itself. We use -% \the<toks register> to achieve this: TeX expands \the<toks> only once, -% simply yielding the contents of the <toks register>. -\toks0 = {#1}\message{(\the\toks0)}% -% -\unnumbchapmacro {#1}% -\gdef\thischapter{#1}\gdef\thissection{#1}% -{\chapternofonts% -\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\unnumbnoderef % -\global\let\section = \unnumberedsec -\global\let\subsection = \unnumberedsubsec -\global\let\subsubsection = \unnumberedsubsubsec -}} - -\outer\def\numberedsec{\parsearg\secyyy} -\def\secyyy #1{\numhead1{#1}} % normally calls seczzz -\def\seczzz #1{\seccheck{section}% -\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % -\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% -{\chapternofonts% -\edef\temp{{\realbackslash secentry % -{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\donoderef % -\penalty 10000 % -}} - -\outer\def\appenixsection{\parsearg\appendixsecyyy} -\outer\def\appendixsec{\parsearg\appendixsecyyy} -\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz -\def\appendixsectionzzz #1{\seccheck{appendixsection}% -\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % -\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% -{\chapternofonts% -\edef\temp{{\realbackslash secentry % -{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\appendixnoderef % -\penalty 10000 % -}} - -\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} -\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz -\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% -\plainsecheading {#1}\gdef\thissection{#1}% -{\chapternofonts% -\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\unnumbnoderef % -\penalty 10000 % -}} - -\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} -\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz -\def\numberedsubseczzz #1{\seccheck{subsection}% -\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % -\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% -{\chapternofonts% -\edef\temp{{\realbackslash subsecentry % -{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\donoderef % -\penalty 10000 % -}} - -\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} -\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz -\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% -\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % -\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% -{\chapternofonts% -\edef\temp{{\realbackslash subsecentry % -{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\appendixnoderef % -\penalty 10000 % -}} - -\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} -\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz -\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% -\plainsecheading {#1}\gdef\thissection{#1}% -{\chapternofonts% -\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\unnumbnoderef % -\penalty 10000 % -}} - -\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} -\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz -\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% -\gdef\thissection{#1}\global\advance \subsubsecno by 1 % -\subsubsecheading {#1} - {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% -{\chapternofonts% -\edef\temp{{\realbackslash subsubsecentry % - {#1} - {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} - {\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\donoderef % -\penalty 10000 % -}} - -\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} -\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz -\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% -\gdef\thissection{#1}\global\advance \subsubsecno by 1 % -\subsubsecheading {#1} - {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% -{\chapternofonts% -\edef\temp{{\realbackslash subsubsecentry{#1}% - {\appendixletter} - {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\appendixnoderef % -\penalty 10000 % -}} - -\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} -\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz -\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% -\plainsecheading {#1}\gdef\thissection{#1}% -{\chapternofonts% -\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% -\escapechar=`\\% -\write \contentsfile \temp % -\unnumbnoderef % -\penalty 10000 % -}} - -% These are variants which are not "outer", so they can appear in @ifinfo. -% Actually, they should now be obsolete; ordinary section commands should work. -\def\infotop{\parsearg\unnumberedzzz} -\def\infounnumbered{\parsearg\unnumberedzzz} -\def\infounnumberedsec{\parsearg\unnumberedseczzz} -\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} -\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} - -\def\infoappendix{\parsearg\appendixzzz} -\def\infoappendixsec{\parsearg\appendixseczzz} -\def\infoappendixsubsec{\parsearg\appendixsubseczzz} -\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} - -\def\infochapter{\parsearg\chapterzzz} -\def\infosection{\parsearg\sectionzzz} -\def\infosubsection{\parsearg\subsectionzzz} -\def\infosubsubsection{\parsearg\subsubsectionzzz} - -% These macros control what the section commands do, according -% to what kind of chapter we are in (ordinary, appendix, or unnumbered). -% Define them by default for a numbered chapter. -\global\let\section = \numberedsec -\global\let\subsection = \numberedsubsec -\global\let\subsubsection = \numberedsubsubsec - -% Define @majorheading, @heading and @subheading - -% NOTE on use of \vbox for chapter headings, section headings, and -% such: -% 1) We use \vbox rather than the earlier \line to permit -% overlong headings to fold. -% 2) \hyphenpenalty is set to 10000 because hyphenation in a -% heading is obnoxious; this forbids it. -% 3) Likewise, headings look best if no \parindent is used, and -% if justification is not attempted. Hence \raggedright. - - -\def\majorheading{\parsearg\majorheadingzzz} -\def\majorheadingzzz #1{% -{\advance\chapheadingskip by 10pt \chapbreak }% -{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}\bigskip \par\penalty 200} - -\def\chapheading{\parsearg\chapheadingzzz} -\def\chapheadingzzz #1{\chapbreak % -{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}\bigskip \par\penalty 200} - -\def\heading{\parsearg\secheadingi} - -\def\subheading{\parsearg\subsecheadingi} - -\def\subsubheading{\parsearg\subsubsecheadingi} - -% These macros generate a chapter, section, etc. heading only -% (including whitespace, linebreaking, etc. around it), -% given all the information in convenient, parsed form. - -%%% Args are the skip and penalty (usually negative) -\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} - -\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} - -%%% Define plain chapter starts, and page on/off switching for it -% Parameter controlling skip before chapter headings (if needed) - -\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt - -\def\chapbreak{\dobreak \chapheadingskip {-4000}} -\def\chappager{\par\vfill\supereject} -\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} - -\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} - -\def\CHAPPAGoff{ -\global\let\pchapsepmacro=\chapbreak -\global\let\pagealignmacro=\chappager} - -\def\CHAPPAGon{ -\global\let\pchapsepmacro=\chappager -\global\let\pagealignmacro=\chappager -\global\def\HEADINGSon{\HEADINGSsingle}} - -\def\CHAPPAGodd{ -\global\let\pchapsepmacro=\chapoddpage -\global\let\pagealignmacro=\chapoddpage -\global\def\HEADINGSon{\HEADINGSdouble}} - -\CHAPPAGon - -\def\CHAPFplain{ -\global\let\chapmacro=\chfplain -\global\let\unnumbchapmacro=\unnchfplain} - -\def\chfplain #1#2{% - \pchapsepmacro - {% - \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #2\enspace #1}% - }% - \bigskip - \penalty5000 -} - -\def\unnchfplain #1{% -\pchapsepmacro % -{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}\bigskip \par\penalty 10000 % -} -\CHAPFplain % The default - -\def\unnchfopen #1{% -\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}\bigskip \par\penalty 10000 % -} - -\def\chfopen #1#2{\chapoddpage {\chapfonts -\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% -\par\penalty 5000 % -} - -\def\CHAPFopen{ -\global\let\chapmacro=\chfopen -\global\let\unnumbchapmacro=\unnchfopen} - -% Parameter controlling skip before section headings. - -\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt -\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} - -\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt -\def\secheadingbreak{\dobreak \secheadingskip {-1000}} - -% @paragraphindent is defined for the Info formatting commands only. -\let\paragraphindent=\comment - -% Section fonts are the base font at magstep2, which produces -% a size a bit more than 14 points in the default situation. - -\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}} -\def\plainsecheading #1{\secheadingi {#1}} -\def\secheadingi #1{{\advance \secheadingskip by \parskip % -\secheadingbreak}% -{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}% -\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } - - -% Subsection fonts are the base font at magstep1, -% which produces a size of 12 points. - -\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}} -\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip % -\subsecheadingbreak}% -{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}% -\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } - -\def\subsubsecfonts{\subsecfonts} % Maybe this should change: - % Perhaps make sssec fonts scaled - % magstep half -\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}} -\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip % -\subsecheadingbreak}% -{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 - \parindent=0pt\raggedright - \rm #1\hfill}}% -\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000} - - -\message{toc printing,} - -% Finish up the main text and prepare to read what we've written -% to \contentsfile. - -\newskip\contentsrightmargin \contentsrightmargin=1in -\def\startcontents#1{% - \pagealignmacro - \immediate\closeout \contentsfile - \ifnum \pageno>0 - \pageno = -1 % Request roman numbered pages. - \fi - % Don't need to put `Contents' or `Short Contents' in the headline. - % It is abundantly clear what they are. - \unnumbchapmacro{#1}\def\thischapter{}% - \begingroup % Set up to handle contents files properly. - \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 - \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi - \raggedbottom % Worry more about breakpoints than the bottom. - \advance\hsize by -\contentsrightmargin % Don't use the full line length. -} - - -% Normal (long) toc. -\outer\def\contents{% - \startcontents{\putwordTableofContents}% - \input \jobname.toc - \endgroup - \vfill \eject -} - -% And just the chapters. -\outer\def\summarycontents{% - \startcontents{\putwordShortContents}% - % - \let\chapentry = \shortchapentry - \let\unnumbchapentry = \shortunnumberedentry - % We want a true roman here for the page numbers. - \secfonts - \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl - \rm - \advance\baselineskip by 1pt % Open it up a little. - \def\secentry ##1##2##3##4{} - \def\unnumbsecentry ##1##2{} - \def\subsecentry ##1##2##3##4##5{} - \def\unnumbsubsecentry ##1##2{} - \def\subsubsecentry ##1##2##3##4##5##6{} - \def\unnumbsubsubsecentry ##1##2{} - \input \jobname.toc - \endgroup - \vfill \eject -} -\let\shortcontents = \summarycontents - -% These macros generate individual entries in the table of contents. -% The first argument is the chapter or section name. -% The last argument is the page number. -% The arguments in between are the chapter number, section number, ... - -% Chapter-level things, for both the long and short contents. -\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} - -% See comments in \dochapentry re vbox and related settings -\def\shortchapentry#1#2#3{% - \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% -} - -% Typeset the label for a chapter or appendix for the short contents. -% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. -% We could simplify the code here by writing out an \appendixentry -% command in the toc file for appendices, instead of using \chapentry -% for both, but it doesn't seem worth it. -\setbox0 = \hbox{\shortcontrm \putwordAppendix } -\newdimen\shortappendixwidth \shortappendixwidth = \wd0 - -\def\shortchaplabel#1{% - % We typeset #1 in a box of constant width, regardless of the text of - % #1, so the chapter titles will come out aligned. - \setbox0 = \hbox{#1}% - \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi - % - % This space should be plenty, since a single number is .5em, and the - % widest letter (M) is 1em, at least in the Computer Modern fonts. - % (This space doesn't include the extra space that gets added after - % the label; that gets put in in \shortchapentry above.) - \advance\dimen0 by 1.1em - \hbox to \dimen0{#1\hfil}% -} - -\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} -\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} - -% Sections. -\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} -\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} - -% Subsections. -\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} -\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} - -% And subsubsections. -\def\subsubsecentry#1#2#3#4#5#6{% - \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} -\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} - - -% This parameter controls the indentation of the various levels. -\newdimen\tocindent \tocindent = 3pc - -% Now for the actual typesetting. In all these, #1 is the text and #2 is the -% page number. -% -% If the toc has to be broken over pages, we would want to be at chapters -% if at all possible; hence the \penalty. -\def\dochapentry#1#2{% - \penalty-300 \vskip\baselineskip - \begingroup - \chapentryfonts - \tocentry{#1}{\dopageno{#2}}% - \endgroup - \nobreak\vskip .25\baselineskip -} - -\def\dosecentry#1#2{\begingroup - \secentryfonts \leftskip=\tocindent - \tocentry{#1}{\dopageno{#2}}% -\endgroup} - -\def\dosubsecentry#1#2{\begingroup - \subsecentryfonts \leftskip=2\tocindent - \tocentry{#1}{\dopageno{#2}}% -\endgroup} - -\def\dosubsubsecentry#1#2{\begingroup - \subsubsecentryfonts \leftskip=3\tocindent - \tocentry{#1}{\dopageno{#2}}% -\endgroup} - -% Final typesetting of a toc entry; we use the same \entry macro as for -% the index entries, but we want to suppress hyphenation here. (We -% can't do that in the \entry macro, since index entries might consist -% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) -% -\def\tocentry#1#2{\begingroup - \hyphenpenalty = 10000 - \entry{#1}{#2}% -\endgroup} - -% Space between chapter (or whatever) number and the title. -\def\labelspace{\hskip1em \relax} - -\def\dopageno#1{{\rm #1}} -\def\doshortpageno#1{{\rm #1}} - -\def\chapentryfonts{\secfonts \rm} -\def\secentryfonts{\textfonts} -\let\subsecentryfonts = \textfonts -\let\subsubsecentryfonts = \textfonts - - -\message{environments,} - -% Since these characters are used in examples, it should be an even number of -% \tt widths. Each \tt character is 1en, so two makes it 1em. -% Furthermore, these definitions must come after we define our fonts. -\newbox\dblarrowbox \newbox\longdblarrowbox -\newbox\pushcharbox \newbox\bullbox -\newbox\equivbox \newbox\errorbox - -\let\ptexequiv = \equiv - -%{\tentt -%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} -%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} -%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} -%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} -% Adapted from the manmac format (p.420 of TeXbook) -%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex -% depth .1ex\hfil} -%} - -\def\point{$\star$} - -\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} -\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} -\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} - -\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} - -% Adapted from the TeXbook's \boxit. -{\tentt \global\dimen0 = 3em}% Width of the box. -\dimen2 = .55pt % Thickness of rules -% The text. (`r' is open on the right, `e' somewhat less so on the left.) -\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} - -\global\setbox\errorbox=\hbox to \dimen0{\hfil - \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. - \advance\hsize by -2\dimen2 % Rules. - \vbox{ - \hrule height\dimen2 - \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. - \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. - \kern3pt\vrule width\dimen2}% Space to right. - \hrule height\dimen2} - \hfil} - -% The @error{} command. -\def\error{\leavevmode\lower.7ex\copy\errorbox} - -% @tex ... @end tex escapes into raw Tex temporarily. -% One exception: @ is still an escape character, so that @end tex works. -% But \@ or @@ will get a plain tex @ character. - -\def\tex{\begingroup -\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 -\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 -\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie -\catcode `\%=14 -\catcode 43=12 -\catcode`\"=12 -\catcode`\==12 -\catcode`\|=12 -\catcode`\<=12 -\catcode`\>=12 -\escapechar=`\\ -% -\let\~=\ptextilde -\let\{=\ptexlbrace -\let\}=\ptexrbrace -\let\.=\ptexdot -\let\*=\ptexstar -\let\dots=\ptexdots -\def\@{@}% -\let\bullet=\ptexbullet -\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl -\let\L=\ptexL -% -\let\Etex=\endgroup} - -% Define @lisp ... @endlisp. -% @lisp does a \begingroup so it can rebind things, -% including the definition of @endlisp (which normally is erroneous). - -% Amount to narrow the margins by for @lisp. -\newskip\lispnarrowing \lispnarrowing=0.4in - -% This is the definition that ^^M gets inside @lisp, @example, and other -% such environments. \null is better than a space, since it doesn't -% have any width. -\def\lisppar{\null\endgraf} - -% Make each space character in the input produce a normal interword -% space in the output. Don't allow a line break at this space, as this -% is used only in environments like @example, where each line of input -% should produce a line of output anyway. -% -{\obeyspaces % -\gdef\sepspaces{\obeyspaces\let =\tie}} - -% Define \obeyedspace to be our active space, whatever it is. This is -% for use in \parsearg. -{\sepspaces% -\global\let\obeyedspace= } - -% This space is always present above and below environments. -\newskip\envskipamount \envskipamount = 0pt - -% Make spacing and below environment symmetrical. We use \parskip here -% to help in doing that, since in @example-like environments \parskip -% is reset to zero; thus the \afterenvbreak inserts no space -- but the -% start of the next paragraph will insert \parskip -% -\def\aboveenvbreak{{\advance\envskipamount by \parskip -\endgraf \ifdim\lastskip<\envskipamount -\removelastskip \penalty-50 \vskip\envskipamount \fi}} - -\let\afterenvbreak = \aboveenvbreak - -% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. -\let\nonarrowing=\relax - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% \cartouche: draw rectangle w/rounded corners around argument -\font\circle=lcircle10 -\newdimen\circthick -\newdimen\cartouter\newdimen\cartinner -\newskip\normbskip\newskip\normpskip\newskip\normlskip -\circthick=\fontdimen8\circle -% -\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth -\def\ctr{{\hskip 6pt\circle\char'010}} -\def\cbl{{\circle\char'012\hskip -6pt}} -\def\cbr{{\hskip 6pt\circle\char'011}} -\def\carttop{\hbox to \cartouter{\hskip\lskip - \ctl\leaders\hrule height\circthick\hfil\ctr - \hskip\rskip}} -\def\cartbot{\hbox to \cartouter{\hskip\lskip - \cbl\leaders\hrule height\circthick\hfil\cbr - \hskip\rskip}} -% -\newskip\lskip\newskip\rskip - -\long\def\cartouche{% -\begingroup - \lskip=\leftskip \rskip=\rightskip - \leftskip=0pt\rightskip=0pt %we want these *outside*. - \cartinner=\hsize \advance\cartinner by-\lskip - \advance\cartinner by-\rskip - \cartouter=\hsize - \advance\cartouter by 18pt % allow for 3pt kerns on either -% side, and for 6pt waste from -% each corner char - \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip - % Flag to tell @lisp, etc., not to narrow margin. - \let\nonarrowing=\comment - \vbox\bgroup - \baselineskip=0pt\parskip=0pt\lineskip=0pt - \carttop - \hbox\bgroup - \hskip\lskip - \vrule\kern3pt - \vbox\bgroup - \hsize=\cartinner - \kern3pt - \begingroup - \baselineskip=\normbskip - \lineskip=\normlskip - \parskip=\normpskip - \vskip -\parskip -\def\Ecartouche{% - \endgroup - \kern3pt - \egroup - \kern3pt\vrule - \hskip\rskip - \egroup - \cartbot - \egroup -\endgroup -}} - - -% This macro is called at the beginning of all the @example variants, -% inside a group. -\def\nonfillstart{% - \aboveenvbreak - \inENV % This group ends at the end of the body - \hfuzz = 12pt % Don't be fussy - \sepspaces % Make spaces be word-separators rather than space tokens. - \singlespace - \let\par = \lisppar % don't ignore blank lines - \obeylines % each line of input is a line of output - \parskip = 0pt - \parindent = 0pt - \emergencystretch = 0pt % don't try to avoid overfull boxes - % @cartouche defines \nonarrowing to inhibit narrowing - % at next level down. - \ifx\nonarrowing\relax - \advance \leftskip by \lispnarrowing - \exdentamount=\lispnarrowing - \let\exdent=\nofillexdent - \let\nonarrowing=\relax - \fi -} - -% To ending an @example-like environment, we first end the paragraph -% (via \afterenvbreak's vertical glue), and then the group. That way we -% keep the zero \parskip that the environments set -- \parskip glue -% will be inserted at the beginning of the next paragraph in the -% document, after the environment. -% -\def\nonfillfinish{\afterenvbreak\endgroup}% - -% This macro is -\def\lisp{\begingroup - \nonfillstart - \let\Elisp = \nonfillfinish - \tt - \rawbackslash % have \ input char produce \ char from current font - \gobble -} - -% Define the \E... control sequence only if we are inside the -% environment, so the error checking in \end will work. -% -% We must call \lisp last in the definition, since it reads the -% return following the @example (or whatever) command. -% -\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} -\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} -\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} - -% @smallexample and @smalllisp. This is not used unless the @smallbook -% command is given. Originally contributed by Pavel@xerox. -% -\def\smalllispx{\begingroup - \nonfillstart - \let\Esmalllisp = \nonfillfinish - \let\Esmallexample = \nonfillfinish - % - % Smaller interline space and fonts for small examples. - \setleading{10pt}% - \indexfonts \tt - \rawbackslash % make \ output the \ character from the current font (tt) - \gobble -} - -% This is @display; same as @lisp except use roman font. -% -\def\display{\begingroup - \nonfillstart - \let\Edisplay = \nonfillfinish - \gobble -} - -% This is @format; same as @display except don't narrow margins. -% -\def\format{\begingroup - \let\nonarrowing = t - \nonfillstart - \let\Eformat = \nonfillfinish - \gobble -} - -% @flushleft (same as @format) and @flushright. -% -\def\flushleft{\begingroup - \let\nonarrowing = t - \nonfillstart - \let\Eflushleft = \nonfillfinish - \gobble -} -\def\flushright{\begingroup - \let\nonarrowing = t - \nonfillstart - \let\Eflushright = \nonfillfinish - \advance\leftskip by 0pt plus 1fill - \gobble} - -% @quotation does normal linebreaking (hence we can't use \nonfillstart) -% and narrows the margins. -% -\def\quotation{% - \begingroup\inENV %This group ends at the end of the @quotation body - {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip - \singlespace - \parindent=0pt - % We have retained a nonzero parskip for the environment, since we're - % doing normal filling. So to avoid extra space below the environment... - \def\Equotation{\parskip = 0pt \nonfillfinish}% - % - % @cartouche defines \nonarrowing to inhibit narrowing at next level down. - \ifx\nonarrowing\relax - \advance\leftskip by \lispnarrowing - \advance\rightskip by \lispnarrowing - \exdentamount = \lispnarrowing - \let\nonarrowing = \relax - \fi -} - -\message{defuns,} -% Define formatter for defuns -% First, allow user to change definition object font (\df) internally -\def\setdeffont #1 {\csname DEF#1\endcsname} - -\newskip\defbodyindent \defbodyindent=.4in -\newskip\defargsindent \defargsindent=50pt -\newskip\deftypemargin \deftypemargin=12pt -\newskip\deflastargmargin \deflastargmargin=18pt - -\newcount\parencount -% define \functionparens, which makes ( and ) and & do special things. -% \functionparens affects the group it is contained in. -\def\activeparens{% -\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active -\catcode`\[=\active \catcode`\]=\active} - -% Make control sequences which act like normal parenthesis chars. -\let\lparen = ( \let\rparen = ) - -{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) - -% Be sure that we always have a definition for `(', etc. For example, -% if the fn name has parens in it, \boldbrax will not be in effect yet, -% so TeX would otherwise complain about undefined control sequence. -\global\let(=\lparen \global\let)=\rparen -\global\let[=\lbrack \global\let]=\rbrack - -\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } -\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} - -% Definitions of (, ) and & used in args for functions. -% This is the definition of ( outside of all parentheses. -\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % -\global\advance\parencount by 1 } -% -% This is the definition of ( when already inside a level of parens. -\gdef\opnested{\char`\(\global\advance\parencount by 1 } -% -\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. -% also in that case restore the outer-level definition of (. -\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi -\global\advance \parencount by -1 } -% If we encounter &foo, then turn on ()-hacking afterwards -\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } -% -\gdef\normalparens{\boldbrax\let&=\ampnr} -} % End of definition inside \activeparens -%% These parens (in \boldbrax) actually are a little bolder than the -%% contained text. This is especially needed for [ and ] -\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} -\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} - -% First, defname, which formats the header line itself. -% #1 should be the function name. -% #2 should be the type of definition, such as "Function". - -\def\defname #1#2{% -% Get the values of \leftskip and \rightskip as they were -% outside the @def... -\dimen2=\leftskip -\advance\dimen2 by -\defbodyindent -\dimen3=\rightskip -\advance\dimen3 by -\defbodyindent -\noindent % -\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% -\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line -\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations -\parshape 2 0in \dimen0 \defargsindent \dimen1 % -% Now output arg 2 ("Function" or some such) -% ending at \deftypemargin from the right margin, -% but stuck inside a box of width 0 so it does not interfere with linebreaking -{% Adjust \hsize to exclude the ambient margins, -% so that \rightline will obey them. -\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 -\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% -% Make all lines underfull and no complaints: -\tolerance=10000 \hbadness=10000 -\advance\leftskip by -\defbodyindent -\exdentamount=\defbodyindent -{\df #1}\enskip % Generate function name -} - -% Actually process the body of a definition -% #1 should be the terminating control sequence, such as \Edefun. -% #2 should be the "another name" control sequence, such as \defunx. -% #3 should be the control sequence that actually processes the header, -% such as \defunheader. - -\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup % -\catcode 61=\active % 61 is `=' -\obeylines\activeparens\spacesplit#3} - -\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} - -\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2##1 ##2 {\def#4{##1}% -\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} - -% These parsing functions are similar to the preceding ones -% except that they do not make parens into active characters. -% These are used for "variables" since they have no arguments. - -\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2{\begingroup\obeylines\spacesplit#3}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup % -\catcode 61=\active % -\obeylines\spacesplit#3} - -% This is used for \def{tp,vr}parsebody. It could probably be used for -% some of the others, too, with some judicious conditionals. -% -\def\parsebodycommon#1#2#3{% - \begingroup\inENV % - \medbreak % - % Define the end token that this defining construct specifies - % so that it will exit this group. - \def#1{\endgraf\endgroup\medbreak}% - \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% - \parindent=0in - \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent - \exdentamount=\defbodyindent - \begingroup\obeylines -} - -\def\defvrparsebody#1#2#3#4 {% - \parsebodycommon{#1}{#2}{#3}% - \spacesplit{#3{#4}}% -} - -% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the -% type is just `struct', because we lose the braces in `{struct -% termios}' when \spacesplit reads its undelimited argument. Sigh. -% \let\deftpparsebody=\defvrparsebody -% -% So, to get around this, we put \empty in with the type name. That -% way, TeX won't find exactly `{...}' as an undelimited argument, and -% won't strip off the braces. -% -\def\deftpparsebody #1#2#3#4 {% - \parsebodycommon{#1}{#2}{#3}% - \spacesplit{\parsetpheaderline{#3{#4}}}\empty -} - -% Fine, but then we have to eventually remove the \empty *and* the -% braces (if any). That's what this does, putting the result in \tptemp. -% -\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% - -% After \spacesplit has done its work, this is called -- #1 is the final -% thing to call, #2 the type name (which starts with \empty), and #3 -% (which might be empty) the arguments. -% -\def\parsetpheaderline#1#2#3{% - \removeemptybraces#2\relax - #1{\tptemp}{#3}% -}% - -\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % -\medbreak % -% Define the end token that this defining construct specifies -% so that it will exit this group. -\def#1{\endgraf\endgroup\medbreak}% -\def#2##1 ##2 {\def#4{##1}% -\begingroup\obeylines\spacesplit{#3{##2}}}% -\parindent=0in -\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent -\exdentamount=\defbodyindent -\begingroup\obeylines\spacesplit{#3{#5}}} - -% Split up #2 at the first space token. -% call #1 with two arguments: -% the first is all of #2 before the space token, -% the second is all of #2 after that space token. -% If #2 contains no space token, all of it is passed as the first arg -% and the second is passed as empty. - -{\obeylines -\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% -\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% -\ifx\relax #3% -#1{#2}{}\else #1{#2}{#3#4}\fi}} - -% So much for the things common to all kinds of definitions. - -% Define @defun. - -% First, define the processing that is wanted for arguments of \defun -% Use this to expand the args and terminate the paragraph they make up - -\def\defunargs #1{\functionparens \sl -% Expand, preventing hyphenation at `-' chars. -% Note that groups don't affect changes in \hyphenchar. -\hyphenchar\tensl=0 -#1% -\hyphenchar\tensl=45 -\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% -\interlinepenalty=10000 -\advance\rightskip by 0pt plus 1fil -\endgraf\penalty 10000\vskip -\parskip\penalty 10000% -} - -\def\deftypefunargs #1{% -% Expand, preventing hyphenation at `-' chars. -% Note that groups don't affect changes in \hyphenchar. -\functionparens -\tclose{#1}% avoid \code because of side effects on active chars -\interlinepenalty=10000 -\advance\rightskip by 0pt plus 1fil -\endgraf\penalty 10000\vskip -\parskip\penalty 10000% -} - -% Do complete processing of one @defun or @defunx line already parsed. - -% @deffn Command forward-char nchars - -\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} - -\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% -\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % -\catcode 61=\other % Turn off change made in \defparsebody -} - -% @defun == @deffn Function - -\def\defun{\defparsebody\Edefun\defunx\defunheader} - -\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index -\begingroup\defname {#1}{Function}% -\defunargs {#2}\endgroup % -\catcode 61=\other % Turn off change made in \defparsebody -} - -% @deftypefun int foobar (int @var{foo}, float @var{bar}) - -\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} - -% #1 is the data type. #2 is the name and args. -\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} -% #1 is the data type, #2 the name, #3 the args. -\def\deftypefunheaderx #1#2 #3\relax{% -\doind {fn}{\code{#2}}% Make entry in function index -\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% -\deftypefunargs {#3}\endgroup % -\catcode 61=\other % Turn off change made in \defparsebody -} - -% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) - -\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} - -% \defheaderxcond#1\relax$$$ -% puts #1 in @code, followed by a space, but does nothing if #1 is null. -\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} - -% #1 is the classification. #2 is the data type. #3 is the name and args. -\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} -% #1 is the classification, #2 the data type, #3 the name, #4 the args. -\def\deftypefnheaderx #1#2#3 #4\relax{% -\doind {fn}{\code{#3}}% Make entry in function index -\begingroup -\normalparens % notably, turn off `&' magic, which prevents -% at least some C++ text from working -\defname {\defheaderxcond#2\relax$$$#3}{#1}% -\deftypefunargs {#4}\endgroup % -\catcode 61=\other % Turn off change made in \defparsebody -} - -% @defmac == @deffn Macro - -\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} - -\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index -\begingroup\defname {#1}{Macro}% -\defunargs {#2}\endgroup % -\catcode 61=\other % Turn off change made in \defparsebody -} - -% @defspec == @deffn Special Form - -\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} - -\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index -\begingroup\defname {#1}{Special Form}% -\defunargs {#2}\endgroup % -\catcode 61=\other % Turn off change made in \defparsebody -} - -% This definition is run if you use @defunx -% anywhere other than immediately after a @defun or @defunx. - -\def\deffnx #1 {\errmessage{@deffnx in invalid context}} -\def\defunx #1 {\errmessage{@defunx in invalid context}} -\def\defmacx #1 {\errmessage{@defmacx in invalid context}} -\def\defspecx #1 {\errmessage{@defspecx in invalid context}} -\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} -\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} - -% @defmethod, and so on - -% @defop {Funny Method} foo-class frobnicate argument - -\def\defop #1 {\def\defoptype{#1}% -\defopparsebody\Edefop\defopx\defopheader\defoptype} - -\def\defopheader #1#2#3{% -\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index -\begingroup\defname {#2}{\defoptype{} on #1}% -\defunargs {#3}\endgroup % -} - -% @defmethod == @defop Method - -\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} - -\def\defmethodheader #1#2#3{% -\dosubind {fn}{\code{#2}}{on #1}% entry in function index -\begingroup\defname {#2}{Method on #1}% -\defunargs {#3}\endgroup % -} - -% @defcv {Class Option} foo-class foo-flag - -\def\defcv #1 {\def\defcvtype{#1}% -\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} - -\def\defcvarheader #1#2#3{% -\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index -\begingroup\defname {#2}{\defcvtype{} of #1}% -\defvarargs {#3}\endgroup % -} - -% @defivar == @defcv {Instance Variable} - -\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} - -\def\defivarheader #1#2#3{% -\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index -\begingroup\defname {#2}{Instance Variable of #1}% -\defvarargs {#3}\endgroup % -} - -% These definitions are run if you use @defmethodx, etc., -% anywhere other than immediately after a @defmethod, etc. - -\def\defopx #1 {\errmessage{@defopx in invalid context}} -\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} -\def\defcvx #1 {\errmessage{@defcvx in invalid context}} -\def\defivarx #1 {\errmessage{@defivarx in invalid context}} - -% Now @defvar - -% First, define the processing that is wanted for arguments of @defvar. -% This is actually simple: just print them in roman. -% This must expand the args and terminate the paragraph they make up -\def\defvarargs #1{\normalparens #1% -\interlinepenalty=10000 -\endgraf\penalty 10000\vskip -\parskip\penalty 10000} - -% @defvr Counter foo-count - -\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} - -\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% -\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} - -% @defvar == @defvr Variable - -\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} - -\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index -\begingroup\defname {#1}{Variable}% -\defvarargs {#2}\endgroup % -} - -% @defopt == @defvr {User Option} - -\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} - -\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index -\begingroup\defname {#1}{User Option}% -\defvarargs {#2}\endgroup % -} - -% @deftypevar int foobar - -\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} - -% #1 is the data type. #2 is the name. -\def\deftypevarheader #1#2{% -\doind {vr}{\code{#2}}% Make entry in variables index -\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% -\interlinepenalty=10000 -\endgraf\penalty 10000\vskip -\parskip\penalty 10000 -\endgroup} - -% @deftypevr {Global Flag} int enable - -\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} - -\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% -\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} -\interlinepenalty=10000 -\endgraf\penalty 10000\vskip -\parskip\penalty 10000 -\endgroup} - -% This definition is run if you use @defvarx -% anywhere other than immediately after a @defvar or @defvarx. - -\def\defvrx #1 {\errmessage{@defvrx in invalid context}} -\def\defvarx #1 {\errmessage{@defvarx in invalid context}} -\def\defoptx #1 {\errmessage{@defoptx in invalid context}} -\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} -\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} - -% Now define @deftp -% Args are printed in bold, a slight difference from @defvar. - -\def\deftpargs #1{\bf \defvarargs{#1}} - -% @deftp Class window height width ... - -\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} - -\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% -\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} - -% This definition is run if you use @deftpx, etc -% anywhere other than immediately after a @deftp, etc. - -\def\deftpx #1 {\errmessage{@deftpx in invalid context}} - -\message{cross reference,} -% Define cross-reference macros -\newwrite \auxfile - -\newif\ifhavexrefs % True if xref values are known. -\newif\ifwarnedxrefs % True if we warned once that they aren't known. - -% \setref{foo} defines a cross-reference point named foo. - -\def\setref#1{% -\dosetq{#1-title}{Ytitle}% -\dosetq{#1-pg}{Ypagenumber}% -\dosetq{#1-snt}{Ysectionnumberandtype}} - -\def\unnumbsetref#1{% -\dosetq{#1-title}{Ytitle}% -\dosetq{#1-pg}{Ypagenumber}% -\dosetq{#1-snt}{Ynothing}} - -\def\appendixsetref#1{% -\dosetq{#1-title}{Ytitle}% -\dosetq{#1-pg}{Ypagenumber}% -\dosetq{#1-snt}{Yappendixletterandtype}} - -% \xref, \pxref, and \ref generate cross-references to specified points. -% For \xrefX, #1 is the node name, #2 the name of the Info -% cross-reference, #3 the printed node name, #4 the name of the Info -% file, #5 the name of the printed manual. All but the node name can be -% omitted. -% -\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} -\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} -\def\ref#1{\xrefX[#1,,,,,,,]} -\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup - \def\printedmanual{\ignorespaces #5}% - \def\printednodename{\ignorespaces #3}% - \setbox1=\hbox{\printedmanual}% - \setbox0=\hbox{\printednodename}% - \ifdim \wd0 = 0pt - % No printed node name was explicitly given. - \ifx\SETxref-automatic-section-title\relax % - % Use the actual chapter/section title appear inside - % the square brackets. Use the real section title if we have it. - \ifdim \wd1>0pt% - % It is in another manual, so we don't have it. - \def\printednodename{\ignorespaces #1}% - \else - \ifhavexrefs - % We know the real title if we have the xref values. - \def\printednodename{\refx{#1-title}}% - \else - % Otherwise just copy the Info node name. - \def\printednodename{\ignorespaces #1}% - \fi% - \fi - \def\printednodename{#1-title}% - \else - % Use the node name inside the square brackets. - \def\printednodename{\ignorespaces #1}% - \fi - \fi - % - % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not - % insert empty discretionaries after hyphens, which means that it will - % not find a line break at a hyphen in a node names. Since some manuals - % are best written with fairly long node names, containing hyphens, this - % is a loss. Therefore, we give the text of the node name again, so it - % is as if TeX is seeing it for the first time. - \ifdim \wd1 > 0pt - \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% - \else - % _ (for example) has to be the character _ for the purposes of the - % control sequence corresponding to the node, but it has to expand - % into the usual \leavevmode...\vrule stuff for purposes of - % printing. So we \turnoffactive for the \refx-snt, back on for the - % printing, back off for the \refx-pg. - {\turnoffactive \refx{#1-snt}{}}% - \space [\printednodename],\space - \turnoffactive \putwordpage\tie\refx{#1-pg}{}% - \fi -\endgroup} - -% \dosetq is the interface for calls from other macros - -% Use \turnoffactive so that punctuation chars such as underscore -% work in node names. -\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat% -\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% -\next}} - -% \internalsetq {foo}{page} expands into -% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} -% When the aux file is read, ' is the escape character - -\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} - -% Things to be expanded by \internalsetq - -\def\Ypagenumber{\folio} - -\def\Ytitle{\thissection} - -\def\Ynothing{} - -\def\Ysectionnumberandtype{% -\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % -\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % -\else \ifnum \subsubsecno=0 % -\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % -\else % -\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % -\fi \fi \fi } - -\def\Yappendixletterandtype{% -\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% -\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % -\else \ifnum \subsubsecno=0 % -\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % -\else % -\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % -\fi \fi \fi } - -\gdef\xreftie{'tie} - -% Use TeX 3.0's \inputlineno to get the line number, for better error -% messages, but if we're using an old version of TeX, don't do anything. -% -\ifx\inputlineno\thisisundefined - \let\linenumber = \empty % Non-3.0. -\else - \def\linenumber{\the\inputlineno:\space} -\fi - -% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. -% If its value is nonempty, SUFFIX is output afterward. - -\def\refx#1#2{% - \expandafter\ifx\csname X#1\endcsname\relax - % If not defined, say something at least. - $\langle$un\-de\-fined$\rangle$% - \ifhavexrefs - \message{\linenumber Undefined cross reference `#1'.}% - \else - \ifwarnedxrefs\else - \global\warnedxrefstrue - \message{Cross reference values unknown; you must run TeX again.}% - \fi - \fi - \else - % It's defined, so just use it. - \csname X#1\endcsname - \fi - #2% Output the suffix in any case. -} - -% Read the last existing aux file, if any. No error if none exists. - -% This is the macro invoked by entries in the aux file. -\def\xrdef #1#2{ -{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} - -\def\readauxfile{% -\begingroup -\catcode `\^^@=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\^^C=\other -\catcode `\^^D=\other -\catcode `\^^E=\other -\catcode `\^^F=\other -\catcode `\^^G=\other -\catcode `\^^H=\other -\catcode `\=\other -\catcode `\^^L=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode `\=\other -\catcode 26=\other -\catcode `\^^[=\other -\catcode `\^^\=\other -\catcode `\^^]=\other -\catcode `\^^^=\other -\catcode `\^^_=\other -\catcode `\@=\other -\catcode `\^=\other -\catcode `\~=\other -\catcode `\[=\other -\catcode `\]=\other -\catcode`\"=\other -\catcode`\_=\other -\catcode`\|=\other -\catcode`\<=\other -\catcode`\>=\other -\catcode `\$=\other -\catcode `\#=\other -\catcode `\&=\other -% `\+ does not work, so use 43. -\catcode 43=\other -% Make the characters 128-255 be printing characters -{% - \count 1=128 - \def\loop{% - \catcode\count 1=\other - \advance\count 1 by 1 - \ifnum \count 1<256 \loop \fi - }% -}% -% the aux file uses ' as the escape. -% Turn off \ as an escape so we do not lose on -% entries which were dumped with control sequences in their names. -% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ -% Reference to such entries still does not work the way one would wish, -% but at least they do not bomb out when the aux file is read in. -\catcode `\{=1 \catcode `\}=2 -\catcode `\%=\other -\catcode `\'=0 -\catcode`\^=7 % to make ^^e4 etc usable in xref tags -\catcode `\\=\other -\openin 1 \jobname.aux -\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue -\global\warnedobstrue -\fi -% Open the new aux file. Tex will close it automatically at exit. -\openout \auxfile=\jobname.aux -\endgroup} - - -% Footnotes. - -\newcount \footnoteno - -% The trailing space in the following definition for supereject is -% vital for proper filling; pages come out unaligned when you do a -% pagealignmacro call if that space before the closing brace is -% removed. -\def\supereject{\par\penalty -20000\footnoteno =0 } - -% @footnotestyle is meaningful for info output only.. -\let\footnotestyle=\comment - -\let\ptexfootnote=\footnote - -{\catcode `\@=11 -% -% Auto-number footnotes. Otherwise like plain. -\gdef\footnote{% - \global\advance\footnoteno by \@ne - \edef\thisfootno{$^{\the\footnoteno}$}% - % - % In case the footnote comes at the end of a sentence, preserve the - % extra spacing after we do the footnote number. - \let\@sf\empty - \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi - % - % Remove inadvertent blank space before typesetting the footnote number. - \unskip - \thisfootno\@sf - \footnotezzz -}% - -% Don't bother with the trickery in plain.tex to not require the -% footnote text as a parameter. Our footnotes don't need to be so general. -% -\long\gdef\footnotezzz#1{\insert\footins{% - % We want to typeset this text as a normal paragraph, even if the - % footnote reference occurs in (for example) a display environment. - % So reset some parameters. - \interlinepenalty\interfootnotelinepenalty - \splittopskip\ht\strutbox % top baseline for broken footnotes - \splitmaxdepth\dp\strutbox - \floatingpenalty\@MM - \leftskip\z@skip - \rightskip\z@skip - \spaceskip\z@skip - \xspaceskip\z@skip - \parindent\defaultparindent - % - % Hang the footnote text off the number. - \hang - \textindent{\thisfootno}% - % - % Don't crash into the line above the footnote text. Since this - % expands into a box, it must come within the paragraph, lest it - % provide a place where TeX can split the footnote. - \footstrut - #1\strut}% -} - -}%end \catcode `\@=11 - -% Set the baselineskip to #1, and the lineskip and strut size -% correspondingly. There is no deep meaning behind these magic numbers -% used as factors; they just match (closely enough) what Knuth defined. -% -\def\lineskipfactor{.08333} -\def\strutheightpercent{.70833} -\def\strutdepthpercent {.29167} -% -\def\setleading#1{% - \normalbaselineskip = #1\relax - \normallineskip = \lineskipfactor\normalbaselineskip - \normalbaselines - \setbox\strutbox =\hbox{% - \vrule width0pt height\strutheightpercent\baselineskip - depth \strutdepthpercent \baselineskip - }% -} - -% @| inserts a changebar to the left of the current line. It should -% surround any changed text. This approach does *not* work if the -% change spans more than two lines of output. To handle that, we would -% have adopt a much more difficult approach (putting marks into the main -% vertical list for the beginning and end of each change). -% -\def\|{% - % \vadjust can only be used in horizontal mode. - \leavevmode - % - % Append this vertical mode material after the current line in the output. - \vadjust{% - % We want to insert a rule with the height and depth of the current - % leading; that is exactly what \strutbox is supposed to record. - \vskip-\baselineskip - % - % \vadjust-items are inserted at the left edge of the type. So - % the \llap here moves out into the left-hand margin. - \llap{% - % - % For a thicker or thinner bar, change the `1pt'. - \vrule height\baselineskip width1pt - % - % This is the space between the bar and the text. - \hskip 12pt - }% - }% -} - -% For a final copy, take out the rectangles -% that mark overfull boxes (in case you have decided -% that the text looks ok even though it passes the margin). -% -\def\finalout{\overfullrule=0pt} - - -% End of control word definitions. - -\message{and turning on texinfo input format.} - -\def\openindices{% - \newindex{cp}% - \newcodeindex{fn}% - \newcodeindex{vr}% - \newcodeindex{tp}% - \newcodeindex{ky}% - \newcodeindex{pg}% -} - -% Set some numeric style parameters, for 8.5 x 11 format. - -%\hsize = 6.5in -\newdimen\defaultparindent \defaultparindent = 15pt -\parindent = \defaultparindent -\parskip 18pt plus 1pt -\setleading{15pt} -\advance\topskip by 1.2cm - -% Prevent underfull vbox error messages. -\vbadness=10000 - -% Following George Bush, just get rid of widows and orphans. -\widowpenalty=10000 -\clubpenalty=10000 - -% Use TeX 3.0's \emergencystretch to help line breaking, but if we're -% using an old version of TeX, don't do anything. We want the amount of -% stretch added to depend on the line length, hence the dependence on -% \hsize. This makes it come to about 9pt for the 8.5x11 format. -% -\ifx\emergencystretch\thisisundefined - % Allow us to assign to \emergencystretch anyway. - \def\emergencystretch{\dimen0}% -\else - \emergencystretch = \hsize - \divide\emergencystretch by 45 -\fi - -% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) -\def\smallbook{ - -% These values for secheadingskip and subsecheadingskip are -% experiments. RJC 7 Aug 1992 -\global\secheadingskip = 17pt plus 6pt minus 3pt -\global\subsecheadingskip = 14pt plus 6pt minus 3pt - -\global\lispnarrowing = 0.3in -\setleading{12pt} -\advance\topskip by -1cm -\global\parskip 3pt plus 1pt -\global\hsize = 5in -\global\vsize=7.5in -\global\tolerance=700 -\global\hfuzz=1pt -\global\contentsrightmargin=0pt -\global\deftypemargin=0pt -\global\defbodyindent=.5cm - -\global\pagewidth=\hsize -\global\pageheight=\vsize - -\global\let\smalllisp=\smalllispx -\global\let\smallexample=\smalllispx -\global\def\Esmallexample{\Esmalllisp} -} - -% Use @afourpaper to print on European A4 paper. -\def\afourpaper{ -\global\tolerance=700 -\global\hfuzz=1pt -\setleading{12pt} -\global\parskip 15pt plus 1pt - -\global\vsize= 53\baselineskip -\advance\vsize by \topskip -%\global\hsize= 5.85in % A4 wide 10pt -\global\hsize= 6.5in -\global\outerhsize=\hsize -\global\advance\outerhsize by 0.5in -\global\outervsize=\vsize -\global\advance\outervsize by 0.6in - -\global\pagewidth=\hsize -\global\pageheight=\vsize -} - -% Allow control of the text dimensions. Parameters in order: textheight; -% textwidth; \voffset; \hoffset (!); binding offset. All require a dimension; -% header is additional; added length extends the bottom of the page. - -\def\changepagesizes#1#2#3#4#5{ - \global\vsize= #1 - \advance\vsize by \topskip - \global\voffset= #3 - \global\hsize= #2 - \global\outerhsize=\hsize - \global\advance\outerhsize by 0.5in - \global\outervsize=\vsize - \global\advance\outervsize by 0.6in - \global\pagewidth=\hsize - \global\pageheight=\vsize - \global\normaloffset= #4 - \global\bindingoffset= #5} - -% This layout is compatible with Latex on A4 paper. - -\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}} - -% Define macros to output various characters with catcode for normal text. -\catcode`\"=\other -\catcode`\~=\other -\catcode`\^=\other -\catcode`\_=\other -\catcode`\|=\other -\catcode`\<=\other -\catcode`\>=\other -\catcode`\+=\other -\def\normaldoublequote{"} -\def\normaltilde{~} -\def\normalcaret{^} -\def\normalunderscore{_} -\def\normalverticalbar{|} -\def\normalless{<} -\def\normalgreater{>} -\def\normalplus{+} - -% This macro is used to make a character print one way in ttfont -% where it can probably just be output, and another way in other fonts, -% where something hairier probably needs to be done. -% -% #1 is what to print if we are indeed using \tt; #2 is what to print -% otherwise. Since all the Computer Modern typewriter fonts have zero -% interword stretch (and shrink), and it is reasonable to expect all -% typewriter fonts to have this, we can check that font parameter. -% -\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} - -% Turn off all special characters except @ -% (and those which the user can use as if they were ordinary). -% Most of these we simply print from the \tt font, but for some, we can -% use math or other variants that look better in normal text. - -\catcode`\"=\active -\def\activedoublequote{{\tt \char '042}} -\let"=\activedoublequote -\catcode`\~=\active -\def~{{\tt \char '176}} -\chardef\hat=`\^ -\catcode`\^=\active -\def\auxhat{\def^{'hat}} -\def^{{\tt \hat}} - -\catcode`\_=\active -\def_{\ifusingtt\normalunderscore\_} -% Subroutine for the previous macro. -\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}} - -% \lvvmode is equivalent in function to \leavevmode. -% Using \leavevmode runs into trouble when written out to -% an index file due to the expansion of \leavevmode into ``\unhbox -% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our -% magic tricks with @. -\def\lvvmode{\vbox to 0pt{}} - -\catcode`\|=\active -\def|{{\tt \char '174}} -\chardef \less=`\< -\catcode`\<=\active -\def<{{\tt \less}} -\chardef \gtr=`\> -\catcode`\>=\active -\def>{{\tt \gtr}} -\catcode`\+=\active -\def+{{\tt \char 43}} -%\catcode 27=\active -%\def^^[{$\diamondsuit$} - -% Set up an active definition for =, but don't enable it most of the time. -{\catcode`\==\active -\global\def={{\tt \char 61}}} - -\catcode`\@=0 - -% \rawbackslashxx output one backslash character in current font -\global\chardef\rawbackslashxx=`\\ -%{\catcode`\\=\other -%@gdef@rawbackslashxx{\}} - -% \rawbackslash redefines \ as input to do \rawbackslashxx. -{\catcode`\\=\active -@gdef@rawbackslash{@let\=@rawbackslashxx }} - -% \normalbackslash outputs one backslash in fixed width font. -\def\normalbackslash{{\tt\rawbackslashxx}} - -% Say @foo, not \foo, in error messages. -\escapechar=`\@ - -% \catcode 17=0 % Define control-q -\catcode`\\=\active - -% Used sometimes to turn off (effectively) the active characters -% even after parsing them. -@def@turnoffactive{@let"=@normaldoublequote -@let\=@realbackslash -@let~=@normaltilde -@let^=@normalcaret -@let_=@normalunderscore -@let|=@normalverticalbar -@let<=@normalless -@let>=@normalgreater -@let+=@normalplus} - -@def@normalturnoffactive{@let"=@normaldoublequote -@let\=@normalbackslash -@let~=@normaltilde -@let^=@normalcaret -@let_=@normalunderscore -@let|=@normalverticalbar -@let<=@normalless -@let>=@normalgreater -@let+=@normalplus} - -% If a .fmt file is being used, we don't want the `\input texinfo' to show up. -% That is what \eatinput is for; after that, the `\' should revert to printing -% a backslash. -% -@gdef@eatinput input texinfo{@fixbackslash} -@global@let\ = @eatinput - -% On the other hand, perhaps the file did not have a `\input texinfo'. Then -% the first `\{ in the file would cause an error. This macro tries to fix -% that, assuming it is called before the first `\' could plausibly occur. -% -@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi} - -%% These look ok in all fonts, so just make them not special. The @rm below -%% makes sure that the current font starts out as the newly loaded cmr10 -@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other - -@textfonts -@rm - -@c Local variables: -@c page-delimiter: "^\\\\message" -@c End: diff --git a/contrib/rcslock.pl b/contrib/rcslock.pl deleted file mode 100644 index db09b4bf2adec823d99fd0f0c9b9ef6419f77ace..0000000000000000000000000000000000000000 --- a/contrib/rcslock.pl +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/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/cvs-format.el b/cvs-format.el deleted file mode 100644 index 5e70429940b6c0eb5c5710cc88a98105be53ca4e..0000000000000000000000000000000000000000 --- a/cvs-format.el +++ /dev/null @@ -1,75 +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) - -;; 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/cvsinit.sh b/cvsinit.sh deleted file mode 100644 index 61f3a101fbe2280fa8d8d57d4336c70f4553c02a..0000000000000000000000000000000000000000 --- a/cvsinit.sh +++ /dev/null @@ -1,239 +0,0 @@ -#! /bin/sh -: -# -# Copyright (c) 1992, Brian Berliner -# -# You may distribute under the terms of the GNU General Public License as -# specified in the README file that comes with the CVS 1.4 kit. -# -# $CVSid: @(#)cvsinit.sh 1.1 94/10/22 $ -# -# This script should be run once to help you setup your site for CVS. - -# this line is edited by Makefile when creating cvsinit.inst -CVSLIB="xLIBDIRx" - -# 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 - remind_cvsroot=yes -else - echo "Using $CVSROOT as the source repository." - remind_cvsroot=no -fi -echo "" - -# Now, create the $CVSROOT if it is not already there -if [ ! -d $CVSROOT ]; then - echo "Hmmm... $CVSROOT does not exist; trying to make it..." - path= - for comp in `echo $CVSROOT | sed -e 's,/, ,g'`; do - path=$path/$comp - if [ ! -d $path ]; then - mkdir $path - fi - done -else - echo "Good... $CVSROOT already exists." -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 "Making the $CVSROOT/CVSROOT directory..." - mkdir $CVSROOT/CVSROOT - fi -else - echo "Wow!... so does $CVSROOT/CVSROOT." -fi -echo "" -if [ ! -d $CVSROOT/CVSROOT ]; then - echo "You still don't have a $CVSROOT/CVSROOT directory." - echo "I give up." - exit 1 -fi - -# Create the special *info files within $CVSROOT/CVSROOT - -# Trump up a simple modules file, if one doesn't exist -if [ -f $CVSROOT/CVSROOT/modules,v ]; then - if [ ! -f $CVSROOT/CVSROOT/modules ]; then - echo "You have a $CVSROOT/CVSROOT/modules,v file," - echo "But no $CVSROOT/CVSROOT/modules file. This is OK." - echo "I'll checkout a fresh copy..." - (cd $CVSROOT/CVSROOT; co -q modules) - echo "" - fi -else - if [ -f $CVSROOT/CVSROOT/modules ]; then - echo "You have a $CVSROOT/CVSROOT/modules file," - echo "But no $CVSROOT/CVSROOT/modules,v file." - echo "I'll create one for you, but otherwise leave it alone..." - else - echo "The $CVSROOT/CVSROOT/modules file does not exist." - echo "Making a simple one for you..." - cat > $CVSROOT/CVSROOT/modules <<"HERE" -# -# The CVS modules file -# -# 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. -# -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; run mkmodules whenever anything changes. -CVSROOT -i mkmodules CVSROOT -modules -i mkmodules CVSROOT modules -loginfo -i mkmodules CVSROOT loginfo -commitinfo -i mkmodules CVSROOT commitinfo -rcsinfo -i mkmodules CVSROOT rcsinfo -editinfo -i mkmodules CVSROOT editinfo - -# Add other modules here... -HERE - fi - (cd $CVSROOT/CVSROOT; ci -q -u -t/dev/null -m'initial checkin of modules' modules) - 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 - -# loginfo, like modules, is special-cased -if [ -f $CVSROOT/CVSROOT/loginfo,v ]; then - if [ ! -f $CVSROOT/CVSROOT/loginfo ]; then - echo "You have a $CVSROOT/CVSROOT/loginfo,v file," - echo "But no $CVSROOT/CVSROOT/loginfo file. This is OK." - echo "I'll checkout a fresh copy..." - (cd $CVSROOT/CVSROOT; co -q loginfo) - echo "" - fi -else - if [ -f $CVSROOT/CVSROOT/loginfo ]; then - echo "You have a $CVSROOT/CVSROOT/loginfo file," - echo "But no $CVSROOT/CVSROOT/loginfo,v file." - echo "I'll create one for you, but otherwise leave it alone..." - else - echo "The $CVSROOT/CVSROOT/loginfo file does not exist." - echo "Making a simple one for you..." - # try to find perl; use fancy log script if we can - for perlpath in `echo $PATH | sed -e 's/:/ /g'` x; do - if [ -f $perlpath/perl ]; then - echo "#!$perlpath/perl" > $CVSROOT/CVSROOT/log.pl - cat $CVSLIB/contrib/log.pl >> $CVSROOT/CVSROOT/log.pl - chmod 755 $CVSROOT/CVSROOT/log.pl - cp $CVSLIB/examples/loginfo $CVSROOT/CVSROOT/loginfo - break - fi - done - if [ $perlpath = x ]; then - # we did not find perl anywhere, so make a simple loginfo file - cat > $CVSROOT/CVSROOT/loginfo <<"HERE" -# -# 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. 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 (ala printf). If -# %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 "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 (echo ""; echo $USER; date; cat) >> $CVSROOT/CVSROOT/commitlog -HERE - fi - fi - (cd $CVSROOT/CVSROOT; ci -q -u -t/dev/null -m'initial checkin of loginfo' loginfo) - echo "" -fi - -# The remaining files are generated from the examples files. -for info in commitinfo rcsinfo editinfo; do - if [ -f $CVSROOT/CVSROOT/${info},v ]; then - if [ ! -f $CVSROOT/CVSROOT/$info ]; then - echo "You have a $CVSROOT/CVSROOT/${info},v file," - echo "But no $CVSROOT/CVSROOT/$info file. This is OK." - echo "I'll checkout a fresh copy..." - (cd $CVSROOT/CVSROOT; co -q $info) - echo "" - fi - else - if [ -f $CVSROOT/CVSROOT/$info ]; then - echo "You have a $CVSROOT/CVSROOT/$info file," - echo "But no $CVSROOT/CVSROOT/${info},v file." - echo "I'll create one for you, but otherwise leave it alone..." - else - echo "The $CVSROOT/CVSROOT/$info file does not exist." - echo "Making a simple one for you..." - sed -e 's/^\([^#]\)/#\1/' $CVSLIB/examples/$info > $CVSROOT/CVSROOT/$info - fi - (cd $CVSROOT/CVSROOT; ci -q -u -t/dev/null -m"initial checkin of $info" $info) - echo "" - fi -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 - echo "" -fi - -# finish up by running mkmodules -echo "All done! Running 'mkmodules' as my final step..." -mkmodules $CVSROOT/CVSROOT - -# and, if necessary, remind them about setting CVSROOT -if [ $remind_cvsroot = yes ]; then - echo "Remember to set the CVSROOT environment variable in your login script" -fi - -exit 0 diff --git a/doc/.cvsignore b/doc/.cvsignore deleted file mode 100644 index 1bf8a43be599446f0e4239341983725cca58c2c9..0000000000000000000000000000000000000000 --- a/doc/.cvsignore +++ /dev/null @@ -1,18 +0,0 @@ -*.dvi -Makefile -cvs-paper.ps -cvs.aux -cvs.cp -cvs.cps -cvs.dvi -cvs.fn -cvs.info -cvs.info-* -cvs.ky -cvs.log -cvs.pg -cvs.ps -cvs.toc -cvs.tp -cvs.vr -cvsclient.info diff --git a/doc/ChangeLog b/doc/ChangeLog deleted file mode 100644 index 69bc049179b53b49c77eab5ef003982d59520b4e..0000000000000000000000000000000000000000 --- a/doc/ChangeLog +++ /dev/null @@ -1,110 +0,0 @@ -Mon Nov 28 10:22:46 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Notes): Remove item about commit options; now - fixed. Rewrite paragraph about server memory usage. - - * cvsclient.texi (Responses): Add Set-checkin-prog and - Set-update-prog. - (Requests): Add Checkin-prog and Update-prog. - * cvsclient.texi (TODO): Remove last item (it is fixed) and node. - -Fri Nov 18 16:51:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Requests): Add Max-dotdot. - -Thu Nov 3 07:04:24 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Add Directory request. - (TODO): Remove item about renaming directories. - (Protocol): Change @subheading to @node/@section. - -Fri Oct 28 07:51:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Add expand-module request and - Module-expansion response. - (Protocol Notes, TODO): Remove items about cvs co funkiness. - -Wed Oct 12 19:49:36 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Add Copy-file response. - - * cvsclient.texi (How To): Correct item about where declaration - of cvs commands go. - - * cvsclient.texi (Protocol): Add new commands. Merge description - of how commands work which was duplicated among the various - commands. Formatting cleanups. - (TODO): Remove item about bad error message on checking in a - nonexistent file; this works now (presumably fixed by the - Unchanged stuff). - (Notes): Remove thing about trying unsupported commands via NFS, - rdist, etc. Also remove item about some commands not being - supported. There are no unsupported commands anymore. - -Tue Sep 13 13:28:52 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Document New-entry response. - -Mon Sep 12 06:35:15 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Clarify that checksum is of patched - file, not patch itself. Fix typo (valid-requests -> Valid-requests). - - * cvsclient.texi (Protocol): Document Sticky request and - Set-sticky and Clear-sticky responses. - (Notes): Remove sticky tags from todo list. - -Thu Sep 8 14:23:58 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Document Static-directory requests - and Set-static-directory and Clear-static-directory responses. - (Notes): Remove Entries.Static support from todo list. - - * cvsclient.texi (Protocol): Document Unchanged and UseUnchanged - requests. Update documentation of Entry and Lost accordingly. - -Mon Aug 22 14:08:21 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Goals): Remove mention of rsh. - (Protocol Notes, TODO): Remove compression item. - (Protocol): Document "status" request. - (TODO): Remove suggestion to add "cvs status". - -Tue Jul 19 10:02:53 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * Makefile.in (install-info): Do not depend upon installdirs. - -Fri Jul 15 12:56:53 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * Makefile.in (all): Do not depend upon info. - (install): Do not depend upon install-info. - -Thu Jul 7 20:43:12 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * cvsclient.texi (Protocol): Add Checksum response. - -Thu Jun 30 15:16:50 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Add Global_option request. - -Wed Jun 29 14:09:42 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * cvsclient.texi: Describe sending patches, including the dummy - update-patches request and the Patched response. Mention Kerberos - authentication using ``cvs kserver''. Some other minor changes. - -Tue Jun 28 15:21:06 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol Notes): Remove note about sending diffs - in Updated; Ian did it. Remove note about adding encryption to rsh. - -Sat May 7 10:44:30 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi (Protocol): Document Modified without Entry. Add - `add' and `remove' and `Remove-entry'. Formatting cleanups. - -Tue Apr 19 01:29:04 1994 John Gilmore (gnu@cygnus.com) - - * cvsclient.texi: New node How To; cleanups throughout. - * Makefile.in: Add dependencies on cvsclient.texi. - diff --git a/doc/ChangeLog.fsf b/doc/ChangeLog.fsf deleted file mode 100644 index 2f140999caf3d65a26c00658c28b26978e05019b..0000000000000000000000000000000000000000 --- a/doc/ChangeLog.fsf +++ /dev/null @@ -1,38 +0,0 @@ -Thu Sep 15 14:19:50 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * Makefile.in: define TEXI2DVI - -Sat Dec 18 01:23:39 1993 david d zuhn (zoo@monad.armadillo.com) - - * cvs.texinfo: document -k SUBST options to 'cvs import'; - regularize use @sc{cvs} - - * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead - (install-info): grab all info files, not just *.info - -Mon Oct 11 16:23:54 1993 Jim Kingdon (kingdon@lioth.cygnus.com) - - * cvsclient.texi: New node TODO; various other changes. - -Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) - - * Makefile.in, configure.in: removed traces of namesubdir, - -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced - copyrights to '92, changed some from Cygnus to FSF. - -Tue Dec 10 04:07:10 1991 K. Richard Pixley (rich at rtl.cygnus.com) - - * Makefile.in: infodir belongs in datadir. - -Thu Dec 5 22:46:01 1991 K. Richard Pixley (rich at rtl.cygnus.com) - - * Makefile.in: idestdir and ddestdir go away. Added copyrights - and shift gpl to v2. Added ChangeLog if it didn't exist. docdir - and mandir now keyed off datadir by default. - -Wed Nov 27 02:45:18 1991 K. Richard Pixley (rich at sendai) - - * brought Makefile.in's up to standards.text. - - * fresh changelog. - diff --git a/doc/Makefile.in b/doc/Makefile.in deleted file mode 100644 index 4a4abf1b65edd35dc461373f4e665ff28730216d..0000000000000000000000000000000000000000 --- a/doc/Makefile.in +++ /dev/null @@ -1,139 +0,0 @@ -# Makefile for GNU CVS documentation. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986, 1988-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. - -# $CVSid: @(#)Makefile.in 1.8 94/10/22 $ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -infodir = $(prefix)/info - -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ - -DISTFILES = Makefile.in cvs-paper.ms cvs-paper.ps cvs.texinfo cvs.ps - -# these are part of the texinfo distribution -MAKEINFO=makeinfo -TEXI2DVI = texi2dvi - -# where to find texinfo; -TEXIDIR=${gdbdir}/../texinfo - -SET_TEXINPUTS = TEXINPUTS=.:$(srcdir):$$TEXINPUTS - -# Don Knuth's TeX formatter -TEX = tex - -# auxiliary program for sorting Texinfo indices -TEXINDEX = texindex - -DVIPS = dvips -DVIPSFLAGS = - -ROFF = groff - -# CYGNUS LOCAL: all does not depend upon info -all: -.PHONY: all - -# CYGNUS LOCAL: install does not depend on install-info -install: all -.PHONY: install - -doc: cvs.ps cvs-paper.ps - -info: cvs.info cvsclient.info - -cvs.info: cvs.texinfo - $(MAKEINFO) $(srcdir)/cvs.texinfo -o cvs.info - -cvsclient.info: cvsclient.texi - $(MAKEINFO) $(srcdir)/cvsclient.texi -o cvsclient.info - -install-info: info - for i in *.info* ; do \ - $(INSTALL_DATA) $$i $(infodir)/$$i ; \ - done - -installdirs: - $(SHELL) $(top_srcdir)/mkinstalldirs $(infodir) -.PHONY: installdirs - -dvi: cvs.dvi cvsclient.dvi - -cvs.dvi: - $(TEXI2DVI) $(srcdir)/cvs.texinfo - -cvsclient.dvi: cvsclient.texi - $(SET_TEXINPUTS) $(TEX) cvsclient.texi - $(SET_TEXINPUTS) $(TEX) cvsclient.texi - $(TEXINDEX) cvsclient.?? - $(SET_TEXINPUTS) $(TEX) cvsclient.texi - rm -f cvsclient.?? cvsclient.log cvsclient.aux cvsclient.toc cvsclient.??s - -cvs.ps: cvs.dvi - $(DVIPS) $(DVIPSFLAGS) cvs.dvi -o cvs.ps - -cvs-paper.ps: cvs-paper.ms - $(ROFF) -t -p -ms -Tps $(srcdir)/cvs-paper.ms > $@ - -tags: -.PHONY: tags - -TAGS: -.PHONY: TAGS - -ls: - @echo $(DISTFILES) -.PHONY: ls - -clean: - rm -f *.o core - rm -f cvs.cp cvs.fn cvs.ky cvs.pg cvs.tp cvs.vr - rm -f cvs.cps cvs.fns cvs.kys cvs.pgs cvs.tps cvs.vrs - rm -f cvs.aux cvs.dvi cvs.log cvs.toc - -.PHONY: clean - -distclean: clean - rm -f Makefile -.PHONY: distclean - -realclean: distclean - rm -f cvs.info* cvs-paper.ps -.PHONY: realclean - -dist: $(DISTFILES) - ln $(DISTFILES) ../`cat ../.fname`/doc -.PHONY: dist - -Makefile: Makefile.in - cd .. ; $(SHELL) config.status - -../config.status: ../configure - cd .. ; $(SHELL) config.status --recheck - -../configure: ../configure.in - cd $(top_srcdir) ; autoconf diff --git a/doc/cvs-paper.ms b/doc/cvs-paper.ms deleted file mode 100644 index 567179b393f840f87bc4d03a26f9a4ef7cd0a654..0000000000000000000000000000000000000000 --- a/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/doc/cvs-paper.ps b/doc/cvs-paper.ps deleted file mode 100644 index 903cf3ba4f2e5f94c2cf4a02e3d3f3724142f274..0000000000000000000000000000000000000000 --- a/doc/cvs-paper.ps +++ /dev/null @@ -1,1360 +0,0 @@ -%!PS-Adobe-3.0 -%%Creator: groff version 1.08 -%%DocumentNeededResources: font Times-Bold -%%+ font Times-Italic -%%+ font Times-Roman -%%+ font Courier -%%DocumentSuppliedResources: procset grops 1.08 0 -%%Pages: 12 -%%PageOrder: Ascend -%%Orientation: Portrait -%%EndComments -%%BeginProlog -%%BeginResource: procset grops 1.08 0 -%!PS-Adobe-3.0 Resource-ProcSet -/setpacking where{ -pop -currentpacking -true setpacking -}if -/grops 120 dict dup begin -/SC 32 def -/A/show load def -/B{0 SC 3 -1 roll widthshow}bind def -/C{0 exch ashow}bind def -/D{0 exch 0 SC 5 2 roll awidthshow}bind def -/E{0 rmoveto show}bind def -/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def -/G{0 rmoveto 0 exch ashow}bind def -/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/I{0 exch rmoveto show}bind def -/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def -/K{0 exch rmoveto 0 exch ashow}bind def -/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/M{rmoveto show}bind def -/N{rmoveto 0 SC 3 -1 roll widthshow}bind def -/O{rmoveto 0 exch ashow}bind def -/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/Q{moveto show}bind def -/R{moveto 0 SC 3 -1 roll widthshow}bind def -/S{moveto 0 exch ashow}bind def -/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def -/SF{ -findfont exch -[exch dup 0 exch 0 exch neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/MF{ -findfont -[5 2 roll -0 3 1 roll -neg 0 0]makefont -dup setfont -[exch/setfont cvx]cvx bind def -}bind def -/level0 0 def -/RES 0 def -/PL 0 def -/LS 0 def -/PLG{ -gsave newpath clippath pathbbox grestore -exch pop add exch pop -}bind def -/BP{ -/level0 save def -1 setlinecap -1 setlinejoin -72 RES div dup scale -LS{ -90 rotate -}{ -0 PL translate -}ifelse -1 -1 scale -}bind def -/EP{ -level0 restore -showpage -}bind def -/DA{ -newpath arcn stroke -}bind def -/SN{ -transform -.25 sub exch .25 sub exch -round .25 add exch round .25 add exch -itransform -}bind def -/DL{ -SN -moveto -SN -lineto stroke -}bind def -/DC{ -newpath 0 360 arc closepath -}bind def -/TM matrix def -/DE{ -TM currentmatrix pop -translate scale newpath 0 0 .5 0 360 arc closepath -TM setmatrix -}bind def -/RC/rcurveto load def -/RL/rlineto load def -/ST/stroke load def -/MT/moveto load def -/CL/closepath load def -/FL{ -currentgray exch setgray fill setgray -}bind def -/BL/fill load def -/LW/setlinewidth load def -/RE{ -findfont -dup maxlength 1 index/FontName known not{1 add}if dict begin -{ -1 index/FID ne{def}{pop pop}ifelse -}forall -/Encoding exch def -dup/FontName exch def -currentdict end definefont pop -}bind def -/DEFS 0 def -/EBEGIN{ -moveto -DEFS begin -}bind def -/EEND/end load def -/CNT 0 def -/level1 0 def -/PBEGIN{ -/level1 save def -translate -div 3 1 roll div exch scale -neg exch neg exch translate -0 setgray -0 setlinecap -1 setlinewidth -0 setlinejoin -10 setmiterlimit -[]0 setdash -/setstrokeadjust where{ -pop -false setstrokeadjust -}if -/setoverprint where{ -pop -false setoverprint -}if -newpath -/CNT countdictstack def -userdict begin -/showpage{}def -}bind def -/PEND{ -clear -countdictstack CNT sub{end}repeat -level1 restore -}bind def -end def -/setpacking where{ -pop -setpacking -}if -%%EndResource -%%EndProlog -%%BeginSetup -%%IncludeResource: font Times-Bold -%%IncludeResource: font Times-Italic -%%IncludeResource: font Times-Roman -%%IncludeResource: font Courier -grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL -792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron -/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef -/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space -/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft -/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four -/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C -/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash -/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q -/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase -/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger -/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut -/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash -/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar -/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus -/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu -/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright -/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde -/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute -/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis -/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls -/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute -/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve -/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex -/udieresis/yacute/thorn/ydieresis]def/Courier@0 ENC0/Courier RE/Times-Roman@0 -ENC0/Times-Roman RE/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0 -/Times-Bold RE -%%EndSetup -%%Page: 1 1 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 14/Times-Bold@0 SF(CVS II:)282.473 127 Q -.14(Pa)199.054 143 S -(rallelizing Softwar).14 E 3.5(eD)-.252 G -3.22 -.21(ev e)344.864 143 T -(lopment).21 E/F1 12/Times-Italic@0 SF(Brian Berliner)270.834 169 Q -(Prisma, Inc.)276.504 188.5 Q(5465 Mark Dabling Blvd.)244.338 201.5 Q(Color) -233.916 214.5 Q(ado Springs, CO)-.18 E(80918)6 E(berliner@prisma.com)252.984 -227.5 Q/F2 11/Times-Italic@0 SF(ABSTRA)280.188 266.5 Q(CT)-.33 E/F3 11 -/Times-Roman@0 SF 1.027 -(The program described in this paper \214lls a need in the UNIX community)153.5 -296.4 R 1.371(for a freely a)126 309.4 R -.275(va)-.22 G 1.372 -(ilable tool to manage softw).275 F 1.372(are re)-.11 F 1.372 -(vision and release control in a)-.275 F(multi-de)126 322.4 Q -.165(ve)-.275 G -(loper).165 E 8.601(,m)-.44 G(ulti-directory)215.297 322.4 Q 8.601(,m)-.715 G -5.851(ulti-group en)292.538 322.4 R 8.601(vironment. This)-.44 F 5.85 -(tool also)8.6 F .43(addresses the increasing need for tracking third-party v) -126 335.4 R .431(endor source distrib)-.165 F(utions)-.22 E -(while trying to maintain local modi\214cations to earlier releases.)126 348.4 -Q/F4 11/Times-Bold@0 SF 2.75(1. Backgr)90 387.4 R(ound)-.198 E F3 .774(In lar) -117.5 404.3 R .774(ge softw)-.198 F .774(are de)-.11 F -.165(ve)-.275 G .774 -(lopment projects, it is usually necessary for more than one softw).165 F(are) --.11 E(de)90 417.3 Q -.165(ve)-.275 G 1.494 -(loper to be modifying \(usually dif).165 F 1.494 -(ferent\) modules of the code at the same time.)-.275 F 1.495(Some of)6.995 F -.598(these code modi\214cations are done in an e)90 430.3 R .597 -(xperimental sense, at least until the code functions cor)-.165 F(-)-.22 E -(rectly)90 443.3 Q 3.769(,a)-.715 G 1.02 -(nd some testing of the entire program is usually necessary)125.735 443.3 R -6.52(.T)-.715 G 1.02(hen, the modi\214cations are)405.288 443.3 R .882 -(returned to a master source repository so that others in the project can enjo) -90 456.3 R 3.631(yt)-.11 G .881(he ne)441.95 456.3 R 3.631(wb)-.275 G .881 -(ug-\214x or)482.927 456.3 R(functionality)90 469.3 Q 6.503(.I)-.715 G 3.753 -(no)158.422 469.3 S 1.004(rder to manage such a project, some sort of re) -173.175 469.3 R 1.004(vision control system is neces-)-.275 F(sary)90 482.3 Q -(.)-.715 E(Speci\214cally)117.5 499.2 Q 4.219(,U)-.715 G(NIX)183.638 499.2 Q/F5 -7.7/Times-Roman@0 SF(1)203.185 494.69 Q F3 -.11(ke)211.254 499.2 S 1.469 -(rnel de).11 F -.165(ve)-.275 G 1.468(lopment is an e).165 F 1.468(xcellent e) --.165 F 1.468(xample of the problems that an)-.165 F .692(adequate re)90 512.2 -R .692(vision control system must address.)-.275 F .693(The SunOS)6.193 F F5(2) -358.243 507.69 Q F3 -.11(ke)365.536 512.2 S .693(rnel is composed of o).11 F --.165(ve)-.165 G 3.443(rat).165 G(hou-)501.837 512.2 Q .518 -(sand \214les spread across a hierarch)90 525.2 R 3.268(yo)-.055 G 3.268(fd) -256.172 525.2 S .518(ozens of directories.)268.603 525.2 R F5(3)358.529 520.69 -Q F3 .517(Pieces of the k)365.646 525.2 R .517(ernel must be edited)-.11 F -2.573(by man)90 538.2 R 5.323(ys)-.165 G(oftw)140.202 538.2 Q 2.573(are de)-.11 -F -.165(ve)-.275 G 2.574(lopers within an or).165 F -.055(ga)-.198 G 5.324 -(nization. While).055 F 2.574(undesirable in theory)5.324 F 5.324(,i)-.715 G -5.324(ti)486.899 538.2 S 5.324(sn)498.339 538.2 S(ot)513.442 538.2 Q .956 -(uncommon to ha)90 551.2 R 1.286 -.165(ve t)-.22 H 1.176 -.11(wo o).165 H 3.706 -(rm).11 G .955 -(ore people making modi\214cations to the same \214le within the k)221.082 -551.2 R(ernel)-.11 E .372(sources in order to f)90 564.2 R .372 -(acilitate a desired change.)-.11 F .372(Existing re)5.872 F .373 -(vision control systems lik)-.275 F(e)-.11 E/F6 9/Times-Roman@0 SF(RCS)3.123 E -F3([T)2.623 E(ich)-.385 E(y])-.055 E(or)90 577.2 Q F6(SCCS)3.088 E F3 .337 -([Bell] serialize \214le modi\214cations by allo)2.588 F .337(wing only one de) --.275 F -.165(ve)-.275 G .337(loper to ha).165 F .667 -.165(ve a w)-.22 H .337 -(ritable cop).165 F(y)-.11 E .086(of a particular \214le at an)90 590.2 R 2.836 -(yo)-.165 G .086(ne point in time.)206.434 590.2 R .086(That de)5.586 F -.165 -(ve)-.275 G .086(loper is said to ha).165 F .416 -.165(ve \231)-.22 H(lock).165 -E .087(ed\232 the \214le for his)-.11 F -.165(ex)90 603.2 S(clusi).165 E .835 --.165(ve u)-.275 H .505(se, and no other de).165 F -.165(ve)-.275 G .505 -(loper is allo).165 F .505(wed to check out a writable cop)-.275 F 3.254(yo) --.11 G 3.254(ft)444.205 603.2 S .504(he \214le until the)454.18 603.2 R .554 -(locking de)90 616.2 R -.165(ve)-.275 G .554 -(loper has \214nished impeding others' producti).165 F(vity)-.275 E 6.054(.D) --.715 G -2.365 -.275(ev e)376.897 616.2 T .554(lopment pressures of produc-) -.275 F(ti)90 629.2 Q .244(vity and deadlines often force or)-.275 F -.055(ga) --.198 G .244(nizations to require that multiple de).055 F -.165(ve)-.275 G .244 -(lopers be able to simul-).165 F(taneously edit copies of the same re)90 642.2 -Q(vision controlled \214le.)-.275 E .36 LW 162 666.75 90 666.75 DL/F7 6.3 -/Times-Roman@0 SF(1)101 676.01 Q F6(UNIX is a re)2.25 3.69 M -(gistered trademark of A)-.135 E(T&T)-.999 E(.)-.666 E F7(2)101 688.96 Q F6 -(SunOS is a trademark of Sun Microsystems, Inc.)2.25 3.69 M F7(3)101 701.91 Q -F6 -.9(Ye)2.25 3.69 O(s, the SunOS 4.0 k).9 E(ernel is composed of o)-.09 E --.135(ve)-.135 G 2.25(ra).135 G/F8 9/Times-Italic@0 SF(thousand)A F6(\214les!) -2.25 E EP -%%Page: 2 2 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF(-2-)299.587 49 Q 1.36(The necessity for multiple de) -117.5 85 R -.165(ve)-.275 G 1.36 -(lopers to modify the same \214le concurrently questions the).165 F -.275(va)90 -98 S 2.578(lue of serialization-based policies in traditional re).275 F 2.578 -(vision control.)-.275 F 2.577(This paper discusses the)8.078 F 1.728 -(approach that Prisma took in adapting a standard re)90 111 R 1.728 -(vision control system,)-.275 F/F1 9/Times-Roman@0 SF(RCS)4.478 E F0 4.478(,a)C -1.728(long with an)463.543 111 R -.165(ex)90 124 S 1.2 -(isting public-domain collection of shell scripts that sits atop).165 F F1(RCS) -3.95 E F0 1.199(and pro)3.449 F 1.199(vides the basic con-)-.165 F .965 -(\215ict-resolution algorithms.)90 137 R .966(The resulting program,)6.466 F/F2 -11/Times-Bold@0 SF(cvs)3.716 E F0 3.716(,a)C .966 -(ddresses not only the issue of con\215ict-)347.552 137 R .789 -(resolution in a multi-de)90 150 R -.165(ve)-.275 G .789(loper open-editing en) -.165 F .789(vironment, b)-.44 F .789(ut also the issues of softw)-.22 F .789 -(are release)-.11 F(control and v)90 163 Q(endor source support and inte)-.165 -E(gration.)-.165 E F2 2.75(2. The)90 189 R(CVS Pr)2.75 E(ogram)-.198 E(cvs) -117.5 205.9 Q F0 .89(\(Concurrent V)3.64 F .891 -(ersions System\) is a front end to the)-1.221 F F1(RCS)3.641 E F0(re)3.141 E -.891(vision control system which)-.275 F -.165(ex)90 218.9 S .117 -(tends the notion of re).165 F .116(vision control from a collection of \214le\ -s in a single directory to a hierarchi-)-.275 F .703 -(cal collection of directories each containing re)90 231.9 R .704 -(vision controlled \214les.)-.275 F .704(Directories and \214les in the)6.204 F -F2(cvs)90 244.9 Q F0 .495(system can be combined together in man)3.245 F 3.245 -(yw)-.165 G .495(ays to form a softw)306.931 244.9 R .495(are release.)-.11 F -F2(cvs)5.994 E F0(pro)3.244 E .494(vides the)-.165 F 1.446 -(functions necessary to manage these softw)90 257.9 R 1.446 -(are releases and to control the concurrent editing of)-.11 F -(source \214les among multiple softw)90 270.9 Q(are de)-.11 E -.165(ve)-.275 G -(lopers.).165 E .85(The six major features of)117.5 287.8 R F2(cvs)3.6 E F0 .85 -(are listed belo)3.6 F 2.28 -.715(w, a)-.275 H .85 -(nd will be described in more detail in the).715 F(follo)90 300.8 Q -(wing sections:)-.275 E 16.5(1. Concurrent)117.5 317.7 R 4.661 -(access and con\215ict-resolution algorithms to guarantee that source)7.41 F -(changes are not \231lost.)145 330.7 Q<9a>-.77 E 16.5(2. Support)117.5 347.6 R -1.908(for tracking third-party v)4.658 F 1.908(endor source distrib)-.165 F -1.907(utions while maintaining the)-.22 F -(local modi\214cations made to those sources.)145 360.6 Q 16.5(3. A)117.5 377.5 -R<8d65>3.998 E 1.248(xible module database that pro)-.165 F 1.248 -(vides a symbolic mapping of names to compo-)-.165 F .534(nents of a lar)145 -390.5 R .534(ger softw)-.198 F .534(are distrib)-.11 F 3.284(ution. This)-.22 F -.534(symbolic mapping pro)3.284 F .533(vides for location)-.165 F .163 -(independence within the softw)145 403.5 R .163(are release and, for e)-.11 F -.163(xample, allo)-.165 F .163(ws one to check out a)-.275 F(cop)145 416.5 Q -3.728(yo)-.11 G 3.727(ft)175.502 416.5 S .977(he \231dif)185.95 416.5 R .977 -(f\232 program without e)-.275 F -.165(ve)-.275 G 3.727(rk).165 G(no)335.221 -416.5 Q .977(wing that the sources to \231dif)-.275 F .977(f\232 actually)-.275 -F(reside in the \231bin/dif)145 429.5 Q(f\232 directory)-.275 E(.)-.715 E 16.5 -(4. Con\214gurable)117.5 446.4 R 3.203(logging support allo)5.952 F 3.203 -(ws all \231committed\232 source \214le changes to be)-.275 F 1.642 -(logged using an arbitrary program to sa)145 459.4 R 1.972 -.165(ve t)-.22 H -1.642(he log messages in a \214le, notes\214le, or).165 F(ne)145 472.4 Q -(ws database.)-.275 E 16.5(5. A)117.5 489.3 R(softw)3.129 E .379 -(are release can be symbolically tagged and check)-.11 F .379(ed out at an)-.11 -F 3.13(yt)-.165 G .38(ime based on)463.193 489.3 R 1.553(that tag.)145 502.3 R -1.553(An e)7.053 F 1.553(xact cop)-.165 F 4.303(yo)-.11 G 4.303(fap)265.218 -502.3 S(re)287.871 502.3 Q 1.553(vious softw)-.275 F 1.553 -(are release can be check)-.11 F 1.553(ed out at an)-.11 F(y)-.165 E(time,)145 -515.3 Q/F3 11/Times-Italic@0 SF -.407(re)4.319 G(gar)-.033 E(dless)-.407 E F0 -1.57(of whether \214les or directories ha)4.319 F 1.9 -.165(ve b)-.22 H 1.57 -(een added/remo).165 F -.165(ve)-.165 G 4.32(df).165 G 1.57(rom the)486.517 -515.3 R .42(\231current\232 softw)145 528.3 R .42(are release.)-.11 F .42 -(As well, a \231date\232 can be used to check out the)5.92 F F3 -.22(ex)3.17 G -(act).22 E F0 -.165(ve)3.17 G -.22(r-).165 G(sion of the softw)145 541.3 Q -(are release as of the speci\214ed date.)-.11 E 16.5(6. A)117.5 558.2 R .5 -(\231patch\232 format \214le [W)3.249 F .5(all] can be produced between tw)-.88 -F 3.25(os)-.11 G(oftw)414.152 558.2 Q .5(are releases, e)-.11 F -.165(ve)-.275 -G 3.25(ni).165 G(f)518.337 558.2 Q(the releases span multiple directories.)145 -571.2 Q 1.169(The sources maintained by)117.5 588.1 R F2(cvs)3.918 E F0 1.168 -(are k)3.918 F 1.168(ept within a single directory hierarch)-.11 F 3.918(yk) --.055 G(no)467.392 588.1 Q 1.168(wn as the)-.275 F .453(\231source repository) -90 601.1 R 4.743 -.77(.\232 T)-.715 H .454 -(his \231source repository\232 holds the actual).77 F F1(RCS)3.204 E F0 .454 -(\231,v\232 \214les directly)2.704 F 3.204(,a)-.715 G 3.204(sw)475.12 601.1 S -.454(ell as a)490.545 601.1 R .892(special per)90 614.1 R .892 -(-repository directory \()-.22 F F1(CVSR)A(OO)-.36 E -.666(T.)-.36 G(adm).666 E -F0 3.642(\)w)C .892(hich contains a small number of administrati)310.553 614.1 -R -.165(ve)-.275 G .225(\214les that describe the repository and ho)90 627.1 R -2.975(wi)-.275 G 2.976(tc)277.97 627.1 S .226(an be accessed.)288.888 627.1 R -.226(See Figure 1 for a picture of the)5.726 F F2(cvs)2.976 E F0(tree.)90 640.1 -Q F2 2.75(2.1. Softwar)90 666.1 R 2.75(eC)-.198 G(on\215ict Resolution)164.646 -666.1 Q/F4 7.7/Times-Bold@0 SF(4)246.849 661.59 Q .36 LW 162 674.1 90 674.1 DL -/F5 6.3/Times-Roman@0 SF(4)101 683.36 Q F1 .259 -(The basic con\215ict-resolution algorithms used in the)2.25 3.69 N/F6 9 -/Times-Bold@0 SF(cvs)2.509 E F1 .259 -(program \214nd their roots in the original)2.509 F -.09(wo)90 698.05 S .439 -(rk done by Dick Grune at Vrije Uni).09 F -.135(ve)-.225 G .439 -(rsiteit in Amsterdam and posted to).135 F F6(comp.sour)2.689 E(ces.unix)-.162 -E F1(in)2.69 E 1.528(the v)90 709.05 R 1.528(olume 6 release sometime in 1986.) --.18 F 1.528(This original v)6.028 F 1.528(ersion of)-.135 F F6(cvs)3.778 E F1 --.09(wa)3.778 G 3.777(sac).09 G 1.527(ollection of shell)386.448 709.05 R EP -%%Page: 3 3 -%%BeginPageSetup -BP -%%EndPageSetup -.44 LW 131.5 85 126 85 DL 134 85 128.5 85 DL 139.5 85 134 85 DL 145 85 139.5 85 -DL 150.5 85 145 85 DL 156 85 150.5 85 DL 161.5 85 156 85 DL 167 85 161.5 85 DL -172.5 85 167 85 DL 178 85 172.5 85 DL 183.5 85 178 85 DL 189 85 183.5 85 DL -194.5 85 189 85 DL 200 85 194.5 85 DL 205.5 85 200 85 DL 211 85 205.5 85 DL -216.5 85 211 85 DL 222 85 216.5 85 DL 227.5 85 222 85 DL 233 85 227.5 85 DL -238.5 85 233 85 DL 244 85 238.5 85 DL 249.5 85 244 85 DL 255 85 249.5 85 DL -260.5 85 255 85 DL 266 85 260.5 85 DL 271.5 85 266 85 DL 277 85 271.5 85 DL -282.5 85 277 85 DL 288 85 282.5 85 DL 293.5 85 288 85 DL 299 85 293.5 85 DL -304.5 85 299 85 DL 310 85 304.5 85 DL 315.5 85 310 85 DL 321 85 315.5 85 DL -326.5 85 321 85 DL 332 85 326.5 85 DL 337.5 85 332 85 DL 343 85 337.5 85 DL -348.5 85 343 85 DL 354 85 348.5 85 DL 359.5 85 354 85 DL 365 85 359.5 85 DL -370.5 85 365 85 DL 376 85 370.5 85 DL 381.5 85 376 85 DL 387 85 381.5 85 DL -392.5 85 387 85 DL 398 85 392.5 85 DL 403.5 85 398 85 DL 409 85 403.5 85 DL -414.5 85 409 85 DL 420 85 414.5 85 DL 425.5 85 420 85 DL 431 85 425.5 85 DL -436.5 85 431 85 DL 442 85 436.5 85 DL 447.5 85 442 85 DL 453 85 447.5 85 DL -458.5 85 453 85 DL 464 85 458.5 85 DL 469.5 85 464 85 DL 475 85 469.5 85 DL -480.5 85 475 85 DL 486 85 480.5 85 DL 473.192 189.232 369.656 166.696 DL -473.192 189.232 465.776 189.448 DL 466.568 185.92 473.192 189.232 DL 401.192 -184.696 369.656 166.696 DL 401.192 184.696 394.064 182.68 DL 395.864 179.584 -401.192 184.696 DL 342.656 189.232 369.656 166.696 DL 342.656 189.232 347.048 -183.184 DL 349.352 185.992 342.656 189.232 DL 414.656 243.232 333.656 198.232 -DL 414.656 243.232 407.528 241.288 DL 409.256 238.12 414.656 243.232 DL 342.656 -243.232 333.656 198.232 DL 342.656 243.232 339.488 236.464 DL 343.016 235.816 -342.656 243.232 DL 261.656 238.696 333.656 198.232 DL 261.656 238.696 267.056 -233.584 DL 268.856 236.752 261.656 238.696 DL 270.656 184.696 243.656 162.232 -DL 270.656 184.696 264.032 181.456 DL 266.336 178.72 270.656 184.696 DL 212.192 -184.696 243.656 162.232 DL 212.192 184.696 217.016 179.08 DL 219.104 181.96 -212.192 184.696 DL 365.192 153.232 315.656 126.232 DL 365.192 153.232 357.992 -151.36 DL 359.72 148.192 365.192 153.232 DL 252.656 153.232 315.656 126.232 DL -252.656 153.232 258.632 148.696 DL 260 152.008 252.656 153.232 DL/F0 11 -/Times-Roman@0 SF(ne)396.656 252.42 Q(wfs.c,v)-.275 E(mkfs.c,v)324.656 252.42 Q -(Mak)234.656 252.42 Q(e\214le,v)-.11 E(ne)324.656 198.42 Q(wfs)-.275 E -(halt.c,v)468.656 198.42 Q(Mak)378.656 198.42 Q(e\214le,v)-.11 E(modules,v) -252.656 198.42 Q(loginfo,v)180.728 198.42 Q(etc)360.656 162.42 Q(CVSR)216.728 -162.42 Q(OO)-.44 E -.814(T.)-.44 G(adm).814 E(/src/master)288.656 126.42 Q -131.5 281.5 126 281.5 DL 134 281.5 128.5 281.5 DL 139.5 281.5 134 281.5 DL 145 -281.5 139.5 281.5 DL 150.5 281.5 145 281.5 DL 156 281.5 150.5 281.5 DL 161.5 -281.5 156 281.5 DL 167 281.5 161.5 281.5 DL 172.5 281.5 167 281.5 DL 178 281.5 -172.5 281.5 DL 183.5 281.5 178 281.5 DL 189 281.5 183.5 281.5 DL 194.5 281.5 -189 281.5 DL 200 281.5 194.5 281.5 DL 205.5 281.5 200 281.5 DL 211 281.5 205.5 -281.5 DL 216.5 281.5 211 281.5 DL 222 281.5 216.5 281.5 DL 227.5 281.5 222 -281.5 DL 233 281.5 227.5 281.5 DL 238.5 281.5 233 281.5 DL 244 281.5 238.5 -281.5 DL 249.5 281.5 244 281.5 DL 255 281.5 249.5 281.5 DL 260.5 281.5 255 -281.5 DL 266 281.5 260.5 281.5 DL 271.5 281.5 266 281.5 DL 277 281.5 271.5 -281.5 DL 282.5 281.5 277 281.5 DL 288 281.5 282.5 281.5 DL 293.5 281.5 288 -281.5 DL 299 281.5 293.5 281.5 DL 304.5 281.5 299 281.5 DL 310 281.5 304.5 -281.5 DL 315.5 281.5 310 281.5 DL 321 281.5 315.5 281.5 DL 326.5 281.5 321 -281.5 DL 332 281.5 326.5 281.5 DL 337.5 281.5 332 281.5 DL 343 281.5 337.5 -281.5 DL 348.5 281.5 343 281.5 DL 354 281.5 348.5 281.5 DL 359.5 281.5 354 -281.5 DL 365 281.5 359.5 281.5 DL 370.5 281.5 365 281.5 DL 376 281.5 370.5 -281.5 DL 381.5 281.5 376 281.5 DL 387 281.5 381.5 281.5 DL 392.5 281.5 387 -281.5 DL 398 281.5 392.5 281.5 DL 403.5 281.5 398 281.5 DL 409 281.5 403.5 -281.5 DL 414.5 281.5 409 281.5 DL 420 281.5 414.5 281.5 DL 425.5 281.5 420 -281.5 DL 431 281.5 425.5 281.5 DL 436.5 281.5 431 281.5 DL 442 281.5 436.5 -281.5 DL 447.5 281.5 442 281.5 DL 453 281.5 447.5 281.5 DL 458.5 281.5 453 -281.5 DL 464 281.5 458.5 281.5 DL 469.5 281.5 464 281.5 DL 475 281.5 469.5 -281.5 DL 480.5 281.5 475 281.5 DL 486 281.5 480.5 281.5 DL/F1 13/Times-Bold@0 -SF(Figur)281.202 307.5 Q 3.25(e1)-.234 G(.)327.547 307.5 Q/F2 11/Times-Bold@0 -SF(cvs)256.505 320.5 Q F0(Source Repository)2.75 E F2(cvs)117.5 346.5 Q F0 -(allo)3.645 E .895(ws se)-.275 F -.165(ve)-.275 G .896(ral softw).165 F .896 -(are de)-.11 F -.165(ve)-.275 G .896(lopers to edit personal copies of a re) -.165 F .896(vision controlled \214le)-.275 F(concurrently)90 359.5 Q 5.894(.T) --.715 G .394(he re)160.244 359.5 R .393(vision number of each check)-.275 F -.393(ed out \214le is maintained independently for each)-.11 F(user)90 372.5 Q -3.766(,a)-.44 G(nd)119.286 372.5 Q F2(cvs)3.766 E F0 1.016(forces the check) -3.766 F 1.017(ed out \214le to be current with the \231head\232 re)-.11 F 1.017 -(vision before it can be)-.275 F 1.233 -(\231committed\232 as a permanent change.)90 385.5 R 3.983(Ac)6.733 G(heck) -280.68 385.5 Q 1.232(ed out \214le is brought up-to-date with the \231head\232) --.11 F(re)90 398.5 Q .349(vision using the \231update\232 command of)-.275 F F2 -(cvs)3.099 E F0 5.849(.T)C .349(his command compares the \231head\232 re) -302.664 398.5 R .35(vision num-)-.275 F .23(ber with that of the user')90 411.5 -R 2.979<738c>-.605 G .229(le and performs an)212.366 411.5 R/F3 9/Times-Roman@0 -SF(RCS)2.979 E F0(mer)2.479 E .229(ge operation if the)-.198 F 2.979(ya)-.165 G -.229(re not the same.)428.827 411.5 R(The)5.729 E 1.498(result of the mer)90 -424.5 R 1.498(ge is a \214le that contains the user')-.198 F 4.248(sm)-.605 G -1.498(odi\214cations and those modi\214cations that)338.171 424.5 R .704 -(were \231committed\232 after the user check)90 437.5 R .703(ed out his v)-.11 -F .703(ersion of the \214le \(as well as a backup cop)-.165 F 3.453(yo)-.11 G -(f)518.337 437.5 Q .173(the user')90 450.5 R 2.923(so)-.605 G .173 -(riginal \214le\).)140.451 450.5 R F2(cvs)5.673 E F0 .174(points out an)2.924 F -2.924(yc)-.165 G .174(on\215icts during the mer)286.154 450.5 R 2.924(ge. It) --.198 F .174(is the user')2.924 F 2.924(sr)-.605 G(esponsibil-)473.721 450.5 Q -(ity to resolv)90 463.5 Q 2.75(et)-.165 G -(hese con\215icts and to \231commit\232 his/her changes when ready)153.085 -463.5 Q(.)-.715 E .134(Although the)117.5 480.4 R F2(cvs)2.884 E F0 .134 -(con\215ict-resolution algorithm w)2.884 F .133 -(as de\214ned in 1986, it is remarkably similar)-.11 F .642(to the \231Cop)90 -493.4 R(y-Modify-Mer)-.11 E .642(ge\232 scenario included with NSE)-.198 F/F4 -7.7/Times-Roman@0 SF(5)349.558 488.89 Q F0 .643 -(and described in [Honda] and [Cour)356.8 493.4 R(-)-.22 E 2.75(ington]. The)90 -506.4 R(follo)2.75 E(wing e)-.275 E(xplanation from [Honda] also applies to) --.165 E F2(cvs)2.75 E F0(:)A .142(Simply stated, a de)117.5 523.3 R -.165(ve) --.275 G .142(loper copies an object without locking it, modi\214es the cop).165 -F 1.571 -.715(y, a)-.11 H(nd).715 E .134(then mer)117.5 536.3 R .134 -(ges the modi\214ed cop)-.198 F 2.884(yw)-.11 G .134(ith the original.)264.206 -536.3 R .135(This paradigm allo)5.635 F .135(ws de)-.275 F -.165(ve)-.275 G -.135(lopers to).165 F -.11(wo)117.5 549.3 S 2.078 -(rk in isolation from one another since changes are made to copies of objects.) -.11 F .06(Because locks are not used, de)117.5 562.3 R -.165(ve)-.275 G .06 -(lopment is not serialized and can proceed in parallel.).165 F(De)117.5 575.3 Q --.165(ve)-.275 G .511(lopers, ho).165 F(we)-.275 E -.165(ve)-.275 G 1.391 -.44 -(r, m).165 H .511(ust mer).44 F .51(ge objects after the changes ha)-.198 F .84 --.165(ve b)-.22 H .51(een made.).165 F .51(In par)6.01 F(-)-.22 E(ticular)117.5 -588.3 Q 2.783(,ad)-.44 G -2.365 -.275(ev e)163.865 588.3 T .033 -(loper must resolv).275 F 2.783(ec)-.165 G .034 -(on\215icts when the same object has been modi\214ed by)267.529 588.3 R -(someone else.)117.5 601.3 Q .164(In practice, Prisma has found that con\215ic\ -ts that occur when the same object has been modi-)117.5 618.2 R .362 -(\214ed by someone else are quite rare.)90 631.2 R .362(When the)5.862 F 3.112 -(yd)-.165 G 3.112(oh)310.288 631.2 S .362 -(appen, the changes made by the other de)324.4 631.2 R -.165(ve)-.275 G(l-).165 -E 1.542(oper are usually easily resolv)90 644.2 R 4.292(ed. This)-.165 F 1.541 -(practical use has sho)4.292 F 1.541(wn that the \231Cop)-.275 F(y-Modify-Mer) --.11 E(ge\232)-.198 E(paradigm is a correct and useful one.)90 657.2 Q .36 LW -162 681.65 90 681.65 DL F3(scripts that combined to form a front end to the)90 -692.65 Q/F5 7/Times-Roman@0 SF(RCS)2.25 E F3(programs.)1.75 E/F6 6.3 -/Times-Roman@0 SF(5)101 701.91 Q F3(NSE is the Netw)2.25 3.69 M(ork Softw)-.09 -E(are En)-.09 E(vironment, a product of Sun Microsystems, Inc.)-.36 E EP -%%Page: 4 4 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF(-4-)299.587 49 Q/F1 11/Times-Bold@0 SF 2.75(2.2. T)90 -85 R(racking Third-P)-.814 E(arty Sour)-.11 E(ce Distrib)-.198 E(utions)-.22 E -F0(Currently)117.5 101.9 Q 4.115(,al)-.715 G(ar)177.87 101.9 Q 1.365 -(ge amount of softw)-.198 F 1.366(are is based on source distrib)-.11 F 1.366 -(utions from a third-party)-.22 F(distrib)90 114.9 Q(utor)-.22 E 5.56(.I)-.605 -G 2.81(ti)146.985 114.9 S 2.81(so)155.911 114.9 S .059 -(ften the case that local modi\214cations are to be made to this distrib)168.5 -114.9 R(ution,)-.22 E/F2 11/Times-Italic@0 SF(and)2.809 E F0(that)2.809 E .523 -(the v)90 127.9 R(endor')-.165 E 3.273(sf)-.605 G .523 -(uture releases should be track)151.37 127.9 R 3.274(ed. Rolling)-.11 F .524 -(your local modi\214cations forw)3.274 F .524(ard into the)-.11 F(ne)90 140.9 Q -5.213(wv)-.275 G 2.463(endor release is a time-consuming task, b)118.599 140.9 -R(ut)-.22 E F1(cvs)5.213 E F0 2.463(can ease this b)5.213 F 2.463(urden some) --.22 F 5.213(what. The)-.275 F F1(checkin)90 153.9 Q F0 1.32(program of)4.07 F -F1(cvs)4.07 E F0 1.321(initially sets up a source repository by inte)4.07 F -1.321(grating the source modules)-.165 F .41(directly from the v)90 166.9 R -(endor')-.165 E 3.16(sr)-.605 G .41(elease, preserving the directory hierarch) -212.453 166.9 R 3.159(yo)-.055 G 3.159(ft)404.437 166.9 S .409(he v)414.317 -166.9 R(endor')-.165 E 3.159(sd)-.605 G(istrib)474.238 166.9 Q(ution.)-.22 E -.405(The branch support of)90 179.9 R/F3 9/Times-Roman@0 SF(RCS)3.155 E F0 .406 -(is used to b)2.656 F .406(uild this v)-.22 F .406 -(endor release as a branch of the main)-.165 F F3(RCS)3.156 E F0(trunk.)2.656 E -.503(Figure 2 sho)90 192.9 R .503(ws ho)-.275 F 3.253(wt)-.275 G .503 -(he \231head\232 tracks a sample v)186.183 192.9 R .503 -(endor branch when no local modi\214cations ha)-.165 F -.165(ve)-.22 G -(been made to the \214le.)90 205.9 Q .44 LW 131.5 218.9 126 218.9 DL 134 218.9 -128.5 218.9 DL 139.5 218.9 134 218.9 DL 145 218.9 139.5 218.9 DL 150.5 218.9 -145 218.9 DL 156 218.9 150.5 218.9 DL 161.5 218.9 156 218.9 DL 167 218.9 161.5 -218.9 DL 172.5 218.9 167 218.9 DL 178 218.9 172.5 218.9 DL 183.5 218.9 178 -218.9 DL 189 218.9 183.5 218.9 DL 194.5 218.9 189 218.9 DL 200 218.9 194.5 -218.9 DL 205.5 218.9 200 218.9 DL 211 218.9 205.5 218.9 DL 216.5 218.9 211 -218.9 DL 222 218.9 216.5 218.9 DL 227.5 218.9 222 218.9 DL 233 218.9 227.5 -218.9 DL 238.5 218.9 233 218.9 DL 244 218.9 238.5 218.9 DL 249.5 218.9 244 -218.9 DL 255 218.9 249.5 218.9 DL 260.5 218.9 255 218.9 DL 266 218.9 260.5 -218.9 DL 271.5 218.9 266 218.9 DL 277 218.9 271.5 218.9 DL 282.5 218.9 277 -218.9 DL 288 218.9 282.5 218.9 DL 293.5 218.9 288 218.9 DL 299 218.9 293.5 -218.9 DL 304.5 218.9 299 218.9 DL 310 218.9 304.5 218.9 DL 315.5 218.9 310 -218.9 DL 321 218.9 315.5 218.9 DL 326.5 218.9 321 218.9 DL 332 218.9 326.5 -218.9 DL 337.5 218.9 332 218.9 DL 343 218.9 337.5 218.9 DL 348.5 218.9 343 -218.9 DL 354 218.9 348.5 218.9 DL 359.5 218.9 354 218.9 DL 365 218.9 359.5 -218.9 DL 370.5 218.9 365 218.9 DL 376 218.9 370.5 218.9 DL 381.5 218.9 376 -218.9 DL 387 218.9 381.5 218.9 DL 392.5 218.9 387 218.9 DL 398 218.9 392.5 -218.9 DL 403.5 218.9 398 218.9 DL 409 218.9 403.5 218.9 DL 414.5 218.9 409 -218.9 DL 420 218.9 414.5 218.9 DL 425.5 218.9 420 218.9 DL 431 218.9 425.5 -218.9 DL 436.5 218.9 431 218.9 DL 442 218.9 436.5 218.9 DL 447.5 218.9 442 -218.9 DL 453 218.9 447.5 218.9 DL 458.5 218.9 453 218.9 DL 464 218.9 458.5 -218.9 DL 469.5 218.9 464 218.9 DL 475 218.9 469.5 218.9 DL 480.5 218.9 475 -218.9 DL 486 218.9 480.5 218.9 DL 72 36 288.232 491.828 DE ST 291.832 437.828 -288.232 437.828 DL 298.312 437.828 294.712 437.828 DL 304.792 437.828 301.192 -437.828 DL 311.272 437.828 307.672 437.828 DL 317.752 437.828 314.152 437.828 -DL 324.232 437.828 320.632 437.828 DL 324.232 434.228 324.232 437.828 DL -324.232 427.028 324.232 430.628 DL 324.232 419.828 324.232 423.428 DL 324.232 -412.628 324.232 416.228 DL 324.232 405.428 324.232 409.028 DL 324.232 398.228 -324.232 401.828 DL 324.232 391.028 324.232 394.628 DL 324.232 383.828 324.232 -387.428 DL 324.232 376.628 324.232 380.228 DL 324.232 369.428 324.232 373.028 -DL 324.232 362.228 324.232 365.828 DL 324.232 355.028 324.232 358.628 DL -324.232 347.9 324.232 351.5 DL 324.232 340.7 324.232 344.3 DL 324.232 333.5 -324.232 337.1 DL 324.232 326.3 324.232 329.9 DL 324.232 319.1 324.232 322.7 DL -324.232 311.9 324.232 315.5 DL 324.232 304.7 324.232 308.3 DL 324.232 297.5 -324.232 301.1 DL 324.232 290.3 324.232 293.9 DL 324.232 283.1 324.232 286.7 DL -324.232 275.9 324.232 279.5 DL 327.832 275.9 324.232 275.9 DL 334.312 275.9 -330.712 275.9 DL 340.792 275.9 337.192 275.9 DL 347.272 275.9 343.672 275.9 DL -353.752 275.9 350.152 275.9 DL 360.232 275.9 356.632 275.9 DL 360.232 275.9 -353.104 277.7 DL 353.104 274.1 360.232 275.9 DL 219.832 383.9 216.232 383.9 DL -227.464 383.9 223.864 383.9 DL 235.024 383.9 231.424 383.9 DL 242.656 383.9 -239.056 383.9 DL 250.216 383.9 246.616 383.9 DL 257.848 383.9 254.248 383.9 DL -265.408 383.9 261.808 383.9 DL 273.04 383.9 269.44 383.9 DL 280.6 383.9 277 -383.9 DL 288.232 383.9 284.632 383.9 DL 288.232 387.5 288.232 383.9 DL 288.232 -394.7 288.232 391.1 DL 288.232 401.9 288.232 398.3 DL 288.232 409.1 288.232 -405.5 DL 288.232 416.3 288.232 412.7 DL 288.232 423.5 288.232 419.9 DL 288.232 -430.7 288.232 427.1 DL 288.232 437.828 288.232 434.228 DL 288.232 445.028 -288.232 441.428 DL 288.232 452.228 288.232 448.628 DL 288.232 459.428 288.232 -455.828 DL 288.232 466.628 288.232 463.028 DL 288.232 473.828 288.232 470.228 -DL 288.232 473.828 286.432 466.7 DL 290.032 466.7 288.232 473.828 DL 360.232 -491.828 324.232 491.828 DL 360.232 491.828 353.104 493.7 DL 353.104 490.028 -360.232 491.828 DL 252.232 491.828 216.232 491.828 DL 252.232 491.828 245.032 -493.7 DL 245.032 490.028 252.232 491.828 DL 180.304 509.828 180.304 545.828 DL -180.304 509.828 182.032 517.028 DL 178.504 517.028 180.304 509.828 DL 216.232 -473.828 144.304 473.828 DL 216.232 509.828 216.232 473.828 DL 144.304 509.828 -216.232 509.828 DL 144.304 473.828 144.304 509.828 DL 432.232 329.9 360.232 -329.9 DL 432.232 365.9 432.232 329.9 DL 360.232 365.9 432.232 365.9 DL 360.232 -329.9 360.232 365.9 DL 432.232 401.9 360.232 401.9 DL 432.232 437.828 432.232 -401.9 DL 360.232 437.828 432.232 437.828 DL 360.232 401.9 360.232 437.828 DL -432.232 473.828 360.232 473.828 DL 432.232 509.828 432.232 473.828 DL 360.232 -509.828 432.232 509.828 DL 360.232 473.828 360.232 509.828 DL 396.232 437.828 -396.232 473.828 DL 396.232 437.828 398.104 445.028 DL 394.432 445.028 396.232 -437.828 DL 396.232 365.9 396.232 401.9 DL 396.232 365.9 398.104 373.1 DL -394.432 373.1 396.232 365.9 DL 432.232 257.9 360.232 257.9 DL 432.232 293.9 -432.232 257.9 DL 360.232 293.9 432.232 293.9 DL 360.232 257.9 360.232 293.9 DL -396.232 293.9 396.232 329.9 DL 396.232 293.9 398.104 301.1 DL 394.432 301.1 -396.232 293.9 DL 486.232 545.828 486.232 617.828 DL 126.304 545.828 486.232 -545.828 DL 126.304 617.828 126.304 545.828 DL 486.232 617.828 126.304 617.828 -DL("HEAD")166.768 388.552 Q('SunOS')270.232 528.088 Q(1.1.1)274.768 492.088 Q -(1.1)171.304 492.088 Q(1.1.1.1)378.232 492.088 Q(1.1.1.2)378.232 420.088 Q -(1.1.1.3)378.232 348.088 Q(1.1.1.4)378.232 276.088 Q('SunOS_4_0')450.232 -492.088 Q('SunOS_4_0_1')450.232 420.088 Q('Y)450.232 348.088 Q(APT_5_5C')-1.32 -E('SunOS_4_0_3')450.232 276.088 Q(rcs\214le.c,v)270.232 582.088 Q 131.5 649.328 -126 649.328 DL 134 649.328 128.5 649.328 DL 139.5 649.328 134 649.328 DL 145 -649.328 139.5 649.328 DL 150.5 649.328 145 649.328 DL 156 649.328 150.5 649.328 -DL 161.5 649.328 156 649.328 DL 167 649.328 161.5 649.328 DL 172.5 649.328 167 -649.328 DL 178 649.328 172.5 649.328 DL 183.5 649.328 178 649.328 DL 189 -649.328 183.5 649.328 DL 194.5 649.328 189 649.328 DL 200 649.328 194.5 649.328 -DL 205.5 649.328 200 649.328 DL 211 649.328 205.5 649.328 DL 216.5 649.328 211 -649.328 DL 222 649.328 216.5 649.328 DL 227.5 649.328 222 649.328 DL 233 -649.328 227.5 649.328 DL 238.5 649.328 233 649.328 DL 244 649.328 238.5 649.328 -DL 249.5 649.328 244 649.328 DL 255 649.328 249.5 649.328 DL 260.5 649.328 255 -649.328 DL 266 649.328 260.5 649.328 DL 271.5 649.328 266 649.328 DL 277 -649.328 271.5 649.328 DL 282.5 649.328 277 649.328 DL 288 649.328 282.5 649.328 -DL 293.5 649.328 288 649.328 DL 299 649.328 293.5 649.328 DL 304.5 649.328 299 -649.328 DL 310 649.328 304.5 649.328 DL 315.5 649.328 310 649.328 DL 321 -649.328 315.5 649.328 DL 326.5 649.328 321 649.328 DL 332 649.328 326.5 649.328 -DL 337.5 649.328 332 649.328 DL 343 649.328 337.5 649.328 DL 348.5 649.328 343 -649.328 DL 354 649.328 348.5 649.328 DL 359.5 649.328 354 649.328 DL 365 -649.328 359.5 649.328 DL 370.5 649.328 365 649.328 DL 376 649.328 370.5 649.328 -DL 381.5 649.328 376 649.328 DL 387 649.328 381.5 649.328 DL 392.5 649.328 387 -649.328 DL 398 649.328 392.5 649.328 DL 403.5 649.328 398 649.328 DL 409 -649.328 403.5 649.328 DL 414.5 649.328 409 649.328 DL 420 649.328 414.5 649.328 -DL 425.5 649.328 420 649.328 DL 431 649.328 425.5 649.328 DL 436.5 649.328 431 -649.328 DL 442 649.328 436.5 649.328 DL 447.5 649.328 442 649.328 DL 453 -649.328 447.5 649.328 DL 458.5 649.328 453 649.328 DL 464 649.328 458.5 649.328 -DL 469.5 649.328 464 649.328 DL 475 649.328 469.5 649.328 DL 480.5 649.328 475 -649.328 DL 486 649.328 480.5 649.328 DL/F4 13/Times-Bold@0 SF(Figur)281.202 -675.328 Q 3.25(e2)-.234 G(.)327.547 675.328 Q F1(cvs)243.223 688.328 Q F0 --1.221(Ve)2.75 G(ndor Branch Example)1.221 E .753(Once this is done, de)90 -705.228 R -.165(ve)-.275 G .753(lopers can check out \214les and mak).165 F -3.503(el)-.11 G .754(ocal changes to the v)362.294 705.228 R(endor')-.165 E -3.504(ss)-.605 G(ource)497.569 705.228 Q(distrib)90 718.228 Q 3.267 -(ution. These)-.22 F .516(local changes form a ne)3.267 F 3.266(wb)-.275 G .516 -(ranch to the tree which is then used as the source)301.779 718.228 R EP -%%Page: 5 5 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF .422(for future check outs.)90 85 R .423(Figure 3 sho) -5.922 F .423(ws ho)-.275 F 3.173(wt)-.275 G .423(he \231head\232 mo)287.134 85 -R -.165(ve)-.165 G 3.173(st).165 G 3.173(ot)369.022 85 S .423(he main)380.753 -85 R/F1 9/Times-Roman@0 SF(RCS)3.173 E F0 .423(trunk when a local)2.673 F -(modi\214cation is made.)90 98 Q .44 LW 131.5 111 126 111 DL 134 111 128.5 111 -DL 139.5 111 134 111 DL 145 111 139.5 111 DL 150.5 111 145 111 DL 156 111 150.5 -111 DL 161.5 111 156 111 DL 167 111 161.5 111 DL 172.5 111 167 111 DL 178 111 -172.5 111 DL 183.5 111 178 111 DL 189 111 183.5 111 DL 194.5 111 189 111 DL 200 -111 194.5 111 DL 205.5 111 200 111 DL 211 111 205.5 111 DL 216.5 111 211 111 DL -222 111 216.5 111 DL 227.5 111 222 111 DL 233 111 227.5 111 DL 238.5 111 233 -111 DL 244 111 238.5 111 DL 249.5 111 244 111 DL 255 111 249.5 111 DL 260.5 111 -255 111 DL 266 111 260.5 111 DL 271.5 111 266 111 DL 277 111 271.5 111 DL 282.5 -111 277 111 DL 288 111 282.5 111 DL 293.5 111 288 111 DL 299 111 293.5 111 DL -304.5 111 299 111 DL 310 111 304.5 111 DL 315.5 111 310 111 DL 321 111 315.5 -111 DL 326.5 111 321 111 DL 332 111 326.5 111 DL 337.5 111 332 111 DL 343 111 -337.5 111 DL 348.5 111 343 111 DL 354 111 348.5 111 DL 359.5 111 354 111 DL 365 -111 359.5 111 DL 370.5 111 365 111 DL 376 111 370.5 111 DL 381.5 111 376 111 DL -387 111 381.5 111 DL 392.5 111 387 111 DL 398 111 392.5 111 DL 403.5 111 398 -111 DL 409 111 403.5 111 DL 414.5 111 409 111 DL 420 111 414.5 111 DL 425.5 111 -420 111 DL 431 111 425.5 111 DL 436.5 111 431 111 DL 442 111 436.5 111 DL 447.5 -111 442 111 DL 453 111 447.5 111 DL 458.5 111 453 111 DL 464 111 458.5 111 DL -469.5 111 464 111 DL 475 111 469.5 111 DL 480.5 111 475 111 DL 486 111 480.5 -111 DL 72 36 288.232 383.928 DE ST 253.168 217.464 256.768 217.464 DL 245.896 -217.464 249.496 217.464 DL 238.624 217.464 242.224 217.464 DL 231.28 217.464 -234.88 217.464 DL 224.008 217.464 227.608 217.464 DL 216.736 217.464 220.336 -217.464 DL 209.464 217.464 213.064 217.464 DL 202.192 217.464 205.792 217.464 -DL 194.848 217.464 198.448 217.464 DL 187.576 217.464 191.176 217.464 DL -180.304 217.464 183.904 217.464 DL 180.304 221.064 180.304 217.464 DL 180.304 -228.336 180.304 224.736 DL 180.304 235.68 180.304 232.08 DL 180.304 242.952 -180.304 239.352 DL 180.304 250.224 180.304 246.624 DL 180.304 257.568 180.304 -253.968 DL 180.304 264.84 180.304 261.24 DL 180.304 272.112 180.304 268.512 DL -180.304 279.384 180.304 275.784 DL 180.304 286.728 180.304 283.128 DL 180.304 -294 180.304 290.4 DL 180.304 294 178.504 286.8 DL 182.032 286.8 180.304 294 DL -180.304 329.928 180.304 365.928 DL 180.304 329.928 182.032 337.128 DL 178.504 -337.128 180.304 329.928 DL 216.232 294 144.304 294 DL 216.232 329.928 216.232 -294 DL 144.304 329.928 216.232 329.928 DL 144.304 294 144.304 329.928 DL -360.232 383.928 324.232 383.928 DL 360.232 383.928 353.104 385.8 DL 353.104 -382.128 360.232 383.928 DL 252.232 383.928 216.232 383.928 DL 252.232 383.928 -245.032 385.8 DL 245.032 382.128 252.232 383.928 DL 180.304 401.928 180.304 -437.928 DL 180.304 401.928 182.032 409.128 DL 178.504 409.128 180.304 401.928 -DL 216.232 365.928 144.304 365.928 DL 216.232 401.928 216.232 365.928 DL -144.304 401.928 216.232 401.928 DL 144.304 365.928 144.304 401.928 DL 432.232 -222 360.232 222 DL 432.232 258 432.232 222 DL 360.232 258 432.232 258 DL -360.232 222 360.232 258 DL 432.232 294 360.232 294 DL 432.232 329.928 432.232 -294 DL 360.232 329.928 432.232 329.928 DL 360.232 294 360.232 329.928 DL -432.232 365.928 360.232 365.928 DL 432.232 401.928 432.232 365.928 DL 360.232 -401.928 432.232 401.928 DL 360.232 365.928 360.232 401.928 DL 396.232 329.928 -396.232 365.928 DL 396.232 329.928 398.104 337.128 DL 394.432 337.128 396.232 -329.928 DL 396.232 258 396.232 294 DL 396.232 258 398.104 265.2 DL 394.432 -265.2 396.232 258 DL 432.232 150 360.232 150 DL 432.232 186 432.232 150 DL -360.232 186 432.232 186 DL 360.232 150 360.232 186 DL 396.232 186 396.232 222 -DL 396.232 186 398.104 193.2 DL 394.432 193.2 396.232 186 DL 486.232 437.928 -486.232 509.928 DL 126.304 437.928 486.232 437.928 DL 126.304 509.928 126.304 -437.928 DL 486.232 509.928 126.304 509.928 DL(1.2)171.304 312.188 Q("HEAD") -261.232 222.188 Q('SunOS')270.232 420.188 Q(1.1.1)274.768 384.188 Q(1.1)171.304 -384.188 Q(1.1.1.1)378.232 384.188 Q(1.1.1.2)378.232 312.188 Q(1.1.1.3)378.232 -240.188 Q(1.1.1.4)378.232 168.188 Q('SunOS_4_0')450.232 384.188 Q -('SunOS_4_0_1')450.232 312.188 Q('Y)450.232 240.188 Q(APT_5_5C')-1.32 E -('SunOS_4_0_3')450.232 168.188 Q(rcs\214le.c,v)270.232 474.188 Q 131.5 541.428 -126 541.428 DL 134 541.428 128.5 541.428 DL 139.5 541.428 134 541.428 DL 145 -541.428 139.5 541.428 DL 150.5 541.428 145 541.428 DL 156 541.428 150.5 541.428 -DL 161.5 541.428 156 541.428 DL 167 541.428 161.5 541.428 DL 172.5 541.428 167 -541.428 DL 178 541.428 172.5 541.428 DL 183.5 541.428 178 541.428 DL 189 -541.428 183.5 541.428 DL 194.5 541.428 189 541.428 DL 200 541.428 194.5 541.428 -DL 205.5 541.428 200 541.428 DL 211 541.428 205.5 541.428 DL 216.5 541.428 211 -541.428 DL 222 541.428 216.5 541.428 DL 227.5 541.428 222 541.428 DL 233 -541.428 227.5 541.428 DL 238.5 541.428 233 541.428 DL 244 541.428 238.5 541.428 -DL 249.5 541.428 244 541.428 DL 255 541.428 249.5 541.428 DL 260.5 541.428 255 -541.428 DL 266 541.428 260.5 541.428 DL 271.5 541.428 266 541.428 DL 277 -541.428 271.5 541.428 DL 282.5 541.428 277 541.428 DL 288 541.428 282.5 541.428 -DL 293.5 541.428 288 541.428 DL 299 541.428 293.5 541.428 DL 304.5 541.428 299 -541.428 DL 310 541.428 304.5 541.428 DL 315.5 541.428 310 541.428 DL 321 -541.428 315.5 541.428 DL 326.5 541.428 321 541.428 DL 332 541.428 326.5 541.428 -DL 337.5 541.428 332 541.428 DL 343 541.428 337.5 541.428 DL 348.5 541.428 343 -541.428 DL 354 541.428 348.5 541.428 DL 359.5 541.428 354 541.428 DL 365 -541.428 359.5 541.428 DL 370.5 541.428 365 541.428 DL 376 541.428 370.5 541.428 -DL 381.5 541.428 376 541.428 DL 387 541.428 381.5 541.428 DL 392.5 541.428 387 -541.428 DL 398 541.428 392.5 541.428 DL 403.5 541.428 398 541.428 DL 409 -541.428 403.5 541.428 DL 414.5 541.428 409 541.428 DL 420 541.428 414.5 541.428 -DL 425.5 541.428 420 541.428 DL 431 541.428 425.5 541.428 DL 436.5 541.428 431 -541.428 DL 442 541.428 436.5 541.428 DL 447.5 541.428 442 541.428 DL 453 -541.428 447.5 541.428 DL 458.5 541.428 453 541.428 DL 464 541.428 458.5 541.428 -DL 469.5 541.428 464 541.428 DL 475 541.428 469.5 541.428 DL 480.5 541.428 475 -541.428 DL 486 541.428 480.5 541.428 DL/F2 13/Times-Bold@0 SF(Figur)281.202 -567.428 Q 3.25(e3)-.234 G(.)327.547 567.428 Q/F3 11/Times-Bold@0 SF(cvs)214.804 -580.428 Q F0(Local Modi\214cation to V)2.75 E(endor Branch)-1.221 E .663 -(When a ne)117.5 610.328 R 3.413(wv)-.275 G .662(ersion of the v)182.277 -610.328 R(endor')-.165 E 3.412(ss)-.605 G .662(ource distrib)287.413 610.328 R -.662(ution arri)-.22 F -.165(ve)-.275 G .662(s, the).165 F F3(checkin)3.412 E -F0 .662(program adds)3.412 F .879(the ne)90 623.328 R 3.629(wa)-.275 G .879 -(nd changed v)133.635 623.328 R(endor')-.165 E 3.629<738c>-.605 G .879 -(les to the already e)236.009 623.328 R .879(xisting source repository)-.165 F -6.379(.F)-.715 G .879(or \214les that ha)446.729 623.328 R -.165(ve)-.22 G .476 -(not been changed locally)90 636.328 R 3.226(,t)-.715 G .476(he ne)209.417 -636.328 R 3.226<778c>-.275 G .476(le from the v)250.42 636.328 R .475 -(endor becomes the current \231head\232 re)-.165 F 3.225(vision. F)-.275 F(or) --.165 E 1.192(\214les that ha)90 649.328 R 1.522 -.165(ve b)-.22 H 1.192 -(een modi\214ed locally).165 F(,)-.715 E F3(checkin)3.942 E F0 -.11(wa)3.943 G -1.193(rns that the \214le must be mer).11 F 1.193(ged with the ne)-.198 F(w) --.275 E -.165(ve)90 662.328 S .394(ndor release.).165 F(The)5.893 E F3(cvs) -3.143 E F0 .393(\231join\232 command is a useful tool that aids this process b\ -y performing the)3.143 F(necessary)90 675.328 Q F1(RCS)2.75 E F0(mer)2.25 E -(ge, as is done abo)-.198 E .33 -.165(ve w)-.165 H -(hen performing an \231update.).165 E<9a>-.77 E .073 -(There is also limited support for \231dual\232 deri)117.5 692.228 R -.275(va) --.275 G .073(tions for source \214les.).275 F .074(See Figure 4 for a sam-) -5.574 F 1.767(ple dual-deri)90 705.228 R -.165(ve)-.275 G 4.517<648c>.165 G -4.516(le. This)173.746 705.228 R -.165(ex)4.516 G 1.766 -(ample tracks the SunOS distrib).165 F 1.766(ution b)-.22 F 1.766 -(ut includes major changes)-.22 F(from Berk)90 718.228 Q(ele)-.11 E 4.18 -.715 -(y. T)-.165 H(hese BSD \214les are sa).715 E -.165(ve)-.22 G 2.75(dd).165 G -(irectly in the)284.447 718.228 Q F1(RCS)2.75 E F0(\214le of)2.25 E 2.75(fan) --.275 G .55 -.275(ew b)407.305 718.228 T(ranch.).275 E EP -%%Page: 6 6 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF(-6-)299.587 49 Q .44 LW 131.5 85 126 85 DL 134 85 128.5 -85 DL 139.5 85 134 85 DL 145 85 139.5 85 DL 150.5 85 145 85 DL 156 85 150.5 85 -DL 161.5 85 156 85 DL 167 85 161.5 85 DL 172.5 85 167 85 DL 178 85 172.5 85 DL -183.5 85 178 85 DL 189 85 183.5 85 DL 194.5 85 189 85 DL 200 85 194.5 85 DL -205.5 85 200 85 DL 211 85 205.5 85 DL 216.5 85 211 85 DL 222 85 216.5 85 DL -227.5 85 222 85 DL 233 85 227.5 85 DL 238.5 85 233 85 DL 244 85 238.5 85 DL -249.5 85 244 85 DL 255 85 249.5 85 DL 260.5 85 255 85 DL 266 85 260.5 85 DL -271.5 85 266 85 DL 277 85 271.5 85 DL 282.5 85 277 85 DL 288 85 282.5 85 DL -293.5 85 288 85 DL 299 85 293.5 85 DL 304.5 85 299 85 DL 310 85 304.5 85 DL -315.5 85 310 85 DL 321 85 315.5 85 DL 326.5 85 321 85 DL 332 85 326.5 85 DL -337.5 85 332 85 DL 343 85 337.5 85 DL 348.5 85 343 85 DL 354 85 348.5 85 DL -359.5 85 354 85 DL 365 85 359.5 85 DL 370.5 85 365 85 DL 376 85 370.5 85 DL -381.5 85 376 85 DL 387 85 381.5 85 DL 392.5 85 387 85 DL 398 85 392.5 85 DL -403.5 85 398 85 DL 409 85 403.5 85 DL 414.5 85 409 85 DL 420 85 414.5 85 DL -425.5 85 420 85 DL 431 85 425.5 85 DL 436.5 85 431 85 DL 442 85 436.5 85 DL -447.5 85 442 85 DL 453 85 447.5 85 DL 458.5 85 453 85 DL 464 85 458.5 85 DL -469.5 85 464 85 DL 475 85 469.5 85 DL 480.5 85 475 85 DL 486 85 480.5 85 DL -50.4 27 303.48 241 DE ST 50.4 27 301.68 200.536 DE ST 223.416 184.264 223.416 -209.536 DL 223.416 184.264 225.216 191.464 DL 221.616 191.464 223.416 184.264 -DL 250.416 158.2 198.216 158.2 DL 250.416 184.264 250.416 158.2 DL 198.216 -184.264 250.416 184.264 DL 198.216 158.2 198.216 184.264 DL 250.416 209.536 -198.216 209.536 DL 250.416 235.6 250.416 209.536 DL 198.216 235.6 250.416 235.6 -DL 198.216 209.536 198.216 235.6 DL 479.016 124 426.816 124 DL 479.016 149.2 -479.016 124 DL 426.816 149.2 479.016 149.2 DL 426.816 124 426.816 149.2 DL -479.016 176.2 426.816 176.2 DL 479.016 202.264 479.016 176.2 DL 426.816 202.264 -479.016 202.264 DL 426.816 176.2 426.816 202.264 DL 479.016 227.536 426.816 -227.536 DL 479.016 253.6 479.016 227.536 DL 426.816 253.6 479.016 253.6 DL -426.816 227.536 426.816 253.6 DL 453.816 202.264 453.816 227.536 DL 453.816 -202.264 455.616 209.464 DL 452.016 209.464 453.816 202.264 DL 453.816 149.2 -453.816 176.2 DL 453.816 149.2 455.616 156.4 DL 452.016 156.4 453.816 149.2 DL -407.016 138.4 354.816 138.4 DL 407.016 164.536 407.016 138.4 DL 354.816 164.536 -407.016 164.536 DL 354.816 138.4 354.816 164.536 DL 407.016 187.936 354.816 -187.936 DL 407.016 214 407.016 187.936 DL 354.816 214 407.016 214 DL 354.816 -187.936 354.816 214 DL 186.552 277 186.552 331 DL 489.816 277 186.552 277 DL -489.816 331 489.816 277 DL 186.552 331 489.816 331 DL 224.352 236.536 224.352 -277 DL 224.352 236.536 226.08 243.736 DL 222.552 243.736 224.352 236.536 DL -277.416 241 251.352 223 DL 277.416 241 270.432 238.408 DL 272.52 235.456 -277.416 241 DL 426.816 241 327.816 241 DL 426.816 241 419.616 242.8 DL 419.616 -239.2 426.816 241 DL 354.816 200.536 327.816 200.536 DL 354.816 200.536 347.616 -202.336 DL 347.616 198.736 354.816 200.536 DL 381.816 164.536 381.816 187 DL -381.816 164.536 383.616 171.736 DL 380.016 171.736 381.816 164.536 DL 273.816 -200.536 251.352 223 DL 273.816 200.536 270 206.872 DL 267.48 204.352 273.816 -200.536 DL('BSD')289.152 178.188 Q(1.2)215.352 173.724 Q(1.1)216.216 224.988 Q -(1.1.1.1)435.816 245.724 Q(1.1.1.2)435.816 192.588 Q(1.1.1.3)435.816 141.324 Q -(1.1.2.2)363.816 155.724 Q(1.1.2.1)363.816 205.188 Q(rcs\214le.c,v)309.816 -305.988 Q(1.1.1)291.816 243.924 Q('SunOS')288.216 267.324 Q(1.1.2)290.952 -203.388 Q 131.5 362.5 126 362.5 DL 134 362.5 128.5 362.5 DL 139.5 362.5 134 -362.5 DL 145 362.5 139.5 362.5 DL 150.5 362.5 145 362.5 DL 156 362.5 150.5 -362.5 DL 161.5 362.5 156 362.5 DL 167 362.5 161.5 362.5 DL 172.5 362.5 167 -362.5 DL 178 362.5 172.5 362.5 DL 183.5 362.5 178 362.5 DL 189 362.5 183.5 -362.5 DL 194.5 362.5 189 362.5 DL 200 362.5 194.5 362.5 DL 205.5 362.5 200 -362.5 DL 211 362.5 205.5 362.5 DL 216.5 362.5 211 362.5 DL 222 362.5 216.5 -362.5 DL 227.5 362.5 222 362.5 DL 233 362.5 227.5 362.5 DL 238.5 362.5 233 -362.5 DL 244 362.5 238.5 362.5 DL 249.5 362.5 244 362.5 DL 255 362.5 249.5 -362.5 DL 260.5 362.5 255 362.5 DL 266 362.5 260.5 362.5 DL 271.5 362.5 266 -362.5 DL 277 362.5 271.5 362.5 DL 282.5 362.5 277 362.5 DL 288 362.5 282.5 -362.5 DL 293.5 362.5 288 362.5 DL 299 362.5 293.5 362.5 DL 304.5 362.5 299 -362.5 DL 310 362.5 304.5 362.5 DL 315.5 362.5 310 362.5 DL 321 362.5 315.5 -362.5 DL 326.5 362.5 321 362.5 DL 332 362.5 326.5 362.5 DL 337.5 362.5 332 -362.5 DL 343 362.5 337.5 362.5 DL 348.5 362.5 343 362.5 DL 354 362.5 348.5 -362.5 DL 359.5 362.5 354 362.5 DL 365 362.5 359.5 362.5 DL 370.5 362.5 365 -362.5 DL 376 362.5 370.5 362.5 DL 381.5 362.5 376 362.5 DL 387 362.5 381.5 -362.5 DL 392.5 362.5 387 362.5 DL 398 362.5 392.5 362.5 DL 403.5 362.5 398 -362.5 DL 409 362.5 403.5 362.5 DL 414.5 362.5 409 362.5 DL 420 362.5 414.5 -362.5 DL 425.5 362.5 420 362.5 DL 431 362.5 425.5 362.5 DL 436.5 362.5 431 -362.5 DL 442 362.5 436.5 362.5 DL 447.5 362.5 442 362.5 DL 453 362.5 447.5 -362.5 DL 458.5 362.5 453 362.5 DL 464 362.5 458.5 362.5 DL 469.5 362.5 464 -362.5 DL 475 362.5 469.5 362.5 DL 480.5 362.5 475 362.5 DL 486 362.5 480.5 -362.5 DL/F1 13/Times-Bold@0 SF(Figur)281.202 388.5 Q 3.25(e4)-.234 G(.)327.547 -388.5 Q/F2 11/Times-Bold@0 SF(cvs)227.229 401.5 Q F0(Support F)2.75 E -(or \231Dual\232 Deri)-.165 E -.275(va)-.275 G(tions).275 E F2 2.75 -(2.3. Location)90 427.5 R(Independent Module Database)2.75 E(cvs)117.5 444.4 Q -F0 1.349(contains support for a simple, yet po)4.099 F 1.349 -(werful, \231module\232 database.)-.275 F -.165(Fo)6.85 G 4.1(rr).165 G 1.35 -(easons of ef)457.26 444.4 R<8c2d>-.275 E(cienc)90 457.4 Q 2.1 -.715(y, t)-.165 -H .67(his database is stored in).715 F F2(ndbm)3.42 E F0 .67(\(3\) format.) -1.833 F .669(The module database is used to apply names)6.17 F .212 -(to collections of directories and \214les as a matter of con)90 470.4 R -.165 -(ve)-.44 G .212(nience for checking out pieces of a lar).165 F(ge)-.198 E -(softw)90 483.4 Q 1.907(are distrib)-.11 F 4.657(ution. The)-.22 F 1.907 -(database records the ph)4.657 F 1.907 -(ysical location of the sources as a form of)-.055 F .088 -(information hiding, allo)90 496.4 R .089 -(wing one to check out whole directory hierarchies or indi)-.275 F .089 -(vidual \214les with-)-.275 F(out re)90 509.4 Q -.055(ga)-.165 G -(rd for their actual location within the global source distrib).055 E(ution.) --.22 E .773(Consider the follo)117.5 526.3 R .772 -(wing small sample of a module database, which must be tailored manu-)-.275 F -(ally to each speci\214c source repository en)90 539.3 Q(vironment:)-.44 E/F3 -11/Courier@0 SF 33(#key [-option)181 558.8 R(argument] directory [files...])6.6 -E 33(diff bin/diff)181 571.8 R 33(libc lib/libc)181 584.8 R 39.6(sys -o)181 -597.8 R(sys/tools/make_links sys)6.6 E 13.2(modules -i)181 610.8 R -(mkmodules CVSROOT.adm modules)6.6 E 19.8(kernel -a)181 623.8 R(sys lang/adb) -6.6 E 46.2(ps bin)181 636.8 R(Makefile ps.c)6.6 E F0 1.66(The \231dif)117.5 -660.2 R 1.661(f\232 and \231libc\232 modules refer to whole directory hierarch\ -ies that are e)-.275 F 1.661(xtracted on)-.165 F .406(check out.)90 673.2 R -.405(The \231sys\232 module e)5.906 F .405(xtracts the \231sys\232 hierarch) --.165 F 1.835 -.715(y, a)-.055 H .405(nd runs the \231mak).715 F .405 -(e_links\232 program at)-.11 F 1.529(the end of the check out process \(the)90 -686.2 R/F4 11/Times-Italic@0 SF(-o)4.279 E F0 1.53 -(option speci\214es a program to run on check)4.279 F F4(o)A F0 4.28(ut\). The) -B 1.286(\231modules\232 module allo)90 699.2 R 1.285 -(ws one to edit the module database \214le and runs the \231mkmodules\232 pro-) --.275 F .401(gram on check)90 712.2 R F4(i)A F0 3.151(nt)C 3.151(or)170.326 -712.2 S -.165(eg)182.64 712.2 S .401(enerate the).165 F F2(ndbm)3.151 E F0 .401 -(database that)3.151 F F2(cvs)3.151 E F0 3.151(uses. The)3.151 F<996b>3.152 E -.402(ernel\232 module is an alias)-.11 F EP -%%Page: 7 7 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF 1.136(\(as the)90 85 R/F1 11/Times-Italic@0 SF(-a)3.886 -E F0 1.136(option speci\214es\) which causes the remaining ar)3.886 F 1.136 -(guments after the)-.198 F F1(-a)3.885 E F0 1.135(to be interpreted)3.885 F --.165(ex)90 98 S .469(actly as if the).165 F 3.219(yh)-.165 G .469 -(ad been speci\214ed on the command line.)174.64 98 R .47 -(This is useful for objects that require)5.97 F .519 -(shared pieces of code from f)90 111 R .519(ar a)-.11 F -.11(wa)-.165 G 3.269 -(yp).11 G .519(laces to be compiled \(as is the case with the k)260.932 111 R -.518(ernel deb)-.11 F(ug-)-.22 E(ger)90 124 Q(,)-.44 E/F2 11/Times-Bold@0 SF -(kadb)3.28 E F0 3.28(,w)C .531(hich shares code with the standard)147.457 124 R -F2(adb)3.281 E F0(deb)3.281 E 3.281(ugger\). The)-.22 F .531 -(\231ps\232 module sho)3.281 F .531(ws that the)-.275 F 1.019 -(source for \231ps\232 li)90 137 R -.165(ve)-.275 G 3.769(si).165 G 3.769(nt) -189.556 137 S 1.019(he \231bin\232 directory)201.883 137 R 3.769(,b)-.715 G -1.019(ut only)294.425 137 R F1(Mak)3.769 E(e\214le)-.11 E F0(and)3.769 E F1 -(ps.c)3.769 E F0 1.019(are required to b)3.769 F 1.018(uild the)-.22 F(object.) -90 150 Q 2.129(The module database at Prisma is no)117.5 166.9 R 4.88(wp)-.275 -G 2.13(opulated for the entire UNIX distrib)309.636 166.9 R 2.13(ution and)-.22 -F 1.173(thereby allo)90 179.9 R 1.173(ws us to issue the follo)-.275 F 1.173 -(wing con)-.275 F -.165(ve)-.44 G 1.173 -(nient commands to check out components of the).165 F(UNIX distrib)90 192.9 Q -(ution without re)-.22 E -.055(ga)-.165 G -(rd for their actual location within the master source repository:).055 E/F3 11 -/Courier@0 SF(example% cvs checkout diff)181 212.4 Q -(example% cvs checkout libc ps)181 225.4 Q(example% cd diff; make)181 238.4 Q -F0 1.463(In b)117.5 261.8 R 1.463 -(uilding the module database \214le, it is quite possible to ha)-.22 F 1.794 --.165(ve n)-.22 H 1.464(ame con\215icts within a).165 F .965(global softw)90 -274.8 R .965(are distrib)-.11 F 3.715(ution. F)-.22 F .965(or e)-.165 F .965 -(xample, SunOS pro)-.165 F .964(vides tw)-.165 F(o)-.11 E F2(cat)3.714 E F0 -.964(programs: one for the stan-)3.714 F 1.305(dard en)90 287.8 R(vironment,) --.44 E F1(/bin/cat)4.055 E F0 4.055(,a)C 1.305(nd one for the System V en) -220.877 287.8 R(vironment,)-.44 E F1(/usr/5bin/cat)4.055 E F0 6.805(.W)C 4.056 -(er)475.957 287.8 S(esolv)488.56 287.8 Q(ed)-.165 E .019 -(this con\215ict by naming the standard)90 300.8 R F2(cat)2.769 E F0 .019 -(module \231cat\232, and the System V)2.769 F F2(cat)2.769 E F0 .019 -(module \2315cat\232.)2.769 F(Sim-)5.519 E .447(ilar name modi\214cations must\ - be applied to other con\215icting names, as might be found between a)90 313.8 -R .171(utility program and a library function, though Prisma chose not to incl\ -ude indi)90 326.8 R .171(vidual library func-)-.275 F -(tions within the module database at this time.)90 339.8 Q F2 2.75 -(2.4. Con\214gurable)90 365.8 R(Logging Support)2.75 E F0(The)117.5 382.7 Q F2 -(cvs)4.549 E F0 1.799(\231commit\232 command is used to mak)4.549 F 4.549(eap) --.11 G 1.799(ermanent change to the master source)347.135 382.7 R .363 -(repository \(where the)90 395.7 R/F4 9/Times-Roman@0 SF(RCS)3.113 E F0 .362 -(\231,v\232 \214les li)2.612 F -.165(ve)-.275 G 3.112(\). Whene).165 F -.165 -(ve)-.275 G 3.112(ra\231).165 G .362 -(commit\232 is done, the log message for the)339.209 395.7 R .978(change is ca\ -refully logged by an arbitrary program \(in a \214le, notes\214le, ne)90 408.7 -R .978(ws database, or mail\).)-.275 F -.165(Fo)90 421.7 S 4.13(re).165 G 1.38 -(xample, a collection of these updates can be used to produce release notices.) -113.963 421.7 R F2(cvs)6.879 E F0 1.379(can be)4.129 F .105(con\214gured to se\ -nd log updates through one or more \214lter programs, based on a re)90 434.7 R -.105(gular e)-.165 F(xpression)-.165 E .08 -(match on the directory that is being changed.)90 447.7 R .08(This allo)5.58 F -.079(ws multiple related or unrelated projects to)-.275 F -.165(ex)90 460.7 S -.752(ist within a single).165 F F2(cvs)3.502 E F0 .753 -(source repository tree, with each dif)3.502 F .753 -(ferent project sending its \231commit\232)-.275 F(reports to a unique log de) -90 473.7 Q(vice.)-.275 E 2.75(As)117.5 490.6 S -(ample logging con\214guration \214le might look as follo)132.471 490.6 Q(ws:) --.275 E F3 33(#regex filter-program)153.5 510.1 R 26.4 -(DEFAULT /usr/local/bin/nfpipe)153.5 523.1 R(-t %s utils.updates)6.6 E 39.6 -(^diag /usr/local/bin/nfpipe)153.5 536.1 R(-t %s diag.updates)6.6 E 33 -(^local /usr/local/bin/nfpipe)153.5 549.1 R(-t %s local.updates)6.6 E 39.6 -(^perf /usr/local/bin/nfpipe)153.5 562.1 R(-t %s perf.updates)6.6 E 46.2 -(^sys /usr/local/bin/nfpipe)153.5 575.1 R(-t %s kernel.updates)6.6 E F0 .094 -(This sample allo)117.5 598.5 R .094 -(ws the diagnostics and performance groups to share the same source repos-) --.275 F .842(itory with the k)90 611.5 R .842(ernel and utilities groups.)-.11 -F .843(Changes that the)6.343 F 3.593(ym)-.165 G(ak)373.139 611.5 Q 3.593(ea) --.11 G .843(re sent directly to their o)396.774 611.5 R(wn)-.275 E .748 -(notes\214le [Essick] through the \231nfpipe\232 program.)90 624.5 R 3.498(As) -6.248 G(uf)328.337 624.5 Q .748 -(\214ciently simple title is substituted for the)-.275 F 1.051(\231%s\232 ar)90 -637.5 R 1.051(gument before the \214lter program is e)-.198 F -.165(xe)-.165 G -3.802(cuted. This).165 F 1.052(logging con\214guration \214le is tailored)3.802 -F(manually to each speci\214c source repository en)90 650.5 Q(vironment.)-.44 E -F2 2.75(2.5. T)90 676.5 R(agged Releases and Dates)-1.012 E F0(An)117.5 693.4 Q -3.342(yr)-.165 G .592(elease can be gi)143.282 693.4 R -.165(ve)-.275 G 3.342 -(nas).165 G .592(ymbolic tag name that is stored directly in the)245.682 693.4 -R F4(RCS)3.342 E F0 3.341(\214les. This)2.842 F .053(tag can be used at an)90 -706.4 R 2.804(yt)-.165 G .054(ime to get an e)192.795 706.4 R .054(xact cop) --.165 F 2.804(yo)-.11 G 2.804(fa)308.322 706.4 S .384 -.165(ny p)319.673 706.4 -T(re).165 E .054(vious release.)-.275 F -.44(Wi)5.554 G .054 -(th equal ease, one can).44 F EP -%%Page: 8 8 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF(-8-)299.587 49 Q .292(also e)90 85 R .292(xtract an e) --.165 F .292(xact cop)-.165 F 3.042(yo)-.11 G 3.042(ft)212.9 85 S .292 -(he source \214les as of an)222.663 85 R 3.042(ya)-.165 G .292 -(rbitrary date in the past as well.)337.275 85 R .291(Thus, all)5.791 F(that') -90 98 Q 2.75(sr)-.605 G(equired to tag the current k)120.25 98 Q -(ernel, and to tag the k)-.11 E(ernel as of the F)-.11 E(ourth of July is:) --.165 E/F1 11/Courier@0 SF(example% cvs tag TEST_KERNEL kernel)153.5 117.5 Q -(example% cvs tag -D 'July 4' PATRIOTIC_KERNEL kernel)153.5 130.5 Q F0 -(The follo)90 150 Q(wing command w)-.275 E(ould retrie)-.11 E .33 -.165(ve a) --.275 H 2.75(ne).165 G(xact cop)285.14 150 Q 2.75(yo)-.11 G 2.75(ft)335.74 150 -S(he test k)345.211 150 Q(ernel at some later date:)-.11 E F1 -(example% cvs checkout -fp -rTEST_KERNEL kernel)153.5 169.5 Q F0(The)90 189 Q -/F2 11/Times-Italic@0 SF(-f)3.945 E F0 1.196 -(option causes only \214les that match the speci\214ed tag to be e)3.945 F -1.196(xtracted, while the)-.165 F F2(-p)3.946 E F0(option)3.946 E 1.355 -(automatically prunes empty directories.)90 202 R(Consequently)6.855 E 4.105 -(,d)-.715 G 1.355(irectories added to the k)347.201 202 R 1.354 -(ernel after the)-.11 F(test k)90 215 Q(ernel w)-.11 E -(as tagged are not included in the ne)-.11 E(wly e)-.275 E(xtracted cop)-.165 E -2.75(yo)-.11 G 2.75(ft)392.885 215 S(he test k)402.356 215 Q(ernel.)-.11 E(The) -117.5 231.9 Q/F3 11/Times-Bold@0 SF(cvs)2.998 E F0 .249(date support has e) -2.998 F .249(xactly the same interf)-.165 F .249(ace as that pro)-.11 F .249 -(vided with)-.165 F/F4 9/Times-Roman@0 SF(RCS)2.999 E F0 2.999(,h)C -.275(ow) -472.68 231.9 S -2.365 -.275(ev e).275 H(r).275 E F3(cvs)2.999 E F0 .183(must p\ -rocess the \231,v\232 \214les directly due to the special handling required by\ - the v)90 244.9 R .183(endor branch sup-)-.165 F 3.016(port. The)90 257.9 R -(standard)3.016 E F4(RCS)3.016 E F0 .267 -(date handling only processes one branch \(or the main trunk\) when check-) -2.517 F .075(ing out based on a date speci\214cation.)90 270.9 R F3(cvs)5.574 E -F0 .074(must instead process the current \231head\232 branch and, if a)2.824 F -.496(match is not found, proceed to look for a match on the v)90 283.9 R .496 -(endor branch.)-.165 F .497(This, combined with rea-)5.996 F 1.157 -(sons of performance, is wh)90 296.9 R(y)-.055 E F3(cvs)3.907 E F0 1.156 -(processes re)3.907 F 1.156 -(vision \(symbolic and numeric\) and date speci\214ca-)-.275 F -(tions directly from the \231,v\232 \214les.)90 309.9 Q F3 2.75(2.6. Building) -90 335.9 R(\231patch\232 Sour)2.75 E(ce Distrib)-.198 E(utions)-.22 E(cvs)117.5 -352.8 Q F0 .112(can produce a \231patch\232 format [W)2.862 F .113 -(all] output \214le which can be used to bring a pre)-.88 F(viously)-.275 E -.872(released softw)90 365.8 R .872(are distrib)-.11 F .872 -(ution current with the ne)-.22 F .871(west release.)-.275 F .871 -(This patch \214le supports an entire)6.371 F .444(directory hierarch)90 378.8 -R 3.194(yw)-.055 G .444 -(ithin a single patch, as well as being able to add whole ne)185.521 378.8 R -3.194<778c>-.275 G .445(les to the pre-)460.485 378.8 R 1.33(vious release.)90 -391.8 R 1.33(One can combine symbolic re)6.83 F 1.33 -(visions and dates together to display changes in a)-.275 F -.165(ve)90 404.8 S -(ry generic w).165 E(ay:)-.11 E F1(example% cvs patch -D 'December 1, 1988' \\) -153.5 424.3 Q(-D 'January 1, 1989' sys)278.9 437.3 Q F0 1.126(This e)90 456.8 R -1.127(xample displays the k)-.165 F 1.127 -(ernel changes made in the month of December)-.11 F 3.877(,1)-.44 G 3.877 -(988. T)441.608 456.8 R 3.877(or)-.88 G 1.127(elease a)486.366 456.8 R .425 -(patch \214le, for e)90 469.8 R .425(xample, to tak)-.165 F 3.175(et)-.11 G(he) -232.195 469.8 Q F3(cvs)3.175 E F0(distrib)3.175 E .425(ution from v)-.22 F .425 -(ersion 1.0 to v)-.165 F .425(ersion 1.4 might be done)-.165 F(as follo)90 -482.8 Q(ws:)-.275 E F1(example% cvs patch -rCVS_1_0 -rCVS_1_4 cvs)153.5 502.3 Q -F3 2.75(3. CVS)90 534.8 R(Experience)2.75 E 2.75(3.1. Statistics)90 560.8 R F0 -2.882(Aq)117.5 577.7 S .132(uick summary of the scale that)133.824 577.7 R F3 -(cvs)2.882 E F0 .133(is addressing today can be found in T)2.882 F .133 -(able 1.)-.88 F -.88(Ta)5.633 G .133(ble 2).88 F(sho)90 590.7 Q .125 -(ws the history of \214les changed or added and the number of source lines af) --.275 F .124(fected by the change)-.275 F 1.062(at Prisma.)90 603.7 R 1.062 -(Only changes made to the k)6.562 F 1.062(ernel sources are included.)-.11 F -1.063(The lar)6.563 F 1.063(ge number of source)-.198 F .116 -(\214le changes made in September are the result of mer)90 616.7 R .115 -(ging the SunOS 4.0.3 sources into the k)-.198 F(ernel.)-.11 E(This mer)90 -629.7 Q(ge process is described in section 3.3.)-.198 E F3 2.75(3.2. P)90 655.7 -R(erf)-.22 E(ormance)-.275 E F0 1.095(The performance of)117.5 672.6 R F3(cvs) -3.845 E F0 1.095(is currently quite reasonable.)3.845 F 1.096(Little ef)6.596 F -1.096(fort has been e)-.275 F 1.096(xpended on)-.165 F(tuning)90 685.6 Q F3 -(cvs)3.295 E F0 3.295(,a)C .545 -(lthough performance related decisions were made during the)147.003 685.6 R F3 -(cvs)3.294 E F0 3.294(design. F)3.294 F .544(or e)-.165 F(xam-)-.165 E(ple,)90 -698.6 Q F3(cvs)2.842 E F0 .092(parses the)2.842 F F4(RCS)2.842 E F0 .093 -(\231,v\232 \214les directly instead of running an)2.343 F F4(RCS)2.843 E F0 -2.843(process. This)2.343 F .093(includes follo)2.843 F(w-)-.275 E 1.552 -(ing branches as well as inte)90 711.6 R 1.552(grating with the v)-.165 F 1.551 -(endor source branches and the main trunk when)-.165 F EP -%%Page: 9 9 -%%BeginPageSetup -BP -%%EndPageSetup -.44 LW 413.471 83.25 198.528 83.25 DL/F0 13/Times-Bold@0 SF(Re)204.028 93.5 Q -(vision Contr)-.195 E(ol Statistics at Prisma)-.234 E(as of 11/11/89)268.442 -106.5 Q 413.471 111.25 198.528 111.25 DL/F1 11/Times-Roman@0 SF(Ho)235.673 -121.5 Q 2.75(wM)-.275 G(an)269.311 121.5 Q -.715(y.)-.165 G 67.855(.. T).715 F -(otal)-.88 E 413.471 126.25 198.528 126.25 DL 413.471 128.25 198.528 128.25 DL -137.917(Files 17243)204.028 138.5 R 115.939(Directories 1005)204.028 151.5 R -(Lines of code)204.028 164.5 Q(3927255)355.09 164.5 Q(Remo)204.028 177.5 Q --.165(ve)-.165 G 2.75<648c>.165 G 107.392(les 131)254.727 177.5 R(Softw)204.028 -190.5 Q(are de)-.11 E -.165(ve)-.275 G 86.25(lopers 14).165 F(Softw)204.028 -203.5 Q(are groups)-.11 E(6)388.09 203.5 Q(Me)204.028 216.5 Q -.055(ga)-.165 G -(bytes of source).055 E(128)377.09 216.5 Q 413.471 221.25 198.528 221.25 DL -332.46 111.25 332.46 221.25 DL 413.471 83.25 413.471 221.25 DL 198.528 83.25 -198.528 221.25 DL F0 -1.196(Ta)284.205 236 S(ble 1.)1.196 E/F2 11/Times-Bold@0 -SF(cvs)277.427 249 Q F1(Statistics)2.75 E 437.686 264.15 174.313 264.15 DL F0 -(Prisma K)207.44 274.4 Q(er)-.325 E(nel Sour)-.195 E(ce File Changes)-.234 E -(By Month, 1988-1989)246.596 287.4 Q 437.686 292.15 174.313 292.15 DL F1 2.75 -(#C)225.65 302.4 S 16.956(hanged #)241.237 302.4 R 16.957(Lines #)2.75 F 13.904 -(Added #)2.75 F(Lines)2.75 E 26.73(Files Changed)238.63 315.4 R 23.678 -(Files Added)353.2 315.4 R(Month)179.813 308.9 Q 437.686 320.15 174.313 320.15 -DL 437.686 322.15 174.313 322.15 DL 49.054(Dec 87)179.813 332.4 R 35.591 -(3619 68)300.807 332.4 R(9266)410.186 332.4 Q 52.101(Jan 39)179.813 345.4 R -41.091(4324 0)300.807 345.4 R(0)426.686 345.4 Q 50.264(Feb 73)179.813 358.4 R -41.091(1578 5)300.807 358.4 R(3550)410.186 358.4 Q 48.438(Mar 99)179.813 371.4 -R 35.591(5301 18)300.807 371.4 R(11461)404.686 371.4 Q 44.159(Apr 112)179.813 -384.4 R 35.591(7333 11)300.807 384.4 R(5759)410.186 384.4 Q 41.101(May 138) -179.813 397.4 R 35.591(5371 17)300.807 397.4 R(13986)404.686 397.4 Q 51.485 -(Jun 65)179.813 410.4 R 35.591(2261 27)300.807 410.4 R(12875)404.686 410.4 Q -53.927(Jul 34)179.813 423.4 R 41.091(2000 1)300.807 423.4 R(58)421.186 423.4 Q -47.822(Aug 65)179.813 436.4 R 41.091(6378 8)300.807 436.4 R(4724)410.186 436.4 -Q 44.764(Sep 266)179.813 449.4 R 30.091(23410 113)295.307 449.4 R(39965)404.686 -449.4 Q 50.88(Oct 22)179.813 462.4 R 41.091(621 1)306.307 462.4 R(155)415.686 -462.4 Q -.88(To)179.813 475.4 S 33.423(tal 1000).88 F 30.091(62196 269)295.307 -475.4 R(101799)399.186 475.4 Q 437.686 480.15 174.313 480.15 DL 390.936 292.15 -390.936 480.15 DL 335.86 292.15 335.86 480.15 DL 337.86 292.15 337.86 480.15 DL -281.255 292.15 281.255 480.15 DL 216.4 292.15 216.4 480.15 DL 218.4 292.15 -218.4 480.15 DL 437.686 264.15 437.686 480.15 DL 174.313 264.15 174.313 480.15 -DL F0 -1.196(Ta)284.205 494.9 S(ble 2.)1.196 E F2(cvs)233.587 507.9 Q F1 -(Usage History for the K)2.75 E(ernel)-.275 E -(checking out \214les based on a date.)90 533.9 Q .098 -(Checking out the entire k)117.5 550.8 R .098 -(ernel source tree \(1223 \214les/59 directories\) currently tak)-.11 F .098 -(es 16 w)-.11 F(all)-.11 E 1.885(clock minutes on a Sun-4/280.)90 563.8 R(Ho) -7.385 E(we)-.275 E -.165(ve)-.275 G 2.765 -.44(r, b).165 H 1.885 -(ringing the tree up-to-date with the current k).44 F(ernel)-.11 E .471 -(sources, once it has been check)90 576.8 R .471(ed out, tak)-.11 F .471 -(es only 1.5 w)-.11 F .472(all clock minutes.)-.11 F .472(Updating the)5.972 F -/F3 11/Times-Italic@0 SF(complete)3.222 E F1 1.687(128 MByte source tree under) -90 589.8 R F2(cvs)4.436 E F1 1.686 -(control \(17243 \214les/1005 directories\) tak)4.436 F 1.686(es roughly 28 w) --.11 F(all)-.11 E 3.394(clock minutes and utilizes one-third of the machine.)90 -602.8 R -.165(Fo)8.895 G 6.145(rn).165 G 3.945 -.275(ow t)377.938 602.8 T 3.395 -(his is entirely acceptable;).275 F(impro)90 615.8 Q -.165(ve)-.165 G -(ments on these numbers will possibly be made in the future.).165 E F2 2.75 -(3.3. The)90 641.8 R(SunOS 4.0.3 Mer)2.75 E(ge)-.11 E F1 1.268 -(The true test of the)117.5 658.7 R F2(cvs)4.018 E F1 -.165(ve)4.018 G 1.268 -(ndor branch support came with the arri).165 F -.275(va)-.275 G 4.017(lo).275 G -4.017(ft)439.67 658.7 S 1.267(he SunOS 4.0.3)450.408 658.7 R 2.257 -(source upgrade tape.)90 671.7 R 2.257(As described abo)7.757 F -.165(ve)-.165 -G 5.007(,t).165 G(he)294.128 671.7 Q F2(checkin)5.007 E F1 2.257(program w) -5.007 F 2.257(as used to install the ne)-.11 F(w)-.275 E .667(sources and the \ -resulting output \214le listed the \214les that had been locally modi\214ed, n\ -eeding to be)90 684.7 R(mer)90 697.7 Q .983(ged manually)-.198 F 6.484(.F)-.715 -G .984(or the k)181.936 697.7 R .984 -(ernel, there were 94 \214les in con\215ict.)-.11 F(The)6.484 E F2(cvs)3.734 E -F1 .984(\231join\232 command w)3.734 F(as)-.11 E(used on each of the 94 con\ -\215icting \214les, and the remaining con\215icts were resolv)90 710.7 Q(ed.) --.165 E EP -%%Page: 10 10 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF(-10-)296.837 49 Q 1.315 -(The \231join\232 command performs an)117.5 85 R/F1 11/Times-Bold@0 SF -.198 -(rc)4.064 G(smer).198 E(ge)-.11 E F0 4.064(operation. This)4.064 F 1.314 -(in turn uses)4.064 F/F2 11/Times-Italic@0 SF(/usr/lib/dif)4.064 E(f3)-.198 E -F0(to)4.064 E 1.458(produce a three-w)90 98 R 1.458(ay dif)-.11 F 4.208<668c> --.275 G 4.208(le. As)212.74 98 R 1.458(it happens, the)4.208 F F1(diff3)4.208 E -F0 1.458(program has a hard-coded limit of 200)4.208 F 1.917 -(source-\214le changes maximum.)90 111 R 1.917(This pro)7.417 F -.165(ve)-.165 -G 4.667(dt).165 G 4.667(ob)298.146 111 S 4.667(et)313.813 111 S 1.917 -(oo small for a fe)326.422 111 R 4.666(wo)-.275 G 4.666(ft)424.015 111 S 1.916 -(he k)435.402 111 R 1.916(ernel \214les that)-.11 F 1.038(needed mer)90 124 R -1.038(ging by hand, due to the lar)-.198 F 1.039 -(ge number of local changes that Prisma had made.)-.198 F(The)6.539 E F1(diff3) -90 137 Q F0(problem w)2.75 E(as solv)-.11 E -(ed by increasing the hard-coded limit by an order of magnitude.)-.165 E .167 -(The SunOS 4.0.3 k)117.5 153.9 R .167(ernel source upgrade distrib)-.11 F .166 -(ution contained 346 \214les, 233 of which were)-.22 F 1.687 -(modi\214cations to pre)90 166.9 R 1.687 -(viously released \214les, and 113 of which were ne)-.275 F 1.687 -(wly added \214les.)-.275 F F1(checkin)7.187 E F0 .599(added the 113 ne)90 -179.9 R 3.348<778c>-.275 G .598(les to the source repository without interv) -183.772 179.9 R 3.348(ention. Of)-.165 F .598(the 233 modi\214ed \214les,)3.348 -F .171(139 dropped in cleanly by)90 192.9 R F1(checkin)2.921 E F0 2.921(,s)C -.171(ince Prisma had not made an)254.486 192.9 R 2.921(yl)-.165 G .172 -(ocal changes to them, and 94)393.441 192.9 R .625(required manual mer)90 205.9 -R .624(ging due to local modi\214cations.)-.198 F .624 -(The 233 modi\214ed \214les consisted of 20,766)6.124 F 1.592(lines of dif)90 -218.9 R 4.342(ferences. It)-.275 F 1.592(took one de)4.342 F -.165(ve)-.275 G -1.592(loper tw).165 F 4.342(od)-.11 G 1.592(ays to manually mer)315.751 218.9 R -1.592(ge the 94 \214les using the)-.198 F 1.81 -(\231join\232 command and resolving con\215icts manually)90 231.9 R 7.31(.A) --.715 G 4.56(na)335.404 231.9 S 1.81(dditional day w)350.348 231.9 R 1.81 -(as required for k)-.11 F(ernel)-.11 E(deb)90 244.9 Q 3.116(ugging. The)-.22 F -.366(entire process of mer)3.116 F .367(ging o)-.198 F -.165(ve)-.165 G 3.117 -(r2).165 G .367(0,000 lines of dif)309.023 244.9 R .367(ferences w)-.275 F .367 -(as completed in less)-.11 F 2.292(than a week.)90 257.9 R 2.292 -(This one time-sa)7.792 F 2.292(vings alone w)-.22 F 2.292 -(as justi\214cation enough for the)-.11 F F1(cvs)5.042 E F0(de)5.042 E -.165 -(ve)-.275 G(lopment).165 E(ef)90 270.9 Q(fort; we e)-.275 E(xpect to g)-.165 E -(ain e)-.055 E -.165(ve)-.275 G 2.75(nm).165 G -(ore when tracking future SunOS releases.)231.416 270.9 Q F1 2.75(4. Futur)90 -296.9 R 2.75(eE)-.198 G(nhancements and Curr)146.023 296.9 Q(ent Bugs)-.198 E -F0(Since)117.5 313.8 Q F1(cvs)3.639 E F0 -.11(wa)3.639 G 3.639(sd).11 G .889 -(esigned to be incomplete, for reasons of design simplicity)190.017 313.8 R -3.64(,t)-.715 G .89(here are natu-)459.753 313.8 R .978 -(rally a good number of enhancements that can be made to mak)90 326.8 R 3.728 -(ei)-.11 G 3.728(tm)388.179 326.8 S .978(ore useful.)403.523 326.8 R .978 -(As well, some)6.478 F(nuisances e)90 339.8 Q -(xist in the current implementation.)-.165 E<83>117.5 356.7 Q F1(cvs)134 356.7 -Q F0 1.047(does not currently \231remember\232 who has a check)3.797 F 1.048 -(ed out a cop)-.11 F 3.798(yo)-.11 G 3.798(fam)442.656 356.7 S 3.798(odule. As) -467.357 356.7 R(a)3.798 E .136(result, it is impossible to kno)134 369.7 R -2.886(ww)-.275 G .136(ho might be w)280.302 369.7 R .136 -(orking on the same module that you are.)-.11 F 2.75(As)134 382.7 S -(imple-minded database that is updated nightly w)148.971 382.7 Q(ould lik)-.11 -E(ely suf)-.11 E(\214ce.)-.275 E 12.65<8353>117.5 399.6 S 2.655 -(ignal processing, k)140.116 399.6 R -.165(ey)-.11 G 2.655 -(board interrupt handling in particular).165 F 5.406(,i)-.44 G 5.406(sc)422.869 -399.6 S 2.656(urrently some)437.438 399.6 R(what)-.275 E 3.997(weak. This)134 -412.6 R 1.247(is due to the hea)3.997 F 1.246(vy use of the)-.22 F F1(system) -3.996 E F0 1.246(\(3\) library function to e)1.833 F -.165(xe)-.165 G(cute).165 -E/F3 9/Times-Roman@0 SF(RCS)3.996 E F0 .545(programs lik)134 425.6 R(e)-.11 E -F1(co)3.295 E F0(and)3.295 E F1(ci)3.295 E F0 6.045(.I)C 3.295(ts)251.785 425.6 -S .545(ometimes tak)262.417 425.6 R .545(es multiple interrupts to mak)-.11 F -(e)-.11 E F1(cvs)3.295 E F0 3.296(quit. This)3.295 F(can be \214x)134 438.6 Q -(ed by using a home-gro)-.165 E(wn)-.275 E F1(system)2.75 E F0 -(\(\) replacement.)1.833 E 12.65<8353>117.5 455.5 S .878 -(ecurity of the source repository is currently not dealt with directly)140.116 -455.5 R 6.378(.T)-.715 G .878(he usual UNIX)453.65 455.5 R 1.457 -(approach of user)134 468.5 R 1.457 -(-group-other security permissions through the \214le system is utilized,)-.22 -F -.22(bu)134 481.5 S 3.531(tn).22 G .781(othing else.)156.869 481.5 R F1(cvs) -6.281 E F0 .781(could lik)3.531 F .781(ely be a set-group-id e)-.11 F -.165(xe) --.165 G .78(cutable that checks a protected).165 F 1.641(database to v)134 -494.5 R 1.642(erify user access permissions for particular objects before allo) --.165 F 1.642(wing an)-.275 F(y)-.165 E(operations to af)134 507.5 Q -(fect those objects.)-.275 E 12.65<8357>117.5 524.4 S 1.347(ith e)143.944 524.4 -R -.165(ve)-.275 G 1.346(ry check).165 F 1.346(ed-out directory)-.11 F(,)-.715 -E F1(cvs)4.096 E F0 1.346(maintains some administrati)4.096 F 1.676 -.165 -(ve \214)-.275 H 1.346(les that record).165 F 2.036(the current re)134 537.4 R -2.036(vision numbers of the check)-.275 F 2.037 -(ed-out \214les as well as the location of the)-.11 F(respecti)134 550.4 Q 1.46 --.165(ve s)-.275 H 1.13(ource repository).165 F(.)-.715 E F1(cvs)6.63 E F0 1.13 -(does not reco)3.88 F -.165(ve)-.165 G 3.88(rn).165 G 1.13 -(icely at all if these administrati)370.446 550.4 R -.165(ve)-.275 G -(\214les are remo)134 563.4 Q -.165(ve)-.165 G(d.).165 E 12.65<8354>117.5 580.3 -S 1.2(he source code for)140.721 580.3 R F1(cvs)3.95 E F0 1.2 -(has been tested e)3.95 F(xtensi)-.165 E -.165(ve)-.275 G 1.201 -(ly on Sun-3 and Sun-4 systems, all).165 F .092(running SunOS 4.0 or later v) -134 593.3 R .092(ersions of the operating system.)-.165 F .091 -(Since the code has not yet)5.591 F .024 -(been compiled under other platforms, the o)134 606.3 R -.165(ve)-.165 G .025 -(rall portability of the code is still question-).165 F(able.)134 619.3 Q 12.65 -<8341>117.5 636.2 S 4.241(sw)141.942 636.2 S 1.491(itnessed in the pre)158.404 -636.2 R 1.491(vious section, the)-.275 F F1(cvs)4.241 E F0 1.49 -(method for tracking third party v)4.241 F(endor)-.165 E 1.09(source distrib) -134 649.2 R 1.09(utions can w)-.22 F 1.09(ork quite nicely)-.11 F 6.591(.H) --.715 G -.275(ow)339.916 649.2 S -2.365 -.275(ev e).275 H 1.971 -.44(r, i).275 -H 3.841(ft).44 G 1.091(he v)391.345 649.2 R 1.091(endor changes the direc-) --.165 F .266(tory structure or the \214le names within the source distrib)134 -662.2 R(ution,)-.22 E F1(cvs)3.016 E F0 .266(has no w)3.016 F .266 -(ay of match-)-.11 F 1.407(ing the old release with the ne)134 675.2 R 4.158 -(wo)-.275 G 4.158(ne. It)291.748 675.2 R 1.408(is currently unclear as to ho) -4.158 F 4.158(wt)-.275 G 4.158(os)466.483 675.2 S(olv)480.42 675.2 Q 4.158(et) --.165 G(his,)506.413 675.2 Q(though it is certain to happen in practice.)134 -688.2 Q EP -%%Page: 11 11 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Bold@0 SF 2.75(5. A)90 85 R -.11(va)-1.1 G(ilability).11 E/F1 11 -/Times-Roman@0 SF(The)117.5 101.9 Q F0(cvs)3.134 E F1 .384 -(program sources can be found in a recent posting to the)3.134 F F0(comp.sour) -3.134 E(ces.unix)-.198 E F1(ne)3.134 E(ws-)-.275 E 3.843(group. It)90 114.9 R -1.093(is also currently a)3.843 F -.275(va)-.22 G 1.093(ilable via anon).275 F -1.093(ymous ftp from \231prisma.com\232.)-.165 F(Cop)6.593 E 1.093 -(ying rights for)-.11 F F0(cvs)90 127.9 Q F1(will be co)2.75 E -.165(ve)-.165 G -(red by the GNU General Public License.).165 E F0 2.75(6. Summary)90 153.9 R F1 -1.175(Prisma has used)117.5 170.8 R F0(cvs)3.925 E F1 1.175(since December) -3.925 F 3.925(,1)-.44 G 3.925(988. It)296.711 170.8 R 1.175(has e)3.925 F -.22 -(vo)-.275 G(lv).22 E 1.174(ed to meet our speci\214c needs of)-.165 F(re)90 -183.8 Q 1.24(vision and release control.)-.275 F 3 -.88(We w)6.74 H 1.24 -(ill mak).88 F 3.991(eo)-.11 G 1.241(ur code freely a)296.901 183.8 R -.275(va) --.22 G 1.241(ilable so that others can bene\214t).275 F(from our w)90 196.8 Q -(ork, and can enhance)-.11 E F0(cvs)2.75 E F1(to meet broader needs yet.)2.75 E -(Man)117.5 213.7 Q 3.519(yo)-.165 G 3.519(ft)152.017 213.7 S .769 -(he other softw)162.257 213.7 R .769(are release and re)-.11 F .769 -(vision control systems, lik)-.275 F 3.519(et)-.11 G .769(he one described in) -434.465 213.7 R([Gle)90 226.7 Q .09 -(w], appear to use a collection of tools that are geared to)-.275 F -.11(wa) --.275 G .091(rd speci\214c en).11 F .091(vironments \212 one set)-.44 F .616 -(of tools for the k)90 239.7 R .615(ernel, one set for \231generic\232 softw) --.11 F .615(are, one set for utilities, and one set for k)-.11 F(ernel)-.11 E -2.313(and utilities.)90 252.7 R 2.314(Each of these tool sets apparently handl\ -e some speci\214c aspect of the problem)7.813 F(uniquely)90 265.7 Q(.)-.715 E -F0(cvs)5.634 E F1 .134(took a some)2.884 F .134(what dif)-.275 F .133 -(ferent approach.)-.275 F .133(File sharing through symbolic or hard links is) -5.633 F .269(not addressed; instead, the disk space is simply b)90 278.7 R .27 -(urned since it is \231cheap.)-.22 F 5.77<9a53>-.77 G .27(upport for producing) -429.808 278.7 R 1.973(objects for multiple architectures is not addressed; ins\ -tead, a parallel check)90 291.7 R 1.973(ed-out source tree)-.11 F .797 -(must be used for each architecture, ag)90 304.7 R .798(ain w)-.055 F .798 -(asting disk space to simplify comple)-.11 F .798(xity and ease of)-.165 F .204 -(use \212 punting on this issue allo)90 317.7 R(wed)-.275 E/F2 11 -/Times-Italic@0 SF(Mak)2.954 E(e\214le)-.11 E F1 2.954(st)C 2.954(or)301.457 -317.7 S .204(emain unchanged, unlik)313.574 317.7 R 2.953(et)-.11 G .203 -(he approach tak)430.168 317.7 R .203(en in)-.11 F 1.682 -([Mahler], thereby maintaining closer compatibility with the third-party v)90 -330.7 R 1.682(endor sources.)-.165 F F0(cvs)7.182 E F1(is)4.432 E .851 -(essentially a source-\214le serv)90 343.7 R(er)-.165 E 3.601(,m)-.44 G .851 -(aking no assumptions or special handling of the sources that it)239.737 343.7 -R 2.75(controls. T)90 356.7 R(o)-.88 E F0(cvs)2.75 E F1(:)A 2.75(As)117.5 373.6 -S(ource is a source, of course, of course, unless of course the source is Mr) -132.471 373.6 Q 2.75(.E)-.605 G(d.)460.249 373.6 Q/F3 7.7/Times-Roman@0 SF(6) -468.499 369.09 Q F1 .274(Sources are maintained, sa)90 390.5 R -.165(ve)-.22 G -.275(d, and retrie).165 F -.275(va)-.275 G .275(ble at an).275 F 3.025(yt)-.165 -G .275(ime based on symbolic or numeric re)330.589 390.5 R(vision)-.275 E .487 -(or date in the past.)90 403.5 R .487(It is entirely up to)5.987 F F0(cvs)3.236 -E F1 .486(wrapper programs to pro)3.236 F .486(vide for release en)-.165 F -(vironments)-.44 E(and such.)90 416.5 Q 1.437(The major adv)117.5 433.4 R 1.437 -(antage of)-.275 F F0(cvs)4.187 E F1 -.165(ove)4.187 G 4.188(rt).165 G 1.438 -(he man)275.811 433.4 R 4.188(yo)-.165 G 1.438(ther similar systems that ha) -324.348 433.4 R 1.768 -.165(ve a)-.22 H 1.438(lready been).165 F .205 -(designed is the simplicity of)90 446.4 R F0(cvs)2.955 E F1(.)A F0(cvs)5.704 E -F1 .204(contains only three programs that do all the w)2.954 F .204 -(ork of release)-.11 F .168(and re)90 459.4 R .168(vision control, and tw)-.275 -F 2.919(om)-.11 G .169(anually-maintained administrati)230.388 459.4 R .499 --.165(ve \214)-.275 H .169(les for each source repository).165 F(.)-.715 E .494 -(Of course, the deciding f)90 472.4 R .494(actor of an)-.11 F 3.244(yt)-.165 G -.494(ool is whether people use it, and if the)260.581 472.4 R 3.243(ye)-.165 G --.165(ve)445.448 472.4 S(n).165 E F2(lik)3.243 E(e)-.11 E F1 .493(to use it.) -3.243 F(At Prisma,)90 485.4 Q F0(cvs)2.75 E F1(pre)2.75 E -.165(ve)-.275 G -(nted members of the k).165 E(ernel group from killing each other)-.11 E(.) --.605 E F0 2.75(7. Ackno)90 511.4 R(wledgements)-.11 E F1(Man)117.5 528.3 Q -2.939(yt)-.165 G .189(hanks to Dick Grune at Vrije Uni)148.995 528.3 R -.165 -(ve)-.275 G .19(rsiteit in Amsterdam for his w).165 F .19(ork on the original) --.11 F -.165(ve)90 541.3 S .194(rsion of).165 F F0(cvs)2.944 E F1 .194 -(and for making it a)2.944 F -.275(va)-.22 G .194(ilable to the w).275 F 2.943 -(orld. Thanks)-.11 F .193(to Jef)2.943 F 2.943(fP)-.275 G .193 -(olk of Prisma for helping)410.623 541.3 R .398 -(with the design of the module database, v)90 554.3 R .398 -(endor branch support, and for writing the)-.165 F F0(checkin)3.148 E F1(shell) -3.148 E 3.168(script. Thanks)90 567.3 R .417(also to the entire softw)3.168 F -.417(are group at Prisma for taking the time to re)-.11 F(vie)-.275 E 3.167(wt) --.275 G .417(he paper)484.018 567.3 R(and correct my grammar)90 580.3 Q(.)-.605 -E F0 2.75(8. Refer)90 606.3 R(ences)-.198 E F1 37.587([Bell] Bell)90 623.2 R --.77(Te)2.886 G .136(lephone Laboratories.).77 F .137 -(\231Source Code Control System User')5.636 F 2.887(sG)-.605 G(uide.)464.894 -623.2 Q<9a>-.77 E F2(UNIX)5.637 E(System III Pr)156 636.2 Q -.11(og)-.495 G --.165(ra).11 G(mmer').165 E 2.75(sM)-.44 G(anual)278.507 636.2 Q F1 2.75(,O)C -(ctober 1981.)317.007 636.2 Q 5.808([Courington] Courington,)90 653.1 R -1.012 -(W.)7.184 G F2 4.434(The Network Softwar)238.106 653.1 R 7.184(eE)-.407 G -.44 -(nv)358.867 653.1 S(ir).44 E(onment)-.495 E F1 7.184(,S)C 4.434(un T)424.087 -653.1 R 4.434(echnical Report)-.77 F -(FE197-0, Sun Microsystems Inc, February 1989.)156 666.1 Q .36 LW 162 679.7 90 -679.7 DL/F4 6.3/Times-Roman@0 SF(6)101 688.96 Q/F5 9/Times-Bold@0 SF(cvs)2.25 -3.69 M/F6 9/Times-Roman@0 SF 2.25(,o)C 2.25(fc)127.397 692.65 S -(ourse, does not really discriminate ag)136.64 692.65 Q(ainst Mr)-.045 E 2.25 -(.E)-.495 G(d.)310.826 692.65 Q F4(7)-3.69 I(7)101 701.91 Q F6 -.9(Ye)2.25 3.69 -O(t.).9 E EP -%%Page: 12 12 -%%BeginPageSetup -BP -%%EndPageSetup -/F0 11/Times-Roman@0 SF(-12-)296.837 49 Q 27.203([Essick] Essick,)90 85 R 2.938 -(Raymond B. and Robert Bruce K)5.687 F(olstad.)-.385 E/F1 11/Times-Italic@0 SF -2.938(Notes\214le Refer)8.438 F 2.938(ence Manual)-.407 F F0(,)A .212 -(Department of Computer Science T)156 98 R .212(echnical Report #1081, Uni)-.77 -F -.165(ve)-.275 G .212(rsity of Illinois at).165 F -(Urbana-Champaign, Urbana, Illinois, 1982, p. 26.)156 111 Q([Gle)90 127.9 Q -32.373(w] Gle)-.275 F 1.593 -.715(w, A)-.275 H(ndy).715 E 5.663<2e99>-.715 G -(Box)221.523 127.9 Q .164(es, Links, and P)-.165 F .164(arallel T)-.165 F .164 -(rees: Elements of a Con\214guration Man-)-.385 F 1.84(agement System.)156 -140.9 R<9a>-.77 E F1 -1.012(Wo)7.34 G 1.84(rkshop Pr)1.012 F 1.839 -(oceedings of the Softwar)-.495 F 4.589(eM)-.407 G(ana)435.362 140.9 Q -.11(ge) --.11 G 1.839(ment Confer).11 F(-)-.22 E(ence)156 153.9 Q F0 2.75(,U)C -(SENIX, Ne)189.594 153.9 Q 2.75(wO)-.275 G(rleans, April 1989.)258.663 153.9 Q -28.435([Grune] Grune,)90 170.8 R 8.06(Dick. Distrib)8.06 F 5.311 -(uted the original shell script v)-.22 F 5.311(ersion of)-.165 F/F2 11 -/Times-Bold@0 SF(cvs)8.061 E F0 5.311(in the)8.061 F F2(comp.sour)156 183.8 Q -(ces.unix)-.198 E F0 -.22(vo)2.75 G(lume 6 release in 1986.).22 E 26.598 -([Honda] Honda,)90 200.7 R 2.205(Masahiro and T)4.955 F 2.205(errence Miller) --.77 F 7.705<2e99>-.605 G(Softw)345.874 200.7 Q 2.204 -(are Management Using a CASE)-.11 F(En)156 213.7 Q(vironment.)-.44 E<9a>-.77 E -F1 -1.012(Wo)7.082 G 1.582(rkshop Pr)1.012 F 1.582(oceedings of the Softwar) --.495 F 4.332(eM)-.407 G(ana)416.567 213.7 Q -.11(ge)-.11 G 1.582(ment Confer) -.11 F(ence)-.407 E F0(,)A(USENIX, Ne)156 226.7 Q 2.75(wO)-.275 G -(rleans, April 1989.)233.011 226.7 Q 24.156([Mahler] Mahler)90 243.6 R 3.404 -(,A)-.44 G(le)201.424 243.6 Q 3.403(xa)-.165 G .653(nd Andreas Lampen.)222.988 -243.6 R -.88<9941>6.153 G 3.403(nI).88 G(nte)346.908 243.6 Q .653(grated T) --.165 F .653(oolset for Engineering Soft-)-.88 F -.11(wa)156 256.6 S 3.134 -(re Con\214gurations.).11 F<9a>-.77 E F1(Pr)8.634 E 3.135(oceedings of the A) --.495 F 3.135(CM SIGSOFT/SIGPLAN Softwar)-.33 F(e)-.407 E .517 -(Engineering Symposium on Pr)156 269.6 R .517(actical Softwar)-.165 F 3.266(eD) --.407 G -.165(ev)375.251 269.6 S .516(elopment En).165 F(vir)-.44 E(onments) --.495 E F0 3.266(,A)C(CM,)502.134 269.6 Q 5.925(Boston, No)156 282.6 R -.165 -(ve)-.165 G 5.925(mber 1988.).165 F 5.925(Described is the)289.55 282.6 R F2 -(shape)8.675 E F0 5.926(toolkit posted to the)8.676 F F2(comp.sour)156 295.6 Q -(ces.unix)-.198 E F0(ne)2.75 E(wsgroup in the v)-.275 E(olume 19 release.)-.22 -E([T)90 312.5 Q(ich)-.385 E 30.701(y] T)-.055 F(ich)-.385 E 2.477 -.715(y, W) --.055 H 1.047(alter F)-.165 F 6.547<2e99>-.88 G 1.047 -(Design, Implementation, and Ev)239.32 312.5 R 1.047(aluation of a Re)-.275 F -1.046(vision Control)-.275 F(System.)156 325.5 Q<9a>-.77 E F1(Pr)6.261 E .761 -(oceedings of the 6th International Confer)-.495 F .761(ence on Softwar)-.407 F -3.512(eE)-.407 G(ngineer)484.952 325.5 Q(-)-.22 E(ing)156 338.5 Q F0 2.75(,I)C -(EEE, T)179.221 338.5 Q(ok)-.88 E(yo, September 1982.)-.165 E([W)90 355.4 Q -35.42(all] W)-.88 F .373(all, Larry)-.88 F 5.873(.T)-.715 G(he)221.437 355.4 Q -F2(patch)3.123 E F0 .373(program is an indispensable tool for applying a dif) -3.123 F 3.123<668c>-.275 G .373(le to)502.377 355.4 R(an original.)156 368.4 Q -(Can be found on uunet.uu.net in ~ftp/pub/patch.tar)5.5 E(.)-.605 E EP -%%Trailer -end -%%EOF diff --git a/doc/cvs.cps b/doc/cvs.cps deleted file mode 100644 index 53e86b73743bd02fb3fd8ec7a38f2964657ea688..0000000000000000000000000000000000000000 --- a/doc/cvs.cps +++ /dev/null @@ -1,367 +0,0 @@ -\initial {-} -\entry {-j (merging branches)}{29} -\entry {-k (RCS kflags)}{45} -\initial {.} -\entry {.bashrc}{13} -\entry {.cshrc}{13} -\entry {.cvsrc file}{49} -\entry {.profile}{13} -\entry {.tcshrc}{13} -\initial {/} -\entry {/usr/local/cvsroot}{13} -\initial {=} -\entry {=======}{22} -\initial {{\tt\gtr}} -\entry {{\tt\gtr}{\tt\gtr}{\tt\gtr}{\tt\gtr}{\tt\gtr}{\tt\gtr}{\tt\gtr}}{22} -\initial {{\tt\less}} -\entry {{\tt\less}{\tt\less}{\tt\less}{\tt\less}{\tt\less}{\tt\less}{\tt\less}}{22} -\initial {A} -\entry {A sample session}{9} -\entry {About this manual}{1} -\entry {Add (subcommand)}{53} -\entry {Add options}{54} -\entry {Adding a tag}{23} -\entry {Adding files}{33} -\entry {Admin (subcommand)}{55} -\entry {Administrative files (intro)}{15} -\entry {Administrative files (reference)}{81} -\entry {Administrative files, editing them}{15} -\entry {ALL in commitinfo}{83} -\entry {Author keyword}{43} -\entry {Automatically ignored files}{86} -\entry {Avoiding editor invocation}{52} -\initial {B} -\entry {Binary files (inhibit keyword expansion)}{57} -\entry {Branch merge example}{29} -\entry {Branch number}{7} -\entry {Branch numbers}{26} -\entry {Branch, creating a}{25} -\entry {Branch, vendor-}{37} -\entry {Branches}{23} -\entry {Branches motivation}{25} -\entry {Branches, copying changes between}{29} -\entry {Branches, sticky}{26} -\entry {Bringing a file up to date}{19} -\entry {Bugs, known in this manual}{2} -\entry {Bugs, reporting (manual)}{2} -\initial {C} -\entry {Changes, copying between branches}{29} -\entry {Changing a log message}{56} -\entry {Checkin program}{82} -\entry {Checking commits}{83} -\entry {Checking out source}{9} -\entry {Checkout (subcommand)}{58} -\entry {Checkout program}{82} -\entry {Checkout, example}{9} -\entry {Cleaning up}{10} -\entry {Co (subcommand)}{58} -\entry {Command reference}{49} -\entry {Command structure}{49} -\entry {Comment leader}{58} -\entry {Commit (subcommand)}{60} -\entry {Commit files}{82} -\entry {Commit, when to}{47} -\entry {Commitinfo}{83} -\entry {Committing changes}{9} -\entry {Common options}{51} -\entry {Common syntax of info files}{83} -\entry {Conflict markers}{22} -\entry {Conflict resolution}{22} -\entry {Conflicts (merge example)}{21} -\entry {Contributors (CVS program)}{3} -\entry {Contributors (manual)}{2} -\entry {Copying changes}{29} -\entry {Correcting a log message}{56} -\entry {Creating a branch}{25} -\entry {Creating a project}{17} -\entry {Creating a repository}{87} -\entry {Credits (CVS program)}{3} -\entry {Credits (manual)}{2} -\entry {CVS command structure}{49} -\entry {CVS FAQ}{3} -\entry {CVS FTP site}{3} -\entry {CVS, history of}{3} -\entry {CVS, introduction to}{3} -\entry {CVSEDITOR}{89} -\entry {CVSIGNORE}{89} -\entry {Cvsignore, global}{86} -\entry {CVSREAD}{89} -\entry {CVSREAD, overriding}{51} -\entry {cvsroot}{13} -\entry {CVSROOT}{89} -\entry {CVSROOT (file)}{81} -\entry {CVSROOT, environment variable}{13} -\entry {CVSROOT, module name}{15} -\entry {CVSROOT, multiple repositories}{15} -\entry {CVSROOT, overriding}{50} -\initial {D} -\entry {Date keyword}{43} -\entry {Dates}{51} -\entry {Decimal revision number}{7} -\entry {DEFAULT in commitinfo}{83} -\entry {Defining a module}{18} -\entry {Defining modules (intro)}{15} -\entry {Defining modules (reference manual)}{81} -\entry {Deleting files}{35} -\entry {Deleting revisions}{56} -\entry {Deleting sticky tags}{27} -\entry {Descending directories}{31} -\entry {Diff}{10} -\entry {Diff (subcommand)}{63} -\entry {Differences, merging}{30} -\entry {Directories, moving}{41} -\entry {Directory, descending}{31} -\entry {Disjoint repositories}{15} -\entry {Distributing log messages}{85} -\entry {driver.c (merge example)}{20} -\initial {E} -\entry {Editinfo}{84} -\entry {Editing administrative files}{15} -\entry {Editing the modules file}{18} -\entry {EDITOR}{89} -\entry {Editor, avoiding invocation of}{52} -\entry {EDITOR, environment variable}{9} -\entry {EDITOR, overriding}{50} -\entry {Editor, specifying per module}{84} -\entry {emerge}{22} -\entry {Environment variables}{89} -\entry {Errors, reporting (manual)}{2} -\entry {Example of a work-session}{9} -\entry {Example of merge}{20} -\entry {Example, branch merge}{29} -\entry {Export (subcommand)}{64} -\initial {F} -\entry {FAQ}{3} -\entry {Fetching source}{9} -\entry {File locking}{19} -\entry {File permissions}{14} -\entry {File status}{19} -\entry {Files, moving}{39} -\entry {Files, reference manual}{81} -\entry {Fixes to CVS}{3} -\entry {Fixing a log message}{56} -\entry {Forcing a tag match}{52} -\entry {Form for log message}{86} -\entry {Format of CVS commands}{49} -\entry {Four states of a file}{19} -\entry {FTP site}{3} -\initial {G} -\entry {Getting started}{9} -\entry {Getting the source}{9} -\entry {Global cvsignore}{86} -\entry {Global options}{50} -\entry {Group}{14} -\initial {H} -\entry {Header keyword}{43} -\entry {History (subcommand)}{65} -\entry {History file}{87} -\entry {History files}{14} -\entry {History of CVS}{3} -\initial {I} -\entry {Id keyword}{43} -\entry {Ident (shell command)}{44} -\entry {Identifying files}{43} -\entry {Ignored files}{86} -\entry {Ignoring files}{86} -\entry {Import (subcommand)}{67} -\entry {Importing files}{17} -\entry {Importing modules}{37} -\entry {Index}{95} -\entry {Info files (syntax)}{83} -\entry {Informing others}{22} -\entry {Inhibiting keyword expansion}{57} -\entry {Introduction to CVS}{3} -\entry {Invoking CVS}{49} -\initial {J} -\entry {Join}{29} -\initial {K} -\entry {Keyword expansion}{43} -\entry {Keyword expansion, inhibiting}{57} -\entry {Keyword substitution}{43} -\entry {Kflag}{45} -\entry {Known bugs in this manual}{2} -\initial {L} -\entry {Layout of repository}{13} -\entry {Left-hand options}{50} -\entry {Linear development}{7} -\entry {List, mailing list}{3} -\entry {Locally modified}{19} -\entry {Locker keyword}{43} -\entry {Locking files}{19} -\entry {Log (subcommand)}{69} -\entry {Log information, saving}{87} -\entry {Log keyword}{43} -\entry {Log keyword, selecting comment leader}{58} -\entry {Log message entry}{9} -\entry {Log message template}{86} -\entry {Log message, correcting}{56} -\entry {Log messages}{85} -\entry {Log messages, editing}{84} -\entry {Loginfo}{85} -\entry {LOGNAME}{89} -\initial {M} -\entry {Mail, automatic mail on commit}{22} -\entry {Mailing list}{3} -\entry {Mailing log messages}{85} -\entry {Main trunk (intro)}{7} -\entry {Main trunk and branches}{23} -\entry {Many repositories}{15} -\entry {Markers, conflict}{22} -\entry {Merge, an example}{20} -\entry {Merge, branch example}{29} -\entry {Merging}{29} -\entry {Merging a branch}{29} -\entry {Merging a file}{19} -\entry {Merging two revisions}{30} -\entry {mkmodules}{15} -\entry {Modifications, copying between branches}{29} -\entry {Module status}{82} -\entry {Module, defining}{18} -\entry {Modules (admin file)}{81} -\entry {Modules (intro)}{7} -\entry {Modules file}{15} -\entry {Modules file, changing}{18} -\entry {Motivation for branches}{25} -\entry {Moving directories}{41} -\entry {Moving files}{39} -\entry {Multiple developers}{19} -\entry {Multiple repositories}{15} -\initial {N} -\entry {Name, symbolic (tag)}{23} -\entry {Needing merge}{19} -\entry {Needing update}{19} -\entry {Nroff (selecting comment leader)}{58} -\entry {Number, branch}{7} -\entry {Number, revision-}{7} -\initial {O} -\entry {option defaults}{49} -\entry {Options, global}{50} -\entry {Outdating revisions}{56} -\entry {Overlap}{20} -\entry {Overriding CVSREAD}{51} -\entry {Overriding CVSROOT}{50} -\entry {Overriding EDITOR}{50} -\entry {Overriding RCSBIN}{50} -\initial {P} -\entry {Parallel repositories}{15} -\entry {Patches to CVS}{3} -\entry {PATH}{89} -\entry {Per-module editor}{84} -\entry {Policy}{47} -\entry {Precommit checking}{83} -\entry {Preface}{1} -\initial {R} -\entry {RCS history files}{14} -\entry {RCS keywords}{43} -\entry {RCS revision numbers}{23} -\entry {RCS, CVS uses RCS}{14} -\entry {RCSBIN}{89} -\entry {RCSBIN, overriding}{50} -\entry {RCSfile keyword}{43} -\entry {Rcsinfo}{86} -\entry {RCSINIT}{89} -\entry {Rdiff (subcommand)}{70} -\entry {Read-only files}{51} -\entry {Read-only mode}{50} -\entry {Recursive (directory descending)}{31} -\entry {Reference manual (files)}{81} -\entry {Reference manual for variables}{89} -\entry {Reference, commands}{49} -\entry {Release (subcommand)}{72} -\entry {Releases, revisions and versions}{8} -\entry {Releasing your working copy}{10} -\entry {Remove (subcommand)}{73} -\entry {Removing a change}{30} -\entry {Removing files}{35} -\entry {Removing your working copy}{10} -\entry {Renaming directories}{41} -\entry {Renaming files}{39} -\entry {Replacing a log message}{56} -\entry {Reporting bugs (manual)}{2} -\entry {Repositories, multiple}{15} -\entry {Repository (intro)}{7} -\entry {Repository, example}{13} -\entry {Repository, setting up}{87} -\entry {Repository, user parts}{14} -\entry {Resetting sticky tags}{27} -\entry {Resolving a conflict}{22} -\entry {Retrieving an old revision using tags}{24} -\entry {Revision keyword}{43} -\entry {Revision management}{47} -\entry {Revision numbers}{7} -\entry {Revision tree}{7} -\entry {Revision tree, making branches}{23} -\entry {Revisions, merging differences between}{30} -\entry {Revisions, versions and releases}{8} -\entry {Right-hand options}{51} -\entry {Rtag (subcommand)}{75} -\entry {rtag, creating a branch using}{25} -\initial {S} -\entry {Saving space}{56} -\entry {Security}{14} -\entry {setgid}{14} -\entry {Setting up a repository}{87} -\entry {setuid}{14} -\entry {Signum Support}{1} -\entry {Source keyword}{43} -\entry {Source, getting CVS source}{3} -\entry {Source, getting from CVS}{9} -\entry {Specifying dates}{51} -\entry {Spreading information}{22} -\entry {Starting a project with CVS}{17} -\entry {State keyword}{43} -\entry {Status (subcommand)}{76} -\entry {Status of a file}{19} -\entry {Status of a module}{82} -\entry {Sticky tags}{26} -\entry {Sticky tags, resetting}{27} -\entry {Storing log messages}{85} -\entry {Structure}{49} -\entry {Subdirectories}{31} -\entry {Support, getting CVS support}{1} -\entry {Symbolic name (tag)}{23} -\entry {Syntax of info files}{83} -\initial {T} -\entry {Tag (subcommand)}{77} -\entry {Tag program}{82} -\entry {tag, command, introduction}{23} -\entry {tag, example}{23} -\entry {Tag, retrieving old revisions}{24} -\entry {Tag, symbolic name}{23} -\entry {Tags}{23} -\entry {Tags, sticky}{26} -\entry {tc, Trivial Compiler (example)}{9} -\entry {Team of developers}{19} -\entry {TEMP}{89} -\entry {Template for log message}{86} -\entry {Third-party sources}{37} -\entry {Time}{51} -\entry {TMP}{89} -\entry {TMPDIR}{89} -\entry {Trace}{51} -\entry {Tracking sources}{37} -\entry {Trivial Compiler (example)}{9} -\entry {Typical repository}{13} -\initial {U} -\entry {Undoing a change}{30} -\entry {Up-to-date}{19} -\entry {Update (subcommand)}{78} -\entry {Update program}{82} -\entry {update, introduction}{19} -\entry {Updating a file}{19} -\entry {USER}{89} -\entry {User modules}{14} -\initial {V} -\entry {Vendor}{37} -\entry {Vendor branch}{37} -\entry {Versions, revisions and releases}{8} -\entry {Viewing differences}{10} -\initial {W} -\entry {Wdiff (import example)}{37} -\entry {What (shell command)}{44} -\entry {What branches are good for}{25} -\entry {What is CVS?}{3} -\entry {When to commit}{47} -\entry {Work-session, example of}{9} -\entry {Working copy}{19} -\entry {Working copy, removing}{10} diff --git a/doc/cvs.texinfo b/doc/cvs.texinfo deleted file mode 100644 index 2c17bd215e04c509910bc8ab3f3b2265852cc4ce..0000000000000000000000000000000000000000 --- a/doc/cvs.texinfo +++ /dev/null @@ -1,6636 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@comment cvs.texinfo,v 1.3 1994/09/15 23:39:26 zoo 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 release 0.9, for @sc{cvs} 1.3+ -@comment -release- -@sp 3 -@center Per Cederqvist -@sp 3 -@center last updated 2 Nov 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, 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 @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 still very new. Here is a -list of known deficiencies in it: - -@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{ceder@@signum.se}. -@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}) which is populated with a -hierarchy of files and directories. - -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. - -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 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{$EDITOR} determines -which editor is started. If @code{$EDITOR} is not set, -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 - -The @code{$CVSROOT} environment variable should always -be set to an absolute path to the root of the -repository, @file{/usr/local/cvsroot} in this example. -With this setup 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 - -There is nothing magical about the name -@file{/usr/local/cvsroot}. You can choose to place the -repository anywhere you like, but @code{$CVSROOT} must -always point to it. - -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 -@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 set @code{$CVSROOT} to the -repository you want to use at the moment. - -There are disadvantages to having more than one -repository. In @sc{cvs} 1.3 you @emph{must} make sure -that @code{$CVSROOT} always points to the correct -repository. If the same filename is used in two -repositories, and you mix up the setting of -@code{$CVSROOT}, you might lose data. @sc{cvs} 1.4 -solves this problem by saving the repository -information in the local @file{CVS} administration -files. If you try to use the wrong repository, -@sc{cvs} will warn you of the attempt and then exit. - -Notwithstanding, it can be confusing to have two or -more repositories. - -All examples in this manual assume that you have a -single repository. - -@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 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 in @sc{cvs} 1.x. -@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. Some -@sc{cvs} commands work without this step, but others (most notably -@code{release}) require that all modules are properly defined in the -@file{modules} file. - -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 -@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. - -@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. (The output of @code{status} -unfortunately uses the word ``version'' instead of ``revision''.) -@c -- Is this fixed in CVS 1.3.1? - -@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 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''. In previous -versions of @sc{cvs} there was a special command, -@samp{cvs join}, that was used to merge changes between -branches. - -@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 !----! 1.5 ! <- The main trunk -+-----+ +-----+ +-----+ +-----+ +-----+ - ! - ! - ! +---------+ +---------+ +---------+ -Branch R1fix -> +---! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 ! - +---------+ +---------+ +---------+ -@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.5} - -$ cvs update -j R1fix m.c # @r{Merge all changes made on the branch,} - # @r{i.e. the changes between revision 1.2} - # @r{and 1.2.2.3, into your working copy} - # @r{of the file.} - -$ cvs commit -m "Included R1fix" # @r{Create revision 1.6.} -@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 - -@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 with the @code{checkout} -command, remember that the numeric revisions will -probably be very different between the various files -that make up a module. You almost always use symbolic -tags rather than revision numbers with the -@code{checkout} command. - -@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. - -This method is simple and works quite well, but it has -some known deficiencies: - -@itemize @bullet -@item -If you remove the file @file{foo.c}, you cannot later -create a new file called @file{foo.c} unless you -manually remove the file @file{Attic/foo.c,v} inside -the repository. On the other hand, if you remove -@file{Attic/foo.c,v} you will of course not be able to -retrieve any revision of the old file @file{foo.c}. - -@item -If the file @file{bar.c} is present in release 1.0 of a -product, and was accidentally removed in release 1.1, -you cannot easily resurrect it to release 1.2. You -have to move the file out of the @file{Attic} manually -inside the repository. (Do a @samp{mv Attic/@var{file} -@var{file}}). -@end itemize - -There is a design for a @dfn{rename database} that will -solve these problems and many others, but it is not yet -implemented. - -@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. - -@sc{cvs} assumes that you do not import more than one -release of a product per day. If you do, you can always -use something like this instead: - -@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 - -One of the biggest design flaws with the current release of @sc{cvs} is that -it is very difficult to move a file to a different directory or -rename it. There are workarounds, and they all have their strong and weak -points. (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}. Both files reside in the same module, -@var{module}, but not necessarily in the same directory. -The relative path to the module inside the repository is assumed -to be @var{module}. - -@menu -* Outside:: Moving outside the repository -* Inside:: Moving the history file -* Rename by copying:: -@end menu - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@node Outside -@section Moving outside the repository - -One way to move the 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 inside the module). - -@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 - -@noindent -Advantages: - -@itemize @bullet -@item -Checking out old revisions works correctly. -@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 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/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 is probably the best way to do the renaming. It is -safe, but not without drawbacks. - -@example -# @r{Copy the @sc{rcs} file inside the repository} -$ cd $CVSROOT/module -$ cp @var{old},v @var{new},v -# @r{Remove the old file} -$ cd ~/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 -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}. For -example, @samp{-q} can often (but not always) be given -as both a @code{cvs_option} and a -@code{command_option}. @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 @footnote{being the one that drove the -implementation of the .cvsrc support} is that many -people find the default output of the @samp{diff} -command to be very hard to read, and that either -context diffs or unidiffs are much easier to -understand. - -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}), only the name used on the command line will -be used to match against the file. So if this is the -contents of the user's @file{~/.cvsrc} file: - -@example -log -N -diff -u -update -P -co -P -@end example - -@noindent -the command @samp{cvs checkout foo} would not have the -@samp{-P} option added to the arguments, while -@samp{cvs co foo} would. - -With the example file above, the output from @samp{cvs -diff foobar} will be in unidiff format. @samp{cvs diff --c foobar} will provide context diffs, as usual. Since -@code{diff} doesn't have an option to specify use of -the "old" format, you would need to use the @samp{-f} -option to @samp{cvs} to turn off use of the -@file{~/.cvsrc} options. - - - -@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@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. This parameter -should be specified as an absolute pathname. - -@cindex EDITOR, overriding -@cindex Overriding EDITOR -@item -e @var{editor} -Use @var{editor} to enter revision log information. Overrides the -setting of the @code{$EDITOR} environment variable. - -@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 -Q -Cause the command to be really quiet; the command will only -generate output for serious problems. Available with the following -commands: @code{checkout}, @code{import}, @code{export}, -@code{rdiff}, @code{rtag}, @code{tag}, and @code{update}. - -@item -q -Cause the command to be somewhat quiet; informational messages, -such as reports of recursion through subdirectories, are -suppressed. Available with the following commands: -@code{checkout}, @code{import}, @code{export}, @code{rtag}, -@code{tag}, 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} option along with the @samp{-r} 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. - -@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} -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, you should never use this option to take -back a bogus commit unless you work alone. Instead, -you should fix the file and commit a new revision. - -@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} 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 -Q -Really quiet. - -@item -q -Somewhat quiet. - -@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} -Merge the changes made between the resulting revision -and the revision that it is based on (e.g., if -@var{tag} refers to a branch, @sc{cvs} will merge all -changes made on that branch into your working file). - -With two @samp{-j @var{tag}} options, @sc{cvs} will merge in the -changes between the two respective revisions. This can -be used to undo changes made between two revisions -(@pxref{Merging two revisions}) in your working copy, -or to move changes between different branches. - -In addition, each -j option can contain an optional -date specification which, when used with branches, can -limit the chosen revision to one within a specific -date. An optional date is specified by adding a colon -(:) to the tag. An example might be what @code{import} -tells you to do when you have just imported sources -that have conflicts with local changes: - -@example -$ cvs checkout -jTAG:yesterday -jTAG module -@end example - -@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 -Q -Really quiet. - -@item -q -Somewhat quiet. - -@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 [-flNnQq] -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 -Q -Really quiet. - -@item -q -Somewhat quiet. - -@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. - -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 - -These standard options are supported by @code{import} -(@pxref{Common options}, for a complete description of -them): - -@table @code -@item -m @var{message} -Use @var{message} as log information, instead of -invoking an editor. - -@item -Q -Really quiet. - -@item -q -Somewhat quiet. -@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? -@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 -Q -Really quiet. - -@item -q -Somewhat quiet. - -@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 [-dQq] 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 - -Only these standard options are supported by @code{release}. - -@table @code -@item -Q -Really quiet. - -@item -q -Somewhat quiet. -@end table - -In addition to the above, it supports one additional -flag. - -@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 -- this should be fixed for CVS 1.4 -@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 [-falnRQq] [-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 -Q -Really quiet. - -@item -q -Somewhat quiet. - -@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] [-Q] [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. - -@item -Q -Really quiet. Do not print empty sticky parts. This -option is not available in @sc{cvs} 1.3. -@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 [-lQqR] [-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. - -@item -Q -Really quiet. - -@item -q -Somewhat quiet. -@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 [-AdflPpQqR] [-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. - -@item -P -Prune empty directories. - -@item -p -Pipe files to the standard output. - -@item -Q -Really quiet. - -@item -q -Somewhat quiet. - -@item -R -Commit directories recursively. This is on by default. - -@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 -j@var{branch} -Merge the changes made between the resulting revision -and the revision that it is based on (e.g., if the tag -refers to a branch, @sc{cvs} will merge all changes made in -that branch into your working file). - -With two @samp{-j} options, @sc{cvs} will merge in the -changes between the two respective revisions. This can -be used to remove a certain delta from your working -file; if the file @file{foo.c} is based on -revision 1.6 and you want to remove the changes made -between 1.3 and 1.5, you might do: - -@example -$ cvs update -j1.5 -j1.3 foo.c # @r{note the order@dots{}} -@end example - -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}}. -@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 -* 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 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 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. - -Whenever one of the regular expressions matches a -directory name in the repository, the rest of the line -is used. - -@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). - -All lines with a regular expression matching the -relative path to the module will be used. If any of -the commands return 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 -If the name @samp{ALL} appears as a regular expression -it is always used in addition to any matching regular -expression or @samp{DEFAULT}. - -@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{$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 ALL keyword -is not supported. If more than one matching line is -found, the last one is used. This can be useful for -specifying a default edit script in a module, and then -overriding it in a subdirectory. - -If the edit script exits with a non-zero exit status, -the commit is aborted. - -@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. -$EDITOR $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 - $EDITOR $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. - -If the name @samp{ALL} appears as a regular expression -it is always used in addition to any matching regular expression or -@samp{DEFAULT}. - -All matching regular expressions are used. - -@xref{commit files}, for a description of the syntax of -the @file{loginfo} file. - -@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. - -If the name @samp{ALL} appears as a regular expression -it is always 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. - -@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 get the source to @sc{cvs}, and 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.) - -@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}. - -@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{}} You may not need to set -@code{$CVSROOT} if your @sc{cvs} binary has the right path -compiled in. - -If your site has several repositories, you must be -careful to set @code{$CVSROOT} to the appropriate one -when you use @sc{cvs}, even if you just run @samp{cvs -update} inside an already checked-out module. Future -releases of @sc{cvs} will probably store information about -which repository the module came from inside the -@file{CVS} directory, but version 1.3 relies totally on -@code{$CVSROOT}. - -@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 - -If you cannot find what you are looking for here write -to <@t{ceder@@signum.se}> so that an entry can be added -to the next release of this manual. - -@printindex cp - -@summarycontents - -@contents - -@bye - -Local Variables: -fill-column: 55 -End: diff --git a/doc/cvsclient.dvi b/doc/cvsclient.dvi deleted file mode 100644 index e550f84d42b577e3551783f2d5d434ae06623cf9..0000000000000000000000000000000000000000 Binary files a/doc/cvsclient.dvi and /dev/null differ diff --git a/doc/cvsclient.info b/doc/cvsclient.info deleted file mode 100644 index 5ca1b732612f842bc6c835d1bbc8cc28380f3087..0000000000000000000000000000000000000000 --- a/doc/cvsclient.info +++ /dev/null @@ -1,667 +0,0 @@ -This is Info file cvsclient.info, produced by Makeinfo-1.55 from the -input file /u/src/cvs.941129/doc/cvsclient.texi. - - -File: cvsclient.info, Node: Top, Next: Goals, Prev: (DIR), Up: (DIR) - -CVS Client/Server -***************** - -* 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 - - -File: cvsclient.info, Node: Goals, Next: Notes, Prev: Top, Up: Top - -Goals -***** - - * Do not assume any access to the repository other than via this - protocol. It does not depend on NFS, rdist, etc. - - * Providing a reliable transport is outside this protocol. It is - expected that it runs over TCP, UUCP, etc. - - * Security and authentication are handled outside this protocol (but - see below about `cvs kserver'). - - * 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 doing being able - to do any of these things. The protocol, however, is not known to - contain any defects which would preclude them. - - * 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. - - * 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. - - -File: cvsclient.info, Node: Notes, Next: How To, Prev: Goals, Up: Top - -Notes on the Current Implementation -*********************************** - - The client is built in to the normal `cvs' program, triggered by a -`CVSROOT' variable containing a colon, for example -`cygnus.com:/rel/cvsfiles'. - - The client stores what is stored in checked-out directories -(including `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 `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 `cvs kserver', in which case it -does an initial Kerberos authentication on stdin. If the authentication -succeeds, it subsequently runs identically to `cvs server'. - - The current server implementation can use up huge amounts of memory -when transmitting a lot of data. Avoiding this would be a bit tricky -because it is not acceptable to have the server block on the network -(which may be very slow) when it has locks open. The buffer code has -been rewritten so that this does not appear to be a serious problem in -practice. However, if it is seen to be a problem several solutions are -possible. The two-pass design would involve first noting what versions -of everything we need (with locks in place) and then sending the data, -blocking on the network, with no locks needed. The lather-rinse-repeat -design would involve doing things as it does now until a certain amount -of server memory is being used (10M?), then releasing locks, and trying -the whole update again (some of it is presumably already done). One -problem with this is getting merges to work right. - - -File: cvsclient.info, Node: How To, Next: Protocol Notes, Prev: Notes, Up: Top - -How to add more remote commands -******************************* - - It's the usual simple twelve step process. Let's say you're making -the existing `cvs fix' command work remotely. - - * Add a declaration for the `fix' function, which already implements - the `cvs fix' command, to `server.c'. - - * Now, the client side. Add a function `client_fix' to `client.c', - which calls `parse_cvsroot' and then calls the usual `fix' - function. - - * Add a declaration for `client_fix' to `client.h'. - - * Add `client_fix' to the "fix" entry in the table of commands in - `main.c'. - - * Now for the server side. Add the `serve_fix' routine to - `server.c'; make it do: - static void - serve_fix (arg) - char *arg; - { - do_cvs_command (fix); - } - - * Add the server command `"fix"' to the table of requests in - `server.c'. - - * The `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 `fix' function so that if it is run when the variable - `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: - 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 (); - } - - * Build it locally. Copy the new version into somewhere on the - remote system, in your path so that `rsh host cvs' finds it. Now - you can test it. - - * You may want to set the environment variable `CVS_CLIENT_PORT' - (e.g., 1998) to some bad port to value to prevent the client from - contacting the server via a direct TCP link. That will force the - client to fall back to using `rsh', which will run your new binary. - - * Set the environment variable `CVS_CLIENT_LOG' to a filename prefix - such as `/tmp/cvslog'. Whenever you run a remote CVS command, the - commands and responses sent across the client/server connection - will be logged in `/tmp/cvslog.in' and `/tmp/cvslog.out'. Examine - them for problems while you're testing. - - This should produce a good first cut at a working remote `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. - - -File: cvsclient.info, Node: Protocol Notes, Next: Protocol, Prev: How To, Up: Top - -Notes on the Protocol -********************* - - A number of enhancements are possible: - - * The `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 `cvs diff' without arguments. - - * Have the client keep a copy of some part of the repository. This - allows all of `cvs diff' and large parts of `cvs update' and `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). - - * Provide encryption using kerberos. - - * The current procedure for `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. - - -File: cvsclient.info, Node: Protocol, Prev: Protocol Notes, Up: Top - -The CVS client/server protocol -****************************** - -* Menu: - -* Entries Lines:: -* Modes:: -* Requests:: -* Responses:: -* Example:: - - -File: cvsclient.info, Node: Entries Lines, Next: Modes, Up: Protocol - -Entries Lines -============= - - Entries lines are transmitted as: - - / NAME / VERSION / CONFLICT / OPTIONS / TAG_OR_DATE - - TAG_OR_DATE is either `T' TAG or `D' DATE or empty. If it is -followed by a slash, anything after the slash shall be silently ignored. - - VERSION can be empty, or start with `0' or `-', for no user file, -new user file, or user file to be removed, respectively. - - CONFLICT, if it starts with `+', indicates that the file had -conflicts in it. The rest of CONFLICT is `=' if the timestamp matches -the file, or anything else if it doesn't. If CONFLICT does not start -with a `+', it is silently ignored. - - -File: cvsclient.info, Node: Modes, Next: Requests, Prev: Entries Lines, Up: Protocol - -Modes -===== - - A mode is any number of repetitions of - - MODE-TYPE = DATA - - separated by `,'. - - MODE-TYPE is an identifier composed of alphanumeric characters. -Currently specified: `u' for user, `g' for group, `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. - - DATA consists of any data not containing `,', `\0' or `\n'. For -`u', `g', and `o' mode types, data consists of alphanumeric characters, -where `r' means read, `w' means write, `x' means execute, and -unrecognized letters are silently ignored. - - -File: cvsclient.info, Node: Requests, Next: Responses, Prev: Modes, Up: Protocol - -Requests -======== - - File contents (noted below as 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 `gzip-file-contents', a `z' may precede the -length, and the `file contents' sent are actually compressed with -`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. - -`Root PATHNAME \n' - Response expected: no. Tell the server which `CVSROOT' to use. - -`Valid-responses REQUEST-LIST \n' - Response expected: no. Tell the server what responses the client - will accept. request-list is a space separated list of tokens. - -`valid-requests \n' - Response expected: yes. Ask the server to send back a - `Valid-requests' response. - -`Repository 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 `Entry ' and `Modified ' - and also for `ci' and the other commands; normal usage is to send a - `Repository ' for each directory in which there will be an `Entry - ' or `Modified ', and then a final `Repository ' for the original - directory, then the command. - -`Directory LOCAL-DIRECTORY \n' - Additional data: REPOSITORY \n. This is like `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 *Note Responses::. LOCAL-DIRECTORY - is relative to the top level at which the command is occurring - (i.e. the last `Directory' or `Repository' which is sent before - the command). - -`Max-dotdot LEVEL \n' - Tell the server that LEVEL levels of directories above the - directory which `Directory' requests are relative to will be - needed. For example, if the client is planning to use a - `Directory' request for `../../foo', it must send a `Max-dotdot' - request with a LEVEL of at least 2. `Max-dotdot' must be sent - before the first `Directory' request. - -`Static-directory \n' - Response expected: no. Tell the server that the directory most - recently specified with `Repository' or `Directory' should not have - additional files checked out unless explicitly requested. The - client sends this if the `Entries.Static' flag is set, which is - controlled by the `Set-static-directory' and - `Clear-static-directory' responses. - -`Sticky TAGSPEC \n' - Response expected: no. Tell the server that the directory most - recently specified with `Repository' has a sticky tag or date - TAGSPEC. The first character of TAGSPEC is `T' for a tag, or `D' - for a date. The remainder of TAGSPEC contains the actual tag or - date. - -`Checkin-prog PROGRAM \n' - Response expected: no. Tell the server that the directory most - recently specified with `Directory' has a checkin program PROGRAM. - Such a program would have been previously set with the - `Set-checkin-prog' response. - -`Update-prog PROGRAM \n' - Response expected: no. Tell the server that the directory most - recently specified with `Directory' has an update program PROGRAM. - Such a program would have been previously set with the - `Set-update-prog' response. - -`Entry ENTRY-LINE \n' - Response expected: no. Tell the server what version of a file is - on the local machine. The name in ENTRY-LINE is a name relative - to the directory most recently specified with `Repository'. If - the user is operating on only some files in a directory, `Entry' - requests for only those files need be included. If an `Entry' - request is sent without `Modified', `Unchanged', or `Lost' for that - file the meaning depends on whether `UseUnchanged' has been sent; - if it has been it means the file is lost, if not it means the file - is unchanged. - -`Modified FILENAME \n' - Response expected: no. Additional data: mode, \n, file - transmission. Send the server a copy of one locally modified - file. FILENAME is relative to the most recent repository sent - with `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 `Entry', if there is no entry for the file. - -`Lost FILENAME \n' - Response expected: no. Tell the server that FILENAME no longer - exists. The name is relative to the most recent repository sent - with `Repository'. This is used for any case in which `Entry' is - being sent but the file no longer exists. If the client has - issued the `UseUnchanged' request, then this request is not used. - -`Unchanged FILENAME \n' - Response expected: no. Tell the server that FILENAME has not been - modified in the checked out directory. The name is relative to - the most recent repository sent with `Repository'. This request - can only be issued if `UseUnchanged' has been sent. - -`UseUnchanged \n' - Response expected: no. Tell the server that the client will be - indicating unmodified files with `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. - -`Argument 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. - -`Argumentx TEXT \n' - Response expected: no. Append \n followed by text to the current - argument being saved. - -`Global_option OPTION \n' - Transmit one of the global options `-q', `-Q', `-l', `-t', `-r', - or `-n'. OPTION must be one of those strings, no variations (such - as combining of options) are allowed. For graceful handling of - `valid-requests', it is probably better to make new global options - separate requests, rather than trying to add them to this request. - -`expand-modules \n' - Response expected: yes. Expand the modules which are specified in - the arguments. Returns the data in `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. - -`co \n' -`update \n' -`ci \n' -`diff \n' -`tag \n' -`status \n' -`log \n' -`add \n' -`remove \n' -`rdiff \n' -`rtag \n' -`import \n' -`admin \n' -`export \n' -`history \n' -`release \n' - Response expected: yes. Actually do a cvs command. This uses any - previous `Argument', `Repository', `Entry', `Modified', or `Lost' - requests, if they have been sent. The last `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 - `ci' must use a `-m' argument if it wants to specify a log message. - -`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 - `update' request. The client must issue the `-u' argument to - `update' in order to receive patches. - -`gzip-file-contents LEVEL \n' - This request asks the server to filter files it sends to the client - through the `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 `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. - -`OTHER-REQUEST 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 `error unrecognized request', but - it could be a different error if a previous command which doesn't - expect a response produced an error. - - When the client is done, it drops the connection. - - -File: cvsclient.info, Node: Responses, Next: Example, Prev: Requests, Up: Protocol - -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 `,v' endings), and -are suitable for use in a subsequent `Repository' request. However, if -the client has used the `Directory' request, then it is instead a local -directory name relative to the directory in which the command was given -(i.e. the last `Directory' before the command). Then a newline and a -repository name (the pathname which is sent if `Directory' is not -used). Then the slash and the filename. For example, for a file -`i386.mh' which is in the local directory `gas.clean/config' and for -which the repository is `/rel/cvsfiles/devo/gas/config': - - gas.clean/config/ - /rel/cvsfiles/devo/gas/config/i386.mh - - Any response always ends with `error' or `ok'. This indicates that -the response is over. - -`Valid-requests REQUEST-LIST \n' - Indicate what requests the server will accept. REQUEST-LIST is a - space separated list of tokens. If the server supports sending - patches, it will include `update-patches' in this list. The - `update-patches' request does not actually do anything. - -`Checked-in PATHNAME \n' - Additional data: New Entries line, \n. This means a file PATHNAME - has been successfully operated on (checked in, added, etc.). name - in the Entries line is the same as the last component of PATHNAME. - -`New-entry PATHNAME \n' - Additional data: New Entries line, \n. Like `Checked-in', but the - file is not up to date. - -`Updated 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. - -`Merged PATHNAME \n' - This is just like `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. - -`Patched PATHNAME \n' - This is just like `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 `diff -u'. This client - must apply this patch, using the `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 - `update' command is given the `-u' argument. - -`Checksum CHECKSUM\n' - The CHECKSUM applies to the next file sent over via `Updated', - `Merged', or `Patched'. In the case of `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 `Valid-responses' request). - -`Copy-file PATHNAME \n' - Additional data: NEWNAME \n. Copy file PATHNAME to NEWNAME in the - same directory where it already is. This does not affect - `CVS/Entries'. - -`Removed PATHNAME \n' - The file has been removed from the repository (this is the case - where cvs prints `file foobar.c is no longer pertinent'). - -`Remove-entry PATHNAME \n' - The file needs its entry removed from `CVS/Entries', but the file - itself is already gone (this happens in response to a `ci' request - which involves committing the removal of a file). - -`Set-static-directory PATHNAME \n' - This instructs the client to set the `Entries.Static' flag, which - it should then send back to the server in a `Static-directory' - request whenever the directory is operated on. PATHNAME ends in a - slash; its purpose is to specify a directory, not a file within a - directory. - -`Clear-static-directory PATHNAME \n' - Like `Set-static-directory', but clear, not set, the flag. - -`Set-sticky PATHNAME \n' - Additional data: TAGSPEC \n. Tell the client to set a sticky tag - or date, which should be supplied with the `Sticky' request for - future operations. PATHNAME ends in a slash; its purpose is to - specify a directory, not a file within a directory. The first - character of TAGSPEC is `T' for a tag, or `D' for a date. The - remainder of TAGSPEC contains the actual tag or date. - -`Clear-sticky PATHNAME \n' - Clear any sticky tag or date set by `Set-sticky'. - -`Set-checkin-prog DIR \n' - Additional data: PROG \n. Tell the client to set a checkin - program, which should be supplied with the `Checkin-prog' request - for future operations. - -`Set-update-prog DIR \n' - Additional data: PROG \n. Tell the client to set an update - program, which should be supplied with the `Update-prog' request - for future operations. - -`Module-expansion PATHNAME \n' - Return a file or directory which is included in a particular - module. PATHNAME is relative to cvsroot, unlike most pathnames in - responses. - -`M TEXT \n' - A one-line message for the user. - -`E TEXT \n' - Same as `M' but send to stderr not stdout. - -`error ERRNO-CODE ` ' TEXT \n' - The command completed with an error. ERRNO-CODE is a symbolic - error code (e.g. `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 `error'). Text is an error message such as that provided by - strerror(), or any other message the server wants to use. - -`ok \n' - The command completed successfully. - - -File: cvsclient.info, Node: Example, Prev: Responses, Up: Protocol - -Example -======= - - Lines beginning with `c>' are sent by the client; lines beginning -with `s>' are sent by the server; lines beginning with `#' are not part -of the actual exchange. - - 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 - - - -Tag Table: -Node: Top119 -Node: Goals572 -Node: Notes2075 -Node: How To3919 -Node: Protocol Notes7117 -Node: Protocol8800 -Node: Entries Lines9014 -Node: Modes9722 -Node: Requests10542 -Node: Responses19409 -Node: Example25563 - -End Tag Table diff --git a/doc/cvsclient.texi b/doc/cvsclient.texi deleted file mode 100644 index 75c4078962cf3940e4d28d2a7bc4822b10fc872f..0000000000000000000000000000000000000000 --- a/doc/cvsclient.texi +++ /dev/null @@ -1,658 +0,0 @@ -\input texinfo - -@setfilename cvsclient.info - -@node Top -@top CVS Client/Server - -@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. Avoiding this would be a bit tricky because -it is not acceptable to have the server block on the network (which may -be very slow) when it has locks open. The buffer code has been -rewritten so that this does not appear to be a serious problem in -practice. However, if it is seen to be a problem several solutions are -possible. The two-pass design would involve first noting what versions -of everything we need (with locks in place) and then sending the data, -blocking on the network, with no locks needed. The lather-rinse-repeat -design would involve doing things as it does now until a certain amount -of server memory is being used (10M?), then releasing locks, and trying -the whole update again (some of it is presumably already done). One -problem with this is getting merges to work right. - -@node How To -@chapter How to add more remote commands - -It's the usual simple twelve step process. Let's say you're making -the existing @code{cvs fix} command work remotely. - -@itemize @bullet -@item -Add a declaration for the @code{fix} function, which already implements -the @code{cvs fix} command, to @file{server.c}. -@item -Now, the client side. -Add a function @code{client_fix} to @file{client.c}, which calls -@code{parse_cvsroot} and then calls the usual @code{fix} function. -@item -Add a declaration for @code{client_fix} to @file{client.h}. -@item -Add @code{client_fix} to the "fix" entry in the table of commands in -@file{main.c}. -@item -Now for the server side. -Add the @code{serve_fix} routine to @file{server.c}; make it do: -@example @code -static void -serve_fix (arg) - char *arg; -@{ - do_cvs_command (fix); -@} -@end example -@item -Add the server command @code{"fix"} to the table of requests in @file{server.c}. -@item -The @code{fix} function can now be entered in three different situations: -local (the old situation), client, and server. On the server side it probably -will not need any changes to cope. -Modify the @code{fix} function so that if it is run when the variable -@code{client_active} is set, it starts the server, sends over parsed -arguments and possibly files, sends a "fix" command to the server, -and handles responses from the server. Sample code: -@example @code - if (!client_active) @{ - /* Do whatever you used to do */ - @} else @{ - /* We're the local client. Fire up the remote server. */ - start_server (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - send_option_string (options); - - send_files (argc, argv, local); - - if (fprintf (to_server, "fix\n") == EOF) - error (1, errno, "writing to server"); - err = get_responses_and_close (); - @} -@end example -@item -Build it locally. Copy the new version into somewhere on the -remote system, in your path so that @code{rsh host cvs} finds it. -Now you can test it. -@item -You may want to set the environment variable @code{CVS_CLIENT_PORT} -(e.g., 1998) to some bad port value 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/examples/.cvsignore b/examples/.cvsignore deleted file mode 100644 index f3c7a7c5da68804a1bdf391127ba34aed33c3cca..0000000000000000000000000000000000000000 --- a/examples/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/examples/ChangeLog b/examples/ChangeLog deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/examples/Makefile.in b/examples/Makefile.in deleted file mode 100644 index df4dee856036f339dda415b0075d210cb96ff723..0000000000000000000000000000000000000000 --- a/examples/Makefile.in +++ /dev/null @@ -1,86 +0,0 @@ -# Makefile for GNU CVS example files. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986, 1988-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. - -# $CVSid: @(#)Makefile.in 1.4 94/10/22 $ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -# Where to install the executables. -bindir = $(exec_prefix)/bin - -# Where to put the system-wide .cvsrc file -libdir = $(prefix)/lib - -# Where to put the manual pages. -mandir = $(prefix)/man - -# Use cp if you don't have install. -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ - -EXAMPLE_FILES = commitinfo editinfo loginfo modules rcsinfo - -DISTFILES = Makefile.in commitinfo loginfo modules rcsinfo - -all: Makefile -.PHONY: all - -install: all $(libdir)/cvs/examples - for f in $(EXAMPLE_FILES) ; do\ - $(INSTALL_DATA) $(srcdir)/$$f $(libdir)/cvs/examples/$$f; \ - done -.PHONY: install - -$(libdir)/cvs/examples: - $(srcdir)/../mkinstalldirs $(libdir)/cvs/examples - -tags: -.PHONY: tags - -TAGS: -.PHONY: TAGS - -ls: - @echo $(DISTFILES) -.PHONY: ls - -clean: - /bin/rm -f *.o core -.PHONY: clean - -distclean: clean - rm -f Makefile -.PHONY: distclean - -realclean: distclean -.PHONY: realclean - -dist: - ln $(DISTFILES) ../`cat ../.fname`/examples -.PHONY: dist - -Makefile: Makefile.in - cd ..; $(SHELL) config.status diff --git a/examples/commitinfo b/examples/commitinfo deleted file mode 100644 index fd79a2beaa3a5d3d128c2a357fe2e342a3b4e46c..0000000000000000000000000000000000000000 --- a/examples/commitinfo +++ /dev/null @@ -1,21 +0,0 @@ -# -# $Id: commitinfo,v 1.1.1.1 1994/12/03 06:09:30 jimb 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. If a match 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. -# -^cvs checkforcvsid -DEFAULT checkforid diff --git a/examples/editinfo b/examples/editinfo deleted file mode 100644 index 1a0706b904b191fe07229c25f7191dcc8bbde579..0000000000000000000000000000000000000000 --- a/examples/editinfo +++ /dev/null @@ -1,30 +0,0 @@ -# -# $Id: editinfo,v 1.1.1.1 1994/12/03 06:09:30 jimb 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. -# -DEFAULT $CVSROOT/CVSROOT/edit "%s" diff --git a/examples/loginfo b/examples/loginfo deleted file mode 100644 index bb8b650bf2f904141cdb56b95cbfd96d791f7cfb..0000000000000000000000000000000000000000 --- a/examples/loginfo +++ /dev/null @@ -1,20 +0,0 @@ -# -# $CVSid: @(#)loginfo 1.5 92/03/31 $ -# -# 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. 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 (ala printf). If -# %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 "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/log.pl %s -f $CVSROOT/CVSROOT/commitlog diff --git a/examples/modules b/examples/modules deleted file mode 100644 index 891ae3dfee5fa6ed8202f9b479a4995ac4355495..0000000000000000000000000000000000000000 --- a/examples/modules +++ /dev/null @@ -1,566 +0,0 @@ -# -# CVS Modules file for Prisma sources -# $CVSid: @(#)modules 1.5 92/03/31 $ -# -# 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. -# -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 . -kernel -a sys lang/adb sparcsim - -# CVSROOT support -CVSROOT -i /usr/local/bin/mkmodules CVSROOT -modules -i /usr/local/bin/mkmodules CVSROOT modules -loginfo -i /usr/local/bin/mkmodules CVSROOT loginfo -commitinfo -i /usr/local/bin/mkmodules CVSROOT commitinfo -rcsinfo -i /usr/local/bin/mkmodules CVSROOT rcsinfo - -# 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/examples/rcsinfo b/examples/rcsinfo deleted file mode 100644 index f2a27fcc60de3dc6e7284bb230a97088335a23d5..0000000000000000000000000000000000000000 --- a/examples/rcsinfo +++ /dev/null @@ -1,18 +0,0 @@ -# -# $Id: rcsinfo,v 1.1.1.1 1994/12/03 06:09:30 jimb 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. If a match 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 /src/master/CVSROOT/rcstemplate diff --git a/install-sh b/install-sh deleted file mode 100755 index ab74c882e9233c0812e5411d47eaa6bfc0603074..0000000000000000000000000000000000000000 --- a/install-sh +++ /dev/null @@ -1,238 +0,0 @@ -#!/bin/sh -# -# install - install a program, script, or datafile -# This comes from X11R5. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. -# - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -tranformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" - -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift - - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi - - pathcomp="${pathcomp}/" -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi - -# Make a temp file name in the proper directory. - - dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - - $doit $instcmd $src $dsttmp && - - trap "rm -f ${dsttmp}" 0 && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && - -# Now rename the file to the real destination. - - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile - -fi && - - -exit 0 diff --git a/lib/.cvsignore b/lib/.cvsignore deleted file mode 100644 index 21816b93117893c053a68eea4233a5f39a685aa4..0000000000000000000000000000000000000000 --- a/lib/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -Makefile -getdate.c -.pure diff --git a/lib/ChangeLog b/lib/ChangeLog deleted file mode 100644 index deb89e76d0a7a5511f3ed25c2cbd4c3d48341b04..0000000000000000000000000000000000000000 --- a/lib/ChangeLog +++ /dev/null @@ -1,68 +0,0 @@ -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/lib/ChangeLog.fsf b/lib/ChangeLog.fsf deleted file mode 100644 index 176d791c965bc6e8066ad80f7b0e45e55a43f258..0000000000000000000000000000000000000000 --- a/lib/ChangeLog.fsf +++ /dev/null @@ -1,90 +0,0 @@ -Thu Sep 15 00:18:26 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * system.h: remove a bunch of "extern int " declarations of system - functions (could conflict with vendor header files, and didn't - do anything *too* useful to begin with). - - * Makefile.in: update getdate.y message (now has 10 s/r conflicts) - -Wed Sep 14 22:12:21 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * strerror.c: more complete, from the Cygnus libiberty package - - * error.c (strerror): removed, functionality is in strerror.c - - * cvs.h: remove duplicate prototype for Reader_Lock - * history.c: printf argument mismatch - (Both fixes thanks to J.T. Conklin (jtc@cygnus.com) - -Sat Jul 30 13:50:11 1994 david d `zoo' zuhn (zoo@monad.armadillo.com) - - * getopt1.c, getopt.c, getopt.h, getdate.y: latest versions from FSF - -Wed Jul 13 22:11:17 1994 david d `zoo' zuhn (zoo@monad.armadillo.com) - - * system.h: don't set PATH_MAX to pathconf(), since PATH_MAX is - used to size arrays. (thanks to kingdon@cygnus.com) - - * getopt1.c: remove #ifdef __STDC__ around const usages (which - isn't correct and weren't complete) - -Wed Apr 20 14:57:16 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) - - * getopt.h: Prevent multiple inclusion. - -Tue Jan 25 17:34:42 1994 david d zuhn (zoo@monad.armadillo.com) - - * Makefile.in: make sure that no blank lines are in the $(OBJECTS) - list (from Brad Figg) - -Mon Jan 24 12:27:13 1994 david d zuhn (zoo@monad.armadillo.com) - - * system.h: remove alloca checks (added to src/cvs.h); revamped - the MAXPATHLEN and PATH_MAX tests (from Brad Figg - <bradf@wv.MENTORG.COM>); handle index,rindex,bcmp,bzero better - (don't redefine if already defined); added S_IWRITE, S_IWGRP, - S_IWOTH definitions (header file reorganization) - - * strippath.c: use strchr, not index - - * getopt1.c: match prototypes when __STDC__ compiler (lint fixes) - - * getdate.c: alloca checks for when using bison - - * Makefile.in: added CC and YACC definitions; use YACC not BISON; - better getdate.c tests (also from Brad Figg) - -Sat Dec 18 00:55:43 1993 david d zuhn (zoo@monad.armadillo.com) - - * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead - - * memmove.c: new file, implements memmove in terms of bcopy - - * wait.h: include <sys/wait.h> if HAVE_SYS_WAIT_H, not if POSIX - -Thu Sep 9 18:02:11 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * system.h: only #undef PATH_MAX if not on an Alpha. The #undef - causes problems with the Alpha C compiler. - -Thu Apr 8 12:39:56 1993 Ian Lance Taylor (ian@cygnus.com) - - * system.h: Removed several incorrect declarations which fail - on Solaris. - -Wed Jan 20 17:57:24 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * system.h: add externs for sun4 so that gcc -Wall becomes useful - again. - -Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) - - * Makefile.in, configure.in: removed traces of namesubdir, - -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced - copyrights to '92, changed some from Cygnus to FSF. - -Sat Dec 28 02:42:06 1991 K. Richard Pixley (rich at cygnus.com) - - * mkdir.c, rename.c: change fork() to vfork(). - - diff --git a/lib/Makefile.in b/lib/Makefile.in deleted file mode 100644 index b1776f9655f04a82567e39b42d6f01649e575ab1..0000000000000000000000000000000000000000 --- a/lib/Makefile.in +++ /dev/null @@ -1,144 +0,0 @@ -# Makefile for library files used by GNU CVS. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986, 1988-1994 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: @(#)Makefile.in 1.21 94/09/24 $ -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -SHELL = /bin/sh - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -SOURCES = \ - alloca.c \ - argmatch.c \ - error.c \ - fnmatch.c \ - ftruncate.c \ - getdate.y \ - getopt.c \ - getopt1.c \ - getwd.c \ - hostname.c \ - md5.c \ - memmove.c \ - mkdir.c \ - regex.c \ - rename.c \ - sighandle.c \ - strdup.c \ - strerror.c \ - strippath.c \ - stripslash.c \ - waitpid.c \ - yesno.c - -OBJECTS = \ - @ALLOCA@ @LIBOBJS@ \ - argmatch.o \ - error.o \ - fnmatch.o \ - getopt.o \ - getopt1.o \ - md5.o \ - sighandle.o \ - strippath.o \ - stripslash.o \ - yesno.o \ - getdate.o - -DISTFILES = Makefile.in getopt.h fnmatch.h regex.h system.h wait.h $(SOURCES) \ - md5.h - -DEFS = @DEFS@ -RANLIB = @RANLIB@ - -CC = @CC@ -CFLAGS = -g -CPPFLAGS= - -YACC = @YACC@ - -.c.o: - $(CC) $(CPPFLAGS) -I.. -I$(srcdir) $(DEFS) $(CFLAGS) -c $< - -all: libcvs.a -.PHONY: all - -install: all -.PHONY: install - -tags: $(DISTFILES) - ctags `for i in $(DISTFILES); do echo $(srcdir)/$$i; done` - -TAGS: $(DISTFILES) - etags `for i in $(DISTFILES); do echo $(srcdir)/$$i; done` - -ls: - @echo $(DISTFILES) -.PHONY: ls - -clean: - rm -f *.a *.o -.PHONY: clean - -distclean: clean - rm -f tags TAGS Makefile -.PHONY: distclean - -realclean: distclean - rm -f *.tab.c getdate.c -.PHONY: realclean - -dist: - ln $(DISTFILES) ../`cat ../.fname`/lib -.PHONY: dist - -libcvs.a: $(OBJECTS) - $(AR) cr $@ $(OBJECTS) - -$(RANLIB) $@ - -getdate.c: getdate.y - @echo expect 10 shift/reduce conflicts - $(YACC) $(srcdir)/getdate.y - -@if test -f y.tab.c; then \ - mv y.tab.c getdate.c ;\ - else \ - if test -f getdate.tab.c ; then \ - mv getdate.tab.c getdate.c ; \ - else \ - echo '*** Unable to create getdate.c' ;\ - fi ;\ - fi - -fnmatch.o: fnmatch.h -getopt1.o: getopt.h -regex.o: regex.h -getwd.o: system.h -md5.o: md5.h - -Makefile: Makefile.in - cd .. ; $(SHELL) config.status - -../config.status: ../configure - cd .. ; $(SHELL) config.status --recheck - -../configure: ../configure.in - cd $(top_srcdir) ; autoconf diff --git a/lib/alloca.c b/lib/alloca.c deleted file mode 100644 index b57659e418c44cc6281b8f57d0b9d00f84aa0771..0000000000000000000000000000000000000000 --- a/lib/alloca.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - alloca -- (mostly) portable public-domain implementation -- D A Gwyn - - last edit: 86/05/30 rms - include config.h, since on VMS it renames some symbols. - Use xmalloc instead of malloc. - - This implementation of the PWB library alloca() function, - which is used to allocate space off the run-time stack so - that it is automatically reclaimed upon procedure exit, - was inspired by discussions with J. Q. Johnson of Cornell. - - It should work under any C implementation that uses an - actual procedure stack (as opposed to a linked list of - frames). There are some preprocessor constants that can - be defined when compiling for your specific system, for - improved efficiency; however, the defaults should be okay. - - The general concept of this implementation is to keep - track of all alloca()-allocated blocks, and reclaim any - that are found to be deeper in the stack than the current - invocation. This heuristic does not reclaim storage as - soon as it becomes invalid, but it will do so eventually. - - As a special case, alloca(0) reclaims storage without - allocating any. It is a good idea to use alloca(0) in - your main control loop, etc. to force garbage collection. -*/ -#ifndef lint -static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ -#endif - -#if defined(emacs) || defined(HAVE_CONFIG_H) -#include "config.h" -#ifdef static -/* actually, only want this if static is defined as "" - -- this is for usg, in which emacs must undefine static - in order to make unexec workable - */ -#ifndef STACK_DIRECTION -you -lose --- must know STACK_DIRECTION at compile-time -#endif /* STACK_DIRECTION undefined */ -#endif /* static */ -#endif /* emacs || HAVE_CONFIG_H*/ - -#if __STDC__ -typedef void *pointer; /* generic pointer type */ -#else -typedef char *pointer; /* generic pointer type */ -#endif - -#define NULL 0 /* null pointer constant */ - -extern void free(); -extern pointer xmalloc(); - -/* - Define STACK_DIRECTION 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 -*/ - -#ifndef STACK_DIRECTION -#define STACK_DIRECTION 0 /* direction unknown */ -#endif - -#if STACK_DIRECTION != 0 - -#define STACK_DIR STACK_DIRECTION /* known at compile-time */ - -#else /* STACK_DIRECTION == 0; need run-time code */ - -static int stack_dir; /* 1 or -1 once known */ -#define STACK_DIR stack_dir - -static void -find_stack_direction (/* void */) -{ - static char *addr = NULL; /* address of first - `dummy', once known */ - auto char dummy; /* to get stack address */ - - if (addr == NULL) - { /* initial entry */ - addr = &dummy; - - find_stack_direction (); /* recurse once */ - } - else /* second entry */ - if (&dummy > addr) - stack_dir = 1; /* stack grew upward */ - else - stack_dir = -1; /* stack grew downward */ -} - -#endif /* STACK_DIRECTION == 0 */ - -/* - An "alloca header" is used to: - (a) chain together all alloca()ed blocks; - (b) keep track of stack depth. - - It is very important that sizeof(header) agree with malloc() - alignment chunk size. The following default should work okay. -*/ - -#ifndef ALIGN_SIZE -#define ALIGN_SIZE sizeof(double) -#endif - -typedef union hdr -{ - char align[ALIGN_SIZE]; /* to force sizeof(header) */ - struct - { - union hdr *next; /* for chaining headers */ - char *deep; /* for stack depth measure */ - } h; -} header; - -/* - alloca( size ) returns a pointer to at least `size' bytes of - storage which will be automatically reclaimed upon exit from - the procedure that called alloca(). Originally, this space - was supposed to be taken from the current stack frame of the - caller, but that method cannot be made to work for some - implementations of C, for example under Gould's UTX/32. -*/ - -static header *last_alloca_header = NULL; /* -> last alloca header */ - -pointer -alloca (size) /* returns pointer to storage */ - unsigned size; /* # bytes to allocate */ -{ - auto char probe; /* probes stack depth: */ - register char *depth = &probe; - -#if STACK_DIRECTION == 0 - if (STACK_DIR == 0) /* unknown growth direction */ - find_stack_direction (); -#endif - - /* Reclaim garbage, defined as all alloca()ed storage that - was allocated from deeper in the stack than currently. */ - - { - register header *hp; /* traverses linked list */ - - for (hp = last_alloca_header; hp != NULL;) - if (STACK_DIR > 0 && hp->h.deep > depth - || STACK_DIR < 0 && hp->h.deep < depth) - { - register header *np = hp->h.next; - - free ((pointer) hp); /* collect garbage */ - - hp = np; /* -> next header */ - } - else - break; /* rest are not deeper */ - - last_alloca_header = hp; /* -> last valid storage */ - } - - if (size == 0) - return NULL; /* no allocation required */ - - /* Allocate combined header + user data storage. */ - - { - register pointer new = xmalloc (sizeof (header) + size); - /* address of header */ - - ((header *)new)->h.next = last_alloca_header; - ((header *)new)->h.deep = depth; - - last_alloca_header = (header *)new; - - /* User storage begins just after header. */ - - return (pointer)((char *)new + sizeof(header)); - } -} - diff --git a/lib/argmatch.c b/lib/argmatch.c deleted file mode 100644 index 327a27d1cb1adec95bc6c199e8416d0548566f12..0000000000000000000000000000000000000000 --- a/lib/argmatch.c +++ /dev/null @@ -1,87 +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 <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. */ - int 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/lib/dup2.c b/lib/dup2.c deleted file mode 100644 index 19743830ca6e945b3e3b76cd5d5ed788a5753abf..0000000000000000000000000000000000000000 --- a/lib/dup2.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - dup2 -- 7th Edition UNIX system call emulation for UNIX System V - - last edit: 11-Feb-1987 D A Gwyn -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <errno.h> -#include <fcntl.h> - -extern int close(), fcntl(); - -int -dup2( oldfd, newfd ) - int oldfd; /* already-open file descriptor */ - int newfd; /* desired duplicate descriptor */ -{ - register int ret; /* for fcntl() return value */ - register int save; /* for saving entry errno */ - - if ( oldfd == newfd ) - return oldfd; /* be careful not to close() */ - - save = errno; /* save entry errno */ - (void) close( newfd ); /* in case newfd is open */ - /* (may have just clobbered the original errno value) */ - - ret = fcntl( oldfd, F_DUPFD, newfd ); /* dupe it */ - - if ( ret >= 0 ) - errno = save; /* restore entry errno */ - else /* fcntl() returned error */ - if ( errno == EINVAL ) - errno = EBADF; /* we think of everything */ - - return ret; /* return file descriptor */ -} diff --git a/lib/error.c b/lib/error.c deleted file mode 100644 index be5593a742cfdd66427477c7fdd083ec12085078..0000000000000000000000000000000000000000 --- a/lib/error.c +++ /dev/null @@ -1,192 +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 */ - -#ifndef lint -static char rcsid[] = "$CVSid: @(#)error.c 1.13 94/09/30 $"; -#endif /* not lint */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> - -/* turn on CVS support by default, since this is the CVS distribution */ -#define CVS_SUPPORT - -#ifdef CVS_SUPPORT -#if __STDC__ -void Lock_Cleanup(void); -void server_cleanup (int sig); -#else -void Lock_Cleanup(); -void server_cleanup (); -#endif /* __STDC__ */ -extern int server_active; -#endif /* CVS_SUPPORT */ - -#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 (); - -/* 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, char *message, ...) -#else -error (status, errnum, message, va_alist) - int status; - int errnum; - char *message; - va_dcl -#endif -{ - extern char *program_name; -#ifdef CVS_SUPPORT - extern char *command_name; -#endif -#ifdef HAVE_VPRINTF - va_list args; -#endif - -#ifdef CVS_SUPPORT - if (command_name && *command_name) - if (status) - fprintf (stderr, "%s [%s aborted]: ", program_name, command_name); - else - fprintf (stderr, "%s %s: ", program_name, command_name); - else - fprintf (stderr, "%s: ", program_name); -#else - fprintf (stderr, "%s: ", program_name); -#endif -#ifdef HAVE_VPRINTF - VA_START (args, message); - vfprintf (stderr, message, args); - va_end (args); -#else -#ifdef HAVE_DOPRNT - _doprnt (message, &args, stderr); -#else - fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8); -#endif -#endif - if (errnum) - fprintf (stderr, ": %s", strerror (errnum)); - putc ('\n', stderr); - fflush (stderr); - if (status) - { -#ifdef CVS_SUPPORT - Lock_Cleanup(); - if (server_active) - server_cleanup (0); -#endif - exit (status); - } -} - -#ifdef CVS_SUPPORT - -/* 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) - { -#ifdef CVS_SUPPORT - Lock_Cleanup(); - if (server_active) - server_cleanup (0); -#endif - exit (status); - } -} - -#endif /* CVS_SUPPORT */ diff --git a/lib/fnmatch.c b/lib/fnmatch.c deleted file mode 100644 index 2a0543072d4ee028eec35b2f9b99a0f91555f6df..0000000000000000000000000000000000000000 --- a/lib/fnmatch.c +++ /dev/null @@ -1,183 +0,0 @@ -/* Copyright (C) 1992 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -/* Modified slightly by Brian Berliner <berliner@sun.com> for CVS use */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* IGNORE(@ */ -/* #include <ansidecl.h> */ -/* @) */ -#include <errno.h> -#include <fnmatch.h> - -#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) -extern int errno; -#endif - -/* Match STRING against the filename pattern PATTERN, returning zero if - it matches, nonzero if not. */ -int -#if __STDC__ -fnmatch (const char *pattern, const char *string, int flags) -#else -fnmatch (pattern, string, flags) - char *pattern; - char *string; - int flags; -#endif -{ - register const char *p = pattern, *n = string; - register char c; - - if ((flags & ~__FNM_FLAGS) != 0) - { - errno = EINVAL; - return -1; - } - - while ((c = *p++) != '\0') - { - switch (c) - { - case '?': - if (*n == '\0') - return FNM_NOMATCH; - else if ((flags & FNM_PATHNAME) && *n == '/') - return FNM_NOMATCH; - else if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) - return FNM_NOMATCH; - break; - - case '\\': - if (!(flags & FNM_NOESCAPE)) - c = *p++; - if (*n != c) - return FNM_NOMATCH; - break; - - case '*': - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) - return FNM_NOMATCH; - - for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) - if (((flags & FNM_PATHNAME) && *n == '/') || - (c == '?' && *n == '\0')) - return FNM_NOMATCH; - - if (c == '\0') - return 0; - - { - char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; - for (--p; *n != '\0'; ++n) - if ((c == '[' || *n == c1) && - fnmatch(p, n, flags & ~FNM_PERIOD) == 0) - return 0; - return FNM_NOMATCH; - } - - case '[': - { - /* Nonzero if the sense of the character class is inverted. */ - register int not; - - if (*n == '\0') - return FNM_NOMATCH; - - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) - return FNM_NOMATCH; - - not = (*p == '!' || *p == '^'); - if (not) - ++p; - - c = *p++; - for (;;) - { - register char cstart = c, cend = c; - - if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; - - if (c == '\0') - /* [ (unterminated) loses. */ - return FNM_NOMATCH; - - c = *p++; - - if ((flags & FNM_PATHNAME) && c == '/') - /* [/] can never match. */ - return FNM_NOMATCH; - - if (c == '-' && *p != ']') - { - cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == '\\') - cend = *p++; - if (cend == '\0') - return FNM_NOMATCH; - c = *p++; - } - - if (*n >= cstart && *n <= cend) - goto matched; - - if (c == ']') - break; - } - if (!not) - return FNM_NOMATCH; - break; - - matched:; - /* Skip the rest of the [...] that already matched. */ - while (c != ']') - { - if (c == '\0') - /* [... (unterminated) loses. */ - return FNM_NOMATCH; - - c = *p++; - if (!(flags & FNM_NOESCAPE) && c == '\\') - /* 1003.2d11 is unclear if this is right. %%% */ - ++p; - } - if (not) - return FNM_NOMATCH; - } - break; - - default: - if (c != *n) - return FNM_NOMATCH; - } - - ++n; - } - - if (*n == '\0') - return 0; - - return FNM_NOMATCH; -} diff --git a/lib/fnmatch.h b/lib/fnmatch.h deleted file mode 100644 index a1e4f8702185409d7d56084bf382c56c5d66a9d3..0000000000000000000000000000000000000000 --- a/lib/fnmatch.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 1992 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#ifndef _FNMATCH_H - -#define _FNMATCH_H 1 - -/* Bits set in the FLAGS argument to `fnmatch'. */ -#undef FNM_PATHNAME -#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ -#undef FNM_NOESCAPE -#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ -#undef FNM_PERIOD -#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ -#undef __FNM_FLAGS -#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) - -/* Value returned by `fnmatch' if STRING does not match PATTERN. */ -#undef FNM_NOMATCH -#define FNM_NOMATCH 1 - -/* Match STRING against the filename pattern PATTERN, - returning zero if it matches, FNM_NOMATCH if not. */ -#if __STDC__ -extern int fnmatch (const char *pattern, const char *string, int flags); -#else -extern int fnmatch (); -#endif - -#endif /* fnmatch.h */ diff --git a/lib/ftruncate.c b/lib/ftruncate.c deleted file mode 100644 index 13f20a382849ca5728466257640a83db0949fba1..0000000000000000000000000000000000000000 --- a/lib/ftruncate.c +++ /dev/null @@ -1,76 +0,0 @@ -/* ftruncate emulations that work on some System V's. - This file is in the public domain. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> -#include <fcntl.h> - -#ifdef F_CHSIZE -int -ftruncate (fd, length) - int fd; - off_t length; -{ - return fcntl (fd, F_CHSIZE, length); -} -#else -#ifdef F_FREESP -/* The following function was written by - kucharsk@Solbourne.com (William Kucharski) */ - -#include <sys/stat.h> -#include <errno.h> -#include <unistd.h> - -int -ftruncate (fd, length) - int fd; - off_t length; -{ - struct flock fl; - struct stat filebuf; - - if (fstat (fd, &filebuf) < 0) - return -1; - - if (filebuf.st_size < length) - { - /* Extend file length. */ - if (lseek (fd, (length - 1), SEEK_SET) < 0) - return -1; - - /* Write a "0" byte. */ - if (write (fd, "", 1) != 1) - return -1; - } - else - { - /* Truncate length. */ - fl.l_whence = 0; - fl.l_len = 0; - fl.l_start = length; - fl.l_type = F_WRLCK; /* Write lock on file space. */ - - /* This relies on the UNDOCUMENTED F_FREESP argument to - fcntl, which truncates the file so that it ends at the - position indicated by fl.l_start. - Will minor miracles never cease? */ - if (fcntl (fd, F_FREESP, &fl) < 0) - return -1; - } - - return 0; -} -#else -int -ftruncate (fd, length) - int fd; - off_t length; -{ - return chsize (fd, length); -} -#endif -#endif diff --git a/lib/getdate.y b/lib/getdate.y deleted file mode 100644 index 5769e9ceb672a6e02207526640e4fd7be036abec..0000000000000000000000000000000000000000 --- a/lib/getdate.y +++ /dev/null @@ -1,988 +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 - -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/lib/getopt.c b/lib/getopt.c deleted file mode 100644 index 446a8e42384395aa4ede9d89ba17e93e4edc302f..0000000000000000000000000000000000000000 --- a/lib/getopt.c +++ /dev/null @@ -1,759 +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> - -/* 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 == 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/lib/getopt.h b/lib/getopt.h deleted file mode 100644 index f644aa15f465c2daa0703da195b0459d03f9d1b7..0000000000000000000000000000000000000000 --- a/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/lib/getopt1.c b/lib/getopt1.c deleted file mode 100644 index f784b5757c59e1cd26d45fc5ddb0273a7f50b0f4..0000000000000000000000000000000000000000 --- a/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/lib/getwd.c b/lib/getwd.c deleted file mode 100644 index 573a7889244d41af77f14958f72b6d0ffc1bc5ea..0000000000000000000000000000000000000000 --- a/lib/getwd.c +++ /dev/null @@ -1,35 +0,0 @@ -/* getwd.c -- get current working directory pathname - 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. */ - -/* Some systems which include both getwd() and getcwd() have an implementation - of getwd() which is much faster than getcwd(). As a result, we use the - system's getwd() if it is available */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "system.h" - -/* Get the current working directory into PATHNAME */ - -char * -getwd (pathname) - char *pathname; -{ - return (getcwd(pathname, PATH_MAX)); -} diff --git a/lib/hostname.c b/lib/hostname.c deleted file mode 100644 index 34be15e8b6194c0f979de818997bf035f19b0ba2..0000000000000000000000000000000000000000 --- a/lib/hostname.c +++ /dev/null @@ -1,49 +0,0 @@ -/* hostname.c -- use uname() to get the name of the host - 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 defined(STDC_HEADERS) || defined(USG) -#include <string.h> -#ifndef index -#define index strchr -#endif -#else -#include <strings.h> -#endif - -#include <sys/utsname.h> - -/* Put this host's name into NAME, using at most NAMELEN characters */ - -int -gethostname(name, namelen) - char *name; - int namelen; -{ - struct utsname ugnm; - - if (uname(&ugnm) < 0) - return (-1); - - (void) strncpy(name, ugnm.nodename, namelen-1); - name[namelen-1] = '\0'; - - return (0); -} diff --git a/lib/md5.c b/lib/md5.c deleted file mode 100644 index 4ad99cdc060e891c322a2ef6c1aa885c4c884ff6..0000000000000000000000000000000000000000 --- a/lib/md5.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#include "config.h" - -#if HAVE_STRING_H || STDC_HEADERS -#include <string.h> /* for memcpy() */ -#endif - -/* Add prototype support. */ -#ifndef PROTO -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -#define PROTO(ARGS) ARGS -#else -#define PROTO(ARGS) () -#endif -#endif - -#include "md5.h" - -void byteReverse PROTO ((unsigned char *buf, unsigned longs)); - -#ifndef ASM_MD5 -/* - * Note: this code is harmless on little-endian machines. - */ -void byteReverse (buf, longs) - unsigned char *buf; - unsigned longs; -{ - uint32 t; - do { - t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | - ((unsigned)buf[1]<<8 | buf[0]); - *(uint32 *)buf = t; - buf += 4; - } while (--longs); -} -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void -MD5Init(ctx) - struct MD5Context *ctx; -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void -MD5Update(ctx, buf, len) - struct MD5Context *ctx; - unsigned char const *buf; - unsigned len; -{ - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; - - t = 64-t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void -MD5Final(digest, ctx) - unsigned char digest[16]; - struct MD5Context *ctx; -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count-8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32 *)ctx->in); - byteReverse((unsigned char *)ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -#ifndef ASM_MD5 - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void -MD5Transform(buf, in) - uint32 buf[4]; - uint32 const in[16]; -{ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} -#endif diff --git a/lib/md5.h b/lib/md5.h deleted file mode 100644 index bfe79ccd7f287e71d72cb4690bedeea6c5aea272..0000000000000000000000000000000000000000 --- a/lib/md5.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef MD5_H -#define MD5_H - -#if SIZEOF_LONG == 4 -typedef unsigned long uint32; -#else -#if SIZEOF_INT == 4 -typedef unsigned int uint32; -#else -Congratulations! You get to rewrite this code so that it does not require -a 32-bit integer type! (Or maybe you just need to reconfigure.) -#endif -#endif - -struct MD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -void MD5Init PROTO((struct MD5Context *context)); -void MD5Update PROTO((struct MD5Context *context, unsigned char const *buf, unsigned len)); -void MD5Final PROTO((unsigned char digest[16], struct MD5Context *context)); -void MD5Transform PROTO((uint32 buf[4], uint32 const in[16])); - -/* - * This is needed to make RSAREF happy on some MS-DOS compilers. - */ -typedef struct MD5Context MD5_CTX; - -#endif /* !MD5_H */ diff --git a/lib/memmove.c b/lib/memmove.c deleted file mode 100644 index 8818d46544c06eabba9e5e4ca54c8492a252ced0..0000000000000000000000000000000000000000 --- a/lib/memmove.c +++ /dev/null @@ -1,57 +0,0 @@ -/* memmove -- copy memory regions of arbitary length - Copyright (C) 1991 Free Software Foundation, Inc. - -This file is part of the libiberty library. -Libiberty is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -Libiberty 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with libiberty; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - - -/* - -NAME - - memmove -- copy memory regions of arbitary length - -SYNOPSIS - - void memmove (void *out, const void *in, size_t n); - -DESCRIPTION - - Copy LENGTH bytes from memory region pointed to by IN to memory - region pointed to by OUT. - - Regions can be overlapping. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __STDC__ -#include <stddef.h> -#else -#define size_t unsigned long -#endif - -void * -memmove (out, in, length) - void *out; - const void* in; - size_t length; -{ - bcopy(in, out, length); - return out; -} diff --git a/lib/mkdir.c b/lib/mkdir.c deleted file mode 100644 index a70c1d866199c93e875810ac5ae21bae3dcff32d..0000000000000000000000000000000000000000 --- a/lib/mkdir.c +++ /dev/null @@ -1,129 +0,0 @@ -/* mkrmdir.c -- BSD compatible directory functions for System V - Copyright (C) 1988, 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 <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#ifndef STDC_HEADERS -extern int errno; -#endif - -/* mkdir and rmdir adapted from GNU tar. */ - -/* Make directory DPATH, with permission mode DMODE. - - Written by Robert Rother, Mariah Corporation, August 1985 - (sdcsvax!rmr or rmr@uscd). If you want it, it's yours. - - Severely hacked over by John Gilmore to make a 4.2BSD compatible - subroutine. 11Mar86; hoptoad!gnu - - Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir, - subroutine didn't return EEXIST. It does now. */ - -int -mkdir (dpath, dmode) - char *dpath; - int dmode; -{ - int cpid, status; - struct stat statbuf; - - if (stat (dpath, &statbuf) == 0) - { - errno = EEXIST; /* stat worked, so it already exists. */ - return -1; - } - - /* If stat fails for a reason other than non-existence, return error. */ - if (errno != ENOENT) - return -1; - - cpid = fork (); - switch (cpid) - { - case -1: /* Cannot fork. */ - return -1; /* errno is set already. */ - - case 0: /* Child process. */ - /* Cheap hack to set mode of new directory. Since this child - process is going away anyway, we zap its umask. - This won't suffice to set SUID, SGID, etc. on this - directory, so the parent process calls chmod afterward. */ - status = umask (0); /* Get current umask. */ - umask (status | (0777 & ~dmode)); /* Set for mkdir. */ - execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); - _exit (1); - - default: /* Parent process. */ - while (wait (&status) != cpid) /* Wait for kid to finish. */ - /* Do nothing. */ ; - - if (status & 0xFFFF) - { - errno = EIO; /* /bin/mkdir failed. */ - return -1; - } - return chmod (dpath, dmode); - } -} - -/* Remove directory DPATH. - Return 0 if successful, -1 if not. */ - -int -rmdir (dpath) - char *dpath; -{ - int cpid, status; - struct stat statbuf; - - if (stat (dpath, &statbuf) != 0) - return -1; /* stat set errno. */ - - if ((statbuf.st_mode & S_IFMT) != S_IFDIR) - { - errno = ENOTDIR; - return -1; - } - - cpid = fork (); - switch (cpid) - { - case -1: /* Cannot fork. */ - return -1; /* errno is set already. */ - - case 0: /* Child process. */ - execl ("/bin/rmdir", "rmdir", dpath, (char *) 0); - _exit (1); - - default: /* Parent process. */ - while (wait (&status) != cpid) /* Wait for kid to finish. */ - /* Do nothing. */ ; - - if (status & 0xFFFF) - { - errno = EIO; /* /bin/rmdir failed. */ - return -1; - } - return 0; - } -} diff --git a/lib/regex.c b/lib/regex.c deleted file mode 100644 index 8169880d7e4f8cb201116d1a14d9d52f1a8427a5..0000000000000000000000000000000000000000 --- a/lib/regex.c +++ /dev/null @@ -1,4948 +0,0 @@ -/* Extended regular expression matching and search library, - version 0.12. - (Implements POSIX draft P10003.2/D11.2, except for - internationalization features.) - - 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, 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. */ - -/* AIX requires this to be the first thing in the file. */ -#if defined (_AIX) && !defined (REGEX_MALLOC) - #pragma alloca -#endif - -#define _GNU_SOURCE - -/* We need this for `regex.h', and perhaps for the Emacs include files. */ -#include <sys/types.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* The `emacs' switch turns on certain matching commands - that make sense only in Emacs. */ -#ifdef emacs - -#include "lisp.h" -#include "buffer.h" -#include "syntax.h" - -/* Emacs uses `NULL' as a predicate. */ -#undef NULL - -#else /* not emacs */ - -/* We used to test for `BSTRING' here, but only GCC and Emacs define - `BSTRING', as far as I know, and neither of them use this code. */ -#if HAVE_STRING_H || STDC_HEADERS -#include <string.h> -#ifndef bcmp -#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) -#endif -#ifndef bcopy -#define bcopy(s, d, n) memcpy ((d), (s), (n)) -#endif -#ifndef bzero -#define bzero(s, n) memset ((s), 0, (n)) -#endif -#else -#include <strings.h> -#endif - -#ifdef STDC_HEADERS -#include <stdlib.h> -#else -char *malloc (); -char *realloc (); -#endif - - -/* Define the syntax stuff for \<, \>, etc. */ - -/* This must be nonzero for the wordchar and notwordchar pattern - commands in re_match_2. */ -#ifndef Sword -#define Sword 1 -#endif - -#ifdef SYNTAX_TABLE - -extern char *re_syntax_table; - -#else /* not SYNTAX_TABLE */ - -/* How many characters in the character set. */ -#define CHAR_SET_SIZE 256 - -static char re_syntax_table[CHAR_SET_SIZE]; - -static void -init_syntax_once () -{ - register int c; - static int done = 0; - - if (done) - return; - - bzero (re_syntax_table, sizeof re_syntax_table); - - for (c = 'a'; c <= 'z'; c++) - re_syntax_table[c] = Sword; - - for (c = 'A'; c <= 'Z'; c++) - re_syntax_table[c] = Sword; - - for (c = '0'; c <= '9'; c++) - re_syntax_table[c] = Sword; - - re_syntax_table['_'] = Sword; - - done = 1; -} - -#endif /* not SYNTAX_TABLE */ - -#define SYNTAX(c) re_syntax_table[c] - -#endif /* not emacs */ - -/* Get the interface, including the syntax bits. */ -#include "regex.h" - -/* isalpha etc. are used for the character classes. */ -#include <ctype.h> - -#ifndef isascii -#define isascii(c) 1 -#endif - -#ifdef isblank -#define ISBLANK(c) (isascii (c) && isblank (c)) -#else -#define ISBLANK(c) ((c) == ' ' || (c) == '\t') -#endif -#ifdef isgraph -#define ISGRAPH(c) (isascii (c) && isgraph (c)) -#else -#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) -#endif - -#define ISPRINT(c) (isascii (c) && isprint (c)) -#define ISDIGIT(c) (isascii (c) && isdigit (c)) -#define ISALNUM(c) (isascii (c) && isalnum (c)) -#define ISALPHA(c) (isascii (c) && isalpha (c)) -#define ISCNTRL(c) (isascii (c) && iscntrl (c)) -#define ISLOWER(c) (isascii (c) && islower (c)) -#define ISPUNCT(c) (isascii (c) && ispunct (c)) -#define ISSPACE(c) (isascii (c) && isspace (c)) -#define ISUPPER(c) (isascii (c) && isupper (c)) -#define ISXDIGIT(c) (isascii (c) && isxdigit (c)) - -#ifndef NULL -#define NULL 0 -#endif - -/* We remove any previous definition of `SIGN_EXTEND_CHAR', - since ours (we hope) works properly with all combinations of - machines, compilers, `char' and `unsigned char' argument types. - (Per Bothner suggested the basic approach.) */ -#undef SIGN_EXTEND_CHAR -#if __STDC__ -#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) -#else /* not __STDC__ */ -/* As in Harbison and Steele. */ -#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) -#endif - -/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we - use `alloca' instead of `malloc'. This is because using malloc in - re_search* or re_match* could cause memory leaks when C-g is used in - Emacs; also, malloc is slower and causes storage fragmentation. On - the other hand, malloc is more portable, and easier to debug. - - Because we sometimes use alloca, some routines have to be macros, - not functions -- `alloca'-allocated space disappears at the end of the - function it is called in. */ - -#ifdef REGEX_MALLOC - -#define REGEX_ALLOCATE malloc -#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) - -#else /* not REGEX_MALLOC */ - -/* Emacs already defines alloca, sometimes. */ -#ifndef alloca - -/* Make alloca work the best possible way. */ -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not __GNUC__ */ -#if HAVE_ALLOCA_H -#include <alloca.h> -#else /* not __GNUC__ or HAVE_ALLOCA_H */ -#ifndef _AIX /* Already did AIX, up at the top. */ -char *alloca (); -#endif /* not _AIX */ -#endif /* not HAVE_ALLOCA_H */ -#endif /* not __GNUC__ */ - -#endif /* not alloca */ - -#define REGEX_ALLOCATE alloca - -/* Assumes a `char *destination' variable. */ -#define REGEX_REALLOCATE(source, osize, nsize) \ - (destination = (char *) alloca (nsize), \ - bcopy (source, destination, osize), \ - destination) - -#endif /* not REGEX_MALLOC */ - - -/* True if `size1' is non-NULL and PTR is pointing anywhere inside - `string1' or just past its end. This works if PTR is NULL, which is - a good thing. */ -#define FIRST_STRING_P(ptr) \ - (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) - -/* (Re)Allocate N items of type T using malloc, or fail. */ -#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) -#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) -#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) - -#define BYTEWIDTH 8 /* In bits. */ - -#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -typedef char boolean; -#define false 0 -#define true 1 - -/* These are the command codes that appear in compiled regular - expressions. Some opcodes are followed by argument bytes. A - command code can specify any interpretation whatsoever for its - arguments. Zero bytes may appear in the compiled regular expression. - - The value of `exactn' is needed in search.c (search_buffer) in Emacs. - So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of - `exactn' we use here must also be 1. */ - -typedef enum -{ - no_op = 0, - - /* Followed by one byte giving n, then by n literal bytes. */ - exactn = 1, - - /* Matches any (more or less) character. */ - anychar, - - /* Matches any one char belonging to specified set. First - following byte is number of bitmap bytes. Then come bytes - for a bitmap saying which chars are in. Bits in each byte - are ordered low-bit-first. A character is in the set if its - bit is 1. A character too large to have a bit in the map is - automatically not in the set. */ - charset, - - /* Same parameters as charset, but match any character that is - not one of those specified. */ - charset_not, - - /* Start remembering the text that is matched, for storing in a - register. Followed by one byte with the register number, in - the range 0 to one less than the pattern buffer's re_nsub - field. Then followed by one byte with the number of groups - inner to this one. (This last has to be part of the - start_memory only because we need it in the on_failure_jump - of re_match_2.) */ - start_memory, - - /* Stop remembering the text that is matched and store it in a - memory register. Followed by one byte with the register - number, in the range 0 to one less than `re_nsub' in the - pattern buffer, and one byte with the number of inner groups, - just like `start_memory'. (We need the number of inner - groups here because we don't have any easy way of finding the - corresponding start_memory when we're at a stop_memory.) */ - stop_memory, - - /* Match a duplicate of something remembered. Followed by one - byte containing the register number. */ - duplicate, - - /* Fail unless at beginning of line. */ - begline, - - /* Fail unless at end of line. */ - endline, - - /* Succeeds if at beginning of buffer (if emacs) or at beginning - of string to be matched (if not). */ - begbuf, - - /* Analogously, for end of buffer/string. */ - endbuf, - - /* Followed by two byte relative address to which to jump. */ - jump, - - /* Same as jump, but marks the end of an alternative. */ - jump_past_alt, - - /* Followed by two-byte relative address of place to resume at - in case of failure. */ - on_failure_jump, - - /* Like on_failure_jump, but pushes a placeholder instead of the - current string position when executed. */ - on_failure_keep_string_jump, - - /* Throw away latest failure point and then jump to following - two-byte relative address. */ - pop_failure_jump, - - /* Change to pop_failure_jump if know won't have to backtrack to - match; otherwise change to jump. This is used to jump - back to the beginning of a repeat. If what follows this jump - clearly won't match what the repeat does, such that we can be - sure that there is no use backtracking out of repetitions - already matched, then we change it to a pop_failure_jump. - Followed by two-byte address. */ - maybe_pop_jump, - - /* Jump to following two-byte address, and push a dummy failure - point. This failure point will be thrown away if an attempt - is made to use it for a failure. A `+' construct makes this - before the first repeat. Also used as an intermediary kind - of jump when compiling an alternative. */ - dummy_failure_jump, - - /* Push a dummy failure point and continue. Used at the end of - alternatives. */ - push_dummy_failure, - - /* Followed by two-byte relative address and two-byte number n. - After matching N times, jump to the address upon failure. */ - succeed_n, - - /* Followed by two-byte relative address, and two-byte number n. - Jump to the address N times, then fail. */ - jump_n, - - /* Set the following two-byte relative address to the - subsequent two-byte number. The address *includes* the two - bytes of number. */ - set_number_at, - - wordchar, /* Matches any word-constituent character. */ - notwordchar, /* Matches any char that is not a word-constituent. */ - - wordbeg, /* Succeeds if at word beginning. */ - wordend, /* Succeeds if at word end. */ - - wordbound, /* Succeeds if at a word boundary. */ - notwordbound /* Succeeds if not at a word boundary. */ - -#ifdef emacs - ,before_dot, /* Succeeds if before point. */ - at_dot, /* Succeeds if at point. */ - after_dot, /* Succeeds if after point. */ - - /* Matches any character whose syntax is specified. Followed by - a byte which contains a syntax code, e.g., Sword. */ - syntaxspec, - - /* Matches any character whose syntax is not that specified. */ - notsyntaxspec -#endif /* emacs */ -} re_opcode_t; - -/* Common operations on the compiled pattern. */ - -/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ - -#define STORE_NUMBER(destination, number) \ - do { \ - (destination)[0] = (number) & 0377; \ - (destination)[1] = (number) >> 8; \ - } while (0) - -/* Same as STORE_NUMBER, except increment DESTINATION to - the byte after where the number is stored. Therefore, DESTINATION - must be an lvalue. */ - -#define STORE_NUMBER_AND_INCR(destination, number) \ - do { \ - STORE_NUMBER (destination, number); \ - (destination) += 2; \ - } while (0) - -/* Put into DESTINATION a number stored in two contiguous bytes starting - at SOURCE. */ - -#define EXTRACT_NUMBER(destination, source) \ - do { \ - (destination) = *(source) & 0377; \ - (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ - } while (0) - -#ifdef DEBUG -static void -extract_number (dest, source) - int *dest; - unsigned char *source; -{ - int temp = SIGN_EXTEND_CHAR (*(source + 1)); - *dest = *source & 0377; - *dest += temp << 8; -} - -#ifndef EXTRACT_MACROS /* To debug the macros. */ -#undef EXTRACT_NUMBER -#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) -#endif /* not EXTRACT_MACROS */ - -#endif /* DEBUG */ - -/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. - SOURCE must be an lvalue. */ - -#define EXTRACT_NUMBER_AND_INCR(destination, source) \ - do { \ - EXTRACT_NUMBER (destination, source); \ - (source) += 2; \ - } while (0) - -#ifdef DEBUG -static void -extract_number_and_incr (destination, source) - int *destination; - unsigned char **source; -{ - extract_number (destination, *source); - *source += 2; -} - -#ifndef EXTRACT_MACROS -#undef EXTRACT_NUMBER_AND_INCR -#define EXTRACT_NUMBER_AND_INCR(dest, src) \ - extract_number_and_incr (&dest, &src) -#endif /* not EXTRACT_MACROS */ - -#endif /* DEBUG */ - -/* If DEBUG is defined, Regex prints many voluminous messages about what - it is doing (if the variable `debug' is nonzero). If linked with the - main program in `iregex.c', you can enter patterns and strings - interactively. And if linked with the main program in `main.c' and - the other test files, you can run the already-written tests. */ - -#ifdef DEBUG - -/* We use standard I/O for debugging. */ -#include <stdio.h> - -/* It is useful to test things that ``must'' be true when debugging. */ -#include <assert.h> - -static int debug = 0; - -#define DEBUG_STATEMENT(e) e -#define DEBUG_PRINT1(x) if (debug) printf (x) -#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) -#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) -#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) -#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ - if (debug) print_partial_compiled_pattern (s, e) -#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ - if (debug) print_double_string (w, s1, sz1, s2, sz2) - - -extern void printchar (); - -/* Print the fastmap in human-readable form. */ - -void -print_fastmap (fastmap) - char *fastmap; -{ - unsigned was_a_range = 0; - unsigned i = 0; - - while (i < (1 << BYTEWIDTH)) - { - if (fastmap[i++]) - { - was_a_range = 0; - printchar (i - 1); - while (i < (1 << BYTEWIDTH) && fastmap[i]) - { - was_a_range = 1; - i++; - } - if (was_a_range) - { - printf ("-"); - printchar (i - 1); - } - } - } - putchar ('\n'); -} - - -/* Print a compiled pattern string in human-readable form, starting at - the START pointer into it and ending just before the pointer END. */ - -void -print_partial_compiled_pattern (start, end) - unsigned char *start; - unsigned char *end; -{ - int mcnt, mcnt2; - unsigned char *p = start; - unsigned char *pend = end; - - if (start == NULL) - { - printf ("(null)\n"); - return; - } - - /* Loop over pattern commands. */ - while (p < pend) - { - switch ((re_opcode_t) *p++) - { - case no_op: - printf ("/no_op"); - break; - - case exactn: - mcnt = *p++; - printf ("/exactn/%d", mcnt); - do - { - putchar ('/'); - printchar (*p++); - } - while (--mcnt); - break; - - case start_memory: - mcnt = *p++; - printf ("/start_memory/%d/%d", mcnt, *p++); - break; - - case stop_memory: - mcnt = *p++; - printf ("/stop_memory/%d/%d", mcnt, *p++); - break; - - case duplicate: - printf ("/duplicate/%d", *p++); - break; - - case anychar: - printf ("/anychar"); - break; - - case charset: - case charset_not: - { - register int c; - - printf ("/charset%s", - (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); - - assert (p + *p < pend); - - for (c = 0; c < *p; c++) - { - unsigned bit; - unsigned char map_byte = p[1 + c]; - - putchar ('/'); - - for (bit = 0; bit < BYTEWIDTH; bit++) - if (map_byte & (1 << bit)) - printchar (c * BYTEWIDTH + bit); - } - p += 1 + *p; - break; - } - - case begline: - printf ("/begline"); - break; - - case endline: - printf ("/endline"); - break; - - case on_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_jump/0/%d", mcnt); - break; - - case on_failure_keep_string_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_keep_string_jump/0/%d", mcnt); - break; - - case dummy_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/dummy_failure_jump/0/%d", mcnt); - break; - - case push_dummy_failure: - printf ("/push_dummy_failure"); - break; - - case maybe_pop_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/maybe_pop_jump/0/%d", mcnt); - break; - - case pop_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/pop_failure_jump/0/%d", mcnt); - break; - - case jump_past_alt: - extract_number_and_incr (&mcnt, &p); - printf ("/jump_past_alt/0/%d", mcnt); - break; - - case jump: - extract_number_and_incr (&mcnt, &p); - printf ("/jump/0/%d", mcnt); - break; - - case succeed_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); - break; - - case jump_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); - break; - - case set_number_at: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); - break; - - case wordbound: - printf ("/wordbound"); - break; - - case notwordbound: - printf ("/notwordbound"); - break; - - case wordbeg: - printf ("/wordbeg"); - break; - - case wordend: - printf ("/wordend"); - -#ifdef emacs - case before_dot: - printf ("/before_dot"); - break; - - case at_dot: - printf ("/at_dot"); - break; - - case after_dot: - printf ("/after_dot"); - break; - - case syntaxspec: - printf ("/syntaxspec"); - mcnt = *p++; - printf ("/%d", mcnt); - break; - - case notsyntaxspec: - printf ("/notsyntaxspec"); - mcnt = *p++; - printf ("/%d", mcnt); - break; -#endif /* emacs */ - - case wordchar: - printf ("/wordchar"); - break; - - case notwordchar: - printf ("/notwordchar"); - break; - - case begbuf: - printf ("/begbuf"); - break; - - case endbuf: - printf ("/endbuf"); - break; - - default: - printf ("?%d", *(p-1)); - } - } - printf ("/\n"); -} - - -void -print_compiled_pattern (bufp) - struct re_pattern_buffer *bufp; -{ - unsigned char *buffer = bufp->buffer; - - print_partial_compiled_pattern (buffer, buffer + bufp->used); - printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated); - - if (bufp->fastmap_accurate && bufp->fastmap) - { - printf ("fastmap: "); - print_fastmap (bufp->fastmap); - } - - printf ("re_nsub: %d\t", bufp->re_nsub); - printf ("regs_alloc: %d\t", bufp->regs_allocated); - printf ("can_be_null: %d\t", bufp->can_be_null); - printf ("newline_anchor: %d\n", bufp->newline_anchor); - printf ("no_sub: %d\t", bufp->no_sub); - printf ("not_bol: %d\t", bufp->not_bol); - printf ("not_eol: %d\t", bufp->not_eol); - printf ("syntax: %d\n", bufp->syntax); - /* Perhaps we should print the translate table? */ -} - - -void -print_double_string (where, string1, size1, string2, size2) - const char *where; - const char *string1; - const char *string2; - int size1; - int size2; -{ - unsigned this_char; - - if (where == NULL) - printf ("(null)"); - else - { - if (FIRST_STRING_P (where)) - { - for (this_char = where - string1; this_char < size1; this_char++) - printchar (string1[this_char]); - - where = string2; - } - - for (this_char = where - string2; this_char < size2; this_char++) - printchar (string2[this_char]); - } -} - -#else /* not DEBUG */ - -#undef assert -#define assert(e) - -#define DEBUG_STATEMENT(e) -#define DEBUG_PRINT1(x) -#define DEBUG_PRINT2(x1, x2) -#define DEBUG_PRINT3(x1, x2, x3) -#define DEBUG_PRINT4(x1, x2, x3, x4) -#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) -#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) - -#endif /* not DEBUG */ - -/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can - also be assigned to arbitrarily: each pattern buffer stores its own - syntax, so it can be changed between regex compilations. */ -reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; - - -/* Specify the precise syntax of regexps for compilation. This provides - for compatibility for various utilities which historically have - different, incompatible syntaxes. - - The argument SYNTAX is a bit mask comprised of the various bits - defined in regex.h. We return the old syntax. */ - -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; -{ - reg_syntax_t ret = re_syntax_options; - - re_syntax_options = syntax; - return ret; -} - -/* This table gives an error message for each of the error codes listed - in regex.h. Obviously the order here has to be same as there. */ - -static const char *re_error_msg[] = - { NULL, /* REG_NOERROR */ - "No match", /* REG_NOMATCH */ - "Invalid regular expression", /* REG_BADPAT */ - "Invalid collation character", /* REG_ECOLLATE */ - "Invalid character class name", /* REG_ECTYPE */ - "Trailing backslash", /* REG_EESCAPE */ - "Invalid back reference", /* REG_ESUBREG */ - "Unmatched [ or [^", /* REG_EBRACK */ - "Unmatched ( or \\(", /* REG_EPAREN */ - "Unmatched \\{", /* REG_EBRACE */ - "Invalid content of \\{\\}", /* REG_BADBR */ - "Invalid range end", /* REG_ERANGE */ - "Memory exhausted", /* REG_ESPACE */ - "Invalid preceding regular expression", /* REG_BADRPT */ - "Premature end of regular expression", /* REG_EEND */ - "Regular expression too big", /* REG_ESIZE */ - "Unmatched ) or \\)", /* REG_ERPAREN */ - }; - -/* Subroutine declarations and macros for regex_compile. */ - -static void store_op1 (), store_op2 (); -static void insert_op1 (), insert_op2 (); -static boolean at_begline_loc_p (), at_endline_loc_p (); -static boolean group_in_compile_stack (); -static reg_errcode_t compile_range (); - -/* Fetch the next character in the uncompiled pattern---translating it - if necessary. Also cast from a signed character in the constant - string passed to us by the user to an unsigned char that we can use - as an array index (in, e.g., `translate'). */ -#define PATFETCH(c) \ - do {if (p == pend) return REG_EEND; \ - c = (unsigned char) *p++; \ - if (translate) c = translate[c]; \ - } while (0) - -/* Fetch the next character in the uncompiled pattern, with no - translation. */ -#define PATFETCH_RAW(c) \ - do {if (p == pend) return REG_EEND; \ - c = (unsigned char) *p++; \ - } while (0) - -/* Go backwards one character in the pattern. */ -#define PATUNFETCH p-- - - -/* If `translate' is non-null, return translate[D], else just D. We - cast the subscript to translate because some data is declared as - `char *', to avoid warnings when a string constant is passed. But - when we use a character as a subscript we must make it unsigned. */ -#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d)) - - -/* Macros for outputting the compiled pattern into `buffer'. */ - -/* If the buffer isn't allocated when it comes in, use this. */ -#define INIT_BUF_SIZE 32 - -/* Make sure we have at least N more bytes of space in buffer. */ -#define GET_BUFFER_SPACE(n) \ - while (b - bufp->buffer + (n) > bufp->allocated) \ - EXTEND_BUFFER () - -/* Make sure we have one more byte of buffer space and then add C to it. */ -#define BUF_PUSH(c) \ - do { \ - GET_BUFFER_SPACE (1); \ - *b++ = (unsigned char) (c); \ - } while (0) - - -/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ -#define BUF_PUSH_2(c1, c2) \ - do { \ - GET_BUFFER_SPACE (2); \ - *b++ = (unsigned char) (c1); \ - *b++ = (unsigned char) (c2); \ - } while (0) - - -/* As with BUF_PUSH_2, except for three bytes. */ -#define BUF_PUSH_3(c1, c2, c3) \ - do { \ - GET_BUFFER_SPACE (3); \ - *b++ = (unsigned char) (c1); \ - *b++ = (unsigned char) (c2); \ - *b++ = (unsigned char) (c3); \ - } while (0) - - -/* Store a jump with opcode OP at LOC to location TO. We store a - relative address offset by the three bytes the jump itself occupies. */ -#define STORE_JUMP(op, loc, to) \ - store_op1 (op, loc, (to) - (loc) - 3) - -/* Likewise, for a two-argument jump. */ -#define STORE_JUMP2(op, loc, to, arg) \ - store_op2 (op, loc, (to) - (loc) - 3, arg) - -/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ -#define INSERT_JUMP(op, loc, to) \ - insert_op1 (op, loc, (to) - (loc) - 3, b) - -/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ -#define INSERT_JUMP2(op, loc, to, arg) \ - insert_op2 (op, loc, (to) - (loc) - 3, arg, b) - - -/* This is not an arbitrary limit: the arguments which represent offsets - into the pattern are two bytes long. So if 2^16 bytes turns out to - be too small, many things would have to change. */ -#define MAX_BUF_SIZE (1L << 16) - - -/* Extend the buffer by twice its current size via realloc and - reset the pointers that pointed into the old block to point to the - correct places in the new one. If extending the buffer results in it - being larger than MAX_BUF_SIZE, then flag memory exhausted. */ -#define EXTEND_BUFFER() \ - do { \ - unsigned char *old_buffer = bufp->buffer; \ - if (bufp->allocated == MAX_BUF_SIZE) \ - return REG_ESIZE; \ - bufp->allocated <<= 1; \ - if (bufp->allocated > MAX_BUF_SIZE) \ - bufp->allocated = MAX_BUF_SIZE; \ - bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\ - if (bufp->buffer == NULL) \ - return REG_ESPACE; \ - /* If the buffer moved, move all the pointers into it. */ \ - if (old_buffer != bufp->buffer) \ - { \ - b = (b - old_buffer) + bufp->buffer; \ - begalt = (begalt - old_buffer) + bufp->buffer; \ - if (fixup_alt_jump) \ - fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ - if (laststart) \ - laststart = (laststart - old_buffer) + bufp->buffer; \ - if (pending_exact) \ - pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ - } \ - } while (0) - - -/* Since we have one byte reserved for the register number argument to - {start,stop}_memory, the maximum number of groups we can report - things about is what fits in that byte. */ -#define MAX_REGNUM 255 - -/* But patterns can have more than `MAX_REGNUM' registers. We just - ignore the excess. */ -typedef unsigned regnum_t; - - -/* Macros for the compile stack. */ - -/* Since offsets can go either forwards or backwards, this type needs to - be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ -typedef int pattern_offset_t; - -typedef struct -{ - pattern_offset_t begalt_offset; - pattern_offset_t fixup_alt_jump; - pattern_offset_t inner_group_offset; - pattern_offset_t laststart_offset; - regnum_t regnum; -} compile_stack_elt_t; - - -typedef struct -{ - compile_stack_elt_t *stack; - unsigned size; - unsigned avail; /* Offset of next open position. */ -} compile_stack_type; - - -#define INIT_COMPILE_STACK_SIZE 32 - -#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) -#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) - -/* The next available element. */ -#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) - - -/* Set the bit for character C in a list. */ -#define SET_LIST_BIT(c) \ - (b[((unsigned char) (c)) / BYTEWIDTH] \ - |= 1 << (((unsigned char) c) % BYTEWIDTH)) - - -/* Get the next unsigned number in the uncompiled pattern. */ -#define GET_UNSIGNED_NUMBER(num) \ - { if (p != pend) \ - { \ - PATFETCH (c); \ - while (ISDIGIT (c)) \ - { \ - if (num < 0) \ - num = 0; \ - num = num * 10 + c - '0'; \ - if (p == pend) \ - break; \ - PATFETCH (c); \ - } \ - } \ - } - -#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ - -#define IS_CHAR_CLASS(string) \ - (STREQ (string, "alpha") || STREQ (string, "upper") \ - || STREQ (string, "lower") || STREQ (string, "digit") \ - || STREQ (string, "alnum") || STREQ (string, "xdigit") \ - || STREQ (string, "space") || STREQ (string, "print") \ - || STREQ (string, "punct") || STREQ (string, "graph") \ - || STREQ (string, "cntrl") || STREQ (string, "blank")) - -/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. - Returns one of error codes defined in `regex.h', or zero for success. - - Assumes the `allocated' (and perhaps `buffer') and `translate' - fields are set in BUFP on entry. - - If it succeeds, results are put in BUFP (if it returns an error, the - contents of BUFP are undefined): - `buffer' is the compiled pattern; - `syntax' is set to SYNTAX; - `used' is set to the length of the compiled pattern; - `fastmap_accurate' is zero; - `re_nsub' is the number of subexpressions in PATTERN; - `not_bol' and `not_eol' are zero; - - The `fastmap' and `newline_anchor' fields are neither - examined nor set. */ - -static reg_errcode_t -regex_compile (pattern, size, syntax, bufp) - const char *pattern; - int size; - reg_syntax_t syntax; - struct re_pattern_buffer *bufp; -{ - /* We fetch characters from PATTERN here. Even though PATTERN is - `char *' (i.e., signed), we declare these variables as unsigned, so - they can be reliably used as array indices. */ - register unsigned char c, c1; - - /* A random tempory spot in PATTERN. */ - const char *p1; - - /* Points to the end of the buffer, where we should append. */ - register unsigned char *b; - - /* Keeps track of unclosed groups. */ - compile_stack_type compile_stack; - - /* Points to the current (ending) position in the pattern. */ - const char *p = pattern; - const char *pend = pattern + size; - - /* How to translate the characters in the pattern. */ - char *translate = bufp->translate; - - /* Address of the count-byte of the most recently inserted `exactn' - command. This makes it possible to tell if a new exact-match - character can be added to that command or if the character requires - a new `exactn' command. */ - unsigned char *pending_exact = 0; - - /* Address of start of the most recently finished expression. - This tells, e.g., postfix * where to find the start of its - operand. Reset at the beginning of groups and alternatives. */ - unsigned char *laststart = 0; - - /* Address of beginning of regexp, or inside of last group. */ - unsigned char *begalt; - - /* Place in the uncompiled pattern (i.e., the {) to - which to go back if the interval is invalid. */ - const char *beg_interval; - - /* Address of the place where a forward jump should go to the end of - the containing expression. Each alternative of an `or' -- except the - last -- ends with a forward jump of this sort. */ - unsigned char *fixup_alt_jump = 0; - - /* Counts open-groups as they are encountered. Remembered for the - matching close-group on the compile stack, so the same register - number is put in the stop_memory as the start_memory. */ - regnum_t regnum = 0; - -#ifdef DEBUG - DEBUG_PRINT1 ("\nCompiling pattern: "); - if (debug) - { - unsigned debug_count; - - for (debug_count = 0; debug_count < size; debug_count++) - printchar (pattern[debug_count]); - putchar ('\n'); - } -#endif /* DEBUG */ - - /* Initialize the compile stack. */ - compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); - if (compile_stack.stack == NULL) - return REG_ESPACE; - - compile_stack.size = INIT_COMPILE_STACK_SIZE; - compile_stack.avail = 0; - - /* Initialize the pattern buffer. */ - bufp->syntax = syntax; - bufp->fastmap_accurate = 0; - bufp->not_bol = bufp->not_eol = 0; - - /* Set `used' to zero, so that if we return an error, the pattern - printer (for debugging) will think there's no pattern. We reset it - at the end. */ - bufp->used = 0; - - /* Always count groups, whether or not bufp->no_sub is set. */ - bufp->re_nsub = 0; - -#if !defined (emacs) && !defined (SYNTAX_TABLE) - /* Initialize the syntax table. */ - init_syntax_once (); -#endif - - if (bufp->allocated == 0) - { - if (bufp->buffer) - { /* If zero allocated, but buffer is non-null, try to realloc - enough space. This loses if buffer's address is bogus, but - that is the user's responsibility. */ - RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); - } - else - { /* Caller did not allocate a buffer. Do it for them. */ - bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); - } - if (!bufp->buffer) return REG_ESPACE; - - bufp->allocated = INIT_BUF_SIZE; - } - - begalt = b = bufp->buffer; - - /* Loop through the uncompiled pattern until we're at the end. */ - while (p != pend) - { - PATFETCH (c); - - switch (c) - { - case '^': - { - if ( /* If at start of pattern, it's an operator. */ - p == pattern + 1 - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's come before. */ - || at_begline_loc_p (pattern, p, syntax)) - BUF_PUSH (begline); - else - goto normal_char; - } - break; - - - case '$': - { - if ( /* If at end of pattern, it's an operator. */ - p == pend - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's next. */ - || at_endline_loc_p (p, pend, syntax)) - BUF_PUSH (endline); - else - goto normal_char; - } - break; - - - case '+': - case '?': - if ((syntax & RE_BK_PLUS_QM) - || (syntax & RE_LIMITED_OPS)) - goto normal_char; - handle_plus: - case '*': - /* If there is no previous pattern... */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - return REG_BADRPT; - else if (!(syntax & RE_CONTEXT_INDEP_OPS)) - goto normal_char; - } - - { - /* Are we optimizing this jump? */ - boolean keep_string_p = false; - - /* 1 means zero (many) matches is allowed. */ - char zero_times_ok = 0, many_times_ok = 0; - - /* If there is a sequence of repetition chars, collapse it - down to just one (the right one). We can't combine - interval operators with these because of, e.g., `a{2}*', - which should only match an even number of `a's. */ - - for (;;) - { - zero_times_ok |= c != '+'; - many_times_ok |= c != '?'; - - if (p == pend) - break; - - PATFETCH (c); - - if (c == '*' - || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) - ; - - else if (syntax & RE_BK_PLUS_QM && c == '\\') - { - if (p == pend) return REG_EESCAPE; - - PATFETCH (c1); - if (!(c1 == '+' || c1 == '?')) - { - PATUNFETCH; - PATUNFETCH; - break; - } - - c = c1; - } - else - { - PATUNFETCH; - break; - } - - /* If we get here, we found another repeat character. */ - } - - /* Star, etc. applied to an empty pattern is equivalent - to an empty pattern. */ - if (!laststart) - break; - - /* Now we know whether or not zero matches is allowed - and also whether or not two or more matches is allowed. */ - if (many_times_ok) - { /* More than one repetition is allowed, so put in at the - end a backward relative jump from `b' to before the next - jump we're going to put in below (which jumps from - laststart to after this jump). - - But if we are at the `*' in the exact sequence `.*\n', - insert an unconditional jump backwards to the ., - instead of the beginning of the loop. This way we only - push a failure point once, instead of every time - through the loop. */ - assert (p - 1 > pattern); - - /* Allocate the space for the jump. */ - GET_BUFFER_SPACE (3); - - /* We know we are not at the first character of the pattern, - because laststart was nonzero. And we've already - incremented `p', by the way, to be the character after - the `*'. Do we have to do something analogous here - for null bytes, because of RE_DOT_NOT_NULL? */ - if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') - && zero_times_ok - && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') - && !(syntax & RE_DOT_NEWLINE)) - { /* We have .*\n. */ - STORE_JUMP (jump, b, laststart); - keep_string_p = true; - } - else - /* Anything else. */ - STORE_JUMP (maybe_pop_jump, b, laststart - 3); - - /* We've added more stuff to the buffer. */ - b += 3; - } - - /* On failure, jump from laststart to b + 3, which will be the - end of the buffer after this jump is inserted. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump - : on_failure_jump, - laststart, b + 3); - pending_exact = 0; - b += 3; - - if (!zero_times_ok) - { - /* At least one repetition is required, so insert a - `dummy_failure_jump' before the initial - `on_failure_jump' instruction of the loop. This - effects a skip over that instruction the first time - we hit that loop. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); - b += 3; - } - } - break; - - - case '.': - laststart = b; - BUF_PUSH (anychar); - break; - - - case '[': - { - boolean had_char_class = false; - - if (p == pend) return REG_EBRACK; - - /* Ensure that we have enough space to push a charset: the - opcode, the length count, and the bitset; 34 bytes in all. */ - GET_BUFFER_SPACE (34); - - laststart = b; - - /* We test `*p == '^' twice, instead of using an if - statement, so we only need one BUF_PUSH. */ - BUF_PUSH (*p == '^' ? charset_not : charset); - if (*p == '^') - p++; - - /* Remember the first position in the bracket expression. */ - p1 = p; - - /* Push the number of bytes in the bitmap. */ - BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); - - /* Clear the whole map. */ - bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); - - /* charset_not matches newline according to a syntax bit. */ - if ((re_opcode_t) b[-2] == charset_not - && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) - SET_LIST_BIT ('\n'); - - /* Read in characters and ranges, setting map bits. */ - for (;;) - { - if (p == pend) return REG_EBRACK; - - PATFETCH (c); - - /* \ might escape characters inside [...] and [^...]. */ - if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') - { - if (p == pend) return REG_EESCAPE; - - PATFETCH (c1); - SET_LIST_BIT (c1); - continue; - } - - /* Could be the end of the bracket expression. If it's - not (i.e., when the bracket expression is `[]' so - far), the ']' character bit gets set way below. */ - if (c == ']' && p != p1 + 1) - break; - - /* Look ahead to see if it's a range when the last thing - was a character class. */ - if (had_char_class && c == '-' && *p != ']') - return REG_ERANGE; - - /* Look ahead to see if it's a range when the last thing - was a character: if this is a hyphen not at the - beginning or the end of a list, then it's the range - operator. */ - if (c == '-' - && !(p - 2 >= pattern && p[-2] == '[') - && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') - && *p != ']') - { - reg_errcode_t ret - = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) return ret; - } - - else if (p[0] == '-' && p[1] != ']') - { /* This handles ranges made up of characters only. */ - reg_errcode_t ret; - - /* Move past the `-'. */ - PATFETCH (c1); - - ret = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) return ret; - } - - /* See if we're at the beginning of a possible character - class. */ - - else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') - { /* Leave room for the null. */ - char str[CHAR_CLASS_MAX_LENGTH + 1]; - - PATFETCH (c); - c1 = 0; - - /* If pattern is `[[:'. */ - if (p == pend) return REG_EBRACK; - - for (;;) - { - PATFETCH (c); - if (c == ':' || c == ']' || p == pend - || c1 == CHAR_CLASS_MAX_LENGTH) - break; - str[c1++] = c; - } - str[c1] = '\0'; - - /* If isn't a word bracketed by `[:' and:`]': - undo the ending character, the letters, and leave - the leading `:' and `[' (but set bits for them). */ - if (c == ':' && *p == ']') - { - int ch; - boolean is_alnum = STREQ (str, "alnum"); - boolean is_alpha = STREQ (str, "alpha"); - boolean is_blank = STREQ (str, "blank"); - boolean is_cntrl = STREQ (str, "cntrl"); - boolean is_digit = STREQ (str, "digit"); - boolean is_graph = STREQ (str, "graph"); - boolean is_lower = STREQ (str, "lower"); - boolean is_print = STREQ (str, "print"); - boolean is_punct = STREQ (str, "punct"); - boolean is_space = STREQ (str, "space"); - boolean is_upper = STREQ (str, "upper"); - boolean is_xdigit = STREQ (str, "xdigit"); - - if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; - - /* Throw away the ] at the end of the character - class. */ - PATFETCH (c); - - if (p == pend) return REG_EBRACK; - - for (ch = 0; ch < 1 << BYTEWIDTH; ch++) - { - if ( (is_alnum && ISALNUM (ch)) - || (is_alpha && ISALPHA (ch)) - || (is_blank && ISBLANK (ch)) - || (is_cntrl && ISCNTRL (ch)) - || (is_digit && ISDIGIT (ch)) - || (is_graph && ISGRAPH (ch)) - || (is_lower && ISLOWER (ch)) - || (is_print && ISPRINT (ch)) - || (is_punct && ISPUNCT (ch)) - || (is_space && ISSPACE (ch)) - || (is_upper && ISUPPER (ch)) - || (is_xdigit && ISXDIGIT (ch))) - SET_LIST_BIT (ch); - } - had_char_class = true; - } - else - { - c1++; - while (c1--) - PATUNFETCH; - SET_LIST_BIT ('['); - SET_LIST_BIT (':'); - had_char_class = false; - } - } - else - { - had_char_class = false; - SET_LIST_BIT (c); - } - } - - /* Discard any (non)matching list bytes that are all 0 at the - end of the map. Decrease the map-length byte too. */ - while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) - b[-1]--; - b += b[-1]; - } - break; - - - case '(': - if (syntax & RE_NO_BK_PARENS) - goto handle_open; - else - goto normal_char; - - - case ')': - if (syntax & RE_NO_BK_PARENS) - goto handle_close; - else - goto normal_char; - - - case '\n': - if (syntax & RE_NEWLINE_ALT) - goto handle_alt; - else - goto normal_char; - - - case '|': - if (syntax & RE_NO_BK_VBAR) - goto handle_alt; - else - goto normal_char; - - - case '{': - if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) - goto handle_interval; - else - goto normal_char; - - - case '\\': - if (p == pend) return REG_EESCAPE; - - /* Do not translate the character after the \, so that we can - distinguish, e.g., \B from \b, even if we normally would - translate, e.g., B to b. */ - PATFETCH_RAW (c); - - switch (c) - { - case '(': - if (syntax & RE_NO_BK_PARENS) - goto normal_backslash; - - handle_open: - bufp->re_nsub++; - regnum++; - - if (COMPILE_STACK_FULL) - { - RETALLOC (compile_stack.stack, compile_stack.size << 1, - compile_stack_elt_t); - if (compile_stack.stack == NULL) return REG_ESPACE; - - compile_stack.size <<= 1; - } - - /* These are the values to restore when we hit end of this - group. They are all relative offsets, so that if the - whole pattern moves because of realloc, they will still - be valid. */ - COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; - COMPILE_STACK_TOP.fixup_alt_jump - = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; - COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; - COMPILE_STACK_TOP.regnum = regnum; - - /* We will eventually replace the 0 with the number of - groups inner to this one. But do not push a - start_memory for groups beyond the last one we can - represent in the compiled pattern. */ - if (regnum <= MAX_REGNUM) - { - COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; - BUF_PUSH_3 (start_memory, regnum, 0); - } - - compile_stack.avail++; - - fixup_alt_jump = 0; - laststart = 0; - begalt = b; - /* If we've reached MAX_REGNUM groups, then this open - won't actually generate any code, so we'll have to - clear pending_exact explicitly. */ - pending_exact = 0; - break; - - - case ')': - if (syntax & RE_NO_BK_PARENS) goto normal_backslash; - - if (COMPILE_STACK_EMPTY) - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_backslash; - else - return REG_ERPAREN; - - handle_close: - if (fixup_alt_jump) - { /* Push a dummy failure point at the end of the - alternative for a possible future - `pop_failure_jump' to pop. See comments at - `push_dummy_failure' in `re_match_2'. */ - BUF_PUSH (push_dummy_failure); - - /* We allocated space for this jump when we assigned - to `fixup_alt_jump', in the `handle_alt' case below. */ - STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); - } - - /* See similar code for backslashed left paren above. */ - if (COMPILE_STACK_EMPTY) - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_char; - else - return REG_ERPAREN; - - /* Since we just checked for an empty stack above, this - ``can't happen''. */ - assert (compile_stack.avail != 0); - { - /* We don't just want to restore into `regnum', because - later groups should continue to be numbered higher, - as in `(ab)c(de)' -- the second group is #2. */ - regnum_t this_group_regnum; - - compile_stack.avail--; - begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; - fixup_alt_jump - = COMPILE_STACK_TOP.fixup_alt_jump - ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 - : 0; - laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; - this_group_regnum = COMPILE_STACK_TOP.regnum; - /* If we've reached MAX_REGNUM groups, then this open - won't actually generate any code, so we'll have to - clear pending_exact explicitly. */ - pending_exact = 0; - - /* We're at the end of the group, so now we know how many - groups were inside this one. */ - if (this_group_regnum <= MAX_REGNUM) - { - unsigned char *inner_group_loc - = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; - - *inner_group_loc = regnum - this_group_regnum; - BUF_PUSH_3 (stop_memory, this_group_regnum, - regnum - this_group_regnum); - } - } - break; - - - case '|': /* `\|'. */ - if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) - goto normal_backslash; - handle_alt: - if (syntax & RE_LIMITED_OPS) - goto normal_char; - - /* Insert before the previous alternative a jump which - jumps to this alternative if the former fails. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (on_failure_jump, begalt, b + 6); - pending_exact = 0; - b += 3; - - /* The alternative before this one has a jump after it - which gets executed if it gets matched. Adjust that - jump so it will jump to this alternative's analogous - jump (put in below, which in turn will jump to the next - (if any) alternative's such jump, etc.). The last such - jump jumps to the correct final destination. A picture: - _____ _____ - | | | | - | v | v - a | b | c - - If we are at `b', then fixup_alt_jump right now points to a - three-byte space after `a'. We'll put in the jump, set - fixup_alt_jump to right after `b', and leave behind three - bytes which we'll fill in when we get to after `c'. */ - - if (fixup_alt_jump) - STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - - /* Mark and leave space for a jump after this alternative, - to be filled in later either by next alternative or - when know we're at the end of a series of alternatives. */ - fixup_alt_jump = b; - GET_BUFFER_SPACE (3); - b += 3; - - laststart = 0; - begalt = b; - break; - - - case '{': - /* If \{ is a literal. */ - if (!(syntax & RE_INTERVALS) - /* If we're at `\{' and it's not the open-interval - operator. */ - || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - || (p - 2 == pattern && p == pend)) - goto normal_backslash; - - handle_interval: - { - /* If got here, then the syntax allows intervals. */ - - /* At least (most) this many matches must be made. */ - int lower_bound = -1, upper_bound = -1; - - beg_interval = p - 1; - - if (p == pend) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_EBRACE; - } - - GET_UNSIGNED_NUMBER (lower_bound); - - if (c == ',') - { - GET_UNSIGNED_NUMBER (upper_bound); - if (upper_bound < 0) upper_bound = RE_DUP_MAX; - } - else - /* Interval such as `{1}' => match exactly once. */ - upper_bound = lower_bound; - - if (lower_bound < 0 || upper_bound > RE_DUP_MAX - || lower_bound > upper_bound) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_BADBR; - } - - if (!(syntax & RE_NO_BK_BRACES)) - { - if (c != '\\') return REG_EBRACE; - - PATFETCH (c); - } - - if (c != '}') - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_BADBR; - } - - /* We just parsed a valid interval. */ - - /* If it's invalid to have no preceding re. */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - return REG_BADRPT; - else if (syntax & RE_CONTEXT_INDEP_OPS) - laststart = b; - else - goto unfetch_interval; - } - - /* If the upper bound is zero, don't want to succeed at - all; jump from `laststart' to `b + 3', which will be - the end of the buffer after we insert the jump. */ - if (upper_bound == 0) - { - GET_BUFFER_SPACE (3); - INSERT_JUMP (jump, laststart, b + 3); - b += 3; - } - - /* Otherwise, we have a nontrivial interval. When - we're all done, the pattern will look like: - set_number_at <jump count> <upper bound> - set_number_at <succeed_n count> <lower bound> - succeed_n <after jump addr> <succed_n count> - <body of loop> - jump_n <succeed_n addr> <jump count> - (The upper bound and `jump_n' are omitted if - `upper_bound' is 1, though.) */ - else - { /* If the upper bound is > 1, we need to insert - more at the end of the loop. */ - unsigned nbytes = 10 + (upper_bound > 1) * 10; - - GET_BUFFER_SPACE (nbytes); - - /* Initialize lower bound of the `succeed_n', even - though it will be set during matching by its - attendant `set_number_at' (inserted next), - because `re_compile_fastmap' needs to know. - Jump to the `jump_n' we might insert below. */ - INSERT_JUMP2 (succeed_n, laststart, - b + 5 + (upper_bound > 1) * 5, - lower_bound); - b += 5; - - /* Code to initialize the lower bound. Insert - before the `succeed_n'. The `5' is the last two - bytes of this `set_number_at', plus 3 bytes of - the following `succeed_n'. */ - insert_op2 (set_number_at, laststart, 5, lower_bound, b); - b += 5; - - if (upper_bound > 1) - { /* More than one repetition is allowed, so - append a backward jump to the `succeed_n' - that starts this interval. - - When we've reached this during matching, - we'll have matched the interval once, so - jump back only `upper_bound - 1' times. */ - STORE_JUMP2 (jump_n, b, laststart + 5, - upper_bound - 1); - b += 5; - - /* The location we want to set is the second - parameter of the `jump_n'; that is `b-2' as - an absolute address. `laststart' will be - the `set_number_at' we're about to insert; - `laststart+3' the number to set, the source - for the relative address. But we are - inserting into the middle of the pattern -- - so everything is getting moved up by 5. - Conclusion: (b - 2) - (laststart + 3) + 5, - i.e., b - laststart. - - We insert this at the beginning of the loop - so that if we fail during matching, we'll - reinitialize the bounds. */ - insert_op2 (set_number_at, laststart, b - laststart, - upper_bound - 1, b); - b += 5; - } - } - pending_exact = 0; - beg_interval = NULL; - } - break; - - unfetch_interval: - /* If an invalid interval, match the characters as literals. */ - assert (beg_interval); - p = beg_interval; - beg_interval = NULL; - - /* normal_char and normal_backslash need `c'. */ - PATFETCH (c); - - if (!(syntax & RE_NO_BK_BRACES)) - { - if (p > pattern && p[-1] == '\\') - goto normal_backslash; - } - goto normal_char; - -#ifdef emacs - /* There is no way to specify the before_dot and after_dot - operators. rms says this is ok. --karl */ - case '=': - BUF_PUSH (at_dot); - break; - - case 's': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); - break; - - case 'S': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); - break; -#endif /* emacs */ - - - case 'w': - laststart = b; - BUF_PUSH (wordchar); - break; - - - case 'W': - laststart = b; - BUF_PUSH (notwordchar); - break; - - - case '<': - BUF_PUSH (wordbeg); - break; - - case '>': - BUF_PUSH (wordend); - break; - - case 'b': - BUF_PUSH (wordbound); - break; - - case 'B': - BUF_PUSH (notwordbound); - break; - - case '`': - BUF_PUSH (begbuf); - break; - - case '\'': - BUF_PUSH (endbuf); - break; - - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - if (syntax & RE_NO_BK_REFS) - goto normal_char; - - c1 = c - '0'; - - if (c1 > regnum) - return REG_ESUBREG; - - /* Can't back reference to a subexpression if inside of it. */ - if (group_in_compile_stack (compile_stack, c1)) - goto normal_char; - - laststart = b; - BUF_PUSH_2 (duplicate, c1); - break; - - - case '+': - case '?': - if (syntax & RE_BK_PLUS_QM) - goto handle_plus; - else - goto normal_backslash; - - default: - normal_backslash: - /* You might think it would be useful for \ to mean - not to translate; but if we don't translate it - it will never match anything. */ - c = TRANSLATE (c); - goto normal_char; - } - break; - - - default: - /* Expects the character in `c'. */ - normal_char: - /* If no exactn currently being built. */ - if (!pending_exact - - /* If last exactn not at current position. */ - || pending_exact + *pending_exact + 1 != b - - /* We have only one byte following the exactn for the count. */ - || *pending_exact == (1 << BYTEWIDTH) - 1 - - /* If followed by a repetition operator. */ - || *p == '*' || *p == '^' - || ((syntax & RE_BK_PLUS_QM) - ? *p == '\\' && (p[1] == '+' || p[1] == '?') - : (*p == '+' || *p == '?')) - || ((syntax & RE_INTERVALS) - && ((syntax & RE_NO_BK_BRACES) - ? *p == '{' - : (p[0] == '\\' && p[1] == '{')))) - { - /* Start building a new exactn. */ - - laststart = b; - - BUF_PUSH_2 (exactn, 0); - pending_exact = b - 1; - } - - BUF_PUSH (c); - (*pending_exact)++; - break; - } /* switch (c) */ - } /* while p != pend */ - - - /* Through the pattern now. */ - - if (fixup_alt_jump) - STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - - if (!COMPILE_STACK_EMPTY) - return REG_EPAREN; - - free (compile_stack.stack); - - /* We have succeeded; set the length of the buffer. */ - bufp->used = b - bufp->buffer; - -#ifdef DEBUG - if (debug) - { - DEBUG_PRINT1 ("\nCompiled pattern: "); - print_compiled_pattern (bufp); - } -#endif /* DEBUG */ - - return REG_NOERROR; -} /* regex_compile */ - -/* Subroutines for `regex_compile'. */ - -/* Store OP at LOC followed by two-byte integer parameter ARG. */ - -static void -store_op1 (op, loc, arg) - re_opcode_t op; - unsigned char *loc; - int arg; -{ - *loc = (unsigned char) op; - STORE_NUMBER (loc + 1, arg); -} - - -/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ - -static void -store_op2 (op, loc, arg1, arg2) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; -{ - *loc = (unsigned char) op; - STORE_NUMBER (loc + 1, arg1); - STORE_NUMBER (loc + 3, arg2); -} - - -/* Copy the bytes from LOC to END to open up three bytes of space at LOC - for OP followed by two-byte integer parameter ARG. */ - -static void -insert_op1 (op, loc, arg, end) - re_opcode_t op; - unsigned char *loc; - int arg; - unsigned char *end; -{ - register unsigned char *pfrom = end; - register unsigned char *pto = end + 3; - - while (pfrom != loc) - *--pto = *--pfrom; - - store_op1 (op, loc, arg); -} - - -/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ - -static void -insert_op2 (op, loc, arg1, arg2, end) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; - unsigned char *end; -{ - register unsigned char *pfrom = end; - register unsigned char *pto = end + 5; - - while (pfrom != loc) - *--pto = *--pfrom; - - store_op2 (op, loc, arg1, arg2); -} - - -/* P points to just after a ^ in PATTERN. Return true if that ^ comes - after an alternative or a begin-subexpression. We assume there is at - least one character before the ^. */ - -static boolean -at_begline_loc_p (pattern, p, syntax) - const char *pattern, *p; - reg_syntax_t syntax; -{ - const char *prev = p - 2; - boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; - - return - /* After a subexpression? */ - (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) - /* After an alternative? */ - || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); -} - - -/* The dual of at_begline_loc_p. This one is for $. We assume there is - at least one character after the $, i.e., `P < PEND'. */ - -static boolean -at_endline_loc_p (p, pend, syntax) - const char *p, *pend; - int syntax; -{ - const char *next = p; - boolean next_backslash = *next == '\\'; - const char *next_next = p + 1 < pend ? p + 1 : NULL; - - return - /* Before a subexpression? */ - (syntax & RE_NO_BK_PARENS ? *next == ')' - : next_backslash && next_next && *next_next == ')') - /* Before an alternative? */ - || (syntax & RE_NO_BK_VBAR ? *next == '|' - : next_backslash && next_next && *next_next == '|'); -} - - -/* Returns true if REGNUM is in one of COMPILE_STACK's elements and - false if it's not. */ - -static boolean -group_in_compile_stack (compile_stack, regnum) - compile_stack_type compile_stack; - regnum_t regnum; -{ - int this_element; - - for (this_element = compile_stack.avail - 1; - this_element >= 0; - this_element--) - if (compile_stack.stack[this_element].regnum == regnum) - return true; - - return false; -} - - -/* Read the ending character of a range (in a bracket expression) from the - uncompiled pattern *P_PTR (which ends at PEND). We assume the - starting character is in `P[-2]'. (`P[-1]' is the character `-'.) - Then we set the translation of all bits between the starting and - ending characters (inclusive) in the compiled pattern B. - - Return an error code. - - We use these short variable names so we can use the same macros as - `regex_compile' itself. */ - -static reg_errcode_t -compile_range (p_ptr, pend, translate, syntax, b) - const char **p_ptr, *pend; - char *translate; - reg_syntax_t syntax; - unsigned char *b; -{ - unsigned this_char; - - const char *p = *p_ptr; - int range_start, range_end; - - if (p == pend) - return REG_ERANGE; - - /* Even though the pattern is a signed `char *', we need to fetch - with unsigned char *'s; if the high bit of the pattern character - is set, the range endpoints will be negative if we fetch using a - signed char *. - - We also want to fetch the endpoints without translating them; the - appropriate translation is done in the bit-setting loop below. */ - range_start = ((unsigned char *) p)[-2]; - range_end = ((unsigned char *) p)[0]; - - /* Have to increment the pointer into the pattern string, so the - caller isn't still at the ending character. */ - (*p_ptr)++; - - /* If the start is after the end, the range is empty. */ - if (range_start > range_end) - return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; - - /* Here we see why `this_char' has to be larger than an `unsigned - char' -- the range is inclusive, so if `range_end' == 0xff - (assuming 8-bit characters), we would otherwise go into an infinite - loop, since all characters <= 0xff. */ - for (this_char = range_start; this_char <= range_end; this_char++) - { - SET_LIST_BIT (TRANSLATE (this_char)); - } - - return REG_NOERROR; -} - -/* Failure stack declarations and macros; both re_compile_fastmap and - re_match_2 use a failure stack. These have to be macros because of - REGEX_ALLOCATE. */ - - -/* Number of failure points for which to initially allocate space - when matching. If this number is exceeded, we allocate more - space, so it is not a hard limit. */ -#ifndef INIT_FAILURE_ALLOC -#define INIT_FAILURE_ALLOC 5 -#endif - -/* Roughly the maximum number of failure points on the stack. Would be - exactly that if always used MAX_FAILURE_SPACE each time we failed. - This is a variable only so users of regex can assign to it; we never - change it ourselves. */ -int re_max_failures = 2000; - -typedef const unsigned char *fail_stack_elt_t; - -typedef struct -{ - fail_stack_elt_t *stack; - unsigned size; - unsigned avail; /* Offset of next open position. */ -} fail_stack_type; - -#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) -#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) -#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) -#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) - - -/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ - -#define INIT_FAIL_STACK() \ - do { \ - fail_stack.stack = (fail_stack_elt_t *) \ - REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ - \ - if (fail_stack.stack == NULL) \ - return -2; \ - \ - fail_stack.size = INIT_FAILURE_ALLOC; \ - fail_stack.avail = 0; \ - } while (0) - - -/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. - - Return 1 if succeeds, and 0 if either ran out of memory - allocating space for it or it was already too large. - - REGEX_REALLOCATE requires `destination' be declared. */ - -#define DOUBLE_FAIL_STACK(fail_stack) \ - ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ - ? 0 \ - : ((fail_stack).stack = (fail_stack_elt_t *) \ - REGEX_REALLOCATE ((fail_stack).stack, \ - (fail_stack).size * sizeof (fail_stack_elt_t), \ - ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ - \ - (fail_stack).stack == NULL \ - ? 0 \ - : ((fail_stack).size <<= 1, \ - 1))) - - -/* Push PATTERN_OP on FAIL_STACK. - - Return 1 if was able to do so and 0 if ran out of memory allocating - space to do so. */ -#define PUSH_PATTERN_OP(pattern_op, fail_stack) \ - ((FAIL_STACK_FULL () \ - && !DOUBLE_FAIL_STACK (fail_stack)) \ - ? 0 \ - : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \ - 1)) - -/* This pushes an item onto the failure stack. Must be a four-byte - value. Assumes the variable `fail_stack'. Probably should only - be called from within `PUSH_FAILURE_POINT'. */ -#define PUSH_FAILURE_ITEM(item) \ - fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item - -/* The complement operation. Assumes `fail_stack' is nonempty. */ -#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] - -/* Used to omit pushing failure point id's when we're not debugging. */ -#ifdef DEBUG -#define DEBUG_PUSH PUSH_FAILURE_ITEM -#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM () -#else -#define DEBUG_PUSH(item) -#define DEBUG_POP(item_addr) -#endif - - -/* Push the information about the state we will need - if we ever fail back to it. - - Requires variables fail_stack, regstart, regend, reg_info, and - num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be - declared. - - Does `return FAILURE_CODE' if runs out of memory. */ - -#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ - do { \ - char *destination; \ - /* Must be int, so when we don't save any registers, the arithmetic \ - of 0 + -1 isn't done as unsigned. */ \ - int this_reg; \ - \ - DEBUG_STATEMENT (failure_id++); \ - DEBUG_STATEMENT (nfailure_points_pushed++); \ - DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ - DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ - DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ - \ - DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \ - DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ - \ - /* Ensure we have enough space allocated for what we will push. */ \ - while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ - { \ - if (!DOUBLE_FAIL_STACK (fail_stack)) \ - return failure_code; \ - \ - DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ - (fail_stack).size); \ - DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ - } \ - \ - /* Push the info, starting with the registers. */ \ - DEBUG_PRINT1 ("\n"); \ - \ - for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ - this_reg++) \ - { \ - DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ - DEBUG_STATEMENT (num_regs_pushed++); \ - \ - DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ - PUSH_FAILURE_ITEM (regstart[this_reg]); \ - \ - DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ - PUSH_FAILURE_ITEM (regend[this_reg]); \ - \ - DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ - DEBUG_PRINT2 (" match_null=%d", \ - REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ - DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ - DEBUG_PRINT2 (" matched_something=%d", \ - MATCHED_SOMETHING (reg_info[this_reg])); \ - DEBUG_PRINT2 (" ever_matched=%d", \ - EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ - DEBUG_PRINT1 ("\n"); \ - PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ - } \ - \ - DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ - PUSH_FAILURE_ITEM (lowest_active_reg); \ - \ - DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\ - PUSH_FAILURE_ITEM (highest_active_reg); \ - \ - DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \ - DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ - PUSH_FAILURE_ITEM (pattern_place); \ - \ - DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \ - DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ - size2); \ - DEBUG_PRINT1 ("'\n"); \ - PUSH_FAILURE_ITEM (string_place); \ - \ - DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ - DEBUG_PUSH (failure_id); \ - } while (0) - -/* This is the number of items that are pushed and popped on the stack - for each register. */ -#define NUM_REG_ITEMS 3 - -/* Individual items aside from the registers. */ -#ifdef DEBUG -#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ -#else -#define NUM_NONREG_ITEMS 4 -#endif - -/* We push at most this many items on the stack. */ -#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS) - -/* We actually push this many items. */ -#define NUM_FAILURE_ITEMS \ - ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \ - + NUM_NONREG_ITEMS) - -/* How many items can still be added to the stack without overflowing it. */ -#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) - - -/* Pops what PUSH_FAIL_STACK pushes. - - We restore into the parameters, all of which should be lvalues: - STR -- the saved data position. - PAT -- the saved pattern position. - LOW_REG, HIGH_REG -- the highest and lowest active registers. - REGSTART, REGEND -- arrays of string positions. - REG_INFO -- array of information about each subexpression. - - Also assumes the variables `fail_stack' and (if debugging), `bufp', - `pend', `string1', `size1', `string2', and `size2'. */ - -#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ -{ \ - DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ - int this_reg; \ - const unsigned char *string_temp; \ - \ - assert (!FAIL_STACK_EMPTY ()); \ - \ - /* Remove failure points and point to how many regs pushed. */ \ - DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ - DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ - DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ - \ - assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ - \ - DEBUG_POP (&failure_id); \ - DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ - \ - /* If the saved string location is NULL, it came from an \ - on_failure_keep_string_jump opcode, and we want to throw away the \ - saved NULL, thus retaining our current position in the string. */ \ - string_temp = POP_FAILURE_ITEM (); \ - if (string_temp != NULL) \ - str = (const char *) string_temp; \ - \ - DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ - DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ - DEBUG_PRINT1 ("'\n"); \ - \ - pat = (unsigned char *) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ - DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ - \ - /* Restore register info. */ \ - high_reg = (unsigned) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ - \ - low_reg = (unsigned) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ - \ - for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ - { \ - DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ - \ - reg_info[this_reg].word = POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ - \ - regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ - \ - regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ - } \ - \ - DEBUG_STATEMENT (nfailure_points_popped++); \ -} /* POP_FAILURE_POINT */ - -/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in - BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible - characters can start a string that matches the pattern. This fastmap - is used by re_search to skip quickly over impossible starting points. - - The caller must supply the address of a (1 << BYTEWIDTH)-byte data - area as BUFP->fastmap. - - We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in - the pattern buffer. - - Returns 0 if we succeed, -2 if an internal error. */ - -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; -{ - int j, k; - fail_stack_type fail_stack; -#ifndef REGEX_MALLOC - char *destination; -#endif - /* We don't push any register information onto the failure stack. */ - unsigned num_regs = 0; - - register char *fastmap = bufp->fastmap; - unsigned char *pattern = bufp->buffer; - unsigned long size = bufp->used; - const unsigned char *p = pattern; - register unsigned char *pend = pattern + size; - - /* Assume that each path through the pattern can be null until - proven otherwise. We set this false at the bottom of switch - statement, to which we get only if a particular path doesn't - match the empty string. */ - boolean path_can_be_null = true; - - /* We aren't doing a `succeed_n' to begin with. */ - boolean succeed_n_p = false; - - assert (fastmap != NULL && p != NULL); - - INIT_FAIL_STACK (); - bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ - bufp->fastmap_accurate = 1; /* It will be when we're done. */ - bufp->can_be_null = 0; - - while (p != pend || !FAIL_STACK_EMPTY ()) - { - if (p == pend) - { - bufp->can_be_null |= path_can_be_null; - - /* Reset for next path. */ - path_can_be_null = true; - - p = fail_stack.stack[--fail_stack.avail]; - } - - /* We should never be about to go beyond the end of the pattern. */ - assert (p < pend); - -#ifdef SWITCH_ENUM_BUG - switch ((int) ((re_opcode_t) *p++)) -#else - switch ((re_opcode_t) *p++) -#endif - { - - /* I guess the idea here is to simply not bother with a fastmap - if a backreference is used, since it's too hard to figure out - the fastmap for the corresponding group. Setting - `can_be_null' stops `re_search_2' from using the fastmap, so - that is all we do. */ - case duplicate: - bufp->can_be_null = 1; - return 0; - - - /* Following are the cases which match a character. These end - with `break'. */ - - case exactn: - fastmap[p[1]] = 1; - break; - - - case charset: - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) - if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) - fastmap[j] = 1; - break; - - - case charset_not: - /* Chars beyond end of map must be allowed. */ - for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; - - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) - if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) - fastmap[j] = 1; - break; - - - case wordchar: - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) == Sword) - fastmap[j] = 1; - break; - - - case notwordchar: - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) != Sword) - fastmap[j] = 1; - break; - - - case anychar: - /* `.' matches anything ... */ - for (j = 0; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; - - /* ... except perhaps newline. */ - if (!(bufp->syntax & RE_DOT_NEWLINE)) - fastmap['\n'] = 0; - - /* Return if we have already set `can_be_null'; if we have, - then the fastmap is irrelevant. Something's wrong here. */ - else if (bufp->can_be_null) - return 0; - - /* Otherwise, have to check alternative paths. */ - break; - - -#ifdef emacs - case syntaxspec: - k = *p++; - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) == (enum syntaxcode) k) - fastmap[j] = 1; - break; - - - case notsyntaxspec: - k = *p++; - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) != (enum syntaxcode) k) - fastmap[j] = 1; - break; - - - /* All cases after this match the empty string. These end with - `continue'. */ - - - case before_dot: - case at_dot: - case after_dot: - continue; -#endif /* not emacs */ - - - case no_op: - case begline: - case endline: - case begbuf: - case endbuf: - case wordbound: - case notwordbound: - case wordbeg: - case wordend: - case push_dummy_failure: - continue; - - - case jump_n: - case pop_failure_jump: - case maybe_pop_jump: - case jump: - case jump_past_alt: - case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; - if (j > 0) - continue; - - /* Jump backward implies we just went through the body of a - loop and matched nothing. Opcode jumped to should be - `on_failure_jump' or `succeed_n'. Just treat it like an - ordinary jump. For a * loop, it has pushed its failure - point already; if so, discard that as redundant. */ - if ((re_opcode_t) *p != on_failure_jump - && (re_opcode_t) *p != succeed_n) - continue; - - p++; - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; - - /* If what's on the stack is where we are now, pop it. */ - if (!FAIL_STACK_EMPTY () - && fail_stack.stack[fail_stack.avail - 1] == p) - fail_stack.avail--; - - continue; - - - case on_failure_jump: - case on_failure_keep_string_jump: - handle_on_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); - - /* For some patterns, e.g., `(a?)?', `p+j' here points to the - end of the pattern. We don't want to push such a point, - since when we restore it above, entering the switch will - increment `p' past the end of the pattern. We don't need - to push such a point since we obviously won't find any more - fastmap entries beyond `pend'. Such a pattern can match - the null string, though. */ - if (p + j < pend) - { - if (!PUSH_PATTERN_OP (p + j, fail_stack)) - return -2; - } - else - bufp->can_be_null = 1; - - if (succeed_n_p) - { - EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ - succeed_n_p = false; - } - - continue; - - - case succeed_n: - /* Get to the number of times to succeed. */ - p += 2; - - /* Increment p past the n for when k != 0. */ - EXTRACT_NUMBER_AND_INCR (k, p); - if (k == 0) - { - p -= 4; - succeed_n_p = true; /* Spaghetti code alert. */ - goto handle_on_failure_jump; - } - continue; - - - case set_number_at: - p += 4; - continue; - - - case start_memory: - case stop_memory: - p += 2; - continue; - - - default: - abort (); /* We have listed all the cases. */ - } /* switch *p++ */ - - /* Getting here means we have found the possible starting - characters for one path of the pattern -- and that the empty - string does not match. We need not follow this path further. - Instead, look at the next alternative (remembered on the - stack), or quit if no more. The test at the top of the loop - does these things. */ - path_can_be_null = false; - p = pend; - } /* while p */ - - /* Set `can_be_null' for the last path (also the first path, if the - pattern is empty). */ - bufp->can_be_null |= path_can_be_null; - return 0; -} /* re_compile_fastmap */ - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use - this memory for recording register information. STARTS and ENDS - must be allocated using the malloc library routine, and must each - be at least NUM_REGS * sizeof (regoff_t) bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ - -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; -{ - if (num_regs) - { - bufp->regs_allocated = REGS_REALLOCATE; - regs->num_regs = num_regs; - regs->start = starts; - regs->end = ends; - } - else - { - bufp->regs_allocated = REGS_UNALLOCATED; - regs->num_regs = 0; - regs->start = regs->end = (regoff_t) 0; - } -} - -/* Searching routines. */ - -/* Like re_search_2, below, but only one string is specified, and - doesn't let you say where to stop matching. */ - -int -re_search (bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; -{ - return re_search_2 (bufp, NULL, 0, string, size, startpos, range, - regs, size); -} - - -/* Using the compiled pattern in BUFP->buffer, first tries to match the - virtual concatenation of STRING1 and STRING2, starting first at index - STARTPOS, then at STARTPOS + 1, and so on. - - STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. - - RANGE is how far to scan while trying to match. RANGE = 0 means try - only at STARTPOS; in general, the last start tried is STARTPOS + - RANGE. - - In REGS, return the indices of the virtual concatenation of STRING1 - and STRING2 that matched the entire BUFP->buffer and its contained - subexpressions. - - Do not consider matching one past the index STOP in the virtual - concatenation of STRING1 and STRING2. - - We return either the position in the strings at which the match was - found, -1 if no match, or -2 if error (such as failure - stack overflow). */ - -int -re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int startpos; - int range; - struct re_registers *regs; - int stop; -{ - int val; - register char *fastmap = bufp->fastmap; - register char *translate = bufp->translate; - int total_size = size1 + size2; - int endpos = startpos + range; - - /* Check for out-of-range STARTPOS. */ - if (startpos < 0 || startpos > total_size) - return -1; - - /* Fix up RANGE if it might eventually take us outside - the virtual concatenation of STRING1 and STRING2. */ - if (endpos < -1) - range = -1 - startpos; - else if (endpos > total_size) - range = total_size - startpos; - - /* If the search isn't to be a backwards one, don't waste time in a - search for a pattern that must be anchored. */ - if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) - { - if (startpos > 0) - return -1; - else - range = 1; - } - - /* Update the fastmap now if not correct already. */ - if (fastmap && !bufp->fastmap_accurate) - if (re_compile_fastmap (bufp) == -2) - return -2; - - /* Loop through the string, looking for a place to start matching. */ - for (;;) - { - /* If a fastmap is supplied, skip quickly over characters that - cannot be the start of a match. If the pattern can match the - null string, however, we don't need to skip characters; we want - the first null string. */ - if (fastmap && startpos < total_size && !bufp->can_be_null) - { - if (range > 0) /* Searching forwards. */ - { - register const char *d; - register int lim = 0; - int irange = range; - - if (startpos < size1 && startpos + range >= size1) - lim = range - (size1 - startpos); - - d = (startpos >= size1 ? string2 - size1 : string1) + startpos; - - /* Written out as an if-else to avoid testing `translate' - inside the loop. */ - if (translate) - while (range > lim - && !fastmap[(unsigned char) - translate[(unsigned char) *d++]]) - range--; - else - while (range > lim && !fastmap[(unsigned char) *d++]) - range--; - - startpos += irange - range; - } - else /* Searching backwards. */ - { - register char c = (size1 == 0 || startpos >= size1 - ? string2[startpos - size1] - : string1[startpos]); - - if (!fastmap[(unsigned char) TRANSLATE (c)]) - goto advance; - } - } - - /* If can't match the null string, and that's all we have left, fail. */ - if (range >= 0 && startpos == total_size && fastmap - && !bufp->can_be_null) - return -1; - - val = re_match_2 (bufp, string1, size1, string2, size2, - startpos, regs, stop); - if (val >= 0) - return startpos; - - if (val == -2) - return -2; - - advance: - if (!range) - break; - else if (range > 0) - { - range--; - startpos++; - } - else - { - range++; - startpos--; - } - } - return -1; -} /* re_search_2 */ - -/* Declarations and macros for re_match_2. */ - -static int bcmp_translate (); -static boolean alt_match_null_string_p (), - common_op_match_null_string_p (), - group_match_null_string_p (); - -/* Structure for per-register (a.k.a. per-group) information. - This must not be longer than one word, because we push this value - onto the failure stack. Other register information, such as the - starting and ending positions (which are addresses), and the list of - inner groups (which is a bits list) are maintained in separate - variables. - - We are making a (strictly speaking) nonportable assumption here: that - the compiler will pack our bit fields into something that fits into - the type of `word', i.e., is something that fits into one item on the - failure stack. */ -typedef union -{ - fail_stack_elt_t word; - struct - { - /* This field is one if this group can match the empty string, - zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ -#define MATCH_NULL_UNSET_VALUE 3 - unsigned match_null_string_p : 2; - unsigned is_active : 1; - unsigned matched_something : 1; - unsigned ever_matched_something : 1; - } bits; -} register_info_type; - -#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) -#define IS_ACTIVE(R) ((R).bits.is_active) -#define MATCHED_SOMETHING(R) ((R).bits.matched_something) -#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) - - -/* Call this when have matched a real character; it sets `matched' flags - for the subexpressions which we are currently inside. Also records - that those subexprs have matched. */ -#define SET_REGS_MATCHED() \ - do \ - { \ - unsigned r; \ - for (r = lowest_active_reg; r <= highest_active_reg; r++) \ - { \ - MATCHED_SOMETHING (reg_info[r]) \ - = EVER_MATCHED_SOMETHING (reg_info[r]) \ - = 1; \ - } \ - } \ - while (0) - - -/* This converts PTR, a pointer into one of the search strings `string1' - and `string2' into an offset from the beginning of that string. */ -#define POINTER_TO_OFFSET(ptr) \ - (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1) - -/* Registers are set to a sentinel when they haven't yet matched. */ -#define REG_UNSET_VALUE ((char *) -1) -#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) - - -/* Macros for dealing with the split strings in re_match_2. */ - -#define MATCHING_IN_FIRST_STRING (dend == end_match_1) - -/* Call before fetching a character with *d. This switches over to - string2 if necessary. */ -#define PREFETCH() \ - while (d == dend) \ - { \ - /* End of string2 => fail. */ \ - if (dend == end_match_2) \ - goto fail; \ - /* End of string1 => advance to string2. */ \ - d = string2; \ - dend = end_match_2; \ - } - - -/* Test if at very beginning or at very end of the virtual concatenation - of `string1' and `string2'. If only one string, it's `string2'. */ -#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) -#define AT_STRINGS_END(d) ((d) == end2) - - -/* Test if D points to a character which is word-constituent. We have - two special cases to check for: if past the end of string1, look at - the first character in string2; and if before the beginning of - string2, look at the last character in string1. */ -#define WORDCHAR_P(d) \ - (SYNTAX ((d) == end1 ? *string2 \ - : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ - == Sword) - -/* Test if the character before D and the one at D differ with respect - to being word-constituent. */ -#define AT_WORD_BOUNDARY(d) \ - (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ - || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) - - -/* Free everything we malloc. */ -#ifdef REGEX_MALLOC -#define FREE_VAR(var) if (var) free (var); var = NULL -#define FREE_VARIABLES() \ - do { \ - FREE_VAR (fail_stack.stack); \ - FREE_VAR (regstart); \ - FREE_VAR (regend); \ - FREE_VAR (old_regstart); \ - FREE_VAR (old_regend); \ - FREE_VAR (best_regstart); \ - FREE_VAR (best_regend); \ - FREE_VAR (reg_info); \ - FREE_VAR (reg_dummy); \ - FREE_VAR (reg_info_dummy); \ - } while (0) -#else /* not REGEX_MALLOC */ -/* Some MIPS systems (at least) want this to free alloca'd storage. */ -#define FREE_VARIABLES() alloca (0) -#endif /* not REGEX_MALLOC */ - - -/* These values must meet several constraints. They must not be valid - register values; since we have a limit of 255 registers (because - we use only one byte in the pattern for the register number), we can - use numbers larger than 255. They must differ by 1, because of - NUM_FAILURE_ITEMS above. And the value for the lowest register must - be larger than the value for the highest register, so we do not try - to actually save any registers when none are active. */ -#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) -#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) - -/* Matching routines. */ - -#ifndef emacs /* Emacs never uses this. */ -/* re_match is like re_match_2 except it takes only a single string. */ - -int -re_match (bufp, string, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, pos; - struct re_registers *regs; - { - return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); -} -#endif /* not emacs */ - - -/* re_match_2 matches the compiled pattern in BUFP against the - the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 - and SIZE2, respectively). We start matching at POS, and stop - matching at STOP. - - If REGS is non-null and the `no_sub' field of BUFP is nonzero, we - store offsets for the substring each group matched in REGS. See the - documentation for exactly how many groups we fill. - - We return -1 if no match, -2 if an internal error (such as the - failure stack overflowing). Otherwise, we return the length of the - matched substring. */ - -int -re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; -{ - /* General temporaries. */ - int mcnt; - unsigned char *p1; - - /* Just past the end of the corresponding string. */ - const char *end1, *end2; - - /* Pointers into string1 and string2, just past the last characters in - each to consider matching. */ - const char *end_match_1, *end_match_2; - - /* Where we are in the data, and the end of the current string. */ - const char *d, *dend; - - /* Where we are in the pattern, and the end of the pattern. */ - unsigned char *p = bufp->buffer; - register unsigned char *pend = p + bufp->used; - - /* We use this to map every character in the string. */ - char *translate = bufp->translate; - - /* Failure point stack. Each place that can handle a failure further - down the line pushes a failure point on this stack. It consists of - restart, regend, and reg_info for all registers corresponding to - the subexpressions we're currently inside, plus the number of such - registers, and, finally, two char *'s. The first char * is where - to resume scanning the pattern; the second one is where to resume - scanning the strings. If the latter is zero, the failure point is - a ``dummy''; if a failure happens and the failure point is a dummy, - it gets discarded and the next next one is tried. */ - fail_stack_type fail_stack; -#ifdef DEBUG - static unsigned failure_id = 0; - unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; -#endif - - /* We fill all the registers internally, independent of what we - return, for use in backreferences. The number here includes - an element for register zero. */ - unsigned num_regs = bufp->re_nsub + 1; - - /* The currently active registers. */ - unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; - unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; - - /* Information on the contents of registers. These are pointers into - the input strings; they record just what was matched (on this - attempt) by a subexpression part of the pattern, that is, the - regnum-th regstart pointer points to where in the pattern we began - matching and the regnum-th regend points to right after where we - stopped matching the regnum-th subexpression. (The zeroth register - keeps track of what the whole pattern matches.) */ - const char **regstart, **regend; - - /* If a group that's operated upon by a repetition operator fails to - match anything, then the register for its start will need to be - restored because it will have been set to wherever in the string we - are when we last see its open-group operator. Similarly for a - register's end. */ - const char **old_regstart, **old_regend; - - /* The is_active field of reg_info helps us keep track of which (possibly - nested) subexpressions we are currently in. The matched_something - field of reg_info[reg_num] helps us tell whether or not we have - matched any of the pattern so far this time through the reg_num-th - subexpression. These two fields get reset each time through any - loop their register is in. */ - register_info_type *reg_info; - - /* The following record the register info as found in the above - variables when we find a match better than any we've seen before. - This happens as we backtrack through the failure points, which in - turn happens only if we have not yet matched the entire string. */ - unsigned best_regs_set = false; - const char **best_regstart, **best_regend; - - /* Logically, this is `best_regend[0]'. But we don't want to have to - allocate space for that if we're not allocating space for anything - else (see below). Also, we never need info about register 0 for - any of the other register vectors, and it seems rather a kludge to - treat `best_regend' differently than the rest. So we keep track of - the end of the best match so far in a separate variable. We - initialize this to NULL so that when we backtrack the first time - and need to test it, it's not garbage. */ - const char *match_end = NULL; - - /* Used when we pop values we don't care about. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; - -#ifdef DEBUG - /* Counts the total number of registers pushed. */ - unsigned num_regs_pushed = 0; -#endif - - DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); - - INIT_FAIL_STACK (); - - /* Do not bother to initialize all the register variables if there are - no groups in the pattern, as it takes a fair amount of time. If - there are groups, we include space for register 0 (the whole - pattern), even though we never use it, since it simplifies the - array indexing. We should fix this. */ - if (bufp->re_nsub) - { - regstart = REGEX_TALLOC (num_regs, const char *); - regend = REGEX_TALLOC (num_regs, const char *); - old_regstart = REGEX_TALLOC (num_regs, const char *); - old_regend = REGEX_TALLOC (num_regs, const char *); - best_regstart = REGEX_TALLOC (num_regs, const char *); - best_regend = REGEX_TALLOC (num_regs, const char *); - reg_info = REGEX_TALLOC (num_regs, register_info_type); - reg_dummy = REGEX_TALLOC (num_regs, const char *); - reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); - - if (!(regstart && regend && old_regstart && old_regend && reg_info - && best_regstart && best_regend && reg_dummy && reg_info_dummy)) - { - FREE_VARIABLES (); - return -2; - } - } -#ifdef REGEX_MALLOC - else - { - /* We must initialize all our variables to NULL, so that - `FREE_VARIABLES' doesn't try to free them. */ - regstart = regend = old_regstart = old_regend = best_regstart - = best_regend = reg_dummy = NULL; - reg_info = reg_info_dummy = (register_info_type *) NULL; - } -#endif /* REGEX_MALLOC */ - - /* The starting position is bogus. */ - if (pos < 0 || pos > size1 + size2) - { - FREE_VARIABLES (); - return -1; - } - - /* Initialize subexpression text positions to -1 to mark ones that no - start_memory/stop_memory has been seen for. Also initialize the - register information struct. */ - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - regstart[mcnt] = regend[mcnt] - = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; - - REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; - IS_ACTIVE (reg_info[mcnt]) = 0; - MATCHED_SOMETHING (reg_info[mcnt]) = 0; - EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; - } - - /* We move `string1' into `string2' if the latter's empty -- but not if - `string1' is null. */ - if (size2 == 0 && string1 != NULL) - { - string2 = string1; - size2 = size1; - string1 = 0; - size1 = 0; - } - end1 = string1 + size1; - end2 = string2 + size2; - - /* Compute where to stop matching, within the two strings. */ - if (stop <= size1) - { - end_match_1 = string1 + stop; - end_match_2 = string2; - } - else - { - end_match_1 = end1; - end_match_2 = string2 + stop - size1; - } - - /* `p' scans through the pattern as `d' scans through the data. - `dend' is the end of the input string that `d' points within. `d' - is advanced into the following input string whenever necessary, but - this happens before fetching; therefore, at the beginning of the - loop, `d' can be pointing at the end of a string, but it cannot - equal `string2'. */ - if (size1 > 0 && pos <= size1) - { - d = string1 + pos; - dend = end_match_1; - } - else - { - d = string2 + pos - size1; - dend = end_match_2; - } - - DEBUG_PRINT1 ("The compiled pattern is: "); - DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); - DEBUG_PRINT1 ("The string to match is: `"); - DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); - DEBUG_PRINT1 ("'\n"); - - /* This loops over pattern commands. It exits by returning from the - function if the match is complete, or it drops through if the match - fails at this starting point in the input data. */ - for (;;) - { - DEBUG_PRINT2 ("\n0x%x: ", p); - - if (p == pend) - { /* End of pattern means we might have succeeded. */ - DEBUG_PRINT1 ("end of pattern ... "); - - /* If we haven't matched the entire string, and we want the - longest match, try backtracking. */ - if (d != end_match_2) - { - DEBUG_PRINT1 ("backtracking.\n"); - - if (!FAIL_STACK_EMPTY ()) - { /* More failure points to try. */ - boolean same_str_p = (FIRST_STRING_P (match_end) - == MATCHING_IN_FIRST_STRING); - - /* If exceeds best match so far, save it. */ - if (!best_regs_set - || (same_str_p && d > match_end) - || (!same_str_p && !MATCHING_IN_FIRST_STRING)) - { - best_regs_set = true; - match_end = d; - - DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); - - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - best_regstart[mcnt] = regstart[mcnt]; - best_regend[mcnt] = regend[mcnt]; - } - } - goto fail; - } - - /* If no failure points, don't restore garbage. */ - else if (best_regs_set) - { - restore_best_regs: - /* Restore best match. It may happen that `dend == - end_match_1' while the restored d is in string2. - For example, the pattern `x.*y.*z' against the - strings `x-' and `y-z-', if the two strings are - not consecutive in memory. */ - DEBUG_PRINT1 ("Restoring best registers.\n"); - - d = match_end; - dend = ((d >= string1 && d <= end1) - ? end_match_1 : end_match_2); - - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - regstart[mcnt] = best_regstart[mcnt]; - regend[mcnt] = best_regend[mcnt]; - } - } - } /* d != end_match_2 */ - - DEBUG_PRINT1 ("Accepting match.\n"); - - /* If caller wants register contents data back, do it. */ - if (regs && !bufp->no_sub) - { - /* Have the register data arrays been allocated? */ - if (bufp->regs_allocated == REGS_UNALLOCATED) - { /* No. So allocate them with malloc. We need one - extra element beyond `num_regs' for the `-1' marker - GNU code uses. */ - regs->num_regs = MAX (RE_NREGS, num_regs + 1); - regs->start = TALLOC (regs->num_regs, regoff_t); - regs->end = TALLOC (regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - bufp->regs_allocated = REGS_REALLOCATE; - } - else if (bufp->regs_allocated == REGS_REALLOCATE) - { /* Yes. If we need more elements than were already - allocated, reallocate them. If we need fewer, just - leave it alone. */ - if (regs->num_regs < num_regs + 1) - { - regs->num_regs = num_regs + 1; - RETALLOC (regs->start, regs->num_regs, regoff_t); - RETALLOC (regs->end, regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - } - } - else - assert (bufp->regs_allocated == REGS_FIXED); - - /* Convert the pointer data in `regstart' and `regend' to - indices. Register zero has to be set differently, - since we haven't kept track of any info for it. */ - if (regs->num_regs > 0) - { - regs->start[0] = pos; - regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 - : d - string2 + size1); - } - - /* Go through the first `min (num_regs, regs->num_regs)' - registers, since that is all we initialized. */ - for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) - { - if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) - regs->start[mcnt] = regs->end[mcnt] = -1; - else - { - regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); - regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); - } - } - - /* If the regs structure we return has more elements than - were in the pattern, set the extra elements to -1. If - we (re)allocated the registers, this is the case, - because we always allocate enough to have at least one - -1 at the end. */ - for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) - regs->start[mcnt] = regs->end[mcnt] = -1; - } /* regs && !bufp->no_sub */ - - FREE_VARIABLES (); - DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", - nfailure_points_pushed, nfailure_points_popped, - nfailure_points_pushed - nfailure_points_popped); - DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); - - mcnt = d - pos - (MATCHING_IN_FIRST_STRING - ? string1 - : string2 - size1); - - DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); - - return mcnt; - } - - /* Otherwise match next pattern command. */ -#ifdef SWITCH_ENUM_BUG - switch ((int) ((re_opcode_t) *p++)) -#else - switch ((re_opcode_t) *p++) -#endif - { - /* Ignore these. Used to ignore the n of succeed_n's which - currently have n == 0. */ - case no_op: - DEBUG_PRINT1 ("EXECUTING no_op.\n"); - break; - - - /* Match the next n pattern characters exactly. The following - byte in the pattern defines n, and the n bytes after that - are the characters to match. */ - case exactn: - mcnt = *p++; - DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); - - /* This is written out as an if-else so we don't waste time - testing `translate' inside the loop. */ - if (translate) - { - do - { - PREFETCH (); - if (translate[(unsigned char) *d++] != (char) *p++) - goto fail; - } - while (--mcnt); - } - else - { - do - { - PREFETCH (); - if (*d++ != (char) *p++) goto fail; - } - while (--mcnt); - } - SET_REGS_MATCHED (); - break; - - - /* Match any character except possibly a newline or a null. */ - case anychar: - DEBUG_PRINT1 ("EXECUTING anychar.\n"); - - PREFETCH (); - - if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') - || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) - goto fail; - - SET_REGS_MATCHED (); - DEBUG_PRINT2 (" Matched `%d'.\n", *d); - d++; - break; - - - case charset: - case charset_not: - { - register unsigned char c; - boolean not = (re_opcode_t) *(p - 1) == charset_not; - - DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); - - PREFETCH (); - c = TRANSLATE (*d); /* The character to match. */ - - /* Cast to `unsigned' instead of `unsigned char' in case the - bit list is a full 32 bytes long. */ - if (c < (unsigned) (*p * BYTEWIDTH) - && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) - not = !not; - - p += 1 + *p; - - if (!not) goto fail; - - SET_REGS_MATCHED (); - d++; - break; - } - - - /* The beginning of a group is represented by start_memory. - The arguments are the register number in the next byte, and the - number of groups inner to this one in the next. The text - matched within the group is recorded (in the internal - registers data structure) under the register number. */ - case start_memory: - DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); - - /* Find out if this group can match the empty string. */ - p1 = p; /* To send to group_match_null_string_p. */ - - if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[*p]) - = group_match_null_string_p (&p1, pend, reg_info); - - /* Save the position in the string where we were the last time - we were at this open-group operator in case the group is - operated upon by a repetition operator, e.g., with `(a*)*b' - against `ab'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regstart[*p]) ? d : regstart[*p] - : regstart[*p]; - DEBUG_PRINT2 (" old_regstart: %d\n", - POINTER_TO_OFFSET (old_regstart[*p])); - - regstart[*p] = d; - DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); - - IS_ACTIVE (reg_info[*p]) = 1; - MATCHED_SOMETHING (reg_info[*p]) = 0; - - /* This is the new highest active register. */ - highest_active_reg = *p; - - /* If nothing was active before, this is the new lowest active - register. */ - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *p; - - /* Move past the register number and inner group count. */ - p += 2; - break; - - - /* The stop_memory opcode represents the end of a group. Its - arguments are the same as start_memory's: the register - number, and the number of inner groups. */ - case stop_memory: - DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); - - /* We need to save the string position the last time we were at - this close-group operator in case the group is operated - upon by a repetition operator, e.g., with `((a*)*(b*)*)*' - against `aba'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regend[*p]) ? d : regend[*p] - : regend[*p]; - DEBUG_PRINT2 (" old_regend: %d\n", - POINTER_TO_OFFSET (old_regend[*p])); - - regend[*p] = d; - DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); - - /* This register isn't active anymore. */ - IS_ACTIVE (reg_info[*p]) = 0; - - /* If this was the only register active, nothing is active - anymore. */ - if (lowest_active_reg == highest_active_reg) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - { /* We must scan for the new highest active register, since - it isn't necessarily one less than now: consider - (a(b)c(d(e)f)g). When group 3 ends, after the f), the - new highest active register is 1. */ - unsigned char r = *p - 1; - while (r > 0 && !IS_ACTIVE (reg_info[r])) - r--; - - /* If we end up at register zero, that means that we saved - the registers as the result of an `on_failure_jump', not - a `start_memory', and we jumped to past the innermost - `stop_memory'. For example, in ((.)*) we save - registers 1 and 2 as a result of the *, but when we pop - back to the second ), we are at the stop_memory 1. - Thus, nothing is active. */ - if (r == 0) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - highest_active_reg = r; - } - - /* If just failed to match something this time around with a - group that's operated on by a repetition operator, try to - force exit from the ``loop'', and restore the register - information for this group that we had before trying this - last match. */ - if ((!MATCHED_SOMETHING (reg_info[*p]) - || (re_opcode_t) p[-3] == start_memory) - && (p + 2) < pend) - { - boolean is_a_jump_n = false; - - p1 = p + 2; - mcnt = 0; - switch ((re_opcode_t) *p1++) - { - case jump_n: - is_a_jump_n = true; - case pop_failure_jump: - case maybe_pop_jump: - case jump: - case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if (is_a_jump_n) - p1 += 2; - break; - - default: - /* do nothing */ ; - } - p1 += mcnt; - - /* If the next operation is a jump backwards in the pattern - to an on_failure_jump right before the start_memory - corresponding to this stop_memory, exit from the loop - by forcing a failure after pushing on the stack the - on_failure_jump's jump in the pattern, and d. */ - if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump - && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) - { - /* If this group ever matched anything, then restore - what its registers were before trying this last - failed match, e.g., with `(a*)*b' against `ab' for - regstart[1], and, e.g., with `((a*)*(b*)*)*' - against `aba' for regend[3]. - - Also restore the registers for inner groups for, - e.g., `((a*)(b*))*' against `aba' (register 3 would - otherwise get trashed). */ - - if (EVER_MATCHED_SOMETHING (reg_info[*p])) - { - unsigned r; - - EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; - - /* Restore this and inner groups' (if any) registers. */ - for (r = *p; r < *p + *(p + 1); r++) - { - regstart[r] = old_regstart[r]; - - /* xx why this test? */ - if ((int) old_regend[r] >= (int) regstart[r]) - regend[r] = old_regend[r]; - } - } - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - PUSH_FAILURE_POINT (p1 + mcnt, d, -2); - - goto fail; - } - } - - /* Move past the register number and the inner group count. */ - p += 2; - break; - - - /* \<digit> has been turned into a `duplicate' command which is - followed by the numeric value of <digit> as the register number. */ - case duplicate: - { - register const char *d2, *dend2; - int regno = *p++; /* Get which register to match against. */ - DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); - - /* Can't back reference a group which we've never matched. */ - if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) - goto fail; - - /* Where in input to try to start matching. */ - d2 = regstart[regno]; - - /* Where to stop matching; if both the place to start and - the place to stop matching are in the same string, then - set to the place to stop, otherwise, for now have to use - the end of the first string. */ - - dend2 = ((FIRST_STRING_P (regstart[regno]) - == FIRST_STRING_P (regend[regno])) - ? regend[regno] : end_match_1); - for (;;) - { - /* If necessary, advance to next segment in register - contents. */ - while (d2 == dend2) - { - if (dend2 == end_match_2) break; - if (dend2 == regend[regno]) break; - - /* End of string1 => advance to string2. */ - d2 = string2; - dend2 = regend[regno]; - } - /* At end of register contents => success */ - if (d2 == dend2) break; - - /* If necessary, advance to next segment in data. */ - PREFETCH (); - - /* How many characters left in this segment to match. */ - mcnt = dend - d; - - /* Want how many consecutive characters we can match in - one shot, so, if necessary, adjust the count. */ - if (mcnt > dend2 - d2) - mcnt = dend2 - d2; - - /* Compare that many; failure if mismatch, else move - past them. */ - if (translate - ? bcmp_translate (d, d2, mcnt, translate) - : bcmp (d, d2, mcnt)) - goto fail; - d += mcnt, d2 += mcnt; - } - } - break; - - - /* begline matches the empty string at the beginning of the string - (unless `not_bol' is set in `bufp'), and, if - `newline_anchor' is set, after newlines. */ - case begline: - DEBUG_PRINT1 ("EXECUTING begline.\n"); - - if (AT_STRINGS_BEG (d)) - { - if (!bufp->not_bol) break; - } - else if (d[-1] == '\n' && bufp->newline_anchor) - { - break; - } - /* In all other cases, we fail. */ - goto fail; - - - /* endline is the dual of begline. */ - case endline: - DEBUG_PRINT1 ("EXECUTING endline.\n"); - - if (AT_STRINGS_END (d)) - { - if (!bufp->not_eol) break; - } - - /* We have to ``prefetch'' the next character. */ - else if ((d == end1 ? *string2 : *d) == '\n' - && bufp->newline_anchor) - { - break; - } - goto fail; - - - /* Match at the very beginning of the data. */ - case begbuf: - DEBUG_PRINT1 ("EXECUTING begbuf.\n"); - if (AT_STRINGS_BEG (d)) - break; - goto fail; - - - /* Match at the very end of the data. */ - case endbuf: - DEBUG_PRINT1 ("EXECUTING endbuf.\n"); - if (AT_STRINGS_END (d)) - break; - goto fail; - - - /* on_failure_keep_string_jump is used to optimize `.*\n'. It - pushes NULL as the value for the string on the stack. Then - `pop_failure_point' will keep the current value for the - string, instead of restoring it. To see why, consider - matching `foo\nbar' against `.*\n'. The .* matches the foo; - then the . fails against the \n. But the next thing we want - to do is match the \n against the \n; if we restored the - string value, we would be back at the foo. - - Because this is used only in specific cases, we don't need to - check all the things that `on_failure_jump' does, to make - sure the right things get saved on the stack. Hence we don't - share its code. The only reason to push anything on the - stack at all is that otherwise we would have to change - `anychar's code to do something besides goto fail in this - case; that seems worse than this. */ - case on_failure_keep_string_jump: - DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); - - PUSH_FAILURE_POINT (p + mcnt, NULL, -2); - break; - - - /* Uses of on_failure_jump: - - Each alternative starts with an on_failure_jump that points - to the beginning of the next alternative. Each alternative - except the last ends with a jump that in effect jumps past - the rest of the alternatives. (They really jump to the - ending jump of the following alternative, because tensioning - these jumps is a hassle.) - - Repeats start with an on_failure_jump that points past both - the repetition text and either the following jump or - pop_failure_jump back to this on_failure_jump. */ - case on_failure_jump: - on_failure: - DEBUG_PRINT1 ("EXECUTING on_failure_jump"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); - - /* If this on_failure_jump comes right before a group (i.e., - the original * applied to a group), save the information - for that group and all inner ones, so that if we fail back - to this point, the group's information will be correct. - For example, in \(a*\)*\1, we need the preceding group, - and in \(\(a*\)b*\)\2, we need the inner group. */ - - /* We can't use `p' to check ahead because we push - a failure point to `p + mcnt' after we do this. */ - p1 = p; - - /* We need to skip no_op's before we look for the - start_memory in case this on_failure_jump is happening as - the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 - against aba. */ - while (p1 < pend && (re_opcode_t) *p1 == no_op) - p1++; - - if (p1 < pend && (re_opcode_t) *p1 == start_memory) - { - /* We have a new highest active register now. This will - get reset at the start_memory we are about to get to, - but we will have saved all the registers relevant to - this repetition op, as described above. */ - highest_active_reg = *(p1 + 1) + *(p1 + 2); - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *(p1 + 1); - } - - DEBUG_PRINT1 (":\n"); - PUSH_FAILURE_POINT (p + mcnt, d, -2); - break; - - - /* A smart repeat ends with `maybe_pop_jump'. - We change it to either `pop_failure_jump' or `jump'. */ - case maybe_pop_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); - { - register unsigned char *p2 = p; - - /* Compare the beginning of the repeat with what in the - pattern follows its end. If we can establish that there - is nothing that they would both match, i.e., that we - would have to backtrack because of (as in, e.g., `a*a') - then we can change to pop_failure_jump, because we'll - never have to backtrack. - - This is not true in the case of alternatives: in - `(a|ab)*' we do need to backtrack to the `ab' alternative - (e.g., if the string was `ab'). But instead of trying to - detect that here, the alternative has put on a dummy - failure point which is what we will end up popping. */ - - /* Skip over open/close-group commands. */ - while (p2 + 2 < pend - && ((re_opcode_t) *p2 == stop_memory - || (re_opcode_t) *p2 == start_memory)) - p2 += 3; /* Skip over args, too. */ - - /* If we're at the end of the pattern, we can change. */ - if (p2 == pend) - { - /* Consider what happens when matching ":\(.*\)" - against ":/". I don't really understand this code - yet. */ - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 - (" End of pattern: change to `pop_failure_jump'.\n"); - } - - else if ((re_opcode_t) *p2 == exactn - || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) - { - register unsigned char c - = *p2 == (unsigned char) endline ? '\n' : p2[2]; - p1 = p + mcnt; - - /* p1[0] ... p1[2] are the `on_failure_jump' corresponding - to the `maybe_finalize_jump' of this case. Examine what - follows. */ - if ((re_opcode_t) p1[3] == exactn && p1[5] != c) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", - c, p1[5]); - } - - else if ((re_opcode_t) p1[3] == charset - || (re_opcode_t) p1[3] == charset_not) - { - int not = (re_opcode_t) p1[3] == charset_not; - - if (c < (unsigned char) (p1[4] * BYTEWIDTH) - && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) - not = !not; - - /* `not' is equal to 1 if c would match, which means - that we can't change to pop_failure_jump. */ - if (!not) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); - } - } - } - } - p -= 2; /* Point at relative address again. */ - if ((re_opcode_t) p[-1] != pop_failure_jump) - { - p[-1] = (unsigned char) jump; - DEBUG_PRINT1 (" Match => jump.\n"); - goto unconditional_jump; - } - /* Note fall through. */ - - - /* The end of a simple repeat has a pop_failure_jump back to - its matching on_failure_jump, where the latter will push a - failure point. The pop_failure_jump takes off failure - points put on by this pop_failure_jump's matching - on_failure_jump; we got through the pattern to here from the - matching on_failure_jump, so didn't fail. */ - case pop_failure_jump: - { - /* We need to pass separate storage for the lowest and - highest registers, even though we don't care about the - actual values. Otherwise, we will restore only one - register from the stack, since lowest will == highest in - `pop_failure_point'. */ - unsigned dummy_low_reg, dummy_high_reg; - unsigned char *pdummy; - const char *sdummy; - - DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); - POP_FAILURE_POINT (sdummy, pdummy, - dummy_low_reg, dummy_high_reg, - reg_dummy, reg_dummy, reg_info_dummy); - } - /* Note fall through. */ - - - /* Unconditionally jump (without popping any failure points). */ - case jump: - unconditional_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ - DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); - p += mcnt; /* Do the jump. */ - DEBUG_PRINT2 ("(to 0x%x).\n", p); - break; - - - /* We need this opcode so we can detect where alternatives end - in `group_match_null_string_p' et al. */ - case jump_past_alt: - DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); - goto unconditional_jump; - - - /* Normally, the on_failure_jump pushes a failure point, which - then gets popped at pop_failure_jump. We will end up at - pop_failure_jump, also, and with a pattern of, say, `a+', we - are skipping over the on_failure_jump, so we have to push - something meaningless for pop_failure_jump to pop. */ - case dummy_failure_jump: - DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); - /* It doesn't matter what we push for the string here. What - the code at `fail' tests is the value for the pattern. */ - PUSH_FAILURE_POINT (0, 0, -2); - goto unconditional_jump; - - - /* At the end of an alternative, we need to push a dummy failure - point in case we are followed by a `pop_failure_jump', because - we don't want the failure point for the alternative to be - popped. For example, matching `(a|ab)*' against `aab' - requires that we match the `ab' alternative. */ - case push_dummy_failure: - DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); - /* See comments just above at `dummy_failure_jump' about the - two zeroes. */ - PUSH_FAILURE_POINT (0, 0, -2); - break; - - /* Have to succeed matching what follows at least n times. - After that, handle like `on_failure_jump'. */ - case succeed_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); - - assert (mcnt >= 0); - /* Originally, this is how many times we HAVE to succeed. */ - if (mcnt > 0) - { - mcnt--; - p += 2; - STORE_NUMBER_AND_INCR (p, mcnt); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); - } - else if (mcnt == 0) - { - DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); - p[2] = (unsigned char) no_op; - p[3] = (unsigned char) no_op; - goto on_failure; - } - break; - - case jump_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); - - /* Originally, this is how many times we CAN jump. */ - if (mcnt) - { - mcnt--; - STORE_NUMBER (p + 2, mcnt); - goto unconditional_jump; - } - /* If don't have to jump any more, skip over the rest of command. */ - else - p += 4; - break; - - case set_number_at: - { - DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - p1 = p + mcnt; - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); - STORE_NUMBER (p1, mcnt); - break; - } - - case wordbound: - DEBUG_PRINT1 ("EXECUTING wordbound.\n"); - if (AT_WORD_BOUNDARY (d)) - break; - goto fail; - - case notwordbound: - DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); - if (AT_WORD_BOUNDARY (d)) - goto fail; - break; - - case wordbeg: - DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); - if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) - break; - goto fail; - - case wordend: - DEBUG_PRINT1 ("EXECUTING wordend.\n"); - if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) - && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) - break; - goto fail; - -#ifdef emacs -#ifdef emacs19 - case before_dot: - DEBUG_PRINT1 ("EXECUTING before_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) >= point) - goto fail; - break; - - case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) != point) - goto fail; - break; - - case after_dot: - DEBUG_PRINT1 ("EXECUTING after_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) <= point) - goto fail; - break; -#else /* not emacs19 */ - case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) - goto fail; - break; -#endif /* not emacs19 */ - - case syntaxspec: - DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); - mcnt = *p++; - goto matchsyntax; - - case wordchar: - DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); - mcnt = (int) Sword; - matchsyntax: - PREFETCH (); - if (SYNTAX (*d++) != (enum syntaxcode) mcnt) - goto fail; - SET_REGS_MATCHED (); - break; - - case notsyntaxspec: - DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); - mcnt = *p++; - goto matchnotsyntax; - - case notwordchar: - DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); - mcnt = (int) Sword; - matchnotsyntax: - PREFETCH (); - if (SYNTAX (*d++) == (enum syntaxcode) mcnt) - goto fail; - SET_REGS_MATCHED (); - break; - -#else /* not emacs */ - case wordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); - PREFETCH (); - if (!WORDCHAR_P (d)) - goto fail; - SET_REGS_MATCHED (); - d++; - break; - - case notwordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); - PREFETCH (); - if (WORDCHAR_P (d)) - goto fail; - SET_REGS_MATCHED (); - d++; - break; -#endif /* not emacs */ - - default: - abort (); - } - continue; /* Successfully executed one pattern command; keep going. */ - - - /* We goto here if a matching operation fails. */ - fail: - if (!FAIL_STACK_EMPTY ()) - { /* A restart point is known. Restore to that state. */ - DEBUG_PRINT1 ("\nFAIL:\n"); - POP_FAILURE_POINT (d, p, - lowest_active_reg, highest_active_reg, - regstart, regend, reg_info); - - /* If this failure point is a dummy, try the next one. */ - if (!p) - goto fail; - - /* If we failed to the end of the pattern, don't examine *p. */ - assert (p <= pend); - if (p < pend) - { - boolean is_a_jump_n = false; - - /* If failed to a backwards jump that's part of a repetition - loop, need to pop this failure point and use the next one. */ - switch ((re_opcode_t) *p) - { - case jump_n: - is_a_jump_n = true; - case maybe_pop_jump: - case pop_failure_jump: - case jump: - p1 = p + 1; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - - if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) - || (!is_a_jump_n - && (re_opcode_t) *p1 == on_failure_jump)) - goto fail; - break; - default: - /* do nothing */ ; - } - } - - if (d >= string1 && d <= end1) - dend = end_match_1; - } - else - break; /* Matching at this starting point really fails. */ - } /* for (;;) */ - - if (best_regs_set) - goto restore_best_regs; - - FREE_VARIABLES (); - - return -1; /* Failure to match. */ -} /* re_match_2 */ - -/* Subroutine definitions for re_match_2. */ - - -/* We are passed P pointing to a register number after a start_memory. - - Return true if the pattern up to the corresponding stop_memory can - match the empty string, and false otherwise. - - If we find the matching stop_memory, sets P to point to one past its number. - Otherwise, sets P to an undefined byte less than or equal to END. - - We don't handle duplicates properly (yet). */ - -static boolean -group_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; -{ - int mcnt; - /* Point to after the args to the start_memory. */ - unsigned char *p1 = *p + 2; - - while (p1 < end) - { - /* Skip over opcodes that can match nothing, and return true or - false, as appropriate, when we get to one that can't, or to the - matching stop_memory. */ - - switch ((re_opcode_t) *p1) - { - /* Could be either a loop or a series of alternatives. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - - /* If the next operation is not a jump backwards in the - pattern. */ - - if (mcnt >= 0) - { - /* Go through the on_failure_jumps of the alternatives, - seeing if any of the alternatives cannot match nothing. - The last alternative starts with only a jump, - whereas the rest start with on_failure_jump and end - with a jump, e.g., here is the pattern for `a|b|c': - - /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 - /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 - /exactn/1/c - - So, we have to first go through the first (n-1) - alternatives and then deal with the last one separately. */ - - - /* Deal with the first (n-1) alternatives, which start - with an on_failure_jump (see above) that jumps to right - past a jump_past_alt. */ - - while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) - { - /* `mcnt' holds how many bytes long the alternative - is, including the ending `jump_past_alt' and - its number. */ - - if (!alt_match_null_string_p (p1, p1 + mcnt - 3, - reg_info)) - return false; - - /* Move to right after this alternative, including the - jump_past_alt. */ - p1 += mcnt; - - /* Break if it's the beginning of an n-th alternative - that doesn't begin with an on_failure_jump. */ - if ((re_opcode_t) *p1 != on_failure_jump) - break; - - /* Still have to check that it's not an n-th - alternative that starts with an on_failure_jump. */ - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) - { - /* Get to the beginning of the n-th alternative. */ - p1 -= 3; - break; - } - } - - /* Deal with the last alternative: go back and get number - of the `jump_past_alt' just before it. `mcnt' contains - the length of the alternative. */ - EXTRACT_NUMBER (mcnt, p1 - 2); - - if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) - return false; - - p1 += mcnt; /* Get past the n-th alternative. */ - } /* if mcnt > 0 */ - break; - - - case stop_memory: - assert (p1[1] == **p); - *p = p1 + 2; - return true; - - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } - } /* while p1 < end */ - - return false; -} /* group_match_null_string_p */ - - -/* Similar to group_match_null_string_p, but doesn't deal with alternatives: - It expects P to be the first byte of a single alternative and END one - byte past the last. The alternative can contain groups. */ - -static boolean -alt_match_null_string_p (p, end, reg_info) - unsigned char *p, *end; - register_info_type *reg_info; -{ - int mcnt; - unsigned char *p1 = p; - - while (p1 < end) - { - /* Skip over opcodes that can match nothing, and break when we get - to one that can't. */ - - switch ((re_opcode_t) *p1) - { - /* It's a loop. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - break; - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } - } /* while p1 < end */ - - return true; -} /* alt_match_null_string_p */ - - -/* Deals with the ops common to group_match_null_string_p and - alt_match_null_string_p. - - Sets P to one after the op and its arguments, if any. */ - -static boolean -common_op_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; -{ - int mcnt; - boolean ret; - int reg_no; - unsigned char *p1 = *p; - - switch ((re_opcode_t) *p1++) - { - case no_op: - case begline: - case endline: - case begbuf: - case endbuf: - case wordbeg: - case wordend: - case wordbound: - case notwordbound: -#ifdef emacs - case before_dot: - case at_dot: - case after_dot: -#endif - break; - - case start_memory: - reg_no = *p1; - assert (reg_no > 0 && reg_no <= MAX_REGNUM); - ret = group_match_null_string_p (&p1, end, reg_info); - - /* Have to set this here in case we're checking a group which - contains a group and a back reference to it. */ - - if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; - - if (!ret) - return false; - break; - - /* If this is an optimized succeed_n for zero times, make the jump. */ - case jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if (mcnt >= 0) - p1 += mcnt; - else - return false; - break; - - case succeed_n: - /* Get to the number of times to succeed. */ - p1 += 2; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - - if (mcnt == 0) - { - p1 -= 4; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - } - else - return false; - break; - - case duplicate: - if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) - return false; - break; - - case set_number_at: - p1 += 4; - - default: - /* All other opcodes mean we cannot match the empty string. */ - return false; - } - - *p = p1; - return true; -} /* common_op_match_null_string_p */ - - -/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN - bytes; nonzero otherwise. */ - -static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; -{ - register unsigned char *p1 = s1, *p2 = s2; - while (len) - { - if (translate[*p1++] != translate[*p2++]) return 1; - len--; - } - return 0; -} - -/* Entry points for GNU code. */ - -/* re_compile_pattern is the GNU regular expression compiler: it - compiles PATTERN (of length SIZE) and puts the result in BUFP. - Returns 0 if the pattern was valid, otherwise an error string. - - Assumes the `allocated' (and perhaps `buffer') and `translate' fields - are set in BUFP on entry. - - We call regex_compile to do the actual compilation. */ - -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - int length; - struct re_pattern_buffer *bufp; -{ - reg_errcode_t ret; - - /* GNU code is written to assume at least RE_NREGS registers will be set - (and at least one extra will be -1). */ - bufp->regs_allocated = REGS_UNALLOCATED; - - /* And GNU code determines whether or not to get register information - by passing null for the REGS argument to re_match, etc., not by - setting no_sub. */ - bufp->no_sub = 0; - - /* Match anchors at newline. */ - bufp->newline_anchor = 1; - - ret = regex_compile (pattern, length, re_syntax_options, bufp); - - return re_error_msg[(int) ret]; -} - -/* Entry points compatible with 4.2 BSD regex library. We don't define - them if this is an Emacs or POSIX compilation. */ - -#if !defined (emacs) && !defined (_POSIX_SOURCE) - -/* BSD has one and only one pattern buffer. */ -static struct re_pattern_buffer re_comp_buf; - -char * -re_comp (s) - const char *s; -{ - reg_errcode_t ret; - - if (!s) - { - if (!re_comp_buf.buffer) - return "No previous regular expression"; - return 0; - } - - if (!re_comp_buf.buffer) - { - re_comp_buf.buffer = (unsigned char *) malloc (200); - if (re_comp_buf.buffer == NULL) - return "Memory exhausted"; - re_comp_buf.allocated = 200; - - re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); - if (re_comp_buf.fastmap == NULL) - return "Memory exhausted"; - } - - /* Since `re_exec' always passes NULL for the `regs' argument, we - don't need to initialize the pattern buffer fields which affect it. */ - - /* Match anchors at newlines. */ - re_comp_buf.newline_anchor = 1; - - ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); - - /* Yes, we're discarding `const' here. */ - return (char *) re_error_msg[(int) ret]; -} - - -int -re_exec (s) - const char *s; -{ - const int len = strlen (s); - return - 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); -} -#endif /* not emacs and not _POSIX_SOURCE */ - -/* POSIX.2 functions. Don't define these for Emacs. */ - -#ifndef emacs - -/* regcomp takes a regular expression as a string and compiles it. - - PREG is a regex_t *. We do not expect any fields to be initialized, - since POSIX says we shouldn't. Thus, we set - - `buffer' to the compiled pattern; - `used' to the length of the compiled pattern; - `syntax' to RE_SYNTAX_POSIX_EXTENDED if the - REG_EXTENDED bit in CFLAGS is set; otherwise, to - RE_SYNTAX_POSIX_BASIC; - `newline_anchor' to REG_NEWLINE being set in CFLAGS; - `fastmap' and `fastmap_accurate' to zero; - `re_nsub' to the number of subexpressions in PATTERN. - - PATTERN is the address of the pattern string. - - CFLAGS is a series of bits which affect compilation. - - If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we - use POSIX basic syntax. - - If REG_NEWLINE is set, then . and [^...] don't match newline. - Also, regexec will try a match beginning after every newline. - - If REG_ICASE is set, then we considers upper- and lowercase - versions of letters to be equivalent when matching. - - If REG_NOSUB is set, then when PREG is passed to regexec, that - routine will report only success or failure, and nothing about the - registers. - - It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for - the return codes and their meanings.) */ - -int -regcomp (preg, pattern, cflags) - regex_t *preg; - const char *pattern; - int cflags; -{ - reg_errcode_t ret; - unsigned syntax - = (cflags & REG_EXTENDED) ? - RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; - - /* regex_compile will allocate the space for the compiled pattern. */ - preg->buffer = 0; - preg->allocated = 0; - - /* Don't bother to use a fastmap when searching. This simplifies the - REG_NEWLINE case: if we used a fastmap, we'd have to put all the - characters after newlines into the fastmap. This way, we just try - every character. */ - preg->fastmap = 0; - - if (cflags & REG_ICASE) - { - unsigned i; - - preg->translate = (char *) malloc (CHAR_SET_SIZE); - if (preg->translate == NULL) - return (int) REG_ESPACE; - - /* Map uppercase characters to corresponding lowercase ones. */ - for (i = 0; i < CHAR_SET_SIZE; i++) - preg->translate[i] = ISUPPER (i) ? tolower (i) : i; - } - else - preg->translate = NULL; - - /* If REG_NEWLINE is set, newlines are treated differently. */ - if (cflags & REG_NEWLINE) - { /* REG_NEWLINE implies neither . nor [^...] match newline. */ - syntax &= ~RE_DOT_NEWLINE; - syntax |= RE_HAT_LISTS_NOT_NEWLINE; - /* It also changes the matching behavior. */ - preg->newline_anchor = 1; - } - else - preg->newline_anchor = 0; - - preg->no_sub = !!(cflags & REG_NOSUB); - - /* POSIX says a null character in the pattern terminates it, so we - can use strlen here in compiling the pattern. */ - ret = regex_compile (pattern, strlen (pattern), syntax, preg); - - /* POSIX doesn't distinguish between an unmatched open-group and an - unmatched close-group: both are REG_EPAREN. */ - if (ret == REG_ERPAREN) ret = REG_EPAREN; - - return (int) ret; -} - - -/* regexec searches for a given pattern, specified by PREG, in the - string STRING. - - If NMATCH is zero or REG_NOSUB was set in the cflags argument to - `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at - least NMATCH elements, and we set them to the offsets of the - corresponding matched substrings. - - EFLAGS specifies `execution flags' which affect matching: if - REG_NOTBOL is set, then ^ does not match at the beginning of the - string; if REG_NOTEOL is set, then $ does not match at the end. - - We return 0 if we find a match and REG_NOMATCH if not. */ - -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; -{ - int ret; - struct re_registers regs; - regex_t private_preg; - int len = strlen (string); - boolean want_reg_info = !preg->no_sub && nmatch > 0; - - private_preg = *preg; - - private_preg.not_bol = !!(eflags & REG_NOTBOL); - private_preg.not_eol = !!(eflags & REG_NOTEOL); - - /* The user has told us exactly how many registers to return - information about, via `nmatch'. We have to pass that on to the - matching routines. */ - private_preg.regs_allocated = REGS_FIXED; - - if (want_reg_info) - { - regs.num_regs = nmatch; - regs.start = TALLOC (nmatch, regoff_t); - regs.end = TALLOC (nmatch, regoff_t); - if (regs.start == NULL || regs.end == NULL) - return (int) REG_NOMATCH; - } - - /* Perform the searching operation. */ - ret = re_search (&private_preg, string, len, - /* start: */ 0, /* range: */ len, - want_reg_info ? ®s : (struct re_registers *) 0); - - /* Copy the register information to the POSIX structure. */ - if (want_reg_info) - { - if (ret >= 0) - { - unsigned r; - - for (r = 0; r < nmatch; r++) - { - pmatch[r].rm_so = regs.start[r]; - pmatch[r].rm_eo = regs.end[r]; - } - } - - /* If we needed the temporary register info, free the space now. */ - free (regs.start); - free (regs.end); - } - - /* We want zero return to mean success, unlike `re_search'. */ - return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; -} - - -/* Returns a message corresponding to an error code, ERRCODE, returned - from either regcomp or regexec. We don't use PREG here. */ - -size_t -regerror (errcode, preg, errbuf, errbuf_size) - int errcode; - const regex_t *preg; - char *errbuf; - size_t errbuf_size; -{ - const char *msg; - size_t msg_size; - - if (errcode < 0 - || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) - /* Only error codes returned by the rest of the code should be passed - to this routine. If we are given anything else, or if other regex - code generates an invalid error code, then the program has a bug. - Dump core so we can fix it. */ - abort (); - - msg = re_error_msg[errcode]; - - /* POSIX doesn't require that we do anything in this case, but why - not be nice. */ - if (! msg) - msg = "Success"; - - msg_size = strlen (msg) + 1; /* Includes the null. */ - - if (errbuf_size != 0) - { - if (msg_size > errbuf_size) - { - strncpy (errbuf, msg, errbuf_size - 1); - errbuf[errbuf_size - 1] = 0; - } - else - strcpy (errbuf, msg); - } - - return msg_size; -} - - -/* Free dynamically allocated space used by PREG. */ - -void -regfree (preg) - regex_t *preg; -{ - if (preg->buffer != NULL) - free (preg->buffer); - preg->buffer = NULL; - - preg->allocated = 0; - preg->used = 0; - - if (preg->fastmap != NULL) - free (preg->fastmap); - preg->fastmap = NULL; - preg->fastmap_accurate = 0; - - if (preg->translate != NULL) - free (preg->translate); - preg->translate = NULL; -} - -#endif /* not emacs */ - -/* -Local variables: -make-backup-files: t -version-control: t -trim-versions-without-asking: nil -End: -*/ diff --git a/lib/regex.h b/lib/regex.h deleted file mode 100644 index 408dd210348f0fdbea5b19115130107daf496f19..0000000000000000000000000000000000000000 --- a/lib/regex.h +++ /dev/null @@ -1,490 +0,0 @@ -/* Definitions for data structures and routines for the regular - expression library, version 0.12. - - Copyright (C) 1985, 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef __REGEXP_LIBRARY_H__ -#define __REGEXP_LIBRARY_H__ - -/* POSIX says that <sys/types.h> must be included (by the caller) before - <regex.h>. */ - -#ifdef VMS -/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it - should be there. */ -#include <stddef.h> -#endif - - -/* The following bits are used to determine the regexp syntax we - recognize. The set/not-set meanings are chosen so that Emacs syntax - remains the value 0. The bits are given in alphabetical order, and - the definitions shifted by one from the previous bit; thus, when we - add or remove a bit, only one other definition need change. */ -typedef unsigned reg_syntax_t; - -/* If this bit is not set, then \ inside a bracket expression is literal. - If set, then such a \ quotes the following character. */ -#define RE_BACKSLASH_ESCAPE_IN_LISTS (1) - -/* If this bit is not set, then + and ? are operators, and \+ and \? are - literals. - If set, then \+ and \? are operators and + and ? are literals. */ -#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) - -/* If this bit is set, then character classes are supported. They are: - [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], - [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. - If not set, then character classes are not supported. */ -#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) - -/* If this bit is set, then ^ and $ are always anchors (outside bracket - expressions, of course). - If this bit is not set, then it depends: - ^ is an anchor if it is at the beginning of a regular - expression or after an open-group or an alternation operator; - $ is an anchor if it is at the end of a regular expression, or - before a close-group or an alternation operator. - - This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because - POSIX draft 11.2 says that * etc. in leading positions is undefined. - We already implemented a previous draft which made those constructs - invalid, though, so we haven't changed the code back. */ -#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) - -/* If this bit is set, then special characters are always special - regardless of where they are in the pattern. - If this bit is not set, then special characters are special only in - some contexts; otherwise they are ordinary. Specifically, - * + ? and intervals are only special when not after the beginning, - open-group, or alternation operator. */ -#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) - -/* If this bit is set, then *, +, ?, and { cannot be first in an re or - immediately after an alternation or begin-group operator. */ -#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) - -/* If this bit is set, then . matches newline. - If not set, then it doesn't. */ -#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) - -/* If this bit is set, then . doesn't match NUL. - If not set, then it does. */ -#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) - -/* If this bit is set, nonmatching lists [^...] do not match newline. - If not set, they do. */ -#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) - -/* If this bit is set, either \{...\} or {...} defines an - interval, depending on RE_NO_BK_BRACES. - If not set, \{, \}, {, and } are literals. */ -#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) - -/* If this bit is set, +, ? and | aren't recognized as operators. - If not set, they are. */ -#define RE_LIMITED_OPS (RE_INTERVALS << 1) - -/* If this bit is set, newline is an alternation operator. - If not set, newline is literal. */ -#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) - -/* If this bit is set, then `{...}' defines an interval, and \{ and \} - are literals. - If not set, then `\{...\}' defines an interval. */ -#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) - -/* If this bit is set, (...) defines a group, and \( and \) are literals. - If not set, \(...\) defines a group, and ( and ) are literals. */ -#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) - -/* If this bit is set, then \<digit> matches <digit>. - If not set, then \<digit> is a back-reference. */ -#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) - -/* If this bit is set, then | is an alternation operator, and \| is literal. - If not set, then \| is an alternation operator, and | is literal. */ -#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) - -/* If this bit is set, then an ending range point collating higher - than the starting range point, as in [z-a], is invalid. - If not set, then when ending range point collates higher than the - starting range point, the range is ignored. */ -#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) - -/* If this bit is set, then an unmatched ) is ordinary. - If not set, then an unmatched ) is invalid. */ -#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) - -/* This global variable defines the particular regexp syntax to use (for - some interfaces). When a regexp is compiled, the syntax used is - stored in the pattern buffer, so changing this does not affect - already-compiled regexps. */ -extern reg_syntax_t re_syntax_options; - -/* Define combinations of the above bits for the standard possibilities. - (The [[[ comments delimit what gets put into the Texinfo file, so - don't delete them!) */ -/* [[[begin syntaxes]]] */ -#define RE_SYNTAX_EMACS 0 - -#define RE_SYNTAX_AWK \ - (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ - | RE_NO_BK_PARENS | RE_NO_BK_REFS \ - | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ - | RE_UNMATCHED_RIGHT_PAREN_ORD) - -#define RE_SYNTAX_POSIX_AWK \ - (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) - -#define RE_SYNTAX_GREP \ - (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ - | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ - | RE_NEWLINE_ALT) - -#define RE_SYNTAX_EGREP \ - (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ - | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ - | RE_NO_BK_VBAR) - -#define RE_SYNTAX_POSIX_EGREP \ - (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) - -/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ -#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC - -#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC - -/* Syntax bits common to both basic and extended POSIX regex syntax. */ -#define _RE_SYNTAX_POSIX_COMMON \ - (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ - | RE_INTERVALS | RE_NO_EMPTY_RANGES) - -#define RE_SYNTAX_POSIX_BASIC \ - (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) - -/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes - RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this - isn't minimal, since other operators, such as \`, aren't disabled. */ -#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ - (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) - -#define RE_SYNTAX_POSIX_EXTENDED \ - (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ - | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ - | RE_UNMATCHED_RIGHT_PAREN_ORD) - -/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS - replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ -#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ - (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ - | RE_NO_BK_PARENS | RE_NO_BK_REFS \ - | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) -/* [[[end syntaxes]]] */ - -/* Maximum number of duplicates an interval can allow. Some systems - (erroneously) define this in other header files, but we want our - value, so remove any previous define. */ -#ifdef RE_DUP_MAX -#undef RE_DUP_MAX -#endif -#define RE_DUP_MAX ((1 << 15) - 1) - - -/* POSIX `cflags' bits (i.e., information for `regcomp'). */ - -/* If this bit is set, then use extended regular expression syntax. - If not set, then use basic regular expression syntax. */ -#define REG_EXTENDED 1 - -/* If this bit is set, then ignore case when matching. - If not set, then case is significant. */ -#define REG_ICASE (REG_EXTENDED << 1) - -/* If this bit is set, then anchors do not match at newline - characters in the string. - If not set, then anchors do match at newlines. */ -#define REG_NEWLINE (REG_ICASE << 1) - -/* If this bit is set, then report only success or fail in regexec. - If not set, then returns differ between not matching and errors. */ -#define REG_NOSUB (REG_NEWLINE << 1) - - -/* POSIX `eflags' bits (i.e., information for regexec). */ - -/* If this bit is set, then the beginning-of-line operator doesn't match - the beginning of the string (presumably because it's not the - beginning of a line). - If not set, then the beginning-of-line operator does match the - beginning of the string. */ -#define REG_NOTBOL 1 - -/* Like REG_NOTBOL, except for the end-of-line. */ -#define REG_NOTEOL (1 << 1) - - -/* If any error codes are removed, changed, or added, update the - `re_error_msg' table in regex.c. */ -typedef enum -{ - REG_NOERROR = 0, /* Success. */ - REG_NOMATCH, /* Didn't find a match (for regexec). */ - - /* POSIX regcomp return error codes. (In the order listed in the - standard.) */ - REG_BADPAT, /* Invalid pattern. */ - REG_ECOLLATE, /* Not implemented. */ - REG_ECTYPE, /* Invalid character class name. */ - REG_EESCAPE, /* Trailing backslash. */ - REG_ESUBREG, /* Invalid back reference. */ - REG_EBRACK, /* Unmatched left bracket. */ - REG_EPAREN, /* Parenthesis imbalance. */ - REG_EBRACE, /* Unmatched \{. */ - REG_BADBR, /* Invalid contents of \{\}. */ - REG_ERANGE, /* Invalid range end. */ - REG_ESPACE, /* Ran out of memory. */ - REG_BADRPT, /* No preceding re for repetition op. */ - - /* Error codes we've added. */ - REG_EEND, /* Premature end. */ - REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ - REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ -} reg_errcode_t; - -/* This data structure represents a compiled pattern. Before calling - the pattern compiler, the fields `buffer', `allocated', `fastmap', - `translate', and `no_sub' can be set. After the pattern has been - compiled, the `re_nsub' field is available. All other fields are - private to the regex routines. */ - -struct re_pattern_buffer -{ -/* [[[begin pattern_buffer]]] */ - /* Space that holds the compiled pattern. It is declared as - `unsigned char *' because its elements are - sometimes used as array indexes. */ - unsigned char *buffer; - - /* Number of bytes to which `buffer' points. */ - unsigned long allocated; - - /* Number of bytes actually used in `buffer'. */ - unsigned long used; - - /* Syntax setting with which the pattern was compiled. */ - reg_syntax_t syntax; - - /* Pointer to a fastmap, if any, otherwise zero. re_search uses - the fastmap, if there is one, to skip over impossible - starting points for matches. */ - char *fastmap; - - /* Either a translate table to apply to all characters before - comparing them, or zero for no translation. The translation - is applied to a pattern when it is compiled and to a string - when it is matched. */ - char *translate; - - /* Number of subexpressions found by the compiler. */ - size_t re_nsub; - - /* Zero if this pattern cannot match the empty string, one else. - Well, in truth it's used only in `re_search_2', to see - whether or not we should use the fastmap, so we don't set - this absolutely perfectly; see `re_compile_fastmap' (the - `duplicate' case). */ - unsigned can_be_null : 1; - - /* If REGS_UNALLOCATED, allocate space in the `regs' structure - for `max (RE_NREGS, re_nsub + 1)' groups. - If REGS_REALLOCATE, reallocate space if necessary. - If REGS_FIXED, use what's there. */ -#define REGS_UNALLOCATED 0 -#define REGS_REALLOCATE 1 -#define REGS_FIXED 2 - unsigned regs_allocated : 2; - - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ - unsigned fastmap_accurate : 1; - - /* If set, `re_match_2' does not return information about - subexpressions. */ - unsigned no_sub : 1; - - /* If set, a beginning-of-line anchor doesn't match at the - beginning of the string. */ - unsigned not_bol : 1; - - /* Similarly for an end-of-line anchor. */ - unsigned not_eol : 1; - - /* If true, an anchor at a newline matches. */ - unsigned newline_anchor : 1; - -/* [[[end pattern_buffer]]] */ -}; - -typedef struct re_pattern_buffer regex_t; - - -/* search.c (search_buffer) in Emacs needs this one opcode value. It is - defined both in `regex.c' and here. */ -#define RE_EXACTN_VALUE 1 - -/* Type for byte offsets within the string. POSIX mandates this. */ -typedef int regoff_t; - - -/* This is the structure we store register match data in. See - regex.texinfo for a full description of what registers match. */ -struct re_registers -{ - unsigned num_regs; - regoff_t *start; - regoff_t *end; -}; - - -/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, - `re_match_2' returns information about at least this many registers - the first time a `regs' structure is passed. */ -#ifndef RE_NREGS -#define RE_NREGS 30 -#endif - - -/* POSIX specification for registers. Aside from the different names than - `re_registers', POSIX uses an array of structures, instead of a - structure of arrays. */ -typedef struct -{ - regoff_t rm_so; /* Byte offset from string's start to substring's start. */ - regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ -} regmatch_t; - -/* Declarations for routines. */ - -/* To avoid duplicating every routine declaration -- once with a - prototype (if we are ANSI), and once without (if we aren't) -- we - use the following macro to declare argument types. This - unfortunately clutters up the declarations a bit, but I think it's - worth it. */ - -#if __STDC__ - -#define _RE_ARGS(args) args - -#else /* not __STDC__ */ - -#define _RE_ARGS(args) () - -#endif /* not __STDC__ */ - -/* Sets the current default syntax to SYNTAX, and return the old syntax. - You can also simply assign to the `re_syntax_options' variable. */ -extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); - -/* Compile the regular expression PATTERN, with length LENGTH - and syntax given by the global `re_syntax_options', into the buffer - BUFFER. Return NULL if successful, and an error string if not. */ -extern const char *re_compile_pattern - _RE_ARGS ((const char *pattern, int length, - struct re_pattern_buffer *buffer)); - - -/* Compile a fastmap for the compiled pattern in BUFFER; used to - accelerate searches. Return 0 if successful and -2 if was an - internal error. */ -extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); - - -/* Search in the string STRING (with length LENGTH) for the pattern - compiled into BUFFER. Start searching at position START, for RANGE - characters. Return the starting position of the match, -1 for no - match, or -2 for an internal error. Also return register - information in REGS (if REGS and BUFFER->no_sub are nonzero). */ -extern int re_search - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, int range, struct re_registers *regs)); - - -/* Like `re_search', but search in the concatenation of STRING1 and - STRING2. Also, stop searching at index START + STOP. */ -extern int re_search_2 - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, int range, struct re_registers *regs, int stop)); - - -/* Like `re_search', but return how many characters in STRING the regexp - in BUFFER matched, starting at position START. */ -extern int re_match - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, struct re_registers *regs)); - - -/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, struct re_registers *regs, int stop)); - - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using BUFFER and REGS will use this memory - for recording register information. STARTS and ENDS must be - allocated with malloc, and must each be at least `NUM_REGS * sizeof - (regoff_t)' bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ -extern void re_set_registers - _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, - unsigned num_regs, regoff_t *starts, regoff_t *ends)); - -/* 4.2 bsd compatibility. */ -extern char *re_comp _RE_ARGS ((const char *)); -extern int re_exec _RE_ARGS ((const char *)); - -/* POSIX compatibility. */ -extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); -extern int regexec - _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, - regmatch_t pmatch[], int eflags)); -extern size_t regerror - _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, - size_t errbuf_size)); -extern void regfree _RE_ARGS ((regex_t *preg)); - -#endif /* not __REGEXP_LIBRARY_H__ */ - -/* -Local variables: -make-backup-files: t -version-control: t -trim-versions-without-asking: nil -End: -*/ diff --git a/lib/rename.c b/lib/rename.c deleted file mode 100644 index 6c43cf6f698c532b6defd7a6015ccd8911e9b3ef..0000000000000000000000000000000000000000 --- a/lib/rename.c +++ /dev/null @@ -1,72 +0,0 @@ -/* rename.c -- BSD compatible directory function for System V - Copyright (C) 1988, 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 <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#ifndef STDC_HEADERS -extern int errno; -#endif - -/* Rename file FROM to file TO. - Return 0 if successful, -1 if not. */ - -int -rename (from, to) - char *from; - char *to; -{ - struct stat from_stats; - int pid, status; - - if (stat (from, &from_stats) == 0) - { - if (unlink (to) && errno != ENOENT) - return -1; - if ((from_stats.st_mode & S_IFMT) == S_IFDIR) - { - /* Need a setuid root process to link and unlink directories. */ - pid = fork (); - switch (pid) - { - case -1: /* Error. */ - error (1, errno, "cannot fork"); - - case 0: /* Child. */ - execl (MVDIR, "mvdir", from, to, (char *) 0); - error (255, errno, "cannot run `%s'", MVDIR); - - default: /* Parent. */ - while (wait (&status) != pid) - /* Do nothing. */ ; - - errno = 0; /* mvdir printed the system error message. */ - return status != 0 ? -1 : 0; - } - } - else - { - if (link (from, to) == 0 && (unlink (from) == 0 || errno == ENOENT)) - return 0; - } - } - return -1; -} diff --git a/lib/sighandle.c b/lib/sighandle.c deleted file mode 100644 index 1db41776634975f77427186e3e2e2d2cbe305fa7..0000000000000000000000000000000000000000 --- a/lib/sighandle.c +++ /dev/null @@ -1,408 +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 <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 */ - -#ifdef _MINIX -#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */ -#endif - -/* Define the highest signal number (usually) */ -#ifndef SIGMAX -#define SIGMAX 64 -#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 -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 -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 - sigset_t sigset_test; -#endif - - if (SIG_defaults && SIG_handlers) /* already allocated */ - return (0); - -#ifdef POSIX - (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 - 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 - (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 - 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 - (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 - 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 - (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 - 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 - (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 - 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 - (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL); -#else -#ifdef BSD_SIGNALS - (void) sigsetmask(SIG_crSectMask); -#else - /* TBD */ -#endif -#endif - } - } -} diff --git a/lib/strdup.c b/lib/strdup.c deleted file mode 100644 index 46fc8a0d6dbcb614ec6edc56de7dc17f52b3723c..0000000000000000000000000000000000000000 --- a/lib/strdup.c +++ /dev/null @@ -1,43 +0,0 @@ -/* strdup.c -- return a newly allocated copy of 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 - -#ifdef STDC_HEADERS -#include <string.h> -#include <stdlib.h> -#else -char *malloc (); -char *strcpy (); -#endif - -/* Return a newly allocated copy of STR, - or 0 if out of memory. */ - -char * -strdup (str) - char *str; -{ - char *newstr; - - newstr = (char *) malloc (strlen (str) + 1); - if (newstr) - strcpy (newstr, str); - return newstr; -} diff --git a/lib/strerror.c b/lib/strerror.c deleted file mode 100644 index b0bec1317a9122f8d03675df89ed02fad935eaad..0000000000000000000000000000000000000000 --- a/lib/strerror.c +++ /dev/null @@ -1,813 +0,0 @@ -/* Extended support for using errno values. - Copyright (C) 1992 Free Software Foundation, Inc. - Written by Fred Fish. fnf@cygnus.com - -This file is part of the libiberty library. -Libiberty is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -Libiberty 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with libiberty; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#include "config.h" - -#ifndef NEED_sys_errlist -/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least) - might declare sys_errlist in a way that the compiler might consider - incompatible with our later declaration, perhaps by using const - attributes. So we hide the declaration in errno.h (if any) using a - macro. */ -#define sys_errlist sys_errlist__ -#endif - -#include <stdio.h> -#include <errno.h> - -#ifndef NEED_sys_errlist -#undef sys_errlist -#endif - -/* Routines imported from standard C runtime libraries. */ - -#ifdef __STDC__ -#include <stddef.h> -extern void *malloc (size_t size); /* 4.10.3.3 */ -extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ -#else /* !__STDC__ */ -extern char *malloc (); /* Standard memory allocater */ -extern char *memset (); -#endif /* __STDC__ */ - -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -/* Translation table for errno values. See intro(2) in most UNIX systems - Programmers Reference Manuals. - - Note that this table is generally only accessed when it is used at runtime - to initialize errno name and message tables that are indexed by errno - value. - - Not all of these errnos will exist on all systems. This table is the only - thing that should have to be updated as new error numbers are introduced. - It's sort of ugly, but at least its portable. */ - -struct error_info -{ - int value; /* The numeric value from <errno.h> */ - char *name; /* The equivalent symbolic value */ -#ifdef NEED_sys_errlist - char *msg; /* Short message about this value */ -#endif -}; - -#ifdef NEED_sys_errlist -# define ENTRY(value, name, msg) {value, name, msg} -#else -# define ENTRY(value, name, msg) {value, name} -#endif - -static const struct error_info error_table[] = -{ -#if defined (EPERM) - ENTRY(EPERM, "EPERM", "Not owner"), -#endif -#if defined (ENOENT) - ENTRY(ENOENT, "ENOENT", "No such file or directory"), -#endif -#if defined (ESRCH) - ENTRY(ESRCH, "ESRCH", "No such process"), -#endif -#if defined (EINTR) - ENTRY(EINTR, "EINTR", "Interrupted system call"), -#endif -#if defined (EIO) - ENTRY(EIO, "EIO", "I/O error"), -#endif -#if defined (ENXIO) - ENTRY(ENXIO, "ENXIO", "No such device or address"), -#endif -#if defined (E2BIG) - ENTRY(E2BIG, "E2BIG", "Arg list too long"), -#endif -#if defined (ENOEXEC) - ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"), -#endif -#if defined (EBADF) - ENTRY(EBADF, "EBADF", "Bad file number"), -#endif -#if defined (ECHILD) - ENTRY(ECHILD, "ECHILD", "No child processes"), -#endif -#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ - ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"), -#endif -#if defined (EAGAIN) - ENTRY(EAGAIN, "EAGAIN", "No more processes"), -#endif -#if defined (ENOMEM) - ENTRY(ENOMEM, "ENOMEM", "Not enough space"), -#endif -#if defined (EACCES) - ENTRY(EACCES, "EACCES", "Permission denied"), -#endif -#if defined (EFAULT) - ENTRY(EFAULT, "EFAULT", "Bad address"), -#endif -#if defined (ENOTBLK) - ENTRY(ENOTBLK, "ENOTBLK", "Block device required"), -#endif -#if defined (EBUSY) - ENTRY(EBUSY, "EBUSY", "Device busy"), -#endif -#if defined (EEXIST) - ENTRY(EEXIST, "EEXIST", "File exists"), -#endif -#if defined (EXDEV) - ENTRY(EXDEV, "EXDEV", "Cross-device link"), -#endif -#if defined (ENODEV) - ENTRY(ENODEV, "ENODEV", "No such device"), -#endif -#if defined (ENOTDIR) - ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"), -#endif -#if defined (EISDIR) - ENTRY(EISDIR, "EISDIR", "Is a directory"), -#endif -#if defined (EINVAL) - ENTRY(EINVAL, "EINVAL", "Invalid argument"), -#endif -#if defined (ENFILE) - ENTRY(ENFILE, "ENFILE", "File table overflow"), -#endif -#if defined (EMFILE) - ENTRY(EMFILE, "EMFILE", "Too many open files"), -#endif -#if defined (ENOTTY) - ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"), -#endif -#if defined (ETXTBSY) - ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"), -#endif -#if defined (EFBIG) - ENTRY(EFBIG, "EFBIG", "File too large"), -#endif -#if defined (ENOSPC) - ENTRY(ENOSPC, "ENOSPC", "No space left on device"), -#endif -#if defined (ESPIPE) - ENTRY(ESPIPE, "ESPIPE", "Illegal seek"), -#endif -#if defined (EROFS) - ENTRY(EROFS, "EROFS", "Read-only file system"), -#endif -#if defined (EMLINK) - ENTRY(EMLINK, "EMLINK", "Too many links"), -#endif -#if defined (EPIPE) - ENTRY(EPIPE, "EPIPE", "Broken pipe"), -#endif -#if defined (EDOM) - ENTRY(EDOM, "EDOM", "Math argument out of domain of func"), -#endif -#if defined (ERANGE) - ENTRY(ERANGE, "ERANGE", "Math result not representable"), -#endif -#if defined (ENOMSG) - ENTRY(ENOMSG, "ENOMSG", "No message of desired type"), -#endif -#if defined (EIDRM) - ENTRY(EIDRM, "EIDRM", "Identifier removed"), -#endif -#if defined (ECHRNG) - ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"), -#endif -#if defined (EL2NSYNC) - ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"), -#endif -#if defined (EL3HLT) - ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"), -#endif -#if defined (EL3RST) - ENTRY(EL3RST, "EL3RST", "Level 3 reset"), -#endif -#if defined (ELNRNG) - ENTRY(ELNRNG, "ELNRNG", "Link number out of range"), -#endif -#if defined (EUNATCH) - ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"), -#endif -#if defined (ENOCSI) - ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"), -#endif -#if defined (EL2HLT) - ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"), -#endif -#if defined (EDEADLK) - ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"), -#endif -#if defined (ENOLCK) - ENTRY(ENOLCK, "ENOLCK", "No record locks available"), -#endif -#if defined (EBADE) - ENTRY(EBADE, "EBADE", "Invalid exchange"), -#endif -#if defined (EBADR) - ENTRY(EBADR, "EBADR", "Invalid request descriptor"), -#endif -#if defined (EXFULL) - ENTRY(EXFULL, "EXFULL", "Exchange full"), -#endif -#if defined (ENOANO) - ENTRY(ENOANO, "ENOANO", "No anode"), -#endif -#if defined (EBADRQC) - ENTRY(EBADRQC, "EBADRQC", "Invalid request code"), -#endif -#if defined (EBADSLT) - ENTRY(EBADSLT, "EBADSLT", "Invalid slot"), -#endif -#if defined (EDEADLOCK) - ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"), -#endif -#if defined (EBFONT) - ENTRY(EBFONT, "EBFONT", "Bad font file format"), -#endif -#if defined (ENOSTR) - ENTRY(ENOSTR, "ENOSTR", "Device not a stream"), -#endif -#if defined (ENODATA) - ENTRY(ENODATA, "ENODATA", "No data available"), -#endif -#if defined (ETIME) - ENTRY(ETIME, "ETIME", "Timer expired"), -#endif -#if defined (ENOSR) - ENTRY(ENOSR, "ENOSR", "Out of streams resources"), -#endif -#if defined (ENONET) - ENTRY(ENONET, "ENONET", "Machine is not on the network"), -#endif -#if defined (ENOPKG) - ENTRY(ENOPKG, "ENOPKG", "Package not installed"), -#endif -#if defined (EREMOTE) - ENTRY(EREMOTE, "EREMOTE", "Object is remote"), -#endif -#if defined (ENOLINK) - ENTRY(ENOLINK, "ENOLINK", "Link has been severed"), -#endif -#if defined (EADV) - ENTRY(EADV, "EADV", "Advertise error"), -#endif -#if defined (ESRMNT) - ENTRY(ESRMNT, "ESRMNT", "Srmount error"), -#endif -#if defined (ECOMM) - ENTRY(ECOMM, "ECOMM", "Communication error on send"), -#endif -#if defined (EPROTO) - ENTRY(EPROTO, "EPROTO", "Protocol error"), -#endif -#if defined (EMULTIHOP) - ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"), -#endif -#if defined (EDOTDOT) - ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"), -#endif -#if defined (EBADMSG) - ENTRY(EBADMSG, "EBADMSG", "Not a data message"), -#endif -#if defined (ENAMETOOLONG) - ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"), -#endif -#if defined (EOVERFLOW) - ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"), -#endif -#if defined (ENOTUNIQ) - ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"), -#endif -#if defined (EBADFD) - ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"), -#endif -#if defined (EREMCHG) - ENTRY(EREMCHG, "EREMCHG", "Remote address changed"), -#endif -#if defined (ELIBACC) - ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"), -#endif -#if defined (ELIBBAD) - ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"), -#endif -#if defined (ELIBSCN) - ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"), -#endif -#if defined (ELIBMAX) - ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"), -#endif -#if defined (ELIBEXEC) - ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"), -#endif -#if defined (EILSEQ) - ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"), -#endif -#if defined (ENOSYS) - ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"), -#endif -#if defined (ELOOP) - ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"), -#endif -#if defined (ERESTART) - ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"), -#endif -#if defined (ESTRPIPE) - ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"), -#endif -#if defined (ENOTEMPTY) - ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"), -#endif -#if defined (EUSERS) - ENTRY(EUSERS, "EUSERS", "Too many users"), -#endif -#if defined (ENOTSOCK) - ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"), -#endif -#if defined (EDESTADDRREQ) - ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"), -#endif -#if defined (EMSGSIZE) - ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"), -#endif -#if defined (EPROTOTYPE) - ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"), -#endif -#if defined (ENOPROTOOPT) - ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"), -#endif -#if defined (EPROTONOSUPPORT) - ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"), -#endif -#if defined (ESOCKTNOSUPPORT) - ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"), -#endif -#if defined (EOPNOTSUPP) - ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"), -#endif -#if defined (EPFNOSUPPORT) - ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"), -#endif -#if defined (EAFNOSUPPORT) - ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"), -#endif -#if defined (EADDRINUSE) - ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"), -#endif -#if defined (EADDRNOTAVAIL) - ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"), -#endif -#if defined (ENETDOWN) - ENTRY(ENETDOWN, "ENETDOWN", "Network is down"), -#endif -#if defined (ENETUNREACH) - ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"), -#endif -#if defined (ENETRESET) - ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"), -#endif -#if defined (ECONNABORTED) - ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"), -#endif -#if defined (ECONNRESET) - ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"), -#endif -#if defined (ENOBUFS) - ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"), -#endif -#if defined (EISCONN) - ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"), -#endif -#if defined (ENOTCONN) - ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"), -#endif -#if defined (ESHUTDOWN) - ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"), -#endif -#if defined (ETOOMANYREFS) - ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"), -#endif -#if defined (ETIMEDOUT) - ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"), -#endif -#if defined (ECONNREFUSED) - ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"), -#endif -#if defined (EHOSTDOWN) - ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"), -#endif -#if defined (EHOSTUNREACH) - ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"), -#endif -#if defined (EALREADY) - ENTRY(EALREADY, "EALREADY", "Operation already in progress"), -#endif -#if defined (EINPROGRESS) - ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"), -#endif -#if defined (ESTALE) - ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"), -#endif -#if defined (EUCLEAN) - ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"), -#endif -#if defined (ENOTNAM) - ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"), -#endif -#if defined (ENAVAIL) - ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"), -#endif -#if defined (EISNAM) - ENTRY(EISNAM, "EISNAM", "Is a named type file"), -#endif -#if defined (EREMOTEIO) - ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"), -#endif - ENTRY(0, NULL, NULL) -}; - -/* Translation table allocated and initialized at runtime. Indexed by the - errno value to find the equivalent symbolic value. */ - -static char **error_names; -static int num_error_names = 0; - -/* Translation table allocated and initialized at runtime, if it does not - already exist in the host environment. Indexed by the errno value to find - the descriptive string. - - We don't export it for use in other modules because even though it has the - same name, it differs from other implementations in that it is dynamically - initialized rather than statically initialized. */ - -#ifdef NEED_sys_errlist - -static int sys_nerr; -static char **sys_errlist; - -#else - -extern int sys_nerr; -extern char *sys_errlist[]; - -#endif - - -/* - -NAME - - init_error_tables -- initialize the name and message tables - -SYNOPSIS - - static void init_error_tables (); - -DESCRIPTION - - Using the error_table, which is initialized at compile time, generate - the error_names and the sys_errlist (if needed) tables, which are - indexed at runtime by a specific errno value. - -BUGS - - The initialization of the tables may fail under low memory conditions, - in which case we don't do anything particularly useful, but we don't - bomb either. Who knows, it might succeed at a later point if we free - some memory in the meantime. In any case, the other routines know - how to deal with lack of a table after trying to initialize it. This - may or may not be considered to be a bug, that we don't specifically - warn about this particular failure mode. - -*/ - -static void -init_error_tables () -{ - const struct error_info *eip; - int nbytes; - - /* If we haven't already scanned the error_table once to find the maximum - errno value, then go find it now. */ - - if (num_error_names == 0) - { - for (eip = error_table; eip -> name != NULL; eip++) - { - if (eip -> value >= num_error_names) - { - num_error_names = eip -> value + 1; - } - } - } - - /* Now attempt to allocate the error_names table, zero it out, and then - initialize it from the statically initialized error_table. */ - - if (error_names == NULL) - { - nbytes = num_error_names * sizeof (char *); - if ((error_names = (char **) malloc (nbytes)) != NULL) - { - memset (error_names, 0, nbytes); - for (eip = error_table; eip -> name != NULL; eip++) - { - error_names[eip -> value] = eip -> name; - } - } - } - -#ifdef NEED_sys_errlist - - /* Now attempt to allocate the sys_errlist table, zero it out, and then - initialize it from the statically initialized error_table. */ - - if (sys_errlist == NULL) - { - nbytes = num_error_names * sizeof (char *); - if ((sys_errlist = (char **) malloc (nbytes)) != NULL) - { - memset (sys_errlist, 0, nbytes); - sys_nerr = num_error_names; - for (eip = error_table; eip -> name != NULL; eip++) - { - sys_errlist[eip -> value] = eip -> msg; - } - } - } - -#endif - -} - -/* - -NAME - - errno_max -- return the max errno value - -SYNOPSIS - - int errno_max (); - -DESCRIPTION - - Returns the maximum errno value for which a corresponding symbolic - name or message is available. Note that in the case where - we use the sys_errlist supplied by the system, it is possible for - there to be more symbolic names than messages, or vice versa. - In fact, the manual page for perror(3C) explicitly warns that one - should check the size of the table (sys_nerr) before indexing it, - since new error codes may be added to the system before they are - added to the table. Thus sys_nerr might be smaller than value - implied by the largest errno value defined in <errno.h>. - - We return the maximum value that can be used to obtain a meaningful - symbolic name or message. - -*/ - -int -errno_max () -{ - int maxsize; - - if (error_names == NULL) - { - init_error_tables (); - } - maxsize = MAX (sys_nerr, num_error_names); - return (maxsize - 1); -} - -/* - -NAME - - strerror -- map an error number to an error message string - -SYNOPSIS - - char *strerror (int errnoval) - -DESCRIPTION - - Maps an errno number to an error message string, the contents of - which are implementation defined. On systems which have the external - variables sys_nerr and sys_errlist, these strings will be the same - as the ones used by perror(). - - If the supplied error number is within the valid range of indices - for the sys_errlist, but no message is available for the particular - error number, then returns the string "Error NUM", where NUM is the - error number. - - If the supplied error number is not a valid index into sys_errlist, - returns NULL. - - The returned string is only guaranteed to be valid only until the - next call to strerror. - -*/ - -char * -strerror (errnoval) - int errnoval; -{ - char *msg; - static char buf[32]; - -#ifdef NEED_sys_errlist - - if (error_names == NULL) - { - init_error_tables (); - } - -#endif - - if ((errnoval < 0) || (errnoval >= sys_nerr)) - { - /* Out of range, just return NULL */ - msg = NULL; - } - else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL)) - { - /* In range, but no sys_errlist or no entry at this index. */ - sprintf (buf, "Error %d", errnoval); - msg = buf; - } - else - { - /* In range, and a valid message. Just return the message. */ - msg = sys_errlist[errnoval]; - } - - return (msg); -} - - - -/* - -NAME - - strerrno -- map an error number to a symbolic name string - -SYNOPSIS - - char *strerrno (int errnoval) - -DESCRIPTION - - Given an error number returned from a system call (typically - returned in errno), returns a pointer to a string containing the - symbolic name of that error number, as found in <errno.h>. - - If the supplied error number is within the valid range of indices - for symbolic names, but no name is available for the particular - error number, then returns the string "Error NUM", where NUM is - the error number. - - If the supplied error number is not within the range of valid - indices, then returns NULL. - -BUGS - - The contents of the location pointed to are only guaranteed to be - valid until the next call to strerrno. - -*/ - -char * -strerrno (errnoval) - int errnoval; -{ - char *name; - static char buf[32]; - - if (error_names == NULL) - { - init_error_tables (); - } - - if ((errnoval < 0) || (errnoval >= num_error_names)) - { - /* Out of range, just return NULL */ - name = NULL; - } - else if ((error_names == NULL) || (error_names[errnoval] == NULL)) - { - /* In range, but no error_names or no entry at this index. */ - sprintf (buf, "Error %d", errnoval); - name = buf; - } - else - { - /* In range, and a valid name. Just return the name. */ - name = error_names[errnoval]; - } - - return (name); -} - -/* - -NAME - - strtoerrno -- map a symbolic errno name to a numeric value - -SYNOPSIS - - int strtoerrno (char *name) - -DESCRIPTION - - Given the symbolic name of a error number, map it to an errno value. - If no translation is found, returns 0. - -*/ - -int -strtoerrno (name) - char *name; -{ - int errnoval = 0; - - if (name != NULL) - { - if (error_names == NULL) - { - init_error_tables (); - } - for (errnoval = 0; errnoval < num_error_names; errnoval++) - { - if ((error_names[errnoval] != NULL) && - (strcmp (name, error_names[errnoval]) == 0)) - { - break; - } - } - if (errnoval == num_error_names) - { - errnoval = 0; - } - } - return (errnoval); -} - - -/* A simple little main that does nothing but print all the errno translations - if MAIN is defined and this file is compiled and linked. */ - -#ifdef MAIN - -main () -{ - int errn; - int errnmax; - char *name; - char *msg; - char *strerrno (); - char *strerror (); - - errnmax = errno_max (); - printf ("%d entries in names table.\n", num_error_names); - printf ("%d entries in messages table.\n", sys_nerr); - printf ("%d is max useful index.\n", errnmax); - - /* Keep printing values until we get to the end of *both* tables, not - *either* table. Note that knowing the maximum useful index does *not* - relieve us of the responsibility of testing the return pointer for - NULL. */ - - for (errn = 0; errn <= errnmax; errn++) - { - name = strerrno (errn); - name = (name == NULL) ? "<NULL>" : name; - msg = strerror (errn); - msg = (msg == NULL) ? "<NULL>" : msg; - printf ("%-4d%-18s%s\n", errn, name, msg); - } -} - -#endif diff --git a/lib/strippath.c b/lib/strippath.c deleted file mode 100644 index 39687f92b8047aa006206187a26e7327a19d5975..0000000000000000000000000000000000000000 --- a/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/lib/stripslash.c b/lib/stripslash.c deleted file mode 100644 index 265950e80f3a603e540f045bffee37a9b9f909f0..0000000000000000000000000000000000000000 --- a/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/lib/system.h b/lib/system.h deleted file mode 100644 index 0893c605d5c6ea976b853574f441c7c67c59c3dc..0000000000000000000000000000000000000000 --- a/lib/system.h +++ /dev/null @@ -1,297 +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__ -#define alloca __builtin_alloca -#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 */ -char *alloca (); -#endif /* not _AIX */ -#endif /* not HAVE_ALLOCA_H */ -#endif /* not __GNUS__ */ - -#include <sys/types.h> -#include <sys/stat.h> -#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */ -#ifndef mode_t -#define mode_t unsigned short -#endif -#endif -#if !defined(S_ISBLK) && defined(S_IFBLK) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#endif -#if !defined(S_ISCHR) && defined(S_IFCHR) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#endif -#if !defined(S_ISDIR) && defined(S_IFDIR) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif -#if !defined(S_ISREG) && defined(S_IFREG) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif -#if !defined(S_ISFIFO) && defined(S_IFIFO) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#endif -#if !defined(S_ISLNK) && defined(S_IFLNK) -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif -#if !defined(S_ISSOCK) && defined(S_IFSOCK) -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -#endif -#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ -#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) -#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) -#endif -#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ -#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) -#endif -#if !defined(HAVE_MKFIFO) -#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) -#endif - -#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 - -#if defined(POSIX) || defined(HAVE_UNISTD_H) -#include <unistd.h> -#include <limits.h> -#else -off_t lseek (); -#endif - -#ifdef TM_IN_SYS_TIME -#include <sys/time.h> -#else -#include <time.h> -#endif - -#ifndef HAVE_TIMEB_H -struct timeb { - time_t time; /* Seconds since the epoch */ - unsigned short millitm; /* Field not used */ -#ifdef timezone - short tzone; -#else - short timezone; -#endif - short dstflag; /* Field not used */ -}; -#else -#include <sys/timeb.h> -#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. -** 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. -** -** 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 -** Apollo Domain 10.4 -** NEC SVR4 -*/ - -/* On MOST systems this will get you MAXPATHLEN */ -#include <sys/param.h> - -#ifndef PATH_MAX -# ifdef MAXPATHLEN -# define PATH_MAX MAXPATHLEN -# else -# include <limits.h> -# ifndef PATH_MAX -# ifdef _POSIX_PATH_MAX -# define PATH_MAX _POSIX_PATH_MAX -# else -# define PATH_MAX 1024 -# endif /* _POSIX_PATH_MAX */ -# endif /* PATH_MAX */ -# endif /* MAXPATHLEN */ -#endif /* PATH_MAX */ - - - - -#ifdef HAVE_UTIME_H -#include <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_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 <errno.h> -#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 - -#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 - -/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */ -#if defined(DIRENT) || defined(_POSIX_VERSION) -#include <dirent.h> -#define NLENGTH(dirent) (strlen((dirent)->d_name)) -#else /* not (DIRENT or _POSIX_VERSION) */ -#define dirent direct -#define NLENGTH(dirent) ((dirent)->d_namlen) -#ifdef SYSNDIR -#include <sys/ndir.h> -#endif /* SYSNDIR */ -#ifdef SYSDIR -#include <sys/dir.h> -#endif /* SYSDIR */ -#ifdef NDIR -#include <ndir.h> -#endif /* NDIR */ -#endif /* not (DIRENT or _POSIX_VERSION) */ - -/* 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 - diff --git a/lib/valloc.c b/lib/valloc.c deleted file mode 100644 index ce37da7ad3ae2aaee669615936c00f68a097d6a9..0000000000000000000000000000000000000000 --- a/lib/valloc.c +++ /dev/null @@ -1,21 +0,0 @@ -/* valloc -- return memory aligned to the page size. */ - -#ifndef HAVE_GETPAGESIZE -#define getpagesize() 4096 -#endif - -extern char *malloc (); - -char * -valloc (bytes) - int bytes; -{ - long pagesize; - char *ret; - - pagesize = getpagesize (); - ret = (char *) malloc (bytes + pagesize - 1); - if (ret) - ret = (char *) ((long) (ret + pagesize - 1) &~ (pagesize - 1)); - return ret; -} diff --git a/lib/wait.h b/lib/wait.h deleted file mode 100644 index 2e477730f5428d215b4e57ae8eddcf68d3576fc6..0000000000000000000000000000000000000000 --- a/lib/wait.h +++ /dev/null @@ -1,29 +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. */ -#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/lib/waitpid.c b/lib/waitpid.c deleted file mode 100644 index e8ddeb8a85a70a38f53995ddf53c2e9950cccaba..0000000000000000000000000000000000000000 --- a/lib/waitpid.c +++ /dev/null @@ -1,76 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "system.h" -#include "wait.h" - -#include <stdio.h> - -struct unreaped { - pid_t pid; - int status; -}; -static struct unreaped *unreaped; -static int n; - -static struct unreaped *ualloc (oldptr, n) - struct unreaped *oldptr; - int n; -{ - n *= sizeof (struct unreaped); - if (n == 0) - n = 1; - if (oldptr) - oldptr = (struct unreaped *) realloc ((char *) oldptr, n); - else - oldptr = (struct unreaped *) malloc (n); - if (oldptr == 0) - { - fprintf (stderr, "cannot allocate %d bytes\n", n); - exit (1); - } - return oldptr; -} - -pid_t waitpid (pid, status, options) - pid_t pid; - int *status; - int options; -{ - int i; - - /* initialize */ - if (unreaped == 0) - { - unreaped = ualloc (unreaped, 1); - unreaped[0].pid = 0; - n = 1; - } - - for (i = 0; unreaped[i].pid; i++) - if (unreaped[i].pid == pid) - { - *status = unreaped[i].status; - while (unreaped[i].pid) - { - unreaped[i] = unreaped[i+1]; - i++; - } - n--; - return pid; - } - - while (1) - { - pid_t p = wait3 (status, options, (struct rusage *) 0); - - if (p == 0 || p == -1 || p == pid) - return p; - - n++; - unreaped = ualloc (unreaped, n); - unreaped[n-1].pid = p; - unreaped[n-1].status = *status; - } -} diff --git a/lib/yesno.c b/lib/yesno.c deleted file mode 100644 index 7014803f480334387548cb98822c83979ba4a121..0000000000000000000000000000000000000000 --- a/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/man/.cvsignore b/man/.cvsignore deleted file mode 100644 index f3c7a7c5da68804a1bdf391127ba34aed33c3cca..0000000000000000000000000000000000000000 --- a/man/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/man/ChangeLog b/man/ChangeLog deleted file mode 100644 index 34828c8f24bed88ae1858fc48a31cbc66e059985..0000000000000000000000000000000000000000 --- a/man/ChangeLog +++ /dev/null @@ -1,43 +0,0 @@ -Fri Jul 15 12:58:14 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) - - * Makefile.in (install): Do not depend upon installdirs. - -Sat Dec 18 01:23:13 1993 david d zuhn (zoo@monad.armadillo.com) - - * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead - -Mon Jun 14 12:20:33 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) - - * Makefile.in (install): remove parentdir support - -Mon Aug 31 01:42:43 1992 david d [zoo] zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in (install): create $(man1dir) and $(man5dir) before - installing the man pages - -Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) - - * Makefile.in, configure.in: removed traces of namesubdir, - -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced - copyrights to '92, changed some from Cygnus to FSF. - -Tue Dec 10 04:07:08 1991 K. Richard Pixley (rich at rtl.cygnus.com) - - * Makefile.in: infodir belongs in datadir. - -Tue Dec 10 03:59:10 1991 K. Richard Pixley (rich at cygnus.com) - - * cvs.man: small correction to an explanation of an example. - -Thu Dec 5 22:45:59 1991 K. Richard Pixley (rich at rtl.cygnus.com) - - * Makefile.in: idestdir and ddestdir go away. Added copyrights - and shift gpl to v2. Added ChangeLog if it didn't exist. docdir - and mandir now keyed off datadir by default. - -Wed Nov 27 02:46:20 1991 K. Richard Pixley (rich at sendai) - - * brought Makefile.in's up to standards.text. - - * fresh changelog. - diff --git a/man/Makefile.in b/man/Makefile.in deleted file mode 100644 index a2a85a1ba735aafb164423cdcac1eaef0d56341f..0000000000000000000000000000000000000000 --- a/man/Makefile.in +++ /dev/null @@ -1,84 +0,0 @@ -# Makefile for GNU CVS documentation. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986-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. - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -MAN1FILES = cvs.1 mkmodules.1 -MAN5FILES = cvs.5 -MANFILES = $(MAN1FILES) $(MAN5FILES) - -DISTFILES = Makefile.in $(MANFILES) -INSTALL = @INSTALL@ -INSTALL_DATA = $(INSTALL) -mandir = $(prefix)/man -man1dir = $(mandir)/man1 -man5dir = $(mandir)/man5 - -all: -.PHONY: all - -# CYGNUS LOCAL: Do not depend upon installdirs -install: all - for f in $(MAN1FILES); do \ - $(INSTALL_DATA) $(srcdir)/$$f $(man1dir)/$$f; \ - done - for f in $(MAN5FILES); do \ - $(INSTALL_DATA) $(srcdir)/$$f $(man5dir)/$$f; \ - done - -installdirs: - $(SHELL) $(top_srcdir)/mkinstalldirs $(man1dir) $(man5dir) - -.PHONY: install installdirs - -tags: -.PHONY: tags - -TAGS: -.PHONY: TAGS - -ls: - @true -.PHONY: ls - -clean: -.PHONY: clean - -distclean: clean - rm -f Makefile -.PHONY: distclean - -realclean: distclean -.PHONY: realclean - -dist: - ln $(DISTFILES) ../`cat ../.fname`/man -.PHONY: dist - -Makefile: Makefile.in - cd .. ; $(SHELL) config.status - -../config.status: ../configure - cd .. ; $(SHELL) config.status --recheck - -../configure: ../configure.in - cd $(top_srcdir) ; autoconf diff --git a/man/cvs.1 b/man/cvs.1 deleted file mode 100644 index ffcb7cded11f050838e4219a2a1a8fec430da56b..0000000000000000000000000000000000000000 --- a/man/cvs.1 +++ /dev/null @@ -1,2023 +0,0 @@ -.de Id -.ds Rv \\$3 -.ds Dt \\$4 -.. -.Id $Id: cvs.1,v 1.1.1.1 1994/12/03 06:09:41 jimb 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" -elicits a list of available commands, and -.` "cvs \-v " -displays version information on \fBcvs\fP itself. -.SP -.SH "CVS OPTIONS" -Use these options to control the overall -.B cvs -program: -.TP -.B \-H -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 \-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 -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. -.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 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. 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 rcs ( 1 ) -are available. The \fB\-k\fP option is available with the -.BR add ", " checkout ", " diff ", " -.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. -.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 -.B \-Q -Causes the command to be -.I really -quiet; the command will generate output only for serious problems. -Available with the following commands: -.BR checkout ", " import ", " export ", " -.BR rdiff ", " rtag ", " -.BR tag ", and " update . -.TP -.B \-q -Causes the command to be somewhat quiet; informational messages, such -as reports of recursion through subdirectories, are suppressed. -Available with the following commands: -.BR checkout ", " import ", " export ", " -.BR rtag ", " -.BR tag ", and " update . -.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 -option along with the -.B \-r -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 -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 ", " \-Q ", " \-f ", " -.BI \-k " kflag" -\&, -.BR \-l ", " \-n ", " \-p ", " -.BR \-q ", " \-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] \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 always set 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. -There is no way to override this. -.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 -Three of the standard -.B cvs -command options are available: \fB\-Q\fP, \fB\-q\fP, and \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, \fB\-l\fP, \fB\-Q\fP, and -\fB\-q\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 -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 -The standard options \fB\-Q\fP and \fB\-q\fP are also available with -this command. -.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\-lR\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\-b\fP] [\fB\-d\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, but the versions are supplied -implicitly by the \fBcvs\fP records of your working files' history -rather than applied explicitly. -.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 -.B checkout -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 -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 -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, \fB\-Q\fP, \fB\-q\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 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/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/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 -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 /usr/ucb/vi . -.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/man/cvs.5 b/man/cvs.5 deleted file mode 100644 index 9c477f3340a1d0d30c08925d86968f8b975d00d7..0000000000000000000000000000000000000000 --- a/man/cvs.5 +++ /dev/null @@ -1,326 +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/modules,v -.TP -.B $CVSROOT/CVSROOT/commitinfo,v -.TP -.B $CVSROOT/CVSROOT/loginfo,v -.TP -.B $CVSROOT/CVSROOT/rcsinfo,v -.TP -.B $CVSROOT/CVSROOT/editinfo,v -.TP -.B $CVSROOT/CVSROOT/cvsignore,v -.TP -.B $CVSROOT/CVSROOT/history -.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 `\|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 `\|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 ( 1 ) -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\-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 `\|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/man/mkmodules.1 b/man/mkmodules.1 deleted file mode 100644 index 8196a47f137b3384725b81352ee0b9fc0ddc82f6..0000000000000000000000000000000000000000 --- a/man/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 checkin (1), -.BR co (1), -.BR cvs (1), -.BR ndbm (3), -.BR rcs (1), -.SH "BUGS" diff --git a/mkinstalldirs b/mkinstalldirs deleted file mode 100755 index 91f6d04e17c2b7b003c8e54e4c24646818d81456..0000000000000000000000000000000000000000 --- a/mkinstalldirs +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# mkinstalldirs --- make directory hierarchy -# Author: Noah Friedman <friedman@prep.ai.mit.edu> -# Created: 1993-05-16 -# Last modified: 1994-03-25 -# Public domain - -errstatus=0 - -for file in ${1+"$@"} ; do - set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` - shift - - pathcomp= - for d in ${1+"$@"} ; do - pathcomp="$pathcomp$d" - case "$pathcomp" in - -* ) pathcomp=./$pathcomp ;; - esac - - if test ! -d "$pathcomp"; then - echo "mkdir $pathcomp" 1>&2 - mkdir "$pathcomp" || errstatus=$? - fi - - pathcomp="$pathcomp/" - done -done - -exit $errstatus - -# mkinstalldirs ends here diff --git a/src/.cvsignore b/src/.cvsignore deleted file mode 100644 index bc66d1668ea3ed6cbdc2a1d279651fb29de6c43e..0000000000000000000000000000000000000000 --- a/src/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -Makefile -cvs -mkmodules -cvsbug -.pure diff --git a/src/ChangeLog b/src/ChangeLog deleted file mode 100644 index a9038f71c15ea9f8c6c865efd451476b4f3bcd60..0000000000000000000000000000000000000000 --- a/src/ChangeLog +++ /dev/null @@ -1,1249 +0,0 @@ -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/src/ChangeLog.fsf b/src/ChangeLog.fsf deleted file mode 100644 index 47ef44dfeb1026a178c74722ddb45bbc0800baee..0000000000000000000000000000000000000000 --- a/src/ChangeLog.fsf +++ /dev/null @@ -1,520 +0,0 @@ -Thu Sep 15 08:20:23 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * subr.c (run_setup, run_args): Check USE_PROTOTYPES if defined - instead of __STDC__, just like cvs.h does. - -Thu Sep 15 00:14:58 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * main.c: rename nocvsrc to use_cvsrc, don`t read ~/.cvsrc when -H - has been seen - -Wed Sep 14 21:55:17 1994 david d `zoo' zuhn <zoo@monad.armadillo.com> - - * cvs.h, subr.c: use size_t for xmalloc, xrealloc, and xstrdup - parameters - - * cvsrc.c: optimize away two calls of getenv - - * commit.c, subr.c: use mode_t for file mode values (Thanks to jtc@cygnus.com) - - * main.c: update copyrights in -v message - -Tue Sep 6 10:29:13 1994 J.T. Conklin (jtc@rtl.cygnus.com) - - * hash.c (hashp): Replace hash function with one from p436 of the - Dragon book (via libg++'s hash.cc) which has *much* better - behavior. - -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. - -Tue Aug 16 11:15:12 1994 J.T. Conklin (jtc@cygnus.com) - - * rcs.h (struct rcsnode): add symbols_data field. - * rcs.c (RCS_parsercsfile_i): store value of rcs symbols in - symbols_data instead of parsing it. - (RCS_symbols): New function used for lazy symbols parsing. - Build a list out of symbols_data and store it in symbols if it - hasn't been done already, and return the list of symbols. - (RCS_gettag, RCS_magicrev, RCS_nodeisbranch, RCS_whatbranch): - Use RCS_symbols. - * status.c: (status_fileproc): Use RCS_symbols. - -Thu Jul 14 13:02:51 1994 david d `zoo' zuhn (zoo@monad.armadillo.com) - - * src/diff.c (diff_fileproc): add support for "cvs diff -N" which - allows for adding or removing files via patches. (from - K. Richard Pixley <rich@cygnus.com>) - -Wed Jul 13 10:52:56 1994 J.T. Conklin (jtc@phishhead.cygnus.com) - - * cvs.h: Add macro CVSRFLPAT, a string containing a shell wildcard - expression that matches read lock files. - * lock.c (readers_exist): Reorganized to use CVSRFLPAT and to not - compute the full pathname unless the file matches. - - * rcs.h: Add macro RCSPAT, a string containing a shell wildcard - expression that matches RCS files. - * find_names.c (find_rcs, find_dirs): Use RCSPAT. - -Fri Jul 8 07:02:08 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * entries.c (Register): Pass two arguments to write_ent_proc, in - accordance with its declaration. - -Thu Jun 30 09:08:57 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * logmsg.c (do_editor): Fix typo ("c)continue" -> "c)ontinue"). - -Thu Jun 23 18:28:12 1994 J.T. Conklin (jtc@phishhead.cygnus.com) - - * find_names.c (find_rcs, find_dirs): use fnmatch instead of - re_comp/re_exec for wildcard matching. - * lock.c (readers_exist): Likewise. - -Fri May 20 08:13:10 1994 Jim Kingdon (kingdon@lioth.cygnus.com) - - * modules.c (do_module): If something is aliased to itself, print - an error message rather than recursing. - -Fri May 6 19:25:28 1994 david d zuhn (zoo@monad.armadillo.com) - - * cvsrc.c (read_cvsrc): use open_file for error checking - -Sat Feb 26 10:59:37 1994 david d zuhn (zoo@monad.armadillo.com) - - * import.c: use $TMPDIR if available, instead of relying on /tmp - -Mon Jan 24 19:10:03 1994 david d zuhn (zoo@monad.armadillo.com) - - * update.c (joining): compare join_rev1 with NULL instead of - casting pointer to an int - - * options.h: remove S_IWRITE, S_IWGRP, S_IWOTH macros - - * logmsg.c: #if 0 around gethostbyname prototype - - * hash.c (printnode), find_names.c (add_entries_proc), - entries.c (write_ent_proc): correct declaration for function - (added void *closure) - - * cvs.h: header include order reorganization: First include the - program config headers (config.h, options.h). Then include any - system headers (stdio.h, unistd.h). Last, get the program - headers and any cvs supplied library support - - * commit.c: use xstrdup instead of strdup - - * cvs.h: redefined USE(var) macro; comment after an #endif - - * all .c files: remove the semicolon from after the USE(var) - -Sat Dec 18 00:17:27 1993 david d zuhn (zoo@monad.armadillo.com) - - * cvs.h: include errno.h if available, otherwise declare errno if - it's not somehow else defined - - * commit.c (checkaddfile): remove unused file argument from - RCS_nodeisbranch call - - * rcs.c (RCS_nodeisbranch): remove file from arguments (was unused) - - * rcs.h (RCS_nodeisbranch): remove file from prototype - - * main.c: don't use rcsid when printing version number (the CVS - version number is independent of the repository that it comes - from) - - * hash.c (printlist, printnode): use %p to print pointers, not %x - (avoids gcc format warnings) - - * cvs.h: define USE if GCC 2, to avoid unused variable warning - - * all .c files: use USE(rcsid) - - * Makefile.in (VPATH): don't use $(srcdir), but @srcdir@ instead - (COMMON_OBJECTS): define, and use in several places - (OBJECTS): reorder alphabetically - - * hash.c (nodetypestring): handle default return value better - - * modules.c (do_module): remove extra argument to ign_dir_add - - * main.c (main): initialize cvs_update_env to 0 (zero) - - * modules.c (do_module): return error code when ignoring directory - (instead of a bare return). error code should be zero here - - * cvs.h: add prototypes for ignore_directory, ign_dir_add - - * ignore.c: add comments about ignore_directory - - * root.c (Name_Root): remove unused variables has_cvsadm and path - - * checkin.c (Checkin): only use -m<message> when message is non-NULL - - * cvsrc.c (read_cvsrc): make sure homeinit is never used while - uninitialized (could have happened if getenv("HOME") had failed) - - * cvs.h: include unistd.h if available - -Fri Dec 17 23:54:58 1993 david d zuhn (zoo@monad.armadillo.com) - - * all files: now use strchr, strrchr, and memset instead of index, - rindex, and bzero respectively - -Sat Dec 11 09:50:03 1993 david d zuhn (zoo@monad.armadillo.com) - - * version.c (version_string): bump to +104z - - * Makefile.in: set standard directory variables, CC, and other - variables needed to be able to do 'make all' in this directory - - * import.c: implement -k<subst> options, for setting the RCS - keyword expansion mode - - * all files: use PROTO() macro for ANSI function prototypes - instead of #ifdef __STDC__/#else/#endif around two sets of - declarations - -Thu Nov 18 19:02:51 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * add.c (add), import.c (import), commit.c (commit): change - xmalloc & strcpy to xstrdup. - - * commit.c (remove_file): correct another static buffer problem. - -Wed Nov 10 15:01:34 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * recurse.c (start_recursion): directories in repository but not - in working directory should be added to dirlist. Fixes "update - -d dir" case. - - * version.c (version_string): bump to +103r. - - * commit.c (checkaddfile): mkdir attic only if it does not already - exist. comment changes. changed diagnostic about adding on a - branch. if a file is added on a branch, remove and replace the - internal representation of that rcs file. - -Tue Nov 9 18:02:01 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * add.c (add): if a file is being added on a branch, then say so; - add quotes around file names in error messages. - -Thu Nov 4 16:58:33 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * version.c (version_string): bump to +102r. - - * recurse.c (unroll_files_proc, addfile): new files, forward - decls, and prototypes. - (recursion_frame): new struct. - (start_recursion): rewrite to handle the case of "file1 file2 - dir1/file3". - - * rcs.c (RCS_parsercsfile): trap and error out on the case where - getrcskey tells us it hit an error while reading the file. - - * commit.c (lock_filesdoneproc): add comment about untrapped error - condition. - - * hash.c (addnode): comment change. - - * subr.c: add comment about caching. - - * sanity.sh: updated copyright. - -Wed Nov 3 14:49:15 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * version.c (version_string): bump to +101r. - - * hash.c (walklist): add a closure for called routines. All - callers, callees, and prototypes changed. - - * hash.c (nodetypestring, printnode, printlist): new functions for - dumping lists & nodes. - - * tag.c (tag_fileproc): fatal out on failure to set tag. - -Tue Nov 2 14:26:38 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * version.c (version_string): bump version to +99. - -Mon Nov 1 15:54:51 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - Change buffer allocation for check in messages from static to - dynamic. - * add.c (add): dynamically allocate message. - (build_entry): check (message != NULL) now that message is a - pointer. - * commit.c (got_message, commit, commit_fileproc, - commit_filesdoneproc, commit_direntproc): removed. Replaced by - (message != NULL). Dynamically allocate message. - * cvs.h: adjust do_editor prototype and forward decl. - (MAXMESGLEN): removed. - * import.c (import): dynamically allocate message. - * logmsg.c (do_editor): change return type to char *. Remove - message parameter. Slight optimization to algorythm for - removing CVSEDITPREFIX lines. Add comment about fgets lossage. - - * subr.c (xmalloc): change error message to print number of bytes - we were attempting to allocate. - -Fri Oct 29 14:22:02 1993 K. Richard Pixley (rich@sendai.cygnus.com) - - * add.c (add): prevent adding a directory if there exists a dead - file of the same name. - - * sanity.sh: update argument to diff from "+ignore-file" to - "--exclude=". - - * Makefile.in (TAGS): extend to work from an objdir. - -Mon Oct 18 18:45:45 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * tag.c, rtag.c: change the default actions to make writing over - existing tags harder (but not impossible) - -Thu Oct 14 18:00:53 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - CVS/Root changes from Mark Baushke (mdb@cisco.com) - - * Makefile.in: added new file called root.c - - * create_adm.c: will create CVS/Root at the same time that the - other CVS files are being created - - * cvs.h: new CVSADM_ROOT define plus new function externs - - * main.c: default to using CVS/Root contents for CVSROOT - if neither the environment variable or the command line - "-d" switch is given. If either are given, perform a - sanity check that this directory belongs to that repository. - - * update.c: if CVS/Root does not exist, then create it - during an update -- this may be removed if CVS/Root becomes a - standard feature - - * root.c: implement new functions to manipulate CVS/Root - [this may be integrated with other utility functions in - a future revision if CVS/Root becomes a standard feature.] - -Wed Sep 29 17:01:40 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * patch.c (patch_fileproc): output an Index: line for each file - -Mon Sep 6 18:40:22 1993 david d `zoo' zuhn (zoo@rtl.cygnus.com) - - * cvs.h: wrap definition of PATH_MAX in #ifndef PATH_MAX/#endif - -Tue Aug 9 21:52:10 1994 Mark Eichin (eichin@cygnus.com) - - * commit.c (remove_file): actually allocate space for the - filename, not just the directory. - -Tue Jul 6 19:05:37 1993 david d `zoo' zuhn (zoo@cygnus.com) - - * diff.c: patches to print an Index: line - -Mon Jun 14 12:19:35 1993 david d `zoo' zuhn (zoo at rtl.cygnus.com) - - * Makefile.in: update install target - -Tue Jun 1 17:03:05 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in: link cvs against libiberty - -Wed May 19 14:10:34 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * ignore.c: add code for keeping lists of directories to ignore. - - * modules.c: new syntax for modules file, !dirname is added to - the list of directories to ignore - - * update.c: don't process directories on the ignore list - -Tue Apr 6 14:22:48 1993 Ian Lance Taylor (ian@cygnus.com) - - * cvs.h: Removed gethostname prototype, since it is unnecessary - and does not match prototype in <unistd.h> on HP/UX. - -Mon Mar 22 23:25:16 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com) - - * Makefile.in: rename installtest to installcheck - -Mon Feb 1 12:53:34 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * Makefile.in (check, installtest): set RCSBIN so that we - explicitly test the appropriate version of rcs as well. - -Fri Jan 29 13:37:35 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * version.c: bump version to +2. - -Thu Jan 28 18:11:34 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * import.c (update_rcs_file): if a file was dead, be sure to check - in the new version. - - * update.c (checkout_file): if file_is_dead and we *did* have an - entry, scratch it. - -Tue Jan 26 16:16:48 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * sanity.sh: parcel into pieces for easier truncation when - debugging. - - * update.c (checkout_file): print the "no longer pertinent" - message only if there was a user file. - -Wed Jan 20 17:08:09 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * update.c (checkout_file): remove unused variable s. - (join_file): remove unused variables rev & baserev. Fix a typo. - - * commit.c (commit_fileproc): remove unused variable magicbranch. - - * sanity.sh: bring back test 45 even though it fails. Update - tests against imported files. - - * add.c (add_directory): move declaration of unused variable. - - * Makefile.in (xxx): when building in this directory, pass CC for - the recursion. - -Mon Jan 18 13:48:33 1993 K. Richard Pixley (rich@cygnus.com) - - * commit.c (remove_file): fix for files removed in trunk - immediately after import. - - * commit.c (remove_file): initialize some variables. Otherwise we - end up free'ing some rather inconvenient things. - -Wed Jan 13 15:55:36 1993 K. Richard Pixley (rich@rtl.cygnus.com) - - * Makefile.in (check, install, installtest): use the sanity test. - - * sanity.el: make into real functions and bind to sun keys. - - * sanity.sh: bring back to working order. Add test for death - after import. - -Tue Dec 22 17:45:19 1992 K. Richard Pixley (rich@cygnus.com) - - * commit.c (remove_file): when checking in a dead revision to a - branch as we are creating the branch, do not lock the underlying - revision. Also free some malloc'd memory. - -Wed Dec 2 13:09:48 1992 K. Richard Pixley (rich@cygnus.com) - - * RCS-patches: new file. - -Fri Nov 27 20:12:48 1992 K. Richard Pixley (rich@rtl.cygnus.com) - - Added support for adding previously removed files, as well as - adding and removing files in branches. - - * add.c (build_entry): add new argument, tag, so as to store in - Entries the per directory sticky tag under which a file is - added. Changed prototype and caller. - (build_entry): Do not prevent file additions if the file exists - in the Attic. - (add): if the file being adding was previously dead, say so, and - mark the Entries file with the addition. - * checkin.c (Checkin): adding with a tag no longer means to add, - then tag. Hence, remove the tagging operation. - * classify.c (Classify_File): if the base RCS version is dead, - then the file is being added. If a file being added already - exists in the attic, and the base RCS version is NOT dead, then - we have a conflict. - * commit.c (checkaddfile): add the list of srcfiles to calling - convention. Change prototype and callers. - (remove_file): add message and list of srcfiles to calling - convention. Change prototype and callers. When removing a file - with a tag, remove the tag only when the tag does not represent - a branch. Remove files by committing dead revisions in the - appropriate branch. When removing files from the trunk, also - move the RCS file into the Attic. - (check_fileproc): when adding, and looking for previously - existing RCS files, do not look in the Attic. - (commit_fileproc): adding files with tags now implies adding the - file on a branch with that tag. - (checkaddfile): When adding a file on a branch, in addition to - creating the rcs file in the Attic, also create a dead, initial - revision on the trunk and stub in a magic branch tag. - * cvs.h (joining, gca): added prototypes. - * rcs.c (RCS_getbranch): now global rather than static. - remove prototype and forward decl. - (parse_rcs_proc): use RCS_addnode. - (RCS_addnode): new function. - (RCS_parsercsfile): recognize the new RCS revision - newphrase, "dead". Mark the node for the revision. - (RCS_gettag): requesting the head of a file in the attic now - returns the head of the file in the attic rather than NULL. - (RCS_isbranch): use RCS_nodeisbranch. - (RCS_nodeisbranch): new function. - (RCS_isdead): new function. - * rcs.h (RCSDEAD): new macro for new rcs keyword. - (struct rcsversnode): new field to flag dead revisions. - (RCS_nodeisbranch, RCS_isdead, RCS_addnode): new functions, - new prototypes, new externs. - (RCS_getbranch): now global, so prototype and extern moved - to here. - * subr.c (gca): new function. - * update.c (join_file): add entries list to calling - convention. Caller changed. - (update): also search the Attic when joining. - (checkout_file): when joining, checkout dead revisions too. If - a file has died across an update then say so. - (join_file): support joins of dead files against live ones, live - files against dead ones, and added files. Change the semantic - of a join with only rev specified to mean join specified rev - against checked out files via the greatest common ancestor of - the specified rev and the base rev of the checked out files. - (joining): new function. - * vers_ts.c (Version_TS): ALWAYS get the rcs version number. - - * update.c (update): write the 'C' letter for conflicts. - - * cvs.h (ParseTag): remove duplicate extern. - - * add.c (add_directory): do not prompt for interactive - verification before adding a directory. Doing so prevents - scripted testing. - -Wed Feb 26 18:04:40 1992 K. Richard Pixley (rich@cygnus.com) - - * Makefile.in, configure.in: removed traces of namesubdir, - -subdirs, $(subdir), $(unsubdir), some rcs triggers. Forced - copyrights to '92, changed some from Cygnus to FSF. - -Tue Dec 10 01:24:40 1991 K. Richard Pixley (rich at cygnus.com) - - * diff.c: do not pass an empty -r option to rcsdiff. - - * update.c: fix bug where return code from rcsmerge wasn't being - handled properly. - - * main.c: "rm" and "delete" now synonyms for "remove". - - * commit.c: abort if editor session fails, but remember to clear - locks. - - * Makefile.in: remove conf.h and checkin.configured on clean. - infodir belongs in datadir. - -Thu Dec 5 22:46:03 1991 K. Richard Pixley (rich at rtl.cygnus.com) - - * Makefile.in: idestdir and ddestdir go away. Added copyrights - and shift gpl to v2. Added ChangeLog if it didn't exist. docdir - and mandir now keyed off datadir by default. - -Wed Nov 27 02:47:13 1991 K. Richard Pixley (rich at sendai) - - * brought Makefile.in's up to standards.text. - - * fresh changelog. - diff --git a/src/Makefile.in b/src/Makefile.in deleted file mode 100644 index acb79429ac8a7d22fe9fb26787efab3d5090e84d..0000000000000000000000000000000000000000 --- a/src/Makefile.in +++ /dev/null @@ -1,187 +0,0 @@ -# Makefile for GNU CVS program. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986, 1988-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. - -# $CVSid: @(#)Makefile.in 1.19 94/09/29 $ - -SHELL = /bin/sh - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -# Where to install the executables. -bindir = $(exec_prefix)/bin - -# Where to put the system-wide .cvsrc file -libdir = $(prefix)/lib - -# Where to put the manual pages. -mandir = $(prefix)/man - -# Use cp if you don't have install. -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ - -LIBS = @LIBS@ - -SOURCES = add.c admin.c checkin.c checkout.c classify.c commit.c \ -create_adm.c cvsrc.c diff.c entries.c find_names.c hash.c history.c ignore.c \ -import.c lock.c log.c logmsg.c main.c myndbm.c rcs.c modules.c \ -no_diff.c parseinfo.c patch.c recurse.c release.c remove.c repos.c rtag.c \ -status.c tag.c update.c vers_ts.c version.c root.c subr.c server.c client.c -MSOURCES = mkmodules.c - -OBJECTS = add.o admin.o checkin.o checkout.o classify.o commit.o \ -create_adm.o cvsrc.o diff.o entries.o find_names.o hash.o history.o \ -ignore.o import.o lock.o log.o logmsg.o main.o modules.o myndbm.o no_diff.o \ -parseinfo.o patch.o rcs.o recurse.o release.o remove.o repos.o root.o \ -rtag.o status.o tag.o update.o vers_ts.o server.o client.o - -MOBJECTS = hash.o mkmodules.o myndbm.o - -COMMON_OBJECTS = subr.o version.o - -HEADERS = cvs.h rcs.h hash.h myndbm.h patchlevel.h \ - update.h server.h client.h - -DISTFILES = Makefile.in cvsbug.sh \ - ChangeLog NOTES RCS-patches README-rm-add \ - ChangeLog.fsf \ - sanity.sh sanity.el \ - .cvsignore \ - $(HEADERS) $(SOURCES) $(MSOURCES) - -PROGS = cvs mkmodules cvsbug - -DEFS = @DEFS@ @includeopt@ - -CC = @CC@ -CFLAGS = -g -CPPFLAGS= -LDFLAGS= - -INCLUDES = -I.. -I$(srcdir) -I$(top_srcdir)/lib -.c.o: - $(CC) $(CPPFLAGS) $(INCLUDES) $(DEFS) $(CFLAGS) -c $< - -all: $(PROGS) -.PHONY: all - -saber_cvs: - @cd ..; $(MAKE) saber SUBDIRS=src - -lint: - @cd ..; $(MAKE) lint SUBDIRS=src - -# CYGNUS LOCAL: Do not depend upon installdirs -install: - @for prog in $(PROGS); do \ - echo Installing $$prog in $(bindir); \ - $(INSTALL) $$prog $(bindir)/$$prog ; \ - done - -installdirs: - $(SHELL) $(top_srcdir)/mkinstalldirs $(bindir) - -.PHONY: install installdirs - -installcheck: - RCSBIN=$(bindir) ; export RCSBIN ; $(SHELL) $(srcdir)/sanity.sh $(bindir)/cvs -.PHONY: installcheck - -check: all - if [ -d ../../rcs/src ] ; then \ - RCSBIN=`pwd`/../../rcs/src ; \ - export RCSBIN ; \ - fi ; \ - $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs -.PHONY: check - -# This is not yet ready to be part of the standard `make check'. -# We need to fix the problem with making sure we get the server we just built, -# for one thing. -remotecheck: all - $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs -.PHONY: remotecheck - -tags: $(DISTFILES) - ctags $(DISTFILES) - -TAGS: $(DISTFILES) - etags `for i in $(DISTFILES); do echo $(srcdir)/$$i; done` - -ls: - @echo $(DISTFILES) -.PHONY: ls - -clean: - /bin/rm -f $(PROGS) *.o core -.PHONY: clean - -distclean: clean - rm -f tags TAGS Makefile -.PHONY: distclean - -realclean: distclean -.PHONY: realclean - -dist: - ln $(DISTFILES) ../`cat ../.fname`/src -.PHONY: dist - -# Linking rules. - -$(PROGS): ../lib/libcvs.a - -cvs: $(OBJECTS) $(COMMON_OBJECTS) - $(CC) $(OBJECTS) $(COMMON_OBJECTS) ../lib/libcvs.a $(LIBS) $(LDFLAGS) -o $@ - -xlint: $(SOURCES) - files= ; \ - for i in $(SOURCES) ; do \ - files="$$files $(srcdir)/$$i" ; \ - done ; \ - sh -c "lint $(DEFS) $(INCLUDES) $$files | grep -v \"possible pointer alignment problem\" \ - | grep -v \"argument closure unused\"" - -saber: $(SOURCES) - # load $(CFLAGS) $(SOURCES) - # load ../lib/libcvs.a $(LIBS) - -mkmodules: $(MOBJECTS) $(COMMON_OBJECTS) - $(CC) $(LDFLAGS) -o $@ $(MOBJECTS) $(COMMON_OBJECTS) ../lib/libcvs.a $(LIBS) $(LIBIBERTY) - -cvsbug: cvsbug.sh - cp $(srcdir)/cvsbug.sh cvsbug - -# Compilation rules. - -$(OBJECTS) $(COMMON_OBJECTS) mkmodules.o: $(HEADERS) - -Makefile: Makefile.in - cd .. ; $(SHELL) config.status - -#../config.status: ../configure -# cd .. ; $(SHELL) config.status --recheck - -#../configure: ../configure.in -# cd $(top_srcdir) ; autoconf diff --git a/src/NOTES b/src/NOTES deleted file mode 100644 index 646ebdf85207d929399be1fde024843324c31e80..0000000000000000000000000000000000000000 --- a/src/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/src/README-rm-add b/src/README-rm-add deleted file mode 100644 index 406452df4021594fb9304a6a7db7bfc0c7b8f2c1..0000000000000000000000000000000000000000 --- a/src/README-rm-add +++ /dev/null @@ -1,125 +0,0 @@ -SUMMARY: - -The functionality described below has several slightly different -implementations. The one which is used by default in Cyclic CVS -(controlled by the DEATH_STATE define), does not require any RCS -modifications. But if you undefine DEATH_STATE, you'll need these RCS -changes. The only reason to do so is if you want your repository to -be usable by old versions of Cygnus CVS. - -The patches are against rcs 5.6.6 which is a beta version, but given -the above you don't really need to worry about where to get it. - -The death support extends CVS branch support and allows files which -have previously been removed to be added once again. - -- kingdon, 27 Mar 95 (the rest of this file is older; the parts -relating to the CVS functionality involved should be merged into the -main CVS manual, the parts relating to the implementation which -involves changing RCS can hopefully be flushed at some point). - -WHAT THESE PATCHES DO: - -The RCS patches add to RCS the ability to 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. - -I've modified CVS to exploit this facility in several areas. - -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. - - -INCOMPATIBILITIES: - -Previous versions of RCS will not work properly on RCS files that use -the death support. Previous versions of RCS contain a bug in the -future expansion such that unrecognized keywords are not propogated -forward in the rcs file. That is, if your RCS file contains revisions -which are flagged as dead, and you use a previous version of RCS on -this RCS file, the previous version of RCS will delete the death -markers. - -Previous versions of CVS did not record *when* a file died. They only -recorded that a file *was* dead in the trunk. There is a simple -repository conversion that mostly works. There's a new script in -cvs/src/convert.sh to do this for you. Its usage is: - - /bin/sh convert.sh $CVSROOT - -This script will look through the repository specified as its first -argument. For each file in an Attic, .../Attic/foo,v, the script will -copy the rcs file into .../Attic/SAVE/foo,v and will then mark the -file dead as of the time the script is running. This means that -attempts to retrieve the file by date will be innacurate. -Specifically, an attempt to retrieve the file by a date prior to -repository conversion, but after the file was removed, will actually -retrieve a copy of the file when it should not. - -The conversion script also ignores an important case. If you have any -files which were added on a branch by previous version of CVS, they -will not be handled correctly. Previous versions of CVS did not -record this information properly. Specifically, it is not possible to -recognize the difference between a file which was added on a branch -from a file which was removed from the trunk. If you know of any of -these cases, then you will need to repair the file by hand. - -Files added on a branch using this patched version of CVS will behave -properly. - - -HOW TO INSTALL: - -Make backups of everything in sight; your repository, your CVS source, -your RCS source, your dog, your desk, your boss, your boss's boss, and -like that. - -Apply these patches to your copy of CVS. - -Apply the RCS patches from the file RCS-patches into your copy of -rcs-5.6.6. Rebuild and reinstall RCS. - -Rebuild and reinstall CVS. - -Run the repository converter over your repository. - - -7 Dec '92 - K. Richard Pixley <rich@cygnus.com> -modified & updated 22 Nov '93. diff --git a/src/add.c b/src/add.c deleted file mode 100644 index 11b19f897a518021e7b305f125d86e64016d9168..0000000000000000000000000000000000000000 --- a/src/add.c +++ /dev/null @@ -1,524 +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" - -#ifndef lint -static 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); - - /* 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); - - if (client_active) - { - int i; - start_server (); - ign_setup (); - option_with_arg ("-k", 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") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - entries = ParseEntries (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)) - { - /* - * 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 file `%s' for addition on branch `%s'", - user, vers->tag); - else -#endif /* DEATH_SUPPORT */ - error (0, 0, "scheduling file `%s' for addition", user); - } - } - } - } -#ifdef DEATH_SUPPORT - else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) - { - if (isdir (user)) - { - 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)) - { - err += add_directory (repository, user); - continue; - } - if (server_active && begin_added_files != added_files) - server_checked_in (user, ".", repository); - } - if (added_files) - error (0, 0, "use 'cvs commit' to add %s permanently", - (added_files == 1) ? "this file" : "these files"); - dellist (&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 cwd[PATH_MAX], rcsdir[PATH_MAX]; - 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 || strcmp (dir, OCVSADM) == 0) - { - error (0, 0, "cannot add a `%s' or a `%s' directory", CVSADM, OCVSADM); - 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 (getwd (cwd) == NULL) - { - error (0, 0, "cannot get working directory: %s", cwd); - return (1); - } - if (chdir (dir) < 0) - { - error (0, errno, "cannot chdir to %s", dir); - return (1); - } - if (!server_active && (isfile (CVSADM) || isfile (OCVSADM))) - { - error (0, 0, - "%s/%s (or %s/%s) already exists", dir, CVSADM, dir, OCVSADM); - 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 (2); - if (mkdir (rcsdir, 0777) < 0) - { - error (0, errno, "cannot mkdir %s", rcsdir); - (void) umask ((int) omask); - goto out; - } - (void) umask ((int) 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); - } - - if (!server_active) - Create_Admin (".", dir, rcsdir, tag, date); - if (tag) - free (tag); - if (date) - free (date); - - (void) printf ("%s", message); -out: - if (chdir (cwd) < 0) - error (1, errno, "cannot chdir to %s", 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 options for the "add" command are store in the file CVS/user,p - * XXX - no they are not! - */ - (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_OPT); - fp = open_file (fname, "w+"); - if (fclose (fp) == EOF) - error(1, errno, "cannot close %s", fname); - - /* - * And the requested log is read directly from the user and stored in the - * 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 ,p - * and ,t files, 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/src/admin.c b/src/admin.c deleted file mode 100644 index b835d99115c6acc89d0838739339088d342e7a98..0000000000000000000000000000000000000000 --- a/src/admin.c +++ /dev/null @@ -1,145 +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" - -#ifndef lint -static 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; - - if (argc <= 1) - usage (admin_usage); - - /* 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); - - if (client_active) - { - int i; - - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - for (i = 1; i <= ac; ++i) - 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") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - /* start the recursion processor */ - err = start_recursion (admin_fileproc, (int (*) ()) NULL, admin_dirproc, - (int (*) ()) 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/src/checkin.c b/src/checkin.c deleted file mode 100644 index 15dd0de4e5246080e1943a21f12c5220d069dc1e..0000000000000000000000000000000000000000 --- a/src/checkin.c +++ /dev/null @@ -1,174 +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 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; - - 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. - */ - if (!noexec) - copy_file (file, fname); - - run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI, - rev ? "-r" : "", rev ? rev : ""); - run_args ("-m%s", (*message == '\0' || strcmp(message, "\n") == 0) ? - "*** empty log message ***\n" : 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; - } - - /* - * 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)) - { - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, tag, rev); - run_arg (rcs); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } -#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); - break; - - case -1: /* fork failed */ - 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 (!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) - { - run_setup ("%s%s -q -u", Rcsbin, RCS); - run_arg (rcs); - (void) run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL); - } - - 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); - } - - return (0); -} diff --git a/src/checkout.c b/src/checkout.c deleted file mode 100644 index dbe2390a24dafab8db7646053a219311433d2aba..0000000000000000000000000000000000000000 --- a/src/checkout.c +++ /dev/null @@ -1,821 +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 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 const char *const checkout_usage[] = -{ - "Usage:\n %s %s [-ANPQcflnpqs] [-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-Q\tReally quiet.\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-q\tSomewhat quiet.\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 [-NPQflnq] [-r rev | -D date] [-d dir] module...\n", - "\t-N\tDon't shorten module paths if -d specified.\n", - "\t-Q\tReally quiet.\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-q\tSomewhat quiet.\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", - 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; - - /* - * 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 on (like -kv) and takes care to remove the CVS directory - * when it has done its duty - */ - if (strcmp (command_name, "export") == 0) - { - valid_options = "Nnd:flRQqr:D:"; - valid_usage = export_usage; - } - else - { - valid_options = "ANnk:d:flRpQqcsr:D:j:P"; - valid_usage = checkout_usage; - } - - if (argc == -1) - usage (valid_usage); - - ign_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': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - 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); - options = RCS_check_kflag ("v");/* -kv must be on */ - } - - if (client_active) - { - int errs; - int expand_modules; - - start_server (); - - ign_setup (); - - expand_modules = - !cat && !status && !pipeout && supported_request ("expand-modules"); - if (expand_modules) - { - client_expand_modules (argc, argv, local); - } - - if (!run_module_prog) send_arg ("-n"); - if (really_quiet) send_arg ("-Q"); - if (quiet) send_arg ("-q"); - if (local) send_arg ("-l"); - if (pipeout) send_arg ("-p"); - if (!force_tag_match) send_arg ("-f"); - if (aflag) - if (fprintf (to_server, "Argument -A\n") == EOF) - error (1, errno, "writing to server"); - if (!shorten) - if (fprintf (to_server, "Argument -N\n") == EOF) - error (1, errno, "writing to server"); - if (checkout_prune_dirs && strcmp (command_name, "export") != 0) - if (fprintf (to_server, "Argument -P\n") == EOF) - error (1, errno, "writing to server"); - client_prune_dirs = checkout_prune_dirs; - if (cat) - if (fprintf (to_server, "Argument -c\n") == EOF) - error (1, errno, "writing to server"); - if (where != NULL) - { - option_with_arg ("-d", where); - } - if (status) - if (fprintf (to_server, "Argument -s\n") == EOF) - error (1, errno, "writing to server"); - 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) - { - 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") - == EOF) - error (1, errno, "writing to server"); - } - else - { - client_send_expansions (local); - if (fprintf - (to_server, - strcmp (command_name, "export") == 0 ? "export\n" : "co\n") - == EOF) - error (1, errno, "writing to server"); - } - return get_responses_and_close (); - } - - 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) 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) && !isfile (OCVSADM)) - { - (void) sprintf (repository, "%s/%s/%s", CVSroot, CVSROOTADM, - CVSNULLREPOS); - if (!isfile (repository)) - (void) mkdir (repository, 0777); - - /* 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); - if (server_active) - server_set_entstat (preload_update_dir, repository); - } - } - } - - /* - * 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], CHECKOUT, "Updating", checkout_proc, - where, shorten, local, run_module_prog, - (char *) NULL); - close_module (db); - return (err); -} - -/* - * 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) && !isfile (OCVSADM)) - { - 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); - if (server_active) - server_set_entstat (where, repository); - } - 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 (strcmp (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 = ParseEntries (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); - } - dellist (&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) mkdir (cp, 0777); - if (chdir (cp) < 0) - { - error (0, errno, "cannot chdir to %s", cp); - return (1); - } - if (!isfile (CVSADM) && !isfile (OCVSADM) && - 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); - if (server_active) - server_set_entstat (path, repository); - } - } - *slash = '/'; - *slash2 = '/'; - } - (void) mkdir (cp, 0777); - if (chdir (cp) < 0) - { - error (0, errno, "cannot chdir to %s", cp); - return (1); - } - return (0); -} diff --git a/src/classify.c b/src/classify.c deleted file mode 100644 index e23451eada115476851b4813b3f35eb1b4622385..0000000000000000000000000000000000000000 --- a/src/classify.c +++ /dev/null @@ -1,502 +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 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); - - 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); - } - } - } -} diff --git a/src/client.c b/src/client.c deleted file mode 100644 index 26514f09b5fe68be4c0fe55f42b1d46b72f4d81b..0000000000000000000000000000000000000000 --- a/src/client.c +++ /dev/null @@ -1,2972 +0,0 @@ -/* CVS client-related stuff. */ - -#include "cvs.h" -#include "update.h" /* Things shared with update.c */ -#include "md5.h" - -#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 -#endif - -static void add_prune_candidate PROTO((char *)); - - -/* Shared with server. */ - -/* - * Return a malloc'd, '\0'-terminated string - * corresponding to the mode in SB. - */ -char * -mode_to_string (sb) - struct stat *sb; -{ - char *mode_string = xmalloc (80); - strcpy (mode_string, "u="); - if (sb->st_mode & S_IRUSR) strcat (mode_string, "r"); - if (sb->st_mode & S_IWUSR) strcat (mode_string, "w"); - if (sb->st_mode & S_IXUSR) strcat (mode_string, "x"); - strcat (mode_string, ",g="); - if (sb->st_mode & S_IRGRP) strcat (mode_string, "r"); - if (sb->st_mode & S_IWGRP) strcat (mode_string, "w"); - if (sb->st_mode & S_IXGRP) strcat (mode_string, "x"); - strcat (mode_string, ",o="); - if (sb->st_mode & S_IROTH) strcat (mode_string, "r"); - if (sb->st_mode & S_IWOTH) strcat (mode_string, "w"); - if (sb->st_mode & S_IXOTH) strcat (mode_string, "x"); - return mode_string; -} - -/* - * 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; - if (*q == 'w') - can_write = 1; - 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) - mode |= S_IXUSR; - } - else if (p[0] == 'g') - { - if (can_read) - mode |= S_IRGRP; - if (can_write) - mode |= S_IWGRP; - if (can_execute) - mode |= S_IXGRP; - } - else if (p[0] == 'o') - { - if (can_read) - mode |= S_IROTH; - if (can_write) - mode |= S_IWOTH; - if (can_execute) - mode |= S_IXOTH; - } - } - /* Skip to the next field. */ - while (*p != ',' && *p != '\0') - ++p; - if (*p == ',') - ++p; - } - if (chmod (filename, mode) < 0) - return errno; - return 0; -} - -/* The host part of CVSROOT. */ -static char *server_host; -/* 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 () -{ - server_host = xstrdup (CVSroot); - server_cvsroot = strchr (server_host, ':'); - *server_cvsroot = '\0'; - ++server_cvsroot; - - client_active = 1; -} - -/* Stream to write to the server. */ -FILE *to_server; -/* Stream to read from the server. */ -FILE *from_server; -/* Process ID of rsh subprocess. */ -int rsh_pid = -1; - -/* - * 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; -} - -static 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; - } -} - -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); -} - -/* - * 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); -} - -extern int use_unchanged; /* see server.c */ - -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) == EOF) - 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((char *)); - -static char * -get_short_pathname (name) - char *name; -{ - char *retval; - if (use_directory) - return 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 retval; -} - -/* - * Do all the processing for PATHNAME, where pathname consists of the - * repository and the filename. FUNC gets called with the DATA parameter - * to call_in_directory, and with a pointer to an entries list (which - * we manage the storage for). - */ - -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 (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 (errno != ENOENT) - 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; - - do - { - dirp = strchr (dirp, '/'); - if (rdirp == NULL) - error (0, 0, - "internal error: repository string too short."); - else - rdirp = strchr (rdirp, '/'); - if (dirp) - { - strncpy (dir, dirname, dirp - dirname); - dir[dirp - dirname] = '\0'; - /* Skip the slash. */ - ++dirp; - } - else - strcpy (dir, dirname); - if (mkdir (dir, 0777) < 0) - { - if (errno != EEXIST) - error (1, errno, "cannot make directory %s", dir); - - /* 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; - char *p; - - 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) - dellist (&last_entries); - last_entries = ParseEntries (0); - } - } - else - free (dirname); - free (reposdirname); - (*func) (data, last_entries, short_pathname, filename); - free (reposname); -} - -static void -copy_a_file (data, ent_list, short_pathname, filename) - char *data; - List *ent_list; - char *short_pathname; - char *filename; -{ - int len; - char *newname; - - len = 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] = 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; - - read_line (&entries_line, 0); - - 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 - sprintf (temp_filename, ".new.%s", filename); -#endif - buf = xmalloc (size); - fd = open (temp_filename, O_WRONLY | O_CREAT | O_TRUNC, 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)) - error (1, 0, "unexpected end of file from server"); - else if (ferror (from_server)) - 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; - - if (data->contents == UPDATE_ENTRIES_UPDATE) - rename_file (temp_filename, filename); - 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); - } - if (retcode == 0) - { - (void) unlink_file (temp_filename); - (void) unlink_file (backup); - } - else - { - int old_errno = errno; - - if (isfile (backup)) - rename_file (backup, filename); - - /* 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. - */ - 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); - 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; - } - } - - { - int status = change_mode (filename, mode_string); - if (status != 0) - error (0, status, "cannot change mode of %s", short_pathname); - } - 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 *cp; - char *user; - char *vn; - /* Timestamp field. Always empty according to the protocol. */ - char *ts; - char *options; - char *tag; - char *date; - char *tag_or_date; - char *local_timestamp; - char *file_timestamp; - - char *scratch_entries = xstrdup (entries_line); - - if (scratch_entries[0] != '/') - error (1, 0, "bad entries line `%s' from server", entries_line); - user = scratch_entries + 1; - if ((cp = strchr (user, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - vn = cp; - if ((cp = strchr (vn, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - - ts = cp; - if ((cp = strchr (ts, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - options = cp; - if ((cp = strchr (options, '/')) == NULL) - error (1, 0, "bad entries line `%s' from server", entries_line); - *cp++ = '\0'; - tag_or_date = cp; - - /* If a slash ends the tag_or_date, ignore everything after it. */ - cp = strchr (tag_or_date, '/'); - if (cp != NULL) - *cp = '\0'; - tag = (char *) NULL; - date = (char *) NULL; - if (*tag_or_date == 'T') - tag = tag_or_date + 1; - else if (*tag_or_date == 'D') - date = tag_or_date + 1; - - local_timestamp = data->timestamp; - if (local_timestamp == NULL || ts[0] == '+') - file_timestamp = time_stamp (filename); - - /* - * 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); - 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 && errno != ENOENT) - error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); -} - -static void -handle_clear_static_directory (pathname, len) - char *pathname; - int len; -{ - char *dirname; - /* Just the part of pathname relative to toplevel_repos. */ - char *short_pathname; - char *p; - char tmp[PATH_MAX]; - - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - return; - } - short_pathname = get_short_pathname (pathname); - - 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; - int len; - FILE *f; - - len = read_line (&tagspec, 0); - f = open_file (CVSADM_TAG, "w+"); - if (fprintf (f, "%s\n", tagspec) == EOF) - 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; -{ - char *dirname; - /* Just the part of pathname relative to toplevel_repos. */ - char *short_pathname; - char *p; - char tmp[PATH_MAX]; - - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - /* Swallow the tag line. */ - (void) read_line (NULL, 0); - return; - } - short_pathname = get_short_pathname (pathname); - 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 && errno != ENOENT) - error (1, errno, "cannot remove %s", CVSADM_TAG); -} - -static void -handle_clear_sticky (pathname, len) - char *pathname; - int len; -{ - char *dirname; - /* Just the part of pathname relative to toplevel_repos. */ - char *short_pathname; - char *p; - char tmp[PATH_MAX]; - - if (strcmp (command_name, "export") == 0) - { - /* Swallow the repository. */ - read_line (NULL, 0); - return; - } - short_pathname = get_short_pathname (pathname); - - 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) == EOF) - 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) == EOF) - 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 (errno != ENOENT) - 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 && - strcmp (dp->d_name, OCVSADM) != 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)) - { - run_setup ("%s -fr", RM); - run_arg (p->dir); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - 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 ") == EOF) - error (1, errno, "writing to server"); - if (fprintf (to_server, "%s", update_dir) == EOF) - error (1, errno, "writing to server"); - - if (fprintf (to_server, "\n%s\n", repos) - == EOF) - error (1, errno, "writing to server"); - } - else - { - if (fprintf (to_server, "Repository %s\n", repos) == EOF) - error (1, errno, "writing to server"); - } - if (supported_request ("Static-directory") && isreadable (CVSADM_ENTSTAT)) - if (fprintf (to_server, "Static-directory\n") == EOF) - 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 (errno != ENOENT) - error (1, errno, "reading %s", adm_name); - } - else - { - /* Small for testing. */ - char line[2]; - char *nl; - if (fprintf (to_server, "Sticky ") == EOF) - error (1, errno, "writing to server"); - while (fgets (line, sizeof (line), f) != NULL) - { - if (fprintf (to_server, "%s", line) == EOF) - error (1, errno, "writing to server"); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - if (fprintf (to_server, "\n") == EOF) - 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 (errno != ENOENT) - error (1, errno, "reading %s", adm_name); - } - else - { - /* Small for testing. */ - char line[2]; - char *nl; - if (fprintf (to_server, "Checkin-prog ") == EOF) - error (1, errno, "writing to server"); - while (fgets (line, sizeof (line), f) != NULL) - { - if (fprintf (to_server, "%s", line) == EOF) - error (1, errno, "writing to server"); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - if (fprintf (to_server, "\n") == EOF) - 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 (errno != ENOENT) - error (1, errno, "reading %s", adm_name); - } - else - { - /* Small for testing. */ - char line[2]; - char *nl; - if (fprintf (to_server, "Update-prog ") == EOF) - error (1, errno, "writing to server"); - while (fgets (line, sizeof (line), f) != NULL) - { - if (fprintf (to_server, "%s", line) == EOF) - error (1, errno, "writing to server"); - nl = strchr (line, '\n'); - if (nl != NULL) - break; - } - if (nl == NULL) - if (fprintf (to_server, "\n") == EOF) - 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; -{ - int update_dir_len = strlen (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 - { - char *cvsadm; - - /* - * 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") == EOF) - 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 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); -} - -/* This table must be writeable if the server code is included. */ -struct response responses[] = -{ - {"ok", handle_ok, response_type_ok, rs_essential}, - {"error", handle_error, response_type_error, rs_essential}, - {"Valid-requests", handle_valid_requests, response_type_normal, - rs_essential}, - {"Checked-in", handle_checked_in, response_type_normal, rs_essential}, - {"New-entry", handle_new_entry, response_type_normal, rs_optional}, - {"Checksum", handle_checksum, response_type_normal, rs_optional}, - {"Copy-file", handle_copy_file, response_type_normal, rs_optional}, - {"Updated", handle_updated, response_type_normal, rs_essential}, - {"Merged", handle_merged, response_type_normal, rs_essential}, - {"Patched", handle_patched, response_type_normal, rs_optional}, - {"Removed", handle_removed, response_type_normal, rs_essential}, - {"Remove-entry", handle_remove_entry, response_type_normal, rs_optional}, - {"Set-static-directory", handle_set_static_directory, response_type_normal, - rs_optional}, - {"Clear-static-directory", handle_clear_static_directory, - response_type_normal, - rs_optional}, - {"Set-sticky", handle_set_sticky, response_type_normal, rs_optional}, - {"Clear-sticky", handle_clear_sticky, response_type_normal, rs_optional}, - {"Set-checkin-prog", handle_set_checkin_prog, response_type_normal, - rs_optional}, - {"Set-update-prog", handle_set_update_prog, response_type_normal, - rs_optional}, - {"Module-expansion", handle_module_expansion, response_type_normal, - rs_optional}, - {"M", handle_m, response_type_normal, rs_essential}, - {"E", handle_e, response_type_normal, rs_essential}, - /* Possibly should be response_type_error. */ - {NULL, NULL, response_type_normal, rs_essential} -}; - -/* - * 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 (); - -#ifdef HAVE_KERBEROS - if (server_fd != -1) - { - if (shutdown (server_fd, 1) < 0) - error (1, errno, "shutting down connection to %s", server_host); - /* - * In this case, both sides of the net connection will use the - * same fd. - */ - if (fileno (from_server) != fileno (to_server)) - { - if (fclose (to_server) != 0) - error (1, errno, "closing down connection to %s", server_host); - } - } - else -#endif - { - if (fclose (to_server) == EOF) - error (1, errno, "closing connection to %s", server_host); - } - - if (getc (from_server) != EOF) - error (0, 0, "dying gasps from %s unexpected", server_host); - else if (ferror (from_server)) - error (0, errno, "reading from %s", server_host); - - fclose (from_server); - - if (rsh_pid != -1 - && waitpid (rsh_pid, (int *) 0, 0) == -1) - error (1, errno, "waiting for process %d", rsh_pid); - - return errs; -} - -static void start_rsh_server PROTO((int *, int *)); - -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?"); -} - -/* Contact the server. */ - -void -start_server () -{ - int tofd, fromfd; - char *log = getenv ("CVS_CLIENT_LOG"); - -#if HAVE_KERBEROS - { - 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; - start_rsh_server (&tofd, &fromfd); - } - free (hname); - } - -#else /* ! HAVE_KERBEROS */ - - start_rsh_server (&tofd, &fromfd); - -#endif /* ! HAVE_KERBEROS */ - - 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); - } - - /* Should be using binary mode on systems which have it. */ - to_server = fdopen (tofd, "w"); - if (to_server == NULL) - error (1, errno, "cannot fdopen %d for write", tofd); - /* Should be using binary mode on systems which have it. */ - from_server = fdopen (fromfd, "r"); - 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) == EOF) - error (1, errno, "writing to server"); - { - struct response *rs; - if (fprintf (to_server, "Valid-responses") == EOF) - error (1, errno, "writing to server"); - for (rs = responses; rs->name != NULL; ++rs) - { - if (fprintf (to_server, " %s", rs->name) == EOF) - error (1, errno, "writing to server"); - } - if (fprintf (to_server, "\n") == EOF) - error (1, errno, "writing to server"); - } - if (fprintf (to_server, "valid-requests\n") == EOF) - 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") == EOF) - 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") == EOF) - 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") == EOF) - 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") == EOF) - 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") == EOF) - 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") == EOF) - 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) == EOF) - error (1, 0, "writing to server"); - } - else - { - fprintf (stderr, "server doesn't support gzip-file-contents\n"); - gzip_level = 0; - } - } -} - -/* Contact the server by starting it with rsh. */ - -static void -start_rsh_server (tofdp, fromfdp) - int *tofdp; - int *fromfdp; -{ - int to_server_pipe[2]; - int from_server_pipe[2]; - - if (pipe (to_server_pipe) < 0) - error (1, errno, "cannot create pipe"); - if (pipe (from_server_pipe) < 0) - error (1, errno, "cannot create pipe"); - - rsh_pid = fork (); - if (rsh_pid < 0) - error (1, errno, "cannot fork"); - if (rsh_pid == 0) - { - if (dup2 (to_server_pipe[0], STDIN_FILENO) < 0) - error (1, errno, "cannot dup2"); - if (close (to_server_pipe[1]) < 0) - error (1, errno, "cannot close"); - if (close (from_server_pipe[0]) < 0) - error (1, errno, "cannot close"); - if (dup2 (from_server_pipe[1], STDOUT_FILENO) < 0) - error (1, errno, "cannot dup2"); - - execlp ("rsh", "rsh", server_host, - getenv ("CVS_SERVER") ? getenv ("CVS_SERVER") : "cvs", -#if 1 - /* - * This is really cheesy, because it is redundant with the - * Root request, inconsistent with how we do things when we - * aren't using rsh, and the code in main.c which prints - * an error on a bad root just writes to stderr rather than - * using the protocol. - * - * But I'm leaving it in for now because old (Nov 3, 1994) - * versions of the server say - * "`cvs server' is for internal use--don't use it directly" - * if you try to start them up without -d and your .bashrc - * sets CVSROOT to something containing a colon. - */ - "-d", server_cvsroot, -#endif - "server", (char *)NULL); - error (1, errno, "cannot exec"); - } - if (close (to_server_pipe[0]) < 0) - error (1, errno, "cannot close"); - if (close (from_server_pipe[1]) < 0) - error (1, errno, "cannot close"); - *tofdp = to_server_pipe[1]; - *fromfdp = from_server_pipe[0]; -} - -static int send_contents; - -/* Send an argument STRING. */ -void -send_arg (string) - char *string; -{ - char *p = string; - if (fprintf (to_server, "Argument ") == EOF) - error (1, errno, "writing to server"); - while (*p) - { - if (*p == '\n') - { - if (fprintf (to_server, "\nArgumentx ") == EOF) - 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"); -} - -void -send_modified (file, short_pathname) - char *file; - char *short_pathname; -{ - /* File was modified, send it. */ - struct stat sb; - int fd; - char *buf; - char *mode_string; - int bufsize; - - /* 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); - - bufsize = sb.st_size; - buf = xmalloc (bufsize); - - fd = open (file, O_RDONLY); - if (fd < 0) - error (1, errno, "reading %s", short_pathname); - - if (gzip_level && sb.st_size > 100) - { - int nread, newsize = 0, gzip_status; - int size_left = bufsize; - pid_t gzip_pid; - char *bufp = buf; - int readsize = 8192; - - 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); - - 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 - { - if (read (fd, buf, sb.st_size) != sb.st_size) - error (1, errno, "reading %s", short_pathname); - if (close (fd) < 0) - error (0, errno, "warning: can't close %s", short_pathname); - - if (fprintf (to_server, "Modified %s\n%s\n%lu\n", file, - mode_string, (unsigned long) sb.st_size) == EOF) - error (1, errno, "writing to server"); - - /* - * Note that this only ends with a newline if the file ended with - * one. - */ - if (sb.st_size > 0) - if (fwrite (buf, sb.st_size, 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) == EOF) - error (1, errno, "writing to server"); - if (vers->entdata != NULL && vers->entdata->tag) - { - if (fprintf (to_server, "T%s", vers->entdata->tag) == EOF) - error (1, errno, "writing to server"); - } - else if (vers->entdata != NULL && vers->entdata->date) - if (fprintf (to_server, "D%s", vers->entdata->date) == EOF) - error (1, errno, "writing to server"); - if (fprintf (to_server, "\n") == EOF) - 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) == EOF) - 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); - } - else - { - /* Only use this request if the server supports it... */ - if (use_unchanged) - if (fprintf (to_server, "Unchanged %s\n", file) == EOF) - 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); - } - - 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; -{ - char *our_repos = NULL; - Dtype retval; - 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) == EOF) - 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, (int (*) ())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, "."); -} - -/* - * 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; - - 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); - 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. - */ - 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) == EOF) - 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 - - 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 */ -} diff --git a/src/client.h b/src/client.h deleted file mode 100644 index f487ee32ceafd788253bd0faa0489f362f0747ce..0000000000000000000000000000000000000000 --- a/src/client.h +++ /dev/null @@ -1,152 +0,0 @@ -/* Interface between the client and the rest of CVS. */ - -/* Stuff shared with the server. */ -extern char *mode_to_string PROTO((struct stat *)); -extern int change_mode PROTO((char *, char *)); - -/* - * 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; -/* Process ID of rsh subprocess. */ -extern int rsh_pid; - -/* Internal functions that handle client communication to server, etc. */ - -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)); - -/* - * 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; - - /* - * 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; - - /* 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[]; - -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 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)); diff --git a/src/commit.c b/src/commit.c deleted file mode 100644 index 0bb552ef97edf4de52bc186d59d1325c508c715d..0000000000000000000000000000000000000000 --- a/src/commit.c +++ /dev/null @@ -1,1910 +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" - -#ifndef lint -static 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, - 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((Node * p, 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)); -#ifdef CVSDEA -static char *ci_new_rev PROTO((char *rev, char *msg, char *rcs)); -static void mark_dead PROTO((char *file, char *repository, char *new_rev)); -#endif - -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; -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)) < 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'; - } - - 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) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (force_ci) - if (fprintf (to_server, "Argument -f\n") == EOF) - error (1, errno, "writing to server"); - if (!run_module_prog) - if (fprintf (to_server, "Argument -n\n") == EOF) - error (1, errno, "writing to server"); - option_with_arg ("-r", tag); - - send_files (argc, argv, local, 0); - - if (fprintf (to_server, "ci\n") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - /* XXX - this is not the perfect check for this */ - if (argc <= 0) - write_dirtag = tag; - - /* - * Run the recursion processor to find all the dirs to lock and lock all - * the dirs - */ - locklist = getlist (); - err = start_recursion ((int (*) ()) NULL, lock_filesdoneproc, - (Dtype (*) ()) NULL, (int (*) ()) 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, (int (*) ()) 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) - Node *p, *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: - case T_PATCH: - 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. - */ - if (server_active) - retcode = vers->ts_conflict[0] != '='; - else { - filestamp = time_stamp (file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); - } - 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 -s", GREP); - run_arg (RCS_MERGE_PAT); - run_arg (file); - retcode = run_exec (RUN_TTY, RUN_TTY, 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); - } - 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 (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-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, 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); - 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); - } - } - -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) - { - char *cp; - FILE *fp; - char line[MAXLINELEN]; - char *repository; - - /* It is not an error if Checkin.prog does not exist. */ - if ((fp = fopen (CVSADM_CIPROG, "r")) != NULL) - { - if (fgets (line, sizeof (line), fp) != NULL) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\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); - } - (void) fclose (fp); - } - } - - 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); - if (server_active) - server_set_sticky (update_dir, Name_Repository (dir, update_dir), - write_dirtag, (char *) NULL); - } - - 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; - Node *p; - RCSNode *rcsfile; - - corev = NULL; - 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 */ - run_setup ("%s%s -q -N%s", Rcsbin, RCS, tag); - 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 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. */ - 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); - lockflag = ""; - } else - { - corev = xstrdup (rev); - free (branchname); - } - } - - /* if removing without a tag or a branch, then make sure the default - branch is the trunk. */ - if (!tag && !branch) - { - run_setup ("%s%s -q -b", Rcsbin, RCS); - run_arg (rcs); - if (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0) - { - error (0, 0, "cannot change branch to default for %s", - rcs); - return (1); - } - } - - 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); - } - - /* 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 CVSDEA - { - char *new_rev; - new_rev = ci_new_rev (rev, message, rcs); - if (new_rev == NULL) - return 1; - mark_dead (file, repository, new_rev); - free (new_rev); - } -#else -#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", 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); - } -#endif /* CVSDEA */ - - 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 (2); - (void) 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))) - { - /* FIXME: should free tmp. */ - return (1); - } - free(tmp); - } - - 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_OPT); - (void) unlink_file (tmp); - (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); - run_setup ("%s%s -q -u", Rcsbin, RCS); - 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 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); - run_setup ("%s%s -q -b%s", Rcsbin, RCS, branch); - 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, - "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, srcfiles) - char *file; - char *repository; - char *tag; - List *srcfiles; -{ - FILE *fp; - char *cp; - 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 (2); - if (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); - /* 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); - - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT); - fp = fopen (fname, "r"); - /* If the file does not exist, no big deal. In particular, the - server does not (yet at least) create CVSEXT_OPT files. */ - if (fp == NULL) - { - if (errno != ENOENT) - error (1, errno, "cannot open %s", fname); - } - else - { - while (fgets (fname, sizeof (fname), fp) != NULL) - { - if ((cp = strrchr (fname, '\n')) != NULL) - *cp = '\0'; - if (*fname) - run_arg (fname); - } - (void) fclose (fp); - } - 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 CVSDEA - { - char *new_rev; - new_rev = ci_new_rev (NULL, tmp, rcs); - if (new_rev == NULL) - return 1; - mark_dead (file, repository, new_rev); - free (new_rev); - } -#else -#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); - } -#endif /* CVSDEA */ - - /* 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); - magicrev = RCS_magicrev (rcsfile, head); - run_setup ("%s%s -q -N%s:%s %s", Rcsbin, RCS, tag, magicrev, 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 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); - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT); - fp = open_file (fname, "r"); - while (fgets (fname, sizeof (fname), fp) != NULL) - { - if ((cp = strrchr (fname, '\n')) != NULL) - *cp = '\0'; - if (*fname) - run_arg (fname); - } - (void) fclose (fp); - 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) - { - run_setup ("%s%s -q -b", Rcsbin, RCS); - run_arg (rcs); - if (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL) != 0) - { - error (0, 0, "cannot change branch to default for %s", - rcs); - if (branch) - free (branch); - return (1); - } - } - run_setup ("%s%s -q -l", Rcsbin, RCS); - run_arg (rcs); - err = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - } - else - { - run_setup ("%s%s -q -l%s", Rcsbin, RCS, rev ? rev : ""); - run_arg (rcs); - (void) run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL); - } - - 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); - } -} - -#ifdef CVSDEA -/* Run RCS_CI and return a malloc'd array containing the numeric - revision for the new revision. */ -static char * -ci_new_rev (rev, msg, rcs) - char *rev; - char *msg; - char *rcs; -{ - int retcode; - char *tmpdir; - RCSNode *rcsnode; - - int retval_alloced; - int retval_used; - char *retval; - - tmpdir = getenv ("TMPDIR"); - if (tmpdir == NULL || tmpdir[0] == '\0') - tmpdir = "/tmp"; - - run_setup ("%s%s -f %s%s", Rcsbin, RCS_CI, rev ? "-r" : "", - rev ? rev : ""); - run_args ("-m%s", - (message == NULL - || *message == '\0' - || strcmp(message, "\n") == 0) ? - "*** empty log message ***\n" : 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 NULL; - } - - rcsnode = RCS_parsercsfile (rcs); - retval = - rev == NULL ? RCS_head (rcsnode) : RCS_getbranch (rcsnode, rev, 0); - freercsnode (&rcsnode); - return retval; -} - -static void -mark_dead (file, repository, new_rev) - char *file; - char *repository; - char *new_rev; -{ - mode_t omask; - char *deafilename = xmalloc (sizeof (CVSDEA) + strlen (repository) - + strlen (file) + 80); - FILE *deafile; - - /* Make the CVSDEA directory if we need to. */ - sprintf (deafilename, "%s/%s", repository, CVSDEA); - omask = umask (2); - if (mkdir (deafilename, 0777) != 0 && errno != EEXIST) - error (1, errno, "cannot make directory `%s'", deafilename); - (void) umask (omask); - - /* Now add NEW_REV to the revisions in the CVSDEA file for this file. */ - sprintf (deafilename, "%s/%s/%s", repository, CVSDEA, file); - deafile = open_file (deafilename, "a"); - if (fprintf (deafile, "%s\n", new_rev) == EOF) - error (1, errno, "cannot write %s", deafilename); - if (fclose (deafile) == EOF) - error (1, errno, "cannot close %s", deafilename); - free (deafilename); -} -#endif diff --git a/src/create_adm.c b/src/create_adm.c deleted file mode 100644 index d7cd8faec1eba5943bf41e5abc20a03d53e02939..0000000000000000000000000000000000000000 --- a/src/create_adm.c +++ /dev/null @@ -1,129 +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 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]; - - if (noexec) - return; - - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, OCVSADM); - else - (void) strcpy (tmp, OCVSADM); - if (isfile (tmp)) - error (1, 0, "there is a version in %s already", update_dir); - - 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) == EOF) - { - 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); - if (server_active) - server_set_sticky (update_dir, repository, tag, date); -} diff --git a/src/cvs.h b/src/cvs.h deleted file mode 100644 index ee04f522bf64c76d543ab84be791c9a0f8ac2dd0..0000000000000000000000000000000000000000 --- a/src/cvs.h +++ /dev/null @@ -1,479 +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 */ - -#define SERVER_SUPPORT 1 -#define CLIENT_SUPPORT 1 - -/* 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 */ -char *alloca (); -#endif /* not _AIX */ -#endif /* not HAVE_ALLOCA_H */ -#endif /* not __GNUC__ */ - -#if __STDC__ -#define CONST const -#define PTR void * -#else -#define CONST -#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) -#endif - - -#include <stdio.h> - -#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" -#include "server.h" -#include "client.h" - -#ifdef MY_NDBM -#include "myndbm.h" -#else -#include <ndbm.h> -#endif /* MY_NDBM */ - -#include "regex.h" -#include "getopt.h" -#include "wait.h" - -#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_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" - -/* - * The following are obsolete and are maintained here only so that they can be - * cleaned up during the transition - */ -#define OCVSADM "CVS.adm" /* for CVS 1.2 and earlier */ -#define CVSADM_FILE "CVS/Files" -#define CVSADM_MOD "CVS/Mod" - -/* - * 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_EDITINFO "editinfo" -#define CVSROOTADM_HISTORY "history" -#define CVSROOTADM_IGNORE "cvsignore" -#define CVSROOTADM_CHECKOUTLIST "checkoutlist" -#define CVSNULLREPOS "Emptydir" /* an empty directory */ - -/* support for the modules file (CVSROOTADM_MODULES) */ -#define CVSMODULE_OPTS "ad:i:lo:s:t:u:"/* options in modules file */ -#define CVSMODULE_SPEC '&' /* special delimiter */ - -/* - * The following are obsolete and are maintained here only so that they can be - * cleaned up during the transition - */ -#define OCVSROOTADM "CVSROOT.adm" /* for CVS 1.2 and earlier */ - -/* Other CVS file names */ -#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_OPT ",p" -#define CVSEXT_LOG ",t" -#define CVSPREFIX ",," -#define CVSDOTIGNORE ".cvsignore" - -/* Define to enable alternate death support (which doesn't require any - help from RCS). */ -/* #define CVSDEA "CVS.dea" */ - -/* Define to enable alternate death support (which uses the RCS state). */ -#define DEATH_STATE 1 - -#define DEATH_SUPPORT 1 - -/* 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 */ -#define DEVNULL "/dev/null" - -#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 "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 */ - -/* - * 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 */ - -/* The type of request that is being done in do_module() */ -enum mtype -{ - CHECKOUT, TAG, PATCH -}; - -/* - * 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 */ - T_PATCH, /* P Like C, but can patch */ - 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 *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 ParseEntries() and - * Version_TS(). - */ -struct stickydirtag -{ - int aflag; - char *tag; - char *date; - char *options; -}; - -/* 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 */ - -/* 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, *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 int gzip_level; - -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 */ -DBM *open_module PROTO((void)); -FILE *Fopen PROTO((char *name, char *mode)); -FILE *open_file PROTO((char *name, char *mode)); -List *Find_Dirs PROTO((char *repository, int which)); -List *ParseEntries 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((char *str)); -int No_Difference PROTO((char *file, Vers_TS * vers, List * entries, - char *repository, char *update_dir)); -int Parse_Info PROTO((char *infofile, char *repository, int PROTO((*callproc)) PROTO(()), int all)); -int Reader_Lock PROTO((char *xrepository)); -int SIG_register PROTO((int sig, RETSIGTYPE PROTO((*fn)) PROTO(()))); -int Writer_Lock PROTO((List * list)); -int ign_name PROTO((char *name)); -int isdir PROTO((char *file)); -int isfile PROTO((char *file)); -int islink PROTO((char *file)); -int isreadable PROTO((char *file)); -int iswritable PROTO((char *file)); -int joining PROTO((void)); -int link_file PROTO((char *from, char *to)); -int numdots PROTO((char *s)); -int run_exec PROTO((char *stin, char *stout, char *sterr, int flags)); -int unlink_file PROTO((char *f)); -int update PROTO((int argc, char *argv[])); -int xcmp PROTO((char *file1, char *file2)); -int yesno PROTO((void)); -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((char *from, char *to)); -void error PROTO((int status, int errnum, char *message,...)); -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((char *name)); -void make_directory PROTO((char *name)); -void rename_file PROTO((char *from, char *to)); -void run_arg PROTO((char *s)); -void run_print PROTO((FILE * fp)); -#ifdef HAVE_VPRINTF -void run_setup PROTO((char *fmt,...)); -void run_args PROTO((char *fmt,...)); -#else -void run_setup (); -void run_args (); -#endif -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)); -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)); -int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg, - int PROTO((*callback_proc)) (), char *where, int shorten, - int local_specified, int run_module_prog, char *extra_arg)); -int do_recursion PROTO((int PROTO((*xfileproc)) (), int PROTO((*xfilesdoneproc)) (), - Dtype PROTO((*xdirentproc)) (), int PROTO((*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((int PROTO((*fileproc)) (), int PROTO((*filesdoneproc)) (), - Dtype PROTO((*direntproc)) (), int PROTO((*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)); diff --git a/src/cvsbug.sh b/src/cvsbug.sh deleted file mode 100755 index 66d88eabcb2f8189d8ab9d5180af388eac218eae..0000000000000000000000000000000000000000 --- a/src/cvsbug.sh +++ /dev/null @@ -1,534 +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. -# Modified by Jim Blandy for Cyclic CVS. -# $CVSid: @(#)cvsbug.sh 1.2 94/10/22 $ -# -# 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=cyclic-cvs@cyclic.com - -## # 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="cvs-C1.4A" - -# 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. -MAIL_AGENT="/usr/lib/sendmail -oi -t" -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: -` - if [ -n "$ORGANIZATION" ]; then - echo "$ORGANIZATION" - else - echo " $ORGANIZATION_C" ; - fi ; -` ->Confidential: $CONFIDENTIAL_C ->Synopsis: $SYNOPSIS_C ->Severity: $SEVERITY_C ->Priority: $PRIORITY_C ->Category: $CATEGORY_C ->Class: $CLASS_C ->Release: `if [ -n "$DEFAULT_RELEASE" ]; then - echo "$DEFAULT_RELEASE" - else - echo " $RELEASE_C" - fi; ` ->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/src/cvsrc.c b/src/cvsrc.c deleted file mode 100644 index fedd0204c2ee286a37039b651892585c91c2e5f3..0000000000000000000000000000000000000000 --- a/src/cvsrc.c +++ /dev/null @@ -1,140 +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" - -#ifndef lint -static 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 *getenv (); -extern char *strtok (); - -void -read_cvsrc (argc, argv) - int *argc; - char ***argv; -{ - char *homedir; - char *homeinit; - FILE *cvsrcfile; - - char linebuf [MAXLINELEN]; - - char *optstart; - - 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 (access (homeinit, R_OK) != 0) - { - free (homeinit); - return; - } - - /* now scan the file until we find the line for the command in question */ - - cvsrcfile = open_file (homeinit, "r"); - while (fgets (linebuf, MAXLINELEN, cvsrcfile)) - { - /* skip over comment lines */ - if (linebuf[0] == '#') - continue; - - /* stop if we match the current command */ - if (!strncmp (linebuf, (*argv)[0], strlen ((*argv)[0]))) - { - found = 1; - break; - } - } - - fclose (cvsrcfile); - - if (found) - { - /* skip over command in the options line */ - optstart = strtok(linebuf+strlen((*argv)[0]), "\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")); - } - - /* 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/src/diff.c b/src/diff.c deleted file mode 100644 index 29eec0faadca486da843627de959dac0a89bdf04..0000000000000000000000000000000000000000 --- a/src/diff.c +++ /dev/null @@ -1,583 +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 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 (""); - - if (client_active) { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (empty_files) - if (fprintf (to_server, "Argument -N\n") == EOF) - error (1, errno, "writing to server"); - 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 */ - /* 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") == EOF) - error (1, errno, "writing to server"); - err = get_responses_and_close (); - free (options); - return (err); - } - - which = W_LOCAL; - if (diff_rev2 != NULL || diff_date2 != NULL) - which |= W_REPOS | W_ATTIC; - - /* 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]; - -#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); - - 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 (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 - */ -/* 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??? */ - 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) - { - 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) - { - 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/src/entries.c b/src/entries.c deleted file mode 100644 index 83d6bb20378af6f5b994dfd8882ed93b06ece9a3..0000000000000000000000000000000000000000 --- a/src/entries.c +++ /dev/null @@ -1,556 +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" - -#ifndef lint -static char rcsid[] = "$CVSid: @(#)entries.c 1.44 94/10/07 $"; -USE(rcsid) -#endif - -static Node *AddEntryNode PROTO((List * list, char *name, char *version, - char *timestamp, char *options, char *tag, - char *date, char *conflict)); - -static FILE *entfile; -static char *entfilename; /* for error messages */ - -/* - * Write out the line associated with a node of an entries file - */ -static int -write_ent_proc (node, closure) - Node *node; - void *closure; -{ - Entnode *p; - - p = (Entnode *) node->data; - if (fprintf (entfile, "/%s/%s/%s", node->key, p->version, - p->timestamp) == EOF) - error (1, errno, "cannot write %s", entfilename); - if (p->conflict) - { - if (fprintf (entfile, "+%s", p->conflict) == EOF) - error (1, errno, "cannot write %s", entfilename); - } - if (fprintf (entfile, "/%s/", p->options) == EOF) - error (1, errno, "cannot write %s", entfilename); - - if (p->tag) - { - if (fprintf (entfile, "T%s\n", p->tag) == EOF) - error (1, errno, "cannot write %s", entfilename); - } - else if (p->date) - { - if (fprintf (entfile, "D%s\n", p->date) == EOF) - error (1, errno, "cannot write %s", entfilename); - } - else if (fprintf (entfile, "\n") == EOF) - 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); -} - -/* - * Removes the argument file from the Entries file if necessary. - */ -void -Scratch_Entry (list, fname) - List *list; - char *fname; -{ - Node *node; - - if (trace) - (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname); - - /* hashlookup to see if it is there */ - if ((node = findnode (list, fname)) != NULL) - { - delnode (node); /* delete the node */ - if (server_active) - server_scratch (fname); - 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; -{ - int should_write_file = !noexec; - Node *node; - -#ifdef SERVER_SUPPORT - if (server_active) - { - server_register (fname, vn, ts, options, tag, date, ts_conflict); - } -#endif - - if (trace) - { - (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n", - fname, vn, ts, - ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "", - options, tag ? tag : "", date ? date : ""); - } - - /* was it already there? */ - if ((node = findnode (list, fname)) != NULL) - { - /* take it out */ - delnode (node); - - /* add the new one and re-write the file */ - (void) AddEntryNode (list, fname, vn, ts, options, tag, - date, ts_conflict); - - if (should_write_file) - write_entries (list); - } - else - { - /* add the new one */ - node = AddEntryNode (list, fname, vn, ts, options, tag, - date, ts_conflict); - - if (should_write_file) - { - /* append it to the end */ - entfilename = CVSADM_ENT; - entfile = open_file (entfilename, "a"); - (void) write_ent_proc (node, NULL); - if (fclose (entfile) == EOF) - error (1, errno, "error closing %s", entfilename); - } - } -} - -/* - * 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); -} - -/* - * Read the entries file into a list, hashing on the file name. - */ -List * -ParseEntries (aflag) - int aflag; -{ - List *entries; - char line[MAXLINELEN]; - char *cp, *user, *vn, *ts, *options; - char *tag_or_date, *tag, *date, *ts_conflict; - char *dirtag, *dirdate; - int lineno = 0; - int do_rewrite = 0; - FILE *fpin; - - vn = ts = options = tag = date = ts_conflict = 0; - - /* 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; - } - - again: - fpin = fopen (CVSADM_ENT, "r"); - if (fpin == NULL) - error (0, errno, "cannot open %s for reading", CVSADM_ENT); - else - { - while (fgets (line, sizeof (line), fpin) != NULL) - { - lineno++; - if (line[0] == '/') - { - 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) - { - extern char *ctime (); - char *c = ctime (&sb.st_mtime); - - if (!strncmp (ts + 25, c, 24)) - ts = time_stamp (user); - else - { - ts += 24; - ts[0] = '*'; - } - do_rewrite = 1; - } - } - - (void) AddEntryNode (entries, user, vn, ts, options, tag, - date, ts_conflict); - } - else - { - /* try conversion only on first line */ - if (lineno == 1) - { - (void) fclose (fpin); - check_entries ((char *) NULL); - goto again; - } - } - } - } - - 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); -} - -/* - * Look at the entries file to determine if it is in the old entries format. - * If so, convert it to the new format. - */ -void -check_entries (dir) - char *dir; -{ - FILE *fpin, *fpout; - char tmp[MAXLINELEN]; - char line[MAXLINELEN]; - char entname[MAXLINELEN]; - char entbak[MAXLINELEN]; - char *cp, *user, *rev, *ts, *opt; - - if (dir != NULL) - { - (void) sprintf (entname, "%s/%s", dir, CVSADM_ENT); - (void) sprintf (entbak, "%s/%s", dir, CVSADM_ENTBAK); - } - else - { - (void) strcpy (entname, CVSADM_ENT); - (void) strcpy (entbak, CVSADM_ENTBAK); - } - - fpin = open_file (entname, "r"); - if (fgets (line, sizeof (line), fpin) == NULL) - { - (void) fclose (fpin); - return; - } - (void) fclose (fpin); - if (line[0] != '/') - { - rename_file (entname, entbak); - fpin = open_file (entbak, "r"); - fpout = open_file (entname, "w+"); - while (fgets (line, sizeof (line), fpin) != NULL) - { - if (line[0] == '/') - { - if (fputs (line, fpout) == EOF) - error (1, errno, "cannot write %s", CVSADM_ENT); - continue; - } - rev = line; - if ((ts = strchr (line, '|')) == NULL) - continue; - *ts++ = '\0'; - if ((user = strrchr (ts, ' ')) == NULL) - continue; - *user++ = '\0'; - if ((cp = strchr (user, '|')) == NULL) - continue; - *cp = '\0'; - opt = ""; -#ifdef HAVE_RCS5 -#ifdef HAD_RCS4 - opt = "-V4"; -#endif -#endif - if (fprintf (fpout, "/%s/%s/%s/%s/\n", user, rev, ts, opt) == EOF) - error (1, errno, "cannot write %s", CVSADM_ENT); - } - (void) fclose (fpin); - if (fclose (fpout) == EOF) - error (1, errno, "cannot close %s", entname); - - /* clean up any old Files or Mod files */ - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_FILE); - else - (void) strcpy (tmp, CVSADM_FILE); - if (isfile (tmp)) - (void) unlink (tmp); - - if (dir != NULL) - (void) sprintf (tmp, "%s/%s", dir, CVSADM_MOD); - else - (void) strcpy (tmp, CVSADM_MOD); - if (isfile (tmp)) - (void) unlink (tmp); - } -} - -/* - * 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; - free (p->version); - free (p->timestamp); - free (p->options); - if (p->tag) - free (p->tag); - if (p->date) - free (p->date); - if (p->conflict) - free (p->conflict); - free ((char *) p); -} - -/* - * Get an Entries file list node, initialize it, and add it to the specified - * list - */ -static Node * -AddEntryNode (list, name, version, timestamp, options, tag, date, conflict) - List *list; - char *name; - char *version; - char *timestamp; - char *options; - char *tag; - char *date; - char *conflict; -{ - Node *p; - Entnode *entdata; - - /* 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 */ - p->key = xstrdup (name); - - /* malloc the data parts and fill them in */ - p->data = xmalloc (sizeof (Entnode)); - entdata = (Entnode *) p->data; - entdata->version = xstrdup (version); - entdata->timestamp = xstrdup (timestamp); - entdata->options = xstrdup (options); - if (entdata->options == NULL) - entdata->options = xstrdup ("");/* must be non-NULL */ - entdata->conflict = xstrdup (conflict); - entdata->tag = xstrdup (tag); - entdata->date = xstrdup (date); - - /* put the node into the list */ - if (addnode (list, p) != 0) - error (0, 0, "Duplicate filename in entries file (%s) -- ignored", - name); - - 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) == EOF) - error (1, errno, "write to %s failed", tmp); - } - else - { - if (fprintf (fout, "D%s\n", date) == EOF) - 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 && errno != ENOENT) - 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; - char line[MAXLINELEN]; - char *cp; - - if (tagp) - *tagp = (char *) NULL; - if (datep) - *datep = (char *) NULL; - fp = fopen (CVSADM_TAG, "r"); - if (fp) - { - if (fgets (line, sizeof (line), fp) != NULL) - { - if ((cp = strrchr (line, '\n')) != NULL) - *cp = '\0'; - if (*line == 'T' && tagp) - *tagp = xstrdup (line + 1); - else if (*line == 'D' && datep) - *datep = xstrdup (line + 1); - } - (void) fclose (fp); - } -} diff --git a/src/find_names.c b/src/find_names.c deleted file mode 100644 index b6a2fa186cae30f4c883c2e5feb54f5ff93fa134..0000000000000000000000000000000000000000 --- a/src/find_names.c +++ /dev/null @@ -1,281 +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 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 (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 (p, q) - Node *p, *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 = ParseEntries (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 - dellist (&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 || -#ifdef CVSDEA - strcmp (dp->d_name, CVSDEA) == 0 || -#endif - 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)) - { - /* and old style */ - (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, OCVSADM); - 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/src/hash.c b/src/hash.c deleted file mode 100644 index afc554d32edd4956b74e99d6abf60057dad331b2..0000000000000000000000000000000000000000 --- a/src/hash.c +++ /dev/null @@ -1,399 +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 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) - 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; - 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) (); - 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) (); -{ - 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>"); -} - -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/src/hash.h b/src/hash.h deleted file mode 100644 index 8e10e812601ff0aaec76177f2e4a96786351a899..0000000000000000000000000000000000000000 --- a/src/hash.h +++ /dev/null @@ -1,66 +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; - -struct entnode -{ - char *version; - char *timestamp; - char *options; - char *tag; - char *date; - char *conflict; -}; -typedef struct entnode Entnode; - -List *getlist PROTO((void)); -Node *findnode PROTO((List * list, char *key)); -Node *getnode PROTO((void)); -int addnode PROTO((List * list, Node * p)); -int walklist PROTO((List * list, int PROTO((*proc)) PROTO((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 PROTO((*comp))())); diff --git a/src/history.c b/src/history.c deleted file mode 100644 index aa7a201b8faf29a958ea2efa96ab9780eda5b3fc..0000000000000000000000000000000000000000 --- a/src/history.c +++ /dev/null @@ -1,1475 +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 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 int histsize; -static char *histdata; -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\"."); - - 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) - if (fprintf (to_server, "Argument -T\n") == EOF) - error (1, errno, "writing to server"); - if (all_users) - if (fprintf (to_server, "Argument -a\n") == EOF) - error (1, errno, "writing to server"); - if (modified) - if (fprintf (to_server, "Argument -c\n") == EOF) - error (1, errno, "writing to server"); - if (last_entry) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (v_checkout) - if (fprintf (to_server, "Argument -o\n") == EOF) - error (1, errno, "writing to server"); - if (working) - if (fprintf (to_server, "Argument -w\n") == EOF) - error (1, errno, "writing to server"); - if (histfile) - if (fprintf (to_server, "Argument -X\n") == EOF) - error (1, errno, "writing to server"); - 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) - if (fprintf (to_server, "Argument -m\n") == EOF) - error (1, errno, "writing to server"); - 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") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - 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 */ - FILE *fp; - 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 (!(fp = Fopen (fname, "a"))) /* Some directory not there! */ - return; - - 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 (fprintf (fp, "%c%08x|%s|%s|%s|%s|%s\n", type, time ((time_t *) NULL), - username, workdir, repos, revs ? revs : "", name) == EOF) - error (1, errno, "cannot write to history file: %s", fname); - (void) fclose (fp); -} - -/* - * 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"); - histdata = cp = xmalloc (i + 2); - histsize = i; - - 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/src/ignore.c b/src/ignore.c deleted file mode 100644 index 0005f40dd6a1a32cf45715789c6a6f5d156d5759..0000000000000000000000000000000000000000 --- a/src/ignore.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com> - */ - -#include "cvs.h" - -#ifndef lint -static 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 */ - -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 () -{ - extern char *getenv (); - 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); - - /* Then add entries found in repository, if it exists */ - (void) sprintf (file, "%s/%s/%s", CVSroot, CVSROOTADM, CVSROOTADM_IGNORE); - if (isfile (file)) - 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); - if (isfile (file)) - 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 */ - if (!(fp = fopen (file, "r"))) - return; - while (fgets (line, sizeof (line), fp)) - ign_add (line, hold); - (void) fclose (fp); -} - -/* 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/src/import.c b/src/import.c deleted file mode 100644 index b9252d0d43a4a55ef5f3fb2c76a94679c4828d1c..0000000000000000000000000000000000000000 --- a/src/import.c +++ /dev/null @@ -1,1153 +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" - -#ifndef lint -static 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 str2expmode PROTO((char const* expstring)); -static int strn2expmode PROTO((char const* expstring, size_t n)); - -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 [-Qq] [-d] [-k subst] [-I ign] [-m msg] [-b branch]\n", - " repository vendor-tag release-tags...\n", - "\t-Q\tReally quiet.\n", - "\t-q\tSomewhat quiet.\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", - 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", - 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 (); - - (void) strcpy (vbranch, CVSBRANCH); - optind = 1; - while ((c = getopt (argc, argv, "Qqdb:m:I:k:")) != -1) - { - switch (c) - { - case 'Q': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - 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': - if (str2expmode(optarg) != -1) - keyword_opt = optarg; - else - usage (keyword_usage); - 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 */ - RCS_check_tag (argv[i]); - - /* XXX - this should be a module, not just a pathname */ - if (argv[0][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'; - - 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 (); - } - - 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; - } - - if (client_active) - { - int err; - - ign_setup (); - - if (quiet) - if (fprintf (to_server, "Argument -q\n") == EOF) - error (1, errno, "writing to server"); - if (really_quiet) - if (fprintf (to_server, "Argument -Q\n") == EOF) - error (1, errno, "writing to server"); - if (use_file_modtime) - if (fprintf (to_server, "Argument -d\n") == EOF) - error (1, errno, "writing to server"); - - 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; - err = import_descend (message, argv[1], argc - 2, argv + 2); - client_import_done (); - if (fprintf (to_server, "import\n") == EOF) - error (1, errno, "writing to server"); - err += get_responses_and_close (); - return err; - } - - /* - * Make all newly created directories writable. Should really use a more - * sophisticated security mechanism here. - */ - (void) umask (2); - 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); - - 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; - int has_dirs = 0; - - /* first, load up any per-directory ignore lists */ - ign_add_file (CVSDOTIGNORE, 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 (isdir (dp->d_name)) - { - has_dirs = 1; - } - else - { - if (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 (has_dirs) - { - if ((dirp = opendir (".")) == NULL) - err++; - else - { - while ((dp = readdir (dirp)) != NULL) - { - if (!strcmp(".", dp->d_name) || !strcmp("..", dp->d_name)) - continue; - if (!isdir (dp->d_name) || ign_name (dp->d_name)) - continue; - err += import_descend_dir (message, dp->d_name, - vtag, targc, targv); - /* need to re-load .cvsignore after each dir traversal */ - ign_add_file (CVSDOTIGNORE, 1); - } - (void) closedir (dirp); - } - } - 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; - - 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); - } - different = xcmp (xtmpfile, vfile); - (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; - int retcode = 0; - - if (noexec) - return (0); - - locked = 0; - if (vers != NULL) - { - run_setup ("%s%s -q -l%s", Rcsbin, RCS, vbranch); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, DEVNULL, DEVNULL, RUN_NORMAL)) == 0) - locked = 1; - else if (retcode == -1) - { - error (0, errno, "fork failed"); - return (1); - } - } - if (link_file (vfile, FILE_HOLDER) < 0) - { - if (errno == EEXIST) - { - (void) unlink_file (FILE_HOLDER); - (void) link_file (vfile, FILE_HOLDER); - } - else - { - ierrno = errno; - fperror (logfp, 0, ierrno, "ERROR: cannot create link to %s", vfile); - error (0, ierrno, "ERROR: cannot create link to %s", vfile); - return (1); - } - } - run_setup ("%s%s -q -f -r%s", Rcsbin, RCS_CI, vbranch); - run_args ("-m%s", message); - if (use_file_modtime) - run_arg ("-d"); - run_arg (rcs); - status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - ierrno = errno; - rename_file (FILE_HOLDER, vfile); - 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) - { - run_setup ("%s%s -q -u%s", Rcsbin, RCS, vbranch); - run_arg (rcs); - (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - } - 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); - - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, vtag, vbranch); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 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++) - { - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, targv[i], vers->vn_rcs); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 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; -}; - -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", "// ", - "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 */ - "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 */ - "", "# ", /* 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, mode, ierrno, err = 0; - - if (noexec) - return (0); - - fprcs = open_file (rcs, "w+"); - fpuser = open_file (user, "r"); - - /* - * putadmin() - */ - if (fprintf (fprcs, "head %s;\n", vhead) == EOF || - fprintf (fprcs, "branch %s;\n", vbranch) == EOF || - fprintf (fprcs, "access ;\n") == EOF || - fprintf (fprcs, "symbols ") == EOF) - { - goto write_error; - } - - for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */ - if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) == EOF) - goto write_error; - - if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) == EOF || - fprintf (fprcs, "locks ; strict;\n") == EOF || - /* XXX - make sure @@ processing works in the RCS file */ - fprintf (fprcs, "comment @%s@;\n", get_comment (user)) == EOF) - { - goto write_error; - } - - if (keyword_opt != NULL) - if (fprintf (fprcs, "expand @%s@;\n", keyword_opt) == EOF) - { - goto write_error; - } - - if (fprintf (fprcs, "\n") == EOF) - 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) == EOF || - fprintf (fprcs, "date %s; author %s; state Exp;\n", - altdate1, author) == EOF || - fprintf (fprcs, "branches %s.1;\n", vbranch) == EOF || - fprintf (fprcs, "next ;\n") == EOF || - fprintf (fprcs, "\n%s.1\n", vbranch) == EOF || - fprintf (fprcs, "date %s; author %s; state Exp;\n", - altdate2, author) == EOF || - fprintf (fprcs, "branches ;\n") == EOF || - fprintf (fprcs, "next ;\n\n") == EOF || - /* - * putdesc() - */ - fprintf (fprcs, "\ndesc\n") == EOF || - fprintf (fprcs, "@@\n\n\n") == EOF || - /* - * putdelta() - */ - fprintf (fprcs, "\n%s\n", vhead) == EOF || - fprintf (fprcs, "log\n") == EOF || - fprintf (fprcs, "@Initial revision\n@\n") == EOF || - fprintf (fprcs, "text\n@") == EOF) - { - 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) == EOF) - { - free (buf); - goto write_error; - } - free (buf); - } - if (fprintf (fprcs, "@\n\n") == EOF || - fprintf (fprcs, "\n%s.1\n", vbranch) == EOF || - fprintf (fprcs, "log\n@") == EOF || - expand_at_signs (message, (off_t) strlen (message), fprcs) == EOF || - fprintf (fprcs, "@\ntext\n") == EOF || - fprintf (fprcs, "@@\n") == EOF) - { - goto write_error; - } - if (fclose (fprcs) == EOF) - { - ierrno = errno; - goto write_error_noclose; - } - (void) fclose (fpuser); - - /* - * Fix the modes on the RCS files. They must maintain the same modes as - * the original user file, except that all write permissions must be - * turned off. - */ - mode = sb.st_mode & ~(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++; - } - 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"); - } - return (err + 1); -} - -/* - * Sigh.. need to expand @ signs into double @ signs - */ -static int -expand_at_signs (buf, size, fp) - char *buf; - off_t size; - FILE *fp; -{ - char *cp, *end; - - for (cp = buf, end = buf + size; cp < end; cp++) - { - if (*cp == '@') - (void) putc ('@', fp); - if (putc (*cp, fp) == EOF) - 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[]; -{ - char cwd[PATH_MAX]; - char *cp; - int ierrno, err; - - if (islink (dir)) - return (0); - if (getwd (cwd) == NULL) - { - fperror (logfp, 0, 0, "ERROR: cannot get working directory: %s", cwd); - error (0, 0, "ERROR: cannot get working directory: %s", cwd); - 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 && 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 (chdir (cwd) < 0) - error (1, errno, "cannot chdir to %s", cwd); - return (err); -} - -/* the following code is taken from code in rcs/src/rcssyn.c, and returns a - * positive value if 'expstring' contains a valid RCS expansion token for - * the -k option. If an invalid expansion is named, then return -1. - */ - -char const *const expand_names[] = { - /* These must agree with *_EXPAND in rcs/src/rcsbase.h. */ - "kv","kvl","k","v","o", - 0 -}; - -static int -str2expmode(s) - char const *s; -/* Yield expand mode corresponding to S, or -1 if bad. */ -{ - return strn2expmode(s, strlen(s)); -} - -static int -strn2expmode(s, n) - char const *s; - size_t n; -{ - char const *const *p; - - for (p = expand_names; *p; ++p) - if (memcmp(*p,s,n) == 0 && !(*p)[n]) - return p - expand_names; - return -1; -} - diff --git a/src/lock.c b/src/lock.c deleted file mode 100644 index 060adc3bdf00cc9b4bbdb24d10fbc4b3ac3523b6..0000000000000000000000000000000000000000 --- a/src/lock.c +++ /dev/null @@ -1,548 +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 char rcsid[] = "$CVSid: @(#)lock.c 1.50 94/09/30 $"; -USE(rcsid) -#endif - -extern char *ctime (); - -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 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_LOCK_OWNED 2 /* lock already owned by us */ -#define L_LOCKED 3 /* 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]; - struct stat sb; - - if (readlock[0] != '\0') - { - (void) sprintf (tmp, "%s/%s", repository, readlock); - if (unlink (tmp) < 0 && errno != ENOENT) - error (0, errno, "failed to remove lock %s", tmp); - } - - if (writelock[0] != '\0') - { - (void) sprintf (tmp, "%s/%s", repository, writelock); - if (unlink (tmp) < 0 && errno != ENOENT) - 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 (stat (tmp, &sb) != -1 && sb.st_uid == geteuid ()) - { - (void) rmdir (tmp); - } - } - cleanup_lckdir = 0; -} - -/* - * 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 && errno != ENOENT) - 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 && errno != ENOENT) - 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 || status == L_LOCK_OWNED) - { - /* 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) - { - if (rmdir (tmp) < 0) - error (0, errno, "failed to remove lock dir `%s'", tmp); - } - - /* 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 && errno != ENOENT) - 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) - { - if (closedir (dirp) < 0) - error (0, errno, - "error closing directory %s", repository); - goto again; - } -#endif - set_lockers_name (&sb); - } - - ret = 1; - break; - } - errno = 0; - } - if (errno != 0) - error (0, errno, "error reading directory %s", repository); - - if (closedir (dirp) < 0) - error (0, errno, "error closing directory %s", repository); - 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%d", 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; -#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 (;;) - { - SIG_beginCrSect (); - if (mkdir (masterlock, 0777) == 0) - { - cleanup_lckdir = 1; - SIG_endCrSect (); - return (L_OK); - } - SIG_endCrSect (); - - 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 (errno == ENOENT) - continue; - - error (0, errno, "couldn't stat lock directory `%s'", masterlock); - return (L_ERROR); - } - - /* - * if we already own the lock, go ahead and return 1 which means it - * existed but we owned it - */ - if (sb.st_uid == geteuid () && !will_wait) - return (L_LOCK_OWNED); - -#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)) - { - 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() -{ - 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/src/log.c b/src/log.c deleted file mode 100644 index 8ba8f46abd71e8a026b1675c48b5b2f5d132316c..0000000000000000000000000000000000000000 --- a/src/log.c +++ /dev/null @@ -1,260 +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 - * - * 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 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 void log_option_with_arg PROTO((char *name, char **var, char *opt)); - -static char options[PATH_MAX]; - -static const char *const log_usage[] = -{ - "Usage: %s %s [-l] [rlog-options] [files...]\n", - "\t-l\tLocal directory only, no recursion.\n", - NULL -}; - -int -cvslog (argc, argv) - int argc; - char *argv[]; -{ - int i; - int numopt = 1; - int err = 0; - int local = 0; - char *dates_opt = 0; - char *revisions_opt = 0; - char *states_opt = 0; - char *who_opt = 0; - - if (argc == -1) - usage (log_usage); - - /* - * All 'log' command options except -l are passed directly on to 'rlog' - */ - options[0] = '\0'; /* Assume none */ - for (i = 1; i < argc; i++) - { - if (argv[i][0] == '-' || argv[i][0] == '\0') - { - numopt++; - switch (argv[i][1]) - { - case 'l': - local = 1; - break; - case 'd': - log_option_with_arg ("date list", - &dates_opt, argv[i]); - break; - case 'r': - log_option_with_arg ("revision list", - &revisions_opt, argv[i]); - break; - case 's': - log_option_with_arg ("state list", - &states_opt, argv[i]); - break; - case 'w': - log_option_with_arg ("user list", - &who_opt, argv[i]); - break; - default: - (void) strcat (options, " "); - (void) strcat (options, argv[i]); - break; - } - } - } - argc -= numopt; - argv += numopt; - - if (client_active) { - /* We're the local client. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - send_option_string (options); - if (dates_opt) send_arg (dates_opt); - if (revisions_opt) send_arg (revisions_opt); - if (states_opt) send_arg (states_opt); - if (who_opt) send_arg (who_opt); - -#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, argv); -#else - send_files (argc, argv, local, 0); -#endif - - if (fprintf (to_server, "log\n") == EOF) - error (1, errno, "writing to server"); - err = get_responses_and_close (); - return err; - } - - err = start_recursion (log_fileproc, (int (*) ()) NULL, log_dirproc, - (int (*) ()) NULL, argc, argv, local, - W_LOCAL | W_REPOS | W_ATTIC, 0, 1, - (char *) NULL, 1, 0); - return (err); -} - - -/* Append an option to the options string. */ -static void -log_option_with_arg (name, var, opt) - char *name; - char **var; - char *opt; -{ - if (*var) - error (1, 0, "only one %s can be specified", name); - *var = opt; - if (! client_active) - { - (void) strcat (options, " "); - (void) strcat (options, opt); - } -} - -/* - * 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); - } - -#ifdef CVSDEA - /* Print information on dead revisions. Printing them at the - start rather than with each revision is cheesy, but no more so - than printing the symbolic tags at the start. */ - { - char *deafilename; - FILE *deafile; - int ch; - deafilename = xmalloc (strlen (repository) + sizeof (CVSDEA) + - strlen (file) + 80); - sprintf (deafilename, "%s/%s/%s", repository, CVSDEA, file); - deafile = fopen (deafilename, "r"); - if (deafile == NULL) - { - if (errno != ENOENT) - error (0, errno, "cannot read %s", deafilename); - } - else - { - int printed = 0; - while (1) - { - ch = getc (deafile); - if (ferror (deafile)) - error (1, errno, "cannot read %s", deafilename); - if (feof (deafile)) - break; - if (!printed) - { - printed = 1; - printf ("Dead revisions: "); - } - if (ch == '\012') - putc (' ', stdout); - else - putc (ch, stdout); - } - if (printed) - putc ('\n', stdout); - if (fclose (deafile) == EOF) - error (0, errno, "cannot close %s", deafilename); - } - free (deafilename); - } -#endif /* CVSDEA */ - - run_setup ("%s%s %s", Rcsbin, RCS_RLOG, options); - run_arg (rcsfile->path); - 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/src/logmsg.c b/src/logmsg.c deleted file mode 100644 index 6d24376d6b2e8230e10b4e69038372c837675e93..0000000000000000000000000000000000000000 --- a/src/logmsg.c +++ /dev/null @@ -1,461 +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 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 *strlist; -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[MAXLINELEN], 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) - (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 */ - (void) fclose (fp); - 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'; - } - -/* !!! XXX FIXME: fgets is broken. This should not have any line - length limits. */ - - if (*messagep) - { - p = *messagep; - while (fgets (line, sizeof (line), fp) != NULL) - { - if (strncmp (line, CVSEDITPREFIX, sizeof (CVSEDITPREFIX) - 1) == 0) - continue; - (void) strcpy (p, line); - p += strlen (line); - } - } - (void) fclose (fp); - 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 = '\0'; - (void) fgets (line, sizeof (line), stdin); - if (*line == '\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"); - } - } - (void) unlink_file (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; - char line[MAXLINELEN]; - - /* nothing to do if the last one included is the same as this one */ - if (last_template && strcmp (last_template, template) == 0) - return (0); - if (last_template) - free (last_template); - last_template = xstrdup (template); - - if ((tfp = fopen (template, "r")) != NULL) - { - while (fgets (line, sizeof (line), tfp) != NULL) - (void) fputs (line, fp); - (void) fclose (tfp); - return (0); - } - else - { - error (0, 0, "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 (!strlist) - strlist = xmalloc (MAXLISTLEN); - strlist[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 (strlist) + 1 + 2); /* for 's */ - (void) sprintf (title, "'%s%s'", srepos, strlist); - - /* to be nice, free up this chunk of memory */ - free (strlist); - strlist = (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 strlist - */ -static int -title_proc (p, closure) - Node *p; - void *closure; -{ - if (p->data == (char *) type) - { - (void) strcat (strlist, " "); - (void) strcat (strlist, 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; - - /* - * 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"); - (void) 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/src/main.c b/src/main.c deleted file mode 100644 index d9d9d29838b7e150b2d71c4ed96446fd24a593b4..0000000000000000000000000000000000000000 --- a/src/main.c +++ /dev/null @@ -1,644 +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 - * 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> -#include <pwd.h> -#ifndef HAVE_KRB_GET_ERR_TEXT -#define krb_get_err_text(status) krb_err_txt[status] -#endif -#endif - -#ifndef lint -static char rcsid[] = "$CVSid: @(#)main.c 1.78 94/10/07 $\n"; -USE(rcsid) -#endif - -extern char *getenv (); - -char *program_name; -char *command_name = ""; - -/* - * Since some systems don't define this... - */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -char hostname[MAXHOSTNAMELEN]; - -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; - -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)); -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. */ - int (*client_func) (); /* Function to do it via the protocol. */ -} cmds[] = - -{ - { "add", "ad", "new", add, client_add }, - { "admin", "adm", "rcs", admin, client_admin }, - { "checkout", "co", "get", checkout, client_checkout }, - { "commit", "ci", "com", commit, client_commit }, - { "diff", "di", "dif", diff, client_diff }, - { "export", "exp", "ex", checkout, client_export }, - { "history", "hi", "his", history, client_history }, - { "import", "im", "imp", import, client_import }, - { "log", "lo", "rlog", cvslog, client_log }, - { "rdiff", "patch", "pa", patch, client_rdiff }, - { "release", "re", "rel", release, client_release }, - { "remove", "rm", "delete", cvsremove, client_remove }, - { "status", "st", "stat", status, client_status }, - { "rtag", "rt", "rfreeze", rtag, client_rtag }, - { "tag", "ta", "freeze", tag, client_tag }, - { "update", "up", "upd", update, client_update }, - - /* - * 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. - */ - { "server", "server", "server", server, server }, - { NULL, NULL, NULL, NULL, NULL }, -}; - -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", - " -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", - " -z # Use 'gzip -#' for net traffic if possible.\n", - "\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", - " 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); -} - -int -main (argc, argv) - int argc; - char *argv[]; -{ - extern char *version_string; - char *cp; - const struct cmd *cm; - int c, help = FALSE, err = 0; - int rcsbin_update_env, cvs_update_env = 0; - char tmp[PATH_MAX]; - - /* - * Just save the last component of the path for error messages - */ - if ((program_name = strrchr (argv[0], '/')) == NULL) - program_name = argv[0]; - else - program_name++; - - 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; - if ((cp = getenv (CVSROOT_ENV)) != NULL) - { - CVSroot = cp; - cvs_update_env = 0; /* it's already there */ - } - if (getenv (CVSREAD_ENV) != NULL) - cvswrite = FALSE; - - optind = 1; - while ((c = getopt (argc, argv, "Qqrwtnlvb:e:d:Hfz:")) != -1) - { - switch (c) - { - case 'Q': - really_quiet = TRUE; - /* FALL THROUGH */ - case 'q': - quiet = TRUE; - break; - case 'r': - cvswrite = FALSE; - break; - case 'w': - cvswrite = TRUE; - break; - case 't': - trace = TRUE; - break; - case 'n': - noexec = TRUE; - case 'l': /* Fall through */ - logoff = TRUE; - break; - case 'v': - (void) fputs (version_string, stdout); - (void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL); - (void) fputs (tmp, stdout); - (void) fputs ("\nCopyright (c) 1993-1994 Brian Berliner\nCopyright (c) 1993-1994 david d `zoo' zuhn\nCopyright (c) 1992, Brian Berliner and Jeff Polk\nCopyright (c) 1989-1992, Brian Berliner\n\nCVS may be copied only under the terms of the GNU General Public License,\na copy of which can be found with the CVS distribution kit.\n", stdout); - exit (0); - 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; - 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; - case '?': - default: - usage (usg); - } - } - 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 */ - -#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) - { - 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 ((strcmp (CVSroot, CVSADM_Root) != 0) && - !same_directories(CVSroot, CVSADM_Root)) - { - error (0, 0, "%s value for CVS Root found in %s", - CVSADM_Root, CVSADM_ROOT); - if (cvs_update_env) - { - 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 "); - } - else - { - error (0, 0, - "does not match CVSROOT environment value of %s", - CVSroot); - error (1, 0, - "you may wish to unsetenv CVSROOT and try again"); - } - } - } - } -#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 (access (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) && access (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 */ - (void) SIG_register (SIGHUP, main_cleanup); - (void) SIG_register (SIGINT, main_cleanup); - (void) SIG_register (SIGQUIT, main_cleanup); - (void) SIG_register (SIGPIPE, main_cleanup); - (void) SIG_register (SIGTERM, main_cleanup); - - (void) SIG_register (SIGHUP, Lock_Cleanup); - (void) SIG_register (SIGINT, Lock_Cleanup); - (void) SIG_register (SIGQUIT, Lock_Cleanup); - (void) SIG_register (SIGPIPE, Lock_Cleanup); - (void) SIG_register (SIGTERM, Lock_Cleanup); - - 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/src/mkmodules.c b/src/mkmodules.c deleted file mode 100644 index 1527beaf67fdd67d132b8a51a6232104d432e24d..0000000000000000000000000000000000000000 --- a/src/mkmodules.c +++ /dev/null @@ -1,418 +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 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; -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[]; -{ - extern char *getenv (); - 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_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"}, - {NULL, NULL}}; - - /* - * Just save the last component of the path for error messages - */ - if ((program_name = strrchr (argv[0], '/')) == NULL) - program_name = argv[0]; - else - program_name++; - - 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> - */ - for (; fgets (line, sizeof (line), fp) != NULL;) - { - 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]; - - (void) sprintf (dotdir, "%s.dir", temp); - (void) sprintf (dotpag, "%s.pag", temp); - (void) unlink_file (dotdir); - (void) unlink_file (dotpag); - error (1, 0, "DBM creation failed; correct above errors"); - } -} - -static void -rename_dbmfile (temp) - char *temp; -{ - char newdir[50], newpag[50]; - char dotdir[50], dotpag[50]; - char bakdir[50], bakpag[50]; - - (void) sprintf (dotdir, "%s.dir", CVSROOTADM_MODULES); - (void) sprintf (dotpag, "%s.pag", CVSROOTADM_MODULES); - (void) sprintf (bakdir, "%s%s.dir", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (bakpag, "%s%s.pag", BAKPREFIX, CVSROOTADM_MODULES); - (void) sprintf (newdir, "%s.dir", temp); - (void) sprintf (newpag, "%s.pag", temp); - - (void) chmod (newdir, 0666); - (void) chmod (newpag, 0666); - - /* don't mess with me */ - SIG_beginCrSect (); - - (void) unlink_file (bakdir); /* rm .#modules.dir .#modules.pag */ - (void) unlink_file (bakpag); - (void) rename (dotdir, bakdir); /* mv modules.dir .#modules.dir */ - (void) rename (dotpag, bakpag); /* mv modules.pag .#modules.pag */ - (void) rename (newdir, dotdir); /* mv "temp".dir modules.dir */ - (void) rename (newpag, dotpag); /* mv "temp".pag modules.pag */ - - /* 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 () -{ -} - -static void -mkmodules_usage () -{ - (void) fprintf (stderr, "Usage: %s modules-directory\n", program_name); - exit (1); -} diff --git a/src/modules.c b/src/modules.c deleted file mode 100644 index b49981423cd37ff89e5c9ca8aefb75f6537a13f9..0000000000000000000000000000000000000000 --- a/src/modules.c +++ /dev/null @@ -1,844 +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" - -#ifndef lint -static 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; - int (*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 *tag_prog = NULL; - char *update_prog = NULL; - char cwd[PATH_MAX]; - char line[MAXLINELEN]; - char *xmodargv[MAXFILEPERDIR]; - char **modargv; - char *value; - char *zvalue; - char *mwhere = NULL; - char *mfile = NULL; - char *spec_opt = NULL; - char xvalue[PATH_MAX]; - int modargc, alias = 0; - datum key, val; - char *cp; - int c, err = 0; - - /* remember where we start */ - if (getwd (cwd) == NULL) - error (1, 0, "cannot get current working directory: %s", cwd); - - /* 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) && !isfile (OCVSADM)) - { - char nullrepos[PATH_MAX]; - - (void) sprintf (nullrepos, "%s/%s/%s", CVSroot, - CVSROOTADM, CVSNULLREPOS); - if (!isfile (nullrepos)) - (void) mkdir (nullrepos, 0777); - 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); - if (server_active) - server_set_entstat (dir, nullrepos); - } - } - 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 (&modargc, xmodargv, line); - 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 '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); - - /* clean up */ - free_names (&modargc, modargv); - - /* 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 (chdir (cwd) < 0) - error (1, errno, "failed chdir to %s!", 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)) - { - /* - * If a relative pathname is specified as the checkout or - * tag 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 : checkout_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; -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++; -} - -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 = 1; - 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); - } - } -} diff --git a/src/myndbm.c b/src/myndbm.c deleted file mode 100644 index 33ef49cb9ebee5d39c6e330c466aaaf4ebacca25..0000000000000000000000000000000000000000 --- a/src/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 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/src/myndbm.h b/src/myndbm.h deleted file mode 100644 index 3af313055065977372470210e4c0920e88aad8ef..0000000000000000000000000000000000000000 --- a/src/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/src/no_diff.c b/src/no_diff.c deleted file mode 100644 index d09b84ebb4e4d341354503d99371885ac81b13d8..0000000000000000000000000000000000000000 --- a/src/no_diff.c +++ /dev/null @@ -1,101 +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 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; - - 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 (!iswritable (file)) /* fix the modes as a side effect */ - xchmod (file, 1); - - /* do the byte by byte compare */ - if (xcmp (file, tmp) == 0) - { - if (cvswrite == FALSE) /* fix the modes as a side effect */ - xchmod (file, 0); - - /* 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); - if (server_active) - { - /* We need to update the entries line on the client side. */ - server_update_entries - (file, update_dir, repository, SERVER_UPDATED); - } - 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 */ - } - 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) - (void) fprintf (stderr, "-> unlink(%s)\n", tmp); - if (unlink (tmp) < 0) - error (0, errno, "could not remove %s", tmp); - free (options); - return (ret); -} diff --git a/src/parseinfo.c b/src/parseinfo.c deleted file mode 100644 index 17cf1daf2cd7088f31c1efccf0633a1bca6ee2b3..0000000000000000000000000000000000000000 --- a/src/parseinfo.c +++ /dev/null @@ -1,148 +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 char rcsid[] = "$CVSid: @(#)parseinfo.c 1.18 94/09/23 $"; -USE(rcsid) -#endif - -/* - * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for - * each line in the file that matches the REPOSITORY. - * 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; - int (*callproc) (); - int all; -{ - int err = 0; - FILE *fp_info; - char infopath[PATH_MAX]; - char line[MAXLINELEN]; - char *default_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); - - /* 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'; - - /* - * 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 (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, value); - else - error(0, 0, "Keyword `ALL' is ignored at line %d in %s file", - line_number, infofile); - 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, 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); - - return (err); -} diff --git a/src/patch.c b/src/patch.c deleted file mode 100644 index 6840c349d3b5a6045d3230c809c7f4e1173715f3..0000000000000000000000000000000000000000 --- a/src/patch.c +++ /dev/null @@ -1,596 +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" - -#ifndef lint -static 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 [-Qflq] [-c|-u] [-s|-t] [-V %%d]\n", - " -r rev|-D date [-r rev2 | -D date2] modules...\n", - "\t-Q\tReally quiet.\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': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - 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 (""); - - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (really_quiet) - if (fprintf (to_server, "Argument -Q\n") == EOF) - error (1, errno, "writing to server"); - if (quiet) - if (fprintf (to_server, "Argument -q\n") == EOF) - error (1, errno, "writing to server"); - if (force_tag_match) - if (fprintf (to_server, "Argument -f\n") == EOF) - error (1, errno, "writing to server"); - if (toptwo_diffs) - if (fprintf (to_server, "Argument -t\n") == EOF) - error (1, errno, "writing to server"); - if (patch_short) - if (fprintf (to_server, "Argument -s\n") == EOF) - error (1, errno, "writing to server"); - if (unidiff) - if (fprintf (to_server, "Argument -u\n") == EOF) - error (1, errno, "writing to server"); - - 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") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - /* clean up if we get a signal */ - (void) SIG_register (SIGHUP, patch_cleanup); - (void) SIG_register (SIGINT, patch_cleanup); - (void) SIG_register (SIGQUIT, patch_cleanup); - (void) SIG_register (SIGPIPE, patch_cleanup); - (void) SIG_register (SIGTERM, patch_cleanup); - - 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, (int (*) ()) NULL, patch_dirproc, - (int (*) ()) 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[MAXLINELEN], line2[MAXLINELEN]; - 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); - - 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); - - 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); - 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 (fgets (line1, sizeof (line1), fp) == NULL || - fgets (line2, sizeof (line2), fp) == NULL) - { - 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); - while (fgets (line1, sizeof (line1), fp) != NULL) - (void) printf ("%s", line1); - (void) fclose (fp); - break; - default: - error (0, 0, "diff failed for %s", rcs); - } - out: - (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/src/patchlevel.h b/src/patchlevel.h deleted file mode 100644 index dc2214d284704385548e7ac05841d1075d6c27e1..0000000000000000000000000000000000000000 --- a/src/patchlevel.h +++ /dev/null @@ -1 +0,0 @@ -#define PATCHLEVEL 0 diff --git a/src/rcs.c b/src/rcs.c deleted file mode 100644 index 99cbe88453667e0afce8786ba60edad7d073730b..0000000000000000000000000000000000000000 --- a/src/rcs.c +++ /dev/null @@ -1,1676 +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 "cvs.h" - -#ifndef lint -static char rcsid[] = "$CVSid: @(#)rcs.c 1.40 94/10/07 $"; -USE(rcsid) -#endif - -static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, 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[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) - 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) - char *file; - char *repos; -{ - RCSNode *rcs; - FILE *fp; - char rcsfile[PATH_MAX]; - - (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); - } - - (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); - } - - return (NULL); -} - -/* - * Parse a specific rcsfile. - */ -RCSNode * -RCS_parsercsfile (rcsfile) - char *rcsfile; -{ - FILE *fp; - RCSNode *rcs; - - /* 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); -} - -/* - * Do the real work of parsing an RCS file - */ -static RCSNode * -RCS_parsercsfile_i (fp, rcsfile) - FILE *fp; - char *rcsfile; -{ - Node *q, *r; - RCSNode *rdata; - RCSVers *vnode; - int n; - char *cp; - char *key, *value; - - /* make a node */ - rdata = (RCSNode *) xmalloc (sizeof (RCSNode)); - memset ((char *) rdata, 0, sizeof (RCSNode)); - rdata->refcount = 1; - rdata->path = xstrdup (rcsfile); - 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 (!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); - } - - /* process it */ - if (strcmp (RCSHEAD, key) == 0 && value != NULL) - { - rdata->head = xstrdup (value); - continue; - } - if (strcmp (RCSBRANCH, key) == 0 && value != NULL) - { - 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'; - } - continue; - } - if (strcmp (RCSSYMBOLS, key) == 0) - { - if (value != NULL) - { - rdata->symbols_data = 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 or CVSDEA. */ - 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; - } -#ifdef CVSDEA - /* Accept this only #ifdef CVSDEA, because (a) all that extra file - access presumably slows things down, (b) I don't think anyone - is actually using CVSDEA. It probably could be flushed - entirely. */ - /* Check whether vnode->version is listed in CVSDEA file. */ - { - char *p; - FILE *deafile; - int ch; - char *tmp = xmalloc (sizeof (CVSDEA) + strlen (rcsfile) + 40); - char *last_slash = strrchr (rcsfile, '/'); - int len; - - /* Convert /foo/bar/baz/bif,v to /foo/bar/baz/CVS.dea/bif. */ - - strncpy (tmp, rcsfile, last_slash - rcsfile + 1); - p = tmp + (last_slash - rcsfile) + 1; - - /* CVSDEA files do *not* move into the attic. */ - if (last_slash - rcsfile > 6 && strncmp (p - 6, "Attic/", 6) == 0) - p -= 6; - - strcpy (p, CVSDEA); - strcat (p, "/"); - p += strlen (p); - len = strlen (last_slash + 1) - (sizeof (RCSEXT) - 1); - strncpy (p, last_slash + 1, len); - p[len] = '\0'; - - deafile = fopen (tmp, "r"); - if (deafile == NULL) - { - if (errno != ENOENT) - error (1, errno, "cannot open %s", tmp); - } - else - { - p = vnode->version; - while (1) - { - ch = getc (deafile); - if (ferror (deafile)) - error (1, errno, "cannot read %s", tmp); - if (feof (deafile)) - break; - if (ch == '\012') - { - if (p != NULL && *p == '\0') - { - vnode->dead = 1; - break; - } - p = vnode->version; - } - else - { - if (p != NULL && *p++ != ch) - p = NULL; - } - } - if (fclose (deafile) == EOF) - error (1, errno, "cannot close %s", tmp); - } - free (tmp); - } -#endif /* CVSDEA */ - - /* 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; - } - - return (rdata); -} - -/* - * 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)->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 int keysize = 0; -static char *value = NULL; -static int valsize = 0; - -#define ALLOCINCR 1024 - -static int -getrcskey (fp, keyp, valp) - FILE *fp; - char **keyp; - char **valp; -{ - char *cur, *max; - int c; - int funky = 0; - int white = 1; - - /* skip leading whitespace */ - while (1) - { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - if (!whitespace (c)) - break; - } - - /* fill in key */ - cur = key; - max = key + keysize; - while (!whitespace (c) && c != ';') - { - if (cur < max) - *cur++ = c; - else - { - 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); - } - - /* 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 */ - (void) ungetc (c, fp); - cur = value; - max = value + valsize; - - /* process the value */ - for (;;) - { - /* get a character */ - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - - /* if we are in funky mode, do the rest of this string */ - if (funky) - { - - /* - * funky mode processing does the following: o @@ means one @ o - * all other characters are literal up to a single @ (including - * ';') - */ - for (;;) - { - if (c == '@') - { - c = getc (fp); - if (c == EOF) - { - *keyp = (char *) NULL; - *valp = (char *) NULL; - return (-1); - } - if (c != '@') - { - /* @ followed by non @ turns off funky mode */ - funky = 0; - break; - } - /* otherwise, we already ate one @ so copy the other one */ - } - - /* put the character on the value (maybe allocating space) */ - 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); - } - } - } - - /* if we got the semi-colon we are done with the entire value */ - if (c == ';') - break; - - /* process the character we got */ - if (white && c == '@') - { - - /* - * if we are starting a word with an '@', enable funky processing - */ - white = 0; /* you can't be funky and white :-) */ - funky = 1; - } - else - { - - /* - * we put the character on the list, compressing all whitespace - * to a single space - */ - - /* whitespace with white set means compress it out */ - if (white && whitespace (c)) - continue; - - if (whitespace (c)) - { - /* make c a space and set white */ - white = 1; - c = ' '; - } - else - white = 0; - - /* put the char on the end of value (maybe allocating space) */ - if (cur >= max) - { - value = xrealloc (value, valsize + ALLOCINCR); - cur = value + valsize; - valsize += ALLOCINCR; - max = value + valsize; - } - *cur++ = c; - } - } - - /* if the last char was white space, take it off */ - if (white && cur != value) - cur--; - - /* terminate the string */ - if (cur) - { - 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) - RCSNode *rcs; - char *tag; - char *date; - int force_tag_match; -{ - /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) 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); - 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)); - 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, tag, force_tag_match) - RCSNode *rcs; - char *tag; - int force_tag_match; -{ - Node *p; - - /* make sure we have something to look at... */ - if (rcs == NULL) - return ((char *) NULL); - - /* 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) - 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... */ - if (rcs == NULL) - return ((char *) NULL); - - /* 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... */ - if (rcs == NULL) - return ((char *) NULL); - - if (rcs->branch) - return (RCS_getbranch (rcs, rcs->branch, 1)); - - /* - * NOTE: we call getbranch with force_tag_match set to avoid any - * possibility of recursion - */ - 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... */ - if (rcs == NULL) - return ((char *) NULL); - - /* 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 */ - 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... */ - if (rcs == NULL) - return (revdate); - - /* 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; -{ - 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) - char *arg; -{ - static char *kflags[] = - {"kv", "kvl", "k", "v", "o", (char *) NULL}; - char karg[10]; - char **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) - { - (void) fprintf (stderr, "%s %s: invalid -k option\n", - program_name, command_name); - (void) fprintf (stderr, "\tvalid options are:\n"); - for (cpp = kflags; *cpp != NULL; cpp++) - (void) fprintf (stderr, "\t\t-k%s\n", *cpp); - error (1, 0, "Please retry with a valid -k option"); - } - - (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) - char *tag; -{ - char *invalid = "$,.:;@"; /* invalid RCS tag characters */ - 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; - char *tag; -{ - Node *p; - RCSVers *version; - - p = findnode (rcs->versions, tag); - if (p == NULL) - return (0); - - version = (RCSVers *) p->data; - return (version->dead); -} -#endif /* DEATH_SUPPORT */ diff --git a/src/rcs.h b/src/rcs.h deleted file mode 100644 index c139f92b3010f241a33ae2b01f74ee04027b7ebe..0000000000000000000000000000000000000000 --- a/src/rcs.h +++ /dev/null @@ -1,92 +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 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 */ -struct rcsnode -{ - int refcount; - int flags; - char *path; - char *head; - char *branch; - char *symbols_data; - 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((char *file, char *repos)); -RCSNode *RCS_parsercsfile PROTO((char *rcsfile)); -char *RCS_check_kflag PROTO((char *arg)); -char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match)); -char *RCS_gettag PROTO((RCSNode * rcs, char *tag, int force_tag_match)); -char *RCS_getversion PROTO((RCSNode * rcs, char *tag, char *date, - int force_tag_match)); -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((char *tag)); -void freercsnode PROTO((RCSNode ** rnodep)); -void RCS_addnode PROTO((char *file, RCSNode *rcs, List *list)); -char *RCS_getbranch PROTO((RCSNode * rcs, char *tag, int force_tag_match)); diff --git a/src/recurse.c b/src/recurse.c deleted file mode 100644 index 9131720104b05c4b1ad3a2aeb892d1fd5cccf386..0000000000000000000000000000000000000000 --- a/src/recurse.c +++ /dev/null @@ -1,657 +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" - -#ifndef lint -static 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 int (*fileproc) (); -static int (*filesdoneproc) (); -static Dtype (*direntproc) (); -static int (*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 { - int (*fileproc)(); - int (*filesdoneproc) (); - Dtype (*direntproc) (); - int (*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 algorythm is as follows. - */ -int -start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, - argc, argv, local, which, aflag, readlock, - update_preload, dosrcs, wd_is_repos) - int (*fileproc) (); - int (*filesdoneproc) (); - Dtype (*direntproc) (); - int (*dirleaveproc) (); - 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) - dellist (&entries); - 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) && !isdir (OCVSADM)) - 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 (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) || isdir (OCVSADM)) - { - /* 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); - - if (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) - int (*xfileproc) (); - int (*xfilesdoneproc) (); - Dtype (*xdirentproc) (); - int (*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; - - /* - * Fill in repository with the current repository - */ - if (which & W_LOCAL) - { - if (isdir (CVSADM) || isdir (OCVSADM)) - 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 = ParseEntries (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); - dellist (&entries); - } - - /* 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) - { - (void) 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; -#ifndef HAVE_FCHDIR - char savewd[PATH_MAX]; -#else - int savefd; -#endif - - /* 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 */ -#ifdef HAVE_FCHDIR - if ((savefd = open (".", O_RDONLY)) < 0) - error (1, errno, "could not open working directory"); -#else - if (getwd (savewd) == NULL) - error (1, 0, "could not get working directory: %s", savewd); -#endif - 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 */ -#ifdef HAVE_FCHDIR - if (fchdir (savefd) < 0) - error (1, errno, "could not fchdir back to saved working directory"); - (void) close (savefd); -#else - if (chdir (savewd) < 0) - error (1, errno, "could not chdir to %s", savewd); -#endif - 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. */ - (void) 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; -#ifndef HAVE_FCHDIR - char savewd[PATH_MAX]; -#else - int savefd; -#endif - - /* 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) - { -#ifdef HAVE_FCHDIR - if ((savefd = open (".", O_RDONLY)) < 0) - error (1, errno, "could not open working directory"); -#else - if (getwd (savewd) == NULL) - error (1, 0, "could not get working directory: %s", savewd); -#endif - - 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); - -#ifdef HAVE_FCHDIR - if (fchdir (savefd) < 0) - error (1, errno, "could not fchdir back to saved working directory"); - (void) close (savefd); -#else - if (chdir (savewd) < 0) - error (1, errno, "could not chdir to %s", savewd); -#endif - } - - dirlist = save_dirlist; - filelist = NULL; - return(err); -} diff --git a/src/release.c b/src/release.c deleted file mode 100644 index 96d9d9329fa6cfaee14a6badaa5a0a2d37eab209..0000000000000000000000000000000000000000 --- a/src/release.c +++ /dev/null @@ -1,241 +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 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-Q\tReally quiet.\n", - "\t-d\tDelete the given directory.\n", - "\t-q\tSomewhat quiet.\n", - NULL -}; - -static short delete; - -int -release (argc, argv) - int argc; - char **argv; -{ - FILE *fp; - register int i, c; - register char *cp; - int margc; - DBM *db; - datum key, val; - char *repository, *srepos; - char **margv, *modargv[MAXFILEPERDIR], line[PATH_MAX]; - - if (argc == -1) - usage (release_usage); - optind = 1; - while ((c = getopt (argc, argv, "Qdq")) != -1) - { - switch (c) - { - case 'Q': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - break; - case 'd': - delete++; - break; - case '?': - default: - usage (release_usage); - break; - } - } - argc -= optind; - argv += optind; - - if (client_active) { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (quiet) - if (fprintf (to_server, "Argument -q\n") == EOF) - error (1, errno, "writing to server"); - if (really_quiet) - if (fprintf (to_server, "Argument -Q\n") == EOF) - error (1, errno, "writing to server"); - if (delete) - if (fprintf (to_server, "Argument -d\n") == EOF) - error (1, errno, "writing to server"); - - if (fprintf (to_server, "release\n") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - if (!(db = open_module ())) - return (1); - for (i = 0; i < argc; i++) - { - - /* - * 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 (argv[i])) - { - if (chdir (argv[i]) < 0) - { - if (!really_quiet) - error (0, 0, "can't chdir to: %s", argv[i]); - continue; - } - if (!isdir (CVSADM) && !isdir (OCVSADM)) - { - if (!really_quiet) - error (0, 0, "no repository module: %s", argv[i]); - continue; - } - } - else - { - if (!really_quiet) - error (0, 0, "no such directory/module: %s", argv[i]); - continue; - } - - repository = Name_Repository ((char *) NULL, (char *) NULL); - srepos = Short_Repository (repository); - - /* grab module entry from database and check against short repos */ - key.dptr = argv[i]; - key.dsize = strlen (key.dptr); - val = dbm_fetch (db, key); - if (!val.dptr) - { - error (0, 0, "no such module name: %s", argv[i]); - continue; - } - val.dptr[val.dsize] = '\0'; - if ((cp = strchr (val.dptr, '#')) != NULL) /* Strip out a comment */ - { - do - { - *cp-- = '\0'; - } while (isspace (*cp)); - } - (void) sprintf (line, "%s %s", key.dptr, val.dptr); - line2argv (&margc, modargv, line); - margv = modargv; - - optind = 1; - while (getopt (margc, margv, CVSMODULE_OPTS) != -1) - /* do nothing */ ; - margc -= optind; - margv += optind; - - if (margc < 1) - { - error (0, 0, "modules file missing directory for key %s value %s", - key.dptr, val.dptr); - continue; - } - if (strcmp (*margv, srepos)) - { - error (0, 0, "repository mismatch: module[%s], here[%s]", - *margv, srepos); - free (repository); - continue; - } - - if (!really_quiet) - { - - /* - * Now see if there is any reason not to allow a "Release" This - * is "popen()" instead of "Popen()" since we don't want "-n" to - * stop it. - */ - fp = popen ("cvs -n -q update", "r"); - c = 0; - while (fgets (line, sizeof (line), fp)) - { - if (strchr ("MARCZ", *line)) - c++; - (void) printf (line); - } - (void) pclose (fp); - (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) " : "", argv[i]); - c = !yesno (); - if (c) /* "No" */ - { - (void) fprintf (stderr, "** `%s' aborted by user choice.\n", - command_name); - free (repository); - continue; - } - } - - /* - * So, we've passed all the tests, go ahead and release it. First, - * log the release, then attempt to delete it. - */ - history_write ('F', argv[i], "", argv[i], ""); /* F == Free */ - free (repository); - - if (delete) - release_delete (argv[i]); - } - close_module (db); - return (0); -} - -/* We want to "rm -r" the repository, 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/src/remove.c b/src/remove.c deleted file mode 100644 index eba5d86eb6fa21d0e0302c45f61e88391e47b4bf..0000000000000000000000000000000000000000 --- a/src/remove.c +++ /dev/null @@ -1,199 +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 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; - - if (client_active) { - start_server (); - ign_setup (); - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - send_files (argc, argv, local, 0); - if (fprintf (to_server, "remove\n") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - /* 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 unlinking the file works, good. If not, the "unremoved" - * error will indicate problems. - */ - if (force) - (void) unlink (file); - - 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 ,p and ,t file for it and scratch it from the - * entries file. - */ - Scratch_Entry (entries, file); - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_OPT); - (void) unlink_file (fname); - (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG); - (void) unlink_file (fname); - if (!quiet) - error (0, 0, "removed `%s'", file); - - if (server_active) - server_checked_in (file, update_dir, repository); - } - 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++; - - if (server_active) - server_checked_in (file, update_dir, repository); - } - - 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/src/repos.c b/src/repos.c deleted file mode 100644 index 467fe80130bf91044e8fe5a809e6c23db989d01a..0000000000000000000000000000000000000000 --- a/src/repos.c +++ /dev/null @@ -1,170 +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 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 ocvsadm[PATH_MAX]; - char *cp; - int has_cvsadm = 0, has_ocvsadm = 0; - - if (update_dir && *update_dir) - xupdate_dir = update_dir; - else - xupdate_dir = "."; - - if (dir != NULL) - { - (void) sprintf (cvsadm, "%s/%s", dir, CVSADM); - (void) sprintf (ocvsadm, "%s/%s", dir, OCVSADM); - } - else - { - (void) strcpy (cvsadm, CVSADM); - (void) strcpy (ocvsadm, OCVSADM); - } - - /* sanity checks */ - if (!(has_cvsadm = isdir (cvsadm)) && !(has_ocvsadm = isdir (ocvsadm))) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "there is no version here; do '%s checkout' first", - program_name); - } - - if (has_ocvsadm) - { - if (has_cvsadm) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, 0, "error: both `%s' and `%s' exist; I give up", - CVSADM, OCVSADM); - } - if (rename (ocvsadm, cvsadm) < 0) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (1, errno, "cannot rename `%s' to `%s'; I give up", - OCVSADM, CVSADM); - } - - /* - * We have converted the old CVS.adm directory to the new CVS - * directory. Now, convert the Entries file to the new format, if - * necessary. - */ - check_entries (dir); - } - - 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 (repos[0] != '/') - { - 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); - } - if (!client_active && !isdir (repos)) - { - 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 */ - if (strncmp (CVSroot, repository, strlen (CVSroot)) == 0) - return (repository + strlen (CVSroot) + 1); - else - return (repository); -} diff --git a/src/root.c b/src/root.c deleted file mode 100644 index 91005b6f404a4581cbc6f2da4e59b2651365a86f..0000000000000000000000000000000000000000 --- a/src/root.c +++ /dev/null @@ -1,178 +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 char rcsid[] = "@(#)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 possiible 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) && root[0] != '/') -#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]; - - /* 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) == EOF) - error (1, errno, "write to %s failed", tmp); - if (fclose (fout) == EOF) - error (1, errno, "cannot close %s", tmp); - } -} diff --git a/src/rtag.c b/src/rtag.c deleted file mode 100644 index 3e6cd546855904b45b0e588a0d66353b2b7dc7f9..0000000000000000000000000000000000000000 --- a/src/rtag.c +++ /dev/null @@ -1,472 +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 char rcsid[] = "$CVSid: @(#)rtag.c 1.61 94/09/30 $"; -USE(rcsid) -#endif - -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)); - -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 [-QaflRnqF] [-b] [-d] [-r tag|-D date] tag modules...\n", - "\t-Q\tReally quiet.\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-q\tSomewhat quiet.\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': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - 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); - - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (quiet) - if (fprintf (to_server, "Argument -q\n") == EOF) - error (1, errno, "writing to server"); - if (really_quiet) - if (fprintf (to_server, "Argument -Q\n") == EOF) - error (1, errno, "writing to server"); - if (delete) - if (fprintf (to_server, "Argument -d\n") == EOF) - error (1, errno, "writing to server"); - if (branch_mode) - if (fprintf (to_server, "Argument -b\n") == EOF) - error (1, errno, "writing to server"); - if (force_tag_move) - if (fprintf (to_server, "Argument -F\n") == EOF) - error (1, errno, "writing to server"); - if (run_module_prog) - if (fprintf (to_server, "Argument -n\n") == EOF) - error (1, errno, "writing to server"); - if (attic_too) - if (fprintf (to_server, "Argument -a\n") == EOF) - error (1, errno, "writing to server"); - - 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") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - 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; - - /* start the recursion processor */ - err = start_recursion (rtag_fileproc, (int (*) ()) NULL, rtag_dirproc, - (int (*) ()) NULL, *pargc - 1, argv + 1, local, - which, 0, 1, where, 1, 1); - - return (err); -} - -/* - * 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); - 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; - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, 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 *) 0, 1); - 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); - } - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev); - } - run_arg (rcsfile->path); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 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 *) 0, 1); - if (version == NULL) - return (0); - free (version); - } - - version = RCS_getversion (rcsfile, symtag, (char *) 0, 1); - if (version == NULL) - return (0); - free (version); - - run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag); - run_arg (rcsfile->path); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 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/src/sanity.el b/src/sanity.el deleted file mode 100644 index a1470570a011be64a03e870c79b4630cfe79bc99..0000000000000000000000000000000000000000 --- a/src/sanity.el +++ /dev/null @@ -1,18 +0,0 @@ -;;;; -*- lisp-interaction -*- -;;;; Time-stamp: <29 Nov 93 14:25:28, by rich@sendai.cygnus.com> - -(defun reset-fail-counter (arg) - (interactive "p") - (setq fail-counter arg) - (message (concat "fail-counter = " (int-to-string arg)))) - - -(defun inc-next-fail-counter nil - (interactive) - (search-forward "failed test ") - (kill-word 1) - (insert-string fail-counter) - (setq fail-counter (+ 1 fail-counter))) - -(global-set-key [f15] 'reset-fail-counter) -(global-set-key [f16] 'inc-next-fail-counter) diff --git a/src/sanity.sh b/src/sanity.sh deleted file mode 100755 index 34871ca442d8157f77f7c4c053154b620f669be8..0000000000000000000000000000000000000000 --- a/src/sanity.sh +++ /dev/null @@ -1,1193 +0,0 @@ -#!/bin/sh -# a quick sanity test for cvs. -# -# Copyright (C) 1992, 1993 Cygnus Support -# -# Original Author: K. Richard Pixley - -# usage: sanity.sh [-r] @var{cvs-to-test} -# -r means to test remote instead of local cvs. - -# -# These commands are not covered at all. -# admin - -TESTDIR=/tmp/cvs-sanity - -# "debugger" -#set -x - -echo This test should produce no other output than this line. - -# clean any old remnants -rm -rf ${TESTDIR} - -if test x"$1" = x"-r"; then - shift - remote=yes -else - remote=no -fi - -testcvs=$1; shift - -# Remaining arguments are the names of tests to run. -if test x"$*" = x; then - tests="basic0 basic1 basic2 basic3 rtags death import new conflicts" -else - tests="$*" -fi - -# fixme: try things without -m. -# fixme: run this in a loop over "-Q", "-q", and "". -CVS="${testcvs} -Q" -OUTPUT= - -LOGFILE=`pwd`/check.log -if test -f check.log; then mv check.log check.plog; fi - -mkdir ${TESTDIR} -cd ${TESTDIR} - -# so far so good. Let's try something harder. - -# this should die -if ${CVS} -d `pwd`/cvsroot co cvs-sanity 2>> ${LOGFILE} ${OUTPUT} ; 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} ${OUTPUT} ; 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} ${OUTPUT} ; 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} ${OUTPUT} -cd .. ; rm -rf tmp - -# This one should succeed. No warnings. -touch cvsroot/CVSROOT/modules -mkdir tmp ; cd tmp -if ${CVS} -d `pwd`/../cvsroot co CVSROOT ${OUTPUT} ; then - echo "PASS: test 4" >>${LOGFILE} -else - echo "FAIL: test 4" | tee -a ${LOGFILE}; exit 1 -fi - -cd .. ; rm -rf tmp - -# Try setting CVSROOT so we don't have to worry about it anymore. (now that -# we've tested -d cvsroot.) -CVSROOT_FILENAME=`pwd`/cvsroot -CVSROOT=${CVSROOT_FILENAME} ; export CVSROOT -if test "x$remote" = xyes; then - CVSROOT=`hostname`:${CVSROOT_FILENAME} ; export CVSROOT - # Use rsh so we can test it without having to muck with inetd or anything - # like that. Also needed to get CVS_SERVER to work. - CVS_CLIENT_PORT=-1; export CVS_CLIENT_PORT - CVS_SERVER=${CVS}; export CVS_SERVER -fi - -mkdir tmp ; cd tmp -if ${CVS} -d `pwd`/../cvsroot co CVSROOT ${OUTPUT} ; then - echo "PASS: test 5" >>${LOGFILE} -else - echo "FAIL: test 5" | tee -a ${LOGFILE}; exit 1 -fi - -cd .. ; rm -rf tmp - -# start keeping history -touch ${CVSROOT_FILENAME}/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 ${OUTPUT} ; then -# true -# else -# echo cvs does not yet add top level directories cleanly. - mkdir ${CVSROOT_FILENAME}/first-dir -# fi -# rm -rf first-dir - - # check out an empty directory - if ${CVS} co first-dir ${OUTPUT} ; then - echo "PASS: test 6" >>${LOGFILE} - else - echo "FAIL: test 6" | tee -a ${LOGFILE}; exit 1 - fi - - # update the empty directory - if ${CVS} update first-dir ${OUTPUT} ; 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 ${OUTPUT} ; 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 ${OUTPUT} ; 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 ${OUTPUT} ; 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 ${OUTPUT} ; 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 ${OUTPUT} ; 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 ${OUTPUT} ; 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_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir - # check out an empty directory - if ${CVS} co first-dir ${OUTPUT} ; 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} ${OUTPUT} >> ${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 ${OUTPUT} ; 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 ${OUTPUT} >> ${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 ${OUTPUT} >> ${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 ${OUTPUT} >> ${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 ${OUTPUT} >> ${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 ${OUTPUT} ; 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 ${OUTPUT} >> ${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 ${OUTPUT} >> ${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 ${OUTPUT} ; then - true - else - echo '***' failed test 24-${do}-$j. ; exit 1 - fi - - if test "x${do}-$j" = "xadd-add" || test "x${do}-$j" = "xrm-rm" ; then - true - else - # diff all - if ${CVS} diff -u ${OUTPUT} >> ${LOGFILE} || [ $? = 1 ] ; then - true - else - echo '***' failed test 25-${do}-$j. # FIXME; exit 1 - fi - - # diff all - if ${CVS} diff -u first-dir ${OUTPUT} >> ${LOGFILE} || [ $? = 1 ] ; then - true - else - echo '***' failed test 26-${do}-$j. # FIXME; exit 1 - fi - fi - - # update all. - if ${CVS} co first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 27-${do}-$j. ; exit 1 - fi - - cd first-dir - done # j - rm -f ${files} - done # do - - files="file2 file3 file4 file5" - done - if ${CVS} tag first-dive ${OUTPUT} ; then - true - else - echo '***' failed test 28. ; 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 ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 29-$i. ; 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 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 30-$i-$j. ; exit 1 - fi - done - cd ../../../../.. - if ${CVS} update first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 31. ; exit 1 - fi - - # fixme: doesn't work right for added files. - if ${CVS} log first-dir ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 32. # ; exit 1 - fi - - if ${CVS} status first-dir ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 33. ; exit 1 - fi - -# if ${CVS} diff -u first-dir ${OUTPUT} >> ${LOGFILE} || [ $? = 1 ] ; then -# true -# else -# echo '***' failed test 34. # ; exit 1 -# fi - - if ${CVS} ci -m "second dive" first-dir ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 35. ; exit 1 - fi - - if ${CVS} tag second-dive first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 36. ; 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 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 37-$i. ; 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 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 38-$i. ; exit 1 - fi - done - cd ../../../../.. - if ${CVS} update first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 39. ; exit 1 - fi - - # fixme: doesn't work right for added files - if ${CVS} log first-dir ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 40. # ; exit 1 - fi - - if ${CVS} status first-dir ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 41. ; exit 1 - fi - -# if ${CVS} diff -u first-dir ${OUTPUT} >> ${LOGFILE} || [ $? = 1 ] ; then -# true -# else -# echo '***' failed test 42. # ; exit 1 -# fi - - if ${CVS} ci -m "third dive" first-dir ${OUTPUT} >>${LOGFILE} 2>&1; then - true - else - echo '***' failed test 43. ; exit 1 - fi - - if ${CVS} tag third-dive first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 44. ; exit 1 - fi - - # Hmm... fixme. -# if ${CVS} release first-dir ${OUTPUT} ; then -# true -# else -# echo '***' failed test 45. # ; exit 1 -# fi - - # end of third dive - rm -rf first-dir - ;; - - rtags) # now try some rtags - # rtag HEADS - if ${CVS} rtag rtagged-by-head first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 46. ; exit 1 - fi - - # tag by tag - if ${CVS} rtag -r rtagged-by-head rtagged-by-tag first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 47. ; exit 1 - fi - - # tag by revision - if ${CVS} rtag -r1.1 rtagged-by-revision first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 48. ; exit 1 - fi - - # rdiff by revision - if ${CVS} rdiff -r1.1 -rrtagged-by-head first-dir ${OUTPUT} >> ${LOGFILE} || [ $? = 1 ] ; then - true - else - echo '***' failed test 49. ; 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 ${OUTPUT} ; then - true - else - echo '***' failed test 50. ; exit 1 - fi - - mv first-dir 1dir - if ${CVS} export -r rtagged-by-tag first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 51. ; exit 1 - fi - - if diff -c -r 1dir first-dir ; then - true - else - echo '***' failed test 52. ; exit 1 - fi - rm -rf 1dir first-dir - - # For some reason, this command has stopped working and hence much of this sequence is currently off. - # export by revision vs checkout by rtagged-by-revision and compare. -# if ${CVS} export -r1.1 first-dir ${OUTPUT} ; then -# true -# else -# echo '***' failed test 53. # ; exit 1 -# fi - # note sidestep below - #mv first-dir 1dir - - if ${CVS} co -rrtagged-by-revision first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 54. ; exit 1 - fi - # fixme: this is here temporarily to sidestep test 53. - ln -s first-dir 1dir - - # directory copies are done in an oblique way in order to avoid a bug in sun's tmp filesystem. - mkdir first-dir.cpy ; (cd first-dir ; tar cf - * | (cd ../first-dir.cpy ; tar xf -)) - - if diff --exclude=CVS -c -r 1dir first-dir ; then - true - else - echo '***' failed test 55. ; exit 1 - fi - - # interrupt, while we've got a clean 1.1 here, let's import it into another tree. - cd 1dir - if ${CVS} import -m "first-import" second-dir first-immigration immigration1 immigration1_0 ${OUTPUT} ; then - true - else - echo '***' failed test 56. ; exit 1 - fi - cd .. - - if ${CVS} export -r HEAD second-dir ${OUTPUT} ; then - true - else - echo '***' failed test 57. ; exit 1 - fi - - if diff --exclude=CVS -c -r first-dir second-dir ; then - true - else - echo '***' failed test 58. ; exit 1 - fi - - rm -rf 1dir 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* ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 59. ; 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 ${OUTPUT} ; then - true - else - echo '***' failed test 60a. ; exit 1 - fi - if ${CVS} tag -l rtagged-by-revision ${OUTPUT} ; then - true - else - echo '***' failed test 60b. ; exit 1 - fi - - cd .. ; mv first-dir 1dir - mv first-dir.cpy first-dir ; cd first-dir - if ${CVS} diff -u ${OUTPUT} >> ${LOGFILE} || [ $? = 1 ] ; then - true - else - echo '***' failed test 61. ; exit 1 - fi - - if ${CVS} update ${OUTPUT} ; then - true - else - echo '***' failed test 62. ; exit 1 - fi - - cd .. - -# Haven't investigated why this is failing. -# if diff --exclude=CVS -c -r 1dir first-dir ; then -# true -# else -# echo '***' failed test 63. # ; exit 1 -# fi - rm -rf 1dir first-dir - - if ${CVS} his -e -a ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 64. ; exit 1 - fi - ;; - - death) # next dive. test death support. - rm -rf ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir - if ${CVS} co first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 65 ; exit 1 - fi - - cd first-dir - - # add a file. - touch file1 - if ${CVS} add file1 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 66 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 67 ; exit 1 - fi - - # remove - rm file1 - if ${CVS} rm file1 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 68 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} ; then - true - else - echo '***' failed test 69 ; exit 1 - fi - - # add again and create second file - touch file1 file2 - if ${CVS} add file1 file2 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 70 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 71 ; exit 1 - fi - - # log - if ${CVS} log file1 ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 72 ; exit 1 - fi - - - # branch1 - if ${CVS} tag -b branch1 ${OUTPUT} ; then - true - else - echo '***' failed test 73 ; exit 1 - fi - - # and move to the branch. - if ${CVS} update -r branch1 ${OUTPUT} ; then - true - else - echo '***' failed test 74 ; exit 1 - fi - - # add a file in the branch - echo line1 from branch1 >> file3 - if ${CVS} add file3 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 75 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 76 ; exit 1 - fi - - # remove - rm file3 - if ${CVS} rm file3 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 77 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} ; then - true - else - echo '***' failed test 78 ; exit 1 - fi - - # add again - echo line1 from branch1 >> file3 - if ${CVS} add file3 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 79 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 80 ; exit 1 - fi - - # change the first file - echo line2 from branch1 >> file1 - - # commit - if ${CVS} ci -m test ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 81 ; exit 1 - fi - - # remove the second - rm file2 - if ${CVS} rm file2 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 82 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} ; then - true - else - echo '***' failed test 83 ; exit 1 - fi - - # back to the trunk. - if ${CVS} update -A ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 84 ; exit 1 - fi - - if [ -f file3 ] ; then - echo '***' failed test 85 ; exit 1 - else - true - fi - - # join - if ${CVS} update -j branch1 ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 86 ; exit 1 - fi - - if [ -f file3 ] ; then - true - else - echo '***' failed test 87 ; exit 1 - fi - - # update - if ${CVS} update ${OUTPUT} ; then - true - else - echo '***' failed test 88 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} >>${LOGFILE} 2>&1; then - true - else - echo '***' failed test 89 ; exit 1 - fi - - # remove first file. - rm file1 - if ${CVS} rm file1 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 90 ; exit 1 - fi - - # commit - if ${CVS} ci -m test ${OUTPUT} ; then - true - else - echo '***' failed test 91 ; exit 1 - fi - - if [ -f file1 ] ; then - echo '***' failed test 92 ; exit 1 - else - true - fi - - # back to branch1 - if ${CVS} update -r branch1 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 93 ; exit 1 - fi - - if [ -f file1 ] ; then - true - else - echo '***' failed test 94 ; exit 1 - fi - - # and join - if ${CVS} update -j HEAD ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 95 ; exit 1 - fi - - cd .. ; rm -rf first-dir ${CVSROOT_FILENAME}/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 ${OUTPUT} ; then - true - else - echo '***' failed test 96 ; exit 1 - fi - cd .. - - # co - if ${CVS} co first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 97 ; exit 1 - fi - - cd first-dir - for i in 1 2 3 4 ; do - if [ -f imported-file"$i" ] ; then - true - else - echo '***' failed test 98-$i ; exit 1 - fi - done - - # remove - rm imported-file1 - if ${CVS} rm imported-file1 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 99 ; 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 ${OUTPUT} >> ${LOGFILE} 2>&1; then - true - else - echo '***' failed test 100 ; exit 1 - fi - - # log - if ${CVS} log imported-file1 | grep '1.1.1.2 (dead)' ${OUTPUT} ; then - echo '***' failed test 101 ; exit 1 - else - true - fi - - # update into the vendor branch. - if ${CVS} update -rvendor-branch ${OUTPUT} ; then - true - else - echo '***' failed test 102 ; exit 1 - fi - - # remove file4 on the vendor branch - rm imported-file4 - - if ${CVS} rm imported-file4 ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 103 ; exit 1 - fi - - # commit - if ${CVS} ci -m vendor-removed imported-file4 ${OUTPUT} ; then - true - else - echo '***' failed test 104 ; exit 1 - fi - - # update to main line - if ${CVS} update -A ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 105 ; 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 ${OUTPUT} ; then - true - else - echo '***' failed test 106 ; exit 1 - fi - cd .. - - # co - if ${CVS} co first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 107 ; exit 1 - fi - - cd first-dir - - if [ -f imported-file1 ] ; then - echo '***' failed test 108 ; exit 1 - else - true - fi - - for i in 2 3 ; do - if [ -f imported-file"$i" ] ; then - true - else - echo '***' failed test 109-$i ; exit 1 - fi - done - - # check vendor branch for file4 - if ${CVS} update -rvendor-branch ${OUTPUT} ; then - true - else - echo '***' failed test 110 ; exit 1 - fi - - if [ -f imported-file4 ] ; then - true - else - echo '***' failed test 111 ; exit 1 - fi - - # update to main line - if ${CVS} update -A ${OUTPUT} 2>> ${LOGFILE}; then - true - else - echo '***' failed test 112 ; exit 1 - fi - - cd .. - - if ${CVS} co -jjunk-1_0 -jjunk-2_0 first-dir ${OUTPUT} >>${LOGFILE} 2>&1; then - true - else - echo '***' failed test 113 ; exit 1 - fi - - cd first-dir - - if [ -f imported-file1 ] ; then - echo '***' failed test 114 ; exit 1 - else - true - fi - - for i in 2 3 ; do - if [ -f imported-file"$i" ] ; then - true - else - echo '***' failed test 115-$i ; exit 1 - fi - done - - if cat imported-file2 | grep '====' ${OUTPUT} >> ${LOGFILE}; then - true - else - echo '***' failed test 116 ; exit 1 - fi - cd .. ; rm -rf first-dir ${CVSROOT_FILENAME}/first-dir - ;; - - new) # look for stray "no longer pertinent" messages. - rm -rf first-dir ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/first-dir - - if ${CVS} co first-dir ${OUTPUT} ; then - true - else - echo '***' failed test 117 ; exit 1 - fi - - cd first-dir - touch a - - if ${CVS} add a ${OUTPUT} 2>>${LOGFILE}; then - true - else - echo '***' failed test 118 ; exit 1 - fi - - if ${CVS} ci -m added ${OUTPUT} >>${LOGFILE} 2>&1; then - true - else - echo '***' failed test 119 ; exit 1 - fi - - rm a - - if ${CVS} rm a ${OUTPUT} 2>>${LOGFILE}; then - true - else - echo '***' failed test 120 ; exit 1 - fi - - if ${CVS} ci -m removed ${OUTPUT} ; then - true - else - echo '***' failed test 121 ; exit 1 - fi - - if ${CVS} update -A ${OUTPUT} 2>&1 | grep longer ; then - echo '***' failed test 122 ; exit 1 - else - true - fi - - if ${CVS} update -rHEAD 2>&1 | grep longer ; then - echo '***' failed test 123 ; exit 1 - else - true - fi - - cd .. ; rm -rf first-dir ; rm -rf ${CVSROOT_FILENAME}/first-dir - ;; - - conflicts) - rm -rf first-dir ${CVSROOT_FILENAME}/first-dir - mkdir ${CVSROOT_FILENAME}/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 - ;; - - *) echo $what is not the name of a test -- ignored ;; - esac -done - -echo Ok. - -# Local Variables: -# fill-column: 131 -# End: - -# end of sanity.sh diff --git a/src/server.c b/src/server.c deleted file mode 100644 index 1bfde8e9ee9e9bff2e4fc2b2be6ed392d7c88bb7..0000000000000000000000000000000000000000 --- a/src/server.c +++ /dev/null @@ -1,3494 +0,0 @@ -#include "cvs.h" - -/* for select */ -#include <sys/types.h> -#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)); - -void server_cleanup PROTO((int sig)); - -/* - * 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; - -/* - * Zero if compression isn't supported or requested; non-zero to indicate - * a compression level to request from gzip. - */ -int gzip_level; - -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 (mkdir (q, 0777) < 0) - { - if (errno != EEXIST - && (errno != EACCES || !isdir(q))) - { - retval = errno; - goto done; - } - } - ++p; - } - else - { - if (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 (access (path, R_OK | X_OK)) - { - save_errno = errno; - printf ("E Cannot access %s\n", path); - pending_error = save_errno; - } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (isfile (path) && access (path, R_OK | W_OK)) - { - save_errno = errno; - printf ("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; - return; - } - if (chdir (dirname) < 0) - { - pending_error = errno; - return; - } - /* - * This is pretty much like calling Create_Admin, but Create_Admin doesn't - * report errors in the right way for us. - */ - if (mkdir ("CVS", 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) == EOF) - { - 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; - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - 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; - return; - } - if (repos == NO_MEM_ERROR) - { - pending_error = ENOMEM; - return; - } - dirswitch (arg, repos); -} - -static void -serve_static_directory (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_ENTSTAT, "w+"); - if (f == NULL) - { - pending_error = errno; - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - return; - } -} - -static void -serve_sticky (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_TAG, "w+"); - if (f == NULL) - { - pending_error = errno; - return; - } - if (fprintf (f, "%s\n", arg) == EOF) - { - pending_error = errno; - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - 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; -{ - char *buf, *p; - int fd, bytes_left, nbytes; - 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 fd; - char *buf = NULL; - char *p; - - int size; - char *size_text; - char *mode_text; - - int nbytes, bytes_left, 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; - } - 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; - } - 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; - } - } -} - -extern int use_unchanged; -int use_unchanged = 0; - -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; - 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; - 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; - } - } - for (p = entries; p != NULL;) - { - if (!error_pending ()) - { - if (fprintf (f, "%s\n", p->entry) == EOF) - { - pending_error = errno; - } - } - free (p->entry); - q = p->next; - free (p); - p = q; - } - entries = NULL; - if (f != NULL && fclose (f) == EOF && !error_pending ()) - { - pending_error = errno; - } -} - -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) - -/* Linked list of available buffer_data structures. */ -static struct buffer_data *free_buffer_data; - -static void allocate_buffer_datas PROTO((void)); -static 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 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 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 *)); - -/* 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 -#ifdef __GNUC__ -__inline__ -#endif -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; -} - -/* 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 -#ifdef __GNUC__ -__inline__ -#endif -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; -} - -/* - * Set buffer BUF to non-blocking I/O. Returns 0 for success or errno - * code. - */ - -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 -#ifdef __GNUC__ -__inline__ -#endif -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; - -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; - } - - 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; - - 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]); - - /* - * 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; - - 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; - - 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; - fd_set exceptfds; - int numfds; - - FD_ZERO (&readfds); - FD_ZERO (&writefds); - FD_ZERO (&exceptfds); - if (! buf_empty_p (&outbuf)) - FD_SET (STDOUT_FILENO, &writefds); - FD_SET (STDOUT_FILENO, &exceptfds); - if (stdout_pipe[0] >= 0) - { - FD_SET (stdout_pipe[0], &readfds); - FD_SET (stdout_pipe[0], &exceptfds); - } - if (stderr_pipe[0] >= 0) - { - FD_SET (stderr_pipe[0], &readfds); - FD_SET (stderr_pipe[0], &exceptfds); - } - if (protocol_pipe[0] >= 0) - { - FD_SET (protocol_pipe[0], &readfds); - FD_SET (protocol_pipe[0], &exceptfds); - } - - do { - numfds = select (num_to_check, &readfds, &writefds, - &exceptfds, (struct timeval *)NULL); - if (numfds < 0 - && errno != EINTR) - { - print_error (errno); - goto error_exit; - } - } while (numfds < 0); - - if (FD_ISSET (STDOUT_FILENO, &writefds) - || FD_ISSET (STDOUT_FILENO, &exceptfds)) - { - /* What should we do with errors? syslog() them? */ - buf_send_output (&outbuf); - } - - if (stdout_pipe[0] >= 0 - && (FD_ISSET (stdout_pipe[0], &readfds) - || FD_ISSET (stdout_pipe[0], &exceptfds))) - { - 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) - || FD_ISSET (stderr_pipe[0], &exceptfds))) - { - 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) - || FD_ISSET (protocol_pipe[0], &exceptfds))) - { - 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; -} - -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 (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 (file, repository) - char *file; - char *repository; -{ - 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 (file, repository); - } - 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 (file, repository); - 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 ("CVS")) - { - /* - * 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 (errno == ENOENT) - { - /* - * 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 (file, repository); - - { - char *mode_string; - - if (file_info != NULL) - mode_string = mode_to_string (file_info); - else - mode_string = mode_to_string (&sb); - 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 (*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; - return; - } - if (fprintf (f, "%s\n", arg) == EOF) - { - pending_error = errno; - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - return; - } -} - -static void -serve_update_prog (arg) - char *arg; -{ - FILE *f; - f = fopen (CVSADM_UPROG, "w+"); - if (f == NULL) - { - pending_error = errno; - return; - } - if (fprintf (f, "%s\n", arg) == EOF) - { - pending_error = errno; - return; - } - if (fclose (f) == EOF) - { - pending_error = errno; - return; - } -} - -static void serve_valid_requests PROTO((char *arg)); - -struct request requests[] = -{ - {"Root", serve_root, rq_essential}, - {"Valid-responses", serve_valid_responses, rq_essential}, - {"valid-requests", serve_valid_requests, rq_essential}, - {"Repository", serve_repository, rq_essential}, - {"Directory", serve_directory, rq_optional}, - {"Max-dotdot", serve_max_dotdot, rq_optional}, - {"Static-directory", serve_static_directory, rq_optional}, - {"Sticky", serve_sticky, rq_optional}, - {"Checkin-prog", serve_checkin_prog, rq_optional}, - {"Update-prog", serve_update_prog, rq_optional}, - {"Entry", serve_entry, rq_essential}, - {"Modified", serve_modified, rq_essential}, - {"Lost", serve_lost, rq_optional}, - {"UseUnchanged", serve_enable_unchanged, rq_enableme}, - {"Unchanged", serve_unchanged, rq_optional}, - {"Argument", serve_argument, rq_essential}, - {"Argumentx", serve_argumentx, rq_essential}, - {"Global_option", serve_global_option, rq_optional}, - {"expand-modules", serve_expand_modules, rq_optional}, - {"ci", serve_ci, rq_essential}, - {"co", serve_co, rq_essential}, - {"update", serve_update, rq_essential}, - {"diff", serve_diff, rq_optional}, - {"log", serve_log, rq_optional}, - {"add", serve_add, rq_optional}, - {"remove", serve_remove, rq_optional}, - {"update-patches", serve_ignore, rq_optional}, - {"gzip-file-contents", serve_gzip_contents, rq_optional}, - {"status", serve_status, rq_optional}, - {"rdiff", serve_rdiff, rq_optional}, - {"tag", serve_tag, rq_optional}, - {"rtag", serve_rtag, rq_optional}, - {"import", serve_import, rq_optional}, - {"admin", serve_admin, rq_optional}, - {"export", serve_export, rq_optional}, - {"history", serve_history, rq_optional}, - {"release", serve_release, rq_optional}, - {NULL, NULL, rq_optional} -}; - -static void -serve_valid_requests (arg) - char *arg; -{ - struct request *rq; - printf ("Valid-requests"); - for (rq = requests; rq->name != NULL; rq++) - if (rq->func != NULL) - printf (" %s", rq->name); - printf ("\nok\n"); -} - -/* - * 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++; -} - -void -server_cleanup (sig) - int sig; -{ - /* Do "rm -rf" on the temp directory. */ - int len; - char *tempbuf; - 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 = "/usr/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. */ - - /* - * 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 = "/usr/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; -} diff --git a/src/server.h b/src/server.h deleted file mode 100644 index 3b037c3bce3b1fce91cb73e4063c2ab55916682d..0000000000000000000000000000000000000000 --- a/src/server.h +++ /dev/null @@ -1,123 +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 - -/* - * 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)); - - -/* Stuff shared with the client. */ -struct request -{ - /* Name of the request. */ - char *name; - - /* - * 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)); - - /* 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[]; diff --git a/src/status.c b/src/status.c deleted file mode 100644 index 746f83f2e02323f8e2e26dd2e365a070400a0dde..0000000000000000000000000000000000000000 --- a/src/status.c +++ /dev/null @@ -1,276 +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 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; - - if (client_active) { - start_server (); - - if (long_format) - fprintf (to_server, "Argument -v\n"); - if (local) - fprintf (to_server, "Argument -l\n"); - else - fprintf (to_server, "Argument -R\n"); - if (feof (to_server) || ferror (to_server)) - error (1, errno, "writing to server"); - - /* 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") == EOF) - error (1, errno, "writing to server"); - err = get_responses_and_close (); - - return err; - } - - /* start the recursion processor */ - err = start_recursion (status_fileproc, (int (*) ()) NULL, status_dirproc, - (int (*) ()) 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; - case T_PATCH: - sstat = "Needs Patch"; - break; - 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"); - else if (server_active) - (void) printf (" Working revision:\t%s\n", vers->vn_user); - 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 - (void) printf (" Sticky Tag:\t\t(none)\n"); - - if (edata->date) - (void) printf (" Sticky Date:\t\t%s\n", edata->date); - else - (void) printf (" Sticky Date:\t\t(none)\n"); - - if (edata->options && edata->options[0]) - (void) printf (" Sticky Options:\t%s\n", edata->options); - else - (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/src/subr.c b/src/subr.c deleted file mode 100644 index 76968c3afd17f5df31debf3d9439d4285ec4b431..0000000000000000000000000000000000000000 --- a/src/subr.c +++ /dev/null @@ -1,1045 +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 char rcsid[] = "$CVSid: @(#)subr.c 1.64 94/10/07 $"; -USE(rcsid) -#endif - -#ifdef _MINIX -#undef POSIX /* Minix 1.6 doesn't support POSIX.1 sigaction yet */ -#endif - -#ifdef HAVE_VPRINTF -#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) -#include <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 - -/* - * 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 -#ifndef _POSIX_SOURCE -/* - * NeXT doesn't define these without _POSIX_SOURCE, - * but that changes a lot of things. - */ -#define WEXITSTATUS(x) ((x).w_retcode) -#define WTERMSIG(x) ((x).w_termsig) -#endif -#endif - -static void run_add_arg PROTO((char *s)); -static void run_init_prog PROTO((void)); - -extern char *getlogin (); -extern char *strtok (); - -/* - * Copies "from" to "to". mallocs a buffer large enough to hold the entire - * file and does one read/one write to do the copy. This is reasonable, - * since source files are typically not too large. - */ -void -copy_file (from, to) - char *from; - char *to; -{ - struct stat sb; - struct utimbuf t; - int fdin, fdout; - char *buf; - - if (trace) - (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to); - 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) - { - buf = xmalloc ((int) sb.st_size); - if (read (fdin, buf, (int) sb.st_size) != (int) sb.st_size) - error (1, errno, "cannot read file %s for copying", from); - if (write (fdout, buf, (int) sb.st_size) != (int) sb.st_size -#ifdef HAVE_FSYNC - || fsync (fdout) == -1 -#endif - ) - { - error (1, errno, "cannot write file %s for copying", to); - } - free (buf); - } - (void) close (fdin); - 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) - 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) - 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) - char *file; -{ - struct stat sb; - - if (stat (file, &sb) < 0) - return (0); - return (1); -} - -/* - * Returns non-zero if the argument file is readable. - * XXX - must be careful if "cvs" is ever made setuid! - */ -int -isreadable (file) - char *file; -{ - return (access (file, R_OK) != -1); -} - -/* - * Returns non-zero if the argument file is writable - * XXX - muct be careful if "cvs" is ever made setuid! - */ -int -iswritable (file) - char *file; -{ - return (access (file, W_OK) != -1); -} - -/* - * Open a file and die if it fails - */ -FILE * -open_file (name, mode) - char *name; - char *mode; -{ - FILE *fp; - - if ((fp = fopen (name, mode)) == NULL) - error (1, errno, "cannot open %s", name); - return (fp); -} - -/* - * Open a file if allowed and return. - */ -FILE * -Fopen (name, mode) - char *name; - char *mode; -{ - if (trace) - (void) fprintf (stderr, "-> fopen(%s,%s)\n", name, mode); - if (noexec) - return (NULL); - - return (fopen (name, mode)); -} - -/* - * Make a directory and die if it fails - */ -void -make_directory (name) - char *name; -{ - struct stat buf; - - if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode))) - error (0, 0, "%s already exists but is not a directory", name); - if (!noexec && mkdir (name, 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) - char *name; -{ - char *cp; - - if (noexec) - return; - - if (mkdir (name, 0777) == 0 || errno == EEXIST) - return; - if (errno != ENOENT) - { - 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); -} - -/* - * malloc some data and die if it fails - */ -char * -xmalloc (bytes) - size_t bytes; -{ - char *cp; - - if ((cp = malloc (bytes)) == 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) - char *str; -{ - char *s; - - if (str == NULL) - return ((char *) NULL); - s = xmalloc (strlen (str) + 1); - (void) strcpy (s, str); - return (s); -} - -/* - * Change the mode of a file, either adding write permissions, or removing - * all write permissions. Adding write permissions honors the current umask - * setting. - */ -void -xchmod (fname, writable) - char *fname; - int writable; -{ - struct stat sb; - mode_t mode, oumask; - - if (stat (fname, &sb) < 0) - { - if (!noexec) - error (0, errno, "cannot stat %s", fname); - return; - } - if (writable) - { - oumask = umask (0); - (void) umask (oumask); - mode = sb.st_mode | ((S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask); - } - else - { - mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH); - } - - if (trace) - (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode); - 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) - char *from; - char *to; -{ - if (trace) - (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to); - 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) - char *from, *to; -{ - if (trace) - (void) fprintf (stderr, "-> link(%s,%s)\n", from, to); - if (noexec) - return (0); - - return (link (from, to)); -} - -/* - * unlink a file, if possible. - */ -int -unlink_file (f) - char *f; -{ - if (trace) - (void) fprintf (stderr, "-> unlink(%s)\n", f); - if (noexec) - return (0); - - return (unlink (f)); -} - -/* - * Compare "file1" to "file2". Return non-zero if they don't compare exactly. - * - * mallocs a buffer large enough to hold the entire file and does two reads to - * load the buffer and calls memcmp to do the cmp. This is reasonable, since - * source files are typically not too large. - */ - -/* richfix: this *could* exploit mmap. */ - -int -xcmp (file1, file2) - char *file1; - char *file2; -{ - register char *buf1, *buf2; - struct stat sb; - off_t size; - int ret, fd1, fd2; - - 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, &sb) < 0) - error (1, errno, "cannot fstat %s", file1); - size = sb.st_size; - if (fstat (fd2, &sb) < 0) - error (1, errno, "cannot fstat %s", file2); - if (size == sb.st_size) - { - if (size == 0) - ret = 0; - else - { - buf1 = xmalloc ((int) size); - buf2 = xmalloc ((int) size); - if (read (fd1, buf1, (int) size) != (int) size) - error (1, errno, "cannot read file %s for comparing", file1); - if (read (fd2, buf2, (int) size) != (int) size) - error (1, errno, "cannot read file %s for comparing", file2); - ret = memcmp(buf1, buf2, (int) size); - free (buf1); - free (buf2); - } - } - else - ret = 1; - (void) close (fd1); - (void) close (fd2); - return (ret); -} - -/* - * 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) - char *s; -{ - char *cp; - int dots = 0; - - for (cp = s; *cp; cp++) - { - if (*cp == '.') - 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 = getenv("LOGNAME")) || (name = getenv("USER")) || - (name = getlogin ())) && *name) - return (name); - } - if ((pw = (struct passwd *) getpwuid (uid)) == NULL) - { - (void) sprintf (uidname, "uid%lu", (unsigned long) uid); - return (uidname); - } - return (pw->pw_name); -} - -/* - * 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 (char *fmt,...) -#else -void -run_setup (fmt, a1, a2, a3, a4, a5, a6, a7, a8) - char *fmt; -#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) - char *s; -{ - run_add_arg (s); -} - -/* VARARGS */ -#if defined (HAVE_VPRINTF) && (defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)) -void -run_args (char *fmt,...) -#else -void -run_args (fmt, a1, a2, a3, a4, a5, a6, a7, a8) - char *fmt; -#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) - 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; -#if defined(NeXT) && !defined(_POSIX_SOURCE) - union wait status; -#else - int status; -#endif - int rc = -1; - int rerrno = 0; - int pid, w; - -#ifdef POSIX - 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) - { - (void) fprintf (stderr, "-> system("); - 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 - 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 - 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 - 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) - char *cmd, *mode; -{ - if (trace) - (void) fprintf (stderr, "-> Popen(%s,%s)\n", cmd, mode); - if (noexec) - return (NULL); - return (popen (cmd, mode)); -} - -#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)); -} - -#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 diff --git a/src/tag.c b/src/tag.c deleted file mode 100644 index 853148ec22ceda513db28562906c2fb054216954..0000000000000000000000000000000000000000 --- a/src/tag.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. - * - * 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 char rcsid[] = "$CVSid: @(#)tag.c 1.60 94/09/30 $"; -USE(rcsid) -#endif - -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 *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_move; /* don't force tag to move by default */ - -static const char *const tag_usage[] = -{ - "Usage: %s %s [-QlRqF] [-b] [-d] tag [files...]\n", - "\t-Q\tReally quiet.\n", - "\t-l\tLocal directory only, not recursive.\n", - "\t-R\tProcess directories recursively.\n", - "\t-q\tSomewhat quiet.\n", - "\t-d\tDelete the given Tag.\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, "FQqlRdb")) != -1) - { - switch (c) - { - case 'Q': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'd': - delete = 1; - 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); - - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (quiet) - if (fprintf (to_server, "Argument -q\n") == EOF) - error (1, errno, "writing to server"); - if (really_quiet) - if (fprintf (to_server, "Argument -Q\n") == EOF) - error (1, errno, "writing to server"); - if (delete) - if (fprintf (to_server, "Argument -d\n") == EOF) - error (1, errno, "writing to server"); - if (branch_mode) - if (fprintf (to_server, "Argument -b\n") == EOF) - error (1, errno, "writing to server"); - if (force_tag_move) - if (fprintf (to_server, "Argument -F\n") == EOF) - error (1, errno, "writing to server"); - - 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") == EOF) - error (1, errno, "writing to server"); - return get_responses_and_close (); - } - - /* start the recursion processor */ - err = start_recursion (tag_fileproc, (int (*) ()) NULL, tag_dirproc, - (int (*) ()) NULL, argc, argv, local, - W_LOCAL, 0, 1, (char *) NULL, 1, 0); - return (err); -} - -/* - * 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 *rev; - Vers_TS *vers; - int retcode = 0; - - vers = Version_TS (repository, (char *) NULL, (char *) NULL, (char *) NULL, - file, 0, 0, entries, srcfiles); - - 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); - if (version == NULL || vers->srcfile == NULL) - { - freevers_ts (&vers); - return (0); - } - free (version); - - run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag); - run_arg (vers->srcfile->path); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 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. - */ - version = vers->vn_user; - 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); - 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); - } - - run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev); - run_arg (vers->srcfile->path); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 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); - 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/src/update.c b/src/update.c deleted file mode 100644 index 1744c7572482f59688d30bc9c318cffc3667a247..0000000000000000000000000000000000000000 --- a/src/update.c +++ /dev/null @@ -1,1813 +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" -#include "update.h" -#include "md5.h" - -#ifndef lint -static 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:\n %s %s [-APQdflRpq] [-k kopt] [-r rev|-D date] [-j rev] [-I ign] [files...]\n", - "\t-A\tReset any sticky tags/date/kopts.\n", - "\t-P\tPrune empty directories.\n", - "\t-Q\tReally quiet.\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-q\tSomewhat quiet.\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", - 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 (); - - /* parse the args */ - optind = 1; - while ((c = getopt (argc, argv, "ApPflRQqduk:r:D:j:I:")) != -1) - { - switch (c) - { - case 'A': - aflag = 1; - break; - case 'I': - ign_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': - really_quiet = 1; - /* FALL THROUGH */ - case 'q': - quiet = 1; - 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': - if (server_active) - patches = 1; - else - usage (update_usage); - break; - case '?': - default: - usage (update_usage); - break; - } - } - argc -= optind; - argv += optind; - - 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) - if (fprintf (to_server, "Argument -l\n") == EOF) - error (1, errno, "writing to server"); - if (quiet) - if (fprintf (to_server, "Argument -q\n") == EOF) - error (1, errno, "writing to server"); - if (really_quiet) - if (fprintf (to_server, "Argument -Q\n") == EOF) - error (1, errno, "writing to server"); - if (update_build_dirs) - if (fprintf (to_server, "Argument -d\n") == EOF) - error (1, errno, "writing to server"); - if (pipeout) - if (fprintf (to_server, "Argument -p\n") == EOF) - error (1, errno, "writing to server"); - if (!force_tag_match) - if (fprintf (to_server, "Argument -f\n") == EOF) - error (1, errno, "writing to server"); - if (aflag) - if (fprintf (to_server, "Argument -A\n") == EOF) - error (1, errno, "writing to server"); - if (update_prune_dirs) - if (fprintf (to_server, "Argument -P\n") == EOF) - error (1, errno, "writing to server"); - 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) - { - if (fprintf (to_server, "Argument -u\n") == EOF) - error (1, errno, "writing to server"); - } - 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") == EOF) - error (1, errno, "writing to server"); - - status = get_responses_and_close (); - if (status != 0) - return status; - - } while (failed_patches != NULL); - - return 0; - } - - /* - * 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 && errno != ENOENT) - error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); - if (server_active) - server_clear_entstat (".", Name_Repository (NULL, NULL)); - } - - /* keep the CVS/Tag file current with the specified arguments */ - if (aflag || tag || date) - { - WriteTag ((char *) NULL, tag, date); - if (server_active) - server_set_sticky (".", Name_Repository (NULL, NULL), tag, date); - } - } - - /* 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 */ - case T_PATCH: /* needs patch */ - 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 */ - 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. - */ - if (server_active) - retcode = vers->ts_conflict[0] != '='; - else { - filestamp = time_stamp (file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); - } - - if (retcode) - { - /* - * If the timestamps differ, look for Conflict - * indicators to see if 'C' anyway. - */ - run_setup ("%s -s", GREP); - run_arg (RCS_MERGE_PAT); - run_arg (file); - retcode = run_exec (RUN_TTY, RUN_TTY, - 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; - 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. */ - case T_CHECKOUT: /* needs checkout */ - retval = checkout_file (file, repository, entries, srcfiles, - vers, update_dir); - if (server_active && retval == 0) - server_updated (file, update_dir, repository, - SERVER_UPDATED, (struct stat *) NULL, - (unsigned char *) NULL); - 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); - if (server_active && retval == 0) - server_updated (file, update_dir, repository, - SERVER_UPDATED, (struct stat *) NULL, - (unsigned char *) NULL); - 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 - else if (!server_active) - { - /* 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 && errno != ENOENT) - error (1, errno, "cannot remove file %s", tmp); - if (server_active) - server_clear_entstat (update_dir, repository); - } - - /* keep the CVS/Tag file current with the specified arguments */ - if (aflag || tag || date) - { - WriteTag (dir, tag, date); - if (server_active) - server_set_sticky (update_dir, repository, tag, date); - } - - /* 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); - } - - /* 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 && - strcmp (dp->d_name, OCVSADM) != 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_rcs, - 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; - - 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'; - - (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 && errno != ENOENT) - { - 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) - { - /* Assumes diff -u is supported. */ - run_setup ("%s -u %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); - - /* We pass -E to rcsmerge so that it will not indicate a conflict if - both things we are merging are modified the same way. - - Well, okay, but my rcsmerge doesn't take a -E option. --JimB */ - /* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */ - run_setup ("%s%s %s -r%s -r%s", Rcsbin, RCS_RCSMERGE, vers->options, - vers->vn_user, vers->vn_rcs); - run_arg (vers->srcfile->path); - status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - if (status != 0 -#ifdef HAVE_RCS5 - && status != 1 -#endif - ) - { - 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); - } - - /* 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); - } - - 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); - } - - /* possibly run GREP to see if there appear to be conflicts in the file */ - run_setup ("%s -s", GREP); - run_arg (RCS_MERGE_PAT); - run_arg (file); - if (status == 1 || - (retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) == 0) - { - 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; - - /* 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; - } - - /* convert the second rev spec, walking branches and dates. */ - - rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1); - 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. */ - - 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); - 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); - 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); - 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); - 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); - 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 */ - - 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); - } - - /* - * 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 - - /* We pass -E to rcsmerge so that it will not indicate a conflict if - both things we are merging are modified the same way. - - Well, okay, but my rcsmerge doesn't take a -E option. --JimB */ - /* XXX - Do merge by hand instead of using rcsmerge, due to -k handling */ - run_setup ("%s%s %s -r%s -r%s", Rcsbin, RCS_RCSMERGE, options, - rev1, rev2); - run_arg (vers->srcfile->path); - status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); - if (status != 0 -#ifdef HAVE_RCS5 - && status != 1 -#endif - ) - { - 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 HAVE_RCS5 - if (status == 1) - { - 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); - } -#endif - - 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); - } - - return; -} - -/* - * 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); - 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/src/update.h b/src/update.h deleted file mode 100644 index 68c91d55ab932f3436944d476310730f2a4aedf4..0000000000000000000000000000000000000000 --- a/src/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/src/vers_ts.c b/src/vers_ts.c deleted file mode 100644 index a799c3b12193eb02348c77c22a38c7b8a58e6729..0000000000000000000000000000000000000000 --- a/src/vers_ts.c +++ /dev/null @@ -1,307 +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 char rcsid[] = "$CVSid: @(#)vers_ts.c 1.45 94/10/07 $"; -USE(rcsid) -#endif - -#define ctime(X) do not use ctime, please - -extern int use_unchanged; /* in server.c */ - -static void time_stamp_server PROTO((char *, Vers_TS *)); - -/* - * Fill in and return a Vers_TS structure "user" is the name of the local - * file; entries is the entries file - preparsed for our pleasure. xfiles is - * all source code control files, preparsed for our pleasure - */ -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); - else - vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag, - vers_ts->date, force_tag_match); -#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) - { - if (server_active) - time_stamp_server (user, vers_ts); - else - 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; - char *ts; - - if (stat (file, &sb) < 0) - { - if (errno != ENOENT) - 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)->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/src/version.c b/src/version.c deleted file mode 100644 index 957e94af74e1a4ed3a57d0f2088125bb6fa67737..0000000000000000000000000000000000000000 --- a/src/version.c +++ /dev/null @@ -1,20 +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 char rcsid[] = "$CVSid: @(#)version.c 1.15 94/10/03 $"; -USE(rcsid) -#endif - -char *version_string = "\nConcurrent Versions System (CVS) 1.4 Alpha-2(+1)\n"; diff --git a/stamp-h.in b/stamp-h.in deleted file mode 100644 index bb5e5e3873f841fd419ae93dd0e212c97255f26c..0000000000000000000000000000000000000000 --- a/stamp-h.in +++ /dev/null @@ -1 +0,0 @@ -Wed Oct 5 15:45:29 EDT 1994