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.
21 /* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
22 library", are intended to define our interface to RCS files.
24 Whether there will also be a version of RCS which uses this
25 library, or whether the library will be packaged for uses beyond
26 CVS or RCS (many people would like such a thing) is an open
27 question. Some considerations:
29 1. An RCS library for CVS must have the capabilities of the
30 existing CVS code which accesses RCS files. In particular, simple
31 approaches will often be slow.
33 2. An RCS library should not use code from the current RCS
34 (5.7 and its ancestors). The code has many problems. Too few
35 comments, too many layers of abstraction, too many global variables
36 (the correct number for a library is zero), too much intricately
37 interwoven functionality, and too many clever hacks. Paul Eggert,
38 the current RCS maintainer, agrees.
40 3. More work needs to be done in terms of separating out the RCS
41 library from the rest of CVS (for example, cvs_output should be
42 replaced by a callback, and the declarations should be centralized
43 into rcs.h, and probably other such cleanups).
45 4. To be useful for RCS and perhaps for other uses, the library
46 may need features beyond those needed by CVS.
48 5. Any changes to the RCS file format *must* be compatible. Many,
49 many tools (not just CVS and RCS) can at least import this format.
50 RCS and CVS must preserve the current ability to import/export it
51 (preferably improved--magic branches are currently a roadblock).
52 See doc/RCSFILES in the CVS distribution for documentation of this
55 On a related note, see the comments at diff_exec, later in this file,
56 for more on the diff library. */
58 static void RCS_output_diff_options (const char *, const char *, const char *,
62 /* Stuff to deal with passing arguments the way libdiff.a wants to deal
63 with them. This is a crufty interface; there is no good reason for it
64 to resemble a command line rather than something closer to "struct
65 log_data" in log.c. */
67 /* First call call_diff_setup to setup any initial arguments. The
68 argument will be parsed into whitespace separated words and added
69 to the global call_diff_argv list.
71 Then, optionally, call call_diff_arg for each additional argument
72 that you'd like to pass to the diff library.
74 Finally, call call_diff or call_diff3 to produce the diffs. */
76 static char **call_diff_argv;
77 static int call_diff_argc;
78 static int call_diff_argc_allocated;
80 static void call_diff_add_arg (const char *);
81 static void call_diff_setup (const char *prog);
82 static int call_diff (const char *out);
83 static int call_diff3 (char *out);
85 static void call_diff_write_output (const char *, size_t);
86 static void call_diff_flush_output (void);
87 static void call_diff_write_stdout (const char *);
88 static void call_diff_error (const char *, const char *, const char *);
92 call_diff_setup (const char *prog)
98 /* clean out any malloc'ed values from call_diff_argv */
99 for (i = 0; i < call_diff_argc; i++)
101 if (call_diff_argv[i])
103 free (call_diff_argv[i]);
104 call_diff_argv[i] = NULL;
109 call_diff_prog = xstrdup (prog);
111 /* put each word into call_diff_argv, allocating it as we go */
112 for (cp = strtok (call_diff_prog, " \t");
114 cp = strtok (NULL, " \t"))
115 call_diff_add_arg (cp);
116 free (call_diff_prog);
120 call_diff_arg (const char *s)
122 call_diff_add_arg (s);
126 call_diff_add_arg (const char *s)
128 /* allocate more argv entries if we've run out */
129 if (call_diff_argc >= call_diff_argc_allocated)
131 call_diff_argc_allocated += 50;
132 call_diff_argv = xnrealloc (call_diff_argv,
133 call_diff_argc_allocated,
138 call_diff_argv[call_diff_argc++] = xstrdup (s);
140 /* Not post-incremented on purpose! */
141 call_diff_argv[call_diff_argc] = NULL;
144 /* Callback function for the diff library to write data to the output
145 file. This is used when we are producing output to stdout. */
148 call_diff_write_output (const char *text, size_t len)
151 cvs_output (text, len);
154 /* Call back function for the diff library to flush the output file.
155 This is used when we are producing output to stdout. */
158 call_diff_flush_output (void)
163 /* Call back function for the diff library to write to stdout. */
166 call_diff_write_stdout (const char *text)
168 cvs_output (text, 0);
171 /* Call back function for the diff library to write to stderr. */
174 call_diff_error (const char *format, const char *a1, const char *a2)
176 /* FIXME: Should we somehow indicate that this error is coming from
178 error (0, 0, format, a1, a2);
181 /* This set of callback functions is used if we are sending the diff
184 static struct diff_callbacks call_diff_stdout_callbacks =
186 call_diff_write_output,
187 call_diff_flush_output,
188 call_diff_write_stdout,
192 /* This set of callback functions is used if we are sending the diff
195 static struct diff_callbacks call_diff_file_callbacks =
199 call_diff_write_stdout,
206 call_diff (const char *out)
209 return diff_run( call_diff_argc, call_diff_argv, NULL,
210 &call_diff_stdout_callbacks );
212 return diff_run( call_diff_argc, call_diff_argv, out,
213 &call_diff_file_callbacks );
219 call_diff3 (char *out)
222 return diff3_run (call_diff_argc, call_diff_argv, NULL,
223 &call_diff_stdout_callbacks);
225 return diff3_run (call_diff_argc, call_diff_argv, out,
226 &call_diff_file_callbacks);
231 /* Merge revisions REV1 and REV2. */
234 RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
235 const char *options, const char *rev1, const char *rev2)
239 char *diffout = NULL;
242 if (options != NULL && options[0] != '\0')
243 assert (options[0] == '-' && options[1] == 'k');
245 cvs_output ("RCS file: ", 0);
246 cvs_output (rcs->print_path, 0);
247 cvs_output ("\n", 1);
249 /* Calculate numeric revision numbers from rev1 and rev2 (may be
251 FIXME - No they can't. Both calls to RCS_merge are passing in
252 numeric revisions. */
253 xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
254 xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
255 assert (xrev1 && xrev2);
257 /* Check out chosen revisions. The error message when RCS_checkout
258 fails is not very informative -- it is taken verbatim from RCS 5.7,
259 and relies on RCS_checkout saying something intelligent upon failure. */
260 cvs_output ("retrieving revision ", 0);
261 cvs_output (xrev1, 0);
262 cvs_output ("\n", 1);
264 tmp1 = cvs_temp_name();
265 if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
267 cvs_outerr ("rcsmerge: co failed\n", 0);
271 cvs_output ("retrieving revision ", 0);
272 cvs_output (xrev2, 0);
273 cvs_output ("\n", 1);
275 tmp2 = cvs_temp_name();
276 if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
278 cvs_outerr ("rcsmerge: co failed\n", 0);
283 cvs_output ("Merging differences between ", 0);
284 cvs_output (xrev1, 0);
285 cvs_output (" and ", 0);
286 cvs_output (xrev2, 0);
287 cvs_output (" into ", 0);
288 cvs_output (workfile, 0);
289 cvs_output ("\n", 1);
291 /* Remember that the first word in the `call_diff_setup' string is used now
292 only for diagnostic messages -- CVS no longer forks to run diff3. */
293 diffout = cvs_temp_name();
294 call_diff_setup ("diff3");
295 call_diff_arg ("-E");
296 call_diff_arg ("-am");
298 call_diff_arg ("-L");
299 call_diff_arg (workfile);
300 call_diff_arg ("-L");
301 call_diff_arg (xrev1);
302 call_diff_arg ("-L");
303 call_diff_arg (xrev2);
305 call_diff_arg ("--");
306 call_diff_arg (workfile);
307 call_diff_arg (tmp1);
308 call_diff_arg (tmp2);
310 retval = call_diff3 (diffout);
313 cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
314 else if (retval == 2)
318 copy_file (diffout, workfile);
322 int save_noexec = noexec;
324 if (unlink_file (tmp1) < 0)
326 if (!existence_error (errno))
327 error (0, errno, "cannot remove temp file %s", tmp1);
330 if (unlink_file (tmp2) < 0)
332 if (!existence_error (errno))
333 error (0, errno, "cannot remove temp file %s", tmp2);
338 if (unlink_file (diffout) < 0)
340 if (!existence_error (errno))
341 error (0, errno, "cannot remove temp file %s", diffout);
347 noexec = save_noexec;
353 /* Diff revisions and/or files. OPTS controls the format of the diff
354 (it contains options such as "-w -c", &c), or "" for the default.
355 OPTIONS controls keyword expansion, as a string starting with "-k",
356 or "" to use the default. REV1 is the first revision to compare
357 against; it must be non-NULL. If REV2 is non-NULL, compare REV1
358 and REV2; if REV2 is NULL compare REV1 with the file in the working
359 directory, whose name is WORKFILE. LABEL1 and LABEL2 are default
360 file labels, and (if non-NULL) should be added as -L options
361 to diff. Output goes to stdout.
363 Return value is 0 for success, -1 for a failure which set errno,
364 or positive for a failure which printed a message on stderr.
366 This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
368 An issue is what timezone is used for the dates which appear in the
369 diff output. rcsdiff uses the -z flag, which is not presently
370 processed by CVS diff, but I'm not sure exactly how hard to worry
371 about this--any such features are undocumented in the context of
372 CVS, and I'm not sure how important to users. */
374 RCS_exec_rcsdiff (RCSNode *rcsfile, const char *opts, const char *options,
375 const char *rev1, const char *rev1_cache, const char *rev2,
376 const char *label1, const char *label2, const char *workfile)
378 char *tmpfile1 = NULL;
379 char *tmpfile2 = NULL;
380 const char *use_file1, *use_file2;
385 ===================================================================\n\
387 cvs_output (rcsfile->print_path, 0);
388 cvs_output ("\n", 1);
390 /* Historically, `cvs diff' has expanded the $Name keyword to the
391 empty string when checking out revisions. This is an accident,
392 but no one has considered the issue thoroughly enough to determine
393 what the best behavior is. Passing NULL for the `nametag' argument
394 preserves the existing behavior. */
396 cvs_output ("retrieving revision ", 0);
397 cvs_output (rev1, 0);
398 cvs_output ("\n", 1);
400 if (rev1_cache != NULL)
401 use_file1 = rev1_cache;
404 tmpfile1 = cvs_temp_name();
405 status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
415 "cannot check out revision %s of %s", rev1, rcsfile->path );
419 use_file1 = tmpfile1;
424 assert (workfile != NULL);
425 use_file2 = workfile;
429 tmpfile2 = cvs_temp_name ();
430 cvs_output ("retrieving revision ", 0);
431 cvs_output (rev2, 0);
432 cvs_output ("\n", 1);
433 status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
434 tmpfile2, NULL, NULL);
443 "cannot check out revision %s of %s", rev2, rcsfile->path);
446 use_file2 = tmpfile2;
449 RCS_output_diff_options (opts, rev1, rev2, workfile);
450 status = diff_exec( use_file1, use_file2, label1, label2, opts, RUN_TTY );
459 "cannot diff %s and %s", use_file1, use_file2);
466 /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
469 if( tmpfile1 != NULL )
471 if( CVS_UNLINK( tmpfile1 ) < 0 )
473 if( !existence_error( errno ) )
474 error( 0, errno, "cannot remove temp file %s", tmpfile1 );
478 if( tmpfile2 != NULL )
480 if( CVS_UNLINK( tmpfile2 ) < 0 )
482 if( !existence_error( errno ) )
483 error( 0, errno, "cannot remove temp file %s", tmpfile2 );
494 /* Show differences between two files. This is the start of a diff library.
498 * Should option parsing be part of the library or the caller? The
499 former allows the library to add options without changing the callers,
500 but it causes various problems. One is that something like --brief really
501 wants special handling in CVS, and probably the caller should retain
502 some flexibility in this area. Another is online help (the library could
503 have some feature for providing help, but how does that interact with
504 the help provided by the caller directly?). Another is that as things
505 stand currently, there is no separate namespace for diff options versus
506 "cvs diff" options like -l (that is, if the library adds an option which
507 conflicts with a CVS option, it is trouble).
509 * This isn't required for a first-cut diff library, but if there
510 would be a way for the caller to specify the timestamps that appear
511 in the diffs (rather than the library getting them from the files),
512 that would clean up the kludgy utime() calls in patch.c.
514 Show differences between FILE1 and FILE2. Either one can be
515 DEVNULL to indicate a nonexistent file (same as an empty file
516 currently, I suspect, but that may be an issue in and of itself).
517 OPTIONS is a list of diff options, or "" if none. At a minimum,
518 CVS expects that -c (update.c, patch.c) and -n (update.c) will be
519 supported. Other options, like -u, --speed-large-files, &c, will
520 be specified if the user specified them.
522 OUT is a filename to send the diffs to, or RUN_TTY to send them to
523 stdout. Error messages go to stderr. Return value is 0 for
524 success, -1 for a failure which set errno, 1 for success (and some
525 differences were found), or >1 for a failure which printed a
526 message on stderr. */
529 diff_exec (const char *file1, const char *file2, const char *label1,
530 const char *label2, const char *options, const char *out)
534 #ifdef PRESERVE_PERMISSIONS_SUPPORT
535 /* If either file1 or file2 are special files, pretend they are
536 /dev/null. Reason: suppose a file that represents a block
537 special device in one revision becomes a regular file. CVS
538 must find the `difference' between these files, but a special
539 file contains no data useful for calculating this metric. The
540 safe thing to do is to treat the special file as an empty file,
541 thus recording the regular file's full contents. Doing so will
542 create extremely large deltas at the point of transition
543 between device files and regular files, but this is probably
546 There may be ways around this, but I think they are fraught
549 if (preserve_perms &&
550 strcmp (file1, DEVNULL) != 0 &&
551 strcmp (file2, DEVNULL) != 0)
553 struct stat sb1, sb2;
555 if (CVS_LSTAT (file1, &sb1) < 0)
556 error (1, errno, "cannot get file information for %s", file1);
557 if (CVS_LSTAT (file2, &sb2) < 0)
558 error (1, errno, "cannot get file information for %s", file2);
560 if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
562 if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
567 /* The first word in this string is used only for error reporting. */
568 args = Xasprintf ("diff %s", options);
569 call_diff_setup (args);
571 call_diff_arg (label1);
573 call_diff_arg (label2);
574 call_diff_arg ("--");
575 call_diff_arg (file1);
576 call_diff_arg (file2);
579 return call_diff (out);
582 /* Print the options passed to DIFF, in the format used by rcsdiff.
583 The rcsdiff code that produces this output is extremely hairy, and
584 it is not clear how rcsdiff decides which options to print and
585 which not to print. The code below reproduces every rcsdiff run
589 RCS_output_diff_options (const char *opts, const char *rev1, const char *rev2,
590 const char *workfile)
594 tmp = Xasprintf ("diff%s -r%s", opts, rev1);
600 cvs_output (" -r", 3);
601 cvs_output (rev2, 0);
605 assert (workfile != NULL);
607 cvs_output (workfile, 0);
609 cvs_output ("\n", 1);