Merge from vendor branch GCC:
[dragonfly.git] / contrib / cvs-1.12.12 / 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
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.
23
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:
28
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.
32
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.
39
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).
44
45    4.  To be useful for RCS and perhaps for other uses, the library
46    may need features beyond those needed by CVS.
47
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
53    file format.
54
55    On a related note, see the comments at diff_exec, later in this file,
56    for more on the diff library.  */
57
58 static void RCS_output_diff_options (const char *, const char *, const char *,
59                                      const char *);
60
61
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.  */
66
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.
70
71    Then, optionally, call call_diff_arg for each additional argument
72    that you'd like to pass to the diff library.
73
74    Finally, call call_diff or call_diff3 to produce the diffs.  */
75
76 static char **call_diff_argv;
77 static int call_diff_argc;
78 static int call_diff_argc_allocated;
79
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);
84
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 *);
89
90 /* VARARGS */
91 static void 
92 call_diff_setup (const char *prog)
93 {
94     char *cp;
95     int i;
96     char *call_diff_prog;
97
98     /* clean out any malloc'ed values from call_diff_argv */
99     for (i = 0; i < call_diff_argc; i++)
100     {
101         if (call_diff_argv[i])
102         {
103             free (call_diff_argv[i]);
104             call_diff_argv[i] = NULL;
105         }
106     }
107     call_diff_argc = 0;
108
109     call_diff_prog = xstrdup (prog);
110
111     /* put each word into call_diff_argv, allocating it as we go */
112     for (cp = strtok (call_diff_prog, " \t");
113          cp != NULL;
114          cp = strtok (NULL, " \t"))
115         call_diff_add_arg (cp);
116     free (call_diff_prog);
117 }
118
119 static void
120 call_diff_arg (const char *s)
121 {
122     call_diff_add_arg (s);
123 }
124
125 static void
126 call_diff_add_arg (const char *s)
127 {
128     /* allocate more argv entries if we've run out */
129     if (call_diff_argc >= call_diff_argc_allocated)
130     {
131         call_diff_argc_allocated += 50;
132         call_diff_argv = xnrealloc (call_diff_argv,
133                                     call_diff_argc_allocated,
134                                     sizeof (char **));
135     }
136
137     if (s)
138         call_diff_argv[call_diff_argc++] = xstrdup (s);
139     else
140         /* Not post-incremented on purpose!  */
141         call_diff_argv[call_diff_argc] = NULL;
142 }
143
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.  */
146
147 static void
148 call_diff_write_output (const char *text, size_t len)
149 {
150     if (len > 0)
151         cvs_output (text, len);
152 }
153
154 /* Call back function for the diff library to flush the output file.
155    This is used when we are producing output to stdout.  */
156
157 static void
158 call_diff_flush_output (void)
159 {
160     cvs_flushout ();
161 }
162
163 /* Call back function for the diff library to write to stdout.  */
164
165 static void
166 call_diff_write_stdout (const char *text)
167 {
168     cvs_output (text, 0);
169 }
170
171 /* Call back function for the diff library to write to stderr.  */
172
173 static void
174 call_diff_error (const char *format, const char *a1, const char *a2)
175 {
176     /* FIXME: Should we somehow indicate that this error is coming from
177        the diff library?  */
178     error (0, 0, format, a1, a2);
179 }
180
181 /* This set of callback functions is used if we are sending the diff
182    to stdout.  */
183
184 static struct diff_callbacks call_diff_stdout_callbacks =
185 {
186     call_diff_write_output,
187     call_diff_flush_output,
188     call_diff_write_stdout,
189     call_diff_error
190 };
191
192 /* This set of callback functions is used if we are sending the diff
193    to a file.  */
194
195 static struct diff_callbacks call_diff_file_callbacks =
196 {
197     NULL,
198     NULL,
199     call_diff_write_stdout,
200     call_diff_error
201 };
202
203
204
205 static int
206 call_diff (const char *out)
207 {
208     if (out == RUN_TTY)
209         return diff_run( call_diff_argc, call_diff_argv, NULL,
210                          &call_diff_stdout_callbacks );
211     else
212         return diff_run( call_diff_argc, call_diff_argv, out,
213                          &call_diff_file_callbacks );
214 }
215
216
217
218 static int
219 call_diff3 (char *out)
220 {
221     if (out == RUN_TTY)
222         return diff3_run (call_diff_argc, call_diff_argv, NULL,
223                           &call_diff_stdout_callbacks);
224     else
225         return diff3_run (call_diff_argc, call_diff_argv, out,
226                           &call_diff_file_callbacks);
227 }
228
229
230
231 /* Merge revisions REV1 and REV2. */
232
233 int
234 RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
235            const char *options, const char *rev1, const char *rev2)
236 {
237     char *xrev1, *xrev2;
238     char *tmp1, *tmp2;
239     char *diffout = NULL;
240     int retval;
241
242     if (options != NULL && options[0] != '\0')
243       assert (options[0] == '-' && options[1] == 'k');
244
245     cvs_output ("RCS file: ", 0);
246     cvs_output (rcs->print_path, 0);
247     cvs_output ("\n", 1);
248
249     /* Calculate numeric revision numbers from rev1 and rev2 (may be
250        symbolic).
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);
256
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);
263
264     tmp1 = cvs_temp_name();
265     if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
266     {
267         cvs_outerr ("rcsmerge: co failed\n", 0);
268         exit (EXIT_FAILURE);
269     }
270
271     cvs_output ("retrieving revision ", 0);
272     cvs_output (xrev2, 0);
273     cvs_output ("\n", 1);
274
275     tmp2 = cvs_temp_name();
276     if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
277     {
278         cvs_outerr ("rcsmerge: co failed\n", 0);
279         exit (EXIT_FAILURE);
280     }
281
282     /* Merge changes. */
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);
290
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");
297
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);
304
305     call_diff_arg ("--");
306     call_diff_arg (workfile);
307     call_diff_arg (tmp1);
308     call_diff_arg (tmp2);
309
310     retval = call_diff3 (diffout);
311
312     if (retval == 1)
313         cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
314     else if (retval == 2)
315         exit (EXIT_FAILURE);
316
317     if (diffout)
318         copy_file (diffout, workfile);
319
320     /* Clean up. */
321     {
322         int save_noexec = noexec;
323         noexec = 0;
324         if (unlink_file (tmp1) < 0)
325         {
326             if (!existence_error (errno))
327                 error (0, errno, "cannot remove temp file %s", tmp1);
328         }
329         free (tmp1);
330         if (unlink_file (tmp2) < 0)
331         {
332             if (!existence_error (errno))
333                 error (0, errno, "cannot remove temp file %s", tmp2);
334         }
335         free (tmp2);
336         if (diffout)
337         {
338             if (unlink_file (diffout) < 0)
339             {
340                 if (!existence_error (errno))
341                     error (0, errno, "cannot remove temp file %s", diffout);
342             }
343             free (diffout);
344         }
345         free (xrev1);
346         free (xrev2);
347         noexec = save_noexec;
348     }
349
350     return retval;
351 }
352
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.
362
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.
365
366    This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
367
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.  */
373 int
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)
377 {
378     char *tmpfile1 = NULL;
379     char *tmpfile2 = NULL;
380     const char *use_file1, *use_file2;
381     int status, retval;
382
383
384     cvs_output ("\
385 ===================================================================\n\
386 RCS file: ", 0);
387     cvs_output (rcsfile->print_path, 0);
388     cvs_output ("\n", 1);
389
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. */
395
396     cvs_output ("retrieving revision ", 0);
397     cvs_output (rev1, 0);
398     cvs_output ("\n", 1);
399
400     if (rev1_cache != NULL)
401         use_file1 = rev1_cache;
402     else
403     {
404         tmpfile1 = cvs_temp_name();
405         status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
406                                NULL, NULL);
407         if (status > 0)
408         {
409             retval = status;
410             goto error_return;
411         }
412         else if (status < 0)
413         {
414             error( 0, errno,
415                    "cannot check out revision %s of %s", rev1, rcsfile->path );
416             retval = 1;
417             goto error_return;
418         }
419         use_file1 = tmpfile1;
420     }
421
422     if (rev2 == NULL)
423     {
424         assert (workfile != NULL);
425         use_file2 = workfile;
426     }
427     else
428     {
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);
435         if (status > 0)
436         {
437             retval = status;
438             goto error_return;
439         }
440         else if (status < 0)
441         {
442             error (0, errno,
443                    "cannot check out revision %s of %s", rev2, rcsfile->path);
444             return 1;
445         }
446         use_file2 = tmpfile2;
447     }
448
449     RCS_output_diff_options (opts, rev1, rev2, workfile);
450     status = diff_exec( use_file1, use_file2, label1, label2, opts, RUN_TTY );
451     if (status >= 0)
452     {
453         retval = status;
454         goto error_return;
455     }
456     else if (status < 0)
457     {
458         error (0, errno,
459                "cannot diff %s and %s", use_file1, use_file2);
460         retval = 1;
461         goto error_return;
462     }
463
464  error_return:
465     {
466         /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
467          * for noexec.
468          */
469         if( tmpfile1 != NULL )
470         {
471             if( CVS_UNLINK( tmpfile1 ) < 0 )
472             {
473                 if( !existence_error( errno ) )
474                     error( 0, errno, "cannot remove temp file %s", tmpfile1 );
475             }
476             free( tmpfile1 );
477         }
478         if( tmpfile2 != NULL )
479         {
480             if( CVS_UNLINK( tmpfile2 ) < 0 )
481             {
482                 if( !existence_error( errno ) )
483                     error( 0, errno, "cannot remove temp file %s", tmpfile2 );
484             }
485             free (tmpfile2);
486         }
487     }
488
489     return retval;
490 }
491
492
493
494 /* Show differences between two files.  This is the start of a diff library.
495
496    Some issues:
497
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).
508
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.
513
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.
521
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.  */
527
528 int
529 diff_exec (const char *file1, const char *file2, const char *label1,
530            const char *label2, const char *options, const char *out)
531 {
532     char *args;
533
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
544        very rare anyway.
545
546        There may be ways around this, but I think they are fraught
547        with danger. -twp */
548
549     if (preserve_perms &&
550         strcmp (file1, DEVNULL) != 0 &&
551         strcmp (file2, DEVNULL) != 0)
552     {
553         struct stat sb1, sb2;
554
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);
559
560         if (!S_ISREG (sb1.st_mode) && !S_ISDIR (sb1.st_mode))
561             file1 = DEVNULL;
562         if (!S_ISREG (sb2.st_mode) && !S_ISDIR (sb2.st_mode))
563             file2 = DEVNULL;
564     }
565 #endif
566
567     /* The first word in this string is used only for error reporting. */
568     args = Xasprintf ("diff %s", options);
569     call_diff_setup (args);
570     if (label1)
571         call_diff_arg (label1);
572     if (label2)
573         call_diff_arg (label2);
574     call_diff_arg ("--");
575     call_diff_arg (file1);
576     call_diff_arg (file2);
577     free (args);
578
579     return call_diff (out);
580 }
581
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
586    that I have seen. */
587
588 static void
589 RCS_output_diff_options (const char *opts, const char *rev1, const char *rev2,
590                          const char *workfile)
591 {
592     char *tmp;
593
594     tmp = Xasprintf ("diff%s -r%s", opts, rev1);
595     cvs_output (tmp, 0);
596     free (tmp);
597
598     if (rev2)
599     {
600         cvs_output (" -r", 3);
601         cvs_output (rev2, 0);
602     }
603     else
604     {
605         assert (workfile != NULL);
606         cvs_output (" ", 1);
607         cvs_output (workfile, 0);
608     }
609     cvs_output ("\n", 1);
610 }