/** * @brief Applies a diff to the universe. * * @param name Diff to apply. * @return 0 on success. */ int diff_apply( const char *name ) { xmlNodePtr node; xmlDocPtr doc; size_t bufsize; char *buf; char *diffname; /* Check if already applied. */ if (diff_isApplied(name)) return 0; buf = ndata_read( DIFF_DATA_PATH, &bufsize ); doc = xmlParseMemory( buf, bufsize ); node = doc->xmlChildrenNode; if (strcmp((char*)node->name,"unidiffs")) { ERR(_("Malformed unidiff file: missing root element 'unidiffs'")); return 0; } node = node->xmlChildrenNode; /* first system node */ if (node == NULL) { ERR(_("Malformed unidiff file: does not contain elements")); return 0; } do { if (xml_isNode(node,"unidiff")) { /* Check to see if it's the diff we're looking for. */ xmlr_attr(node,"name",diffname); if (strcmp(diffname,name)==0) { /* Apply it. */ diff_patch( node ); /* Clean up. */ free(diffname); xmlFreeDoc(doc); free(buf); economy_execQueued(); return 0; } free(diffname); } } while (xml_nextNode(node)); /* More clean up. */ xmlFreeDoc(doc); free(buf); WARN(_("UniDiff '%s' not found in %s."), name, DIFF_DATA_PATH); return -1; }
static int do_merge(int argc, char *argv[], int obj, int reverse, int replace, int ignore, int show_wiggles, int quiet) { /* merge three files, A B C, so changed between B and C get made to A */ struct stream f, flist[3]; struct file fl[3]; int i; int chunks1 = 0, chunks2 = 0, chunks3 = 0; char *replacename = NULL, *orignew = NULL; struct csl *csl1, *csl2; struct ci ci; FILE *outfile = stdout; switch (argc) { case 0: fprintf(stderr, "%s: no files given for --merge\n", Cmd); return 2; case 3: case 2: case 1: for (i = 0; i < argc; i++) { flist[i] = load_file(argv[i]); if (flist[i].body == NULL) { fprintf(stderr, "%s: cannot load file '%s' - %s\n", Cmd, argv[i], strerror(errno)); return 2; } } break; default: fprintf(stderr, "%s: too many files given for --merge\n", Cmd); return 2; } switch (argc) { case 1: /* a merge file */ f = flist[0]; if (!split_merge(f, &flist[0], &flist[1], &flist[2])) { fprintf(stderr, "%s: merge file %s looks bad.\n", Cmd, argv[0]); return 2; } break; case 2: /* a file and a patch */ f = flist[1]; chunks2 = chunks3 = split_patch(f, &flist[1], &flist[2]); break; case 3: /* three separate files */ break; } if (reverse) { f = flist[1]; flist[1] = flist[2]; flist[2] = f; } for (i = 0; i < 3; i++) { if (flist[i].body == NULL) { fprintf(stderr, "%s: file %d missing\n", Cmd, i); return 2; } } if (replace) { int fd; replacename = xmalloc(strlen(argv[0]) + 20); orignew = xmalloc(strlen(argv[0]) + 20); strcpy(replacename, argv[0]); strcpy(orignew, argv[0]); strcat(orignew, ".porig"); if (open(orignew, O_RDONLY) >= 0 || errno != ENOENT) { fprintf(stderr, "%s: %s already exists\n", Cmd, orignew); return 2; } strcat(replacename, "XXXXXX"); fd = mkstemp(replacename); if (fd == -1) { fprintf(stderr, "%s: could not create temporary file for %s\n", Cmd, replacename); return 2; } outfile = fdopen(fd, "w"); } if (obj == 'l') { fl[0] = split_stream(flist[0], ByLine); fl[1] = split_stream(flist[1], ByLine); fl[2] = split_stream(flist[2], ByLine); } else { fl[0] = split_stream(flist[0], ByWord); fl[1] = split_stream(flist[1], ByWord); fl[2] = split_stream(flist[2], ByWord); } if (chunks2 && !chunks1) csl1 = pdiff(fl[0], fl[1], chunks2); else csl1 = diff(fl[0], fl[1]); csl2 = diff_patch(fl[1], fl[2]); ci = make_merger(fl[0], fl[1], fl[2], csl1, csl2, obj == 'w', ignore, show_wiggles); print_merge(outfile, &fl[0], &fl[1], &fl[2], obj == 'w', ci.merger); if (!quiet && ci.conflicts) fprintf(stderr, "%d unresolved conflict%s found\n", ci.conflicts, ci.conflicts == 1 ? "" : "s"); if (!quiet && ci.ignored) fprintf(stderr, "%d already-applied change%s ignored\n", ci.ignored, ci.ignored == 1 ? "" : "s"); if (replace) { fclose(outfile); if (rename(argv[0], orignew) == 0 && rename(replacename, argv[0]) == 0) /* all ok */; else { fprintf(stderr, "%s: failed to move new file into place.\n", Cmd); return 2; } } return (ci.conflicts > 0); }
static int do_diff(int argc, char *argv[], int obj, int ispatch, int which, int reverse) { /* create a diff (line or char) of two streams */ struct stream f, flist[3]; int chunks1 = 0, chunks2 = 0, chunks3 = 0; int exit_status = 0; struct file fl[2]; struct csl *csl; switch (argc) { case 0: fprintf(stderr, "%s: no file given for --diff\n", Cmd); return 2; case 1: f = load_file(argv[0]); if (f.body == NULL) { fprintf(stderr, "%s: cannot load file '%s' - %s\n", Cmd, argv[0], strerror(errno)); return 2; } chunks1 = chunks2 = split_patch(f, &flist[0], &flist[1]); if (!flist[0].body || !flist[1].body) { fprintf(stderr, "%s: couldn't parse patch %s\n", Cmd, argv[0]); return 2; } break; case 2: flist[0] = load_file(argv[0]); if (flist[0].body == NULL) { fprintf(stderr, "%s: cannot load file '%s' - %s\n", Cmd, argv[0], strerror(errno)); return 2; } if (ispatch) { f = load_file(argv[1]); if (f.body == NULL) { fprintf(stderr, "%s: cannot load patch" " '%s' - %s\n", Cmd, argv[1], strerror(errno)); return 2; } if (which == '2') chunks2 = chunks3 = split_patch(f, &flist[2], &flist[1]); else chunks2 = chunks3 = split_patch(f, &flist[1], &flist[2]); } else flist[1] = load_file(argv[1]); if (flist[1].body == NULL) { fprintf(stderr, "%s: cannot load file" " '%s' - %s\n", Cmd, argv[1], strerror(errno)); return 2; } break; default: fprintf(stderr, "%s: too many files given for --diff\n", Cmd); return 2; } if (reverse) { f = flist[1]; flist[1] = flist[2]; flist[2] = f; } fl[0] = split_stream(flist[0], obj == 'l' ? ByLine : ByWord); fl[1] = split_stream(flist[1], obj == 'l' ? ByLine : ByWord); if (chunks2 && !chunks1) csl = pdiff(fl[0], fl[1], chunks2); else csl = diff_patch(fl[0], fl[1]); if (obj == 'l') { if (!chunks1) printf("@@ -1,%d +1,%d @@\n", fl[0].elcnt, fl[1].elcnt); exit_status = do_diff_lines(fl, csl); } else { if (!chunks1) { /* count lines in each file */ int l1, l2, i; l1 = l2 = 0; for (i = 0 ; i < fl[0].elcnt ; i++) if (ends_line(fl[0].list[i])) l1++; for (i = 0 ; i < fl[1].elcnt ; i++) if (ends_line(fl[1].list[i])) l2++; printf("@@ -1,%d +1,%d @@\n", l1, l2); } exit_status = do_diff_words(fl, csl); } return exit_status; }