diff options
author | eadler <eadler@FreeBSD.org> | 2013-06-15 20:29:07 +0000 |
---|---|---|
committer | eadler <eadler@FreeBSD.org> | 2013-06-15 20:29:07 +0000 |
commit | bf7c0f2705c32e44d3c3b62d60453a30dbbffe3f (patch) | |
tree | dca088b474d4fedf5e6d4ef16e823d7756d587bc /contrib/cvs/src/diff.c | |
parent | b95c459e182fd072e6dac884c7eed86a220534e7 (diff) | |
download | FreeBSD-src-bf7c0f2705c32e44d3c3b62d60453a30dbbffe3f.zip FreeBSD-src-bf7c0f2705c32e44d3c3b62d60453a30dbbffe3f.tar.gz |
Remove CVS from the base system.
Discussed with: many
Reviewed by: peter, zi
Approved by: core
Diffstat (limited to 'contrib/cvs/src/diff.c')
-rw-r--r-- | contrib/cvs/src/diff.c | 1178 |
1 files changed, 0 insertions, 1178 deletions
diff --git a/contrib/cvs/src/diff.c b/contrib/cvs/src/diff.c deleted file mode 100644 index 8a61f9a..0000000 --- a/contrib/cvs/src/diff.c +++ /dev/null @@ -1,1178 +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. - * - * 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. - * - * $FreeBSD$ - */ - -#include <assert.h> -#include "cvs.h" - -enum diff_file -{ - DIFF_ERROR, - DIFF_ADDED, - DIFF_REMOVED, - DIFF_DIFFERENT, - DIFF_SAME -}; - -static Dtype diff_dirproc PROTO ((void *callerdat, const char *dir, - const char *pos_repos, - const char *update_dir, - List *entries)); -static int diff_filesdoneproc PROTO ((void *callerdat, int err, - const char *repos, - const char *update_dir, - List *entries)); -static int diff_dirleaveproc PROTO ((void *callerdat, const char *dir, - int err, const char *update_dir, - List *entries)); -static enum diff_file diff_file_nodiff PROTO(( struct file_info *finfo, - Vers_TS *vers, - enum diff_file, - char **rev1_cache )); -static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static void diff_mark_errors PROTO((int err)); - - -/* Global variables. Would be cleaner if we just put this stuff in a - struct like log.c does. */ - -/* Command line tags, from -r option. Points into argv. */ -static char *diff_rev1, *diff_rev2; -/* Command line dates, from -D option. Malloc'd. */ -static char *diff_date1, *diff_date2; -static char *diff_join1, *diff_join2; -static char *use_rev1, *use_rev2; -static int have_rev1_label, have_rev2_label; - -/* 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; - -static char *options; -static char **diff_argv; -static int diff_argc; -static size_t diff_arg_allocated; -static int diff_errors; -static int empty_files = 0; - -static const char *const diff_usage[] = -{ - "Usage: %s %s [-lR] [-k kopt] [format_options]\n", - " [[-r rev1 | -D date1] [-r rev2 | -D date2]] [files...] \n", - "\t-l\tLocal directory only, not recursive\n", - "\t-R\tProcess directories recursively.\n", - "\t-k kopt\tSpecify keyword expansion mode.\n", - "\t-D d1\tDiff revision for date against working file.\n", - "\t-D d2\tDiff rev1/date1 against date2.\n", - "\t-r rev1\tDiff revision for rev1 against working file.\n", - "\t-r rev2\tDiff rev1/date1 against rev2.\n", - "\nformat_options:\n", - " -i --ignore-case Consider upper- and lower-case to be the same.\n", - " -w --ignore-all-space Ignore all white space.\n", - " -b --ignore-space-change Ignore changes in the amount of white space.\n", - " -B --ignore-blank-lines Ignore changes whose lines are all blank.\n", - " -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n", - " --binary Read and write data in binary mode.\n", - " -a --text Treat all files as text.\n\n", - " -c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.\n", - " -u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.\n", - " -NUM Use NUM context lines.\n", - " -L LABEL --label LABEL Use LABEL instead of file name.\n", - " -p --show-c-function Show which C function each change is in.\n", - " -F RE --show-function-line=RE Show the most recent line matching RE.\n", - " --brief Output only whether files differ.\n", - " -e --ed Output an ed script.\n", - " -f --forward-ed Output something like an ed script in forward order.\n", - " -n --rcs Output an RCS format diff.\n", - " -y --side-by-side Output in two columns.\n", - " -W NUM --width=NUM Output at most NUM (default 130) characters per line.\n", - " --left-column Output only the left column of common lines.\n", - " --suppress-common-lines Do not output common lines.\n", - " --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.\n", - " --GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.\n", - " --line-format=LFMT Similar, but format all input lines with LFMT.\n", - " --LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.\n", - " LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.\n", - " GFMT may contain:\n", - " %%< lines from FILE1\n", - " %%> lines from FILE2\n", - " %%= lines common to FILE1 and FILE2\n", - " %%[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER\n", - " LETTERs are as follows for new group, lower case for old group:\n", - " F first line number\n", - " L last line number\n", - " N number of lines = L-F+1\n", - " E F-1\n", - " M L+1\n", - " LFMT may contain:\n", - " %%L contents of line\n", - " %%l contents of line, excluding any trailing newline\n", - " %%[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number\n", - " Either GFMT or LFMT may contain:\n", - " %%%% %%\n", - " %%c'C' the single character C\n", - " %%c'\\OOO' the character with octal code OOO\n\n", - " -t --expand-tabs Expand tabs to spaces in output.\n", - " -T --initial-tab Make tabs line up by prepending a tab.\n\n", - " -N --new-file Treat absent files as empty.\n", - " -s --report-identical-files Report when two files are the same.\n", - " --horizon-lines=NUM Keep NUM lines of the common prefix and suffix.\n", - " -d --minimal Try hard to find a smaller set of changes.\n", - " -H --speed-large-files Assume large files and many scattered small changes.\n", - "\n(Specify the --help global option for a list of other help options)\n", - NULL -}; - -/* I copied this array directly out of diff.c in diffutils 2.7, after - removing the following entries, none of which seem relevant to use - with CVS: - --help - --version (-v) - --recursive (-r) - --unidirectional-new-file (-P) - --starting-file (-S) - --exclude (-x) - --exclude-from (-X) - --sdiff-merge-assist - --paginate (-l) (doesn't work with library callbacks) - - I changed the options which take optional arguments (--context and - --unified) to return a number rather than a letter, so that the - optional argument could be handled more easily. I changed the - --brief and --ifdef options to return numbers, since -q and -D mean - something else to cvs diff. - - The numbers 129- that appear in the fourth element of some entries - tell the big switch in `diff' how to process those options. -- Ian - - The following options, which diff lists as "An alias, no longer - recommended" have been removed: --file-label --entire-new-file - --ascii --print. */ - -static struct option const longopts[] = -{ - {"ignore-blank-lines", 0, 0, 'B'}, - {"context", 2, 0, 143}, - {"ifdef", 1, 0, 131}, - {"show-function-line", 1, 0, 'F'}, - {"speed-large-files", 0, 0, 'H'}, - {"ignore-matching-lines", 1, 0, 'I'}, - {"label", 1, 0, 'L'}, - {"new-file", 0, 0, 'N'}, - {"initial-tab", 0, 0, 'T'}, - {"width", 1, 0, 'W'}, - {"text", 0, 0, 'a'}, - {"ignore-space-change", 0, 0, 'b'}, - {"minimal", 0, 0, 'd'}, - {"ed", 0, 0, 'e'}, - {"forward-ed", 0, 0, 'f'}, - {"ignore-case", 0, 0, 'i'}, - {"rcs", 0, 0, 'n'}, - {"show-c-function", 0, 0, 'p'}, - - /* This is a potentially very useful option, except the output is so - silly. It would be much better for it to look like "cvs rdiff -s" - which displays all the same info, minus quite a few lines of - extraneous garbage. */ - {"brief", 0, 0, 145}, - - {"report-identical-files", 0, 0, 's'}, - {"expand-tabs", 0, 0, 't'}, - {"ignore-all-space", 0, 0, 'w'}, - {"side-by-side", 0, 0, 'y'}, - {"unified", 2, 0, 146}, - {"left-column", 0, 0, 129}, - {"suppress-common-lines", 0, 0, 130}, - {"old-line-format", 1, 0, 132}, - {"new-line-format", 1, 0, 133}, - {"unchanged-line-format", 1, 0, 134}, - {"line-format", 1, 0, 135}, - {"old-group-format", 1, 0, 136}, - {"new-group-format", 1, 0, 137}, - {"unchanged-group-format", 1, 0, 138}, - {"changed-group-format", 1, 0, 139}, - {"horizon-lines", 1, 0, 140}, - {"binary", 0, 0, 142}, - {0, 0, 0, 0} -}; - - - -/* Add one of OPT or LONGOPT, and ARGUMENT, when present, to global DIFF_ARGV. - * - * INPUTS - * opt A character option representation. - * longopt A long option name. - * argument Optional option argument. - * - * GLOBALS - * diff_argc The number of arguments in DIFF_ARGV. - * diff_argv Array of argument strings. - * diff_arg_allocated Allocated length of DIFF_ARGV. - * - * NOTES - * Behavior when both OPT & LONGOPT are provided is undefined. - * - * RETURNS - * Nothing. - */ -static void -add_diff_args (char opt, const char *longopt, const char *argument) -{ - char *tmp; - - /* Add opt or longopt to diff_arv. */ - assert (opt || (longopt && *longopt)); - assert (!(opt && (longopt && *longopt))); - if (opt) - { - tmp = xmalloc (3); - sprintf (tmp, "-%c", opt); - } - else - { - tmp = xmalloc (3 + strlen (longopt)); - sprintf (tmp, "--%s", longopt); - } - run_add_arg_p (&diff_argc, &diff_arg_allocated, &diff_argv, tmp); - free (tmp); - - /* When present, add ARGUMENT to DIFF_ARGV. */ - if (argument) - run_add_arg_p (&diff_argc, &diff_arg_allocated, &diff_argv, argument); -} - - - -/* CVS 1.9 and similar versions seemed to have pretty weird handling - of -y and -T. In the cases where it called rcsdiff, - they would have the meanings mentioned below. In the cases where it - called diff, they would have the meanings mentioned in "longopts". - Noone seems to have missed them, so I think the right thing to do is - just to remove the options altogether (which I have done). - - In the case of -z and -q, "cvs diff" did not accept them even back - when we called rcsdiff (at least, it hasn't accepted them - recently). - - In comparing rcsdiff to the new CVS implementation, I noticed that - the following rcsdiff flags are not handled by CVS diff: - - -y: perform diff even when the requested revisions are the - same revision number - -q: run quietly - -T: preserve modification time on the RCS file - -z: specify timezone for use in file labels - - I think these are not really relevant. -y is undocumented even in - RCS 5.7, and seems like a minor change at best. According to RCS - documentation, -T only applies when a RCS file has been modified - because of lock changes; doesn't CVS sidestep RCS's entire lock - structure? -z seems to be unsupported by CVS diff, and has a - different meaning as a global option anyway. (Adding it could be - a feature, but if it is left out for now, it should not break - anything.) For the purposes of producing output, CVS diff appears - mostly to ignore -q. Maybe this should be fixed, but I think it's - a larger issue than the changes included here. */ - -int -diff (argc, argv) - int argc; - char **argv; -{ - int c, err = 0; - int local = 0; - int which; - int option_index; - - if (argc == -1) - usage (diff_usage); - - have_rev1_label = have_rev2_label = 0; - - /* - * 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. - */ - - /* Clean out our global variables (multiroot can call us multiple - times and the server can too, if the client sends several - diff commands). */ - if (diff_argc) - { - run_arg_free_p (diff_argc, diff_argv); - diff_argc = 0; - } - diff_rev1 = NULL; - diff_rev2 = NULL; - diff_date1 = NULL; - diff_date2 = NULL; - diff_join1 = NULL; - diff_join2 = NULL; - - optind = 0; - /* FIXME: This should really be allocating an argv to be passed to diff - * later rather than strcatting onto the opts variable. We have some - * handling routines that can already handle most of the argc/argv - * maintenance for us and currently, if anyone were to attempt to pass a - * quoted string in here, it would be split on spaces and tabs on its way - * to diff. - */ - while ((c = getopt_long (argc, argv, - "+abcdefhilnpstuwy0123456789BHNRTC:D:F:I:L:U:W:k:r:j:", - longopts, &option_index)) != -1) - { - switch (c) - { - case 'y': - add_diff_args (0, "side-by-side", NULL); - break; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - case 'h': case 'i': case 'n': case 'p': case 's': 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': - add_diff_args (c, NULL, NULL); - break; - case 'L': - if (have_rev1_label++) - if (have_rev2_label++) - { - error (0, 0, "extra -L arguments ignored"); - break; - } - /* Fall through. */ - case 'C': case 'F': case 'I': case 'U': case 'W': - add_diff_args (c, NULL, optarg); - break; - case 129: case 130: case 131: case 132: case 133: case 134: - case 135: case 136: case 137: case 138: case 139: case 140: - case 141: case 142: case 143: case 145: case 146: - add_diff_args (0, longopts[option_index].name, - longopts[option_index].has_arg ? optarg : NULL); - break; - case 'R': - local = 0; - break; - case 'l': - local = 1; - break; - case 'k': - if (options) - free (options); - options = RCS_check_kflag (optarg); - break; - case 'j': - { - char *ptr; - char *cpy = strdup(optarg); - - if ((ptr = strchr(optarg, ':')) != NULL) - *ptr++ = 0; - 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_join2 = cpy; - diff_rev2 = optarg; - diff_date2 = ptr ? Make_Date(ptr) : NULL; - } else { - diff_join1 = cpy; - diff_rev1 = optarg; - diff_date1 = ptr ? Make_Date(ptr) : NULL; - } - } - 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; - 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; - case 'N': - empty_files = 1; - break; - case '?': - default: - usage (diff_usage); - break; - } - } - argc -= optind; - argv += optind; - - /* make sure options is non-null */ - if (!options) - options = xstrdup (""); - -#ifdef CLIENT_SUPPORT - if (current_parsed_root->isremote) { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (local) - send_arg("-l"); - if (empty_files) - send_arg("-N"); - send_options (diff_argc, diff_argv); - if (options[0] != '\0') - send_arg (options); - if (diff_join1) - option_with_arg ("-j", diff_join1); - else if (diff_rev1) - option_with_arg ("-r", diff_rev1); - else if (diff_date1) - client_senddate (diff_date1); - - if (diff_join2) - option_with_arg ("-j", diff_join2); - else if (diff_rev2) - option_with_arg ("-r", diff_rev2); - else if (diff_date2) - client_senddate (diff_date2); - send_arg ("--"); - - /* Send the current files unless diffing two revs from the archive */ - if (diff_rev2 == NULL && diff_date2 == NULL) - send_files (argc, argv, local, 0, 0); - else - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - - send_file_names (argc, argv, SEND_EXPAND_WILD); - - send_to_server ("diff\012", 0); - err = get_responses_and_close (); - } else -#endif - { /* FreeBSD addition - warning idention not changed til matching-} */ - if (diff_rev1 != NULL) - tag_check_valid (diff_rev1, argc, argv, local, 0, ""); - if (diff_rev2 != NULL) - tag_check_valid (diff_rev2, argc, argv, local, 0, ""); - - which = W_LOCAL; - if (diff_rev1 != NULL || diff_date1 != NULL) - which |= W_REPOS | W_ATTIC; - - wrap_setup (); - - /* start the recursion processor */ - err = start_recursion (diff_fileproc, diff_filesdoneproc, diff_dirproc, - diff_dirleaveproc, NULL, argc, argv, local, - which, 0, CVS_LOCK_READ, (char *) NULL, 1, - (char *) NULL); - } /* FreeBSD addition */ - - /* clean up */ - free (options); - options = NULL; - - if (diff_date1 != NULL) - free (diff_date1); - if (diff_date2 != NULL) - free (diff_date2); - if (diff_join1 != NULL) - free (diff_join1); - if (diff_join2 != NULL) - free (diff_join2); - - return (err); -} - -/* - * Do a file diff - */ -/* ARGSUSED */ -static int -diff_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - int status, err = 2; /* 2 == trouble, like rcsdiff */ - Vers_TS *vers; - enum diff_file empty_file = DIFF_DIFFERENT; - char *tmp = NULL; - char *tocvsPath = NULL; - char *fname = NULL; - char *label1; - char *label2; - char *rev1_cache = NULL; - - user_file_rev = 0; - vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0); - - 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) - { - /* The file does not exist in the working directory. */ - if ((diff_rev1 != NULL || diff_date1 != NULL) - && vers->srcfile != NULL) - { - /* The file does exist in the repository. */ - if (empty_files) - empty_file = DIFF_REMOVED; - else - { - int exists; - - exists = 0; - /* special handling for TAG_HEAD */ - if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0) - { - char *head = - (vers->vn_rcs == NULL - ? NULL - : RCS_branch_head (vers->srcfile, vers->vn_rcs)); - exists = head != NULL && !RCS_isdead(vers->srcfile, head); - if (head != NULL) - free (head); - } - else - { - Vers_TS *xvers; - - xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, - 1, 0); - exists = xvers->vn_rcs != NULL && !RCS_isdead(xvers->srcfile, xvers->vn_rcs); - freevers_ts (&xvers); - } - if (exists) - error (0, 0, - "%s no longer exists, no comparison available", - finfo->fullname); - goto out; - } - } - else - { - error (0, 0, "I know nothing about %s", finfo->fullname); - goto out; - } - } - else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') - { - /* The file was added locally. */ - int exists = 0; - - if (vers->srcfile != NULL) - { - /* The file does exist in the repository. */ - - if ((diff_rev1 != NULL || diff_date1 != NULL)) - { - /* special handling for TAG_HEAD */ - if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0) - { - char *head = - (vers->vn_rcs == NULL - ? NULL - : RCS_branch_head (vers->srcfile, vers->vn_rcs)); - exists = head != NULL && !RCS_isdead(vers->srcfile, head); - if (head != NULL) - free (head); - } - else - { - Vers_TS *xvers; - - xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, - 1, 0); - exists = xvers->vn_rcs != NULL - && !RCS_isdead (xvers->srcfile, xvers->vn_rcs); - freevers_ts (&xvers); - } - } - else - { - /* The file was added locally, but an RCS archive exists. Our - * base revision must be dead. - */ - /* No need to set, exists = 0, here. That's the default. */ - } - } - if (!exists) - { - /* If we got here, then either the RCS archive does not exist or - * the relevant revision is dead. - */ - if (empty_files) - empty_file = DIFF_ADDED; - else - { - error (0, 0, "%s is a new entry, no comparison available", - finfo->fullname); - goto out; - } - } - } - else if (vers->vn_user[0] == '-') - { - if (empty_files) - empty_file = DIFF_REMOVED; - else - { - error (0, 0, "%s was removed, no comparison available", - finfo->fullname); - goto out; - } - } - else - { - if (vers->vn_rcs == NULL && vers->srcfile == NULL) - { - error (0, 0, "cannot find revision control file for %s", - finfo->fullname); - goto out; - } - else - { - if (vers->ts_user == NULL) - { - error (0, 0, "cannot find %s", finfo->fullname); - goto out; - } - 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; - } - } - } - - empty_file = diff_file_nodiff( finfo, vers, empty_file, &rev1_cache ); - if( empty_file == DIFF_SAME ) - { - /* In the server case, would be nice to send a "Checked-in" - response, so that the client can rewrite its timestamp. - server_checked_in by itself isn't the right thing (it - needs a server_register), but I'm not sure what is. - It isn't clear to me how "cvs status" handles this (that - is, for a client which sends Modified not Is-modified to - "cvs status"), but it does. */ - err = 0; - goto out; - } - else if( empty_file == DIFF_ERROR ) - goto out; - - /* Output an "Index:" line for patch to use */ - cvs_output ("Index: ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - tocvsPath = wrap_tocvs_process_file(finfo->file); - if( tocvsPath != NULL ) - { - /* Backup the current version of the file to CVS/,,filename */ - fname = xmalloc (strlen (finfo->file) - + sizeof CVSADM - + sizeof CVSPREFIX - + 10); - sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, finfo->file); - if (unlink_file_dir (fname) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", fname); - rename_file (finfo->file, fname); - /* Copy the wrapped file to the current directory then go to work */ - copy_file (tocvsPath, finfo->file); - } - - /* Set up file labels appropriate for compatibility with the Larry Wall - * implementation of patch if the user didn't specify. This is irrelevant - * according to the POSIX.2 specification. - */ - label1 = NULL; - label2 = NULL; - if (!have_rev1_label) - { - if (empty_file == DIFF_ADDED) - label1 = - make_file_label (DEVNULL, NULL, NULL); - else - label1 = - make_file_label (finfo->fullname, use_rev1, - vers ? vers->srcfile : NULL); - } - - if (!have_rev2_label) - { - if (empty_file == DIFF_REMOVED) - label2 = - make_file_label (DEVNULL, NULL, NULL); - else - label2 = - make_file_label (finfo->fullname, use_rev2, - vers ? vers->srcfile : NULL); - } - - if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED) - { - /* This is fullname, not file, possibly despite the POSIX.2 - * specification, because that's the way all the Larry Wall - * implementations of patch (are there other implementations?) want - * things and the POSIX.2 spec appears to leave room for this. - */ - cvs_output ("\ -===================================================================\n\ -RCS file: ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - cvs_output ("diff -N ", 0); - cvs_output (finfo->fullname, 0); - cvs_output ("\n", 1); - - if (empty_file == DIFF_ADDED) - { - if (use_rev2 == NULL) - status = diff_exec (DEVNULL, finfo->file, label1, label2, - diff_argc, diff_argv, RUN_TTY); - else - { - int retcode; - - tmp = cvs_temp_name (); - retcode = RCS_checkout (vers->srcfile, (char *) NULL, - use_rev2, (char *) NULL, - (*options - ? options - : vers->options), - tmp, (RCSCHECKOUTPROC) NULL, - (void *) NULL); - if( retcode != 0 ) - goto out; - - status = diff_exec (DEVNULL, tmp, label1, label2, - diff_argc, diff_argv, RUN_TTY); - } - } - else - { - int retcode; - - tmp = cvs_temp_name (); - retcode = RCS_checkout (vers->srcfile, (char *) NULL, - use_rev1, (char *) NULL, - *options ? options : vers->options, - tmp, (RCSCHECKOUTPROC) NULL, - (void *) NULL); - if (retcode != 0) - goto out; - - status = diff_exec (tmp, DEVNULL, label1, label2, - diff_argc, diff_argv, RUN_TTY); - } - } - else - { - status = RCS_exec_rcsdiff (vers->srcfile, diff_argc, diff_argv, - *options ? options : vers->options, - use_rev1, rev1_cache, use_rev2, - label1, label2, finfo->file); - - } - - if (label1) free (label1); - if (label2) free (label2); - - switch (status) - { - case -1: /* fork failed */ - error (1, errno, "fork failed while diffing %s", - vers->srcfile->path); - case 0: /* everything ok */ - err = 0; - break; - default: /* other error */ - err = status; - break; - } - -out: - if( tocvsPath != NULL ) - { - if (unlink_file_dir (finfo->file) < 0) - if (! existence_error (errno)) - error (1, errno, "cannot remove %s", finfo->file); - - rename_file (fname, finfo->file); - if (unlink_file (tocvsPath) < 0) - error (1, errno, "cannot remove %s", tocvsPath); - free (fname); - } - - /* Call CVS_UNLINK() rather than unlink_file() below to avoid the check - * for noexec. - */ - if( tmp != NULL ) - { - if (CVS_UNLINK(tmp) < 0) - error (0, errno, "cannot remove %s", tmp); - free (tmp); - } - if( rev1_cache != NULL ) - { - if( CVS_UNLINK( rev1_cache ) < 0 ) - error( 0, errno, "cannot remove %s", rev1_cache ); - free( rev1_cache ); - } - - freevers_ts (&vers); - diff_mark_errors (err); - return err; -} - -/* - * Remember the exit status for each file. - */ -static void -diff_mark_errors (err) - int err; -{ - if (err > diff_errors) - diff_errors = err; -} - -/* - * Print a warm fuzzy message when we enter a dir - * - * Don't try to diff directories that don't exist! -- DW - */ -/* ARGSUSED */ -static Dtype -diff_dirproc (callerdat, dir, pos_repos, update_dir, entries) - void *callerdat; - const char *dir; - const char *pos_repos; - const char *update_dir; - List *entries; -{ - /* XXX - check for dirs we don't want to process??? */ - - /* YES ... for instance dirs that don't exist!!! -- DW */ - if (!isdir (dir)) - return (R_SKIP_ALL); - - if (!quiet) - error (0, 0, "Diffing %s", update_dir); - return (R_PROCESS); -} - -/* - * Concoct the proper exit status - done with files - */ -/* ARGSUSED */ -static int -diff_filesdoneproc (callerdat, err, repos, update_dir, entries) - void *callerdat; - int err; - const char *repos; - const char *update_dir; - List *entries; -{ - return (diff_errors); -} - -/* - * Concoct the proper exit status - leaving directories - */ -/* ARGSUSED */ -static int -diff_dirleaveproc (callerdat, dir, err, update_dir, entries) - void *callerdat; - const char *dir; - int err; - const char *update_dir; - List *entries; -{ - return (diff_errors); -} - -/* - * verify that a file is different - */ -static enum diff_file -diff_file_nodiff( finfo, vers, empty_file, rev1_cache ) - struct file_info *finfo; - Vers_TS *vers; - enum diff_file empty_file; - char **rev1_cache; /* Cache the content of rev1 if we have to look - * it up. - */ -{ - Vers_TS *xvers; - int retcode; - - /* 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) - { - if (vers->vn_rcs != NULL && vers->srcfile != NULL) - use_rev1 = RCS_branch_head (vers->srcfile, vers->vn_rcs); - } - else - { - xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0); - if (xvers->vn_rcs != NULL) - 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) - { - if (vers->vn_rcs != NULL && vers->srcfile != NULL) - use_rev2 = RCS_branch_head (vers->srcfile, vers->vn_rcs); - } - else - { - xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0); - if (xvers->vn_rcs != NULL) - use_rev2 = xstrdup (xvers->vn_rcs); - freevers_ts (&xvers); - } - - if( use_rev1 == NULL || RCS_isdead( vers->srcfile, use_rev1 ) ) - { - /* The first revision does not exist. If EMPTY_FILES is - true, treat this as an added file. Otherwise, warn - about the missing tag. */ - if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) ) - /* At least in the case where DIFF_REV1 and DIFF_REV2 - * are both numeric (and non-existant (NULL), as opposed to - * dead?), we should be returning some kind of error (see - * basicb-8a0 in testsuite). The symbolic case may be more - * complicated. - */ - return DIFF_SAME; - if( empty_files ) - return DIFF_ADDED; - if( use_rev1 != NULL ) - { - if (diff_rev1) - { - error( 0, 0, - "Tag %s refers to a dead (removed) revision in file `%s'.", - diff_rev1, finfo->fullname ); - } - else - { - error( 0, 0, - "Date %s refers to a dead (removed) revision in file `%s'.", - diff_date1, finfo->fullname ); - } - error( 0, 0, - "No comparison available. Pass `-N' to `%s diff'?", - program_name ); - } - else if (diff_rev1) - error (0, 0, "tag %s is not in file %s", diff_rev1, - finfo->fullname); - else - error (0, 0, "no revision for date %s in file %s", - diff_date1, finfo->fullname); - return DIFF_ERROR; - } - - assert( use_rev1 != NULL ); - if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) ) - { - /* The second revision does not exist. If EMPTY_FILES is - true, treat this as a removed file. Otherwise warn - about the missing tag. */ - if (empty_files) - return DIFF_REMOVED; - if( use_rev2 != NULL ) - { - if (diff_rev2) - { - error( 0, 0, - "Tag %s refers to a dead (removed) revision in file `%s'.", - diff_rev2, finfo->fullname ); - } - else - { - error( 0, 0, - "Date %s refers to a dead (removed) revision in file `%s'.", - diff_date2, finfo->fullname ); - } - error( 0, 0, - "No comparison available. Pass `-N' to `%s diff'?", - program_name ); - } - else if (diff_rev2) - error (0, 0, "tag %s is not in file %s", diff_rev2, - finfo->fullname); - else - error (0, 0, "no revision for date %s in file %s", - diff_date2, finfo->fullname); - return DIFF_ERROR; - } - /* Now, see if we really need to do the diff. We can't assume that the - * files are different when the revs are. - */ - assert( use_rev2 != NULL ); - if( strcmp (use_rev1, use_rev2) == 0 ) - return DIFF_SAME; - /* else fall through and do the diff */ - } - - /* If we had a r1/d1 & r2/d2, then at this point we must have a C3P0... - * err... ok, then both rev1 & rev2 must have resolved to an existing, - * live version due to if statement we just closed. - */ - assert (!(diff_rev2 || diff_date2) || (use_rev1 && use_rev2)); - - if ((diff_rev1 || diff_date1) && - (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1))) - { - /* The first revision does not exist, and no second revision - was given. */ - if (empty_files) - { - if (empty_file == DIFF_REMOVED) - return DIFF_SAME; - if( user_file_rev && use_rev2 == NULL ) - use_rev2 = xstrdup( user_file_rev ); - return DIFF_ADDED; - } - if( use_rev1 != NULL ) - { - if (diff_rev1) - { - error( 0, 0, - "Tag %s refers to a dead (removed) revision in file `%s'.", - diff_rev1, finfo->fullname ); - } - else - { - error( 0, 0, - "Date %s refers to a dead (removed) revision in file `%s'.", - diff_date1, finfo->fullname ); - } - error( 0, 0, - "No comparison available. Pass `-N' to `%s diff'?", - program_name ); - } - else if ( diff_rev1 ) - error( 0, 0, "tag %s is not in file %s", diff_rev1, - finfo->fullname ); - else - error( 0, 0, "no revision for date %s in file %s", - diff_date1, finfo->fullname ); - return DIFF_ERROR; - } - - assert( !diff_rev1 || use_rev1 ); - - 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 = NULL; - } - - /* Now, see if we really need to do the diff. We can't assume that the - * files are different when the revs are. - */ - if( use_rev1 && use_rev2) - { - if (strcmp (use_rev1, use_rev2) == 0) - return DIFF_SAME; - /* Fall through and do the diff. */ - } - /* Don't want to do the timestamp check with both use_rev1 & use_rev2 set. - * The timestamp check is just for the default case of diffing the - * workspace file against its base revision. - */ - else if( use_rev1 == NULL - || ( vers->vn_user != NULL - && strcmp( use_rev1, vers->vn_user ) == 0 ) ) - { - if (empty_file == DIFF_DIFFERENT - && vers->ts_user != NULL - && strcmp (vers->ts_rcs, vers->ts_user) == 0 - && (!(*options) || strcmp (options, vers->options) == 0)) - { - return DIFF_SAME; - } - if (use_rev1 == NULL - && (vers->vn_user[0] != '0' || vers->vn_user[1] != '\0')) - { - if (vers->vn_user[0] == '-') - use_rev1 = xstrdup (vers->vn_user + 1); - else - use_rev1 = xstrdup (vers->vn_user); - } - } - - /* If we already know that the file is being added or removed, - then we don't want to do an actual file comparison here. */ - if (empty_file != DIFF_DIFFERENT) - return empty_file; - - /* - * Run a quick cmp to see if we should bother with a full diff. - */ - - retcode = RCS_cmp_file( vers->srcfile, use_rev1, rev1_cache, - use_rev2, *options ? options : vers->options, - finfo->file ); - - return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT; -} |