Annotation of src/usr.bin/cvs/diff.c, Revision 1.163
1.163 ! joris 1: /* $OpenBSD: diff.c,v 1.162 2016/10/13 20:51:25 fcambus 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>
1.139 tobias 26: #include <time.h>
1.118 otto 27: #include <unistd.h>
1.1 jfb 28:
29: #include "cvs.h"
1.56 niallo 30: #include "diff.h"
1.108 joris 31: #include "remote.h"
1.86 joris 32:
1.91 joris 33: void cvs_diff_local(struct cvs_file *);
1.46 xsa 34:
1.154 ray 35: static int dflags = 0;
1.126 tobias 36: static int Nflag = 0;
37: static int force_head = 0;
38: static char *koptstr;
39: static char *rev1 = NULL;
40: static char *rev2 = NULL;
1.137 tobias 41: static time_t date1 = -1;
42: static time_t date2 = -1;
1.144 tobias 43: static char *dateflag1 = NULL;
44: static char *dateflag2 = NULL;
1.94 joris 45:
1.36 jfb 46: struct cvs_cmd cvs_cmd_diff = {
1.124 tobias 47: CVS_OP_DIFF, CVS_USE_WDIR, "diff",
1.36 jfb 48: { "di", "dif" },
49: "Show differences between revisions",
1.152 sthen 50: "[-abcdilNnpRuw] [[-D date] [-r rev] [-D date2 | -r rev2]] "
1.43 xsa 51: "[-k mode] [file ...]",
1.158 nicm 52: "abcfC:dD:ik:lNnpr:RuU:w",
1.125 tobias 53: NULL,
54: cvs_diff
55: };
56:
57: struct cvs_cmd cvs_cmd_rdiff = {
58: CVS_OP_RDIFF, 0, "rdiff",
59: { "patch", "pa" },
60: "Show differences between revisions",
61: "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev\n"
62: "[-D date2 | -r rev2] [-k mode] module ...",
1.126 tobias 63: "cfD:k:lr:RuV:",
1.36 jfb 64: NULL,
1.91 joris 65: cvs_diff
1.36 jfb 66: };
67:
1.91 joris 68: int
69: cvs_diff(int argc, char **argv)
1.1 jfb 70: {
1.127 tobias 71: int ch, flags;
1.91 joris 72: char *arg = ".";
1.158 nicm 73: const char *errstr;
1.91 joris 74: struct cvs_recursion cr;
1.1 jfb 75:
1.92 joris 76: flags = CR_RECURSE_DIRS;
1.128 tobias 77: strlcpy(diffargs, cvs_cmdop == CVS_OP_DIFF ? "diff" : "rdiff",
78: sizeof(diffargs));
1.1 jfb 79:
1.127 tobias 80: while ((ch = getopt(argc, argv, cvs_cmdop == CVS_OP_DIFF ?
81: cvs_cmd_diff.cmd_opts : cvs_cmd_rdiff.cmd_opts)) != -1) {
1.1 jfb 82: switch (ch) {
1.152 sthen 83: case 'a':
84: strlcat(diffargs, " -a", sizeof(diffargs));
1.154 ray 85: dflags |= D_FORCEASCII;
1.152 sthen 86: break;
87: case 'b':
88: strlcat(diffargs, " -b", sizeof(diffargs));
1.154 ray 89: dflags |= D_FOLDBLANKS;
1.152 sthen 90: break;
1.1 jfb 91: case 'c':
1.2 jfb 92: strlcat(diffargs, " -c", sizeof(diffargs));
1.58 niallo 93: diff_format = D_CONTEXT;
1.1 jfb 94: break;
1.158 nicm 95: case 'C':
96: diff_context = strtonum(optarg, 0, INT_MAX, &errstr);
97: if (errstr != NULL)
98: fatal("context lines %s: %s", errstr, optarg);
99: strlcat(diffargs, " -C ", sizeof(diffargs));
100: strlcat(diffargs, optarg, sizeof(diffargs));
101: diff_format = D_CONTEXT;
102: break;
1.152 sthen 103: case 'd':
104: strlcat(diffargs, " -d", sizeof(diffargs));
1.154 ray 105: dflags |= D_MINIMAL;
1.152 sthen 106: break;
1.137 tobias 107: case 'D':
108: if (date1 == -1 && rev1 == NULL) {
1.159 ray 109: if ((date1 = date_parse(optarg)) == -1)
110: fatal("invalid date: %s", optarg);
1.144 tobias 111: dateflag1 = optarg;
1.137 tobias 112: } else if (date2 == -1 && rev2 == NULL) {
1.159 ray 113: if ((date2 = date_parse(optarg)) == -1)
114: fatal("invalid date: %s", optarg);
1.144 tobias 115: dateflag2 = optarg;
1.137 tobias 116: } else {
117: fatal("no more than 2 revisions/dates can"
118: " be specified");
119: }
120: break;
1.125 tobias 121: case 'f':
122: force_head = 1;
123: break;
124: case 'i':
125: strlcat(diffargs, " -i", sizeof(diffargs));
1.154 ray 126: dflags |= D_IGNORECASE;
1.125 tobias 127: break;
1.126 tobias 128: case 'k':
129: koptstr = optarg;
130: kflag = rcs_kflag_get(koptstr);
1.132 deraadt 131: if (RCS_KWEXP_INVAL(kflag)) {
1.126 tobias 132: cvs_log(LP_ERR,
1.135 tobias 133: "invalid RCS keyword expansion mode");
1.133 tobias 134: fatal("%s", cvs_cmdop == CVS_OP_DIFF ?
135: cvs_cmd_diff.cmd_synopsis :
136: cvs_cmd_rdiff.cmd_synopsis);
1.126 tobias 137: }
138: break;
1.92 joris 139: case 'l':
140: flags &= ~CR_RECURSE_DIRS;
141: break;
1.33 jfb 142: case 'n':
143: strlcat(diffargs, " -n", sizeof(diffargs));
1.58 niallo 144: diff_format = D_RCSDIFF;
1.33 jfb 145: break;
1.94 joris 146: case 'N':
1.136 tobias 147: strlcat(diffargs, " -N", sizeof(diffargs));
1.95 joris 148: Nflag = 1;
1.94 joris 149: break;
1.101 joris 150: case 'p':
151: strlcat(diffargs, " -p", sizeof(diffargs));
1.154 ray 152: dflags |= D_PROTOTYPE;
1.122 tobias 153: break;
154: case 'R':
155: flags |= CR_RECURSE_DIRS;
1.101 joris 156: break;
1.1 jfb 157: case 'r':
1.137 tobias 158: if (date1 == -1 && rev1 == NULL) {
1.97 joris 159: rev1 = optarg;
1.137 tobias 160: } else if (date2 == -1 && rev2 == NULL) {
1.97 joris 161: rev2 = optarg;
1.23 joris 162: } else {
1.91 joris 163: fatal("no more than 2 revisions/dates can"
164: " be specified");
1.1 jfb 165: }
1.32 joris 166: break;
1.154 ray 167: case 't':
168: strlcat(diffargs, " -t", sizeof(diffargs));
169: dflags |= D_EXPANDTABS;
170: break;
1.1 jfb 171: case 'u':
1.2 jfb 172: strlcat(diffargs, " -u", sizeof(diffargs));
1.58 niallo 173: diff_format = D_UNIFIED;
1.1 jfb 174: break;
1.158 nicm 175: case 'U':
176: diff_context = strtonum(optarg, 0, INT_MAX, &errstr);
177: if (errstr != NULL)
178: fatal("context lines %s: %s", errstr, optarg);
179: strlcat(diffargs, " -U ", sizeof(diffargs));
180: strlcat(diffargs, optarg, sizeof(diffargs));
181: diff_format = D_UNIFIED;
182: break;
1.126 tobias 183: case 'V':
184: fatal("the -V option is obsolete "
185: "and should not be used");
1.152 sthen 186: case 'w':
187: strlcat(diffargs, " -w", sizeof(diffargs));
1.154 ray 188: dflags |= D_IGNOREBLANKS;
1.152 sthen 189: break;
1.1 jfb 190: default:
1.133 tobias 191: fatal("%s", cvs_cmdop == CVS_OP_DIFF ?
192: cvs_cmd_diff.cmd_synopsis :
193: cvs_cmd_rdiff.cmd_synopsis);
1.36 jfb 194: }
1.13 jfb 195: }
196:
1.91 joris 197: argc -= optind;
198: argv += optind;
1.1 jfb 199:
1.91 joris 200: cr.enterdir = NULL;
201: cr.leavedir = NULL;
1.108 joris 202:
1.125 tobias 203: if (cvs_cmdop == CVS_OP_RDIFF) {
1.144 tobias 204: if (rev1 == NULL && rev2 == NULL && dateflag1 == NULL &&
205: dateflag2 == NULL)
1.125 tobias 206: fatal("must specify at least one revision/date!");
207:
1.136 tobias 208: if (!argc)
209: fatal("%s", cvs_cmd_rdiff.cmd_synopsis);
210:
1.125 tobias 211: if (!diff_format) {
212: strlcat(diffargs, " -c", sizeof(diffargs));
213: diff_format = D_CONTEXT;
214: }
215:
216: flags |= CR_REPO;
217: }
218:
1.163 ! joris 219: if (cvsroot_is_remote()) {
1.110 joris 220: cvs_client_connect_to_server();
1.108 joris 221: cr.fileproc = cvs_client_sendfile;
222:
223: if (!(flags & CR_RECURSE_DIRS))
224: cvs_client_send_request("Argument -l");
225:
1.126 tobias 226: if (kflag)
227: cvs_client_send_request("Argument -k%s", koptstr);
228:
1.108 joris 229: switch (diff_format) {
230: case D_CONTEXT:
1.158 nicm 231: if (cvs_cmdop == CVS_OP_RDIFF)
232: cvs_client_send_request("Argument -c");
233: else {
234: cvs_client_send_request("Argument -C %d",
235: diff_context);
236: }
1.108 joris 237: break;
238: case D_RCSDIFF:
239: cvs_client_send_request("Argument -n");
240: break;
241: case D_UNIFIED:
1.160 nicm 242: if (cvs_cmdop == CVS_OP_RDIFF || diff_context == 3)
1.158 nicm 243: cvs_client_send_request("Argument -u");
244: else {
245: cvs_client_send_request("Argument -U %d",
246: diff_context);
247: }
1.108 joris 248: break;
249: default:
250: break;
251: }
252:
253: if (Nflag == 1)
254: cvs_client_send_request("Argument -N");
255:
1.154 ray 256: if (dflags & D_PROTOTYPE)
1.108 joris 257: cvs_client_send_request("Argument -p");
258:
259: if (rev1 != NULL)
260: cvs_client_send_request("Argument -r%s", rev1);
261: if (rev2 != NULL)
262: cvs_client_send_request("Argument -r%s", rev2);
1.144 tobias 263:
264: if (dateflag1 != NULL)
265: cvs_client_send_request("Argument -D%s", dateflag1);
266: if (dateflag2 != NULL)
267: cvs_client_send_request("Argument -D%s", dateflag2);
1.108 joris 268: } else {
1.125 tobias 269: if (cvs_cmdop == CVS_OP_RDIFF &&
270: chdir(current_cvsroot->cr_dir) == -1)
271: fatal("cvs_diff: %s", strerror(errno));
272:
1.108 joris 273: cr.fileproc = cvs_diff_local;
274: }
275:
1.92 joris 276: cr.flags = flags;
1.7 jfb 277:
1.97 joris 278: diff_rev1 = diff_rev2 = NULL;
279:
1.163 ! joris 280: if (cvs_cmdop == CVS_OP_DIFF || cvsroot_is_local()) {
1.125 tobias 281: if (argc > 0)
282: cvs_file_run(argc, argv, &cr);
283: else
284: cvs_file_run(1, &arg, &cr);
285: }
1.108 joris 286:
1.163 ! joris 287: if (cvsroot_is_remote()) {
1.108 joris 288: cvs_client_send_files(argv, argc);
289: cvs_client_senddir(".");
1.125 tobias 290:
291: cvs_client_send_request((cvs_cmdop == CVS_OP_RDIFF) ?
292: "rdiff" : "diff");
293:
1.108 joris 294: cvs_client_get_responses();
295: }
1.36 jfb 296:
297: return (0);
298: }
299:
1.91 joris 300: void
301: cvs_diff_local(struct cvs_file *cf)
1.36 jfb 302: {
1.114 joris 303: BUF *b1;
1.131 joris 304: int fd1, fd2;
1.91 joris 305: struct stat st;
1.69 niallo 306: struct timeval tv[2], tv2[2];
1.139 tobias 307: struct tm datetm;
1.137 tobias 308: char rbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ], *p1, *p2;
1.111 xsa 309:
1.114 joris 310: b1 = NULL;
1.136 tobias 311: fd1 = fd2 = -1;
312: p1 = p2 = NULL;
1.69 niallo 313:
1.91 joris 314: cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path);
1.1 jfb 315:
1.91 joris 316: if (cf->file_type == CVS_DIR) {
1.46 xsa 317: if (verbosity > 1)
1.147 joris 318: cvs_log(LP_ERR, "Diffing inside %s", cf->file_path);
1.1 jfb 319: return;
320: }
321:
1.121 joris 322: cvs_file_classify(cf, cvs_directory_tag);
1.1 jfb 323:
1.136 tobias 324: if (cvs_cmdop == CVS_OP_DIFF) {
325: if (cf->file_ent == NULL) {
326: cvs_log(LP_ERR, "I know nothing about %s",
327: cf->file_path);
328: return;
329: }
1.126 tobias 330:
1.136 tobias 331: switch (cf->file_ent->ce_status) {
332: case CVS_ENT_ADDED:
333: if (Nflag == 0) {
334: cvs_log(LP_ERR, "%s is a new entry, no "
335: "comparison available", cf->file_path);
1.125 tobias 336: return;
337: }
1.145 joris 338: if (!(cf->file_flags & FILE_ON_DISK)) {
339: cvs_log(LP_ERR, "cannot find %s",
340: cf->file_path);
1.136 tobias 341: return;
1.125 tobias 342: }
1.136 tobias 343: break;
344: case CVS_ENT_REMOVED:
345: if (Nflag == 0) {
346: cvs_log(LP_ERR, "%s was removed, no "
347: "comparison available", cf->file_path);
1.125 tobias 348: return;
349: }
1.136 tobias 350: if (cf->file_rcs == NULL) {
351: cvs_log(LP_ERR, "cannot find RCS file for %s",
352: cf->file_path);
353: return;
1.125 tobias 354: }
1.136 tobias 355: break;
356: default:
1.145 joris 357: if (!(cf->file_flags & FILE_ON_DISK)) {
1.147 joris 358: cvs_printf("? %s\n", cf->file_path);
1.136 tobias 359: return;
360: }
1.140 joris 361:
1.136 tobias 362: if (cf->file_rcs == NULL) {
363: cvs_log(LP_ERR, "cannot find RCS file for %s",
364: cf->file_path);
365: return;
366: }
367: break;
1.123 tobias 368: }
1.136 tobias 369: }
1.1 jfb 370:
1.137 tobias 371: if (cf->file_status == FILE_UPTODATE && rev1 == NULL && rev2 == NULL &&
372: date1 == -1 && date2 == -1)
1.146 joris 373: return;
374:
1.142 joris 375: if (cf->file_rcs != NULL && cf->file_rcs->rf_head == NULL) {
1.141 tobias 376: cvs_log(LP_ERR, "no head revision in RCS file for %s\n",
377: cf->file_path);
378: return;
379: }
1.125 tobias 380:
1.136 tobias 381: if (kflag && cf->file_rcs != NULL)
382: rcs_kwexp_set(cf->file_rcs, kflag);
1.125 tobias 383:
1.136 tobias 384: if (cf->file_rcs == NULL)
385: diff_rev1 = NULL;
1.137 tobias 386: else if (rev1 != NULL || date1 != -1) {
387: cvs_specified_date = date1;
1.136 tobias 388: diff_rev1 = rcs_translate_tag(rev1, cf->file_rcs);
389: if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_DIFF) {
1.143 tobias 390: if (rev1 != NULL) {
1.137 tobias 391: cvs_log(LP_ERR, "tag %s not in file %s", rev1,
392: cf->file_path);
1.143 tobias 393: goto cleanup;
394: } else if (Nflag) {
395: diff_rev1 = NULL;
396: } else {
1.139 tobias 397: gmtime_r(&cvs_specified_date, &datetm);
1.137 tobias 398: strftime(tbuf, sizeof(tbuf),
1.139 tobias 399: "%Y.%m.%d.%H.%M.%S", &datetm);
1.137 tobias 400: cvs_log(LP_ERR, "no revision for date %s in "
401: "file %s", tbuf, cf->file_path);
1.143 tobias 402: goto cleanup;
1.137 tobias 403: }
1.136 tobias 404: } else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF &&
405: force_head) {
406: /* -f is not allowed for unknown symbols */
407: if ((diff_rev1 = rcsnum_parse(rev1)) == NULL)
408: fatal("no such tag %s", rev1);
1.162 fcambus 409: free(diff_rev1);
1.1 jfb 410:
1.136 tobias 411: diff_rev1 = cf->file_rcs->rf_head;
412: }
1.137 tobias 413: cvs_specified_date = -1;
1.136 tobias 414: } else if (cvs_cmdop == CVS_OP_DIFF) {
415: if (cf->file_ent->ce_status == CVS_ENT_ADDED)
416: diff_rev1 = NULL;
1.94 joris 417: else
1.136 tobias 418: diff_rev1 = cf->file_ent->ce_rev;
419: }
1.1 jfb 420:
1.136 tobias 421: if (cf->file_rcs == NULL)
422: diff_rev2 = NULL;
1.137 tobias 423: else if (rev2 != NULL || date2 != -1) {
424: cvs_specified_date = date2;
1.136 tobias 425: diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs);
426: if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) {
1.137 tobias 427: if (rev2 != NULL) {
428: cvs_log(LP_ERR, "tag %s not in file %s", rev2,
429: cf->file_path);
1.143 tobias 430: goto cleanup;
431: } else if (Nflag) {
432: diff_rev2 = NULL;
1.137 tobias 433: } else {
1.139 tobias 434: gmtime_r(&cvs_specified_date, &datetm);
1.137 tobias 435: strftime(tbuf, sizeof(tbuf),
1.139 tobias 436: "%Y.%m.%d.%H.%M.%S", &datetm);
1.137 tobias 437: cvs_log(LP_ERR, "no revision for date %s in "
438: "file %s", tbuf, cf->file_path);
1.143 tobias 439: goto cleanup;
1.137 tobias 440: }
1.136 tobias 441: } else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF &&
442: force_head) {
443: /* -f is not allowed for unknown symbols */
444: if ((diff_rev2 = rcsnum_parse(rev2)) == NULL)
445: fatal("no such tag %s", rev2);
1.162 fcambus 446: free(diff_rev2);
1.91 joris 447:
1.136 tobias 448: diff_rev2 = cf->file_rcs->rf_head;
449: }
1.137 tobias 450: cvs_specified_date = -1;
1.136 tobias 451: } else if (cvs_cmdop == CVS_OP_RDIFF)
452: diff_rev2 = cf->file_rcs->rf_head;
453: else if (cf->file_ent->ce_status == CVS_ENT_REMOVED)
454: diff_rev2 = NULL;
1.114 joris 455:
1.136 tobias 456: if (diff_rev1 != NULL && diff_rev2 != NULL &&
457: rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0)
458: goto cleanup;
1.125 tobias 459:
1.136 tobias 460: switch (cvs_cmdop) {
461: case CVS_OP_DIFF:
1.151 joris 462: if (cf->file_status == FILE_UPTODATE) {
463: if (diff_rev2 == NULL &&
464: !rcsnum_cmp(diff_rev1, cf->file_rcsrev, 0))
465: goto cleanup;
466: }
1.136 tobias 467: break;
468: case CVS_OP_RDIFF:
469: if (diff_rev1 == NULL && diff_rev2 == NULL)
470: goto cleanup;
471: break;
472: }
473:
474: cvs_printf("Index: %s\n", cf->file_path);
475: if (cvs_cmdop == CVS_OP_DIFF)
476: cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV,
477: cf->file_rcs != NULL ? cf->file_rpath : cf->file_path);
478:
479: if (diff_rev1 != NULL) {
480: if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) {
481: (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
482: cvs_printf("retrieving revision %s\n", rbuf);
1.125 tobias 483: }
1.136 tobias 484:
485: tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1);
486: tv[0].tv_usec = 0;
487: tv[1] = tv[0];
488:
489: (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
490: fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0);
491: if (futimes(fd1, tv) == -1)
492: fatal("cvs_diff_local: utimes failed");
1.94 joris 493: }
1.91 joris 494:
1.136 tobias 495: if (diff_rev2 != NULL) {
496: if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) {
497: (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf));
498: cvs_printf("retrieving revision %s\n", rbuf);
499: }
1.91 joris 500:
501: tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2);
502: tv2[0].tv_usec = 0;
503: tv2[1] = tv2[0];
1.114 joris 504:
1.136 tobias 505: (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
1.131 joris 506: fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0);
507: if (futimes(fd2, tv2) == -1)
1.125 tobias 508: fatal("cvs_diff_local: utimes failed");
1.145 joris 509: } else if (cvs_cmdop == CVS_OP_DIFF &&
510: (cf->file_flags & FILE_ON_DISK) &&
1.136 tobias 511: cf->file_ent->ce_status != CVS_ENT_REMOVED) {
1.149 joris 512: (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
513: if (cvs_server_active == 1 && cf->fd == -1) {
514: tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs,
515: cf->file_ent->ce_rev);
516: tv2[0].tv_usec = 0;
517: tv2[1] = tv2[0];
1.125 tobias 518:
1.149 joris 519: fd2 = rcs_rev_write_stmp(cf->file_rcs,
520: cf->file_ent->ce_rev, p2, 0);
521: if (futimes(fd2, tv2) == -1)
522: fatal("cvs_diff_local: futimes failed");
523: } else {
524: if (fstat(cf->fd, &st) == -1)
525: fatal("fstat failed %s", strerror(errno));
1.157 ray 526: b1 = buf_load_fd(cf->fd);
1.121 joris 527:
1.149 joris 528: tv2[0].tv_sec = st.st_mtime;
529: tv2[0].tv_usec = 0;
530: tv2[1] = tv2[0];
531:
1.157 ray 532: fd2 = buf_write_stmp(b1, p2, tv2);
533: buf_free(b1);
1.149 joris 534: }
1.17 jfb 535: }
536:
1.136 tobias 537: switch (cvs_cmdop) {
538: case CVS_OP_DIFF:
1.125 tobias 539: cvs_printf("%s", diffargs);
540:
1.136 tobias 541: if (rev1 != NULL && diff_rev1 != NULL) {
542: (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
1.125 tobias 543: cvs_printf(" -r%s", rbuf);
544:
1.136 tobias 545: if (rev2 != NULL && diff_rev2 != NULL) {
1.125 tobias 546: (void)rcsnum_tostr(diff_rev2, rbuf,
547: sizeof(rbuf));
548: cvs_printf(" -r%s", rbuf);
549: }
550: }
1.1 jfb 551:
1.125 tobias 552: if (diff_rev2 == NULL)
1.136 tobias 553: cvs_printf(" %s", cf->file_path);
1.130 tobias 554: cvs_printf("\n");
1.136 tobias 555: break;
556: case CVS_OP_RDIFF:
1.125 tobias 557: cvs_printf("diff ");
558: switch (diff_format) {
559: case D_CONTEXT:
560: cvs_printf("-c ");
561: break;
562: case D_RCSDIFF:
563: cvs_printf("-n ");
564: break;
565: case D_UNIFIED:
566: cvs_printf("-u ");
567: break;
568: default:
569: break;
570: }
571: if (diff_rev1 == NULL) {
572: cvs_printf("%s ", CVS_PATH_DEVNULL);
573: } else {
574: (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf));
575: cvs_printf("%s:%s ", cf->file_path, rbuf);
576: }
1.1 jfb 577:
1.125 tobias 578: if (diff_rev2 == NULL) {
579: cvs_printf("%s:removed\n", cf->file_path);
580: } else {
581: (void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 :
582: cf->file_rcs->rf_head, rbuf, sizeof(rbuf));
583: cvs_printf("%s:%s\n", cf->file_path, rbuf);
1.94 joris 584: }
1.136 tobias 585: break;
1.1 jfb 586: }
587:
1.136 tobias 588: if (fd1 == -1) {
589: if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1)
590: fatal("cannot open %s", CVS_PATH_DEVNULL);
1.114 joris 591: }
1.136 tobias 592: if (fd2 == -1) {
593: if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1)
594: fatal("cannot open %s", CVS_PATH_DEVNULL);
595: }
1.111 xsa 596:
1.155 ray 597: if (diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL,
1.154 ray 598: p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL,
599: dflags) == D_ERROR)
1.111 xsa 600: fatal("cvs_diff_local: failed to get RCS patch");
1.131 joris 601:
602: close(fd1);
603: close(fd2);
1.58 niallo 604:
1.156 ray 605: worklist_run(&temp_files, worklist_unlink);
1.111 xsa 606:
1.161 nicm 607: free(p1);
608: free(p2);
1.101 joris 609:
1.136 tobias 610: cleanup:
611: if (diff_rev1 != NULL &&
612: (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) &&
613: (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev))
1.161 nicm 614: free(diff_rev1);
1.136 tobias 615: diff_rev1 = NULL;
1.94 joris 616:
1.136 tobias 617: if (diff_rev2 != NULL &&
618: (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head))
1.161 nicm 619: free(diff_rev2);
1.136 tobias 620: diff_rev2 = NULL;
1.1 jfb 621: }