2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
13 * The functions in this file provide an interface for performing
14 * operations directly on RCS files.
24 /* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
25 library", are intended to define our interface to RCS files.
27 Whether there will also be a version of RCS which uses this
28 library, or whether the library will be packaged for uses beyond
29 CVS or RCS (many people would like such a thing) is an open
30 question. Some considerations:
32 1. An RCS library for CVS must have the capabilities of the
33 existing CVS code which accesses RCS files. In particular, simple
34 approaches will often be slow.
36 2. An RCS library should not use code from the current RCS
37 (5.7 and its ancestors). The code has many problems. Too few
38 comments, too many layers of abstraction, too many global variables
39 (the correct number for a library is zero), too much intricately
40 interwoven functionality, and too many clever hacks. Paul Eggert,
41 the current RCS maintainer, agrees.
43 3. More work needs to be done in terms of separating out the RCS
44 library from the rest of CVS (for example, cvs_output should be
45 replaced by a callback, and the declarations should be centralized
46 into rcs.h, and probably other such cleanups).
48 4. To be useful for RCS and perhaps for other uses, the library
49 may need features beyond those needed by CVS.
51 5. Any changes to the RCS file format *must* be compatible. Many,
52 many tools (not just CVS and RCS) can at least import this format.
53 RCS and CVS must preserve the current ability to import/export it
54 (preferably improved--magic branches are currently a roadblock).
55 See doc/RCSFILES in the CVS distribution for documentation of this
58 On a related note, see the comments at diff_exec, later in this file,
59 for more on the diff library. */
61 static void RCS_output_diff_options PROTO ((int, char *const *, const char *,
62 const char *, const char *));
65 /* Stuff to deal with passing arguments the way libdiff.a wants to deal
66 with them. This is a crufty interface; there is no good reason for it
67 to resemble a command line rather than something closer to "struct
68 log_data" in log.c. */
70 /* First call call_diff_setup to setup any initial arguments. The
71 argument will be parsed into whitespace separated words and added
72 to the global call_diff_argv list.
74 Then, optionally, call call_diff_add_arg for each additional argument
75 that you'd like to pass to the diff library.
77 Finally, call call_diff or call_diff3 to produce the diffs. */
79 static char **call_diff_argv;
80 static int call_diff_argc;
81 static size_t call_diff_argc_allocated;
83 static void call_diff_add_arg PROTO ((const char *));
84 static void call_diff_setup PROTO ((const char *prog,
85 int argc, char * const *argv));
86 static int call_diff PROTO ((const char *out));
87 static int call_diff3 PROTO ((char *out));
89 static void call_diff_write_output PROTO((const char *, size_t));
90 static void call_diff_flush_output PROTO((void));
91 static void call_diff_write_stdout PROTO((const char *));
92 static void call_diff_error PROTO((const char *, const char *, const char *));
100 run_add_arg_p (&call_diff_argc, &call_diff_argc_allocated, &call_diff_argv,
108 call_diff_setup (prog, argc, argv)
115 /* clean out any malloc'ed values from call_diff_argv */
116 run_arg_free_p (call_diff_argc, call_diff_argv);
119 /* put each word into call_diff_argv, allocating it as we go */
120 call_diff_add_arg (prog);
121 for (i = 0; i < argc; i++)
122 call_diff_add_arg (argv[i]);
126 /* Callback function for the diff library to write data to the output
127 file. This is used when we are producing output to stdout. */
130 call_diff_write_output (text, len)
135 cvs_output (text, len);
138 /* Call back function for the diff library to flush the output file.
139 This is used when we are producing output to stdout. */
142 call_diff_flush_output ()
147 /* Call back function for the diff library to write to stdout. */
150 call_diff_write_stdout (text)
153 cvs_output (text, 0);
156 /* Call back function for the diff library to write to stderr. */
159 call_diff_error (format, a1, a2)
164 /* FIXME: Should we somehow indicate that this error is coming from
166 error (0, 0, format, a1, a2);
169 /* This set of callback functions is used if we are sending the diff
172 static struct diff_callbacks call_diff_stdout_callbacks =
174 call_diff_write_output,
175 call_diff_flush_output,
176 call_diff_write_stdout,
180 /* This set of callback functions is used if we are sending the diff
183 static struct diff_callbacks call_diff_file_callbacks =
185 (void (*) PROTO((const char *, size_t))) NULL,
186 (void (*) PROTO((void))) NULL,
187 call_diff_write_stdout,
197 call_diff_add_arg (NULL);
200 return diff_run (call_diff_argc, call_diff_argv, NULL,
201 &call_diff_stdout_callbacks);
203 return diff_run (call_diff_argc, call_diff_argv, out,
204 &call_diff_file_callbacks);
214 return diff3_run (call_diff_argc, call_diff_argv, NULL,
215 &call_diff_stdout_callbacks);
217 return diff3_run (call_diff_argc, call_diff_argv, out,
218 &call_diff_file_callbacks);
223 /* Merge revisions REV1 and REV2. */
226 RCS_merge(rcs, path, workfile, options, rev1, rev2)
229 const char *workfile;
236 char *diffout = NULL;
239 if (options != NULL && options[0] != '\0')
240 assert (options[0] == '-' && options[1] == 'k');
242 cvs_output ("RCS file: ", 0);
243 cvs_output (rcs->path, 0);
244 cvs_output ("\n", 1);
246 /* Calculate numeric revision numbers from rev1 and rev2 (may be
248 xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
249 xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
250 assert (xrev1 && xrev2);
252 /* Check out chosen revisions. The error message when RCS_checkout
253 fails is not very informative -- it is taken verbatim from RCS 5.7,
254 and relies on RCS_checkout saying something intelligent upon failure. */
255 cvs_output ("retrieving revision ", 0);
256 cvs_output (xrev1, 0);
257 cvs_output ("\n", 1);
259 tmp1 = cvs_temp_name();
260 if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1,
261 (RCSCHECKOUTPROC)0, NULL))
263 cvs_outerr ("rcsmerge: co failed\n", 0);
267 cvs_output ("retrieving revision ", 0);
268 cvs_output (xrev2, 0);
269 cvs_output ("\n", 1);
271 tmp2 = cvs_temp_name();
272 if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2,
273 (RCSCHECKOUTPROC)0, NULL))
275 cvs_outerr ("rcsmerge: co failed\n", 0);
280 cvs_output ("Merging differences between ", 0);
281 cvs_output (xrev1, 0);
282 cvs_output (" and ", 0);
283 cvs_output (xrev2, 0);
284 cvs_output (" into ", 0);
285 cvs_output (workfile, 0);
286 cvs_output ("\n", 1);
288 /* Remember that the first word in the `call_diff_setup' string is used now
289 only for diagnostic messages -- CVS no longer forks to run diff3. */
290 diffout = cvs_temp_name();
291 call_diff_setup ("diff3", 0, NULL);
292 call_diff_add_arg ("-E");
293 call_diff_add_arg ("-am");
295 call_diff_add_arg ("-L");
296 call_diff_add_arg (workfile);
297 call_diff_add_arg ("-L");
298 call_diff_add_arg (xrev1);
299 call_diff_add_arg ("-L");
300 call_diff_add_arg (xrev2);
302 call_diff_add_arg ("--");
303 call_diff_add_arg (workfile);
304 call_diff_add_arg (tmp1);
305 call_diff_add_arg (tmp2);
307 retval = call_diff3 (diffout);
310 cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
311 else if (retval == 2)
315 copy_file (diffout, workfile);
319 int save_noexec = noexec;
321 if (unlink_file (tmp1) < 0)
323 if (!existence_error (errno))
324 error (0, errno, "cannot remove temp file %s", tmp1);
327 if (unlink_file (tmp2) < 0)
329 if (!existence_error (errno))
330 error (0, errno, "cannot remove temp file %s", tmp2);
335 if (unlink_file (diffout) < 0)
337 if (!existence_error (errno))
338 error (0, errno, "cannot remove temp file %s", diffout);
344 noexec = save_noexec;
350 /* Diff revisions and/or files. OPTS controls the format of the diff
351 (it contains options such as "-w -c", &c), or "" for the default.
352 OPTIONS controls keyword expansion, as a string starting with "-k",
353 or "" to use the default. REV1 is the first revision to compare
354 against; it must be non-NULL. If REV2 is non-NULL, compare REV1
355 and REV2; if REV2 is NULL compare REV1 with the file in the working
356 directory, whose name is WORKFILE. LABEL1 and LABEL2 are default
357 file labels, and (if non-NULL) should be added as -L options
358 to diff. Output goes to stdout.
360 Return value is 0 for success, -1 for a failure which set errno,
361 or positive for a failure which printed a message on stderr.
363 This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
365 An issue is what timezone is used for the dates which appear in the
366 diff output. rcsdiff uses the -z flag, which is not presently
367 processed by CVS diff, but I'm not sure exactly how hard to worry
368 about this--any such features are undocumented in the context of
369 CVS, and I'm not sure how important to users. */
371 RCS_exec_rcsdiff (rcsfile, diff_argc, diff_argv, options, rev1, rev1_cache,
372 rev2, label1, label2, workfile)
375 char * const *diff_argv;
378 const char *rev1_cache;
382 const char *workfile;
384 char *tmpfile1 = NULL;
385 char *tmpfile2 = NULL;
386 const char *use_file1, *use_file2;
391 ===================================================================\n\
393 cvs_output (rcsfile->path, 0);
394 cvs_output ("\n", 1);
396 /* Historically, `cvs diff' has expanded the $Name keyword to the
397 empty string when checking out revisions. This is an accident,
398 but no one has considered the issue thoroughly enough to determine
399 what the best behavior is. Passing NULL for the `nametag' argument
400 preserves the existing behavior. */
402 cvs_output ("retrieving revision ", 0);
403 cvs_output (rev1, 0);
404 cvs_output ("\n", 1);
406 if (rev1_cache != NULL)
407 use_file1 = rev1_cache;
410 tmpfile1 = cvs_temp_name();
411 status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
412 (RCSCHECKOUTPROC)0, NULL);
421 "cannot check out revision %s of %s", rev1, rcsfile->path );
425 use_file1 = tmpfile1;
430 assert (workfile != NULL);
431 use_file2 = workfile;
435 tmpfile2 = cvs_temp_name ();
436 cvs_output ("retrieving revision ", 0);
437 cvs_output (rev2, 0);
438 cvs_output ("\n", 1);
439 status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
440 tmpfile2, (RCSCHECKOUTPROC)0, NULL);
449 "cannot check out revision %s of %s", rev2, rcsfile->path);
452 use_file2 = tmpfile2;
455 RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile);
456 status = diff_exec (use_file1, use_file2, label1, label2,
457 diff_argc, diff_argv, RUN_TTY);
466 "cannot diff %s and %s", use_file1, use_file2);
473 /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
476 if( tmpfile1 != NULL )
478 if( CVS_UNLINK( tmpfile1 ) < 0 )
480 if( !existence_error( errno ) )
481 error( 0, errno, "cannot remove temp file %s", tmpfile1 );
485 if( tmpfile2 != NULL )
487 if( CVS_UNLINK( tmpfile2 ) < 0 )
489 if( !existence_error( errno ) )
490 error( 0, errno, "cannot remove temp file %s", tmpfile2 );
501 /* Show differences between two files. This is the start of a diff library.
505 * Should option parsing be part of the library or the caller? The
506 former allows the library to add options without changing the callers,
507 but it causes various problems. One is that something like --brief really
508 wants special handling in CVS, and probably the caller should retain
509 some flexibility in this area. Another is online help (the library could
510 have some feature for providing help, but how does that interact with
511 the help provided by the caller directly?). Another is that as things
512 stand currently, there is no separate namespace for diff options versus
513 "cvs diff" options like -l (that is, if the library adds an option which
514 conflicts with a CVS option, it is trouble).
516 * This isn't required for a first-cut diff library, but if there
517 would be a way for the caller to specify the timestamps that appear
518 in the diffs (rather than the library getting them from the files),
519 that would clean up the kludgy utime() calls in patch.c.
521 Show differences between FILE1 and FILE2. Either one can be
522 DEVNULL to indicate a nonexistent file (same as an empty file
523 currently, I suspect, but that may be an issue in and of itself).
524 OPTIONS is a list of diff options, or "" if none. At a minimum,
525 CVS expects that -c (update.c, patch.c) and -n (update.c) will be
526 supported. Other options, like -u, --speed-large-files, &c, will
527 be specified if the user specified them.
529 OUT is a filename to send the diffs to, or RUN_TTY to send them to
530 stdout. Error messages go to stderr. Return value is 0 for
531 success, -1 for a failure which set errno, 1 for success (and some
532 differences were found), or >1 for a failure which printed a
533 message on stderr. */
536 diff_exec (file1, file2, label1, label2, dargc, dargv, out)
545 #ifdef PRESERVE_PERMISSIONS_SUPPORT
546 /* If either file1 or file2 are special files, pretend they are
547 /dev/null. Reason: suppose a file that represents a block
548 special device in one revision becomes a regular file. CVS
549 must find the `difference' between these files, but a special
550 file contains no data useful for calculating this metric. The
551 safe thing to do is to treat the special file as an empty file,
552 thus recording the regular file's full contents. Doing so will
553 create extremely large deltas at the point of transition
554 between device files and regular files, but this is probably
557 There may be ways around this, but I think they are fraught
560 if (preserve_perms &&
561 strcmp (file1, DEVNULL) != 0 &&
562 strcmp (file2, DEVNULL) != 0)
564 struct stat sb1, sb2;
566 if (CVS_LSTAT (file1, &sb1) < 0)
567 error (1, errno, "cannot get file information for %s", file1);
568 if (CVS_LSTAT (file2, &sb2) < 0)
569 error (1, errno, "cannot get file information for %s", file2);
571 if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
573 if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
578 /* The first arg to call_diff_setup is used only for error reporting. */
579 call_diff_setup ("diff", dargc, dargv);
581 call_diff_add_arg (label1);
583 call_diff_add_arg (label2);
584 call_diff_add_arg ("--");
585 call_diff_add_arg (file1);
586 call_diff_add_arg (file2);
588 return call_diff (out);
591 /* Print the options passed to DIFF, in the format used by rcsdiff.
592 The rcsdiff code that produces this output is extremely hairy, and
593 it is not clear how rcsdiff decides which options to print and
594 which not to print. The code below reproduces every rcsdiff run
598 RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile)
600 char * const *diff_argv;
603 const char *workfile;
607 cvs_output ("diff", 0);
608 for (i = 0; i < diff_argc; i++)
611 cvs_output (diff_argv[i], 0);
613 cvs_output (" -r", 3);
614 cvs_output (rev1, 0);
618 cvs_output (" -r", 3);
619 cvs_output (rev2, 0);
623 assert (workfile != NULL);
625 cvs_output (workfile, 0);
627 cvs_output ("\n", 1);