I just committed the attached patch to the stable branch. This problem has been listed in BUGS for some time, so I felt justified despite it being a fairly large patch. I went to some lengths to keep it clean and I think that it mostly actually simplifes the code.
Cheers, Derek
Index: BUGS =================================================================== RCS file: /cvs/ccvs/BUGS,v retrieving revision 1.55.6.18 retrieving revision 1.55.6.19 diff -u -p -r1.55.6.18 -r1.55.6.19 --- BUGS 25 Aug 2004 03:14:01 -0000 1.55.6.18 +++ BUGS 27 May 2005 16:25:41 -0000 1.55.6.19 @@ -88,13 +88,6 @@ an incorrect value, though this does not noticed under BSDI. -* Spaces in arguments to `cvs diff' are currently split on spaces and tabs -before being passed to diff. This can often cause diff to abort since it can -no longer interpret its options string and if it can, coincidentally, -interpret its option string, then the problem may be output in unexpected -formats. - - * Status /*-------. Index: ChangeLog =================================================================== RCS file: /cvs/ccvs/ChangeLog,v retrieving revision 1.692.2.209 retrieving revision 1.692.2.210 diff -u -p -r1.692.2.209 -r1.692.2.210 --- ChangeLog 4 May 2005 02:35:14 -0000 1.692.2.209 +++ ChangeLog 27 May 2005 16:25:41 -0000 1.692.2.210 @@ -1,3 +1,8 @@ +2005-05-27 Derek Price <[EMAIL PROTECTED]> + + * NEWS: Note diff space split fix. + * BUGS: Remove diff space split note. + 2005-05-03 Derek Price <[EMAIL PROTECTED]> * INSTALL: Add footnote about compiling a CVS checkout of CVS on a Index: NEWS =================================================================== RCS file: /cvs/ccvs/NEWS,v retrieving revision 1.116.2.131 retrieving revision 1.116.2.132 diff -u -p -r1.116.2.131 -r1.116.2.132 --- NEWS 2 May 2005 17:07:20 -0000 1.116.2.131 +++ NEWS 27 May 2005 16:25:41 -0000 1.116.2.132 @@ -3,6 +3,8 @@ Changes since 1.11.20: BUG FIXES +* `cvs diff' no longer splits its arguments on spaces. + * Thanks to an old report and patch from Stewart Brodie <[EMAIL PROTECTED]>, a potential crash in response to a corrupt RCS file has been fixed. Index: src/ChangeLog =================================================================== RCS file: /cvs/ccvs/src/ChangeLog,v retrieving revision 1.2336.2.371 retrieving revision 1.2336.2.373 diff -u -p -r1.2336.2.371 -r1.2336.2.373 --- src/ChangeLog 2 May 2005 19:39:10 -0000 1.2336.2.371 +++ src/ChangeLog 27 May 2005 16:28:00 -0000 1.2336.2.373 @@ -1,3 +1,25 @@ +2005-05-27 Derek Price <[EMAIL PROTECTED]> + + * client.c (send_arg): Make arg const. + (send_option_string): Rename to... + (send_options): ...this and accept argc/argv in place of string. + * client.h: Update protos to match the changes to client.c. + * cvs.h (RCS_exec_rcsdiff, diff_exec): Update protos. + (run_add_arg_p, run_arg_free_p): New protos. + * diff.c (opts, opts_allocated): Replace with... + (diff_argv, diff_argc, diff_arg_allocated): ...these. + (add_diff_args): New convenience function. + (diff): Use new constructs and APIs. + * patch.c (patch_fileproc, RCS_checkin, RCS_delete_revs), rcscmds.c + (call_diff_add_arg, call_diff_setup, RCS_merge, RCS_exec_rcsdiff, + diff_exec, RCS_output_diff_options), update.c (patch_file): Use new + APIs. + * run.c (run_add_arg_p, run_arg_free_p): New functions. + (run_argc_allocated): Make size_t. + (run_setup, run_add_arg): Use new functions. + * sanity.sh: Accomodate above changes. + (rcslib-diffrgx-3): Slip in test for space splitting. + 2005-05-02 Derek Price <[EMAIL PROTECTED]> Remove unnecessary level of indirection. Index: src/client.c =================================================================== RCS file: /cvs/ccvs/src/client.c,v retrieving revision 1.318.4.27 retrieving revision 1.318.4.28 diff -u -p -r1.318.4.27 -r1.318.4.28 --- src/client.c 17 Mar 2005 15:39:09 -0000 1.318.4.27 +++ src/client.c 27 May 2005 16:25:10 -0000 1.318.4.28 @@ -4903,10 +4903,10 @@ start_rsh_server (root, to_server, from_ /* Send an argument STRING. */ void send_arg (string) - char *string; + const char *string; { char buf[1]; - char *p = string; + const char *p = string; send_to_server ("Argument ", 0); @@ -5404,36 +5404,15 @@ send_dirleave_proc (callerdat, dir, err, } /* - * Send each option in a string to the server, one by one. - * This assumes that the options are separated by spaces, for example - * STRING might be "--foo -C5 -y". + * Send each option in an array to the server, one by one. + * argv might be "--foo=bar", "-C", "5", "-y". */ - void -send_option_string (string) - char *string; +send_options (int argc, char *const *argv) { - char *copy; - char *p; - - copy = xstrdup (string); - p = copy; - while (1) - { - char *s; - char l; - - for (s = p; *s != ' ' && *s != '\0'; s++) - ; - l = *s; - *s = '\0'; - if (s != p) - send_arg (p); - if (l == '\0') - break; - p = s + 1; - } - free (copy); + int i; + for (i = 0; i < argc; i++) + send_arg (argv[i]); } Index: src/client.h =================================================================== RCS file: /cvs/ccvs/src/client.h,v retrieving revision 1.39.6.2 retrieving revision 1.39.6.3 diff -u -p -r1.39.6.2 -r1.39.6.3 --- src/client.h 20 Mar 2004 18:14:56 -0000 1.39.6.2 +++ src/client.h 27 May 2005 16:25:10 -0000 1.39.6.3 @@ -119,11 +119,10 @@ send_files PROTO((int argc, char **argv, /* Send an argument to the remote server. */ void -send_arg PROTO((char *string)); +send_arg PROTO((const char *string)); /* Send a string of single-char options to the remote server, one by one. */ -void -send_option_string PROTO((char *string)); +void send_options PROTO ((int argc, char * const *argv)); extern void send_a_repository PROTO ((const char *, const char *, const char *)); Index: src/cvs.h =================================================================== RCS file: /cvs/ccvs/src/cvs.h,v retrieving revision 1.235.4.31 retrieving revision 1.235.4.32 diff -u -p -r1.235.4.31 -r1.235.4.32 --- src/cvs.h 2 May 2005 17:06:56 -0000 1.235.4.31 +++ src/cvs.h 27 May 2005 16:25:10 -0000 1.235.4.32 @@ -431,14 +431,16 @@ int RCS_merge PROTO((RCSNode *, const ch #define RCS_FLAGS_KEEPFILE 16 #define RCS_FLAGS_USETIME 32 -extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile, - const char *opts, const char *options, +extern int RCS_exec_rcsdiff PROTO ((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)); extern int diff_exec PROTO ((const char *file1, const char *file2, const char *label1, const char *label2, - const char *options, const char *out)); + int diff_argc, char *const *diff_argv, + const char *out)); #include "error.h" @@ -696,6 +698,8 @@ void sleep_past PROTO ((time_t desttime) #define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */ #define RUN_TTY (char *)0 /* for the benefit of lint */ +void run_add_arg_p PROTO ((int *, size_t *, char ***, const char *s)); +void run_arg_free_p PROTO ((int, char **)); void run_arg PROTO((const char *s)); void run_print PROTO((FILE * fp)); void run_setup PROTO ((const char *prog)); Index: src/diff.c =================================================================== RCS file: /cvs/ccvs/src/diff.c,v retrieving revision 1.94.2.9 retrieving revision 1.94.2.10 diff -u -p -r1.94.2.9 -r1.94.2.10 --- src/diff.c 31 Jan 2005 22:15:11 -0000 1.94.2.9 +++ src/diff.c 27 May 2005 16:25:11 -0000 1.94.2.10 @@ -65,8 +65,9 @@ static int have_rev1_label, have_rev2_la static char *user_file_rev; static char *options; -static char *opts; -static size_t opts_allocated = 1; +static char **diff_argv; +static int diff_argc; +static size_t diff_arg_allocated; static int diff_errors; static int empty_files = 0; @@ -211,6 +212,54 @@ static struct option const longopts[] = {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 @@ -247,7 +296,6 @@ diff (argc, argv) int argc; char **argv; { - char tmp[50]; int c, err = 0; int local = 0; int which; @@ -267,12 +315,11 @@ diff (argc, argv) /* Clean out our global variables (multiroot can call us multiple times and the server can too, if the client sends several diff commands). */ - if (opts == NULL) + if (diff_argc) { - opts_allocated = 1; - opts = xmalloc (opts_allocated); + run_arg_free_p (diff_argc, diff_argv); + diff_argc = 0; } - opts[0] = '\0'; diff_rev1 = NULL; diff_rev2 = NULL; diff_date1 = NULL; @@ -293,7 +340,7 @@ diff (argc, argv) switch (c) { case 'y': - xrealloc_and_strcat (&opts, &opts_allocated, " --side-by-side"); + 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': @@ -301,8 +348,7 @@ diff (argc, argv) 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': - (void) sprintf (tmp, " -%c", (char) c); - xrealloc_and_strcat (&opts, &opts_allocated, tmp); + add_diff_args (c, NULL, NULL); break; case 'L': if (have_rev1_label++) @@ -311,33 +357,15 @@ diff (argc, argv) error (0, 0, "extra -L arguments ignored"); break; } - - xrealloc_and_strcat (&opts, &opts_allocated, " -L"); - xrealloc_and_strcat (&opts, &opts_allocated, optarg); - break; + /* Fall through. */ case 'C': case 'F': case 'I': case 'U': case 'W': - (void) sprintf (tmp, " -%c", (char) c); - xrealloc_and_strcat (&opts, &opts_allocated, tmp); - xrealloc_and_strcat (&opts, &opts_allocated, optarg); + add_diff_args (c, NULL, optarg); break; - case 131: - /* --ifdef. */ - xrealloc_and_strcat (&opts, &opts_allocated, " --ifdef="); - xrealloc_and_strcat (&opts, &opts_allocated, optarg); - break; - case 129: case 130: case 132: case 133: case 134: + 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: - xrealloc_and_strcat (&opts, &opts_allocated, " --"); - xrealloc_and_strcat (&opts, &opts_allocated, - longopts[option_index].name); - if (longopts[option_index].has_arg == 1 - || (longopts[option_index].has_arg == 2 - && optarg != NULL)) - { - xrealloc_and_strcat (&opts, &opts_allocated, "="); - xrealloc_and_strcat (&opts, &opts_allocated, optarg); - } + add_diff_args (0, longopts[option_index].name, + longopts[option_index].has_arg ? optarg : NULL); break; case 'R': local = 0; @@ -395,7 +423,7 @@ diff (argc, argv) send_arg("-l"); if (empty_files) send_arg("-N"); - send_option_string (opts); + send_options (diff_argc, diff_argv); if (options[0] != '\0') send_arg (options); if (diff_rev1) @@ -705,8 +733,8 @@ RCS file: ", 0); if (empty_file == DIFF_ADDED) { if (use_rev2 == NULL) - status = diff_exec (DEVNULL, finfo->file, label1, label2, opts, - RUN_TTY); + status = diff_exec (DEVNULL, finfo->file, label1, label2, + diff_argc, diff_argv, RUN_TTY); else { int retcode; @@ -722,7 +750,8 @@ RCS file: ", 0); if( retcode != 0 ) goto out; - status = diff_exec (DEVNULL, tmp, label1, label2, opts, RUN_TTY); + status = diff_exec (DEVNULL, tmp, label1, label2, + diff_argc, diff_argv, RUN_TTY); } } else @@ -738,16 +767,16 @@ RCS file: ", 0); if (retcode != 0) goto out; - status = diff_exec (tmp, DEVNULL, label1, label2, opts, RUN_TTY); + status = diff_exec (tmp, DEVNULL, label1, label2, + diff_argc, diff_argv, RUN_TTY); } } else { - status = RCS_exec_rcsdiff(vers->srcfile, opts, - *options ? options : vers->options, - use_rev1, rev1_cache, use_rev2, - label1, label2, - finfo->file); + status = RCS_exec_rcsdiff (vers->srcfile, diff_argc, diff_argv, + *options ? options : vers->options, + use_rev1, rev1_cache, use_rev2, + label1, label2, finfo->file); } Index: src/patch.c =================================================================== RCS file: /cvs/ccvs/src/patch.c,v retrieving revision 1.80.4.11 retrieving revision 1.80.4.12 diff -u -p -r1.80.4.11 -r1.80.4.12 --- src/patch.c 18 Apr 2005 17:36:45 -0000 1.80.4.11 +++ src/patch.c 27 May 2005 16:25:11 -0000 1.80.4.12 @@ -406,6 +406,9 @@ patch_fileproc (callerdat, finfo) char *cp1, *cp2; FILE *fp; int line_length; + int dargc = 0; + size_t darg_allocated = 0; + char **dargv = NULL; line1 = NULL; line1_chars_allocated = 0; @@ -585,8 +588,10 @@ patch_fileproc (callerdat, finfo) (void)utime (tmpfile2, &t); } - switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, unidiff ? "-u" : "-c", - tmpfile3)) + if (unidiff) run_add_arg_p (&dargc, &darg_allocated, &dargv, "-u"); + else run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c"); + switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, dargc, dargv, + tmpfile3)) { case -1: /* fork/wait failure */ error (1, errno, "fork for diff failed on %s", rcs); @@ -758,6 +763,11 @@ failed to read diff file header %s for % free (tmpfile2); free (tmpfile3); tmpfile1 = tmpfile2 = tmpfile3 = NULL; + if (dargc) + { + run_arg_free_p (dargc, dargv); + free (dargv); + } out2: if (vers_tag != NULL) Index: src/rcs.c =================================================================== RCS file: /cvs/ccvs/src/rcs.c,v retrieving revision 1.262.4.37 retrieving revision 1.262.4.38 diff -u -p -r1.262.4.37 -r1.262.4.38 --- src/rcs.c 20 Apr 2005 20:40:42 -0000 1.262.4.37 +++ src/rcs.c 27 May 2005 16:25:11 -0000 1.262.4.38 @@ -5049,7 +5049,9 @@ RCS_checkin (rcs, workfile_in, message, Deltatext *dtext; Node *nodep; char *tmpfile, *changefile; - char *diffopts; + int dargc = 0; + size_t darg_allocated = 0; + char **dargv = NULL; size_t bufsize; int status, checkin_quiet; struct tm *ftm; @@ -5478,9 +5480,10 @@ workfile); /* Diff options should include --binary if the RCS file has -kb set in its `expand' field. */ - diffopts = (rcs->expand != NULL && STREQ (rcs->expand, "b") - ? "-a -n --binary" - : "-a -n"); + run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); + run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); + if (rcs->expand && STREQ (rcs->expand, "b")) + run_add_arg_p (&dargc, &darg_allocated, &dargv, "--binary"); if (STREQ (commitpt->version, rcs->head) && numdots (delta->version) == 1) @@ -5503,7 +5506,8 @@ workfile); memset (commitpt->text, 0, sizeof (Deltatext)); bufsize = 0; - switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile)) + switch (diff_exec (workfile, tmpfile, NULL, NULL, + dargc, dargv, changefile)) { case 0: case 1: @@ -5551,7 +5555,8 @@ workfile); /* This file is not being inserted at the head, but on a side branch somewhere. Make a diff from the previous revision to the working file. */ - switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile)) + switch (diff_exec (tmpfile, workfile, NULL, NULL, + dargc, dargv, changefile)) { case 0: case 1: @@ -5578,6 +5583,9 @@ workfile); } } + run_arg_free_p (dargc, dargv); + free (dargv); + /* Update DELTA linkage. It is important not to do this before the very end of RCS_checkin; if an error arises that forces us to abort checking in, we must not have malformed deltas @@ -6651,6 +6659,10 @@ RCS_delete_revs (rcs, tag1, tag2, inclus } else { + int dargc = 0; + size_t darg_allocated = 0; + char **dargv = NULL; + beforefile = cvs_temp_name(); status = RCS_checkout (rcs, NULL, before, NULL, "-ko", beforefile, (RCSCHECKOUTPROC)0, NULL); @@ -6658,7 +6670,12 @@ RCS_delete_revs (rcs, tag1, tag2, inclus goto delrev_done; outfile = cvs_temp_name(); - status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile); + run_add_arg_p (&dargc, &darg_allocated, &dargv, "-a"); + run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); + status = diff_exec (beforefile, afterfile, NULL, NULL, + dargc, dargv, outfile); + run_arg_free_p (dargc, dargv); + free (dargv); if (status == 2) { Index: src/rcscmds.c =================================================================== RCS file: /cvs/ccvs/src/rcscmds.c,v retrieving revision 1.52.4.5 retrieving revision 1.52.4.6 diff -u -p -r1.52.4.5 -r1.52.4.6 --- src/rcscmds.c 16 Mar 2005 22:00:45 -0000 1.52.4.5 +++ src/rcscmds.c 27 May 2005 16:25:11 -0000 1.52.4.6 @@ -56,8 +56,8 @@ 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 ((const char *, const char *, - const char *, const char *)); +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 @@ -69,7 +69,7 @@ static void RCS_output_diff_options PROT argument will be parsed into whitespace separated words and added to the global call_diff_argv list. - Then, optionally, call call_diff_arg for each additional argument + 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. */ @@ -79,7 +79,8 @@ static int call_diff_argc; static int call_diff_argc_allocated; static void call_diff_add_arg PROTO ((const char *)); -static void call_diff_setup PROTO ((const char *prog)); +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)); @@ -88,62 +89,37 @@ static void call_diff_flush_output PROTO 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) +call_diff_setup (prog, argc, argv) const char *prog; + int argc; + char * const *argv; { - char *cp; int i; - char *call_diff_prog; /* clean out any malloc'ed values from call_diff_argv */ - for (i = 0; i < call_diff_argc; i++) - { - if (call_diff_argv[i]) - { - free (call_diff_argv[i]); - call_diff_argv[i] = (char *) 0; - } - } + run_arg_free_p (call_diff_argc, call_diff_argv); call_diff_argc = 0; - call_diff_prog = xstrdup (prog); - /* put each word into call_diff_argv, allocating it as we go */ - for (cp = strtok (call_diff_prog, " \t"); - cp != NULL; - cp = strtok ((char *) NULL, " \t")) - call_diff_add_arg (cp); - free (call_diff_prog); -} - -static void -call_diff_arg (s) - const char *s; -{ - call_diff_add_arg (s); + call_diff_add_arg (prog); + for (i = 0; i < argc; i++) + call_diff_add_arg (argv[i]); } -static void -call_diff_add_arg (s) - const char *s; -{ - /* allocate more argv entries if we've run out */ - if (call_diff_argc >= call_diff_argc_allocated) - { - call_diff_argc_allocated += 50; - call_diff_argv = (char **) - xrealloc ((char *) call_diff_argv, - call_diff_argc_allocated * sizeof (char **)); - } - - if (s) - call_diff_argv[call_diff_argc++] = xstrdup (s); - else - /* Not post-incremented on purpose! */ - call_diff_argv[call_diff_argc] = (char *) 0; -} /* Callback function for the diff library to write data to the output file. This is used when we are producing output to stdout. */ @@ -216,6 +192,8 @@ 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); @@ -308,21 +286,21 @@ RCS_merge(rcs, path, workfile, options, /* 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"); - call_diff_arg ("-E"); - call_diff_arg ("-am"); - - call_diff_arg ("-L"); - call_diff_arg (workfile); - call_diff_arg ("-L"); - call_diff_arg (xrev1); - call_diff_arg ("-L"); - call_diff_arg (xrev2); - - call_diff_arg ("--"); - call_diff_arg (workfile); - call_diff_arg (tmp1); - call_diff_arg (tmp2); + 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); @@ -388,10 +366,11 @@ RCS_merge(rcs, path, workfile, options, 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, opts, options, rev1, rev1_cache, rev2, - label1, label2, workfile ) +RCS_exec_rcsdiff (rcsfile, diff_argc, diff_argv, options, rev1, rev1_cache, + rev2, label1, label2, workfile) RCSNode *rcsfile; - const char *opts; + int diff_argc; + char * const *diff_argv; const char *options; const char *rev1; const char *rev1_cache; @@ -471,8 +450,9 @@ RCS file: ", 0); use_file2 = tmpfile2; } - RCS_output_diff_options (opts, rev1, rev2, workfile); - status = diff_exec( use_file1, use_file2, label1, label2, opts, RUN_TTY ); + 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; @@ -551,16 +531,15 @@ RCS file: ", 0); message on stderr. */ int -diff_exec (file1, file2, label1, label2, options, out) +diff_exec (file1, file2, label1, label2, dargc, dargv, out) const char *file1; const char *file2; const char *label1; const char *label2; - const char *options; + int dargc; + char * const *dargv; const char *out; { - char *args; - #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 @@ -594,18 +573,15 @@ diff_exec (file1, file2, label1, label2, } #endif - args = xmalloc (strlen (options) + 10); - /* The first word in this string is used only for error reporting. */ - sprintf (args, "diff %s", options); - call_diff_setup (args); + /* The first arg to call_diff_setup is used only for error reporting. */ + call_diff_setup ("diff", dargc, dargv); if (label1) - call_diff_arg (label1); + call_diff_add_arg (label1); if (label2) - call_diff_arg (label2); - call_diff_arg ("--"); - call_diff_arg (file1); - call_diff_arg (file2); - free (args); + call_diff_add_arg (label2); + call_diff_add_arg ("--"); + call_diff_add_arg (file1); + call_diff_add_arg (file2); return call_diff (out); } @@ -617,19 +593,23 @@ diff_exec (file1, file2, label1, label2, that I have seen. */ static void -RCS_output_diff_options (opts, rev1, rev2, workfile) - const char *opts; +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; { - char *tmp; - - tmp = (char *) xmalloc (strlen (opts) + strlen (rev1) + 10); - - sprintf (tmp, "diff%s -r%s", opts, rev1); - cvs_output (tmp, 0); - free (tmp); + 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) { Index: src/run.c =================================================================== RCS file: /cvs/ccvs/src/run.c,v retrieving revision 1.33.6.3 retrieving revision 1.33.6.4 diff -u -p -r1.33.6.3 -r1.33.6.4 --- src/run.c 1 Apr 2004 19:07:51 -0000 1.33.6.3 +++ src/run.c 27 May 2005 16:25:11 -0000 1.33.6.4 @@ -36,7 +36,19 @@ extern char *strtok (); */ static char **run_argv; static int run_argc; -static int run_argc_allocated; +static size_t run_argc_allocated; + + + +void +run_arg_free_p (int argc, char **argv) +{ + int i; + for (i = 0; i < argc; i++) + free (argv[i]); +} + + /* VARARGS */ void @@ -44,18 +56,10 @@ run_setup (prog) const char *prog; { char *cp; - int i; char *run_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_arg_free_p (run_argc, run_argv); run_argc = 0; run_prog = xstrdup (prog); @@ -73,22 +77,35 @@ run_arg (s) run_add_arg (s); } -static void -run_add_arg (s) + + +void +run_add_arg_p (iargc, iarg_allocated, iargv, s) + int *iargc; + size_t *iarg_allocated; + char ***iargv; const char *s; { /* allocate more argv entries if we've run out */ - if (run_argc >= run_argc_allocated) + if (*iargc >= *iarg_allocated) { - run_argc_allocated += 50; - run_argv = (char **) xrealloc ((char *) run_argv, - run_argc_allocated * sizeof (char **)); + *iarg_allocated += 50; + *iargv = xrealloc (*iargv, *iarg_allocated * sizeof (char **)); } if (s) - run_argv[run_argc++] = xstrdup (s); + (*iargv)[(*iargc)++] = xstrdup (s); else - run_argv[run_argc] = (char *) 0; /* not post-incremented on purpose! */ + (*iargv)[*iargc] = NULL; /* not post-incremented on purpose! */ +} + + + +static void +run_add_arg (s) + const char *s; +{ + run_add_arg_p (&run_argc, &run_argc_allocated, &run_argv, s); } Index: src/sanity.sh =================================================================== RCS file: /cvs/ccvs/src/sanity.sh,v retrieving revision 1.752.2.170 retrieving revision 1.752.2.171 diff -u -p -r1.752.2.170 -r1.752.2.171 --- src/sanity.sh 2 May 2005 17:06:56 -0000 1.752.2.170 +++ src/sanity.sh 27 May 2005 16:25:11 -0000 1.752.2.171 @@ -2204,7 +2204,7 @@ ${PLUS} ssfile line 2" =================================================================== RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v retrieving revision 1\.1 -diff -c -C3isacrowd -r1\.1 ssfile +diff -c -C 3isacrowd -r1\.1 ssfile ${PROG} diff: invalid context length argument" dotest basica-7 "${testcvs} -q ci -m modify-it" \ "Checking in sdir/ssdir/ssfile; @@ -4813,7 +4813,7 @@ done" =================================================================== RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v retrieving revision 1\.2 -diff --ifdef=HAVE_WINSOCK_H -r1\.2 abc +diff --ifdef HAVE_WINSOCK_H -r1\.2 abc #ifndef HAVE_WINSOCK_H extern int gethostname (); #else /\* HAVE_WINSOCK_H \*/ @@ -7623,12 +7623,12 @@ mumble; } EOF # Use dotest_fail because exit status from `cvs diff' must be 1. - dotest_fail rcslib-diffrgx-3 "${testcvs} diff -c -F'.*(' rgx.c" \ + dotest_fail rcslib-diffrgx-3 "${testcvs} diff -c -F'.* (' rgx.c" \ "Index: rgx\.c =================================================================== RCS file: ${CVSROOT_DIRNAME}/first-dir/rgx\.c,v retrieving revision 1\.1 -diff -c -F\.\*( -r1\.1 rgx\.c +diff -c -F \.\* ( -r1\.1 rgx\.c \*\*\* rgx\.c ${RFCDATE} 1\.1 --- rgx\.c ${RFCDATE} \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* test_regex (whiz, bang) Index: src/update.c =================================================================== RCS file: /cvs/ccvs/src/update.c,v retrieving revision 1.202.4.24 retrieving revision 1.202.4.25 diff -u -p -r1.202.4.24 -r1.202.4.25 --- src/update.c 16 Mar 2005 22:00:45 -0000 1.202.4.24 +++ src/update.c 27 May 2005 16:25:14 -0000 1.202.4.25 @@ -1724,7 +1724,9 @@ patch_file (finfo, vers_ts, docheckout, retcode = 0; if (! fail) { - char *diff_options; + int dargc = 0; + size_t darg_allocated = 0; + char **dargv = NULL; /* If the client does not support the Rcs-diff command, we send a context diff, and the client must invoke patch. @@ -1732,16 +1734,13 @@ patch_file (finfo, vers_ts, docheckout, new approach only requires running diff in the server; the client can handle everything without invoking an external program. */ - if (! rcs_diff_patches) - { + if (!rcs_diff_patches) /* We use -c, not -u, because that is what CVS has traditionally used. Kind of a moot point, now that Rcs-diff is preferred, so there is no point in making the compatibility issues worse. */ - diff_options = "-c"; - } + run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c"); else - { /* Now that diff is librarified, we could be passing -a if we wanted to. However, it is unclear to me whether we would want to. Does diff -a, in any significant @@ -1751,10 +1750,11 @@ patch_file (finfo, vers_ts, docheckout, 'binary'. Conversely, do they tend to be much larger in the bad cases? This needs some more thought/investigation, I suspect. */ - - diff_options = "-n"; - } - retcode = diff_exec (file1, file2, NULL, NULL, diff_options, finfo->file); + run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n"); + retcode = diff_exec (file1, file2, NULL, NULL, dargc, dargv, + finfo->file); + run_arg_free_p (dargc, dargv); + free (dargv); /* A retcode of 0 means no differences. 1 means some differences. */ if (retcode != 0
_______________________________________________ Bug-cvs mailing list Bug-cvs@gnu.org http://lists.gnu.org/mailman/listinfo/bug-cvs