From 1107579059ffc7db70f69180242eddae6626a780 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 14 May 2012 11:01:11 +1000 Subject: [PATCH] Merge: allow merging a multi-patch patchfile. If wiggle -p -r patchfilename is given, multiple patches - each identifying the target file - are read from patchfilename and each is applied to the relevant file. Note that '-r' is required with this usage of -p. Signed-off-by: NeilBrown --- ReadMe.c | 5 ++-- wiggle.1 | 33 ++++++++++++++++++++++++- wiggle.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++------- wiggle.h | 6 +---- 4 files changed, 100 insertions(+), 17 deletions(-) diff --git a/ReadMe.c b/ReadMe.c index 1844005..a2bce34 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -31,8 +31,7 @@ char Version[] = "wiggle 0.8 2010-03-24 GPL-2+ http://neil.brown.name/wiggle/\n"; -char short_options1[] = "xdmwlrhiW123pVRvqB"; /* not mode B */ -char short_options2[] = "xdmwlrhiW123p::VRvqB"; /* mode B */ +char short_options[] = "xdmwlrhiW123p::VRvqB"; struct option long_options[] = { {"browse", 0, 0, 'B'}, @@ -142,6 +141,8 @@ char HelpMerge[] = "\n" "\n" "If --merge is given one file, it is treated as a merge (merge -A\n" "output) and the three needed streams are extracted from it.\n" +"If --merge is given one file and -p, it is a patch which identifies\n" +"the files that should be patched.\n" "If --merge is given two files, the second is treated as a patch\n" "file and the first is the original file.\n" "If --merge is given three files, they are each treated as whole files\n" diff --git a/wiggle.1 b/wiggle.1 index 0123600..a5321a2 100644 --- a/wiggle.1 +++ b/wiggle.1 @@ -144,6 +144,25 @@ Request that all operations and display be line based. .BR -p ", " \-\-patch Treat the last named file as a patch instead of a file (with \-\-diff) or a merge (\-\-extract). +In +.I merge +mode, +.B -p +requires there be exactly one file which is a patch and which can +contain patches to multiple file. The patches are merged into each +file. This usage requires the +.B \-\-replace +option as writing lots of merged files to standard-out is impractical. + +When used in +.I merge +mode, +B -p +can be followed by a numeric argument indicating how many patch name +components to be stripped from files named in the patch file. If no +numeric argument is given, +.I wiggle +will deduce an appropriate number based what files are visible. .TP .BR -r ", " \-\-replace @@ -233,7 +252,9 @@ extracts the three texts that it needs from files listed on the command line. Either 1, 2, or 3 files may be listed, and any one of them may be a lone hyphen signifying standard-input. -If one file is given, it is treated as a +If one file is given and the +.B \-p +option is not present, the file is treated as a .B merge file, i.e. the output of "merge \-A" or "wiggle". Such a file implicitly contains three streams and these are extracted and @@ -246,6 +267,16 @@ or "diff\ \-c", or a ".rej" file from and the two other texts are extracted from that. +If one file is given together with the +.B \-p +option, the file is treated as a patch file containing the names of +the files that it patches. In this case multiple merge operations can +happen and each takes one stream from a file named in the patch, and +the other to from the patch itself. The +.B \-\-replace +option is required and the results are written back to the +target files. + Finally if three files are listed, they are taken to contain the given text and the two other texts, in order. diff --git a/wiggle.c b/wiggle.c index 842c479..a3cba3e 100644 --- a/wiggle.c +++ b/wiggle.c @@ -81,12 +81,13 @@ * Defaults are --merge --words * */ - +#define _GNU_SOURCE #include "wiggle.h" #include #include #include #include +#include #include char *Cmd = "wiggle"; @@ -581,6 +582,56 @@ static int do_merge(int argc, char *argv[], int obj, return (ci.conflicts > 0); } +static int multi_merge(int argc, char *argv[], int obj, + int reverse, int ignore, int show_wiggles, + int replace, int strip, + int quiet) +{ + FILE *f; + char *filename; + struct plist *pl; + int num_patches; + int rv = 0; + int i; + + if (!replace) { + fprintf(stderr, + "%s: -p in merge mode requires -r\n", + Cmd); + return 2; + } + if (argc != 1) { + fprintf(stderr, + "%s: -p in merge mode requires exactly one file\n", + Cmd); + return 2; + } + filename = argv[0]; + f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "%s: cannot open %s\n", + Cmd, filename); + return 2; + } + pl = parse_patch(f, NULL, &num_patches); + fclose(f); + if (set_prefix(pl, num_patches, strip) == 0) { + fprintf(stderr, "%s: aborting\n", Cmd); + return 2; + } + for (i = 0; i < num_patches; i++) { + char *name; + char *av[2]; + asprintf(&name, "_wiggle_:%d:%d:%s", + pl[i].start, pl[i].end, filename); + av[0] = pl[i].file; + av[1] = name; + rv |= do_merge(2, av, obj, reverse, 1, ignore, + show_wiggles, quiet); + } + return rv; +} + int main(int argc, char *argv[]) { int opt; @@ -604,7 +655,7 @@ int main(int argc, char *argv[]) do_trace = 1; while ((opt = getopt_long(argc, argv, - short_options(mode), long_options, + short_options, long_options, &option_index)) != -1) switch (opt) { case 'h': @@ -731,11 +782,7 @@ int main(int argc, char *argv[]) Cmd); exit(2); } - if (ispatch && (mode != 'x' && mode != 'd')) { - fprintf(stderr, - "%s: --patch only allowed with --extract or --diff\n", Cmd); - exit(2); - } + if (ispatch && which == '3') { fprintf(stderr, "%s: cannot extract -3 from a patch.\n", Cmd); @@ -750,8 +797,16 @@ int main(int argc, char *argv[]) exit_status = do_diff(argc-optind, argv+optind, obj, ispatch, which, reverse); break; case 'm': - exit_status = do_merge(argc-optind, argv+optind, obj, reverse, replace, - ignore, show_wiggles, quiet); + if (ispatch) + exit_status = multi_merge(argc-optind, + argv+optind, obj, + reverse, ignore, + show_wiggles, + replace, strip, + quiet); + else + exit_status = do_merge(argc-optind, argv+optind, obj, reverse, replace, + ignore, show_wiggles, quiet); break; } exit(exit_status); diff --git a/wiggle.h b/wiggle.h index 8e55489..91b4110 100644 --- a/wiggle.h +++ b/wiggle.h @@ -184,11 +184,7 @@ extern int vpatch(int argc, char *argv[], int patch, int strip, extern char *Cmd; extern char Version[]; -extern char short_options1[], short_options2[]; -static inline char *short_options(char mode) -{ - return mode == 'B' ? short_options2 : short_options1; -} +extern char short_options[]; extern struct option long_options[]; extern char Usage[]; extern char Help[]; -- 2.39.5