Annotation of src/usr.bin/cvs/diff.c, Revision 1.138
1.138 ! tobias 1: /* $OpenBSD: diff.c,v 1.137 2008/05/30 11:06:17 tobias Exp $ */
1.1 jfb 2: /*
1.136 tobias 3: * Copyright (c) 2008 Tobias Stoeckmann <tobias@openbsd.org>
1.91 joris 4: * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1 jfb 5: *
1.91 joris 6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 jfb 17: */
18:
1.118 otto 19: #include <sys/stat.h>
1.125 tobias 20: #include <sys/time.h>
1.118 otto 21:
22: #include <errno.h>
1.131 joris 23: #include <fcntl.h>
1.125 tobias 24: #include <stdlib.h>
1.118 otto 25: #include <string.h>
26: #include <unistd.h>
1.1 jfb 27:
28: #include "cvs.h"
1.56 niallo 29: #include "diff.h"
1.108 joris 30: #include "remote.h"
1.86 joris 31:
1.91 joris 32: void cvs_diff_local(struct cvs_file *);
1.46 xsa 33:
1.126 tobias 34: static int Nflag = 0;
35: static int force_head = 0;
36: static char *koptstr;
37: static char *rev1 = NULL;
38: static char *rev2 = NULL;
1.137 tobias 39: static time_t date1 = -1;
40: static time_t date2 = -1;
1.94 joris 41:
1.36 jfb 42: struct cvs_cmd cvs_cmd_diff = {
1.124 tobias 43: CVS_OP_DIFF, CVS_USE_WDIR, "diff",
1.36 jfb 44: { "di", "dif" },
45: "Show differences between revisions",
1.122 tobias 46: "[-cilNnpRu] [[-D date] [-r rev] [-D date2 | -r rev2]] "
1.43 xsa 47: "[-k mode] [file ...]",
1.126 tobias 48: "cfD:ik:lNnpr:Ru",
1.125 tobias 49: NULL,
50: cvs_diff
51: };
52:
53: struct cvs_cmd cvs_cmd_rdiff = {
54: CVS_OP_RDIFF, 0, "rdiff",
55: { "patch", "pa" },
56: "Show differences between revisions",
57: "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev\n"
58: "[-D date2 | -r rev2] [-k mode] module ...",
1.126 tobias 59: "cfD:k:lr:RuV:",
1.36 jfb 60: NULL,
1.91 joris 61: cvs_diff
1.36 jfb 62: };
63:
1.91 joris 64: int
65: cvs_diff(int argc, char **argv)
1.1 jfb 66: {
1.127 tobias 67: int ch, flags;
1.91 joris 68: char *arg = ".";
69: struct cvs_recursion cr;
1.1 jfb 70:
1.92 joris 71: flags = CR_RECURSE_DIRS;
1.128 tobias 72: strlcpy(diffargs, cvs_cmdop == CVS_OP_DIFF ? "diff" : "rdiff",
73: sizeof(diffargs));
1.1 jfb 74:
1.127 tobias 75: while ((ch = getopt(argc, argv, cvs_cmdop == CVS_OP_DIFF ?
76: cvs_cmd_diff.cmd_opts : cvs_cmd_rdiff.cmd_opts)) != -1) {
1.1 jfb 77: switch (ch) {
78: case 'c':
1.2 jfb 79: strlcat(diffargs, " -c", sizeof(diffargs));
1.58 niallo 80: diff_format = D_CONTEXT;
1.1 jfb 81: break;
1.137 tobias 82: case 'D':
83: if (date1 == -1 && rev1 == NULL) {
84: date1 = cvs_date_parse(optarg);
85: } else if (date2 == -1 && rev2 == NULL) {
86: date2 = cvs_date_parse(optarg);
87: } else {
88: fatal("no more than 2 revisions/dates can"
89: " be specified");
90: }
91: break;
1.125 tobias 92: case 'f':
93: force_head = 1;
94: break;
95: case 'i':
96: strlcat(diffargs, " -i", sizeof(diffargs));
97: diff_iflag = 1;
98: break;
1.126 tobias 99: case 'k':
100: koptstr = optarg;
101: kflag = rcs_kflag_get(koptstr);
1.132 deraadt 102: if (RCS_KWEXP_INVAL(kflag)) {
1.126 tobias 103: cvs_log(LP_ERR,
1.135 tobias 104: "invalid RCS keyword expansion mode");
1.133 tobias 105: fatal("%s", cvs_cmdop == CVS_OP_DIFF ?
106: cvs_cmd_diff.cmd_synopsis :
107: cvs_cmd_rdiff.cmd_synopsis);
1.126 tobias 108: }
109: break;
1.92 joris 110: case 'l':
111: flags &= ~CR_RECURSE_DIRS;
112: break;
1.33 jfb 113: case 'n':
114: strlcat(diffargs, " -n", sizeof(diffargs));
1.58 niallo 115: diff_format = D_RCSDIFF;
1.33 jfb 116: break;
1.94 joris 117: case 'N':
1.136 tobias 118: strlcat(diffargs, " -N", sizeof(diffargs));
1.95 joris 119: Nflag = 1;
1.94 joris 120: break;
1.101 joris 121: case 'p':
122: strlcat(diffargs, " -p", sizeof(diffargs));
123: diff_pflag = 1;
1.122 tobias 124: break;
125: case 'R':
126: flags |= CR_RECURSE_DIRS;
1.101 joris 127: break;
1.1 jfb 128: case 'r':
1.137 tobias 129: if (date1 == -1 && rev1 == NULL) {
1.97 joris 130: rev1 = optarg;
1.137 tobias 131: } else if (date2 == -1 && rev2 == NULL) {
1.97 joris 132: rev2 = optarg;
1.23 joris 133: } else {
1.91 joris 134: fatal("no more than 2 revisions/dates can"
135: " be specified");
1.1 jfb 136: }
1.32 joris 137: break;
1.1 jfb 138: case 'u':
1.2 jfb 139: strlcat(diffargs, " -u", sizeof(diffargs));
1.58 niallo 140: diff_format = D_UNIFIED;
1.1 jfb 141: break;
1.126 tobias 142: case 'V':
143: fatal("the -V option is obsolete "
144: "and should not be used");
1.1 jfb 145: default:
1.133 tobias 146: fatal("%s", cvs_cmdop == CVS_OP_DIFF ?
147: cvs_cmd_diff.cmd_synopsis :
148: cvs_cmd_rdiff.cmd_synopsis);
1.36 jfb 149: }
1.13 jfb 150: }
151:
1.91 joris 152: argc -= optind;
153: argv += optind;
1.1 jfb 154:
1.91 joris 155: cr.enterdir = NULL;
156: cr.leavedir = NULL;
1.108 joris 157:
1.125 tobias 158: if (cvs_cmdop == CVS_OP_RDIFF) {
159: if (rev1 == NULL)
160: fatal("must specify at least one revision/date!");
161:
1.136 tobias 162: if (!argc)
163: fatal("%s", cvs_cmd_rdiff.cmd_synopsis);
164:
1.125 tobias 165: if (!diff_format) {
166: strlcat(diffargs, " -c", sizeof(diffargs));
167: diff_format = D_CONTEXT;
168: }
169:
170: flags |= CR_REPO;
171: }
172:
1.108 joris 173: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
1.110 joris 174: cvs_client_connect_to_server();
1.108 joris 175: cr.fileproc = cvs_client_sendfile;
176:
177: if (!(flags & CR_RECURSE_DIRS))
178: cvs_client_send_request("Argument -l");
179:
1.126 tobias 180: if (kflag)
181: cvs_client_send_request("Argument -k%s", koptstr);
182:
1.108 joris 183: switch (diff_format) {
184: case D_CONTEXT:
185: cvs_client_send_request("Argument -c");
186: break;
187: case D_RCSDIFF:
188: cvs_client_send_request("Argument -n");
189: break;
190: case D_UNIFIED:
191: cvs_client_send_request("Argument -u");
192: break;
193: default:
194: break;
195: }
196:
197: if (Nflag == 1)
198: cvs_client_send_request("Argument -N");
199:
200: if (diff_pflag == 1)
201: cvs_client_send_request("Argument -p");
202:
203: if (rev1 != NULL)
204: cvs_client_send_request("Argument -r%s", rev1);
205: if (rev2 != NULL)
206: cvs_client_send_request("Argument -r%s", rev2);
207: } else {
1.125 tobias 208: if (cvs_cmdop == CVS_OP_RDIFF &&
209: chdir(current_cvsroot->cr_dir) == -1)
210: fatal("cvs_diff: %s", strerror(errno));
211:
1.108 joris 212: cr.fileproc = cvs_diff_local;
213: }
214:
1.92 joris 215: cr.flags = flags;
1.7 jfb 216:
1.97 joris 217: diff_rev1 = diff_rev2 = NULL;
218:
1.125 tobias 219: if (cvs_cmdop == CVS_OP_DIFF ||
220: current_cvsroot->cr_method == CVS_METHOD_LOCAL) {
221: if (argc > 0)
222: cvs_file_run(argc, argv, &cr);
223: else
224: cvs_file_run(1, &arg, &cr);
225: }
1.108 joris 226:
227: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
228: cvs_client_send_files(argv, argc);
229: cvs_client_senddir(".");
1.125 tobias 230:
231: cvs_client_send_request((cvs_cmdop == CVS_OP_RDIFF) ?
232: "rdiff" : "diff");
233:
1.108 joris 234: cvs_client_get_responses();
235: }
1.36 jfb 236:
237: return (0);
238: }
239:
1.91 joris 240: void
241: cvs_diff_local(struct cvs_file *cf)
1.36 jfb 242: {
1.114 joris 243: BUF *b1;
1.131 joris 244: int fd1, fd2;
1.91 joris 245: struct stat st;
1.69 niallo 246: struct timeval tv[2], tv2[2];
1.137 tobias 247: struct tm *datetm;
248: char rbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ], *p1, *p2;
1.111 xsa 249:
1.114 joris 250: b1 = NULL;
1.136 tobias 251: fd1 = fd2 = -1;
252: p1 = p2 = NULL;
1.69 niallo 253:
1.91 joris 254: cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path);
1.1 jfb 255:
1.91 joris 256: if (cf->file_type == CVS_DIR) {
1.46 xsa 257: if (verbosity > 1)
1.91 joris 258: cvs_log(LP_NOTICE, "Diffing inside %s", cf->file_path);
1.1 jfb 259: return;
260: }
261:
1.121 joris 262: cvs_file_classify(cf, cvs_directory_tag);
1.1 jfb 263:
1.136 tobias 264: if (cvs_cmdop == CVS_OP_DIFF) {
265: if (cf->file_ent == NULL) {
266: cvs_log(LP_ERR, "I know nothing about %s",
267: cf->file_path);
268: return;
269: }
1.126 tobias 270:
1.136 tobias 271: switch (cf->file_ent->ce_status) {
272: case CVS_ENT_ADDED:
273: if (Nflag == 0) {
274: cvs_log(LP_ERR, "%s is a new entry, no "
275: "comparison available", cf->file_path);
1.125 tobias 276: return;
277: }
1.136 tobias 278: if (cf->fd == -1) {
1.138 ! tobias 279: if (!cvs_server_active)
! 280: cvs_log(LP_ERR, "cannot find %s",
! 281: cf->file_path);
1.136 tobias 282: return;
1.125 tobias 283: }
1.136 tobias 284: break;
285: case CVS_ENT_REMOVED:
286: if (Nflag == 0) {
287: cvs_log(LP_ERR, "%s was removed, no "
288: "comparison available", cf->file_path);
1.125 tobias 289: return;
290: }
1.136 tobias 291: if (cf->file_rcs == NULL) {
292: cvs_log(LP_ERR, "cannot find RCS file for %s",
293: cf->file_path);
294: return;
1.125 tobias 295: }
1.136 tobias 296: break;
297: default:
298: if (cf->fd == -1) {
1.138 ! tobias 299: if (!cvs_server_active)
! 300: cvs_log(LP_ERR, "cannot find %s",
! 301: cf->file_path);
1.136 tobias 302: return;
303: }
304: if (cf->file_rcs == NULL) {
305: cvs_log(LP_ERR, "cannot find RCS file for %s",
306: cf->file_path);
307: return;
308: }
309: break;
1.123 tobias 310: }
1.136 tobias 311: }
1.1 jfb 312:
1.137 tobias 313: if (cf->file_status == FILE_UPTODATE && rev1 == NULL && rev2 == NULL &&
314: date1 == -1 && date2 == -1)
1.125 tobias 315: return;
316:
1.136 tobias 317: if (kflag && cf->file_rcs != NULL)
318: rcs_kwexp_set(cf->file_rcs, kflag);
1.125 tobias 319:
1.136 tobias 320: if (cf->file_rcs == NULL)
321: diff_rev1 = NULL;
1.137 tobias 322: else if (rev1 != NULL || date1 != -1) {
323: cvs_specified_date = date1;
1.136 tobias 324: diff_rev1 = rcs_translate_tag(rev1, cf->file_rcs);
325: if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_DIFF) {
1.137 tobias 326: if (rev1 != NULL)
327: cvs_log(LP_ERR, "tag %s not in file %s", rev1,
328: cf->file_path);
329: else {
330: datetm = gmtime(&cvs_specified_date);
331: strftime(tbuf, sizeof(tbuf),
332: "%Y.%m.%d.%H.%M.%S", datetm);
333: cvs_log(LP_ERR, "no revision for date %s in "
334: "file %s", tbuf, cf->file_path);
335: }
1.136 tobias 336: goto cleanup;
337: } else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF &&
338: force_head) {
339: /* -f is not allowed for unknown symbols */
340: if ((diff_rev1 = rcsnum_parse(rev1)) == NULL)
341: fatal("no such tag %s", rev1);
342: rcsnum_free(diff_rev1);
1.1 jfb 343:
1.136 tobias 344: diff_rev1 = cf->file_rcs->rf_head;
345: }
1.137 tobias 346: cvs_specified_date = -1;
1.136 tobias 347: } else if (cvs_cmdop == CVS_OP_DIFF) {
348: if (cf->file_ent->ce_status == CVS_ENT_ADDED)
349: diff_rev1 = NULL;
1.94 joris 350: else
1.136 tobias 351: diff_rev1 = cf->file_ent->ce_rev;
352: }
1.1 jfb 353:
1.136 tobias 354: if (cf->file_rcs == NULL)
355: diff_rev2 = NULL;
1.137 tobias 356: else if (rev2 != NULL || date2 != -1) {
357: cvs_specified_date = date2;
1.136 tobias 358: diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs);
359: if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) {
1.137 tobias 360: if (rev2 != NULL) {
361: cvs_log(LP_ERR, "tag %s not in file %s", rev2,
362: cf->file_path);
363: } else {
364: datetm = gmtime(&cvs_specified_date);
365: strftime(tbuf, sizeof(tbuf),
366: "%Y.%m.%d.%H.%M.%S", datetm);
367: cvs_log(LP_ERR, "no revision for date %s in "
368: "file %s", tbuf, cf->file_path);
369: }
1.136 tobias 370: goto cleanup;
371: } else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF &&
372: force_head) {
373: /* -f is not allowed for unknown symbols */
374: if ((diff_rev2 = rcsnum_parse(rev2)) == NULL)
375: fatal("no such tag %s", rev2);
376: rcsnum_free(diff_rev2);
1.91 joris 377:
1.136 tobias 378: diff_rev2 = cf->file_rcs->rf_head;
379: }
1.137 tobias 380: cvs_specified_date = -1;
1.136 tobias 381: } else if (cvs_cmdop == CVS_OP_RDIFF)
382: diff_rev2 = cf->file_rcs->rf_head;
383: else if (cf->file_ent->ce_status == CVS_ENT_REMOVED)
384: diff_rev2 = NULL;
1.114 joris 385:
1.136 tobias 386: if (diff_rev1 != NULL && diff_rev2 != NULL &&
387: rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0)
388: goto cleanup;
1.125 tobias 389:
1.136 tobias 390: switch (cvs_cmdop) {
391: case CVS_OP_DIFF:
392: if (cf->file_status == FILE_UPTODATE &&
393: rcsnum_cmp(diff_rev1, cf->file_rcsrev, 0) == 0)
394: goto cleanup;
395: break;
396: case CVS_OP_RDIFF:
397: if (diff_rev1 == NULL && diff_rev2 == NULL)
398: goto cleanup;
399: break;
400: }
401:
402: cvs_printf("Index: %s\n", cf->file_path);
403: if (cvs_cmdop == CVS_OP_DIFF)
404: cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV,
405: cf->file_rcs != NULL ? cf->file_rpath : cf->file_path);
406:
407: if (diff_rev1 != NULL) {
408: if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) {
409: (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
410: cvs_printf("retrieving revision %s\n", rbuf);
1.125 tobias 411: }
1.136 tobias 412:
413: tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1);
414: tv[0].tv_usec = 0;
415: tv[1] = tv[0];
416:
417: (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
418: fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0);
419: if (futimes(fd1, tv) == -1)
420: fatal("cvs_diff_local: utimes failed");
1.94 joris 421: }
1.91 joris 422:
1.136 tobias 423: if (diff_rev2 != NULL) {
424: if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) {
425: (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf));
426: cvs_printf("retrieving revision %s\n", rbuf);
427: }
1.91 joris 428:
429: tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2);
430: tv2[0].tv_usec = 0;
431: tv2[1] = tv2[0];
1.114 joris 432:
1.136 tobias 433: (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
1.131 joris 434: fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0);
435: if (futimes(fd2, tv2) == -1)
1.125 tobias 436: fatal("cvs_diff_local: utimes failed");
1.136 tobias 437: } else if (cvs_cmdop == CVS_OP_DIFF && cf->fd != -1 &&
438: cf->file_ent->ce_status != CVS_ENT_REMOVED) {
439: if (fstat(cf->fd, &st) == -1)
440: fatal("fstat failed %s", strerror(errno));
441: b1 = cvs_buf_load_fd(cf->fd);
1.125 tobias 442:
1.136 tobias 443: tv2[0].tv_sec = st.st_mtime;
444: tv2[0].tv_usec = 0;
445: tv2[1] = tv2[0];
1.121 joris 446:
1.136 tobias 447: (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
448: fd2 = cvs_buf_write_stmp(b1, p2, tv2);
449: cvs_buf_free(b1);
1.17 jfb 450: }
451:
1.136 tobias 452: switch (cvs_cmdop) {
453: case CVS_OP_DIFF:
1.125 tobias 454: cvs_printf("%s", diffargs);
455:
1.136 tobias 456: if (rev1 != NULL && diff_rev1 != NULL) {
457: (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
1.125 tobias 458: cvs_printf(" -r%s", rbuf);
459:
1.136 tobias 460: if (rev2 != NULL && diff_rev2 != NULL) {
1.125 tobias 461: (void)rcsnum_tostr(diff_rev2, rbuf,
462: sizeof(rbuf));
463: cvs_printf(" -r%s", rbuf);
464: }
465: }
1.1 jfb 466:
1.125 tobias 467: if (diff_rev2 == NULL)
1.136 tobias 468: cvs_printf(" %s", cf->file_path);
1.130 tobias 469: cvs_printf("\n");
1.136 tobias 470: break;
471: case CVS_OP_RDIFF:
1.125 tobias 472: cvs_printf("diff ");
473: switch (diff_format) {
474: case D_CONTEXT:
475: cvs_printf("-c ");
476: break;
477: case D_RCSDIFF:
478: cvs_printf("-n ");
479: break;
480: case D_UNIFIED:
481: cvs_printf("-u ");
482: break;
483: default:
484: break;
485: }
486: if (diff_rev1 == NULL) {
487: cvs_printf("%s ", CVS_PATH_DEVNULL);
488: } else {
489: (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
490: cvs_printf("%s:%s ", cf->file_path, rbuf);
491: }
1.1 jfb 492:
1.125 tobias 493: if (diff_rev2 == NULL) {
494: cvs_printf("%s:removed\n", cf->file_path);
495: } else {
496: (void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 :
497: cf->file_rcs->rf_head, rbuf, sizeof(rbuf));
498: cvs_printf("%s:%s\n", cf->file_path, rbuf);
1.94 joris 499: }
1.136 tobias 500: break;
1.1 jfb 501: }
502:
1.136 tobias 503: if (fd1 == -1) {
504: if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1)
505: fatal("cannot open %s", CVS_PATH_DEVNULL);
1.114 joris 506: }
1.136 tobias 507: if (fd2 == -1) {
508: if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1)
509: fatal("cannot open %s", CVS_PATH_DEVNULL);
510: }
1.111 xsa 511:
1.136 tobias 512: if (cvs_diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL,
513: p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL)
514: == D_ERROR)
1.111 xsa 515: fatal("cvs_diff_local: failed to get RCS patch");
1.131 joris 516:
517: close(fd1);
518: close(fd2);
1.58 niallo 519:
1.91 joris 520: cvs_worklist_run(&temp_files, cvs_worklist_unlink);
1.111 xsa 521:
522: if (p1 != NULL)
523: xfree(p1);
524: if (p2 != NULL)
525: xfree(p2);
1.101 joris 526:
1.136 tobias 527: cleanup:
528: if (diff_rev1 != NULL &&
529: (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) &&
530: (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev))
531: xfree(diff_rev1);
532: diff_rev1 = NULL;
1.94 joris 533:
1.136 tobias 534: if (diff_rev2 != NULL &&
535: (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head))
536: xfree(diff_rev2);
537: diff_rev2 = NULL;
1.1 jfb 538: }