update from MirBSD; for us relevant:
[alioth/cvs.git] / src / rcscmds.c
1 /*
2  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3  *
4  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5  *                                  and others.
6  *
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.
12  * 
13  * The functions in this file provide an interface for performing 
14  * operations directly on RCS files. 
15  */
16
17 #include "cvs.h"
18 #include <stdio.h>
19 #include "diffrun.h"
20 #include "quotearg.h"
21
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.
24
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:
29
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.
33
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.
40
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).
45
46    4.  To be useful for RCS and perhaps for other uses, the library
47    may need features beyond those needed by CVS.
48
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.
55
56    On a related note, see the comments at diff_exec, later in this file,
57    for more on the diff library.  */
58
59 static void RCS_output_diff_options (int, char * const *, const char *,
60                                      const char *, const char *);
61
62
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.  */
67
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.
71
72    Then, optionally, call call_diff_add_arg for each additional argument
73    that you'd like to pass to the diff library.
74
75    Finally, call call_diff or call_diff3 to produce the diffs.  */
76
77 static char **call_diff_argv;
78 static int call_diff_argc;
79 static size_t call_diff_arg_allocated;
80
81 static int call_diff (const char *out);
82 static int call_diff3 (char *out);
83
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 *);
88
89
90
91 /* VARARGS */
92 static void
93 call_diff_add_arg (const char *s)
94 {
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);
98 }
99
100
101
102 static void 
103 call_diff_setup (const char *prog, int argc, char * const *argv)
104 {
105     int i;
106
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;
110
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]);
115 }
116
117
118
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.  */
121
122 static void
123 call_diff_write_output (const char *text, size_t len)
124 {
125     if (len > 0)
126         cvs_output (text, len);
127 }
128
129 /* Call back function for the diff library to flush the output file.
130    This is used when we are producing output to stdout.  */
131
132 static void
133 call_diff_flush_output (void)
134 {
135     cvs_flushout ();
136 }
137
138 /* Call back function for the diff library to write to stdout.  */
139
140 static void
141 call_diff_write_stdout (const char *text)
142 {
143     cvs_output (text, 0);
144 }
145
146 /* Call back function for the diff library to write to stderr.  */
147
148 static void
149 call_diff_error (const char *format, const char *a1, const char *a2)
150 {
151     /* FIXME: Should we somehow indicate that this error is coming from
152        the diff library?  */
153     error (0, 0, format, a1, a2);
154 }
155
156 /* This set of callback functions is used if we are sending the diff
157    to stdout.  */
158
159 static struct diff_callbacks call_diff_stdout_callbacks =
160 {
161     call_diff_write_output,
162     call_diff_flush_output,
163     call_diff_write_stdout,
164     call_diff_error
165 };
166
167 /* This set of callback functions is used if we are sending the diff
168    to a file.  */
169
170 static struct diff_callbacks call_diff_file_callbacks =
171 {
172     NULL,
173     NULL,
174     call_diff_write_stdout,
175     call_diff_error
176 };
177
178
179
180 static int
181 call_diff (const char *out)
182 {
183     call_diff_add_arg (NULL);
184
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 );
191 }
192
193
194
195 static int
196 call_diff3 (char *out)
197 {
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);
204 }
205
206
207
208 /* Merge revisions REV1 and REV2. */
209
210 int
211 RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
212            const char *options, const char *rev1, const char *rev2)
213 {
214     char *xrev1, *xrev2;
215     char *tmp1, *tmp2;
216     char *diffout = NULL;
217     int retval;
218
219     if (options != NULL && options[0] != '\0')
220       assert (options[0] == '-' && options[1] == 'k');
221
222     cvs_output ("RCS file: ", 0);
223     cvs_output (rcs->print_path, 0);
224     cvs_output ("\n", 1);
225
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);
233
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);
240
241     tmp1 = cvs_temp_name();
242     if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
243     {
244         cvs_outerr ("rcsmerge: co failed\n", 0);
245         exit (EXIT_FAILURE);
246     }
247
248     cvs_output ("retrieving revision ", 0);
249     cvs_output (xrev2, 0);
250     cvs_output ("\n", 1);
251
252     tmp2 = cvs_temp_name();
253     if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
254     {
255         cvs_outerr ("rcsmerge: co failed\n", 0);
256         exit (EXIT_FAILURE);
257     }
258
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);
267
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");
274
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);
281
282     call_diff_add_arg ("--");
283     call_diff_add_arg (workfile);
284     call_diff_add_arg (tmp1);
285     call_diff_add_arg (tmp2);
286
287     retval = call_diff3 (diffout);
288
289     if (retval == 1)
290         cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
291     else if (retval == 2)
292         exit (EXIT_FAILURE);
293
294     if (diffout)
295         copy_file (diffout, workfile);
296
297     /* Clean up. */
298     {
299         int save_noexec = noexec;
300         noexec = 0;
301         if (unlink_file (tmp1) < 0)
302         {
303             if (!existence_error (errno))
304                 error (0, errno, "cannot remove temp file %s", tmp1);
305         }
306         free (tmp1);
307         if (unlink_file (tmp2) < 0)
308         {
309             if (!existence_error (errno))
310                 error (0, errno, "cannot remove temp file %s", tmp2);
311         }
312         free (tmp2);
313         if (diffout)
314         {
315             if (unlink_file (diffout) < 0)
316             {
317                 if (!existence_error (errno))
318                     error (0, errno, "cannot remove temp file %s", diffout);
319             }
320             free (diffout);
321         }
322         free (xrev1);
323         free (xrev2);
324         noexec = save_noexec;
325     }
326
327     return retval;
328 }
329
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.
339
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.
342
343    This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
344
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.  */
350 int
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)
355 {
356     char *tmpfile1 = NULL;
357     char *tmpfile2 = NULL;
358     const char *use_file1, *use_file2;
359     int status, retval;
360
361
362     cvs_output ("\
363 ===================================================================\n\
364 RCS file: ", 0);
365     cvs_output (rcsfile->print_path, 0);
366     cvs_output ("\n", 1);
367
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. */
373
374     cvs_output ("retrieving revision ", 0);
375     cvs_output (rev1, 0);
376     cvs_output ("\n", 1);
377
378     if (rev1_cache != NULL)
379         use_file1 = rev1_cache;
380     else
381     {
382         tmpfile1 = cvs_temp_name();
383         status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
384                                NULL, NULL);
385         if (status > 0)
386         {
387             retval = status;
388             goto error_return;
389         }
390         else if (status < 0)
391         {
392             error( 0, errno,
393                    "cannot check out revision %s of %s", rev1, rcsfile->path );
394             retval = 1;
395             goto error_return;
396         }
397         use_file1 = tmpfile1;
398     }
399
400     if (rev2 == NULL)
401     {
402         assert (workfile != NULL);
403         use_file2 = workfile;
404     }
405     else
406     {
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)
414         {
415             retval = status;
416             goto error_return;
417         }
418         else if (status < 0)
419         {
420             error (0, errno,
421                    "cannot check out revision %s of %s", rev2, rcsfile->path);
422             return 1;
423         }
424         use_file2 = tmpfile2;
425     }
426
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)
431     {
432         retval = status;
433         goto error_return;
434     }
435     else if (status < 0)
436     {
437         error (0, errno,
438                "cannot diff %s and %s", use_file1, use_file2);
439         retval = 1;
440         goto error_return;
441     }
442
443  error_return:
444     {
445         /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
446          * for noexec.
447          */
448         if( tmpfile1 != NULL )
449         {
450             if( CVS_UNLINK( tmpfile1 ) < 0 )
451             {
452                 if( !existence_error( errno ) )
453                     error( 0, errno, "cannot remove temp file %s", tmpfile1 );
454             }
455             free( tmpfile1 );
456         }
457         if( tmpfile2 != NULL )
458         {
459             if( CVS_UNLINK( tmpfile2 ) < 0 )
460             {
461                 if( !existence_error( errno ) )
462                     error( 0, errno, "cannot remove temp file %s", tmpfile2 );
463             }
464             free (tmpfile2);
465         }
466     }
467
468     return retval;
469 }
470
471
472
473 /* Show differences between two files.  This is the start of a diff library.
474
475    Some issues:
476
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).
487
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.
492
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.
500
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.  */
506
507 int
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)
511 {
512     TRACE (TRACE_FUNCTION, "diff_exec (%s, %s, %s, %s, %s)",
513            file1, file2, label1, label2, out);
514
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.
526
527        There may be ways around this, but I think they are fraught
528        with danger. -twp */
529
530     if (preserve_perms &&
531         strcmp (file1, DEVNULL) != 0 &&
532         strcmp (file2, DEVNULL) != 0)
533     {
534         struct stat sb1, sb2;
535
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);
540
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;
545     }
546 #endif
547
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);
557
558     return call_diff (out);
559 }
560
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. */
566
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)
571 {
572     int i;
573     
574     cvs_output ("diff", 0);
575     for (i = 0; i < diff_argc; i++)
576     {
577         cvs_output (" ", 1);
578         cvs_output (quotearg_style (shell_quoting_style, diff_argv[i]), 0);
579     }
580     cvs_output (" -r", 3);
581     cvs_output (rev1, 0);
582
583     if (rev2)
584     {
585         cvs_output (" -r", 3);
586         cvs_output (rev2, 0);
587     }
588     else
589     {
590         assert (workfile != NULL);
591         cvs_output (" ", 1);
592         cvs_output (workfile, 0);
593     }
594     cvs_output ("\n", 1);
595 }