static BUF * import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) { char *p1, *p2; BUF *b1, *b2; int fd1, fd2; b2 = buf_alloc(128); b1 = buf_load_fd(cf->fd); (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); fd1 = buf_write_stmp(b1, p1, NULL); buf_free(b1); (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE); diff_format = D_RCSDIFF; if (diffreg(p2, p1, fd2, fd1, b2, D_FORCEASCII) == D_ERROR) fatal("import_get_rcsdiff: failed to get RCS patch"); close(fd1); close(fd2); (void)unlink(p1); (void)unlink(p2); xfree(p1); xfree(p2); return (b2); }
/* * Do the actual diff by calling either diffreg() or diffdir(). */ static void diffit(struct dirent *dp, char *path1, size_t plen1, char *path2, size_t plen2, int flags) { flags |= D_HEADER; strlcpy(path1 + plen1, dp->d_name, MAXPATHLEN - plen1); if (stat(path1, &stb1) != 0) { if (!(Nflag || Pflag) || errno != ENOENT) { warn("%s", path1); return; } flags |= D_EMPTY1; memset(&stb1, 0, sizeof(stb1)); } strlcpy(path2 + plen2, dp->d_name, MAXPATHLEN - plen2); if (stat(path2, &stb2) != 0) { if (!Nflag || errno != ENOENT) { warn("%s", path2); return; } flags |= D_EMPTY2; memset(&stb2, 0, sizeof(stb2)); stb2.st_mode = stb1.st_mode; } if (stb1.st_mode == 0) stb1.st_mode = stb2.st_mode; if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) { if (rflag) diffdir(path1, path2, flags); else if (lflag) dp->d_status |= D_COMMON; else printf("Common subdirectories: %s and %s\n", path1, path2); return; } if (!S_ISREG(stb1.st_mode) && !S_ISDIR(stb1.st_mode)) dp->d_status = D_SKIPPED1; else if (!S_ISREG(stb2.st_mode) && !S_ISDIR(stb2.st_mode)) dp->d_status = D_SKIPPED2; else dp->d_status = diffreg(path1, path2, flags); if (!lflag) print_status(dp->d_status, path1, path2, ""); }
static int rcsdiff_rev(RCSFILE *file, RCSNUM *rev1, RCSNUM *rev2, int dflags) { struct timeval tv[2], tv2[2]; BUF *b1, *b2; int ret; char *path1, *path2, rbuf1[RCS_REV_BUFSZ], rbuf2[RCS_REV_BUFSZ]; ret = D_ERROR; b1 = b2 = NULL; memset(&tv, 0, sizeof(tv)); memset(&tv2, 0, sizeof(tv2)); diff_rev1 = rev1; diff_rev2 = rev2; path1 = path2 = NULL; rcsnum_tostr(rev1, rbuf1, sizeof(rbuf1)); if (!quiet) fprintf(stderr, "retrieving revision %s\n", rbuf1); if ((b1 = rcs_getrev(file, rev1)) == NULL) { warnx("failed to retrieve revision %s", rbuf1); goto out; } b1 = rcs_kwexp_buf(b1, file, rev1); tv[0].tv_sec = (long)rcs_rev_getdate(file, rev1); tv[1].tv_sec = tv[0].tv_sec; rcsnum_tostr(rev2, rbuf2, sizeof(rbuf2)); if (!quiet) fprintf(stderr, "retrieving revision %s\n", rbuf2); if ((b2 = rcs_getrev(file, rev2)) == NULL) { warnx("failed to retrieve revision %s", rbuf2); goto out; } b2 = rcs_kwexp_buf(b2, file, rev2); tv2[0].tv_sec = (long)rcs_rev_getdate(file, rev2); tv2[1].tv_sec = tv2[0].tv_sec; if (!quiet) fprintf(stderr, "%s -r%s -r%s\n", diffargs, rbuf1, rbuf2); (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir); buf_write_stmp(b1, path1); buf_free(b1); b1 = NULL; if (utimes(path1, (const struct timeval *)&tv) < 0) warn("utimes"); (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir); buf_write_stmp(b2, path2); buf_free(b2); b2 = NULL; if (utimes(path2, (const struct timeval *)&tv2) < 0) warn("utimes"); ret = diffreg(path1, path2, NULL, dflags); out: if (b1 != NULL) buf_free(b1); if (b2 != NULL) buf_free(b2); if (path1 != NULL) xfree(path1); if (path2 != NULL) xfree(path2); return (ret); }
static int rcsdiff_file(RCSFILE *file, RCSNUM *rev, const char *filename, int dflags) { int ret, fd; time_t t; struct stat st; char *path1, *path2; BUF *b1, *b2; char rbuf[RCS_REV_BUFSZ]; struct tm *tb; struct timeval tv[2], tv2[2]; memset(&tv, 0, sizeof(tv)); memset(&tv2, 0, sizeof(tv2)); ret = D_ERROR; b1 = b2 = NULL; diff_rev1 = rev; diff_rev2 = NULL; path1 = path2 = NULL; if ((fd = open(filename, O_RDONLY)) == -1) { warn("%s", filename); goto out; } rcsnum_tostr(rev, rbuf, sizeof(rbuf)); if (!quiet) { fprintf(stderr, "retrieving revision %s\n", rbuf); fprintf(stderr, "%s -r%s %s\n", diffargs, rbuf, filename); } if ((b1 = rcs_getrev(file, rev)) == NULL) { warnx("failed to retrieve revision %s", rbuf); goto out; } b1 = rcs_kwexp_buf(b1, file, rev); tv[0].tv_sec = (long)rcs_rev_getdate(file, rev); tv[1].tv_sec = tv[0].tv_sec; if ((b2 = buf_load(filename)) == NULL) { warnx("failed to load file: `%s'", filename); goto out; } /* XXX - GNU uses GMT */ if (fstat(fd, &st) == -1) err(D_ERROR, "%s", filename); tb = gmtime(&st.st_mtime); t = mktime(tb); tv2[0].tv_sec = t; tv2[1].tv_sec = t; (void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", rcs_tmpdir); buf_write_stmp(b1, path1); buf_free(b1); b1 = NULL; if (utimes(path1, (const struct timeval *)&tv) < 0) warn("utimes"); (void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", rcs_tmpdir); buf_write_stmp(b2, path2); buf_free(b2); b2 = NULL; if (utimes(path2, (const struct timeval *)&tv2) < 0) warn("utimes"); ret = diffreg(path1, path2, NULL, dflags); out: if (fd != -1) (void)close(fd); if (b1 != NULL) buf_free(b1); if (b2 != NULL) buf_free(b2); if (path1 != NULL) xfree(path1); if (path2 != NULL) xfree(path2); return (ret); }
void pseudomain(int argc, char **argv, FILE *file) { buffer = file; char *ep, **oargv, *optfile; const char *pn; long l; int ch, lastch, gotstdin, prevoptind, newarg; // int oargc; filebehave = FILE_NORMAL; /* Check what is the program name of the binary. In this way we can have all the funcionalities in one binary without the need of scripting and using ugly hacks. */ pn = getprogname(); if (pn[0] == 'z') { filebehave = FILE_GZIP; } oargv = argv; // oargc = argc; gotstdin = 0; optfile = "\0"; lastch = '\0'; prevoptind = 1; newarg = 1; while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (newarg) usage(); /* disallow -[0-9]+ */ else if (lastch == 'c' || lastch == 'u') context = 0; else if (!isdigit(lastch) || context > INT_MAX / 10) usage(); context = (context * 10) + (ch - '0'); break; case 'a': aflag = 1; break; case 'b': bflag = 1; break; case 'B': Bflag = 1; break; case 'C': case 'c': cflag = 1; format = D_CONTEXT; if (optarg != NULL) { l = strtol(optarg, &ep, 10); if (*ep != '\0' || l < 0 || l >= INT_MAX) usage(); context = (int)l; } else context = 3; break; case 'D': format = D_IFDEF; ifdefname = optarg; break; case 'd': dflag = 1; break; case 'E': Eflag = 1; break; case 'e': format = D_EDIT; break; case 'f': format = D_REVERSE; break; case 'h': /* silently ignore for backwards compatibility */ break; case 'I': push_ignore_pats(optarg); break; case 'i': iflag = 1; break; case 'L': if (label[0] == NULL) label[0] = optarg; else if (label[1] == NULL) label[1] = optarg; else usage(); break; case 'l': lflag = 1; signal(SIGPIPE, SIG_IGN); break; case 'N': Nflag = 1; break; case 'n': format = D_NREVERSE; break; case 'P': Pflag = 1; break; case 'p': pflag = 1; break; case 'r': rflag = 1; break; case 'q': format = D_BRIEF; break; case 'S': start = optarg; break; case 's': sflag = 1; break; case 'T': Tflag = 1; break; case 't': tflag = 1; break; case 'U': case 'u': format = D_UNIFIED; if (optarg != NULL) { l = strtol(optarg, &ep, 10); if (*ep != '\0' || l < 0 || l >= INT_MAX) usage(); context = (int)l; } else context = 3; break; case 'v': fprintf(buffer, "FreeBSD diff 2.8.7\n"); exit(0); case 'W': wflag = 1; break; case 'X': read_excludes_file(optarg); break; case 'x': push_excludes(optarg); break; case 'y': yflag = 1; break; case OPT_FFILE: Toflag = 1; optfile = optarg; break; case OPT_TOFILE: Fromflag = 1; optfile = optarg; break; case OPT_CHGD_GF: case OPT_NEW_GF: case OPT_OLD_GF: case OPT_UNCHGD_GF: /* XXX To do: Complete --GTYPE-group-format. */ format = D_GF; group_format = optarg; break; case OPT_NEW_LF: case OPT_OLD_LF: case OPT_UNCHGD_LF: case OPT_LF: /* XXX To do: Complete --line-format. */ format = D_LF; line_format = optarg; break; case OPT_NORMAL: format = D_NORMAL; break; case OPT_LEFTC: /* Do nothing, passes option to sdiff. */ break; case OPT_SUPCL: /* Do nothing, passes option to sdiff. */ break; case OPT_TSIZE: if (optarg != NULL) { l = strtol(optarg, &ep, 10); if (*ep != '\0' || l < 1 || l >= INT_MAX) usage(); tabsize = (int)l; } else tabsize = 8; break; case OPT_STRIPCR: strip_cr=1; break; case OPT_IGN_FN_CASE: ignore_file_case = 1; break; case OPT_NIGN_FN_CASE: ignore_file_case = 0; break; case OPT_HELP: for (; *help_strs; help_strs++) { fprintf(buffer, "%s\n", *help_strs); } exit(0); break; default: usage(); break; } lastch = ch; newarg = optind != prevoptind; prevoptind = optind; } argc -= optind; argv += optind; // if (yflag) { // /* remove y flag from args and call sdiff */ // for (argv = oargv; argv && strcmp(*argv, "-y") != 0 && // strcmp(*argv, "--side-by-side") != 0; argv++); // while(argv != &oargv[oargc]){ // *argv= *(argv+1); // argv++; // } // oargv[0] = _PATH_SDIFF; // *argv= "\0"; // execv(_PATH_SDIFF, oargv); // _exit(1); // } /* * Do sanity checks, fill in stb1 and stb2 and call the appropriate * driver routine. Both drivers use the contents of stb1 and stb2. */ if (argc != 2) usage(); if (ignore_pats != NULL) { char buf[BUFSIZ]; int error; if ((error = regcomp(&ignore_re, ignore_pats, REG_NEWLINE | REG_EXTENDED)) != 0) { regerror(error, &ignore_re, buf, sizeof(buf)); if (*ignore_pats != '\0') errx(2, "%s: %s", ignore_pats, buf); else errx(2, "%s", buf); } } if (strcmp(argv[0], "-") == 0) { fstat(STDIN_FILENO, &stb1); gotstdin = 1; } else if (stat(argv[0], &stb1) != 0) err(2, "%s", argv[0]); if (strcmp(argv[1], "-") == 0) { fstat(STDIN_FILENO, &stb2); gotstdin = 1; } else if (stat(argv[1], &stb2) != 0) err(2, "%s", argv[1]); if (gotstdin && (S_ISDIR(stb1.st_mode) || S_ISDIR(stb2.st_mode))) errx(2, "can't compare - to a directory"); set_argstr(oargv, argv); if (S_ISDIR(stb1.st_mode) && S_ISDIR(stb2.st_mode)) { if (format == D_IFDEF) if (ch == 'D') errx(2, "-D option not supported with directories"); if (ch == OPT_LF) errx(2, "--line-format option not supported with directories"); diffdir(argv[0], argv[1]); } else { if (S_ISDIR(stb1.st_mode)) { argv[0] = splice(argv[0], argv[1]); if (stat(argv[0], &stb1) < 0) err(2, "%s", argv[0]); } if (S_ISDIR(stb2.st_mode)) { argv[1] = splice(argv[1], argv[0]); if (stat(argv[1], &stb2) < 0) err(2, "%s", argv[1]); } /* Checks if --to-file or --from-file are specified */ if (Toflag && Fromflag) { (void)fprintf(stderr, "--from-file and --to-file both specified.\n"); exit(1); } if (Toflag) { print_status(diffreg(optfile, argv[0], 0), optfile, argv[0], NULL); print_status(diffreg(optfile, argv[1], 0), optfile, argv[1], NULL); } if (Fromflag) { print_status(diffreg(argv[0], optfile, 0), argv[0], optfile, NULL); print_status(diffreg(argv[1], optfile, 0), argv[1], optfile, NULL); } if (!Toflag && !Fromflag) print_status(diffreg(argv[0], argv[1], 0), argv[0], argv[1], NULL); } }
void cvs_diff_local(struct cvs_file *cf) { BUF *b1; int fd1, fd2; struct stat st; struct timespec tv[2], tv2[2]; struct tm datetm; char rbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ], *p1, *p2; b1 = NULL; fd1 = fd2 = -1; p1 = p2 = NULL; cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path); if (cf->file_type == CVS_DIR) { if (verbosity > 1) cvs_log(LP_ERR, "Diffing inside %s", cf->file_path); return; } cvs_file_classify(cf, cvs_directory_tag); if (cvs_cmdop == CVS_OP_DIFF) { if (cf->file_ent == NULL) { cvs_log(LP_ERR, "I know nothing about %s", cf->file_path); return; } switch (cf->file_ent->ce_status) { case CVS_ENT_ADDED: if (Nflag == 0) { cvs_log(LP_ERR, "%s is a new entry, no " "comparison available", cf->file_path); return; } if (!(cf->file_flags & FILE_ON_DISK)) { cvs_log(LP_ERR, "cannot find %s", cf->file_path); return; } break; case CVS_ENT_REMOVED: if (Nflag == 0) { cvs_log(LP_ERR, "%s was removed, no " "comparison available", cf->file_path); return; } if (cf->file_rcs == NULL) { cvs_log(LP_ERR, "cannot find RCS file for %s", cf->file_path); return; } break; default: if (!(cf->file_flags & FILE_ON_DISK)) { cvs_printf("? %s\n", cf->file_path); return; } if (cf->file_rcs == NULL) { cvs_log(LP_ERR, "cannot find RCS file for %s", cf->file_path); return; } break; } } if (cf->file_status == FILE_UPTODATE && rev1 == NULL && rev2 == NULL && date1 == -1 && date2 == -1) return; if (cf->file_rcs != NULL && cf->file_rcs->rf_head == NULL) { cvs_log(LP_ERR, "no head revision in RCS file for %s\n", cf->file_path); return; } if (kflag && cf->file_rcs != NULL) rcs_kwexp_set(cf->file_rcs, kflag); if (cf->file_rcs == NULL) diff_rev1 = NULL; else if (rev1 != NULL || date1 != -1) { cvs_specified_date = date1; diff_rev1 = rcs_translate_tag(rev1, cf->file_rcs); if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_DIFF) { if (rev1 != NULL) { cvs_log(LP_ERR, "tag %s not in file %s", rev1, cf->file_path); goto cleanup; } else if (Nflag) { diff_rev1 = NULL; } else { gmtime_r(&cvs_specified_date, &datetm); strftime(tbuf, sizeof(tbuf), "%Y.%m.%d.%H.%M.%S", &datetm); cvs_log(LP_ERR, "no revision for date %s in " "file %s", tbuf, cf->file_path); goto cleanup; } } else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF && force_head) { /* -f is not allowed for unknown symbols */ if ((diff_rev1 = rcsnum_parse(rev1)) == NULL) fatal("no such tag %s", rev1); rcsnum_free(diff_rev1); diff_rev1 = cf->file_rcs->rf_head; } cvs_specified_date = -1; } else if (cvs_cmdop == CVS_OP_DIFF) { if (cf->file_ent->ce_status == CVS_ENT_ADDED) diff_rev1 = NULL; else diff_rev1 = cf->file_ent->ce_rev; } if (cf->file_rcs == NULL) diff_rev2 = NULL; else if (rev2 != NULL || date2 != -1) { cvs_specified_date = date2; diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs); if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) { if (rev2 != NULL) { cvs_log(LP_ERR, "tag %s not in file %s", rev2, cf->file_path); goto cleanup; } else if (Nflag) { diff_rev2 = NULL; } else { gmtime_r(&cvs_specified_date, &datetm); strftime(tbuf, sizeof(tbuf), "%Y.%m.%d.%H.%M.%S", &datetm); cvs_log(LP_ERR, "no revision for date %s in " "file %s", tbuf, cf->file_path); goto cleanup; } } else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF && force_head) { /* -f is not allowed for unknown symbols */ if ((diff_rev2 = rcsnum_parse(rev2)) == NULL) fatal("no such tag %s", rev2); rcsnum_free(diff_rev2); diff_rev2 = cf->file_rcs->rf_head; } cvs_specified_date = -1; } else if (cvs_cmdop == CVS_OP_RDIFF) diff_rev2 = cf->file_rcs->rf_head; else if (cf->file_ent->ce_status == CVS_ENT_REMOVED) diff_rev2 = NULL; if (diff_rev1 != NULL && diff_rev2 != NULL && rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0) goto cleanup; switch (cvs_cmdop) { case CVS_OP_DIFF: if (cf->file_status == FILE_UPTODATE) { if (diff_rev2 == NULL && !rcsnum_cmp(diff_rev1, cf->file_rcsrev, 0)) goto cleanup; } break; case CVS_OP_RDIFF: if (diff_rev1 == NULL && diff_rev2 == NULL) goto cleanup; break; } cvs_printf("Index: %s\n", cf->file_path); if (cvs_cmdop == CVS_OP_DIFF) cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV, cf->file_rcs != NULL ? cf->file_rpath : cf->file_path); if (diff_rev1 != NULL) { if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) { (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); cvs_printf("retrieving revision %s\n", rbuf); } tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1); tv[0].tv_nsec = 0; tv[1] = tv[0]; (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0); if (futimens(fd1, tv) == -1) fatal("cvs_diff_local: futimens failed"); } if (diff_rev2 != NULL) { if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) { (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); cvs_printf("retrieving revision %s\n", rbuf); } tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2); tv2[0].tv_nsec = 0; tv2[1] = tv2[0]; (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0); if (futimens(fd2, tv2) == -1) fatal("cvs_diff_local: futimens failed"); } else if (cvs_cmdop == CVS_OP_DIFF && (cf->file_flags & FILE_ON_DISK) && cf->file_ent->ce_status != CVS_ENT_REMOVED) { (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); if (cvs_server_active == 1 && cf->fd == -1) { tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, cf->file_ent->ce_rev); tv2[0].tv_nsec = 0; tv2[1] = tv2[0]; fd2 = rcs_rev_write_stmp(cf->file_rcs, cf->file_ent->ce_rev, p2, 0); if (futimens(fd2, tv2) == -1) fatal("cvs_diff_local: futimens failed"); } else { if (fstat(cf->fd, &st) == -1) fatal("fstat failed %s", strerror(errno)); b1 = buf_load_fd(cf->fd); tv2[0].tv_sec = st.st_mtime; tv2[0].tv_nsec = 0; tv2[1] = tv2[0]; fd2 = buf_write_stmp(b1, p2, tv2); buf_free(b1); } } switch (cvs_cmdop) { case CVS_OP_DIFF: cvs_printf("%s", diffargs); if (rev1 != NULL && diff_rev1 != NULL) { (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); cvs_printf(" -r%s", rbuf); if (rev2 != NULL && diff_rev2 != NULL) { (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); cvs_printf(" -r%s", rbuf); } } if (diff_rev2 == NULL) cvs_printf(" %s", cf->file_path); cvs_printf("\n"); break; case CVS_OP_RDIFF: cvs_printf("diff "); switch (diff_format) { case D_CONTEXT: cvs_printf("-c "); break; case D_RCSDIFF: cvs_printf("-n "); break; case D_UNIFIED: cvs_printf("-u "); break; default: break; } if (diff_rev1 == NULL) { cvs_printf("%s ", CVS_PATH_DEVNULL); } else { (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); cvs_printf("%s:%s ", cf->file_path, rbuf); } if (diff_rev2 == NULL) { cvs_printf("%s:removed\n", cf->file_path); } else { (void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 : cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); cvs_printf("%s:%s\n", cf->file_path, rbuf); } break; } if (fd1 == -1) { if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) fatal("cannot open %s", CVS_PATH_DEVNULL); } if (fd2 == -1) { if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) fatal("cannot open %s", CVS_PATH_DEVNULL); } if (diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL, p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL, dflags) == D_ERROR) fatal("cvs_diff_local: failed to get RCS patch"); close(fd1); close(fd2); worklist_run(&temp_files, worklist_unlink); if (p1 != NULL) xfree(p1); if (p2 != NULL) xfree(p2); cleanup: if (diff_rev1 != NULL && (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) && (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev)) xfree(diff_rev1); diff_rev1 = NULL; if (diff_rev2 != NULL && (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head)) xfree(diff_rev2); diff_rev2 = NULL; }