kernel: Remove the FFS_ROOT option. It was a no-op since 4.9.
[dragonfly.git] / contrib / cvs-1.12 / src / rcscmds.c
blob3c2afb7f60b52991634ed0ff2fbceecc7768255d
1 /*
2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5 * and others.
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
9 *
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.
17 #include "cvs.h"
18 #include <stdio.h>
19 #include "diffrun.h"
20 #include "quotearg.h"
22 /* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
23 library", are intended to define our interface to RCS files.
25 Whether there will also be a version of RCS which uses this
26 library, or whether the library will be packaged for uses beyond
27 CVS or RCS (many people would like such a thing) is an open
28 question. Some considerations:
30 1. An RCS library for CVS must have the capabilities of the
31 existing CVS code which accesses RCS files. In particular, simple
32 approaches will often be slow.
34 2. An RCS library should not use code from the current RCS
35 (5.7 and its ancestors). The code has many problems. Too few
36 comments, too many layers of abstraction, too many global variables
37 (the correct number for a library is zero), too much intricately
38 interwoven functionality, and too many clever hacks. Paul Eggert,
39 the current RCS maintainer, agrees.
41 3. More work needs to be done in terms of separating out the RCS
42 library from the rest of CVS (for example, cvs_output should be
43 replaced by a callback, and the declarations should be centralized
44 into rcs.h, and probably other such cleanups).
46 4. To be useful for RCS and perhaps for other uses, the library
47 may need features beyond those needed by CVS.
49 5. Any changes to the RCS file format *must* be compatible. Many,
50 many tools (not just CVS and RCS) can at least import this format.
51 RCS and CVS must preserve the current ability to import/export it
52 (preferably improved--magic branches are currently a roadblock).
53 See doc/RCSFILES in the CVS distribution for documentation of this
54 file format.
56 On a related note, see the comments at diff_exec, later in this file,
57 for more on the diff library. */
59 static void RCS_output_diff_options (int, char * const *, const char *,
60 const char *, const char *);
63 /* Stuff to deal with passing arguments the way libdiff.a wants to deal
64 with them. This is a crufty interface; there is no good reason for it
65 to resemble a command line rather than something closer to "struct
66 log_data" in log.c. */
68 /* First call call_diff_setup to setup any initial arguments. The
69 argument will be parsed into whitespace separated words and added
70 to the global call_diff_argv list.
72 Then, optionally, call call_diff_add_arg for each additional argument
73 that you'd like to pass to the diff library.
75 Finally, call call_diff or call_diff3 to produce the diffs. */
77 static char **call_diff_argv;
78 static int call_diff_argc;
79 static size_t call_diff_arg_allocated;
81 static int call_diff (const char *out);
82 static int call_diff3 (char *out);
84 static void call_diff_write_output (const char *, size_t);
85 static void call_diff_flush_output (void);
86 static void call_diff_write_stdout (const char *);
87 static void call_diff_error (const char *, const char *, const char *);
91 /* VARARGS */
92 static void
93 call_diff_add_arg (const char *s)
95 TRACE (TRACE_DATA, "call_diff_add_arg (%s)", s);
96 run_add_arg_p (&call_diff_argc, &call_diff_arg_allocated, &call_diff_argv,
97 s);
102 static void
103 call_diff_setup (const char *prog, int argc, char * const *argv)
105 int i;
107 /* clean out any malloc'ed values from call_diff_argv */
108 run_arg_free_p (call_diff_argc, call_diff_argv);
109 call_diff_argc = 0;
111 /* put each word into call_diff_argv, allocating it as we go */
112 call_diff_add_arg (prog);
113 for (i = 0; i < argc; i++)
114 call_diff_add_arg (argv[i]);
119 /* Callback function for the diff library to write data to the output
120 file. This is used when we are producing output to stdout. */
122 static void
123 call_diff_write_output (const char *text, size_t len)
125 if (len > 0)
126 cvs_output (text, len);
129 /* Call back function for the diff library to flush the output file.
130 This is used when we are producing output to stdout. */
132 static void
133 call_diff_flush_output (void)
135 cvs_flushout ();
138 /* Call back function for the diff library to write to stdout. */
140 static void
141 call_diff_write_stdout (const char *text)
143 cvs_output (text, 0);
146 /* Call back function for the diff library to write to stderr. */
148 static void
149 call_diff_error (const char *format, const char *a1, const char *a2)
151 /* FIXME: Should we somehow indicate that this error is coming from
152 the diff library? */
153 error (0, 0, format, a1, a2);
156 /* This set of callback functions is used if we are sending the diff
157 to stdout. */
159 static struct diff_callbacks call_diff_stdout_callbacks =
161 call_diff_write_output,
162 call_diff_flush_output,
163 call_diff_write_stdout,
164 call_diff_error
167 /* This set of callback functions is used if we are sending the diff
168 to a file. */
170 static struct diff_callbacks call_diff_file_callbacks =
172 NULL,
173 NULL,
174 call_diff_write_stdout,
175 call_diff_error
180 static int
181 call_diff (const char *out)
183 call_diff_add_arg (NULL);
185 if (out == RUN_TTY)
186 return diff_run( call_diff_argc, call_diff_argv, NULL,
187 &call_diff_stdout_callbacks );
188 else
189 return diff_run( call_diff_argc, call_diff_argv, out,
190 &call_diff_file_callbacks );
195 static int
196 call_diff3 (char *out)
198 if (out == RUN_TTY)
199 return diff3_run (call_diff_argc, call_diff_argv, NULL,
200 &call_diff_stdout_callbacks);
201 else
202 return diff3_run (call_diff_argc, call_diff_argv, out,
203 &call_diff_file_callbacks);
208 /* Merge revisions REV1 and REV2. */
211 RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
212 const char *options, const char *rev1, const char *rev2)
214 char *xrev1, *xrev2;
215 char *tmp1, *tmp2;
216 char *diffout = NULL;
217 int retval;
219 if (options != NULL && options[0] != '\0')
220 assert (options[0] == '-' && options[1] == 'k');
222 cvs_output ("RCS file: ", 0);
223 cvs_output (rcs->print_path, 0);
224 cvs_output ("\n", 1);
226 /* Calculate numeric revision numbers from rev1 and rev2 (may be
227 symbolic).
228 FIXME - No they can't. Both calls to RCS_merge are passing in
229 numeric revisions. */
230 xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
231 xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
232 assert (xrev1 && xrev2);
234 /* Check out chosen revisions. The error message when RCS_checkout
235 fails is not very informative -- it is taken verbatim from RCS 5.7,
236 and relies on RCS_checkout saying something intelligent upon failure. */
237 cvs_output ("retrieving revision ", 0);
238 cvs_output (xrev1, 0);
239 cvs_output ("\n", 1);
241 tmp1 = cvs_temp_name();
242 if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
244 cvs_outerr ("rcsmerge: co failed\n", 0);
245 exit (EXIT_FAILURE);
248 cvs_output ("retrieving revision ", 0);
249 cvs_output (xrev2, 0);
250 cvs_output ("\n", 1);
252 tmp2 = cvs_temp_name();
253 if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
255 cvs_outerr ("rcsmerge: co failed\n", 0);
256 exit (EXIT_FAILURE);
259 /* Merge changes. */
260 cvs_output ("Merging differences between ", 0);
261 cvs_output (xrev1, 0);
262 cvs_output (" and ", 0);
263 cvs_output (xrev2, 0);
264 cvs_output (" into ", 0);
265 cvs_output (workfile, 0);
266 cvs_output ("\n", 1);
268 /* Remember that the first word in the `call_diff_setup' string is used now
269 only for diagnostic messages -- CVS no longer forks to run diff3. */
270 diffout = cvs_temp_name();
271 call_diff_setup ("diff3", 0, NULL);
272 call_diff_add_arg ("-E");
273 call_diff_add_arg ("-am");
275 call_diff_add_arg ("-L");
276 call_diff_add_arg (workfile);
277 call_diff_add_arg ("-L");
278 call_diff_add_arg (xrev1);
279 call_diff_add_arg ("-L");
280 call_diff_add_arg (xrev2);
282 call_diff_add_arg ("--");
283 call_diff_add_arg (workfile);
284 call_diff_add_arg (tmp1);
285 call_diff_add_arg (tmp2);
287 retval = call_diff3 (diffout);
289 if (retval == 1)
290 cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
291 else if (retval == 2)
292 exit (EXIT_FAILURE);
294 if (diffout)
295 copy_file (diffout, workfile);
297 /* Clean up. */
299 int save_noexec = noexec;
300 noexec = 0;
301 if (unlink_file (tmp1) < 0)
303 if (!existence_error (errno))
304 error (0, errno, "cannot remove temp file %s", tmp1);
306 free (tmp1);
307 if (unlink_file (tmp2) < 0)
309 if (!existence_error (errno))
310 error (0, errno, "cannot remove temp file %s", tmp2);
312 free (tmp2);
313 if (diffout)
315 if (unlink_file (diffout) < 0)
317 if (!existence_error (errno))
318 error (0, errno, "cannot remove temp file %s", diffout);
320 free (diffout);
322 free (xrev1);
323 free (xrev2);
324 noexec = save_noexec;
327 return retval;
330 /* Diff revisions and/or files. OPTS controls the format of the diff
331 (it contains options such as "-w -c", &c), or "" for the default.
332 OPTIONS controls keyword expansion, as a string starting with "-k",
333 or "" to use the default. REV1 is the first revision to compare
334 against; it must be non-NULL. If REV2 is non-NULL, compare REV1
335 and REV2; if REV2 is NULL compare REV1 with the file in the working
336 directory, whose name is WORKFILE. LABEL1 and LABEL2 are default
337 file labels, and (if non-NULL) should be added as -L options
338 to diff. Output goes to stdout.
340 Return value is 0 for success, -1 for a failure which set errno,
341 or positive for a failure which printed a message on stderr.
343 This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
345 An issue is what timezone is used for the dates which appear in the
346 diff output. rcsdiff uses the -z flag, which is not presently
347 processed by CVS diff, but I'm not sure exactly how hard to worry
348 about this--any such features are undocumented in the context of
349 CVS, and I'm not sure how important to users. */
351 RCS_exec_rcsdiff (RCSNode *rcsfile, int diff_argc,
352 char * const *diff_argv, const char *options,
353 const char *rev1, const char *rev1_cache, const char *rev2,
354 const char *label1, const char *label2, const char *workfile)
356 char *tmpfile1 = NULL;
357 char *tmpfile2 = NULL;
358 const char *use_file1, *use_file2;
359 int status, retval;
362 cvs_output ("\
363 ===================================================================\n\
364 RCS file: ", 0);
365 cvs_output (rcsfile->print_path, 0);
366 cvs_output ("\n", 1);
368 /* Historically, `cvs diff' has expanded the $Name keyword to the
369 empty string when checking out revisions. This is an accident,
370 but no one has considered the issue thoroughly enough to determine
371 what the best behavior is. Passing NULL for the `nametag' argument
372 preserves the existing behavior. */
374 cvs_output ("retrieving revision ", 0);
375 cvs_output (rev1, 0);
376 cvs_output ("\n", 1);
378 if (rev1_cache != NULL)
379 use_file1 = rev1_cache;
380 else
382 tmpfile1 = cvs_temp_name();
383 status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
384 NULL, NULL);
385 if (status > 0)
387 retval = status;
388 goto error_return;
390 else if (status < 0)
392 error( 0, errno,
393 "cannot check out revision %s of %s", rev1, rcsfile->path );
394 retval = 1;
395 goto error_return;
397 use_file1 = tmpfile1;
400 if (rev2 == NULL)
402 assert (workfile != NULL);
403 use_file2 = workfile;
405 else
407 tmpfile2 = cvs_temp_name ();
408 cvs_output ("retrieving revision ", 0);
409 cvs_output (rev2, 0);
410 cvs_output ("\n", 1);
411 status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
412 tmpfile2, NULL, NULL);
413 if (status > 0)
415 retval = status;
416 goto error_return;
418 else if (status < 0)
420 error (0, errno,
421 "cannot check out revision %s of %s", rev2, rcsfile->path);
422 return 1;
424 use_file2 = tmpfile2;
427 RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile);
428 status = diff_exec (use_file1, use_file2, label1, label2,
429 diff_argc, diff_argv, RUN_TTY);
430 if (status >= 0)
432 retval = status;
433 goto error_return;
435 else if (status < 0)
437 error (0, errno,
438 "cannot diff %s and %s", use_file1, use_file2);
439 retval = 1;
440 goto error_return;
443 error_return:
445 /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
446 * for noexec.
448 if( tmpfile1 != NULL )
450 if( CVS_UNLINK( tmpfile1 ) < 0 )
452 if( !existence_error( errno ) )
453 error( 0, errno, "cannot remove temp file %s", tmpfile1 );
455 free( tmpfile1 );
457 if( tmpfile2 != NULL )
459 if( CVS_UNLINK( tmpfile2 ) < 0 )
461 if( !existence_error( errno ) )
462 error( 0, errno, "cannot remove temp file %s", tmpfile2 );
464 free (tmpfile2);
468 return retval;
473 /* Show differences between two files. This is the start of a diff library.
475 Some issues:
477 * Should option parsing be part of the library or the caller? The
478 former allows the library to add options without changing the callers,
479 but it causes various problems. One is that something like --brief really
480 wants special handling in CVS, and probably the caller should retain
481 some flexibility in this area. Another is online help (the library could
482 have some feature for providing help, but how does that interact with
483 the help provided by the caller directly?). Another is that as things
484 stand currently, there is no separate namespace for diff options versus
485 "cvs diff" options like -l (that is, if the library adds an option which
486 conflicts with a CVS option, it is trouble).
488 * This isn't required for a first-cut diff library, but if there
489 would be a way for the caller to specify the timestamps that appear
490 in the diffs (rather than the library getting them from the files),
491 that would clean up the kludgy utime() calls in patch.c.
493 Show differences between FILE1 and FILE2. Either one can be
494 DEVNULL to indicate a nonexistent file (same as an empty file
495 currently, I suspect, but that may be an issue in and of itself).
496 OPTIONS is a list of diff options, or "" if none. At a minimum,
497 CVS expects that -c (update.c, patch.c) and -n (update.c) will be
498 supported. Other options, like -u, --speed-large-files, &c, will
499 be specified if the user specified them.
501 OUT is a filename to send the diffs to, or RUN_TTY to send them to
502 stdout. Error messages go to stderr. Return value is 0 for
503 success, -1 for a failure which set errno, 1 for success (and some
504 differences were found), or >1 for a failure which printed a
505 message on stderr. */
508 diff_exec (const char *file1, const char *file2, const char *label1,
509 const char *label2, int dargc, char * const *dargv,
510 const char *out)
512 TRACE (TRACE_FUNCTION, "diff_exec (%s, %s, %s, %s, %s)",
513 file1, file2, label1, label2, out);
515 #ifdef PRESERVE_PERMISSIONS_SUPPORT
516 /* If either file1 or file2 are special files, pretend they are
517 /dev/null. Reason: suppose a file that represents a block
518 special device in one revision becomes a regular file. CVS
519 must find the `difference' between these files, but a special
520 file contains no data useful for calculating this metric. The
521 safe thing to do is to treat the special file as an empty file,
522 thus recording the regular file's full contents. Doing so will
523 create extremely large deltas at the point of transition
524 between device files and regular files, but this is probably
525 very rare anyway.
527 There may be ways around this, but I think they are fraught
528 with danger. -twp */
530 if (preserve_perms &&
531 strcmp (file1, DEVNULL) != 0 &&
532 strcmp (file2, DEVNULL) != 0)
534 struct stat sb1, sb2;
536 if (lstat (file1, &sb1) < 0)
537 error (1, errno, "cannot get file information for %s", file1);
538 if (lstat (file2, &sb2) < 0)
539 error (1, errno, "cannot get file information for %s", file2);
541 if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
542 file1 = DEVNULL;
543 if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
544 file2 = DEVNULL;
546 #endif
548 /* The first arg to call_diff_setup is used only for error reporting. */
549 call_diff_setup ("diff", dargc, dargv);
550 if (label1)
551 call_diff_add_arg (label1);
552 if (label2)
553 call_diff_add_arg (label2);
554 call_diff_add_arg ("--");
555 call_diff_add_arg (file1);
556 call_diff_add_arg (file2);
558 return call_diff (out);
561 /* Print the options passed to DIFF, in the format used by rcsdiff.
562 The rcsdiff code that produces this output is extremely hairy, and
563 it is not clear how rcsdiff decides which options to print and
564 which not to print. The code below reproduces every rcsdiff run
565 that I have seen. */
567 static void
568 RCS_output_diff_options (int diff_argc, char * const *diff_argv,
569 const char *rev1, const char *rev2,
570 const char *workfile)
572 int i;
574 cvs_output ("diff", 0);
575 for (i = 0; i < diff_argc; i++)
577 cvs_output (" ", 1);
578 cvs_output (quotearg_style (shell_quoting_style, diff_argv[i]), 0);
580 cvs_output (" -r", 3);
581 cvs_output (rev1, 0);
583 if (rev2)
585 cvs_output (" -r", 3);
586 cvs_output (rev2, 0);
588 else
590 assert (workfile != NULL);
591 cvs_output (" ", 1);
592 cvs_output (workfile, 0);
594 cvs_output ("\n", 1);