aboutsummaryrefslogtreecommitdiff
path: root/contrib/cvs/src/rcscmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/rcscmds.c')
-rw-r--r--contrib/cvs/src/rcscmds.c628
1 files changed, 0 insertions, 628 deletions
diff --git a/contrib/cvs/src/rcscmds.c b/contrib/cvs/src/rcscmds.c
deleted file mode 100644
index 18182ffce86c..000000000000
--- a/contrib/cvs/src/rcscmds.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
- *
- * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
- * and others.
- *
- * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
- * Portions 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 source distribution.
- *
- * The functions in this file provide an interface for performing
- * operations directly on RCS files.
- *
- * $FreeBSD$
- */
-
-#include "cvs.h"
-#include <assert.h>
-#include <stdio.h>
-#include "diffrun.h"
-
-/* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
- library", are intended to define our interface to RCS files.
-
- Whether there will also be a version of RCS which uses this
- library, or whether the library will be packaged for uses beyond
- CVS or RCS (many people would like such a thing) is an open
- question. Some considerations:
-
- 1. An RCS library for CVS must have the capabilities of the
- existing CVS code which accesses RCS files. In particular, simple
- approaches will often be slow.
-
- 2. An RCS library should not use code from the current RCS
- (5.7 and its ancestors). The code has many problems. Too few
- comments, too many layers of abstraction, too many global variables
- (the correct number for a library is zero), too much intricately
- interwoven functionality, and too many clever hacks. Paul Eggert,
- the current RCS maintainer, agrees.
-
- 3. More work needs to be done in terms of separating out the RCS
- library from the rest of CVS (for example, cvs_output should be
- replaced by a callback, and the declarations should be centralized
- into rcs.h, and probably other such cleanups).
-
- 4. To be useful for RCS and perhaps for other uses, the library
- may need features beyond those needed by CVS.
-
- 5. Any changes to the RCS file format *must* be compatible. Many,
- many tools (not just CVS and RCS) can at least import this format.
- RCS and CVS must preserve the current ability to import/export it
- (preferably improved--magic branches are currently a roadblock).
- See doc/RCSFILES in the CVS distribution for documentation of this
- file format.
-
- On a related note, see the comments at diff_exec, later in this file,
- for more on the diff library. */
-
-static void RCS_output_diff_options PROTO ((int, char *const *, const char *,
- const char *, const char *));
-
-
-/* Stuff to deal with passing arguments the way libdiff.a wants to deal
- with them. This is a crufty interface; there is no good reason for it
- to resemble a command line rather than something closer to "struct
- log_data" in log.c. */
-
-/* First call call_diff_setup to setup any initial arguments. The
- argument will be parsed into whitespace separated words and added
- to the global call_diff_argv list.
-
- Then, optionally, call call_diff_add_arg for each additional argument
- that you'd like to pass to the diff library.
-
- Finally, call call_diff or call_diff3 to produce the diffs. */
-
-static char **call_diff_argv;
-static int call_diff_argc;
-static size_t call_diff_argc_allocated;
-
-static void call_diff_add_arg PROTO ((const char *));
-static void call_diff_setup PROTO ((const char *prog,
- int argc, char * const *argv));
-static int call_diff PROTO ((const char *out));
-static int call_diff3 PROTO ((char *out));
-
-static void call_diff_write_output PROTO((const char *, size_t));
-static void call_diff_flush_output PROTO((void));
-static void call_diff_write_stdout PROTO((const char *));
-static void call_diff_error PROTO((const char *, const char *, const char *));
-
-
-
-static void
-call_diff_add_arg (s)
- const char *s;
-{
- run_add_arg_p (&call_diff_argc, &call_diff_argc_allocated, &call_diff_argv,
- s);
-}
-
-
-
-/* VARARGS */
-static void
-call_diff_setup (prog, argc, argv)
- const char *prog;
- int argc;
- char * const *argv;
-{
- int i;
-
- /* clean out any malloc'ed values from call_diff_argv */
- run_arg_free_p (call_diff_argc, call_diff_argv);
- call_diff_argc = 0;
-
- /* put each word into call_diff_argv, allocating it as we go */
- call_diff_add_arg (prog);
- for (i = 0; i < argc; i++)
- call_diff_add_arg (argv[i]);
-}
-
-
-/* Callback function for the diff library to write data to the output
- file. This is used when we are producing output to stdout. */
-
-static void
-call_diff_write_output (text, len)
- const char *text;
- size_t len;
-{
- if (len > 0)
- cvs_output (text, len);
-}
-
-/* Call back function for the diff library to flush the output file.
- This is used when we are producing output to stdout. */
-
-static void
-call_diff_flush_output ()
-{
- cvs_flushout ();
-}
-
-/* Call back function for the diff library to write to stdout. */
-
-static void
-call_diff_write_stdout (text)
- const char *text;
-{
- cvs_output (text, 0);
-}
-
-/* Call back function for the diff library to write to stderr. */
-
-static void
-call_diff_error (format, a1, a2)
- const char *format;
- const char *a1;
- const char *a2;
-{
- /* FIXME: Should we somehow indicate that this error is coming from
- the diff library? */
- error (0, 0, format, a1, a2);
-}
-
-/* This set of callback functions is used if we are sending the diff
- to stdout. */
-
-static struct diff_callbacks call_diff_stdout_callbacks =
-{
- call_diff_write_output,
- call_diff_flush_output,
- call_diff_write_stdout,
- call_diff_error
-};
-
-/* This set of callback functions is used if we are sending the diff
- to a file. */
-
-static struct diff_callbacks call_diff_file_callbacks =
-{
- (void (*) PROTO((const char *, size_t))) NULL,
- (void (*) PROTO((void))) NULL,
- call_diff_write_stdout,
- call_diff_error
-};
-
-
-
-static int
-call_diff (out)
- const char *out;
-{
- call_diff_add_arg (NULL);
-
- if (out == RUN_TTY)
- return diff_run (call_diff_argc, call_diff_argv, NULL,
- &call_diff_stdout_callbacks);
- else
- return diff_run (call_diff_argc, call_diff_argv, out,
- &call_diff_file_callbacks);
-}
-
-
-
-static int
-call_diff3 (out)
- char *out;
-{
- if (out == RUN_TTY)
- return diff3_run (call_diff_argc, call_diff_argv, NULL,
- &call_diff_stdout_callbacks);
- else
- return diff3_run (call_diff_argc, call_diff_argv, out,
- &call_diff_file_callbacks);
-}
-
-
-
-/* Merge revisions REV1 and REV2. */
-
-int
-RCS_merge(rcs, path, workfile, options, rev1, rev2)
- RCSNode *rcs;
- const char *path;
- const char *workfile;
- const char *options;
- const char *rev1;
- const char *rev2;
-{
- char *xrev1, *xrev2;
- char *tmp1, *tmp2;
- char *diffout = NULL;
- int retval;
-
- if (options != NULL && options[0] != '\0')
- assert (options[0] == '-' && options[1] == 'k');
-
- cvs_output ("RCS file: ", 0);
- cvs_output (rcs->path, 0);
- cvs_output ("\n", 1);
-
- /* Calculate numeric revision numbers from rev1 and rev2 (may be
- symbolic). */
- xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
- xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
- assert (xrev1 && xrev2);
-
- /* Check out chosen revisions. The error message when RCS_checkout
- fails is not very informative -- it is taken verbatim from RCS 5.7,
- and relies on RCS_checkout saying something intelligent upon failure. */
- cvs_output ("retrieving revision ", 0);
- cvs_output (xrev1, 0);
- cvs_output ("\n", 1);
-
- tmp1 = cvs_temp_name();
- if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1,
- (RCSCHECKOUTPROC)0, NULL))
- {
- cvs_outerr ("rcsmerge: co failed\n", 0);
- error_exit();
- }
-
- cvs_output ("retrieving revision ", 0);
- cvs_output (xrev2, 0);
- cvs_output ("\n", 1);
-
- tmp2 = cvs_temp_name();
- if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2,
- (RCSCHECKOUTPROC)0, NULL))
- {
- cvs_outerr ("rcsmerge: co failed\n", 0);
- error_exit();
- }
-
- /* Merge changes. */
- cvs_output ("Merging differences between ", 0);
- cvs_output (xrev1, 0);
- cvs_output (" and ", 0);
- cvs_output (xrev2, 0);
- cvs_output (" into ", 0);
- cvs_output (workfile, 0);
- cvs_output ("\n", 1);
-
- /* Remember that the first word in the `call_diff_setup' string is used now
- only for diagnostic messages -- CVS no longer forks to run diff3. */
- diffout = cvs_temp_name();
- call_diff_setup ("diff3", 0, NULL);
- call_diff_add_arg ("-E");
- call_diff_add_arg ("-am");
-
- call_diff_add_arg ("-L");
- call_diff_add_arg (workfile);
- call_diff_add_arg ("-L");
- call_diff_add_arg (xrev1);
- call_diff_add_arg ("-L");
- call_diff_add_arg (xrev2);
-
- call_diff_add_arg ("--");
- call_diff_add_arg (workfile);
- call_diff_add_arg (tmp1);
- call_diff_add_arg (tmp2);
-
- retval = call_diff3 (diffout);
-
- if (retval == 1)
- cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
- else if (retval == 2)
- error_exit();
-
- if (diffout)
- copy_file (diffout, workfile);
-
- /* Clean up. */
- {
- int save_noexec = noexec;
- noexec = 0;
- if (unlink_file (tmp1) < 0)
- {
- if (!existence_error (errno))
- error (0, errno, "cannot remove temp file %s", tmp1);
- }
- free (tmp1);
- if (unlink_file (tmp2) < 0)
- {
- if (!existence_error (errno))
- error (0, errno, "cannot remove temp file %s", tmp2);
- }
- free (tmp2);
- if (diffout)
- {
- if (unlink_file (diffout) < 0)
- {
- if (!existence_error (errno))
- error (0, errno, "cannot remove temp file %s", diffout);
- }
- free (diffout);
- }
- free (xrev1);
- free (xrev2);
- noexec = save_noexec;
- }
-
- return retval;
-}
-
-/* Diff revisions and/or files. OPTS controls the format of the diff
- (it contains options such as "-w -c", &c), or "" for the default.
- OPTIONS controls keyword expansion, as a string starting with "-k",
- or "" to use the default. REV1 is the first revision to compare
- against; it must be non-NULL. If REV2 is non-NULL, compare REV1
- and REV2; if REV2 is NULL compare REV1 with the file in the working
- directory, whose name is WORKFILE. LABEL1 and LABEL2 are default
- file labels, and (if non-NULL) should be added as -L options
- to diff. Output goes to stdout.
-
- Return value is 0 for success, -1 for a failure which set errno,
- or positive for a failure which printed a message on stderr.
-
- This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
-
- An issue is what timezone is used for the dates which appear in the
- diff output. rcsdiff uses the -z flag, which is not presently
- processed by CVS diff, but I'm not sure exactly how hard to worry
- about this--any such features are undocumented in the context of
- CVS, and I'm not sure how important to users. */
-int
-RCS_exec_rcsdiff (rcsfile, diff_argc, diff_argv, options, rev1, rev1_cache,
- rev2, label1, label2, workfile)
- RCSNode *rcsfile;
- int diff_argc;
- char * const *diff_argv;
- const char *options;
- const char *rev1;
- const char *rev1_cache;
- const char *rev2;
- const char *label1;
- const char *label2;
- const char *workfile;
-{
- char *tmpfile1 = NULL;
- char *tmpfile2 = NULL;
- const char *use_file1, *use_file2;
- int status, retval;
-
-
- cvs_output ("\
-===================================================================\n\
-RCS file: ", 0);
- cvs_output (rcsfile->path, 0);
- cvs_output ("\n", 1);
-
- /* Historically, `cvs diff' has expanded the $Name keyword to the
- empty string when checking out revisions. This is an accident,
- but no one has considered the issue thoroughly enough to determine
- what the best behavior is. Passing NULL for the `nametag' argument
- preserves the existing behavior. */
-
- cvs_output ("retrieving revision ", 0);
- cvs_output (rev1, 0);
- cvs_output ("\n", 1);
-
- if (rev1_cache != NULL)
- use_file1 = rev1_cache;
- else
- {
- tmpfile1 = cvs_temp_name();
- status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
- (RCSCHECKOUTPROC)0, NULL);
- if (status > 0)
- {
- retval = status;
- goto error_return;
- }
- else if (status < 0)
- {
- error( 0, errno,
- "cannot check out revision %s of %s", rev1, rcsfile->path );
- retval = 1;
- goto error_return;
- }
- use_file1 = tmpfile1;
- }
-
- if (rev2 == NULL)
- {
- assert (workfile != NULL);
- use_file2 = workfile;
- }
- else
- {
- tmpfile2 = cvs_temp_name ();
- cvs_output ("retrieving revision ", 0);
- cvs_output (rev2, 0);
- cvs_output ("\n", 1);
- status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
- tmpfile2, (RCSCHECKOUTPROC)0, NULL);
- if (status > 0)
- {
- retval = status;
- goto error_return;
- }
- else if (status < 0)
- {
- error (0, errno,
- "cannot check out revision %s of %s", rev2, rcsfile->path);
- return 1;
- }
- use_file2 = tmpfile2;
- }
-
- RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile);
- status = diff_exec (use_file1, use_file2, label1, label2,
- diff_argc, diff_argv, RUN_TTY);
- if (status >= 0)
- {
- retval = status;
- goto error_return;
- }
- else if (status < 0)
- {
- error (0, errno,
- "cannot diff %s and %s", use_file1, use_file2);
- retval = 1;
- goto error_return;
- }
-
- error_return:
- {
- /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
- * for noexec.
- */
- if( tmpfile1 != NULL )
- {
- if( CVS_UNLINK( tmpfile1 ) < 0 )
- {
- if( !existence_error( errno ) )
- error( 0, errno, "cannot remove temp file %s", tmpfile1 );
- }
- free( tmpfile1 );
- }
- if( tmpfile2 != NULL )
- {
- if( CVS_UNLINK( tmpfile2 ) < 0 )
- {
- if( !existence_error( errno ) )
- error( 0, errno, "cannot remove temp file %s", tmpfile2 );
- }
- free (tmpfile2);
- }
- }
-
- return retval;
-}
-
-
-
-/* Show differences between two files. This is the start of a diff library.
-
- Some issues:
-
- * Should option parsing be part of the library or the caller? The
- former allows the library to add options without changing the callers,
- but it causes various problems. One is that something like --brief really
- wants special handling in CVS, and probably the caller should retain
- some flexibility in this area. Another is online help (the library could
- have some feature for providing help, but how does that interact with
- the help provided by the caller directly?). Another is that as things
- stand currently, there is no separate namespace for diff options versus
- "cvs diff" options like -l (that is, if the library adds an option which
- conflicts with a CVS option, it is trouble).
-
- * This isn't required for a first-cut diff library, but if there
- would be a way for the caller to specify the timestamps that appear
- in the diffs (rather than the library getting them from the files),
- that would clean up the kludgy utime() calls in patch.c.
-
- Show differences between FILE1 and FILE2. Either one can be
- DEVNULL to indicate a nonexistent file (same as an empty file
- currently, I suspect, but that may be an issue in and of itself).
- OPTIONS is a list of diff options, or "" if none. At a minimum,
- CVS expects that -c (update.c, patch.c) and -n (update.c) will be
- supported. Other options, like -u, --speed-large-files, &c, will
- be specified if the user specified them.
-
- OUT is a filename to send the diffs to, or RUN_TTY to send them to
- stdout. Error messages go to stderr. Return value is 0 for
- success, -1 for a failure which set errno, 1 for success (and some
- differences were found), or >1 for a failure which printed a
- message on stderr. */
-
-int
-diff_exec (file1, file2, label1, label2, dargc, dargv, out)
- const char *file1;
- const char *file2;
- const char *label1;
- const char *label2;
- int dargc;
- char * const *dargv;
- const char *out;
-{
-#ifdef PRESERVE_PERMISSIONS_SUPPORT
- /* If either file1 or file2 are special files, pretend they are
- /dev/null. Reason: suppose a file that represents a block
- special device in one revision becomes a regular file. CVS
- must find the `difference' between these files, but a special
- file contains no data useful for calculating this metric. The
- safe thing to do is to treat the special file as an empty file,
- thus recording the regular file's full contents. Doing so will
- create extremely large deltas at the point of transition
- between device files and regular files, but this is probably
- very rare anyway.
-
- There may be ways around this, but I think they are fraught
- with danger. -twp */
-
- if (preserve_perms &&
- strcmp (file1, DEVNULL) != 0 &&
- strcmp (file2, DEVNULL) != 0)
- {
- struct stat sb1, sb2;
-
- if (CVS_LSTAT (file1, &sb1) < 0)
- error (1, errno, "cannot get file information for %s", file1);
- if (CVS_LSTAT (file2, &sb2) < 0)
- error (1, errno, "cannot get file information for %s", file2);
-
- if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
- file1 = DEVNULL;
- if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
- file2 = DEVNULL;
- }
-#endif
-
- /* The first arg to call_diff_setup is used only for error reporting. */
- call_diff_setup ("diff", dargc, dargv);
- if (label1)
- call_diff_add_arg (label1);
- if (label2)
- call_diff_add_arg (label2);
- call_diff_add_arg ("--");
- call_diff_add_arg (file1);
- call_diff_add_arg (file2);
-
- return call_diff (out);
-}
-
-/* Print the options passed to DIFF, in the format used by rcsdiff.
- The rcsdiff code that produces this output is extremely hairy, and
- it is not clear how rcsdiff decides which options to print and
- which not to print. The code below reproduces every rcsdiff run
- that I have seen. */
-
-static void
-RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile)
- int diff_argc;
- char * const *diff_argv;
- const char *rev1;
- const char *rev2;
- const char *workfile;
-{
- int i;
-
- cvs_output ("diff", 0);
- for (i = 0; i < diff_argc; i++)
- {
- cvs_output (" ", 1);
- cvs_output (diff_argv[i], 0);
- }
- cvs_output (" -r", 3);
- cvs_output (rev1, 0);
-
- if (rev2)
- {
- cvs_output (" -r", 3);
- cvs_output (rev2, 0);
- }
- else
- {
- assert (workfile != NULL);
- cvs_output (" ", 1);
- cvs_output (workfile, 0);
- }
- cvs_output ("\n", 1);
-}