Browser: improve rendering of conflicts in the the 'merge' view.
[wiggle/upstream.git] / extract.c
blobba81ec0282436ed7276c193b3f4a33da19594a30
1 /*
2 * wiggle - apply rejected patches
4 * Copyright (C) 2003 Neil Brown <neilb@cse.unsw.edu.au>
5 * Copyright (C) 2010 Neil Brown <neilb@suse.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Author: Neil Brown
23 * Email: <neilb@suse.de>
27 * split patch or merge files.
30 #include "wiggle.h"
31 #include <stdlib.h>
33 /* skip 'cp' past the new '\n', or all the way to 'end' */
34 static void skip_eol(char **cp, char *end)
36 char *c = *cp;
37 while (c < end && *c != '\n')
38 c++;
39 if (c < end)
40 c++;
41 *cp = c;
44 /* copy one line, or to end, from 'cp' into the stream, extending
45 * the stream.
47 static void copyline(struct stream *s, char **cp, char *end)
49 char *from = *cp;
50 char *to = s->body+s->len;
52 while (from < end && *from != '\n')
53 *to++ = *from++;
54 if (from < end)
55 *to++ = *from++;
56 s->len = to-s->body;
57 *cp = from;
60 int split_patch(struct stream f, struct stream *f1, struct stream *f2)
62 struct stream r1, r2;
63 int chunks = 0;
64 char *cp, *end;
65 int state = 0;
66 int acnt = 0, bcnt = 0;
67 int a, b, c, d;
68 int lineno = 0;
69 char before[100], after[100];
71 f1->body = f2->body = NULL;
73 r1.body = xmalloc(f.len);
74 r2.body = xmalloc(f.len);
75 r1.len = r2.len = 0;
77 cp = f.body;
78 end = f.body+f.len;
79 while (cp < end) {
80 /* state:
81 * 0 not in a patch
82 * 1 first half of context
83 * 2 second half of context
84 * 3 unified
86 lineno++;
87 switch (state) {
88 case 0:
89 if (sscanf(cp, "@@ -%s +%s @@", before, after) == 2) {
90 int ok = 1;
91 if (sscanf(before, "%d,%d", &a, &b) == 2)
92 acnt = b;
93 else if (sscanf(before, "%d", &a) == 1)
94 acnt = 1;
95 else
96 ok = 0;
98 if (sscanf(after, "%d,%d", &c, &d) == 2)
99 bcnt = d;
100 else if (sscanf(after, "%d", &c) == 1)
101 bcnt = 1;
102 else
103 ok = 0;
104 if (ok)
105 state = 3;
106 else
107 state = 0;
108 } else if (sscanf(cp, "*** %d,%d ****", &a, &b) == 2) {
109 acnt = b-a+1;
110 state = 1;
111 } else if (sscanf(cp, "--- %d,%d ----", &c, &d) == 2) {
112 bcnt = d-c+1;
113 state = 2;
115 skip_eol(&cp, end);
116 if (state == 1 || state == 3) {
117 char buf[20];
118 buf[0] = 0;
119 chunks++;
120 sprintf(buf+1, "%5d %5d %5d\n", chunks, a, acnt);
121 memcpy(r1.body+r1.len, buf, 20);
122 r1.len += 20;
124 if (state == 2 || state == 3) {
125 char buf[20];
126 buf[0] = 0;
127 sprintf(buf+1, "%5d %5d %5d\n", chunks, c, bcnt);
128 memcpy(r2.body+r2.len, buf, 20);
129 r2.len += 20;
131 break;
132 case 1:
133 if ((*cp == ' ' || *cp == '!' || *cp == '-' || *cp == '+')
134 && cp[1] == ' ') {
135 cp += 2;
136 copyline(&r1, &cp, end);
137 acnt--;
138 if (acnt == 0)
139 state = 0;
140 } else {
141 fprintf(stderr, "%s: bad context patch at line %d\n",
142 Cmd, lineno);
143 return 0;
145 break;
146 case 2:
147 if ((*cp == ' ' || *cp == '!' || *cp == '-' || *cp == '+')
148 && cp[1] == ' ') {
149 cp += 2;
150 copyline(&r2, &cp, end);
151 bcnt--;
152 if (bcnt == 0)
153 state = 0;
154 } else {
155 fprintf(stderr, "%s: bad context patch/2 at line %d\n",
156 Cmd, lineno);
157 return 0;
159 break;
160 case 3:
161 if (*cp == ' ') {
162 char *cp2;
163 cp++;
164 cp2 = cp;
165 copyline(&r1, &cp, end);
166 copyline(&r2, &cp2, end);
167 acnt--; bcnt--;
168 } else if (*cp == '-') {
169 cp++;
170 copyline(&r1, &cp, end);
171 acnt--;
172 } else if (*cp == '+') {
173 cp++;
174 copyline(&r2, &cp, end);
175 bcnt--;
176 } else {
177 fprintf(stderr, "%s: bad unified patch at line %d\n",
178 Cmd, lineno);
179 return 0;
181 if (acnt <= 0 && bcnt <= 0)
182 state = 0;
183 break;
186 if (r1.len > f.len || r2.len > f.len)
187 abort();
188 *f1 = r1;
189 *f2 = r2;
190 return chunks;
194 * extract parts of a "diff3 -m" or "wiggle -m" output
196 int split_merge(struct stream f, struct stream *f1, struct stream *f2, struct stream *f3)
198 int lineno;
199 int state = 0;
200 char *cp, *end;
201 struct stream r1, r2, r3;
202 f1->body = NULL;
203 f2->body = NULL;
205 r1.body = xmalloc(f.len);
206 r2.body = xmalloc(f.len);
207 r3.body = xmalloc(f.len);
208 r1.len = r2.len = r3.len = 0;
210 cp = f.body;
211 end = f.body+f.len;
212 while (cp < end) {
213 /* state:
214 * 0 not in conflict
215 * 1 in file 1 of conflict
216 * 2 in file 2 of conflict
217 * 3 in file 3 of conflict
218 * 4 in file 2 but expecting 1/3 next
219 * 5 in file 1/3
221 int len = end-cp;
222 lineno++;
223 switch (state) {
224 case 0:
225 if (len >= 8 &&
226 strncmp(cp, "<<<<<<<", 7) == 0 &&
227 (cp[7] == ' ' || cp[7] == '\n')
229 char *peek;
230 state = 1;
231 skip_eol(&cp, end);
232 /* diff3 will do something a bit strange in
233 * the 1st and 3rd sections are the same.
234 * it reports
235 * <<<<<<<
236 * 2nd
237 * =======
238 * 1st and 3rd
239 * >>>>>>>
240 * Without a ||||||| at all.
241 * so to know if we are in '1' or '2', skip forward
242 * having a peek.
244 peek = cp;
245 while (peek < end) {
246 if (end-peek >= 8 &&
247 (peek[7] == ' ' || peek[7] == '\n')) {
248 if (strncmp(peek, "|||||||", 7) == 0 ||
249 strncmp(peek, ">>>>>>>", 7) == 0)
250 break;
251 else if (strncmp(peek, "=======", 7) == 0) {
252 state = 4;
253 break;
256 skip_eol(&peek, end);
258 } else {
259 char *cp2 = cp;
260 copyline(&r1, &cp2, end);
261 cp2 = cp;
262 copyline(&r2, &cp2, end);
263 copyline(&r3, &cp, end);
265 break;
266 case 1:
267 if (len >= 8 &&
268 strncmp(cp, "|||||||", 7) == 0 &&
269 (cp[7] == ' ' || cp[7] == '\n')
271 state = 2;
272 skip_eol(&cp, end);
273 } else
274 copyline(&r1, &cp, end);
275 break;
276 case 2:
277 if (len >= 8 &&
278 strncmp(cp, "=======", 7) == 0 &&
279 (cp[7] == ' ' || cp[7] == '\n')
281 state = 3;
282 skip_eol(&cp, end);
283 } else
284 copyline(&r2, &cp, end);
285 break;
286 case 3:
287 if (len >= 8 &&
288 strncmp(cp, ">>>>>>>", 7) == 0 &&
289 (cp[7] == ' ' || cp[7] == '\n')
291 state = 0;
292 skip_eol(&cp, end);
293 } else
294 copyline(&r3, &cp, end);
295 break;
296 case 4:
297 if (len >= 8 &&
298 strncmp(cp, "=======", 7) == 0 &&
299 (cp[7] == ' ' || cp[7] == '\n')
301 state = 5;
302 skip_eol(&cp, end);
303 } else
304 copyline(&r2, &cp, end);
305 break;
306 case 5:
307 if (len >= 8 &&
308 strncmp(cp, ">>>>>>>", 7) == 0 &&
309 (cp[7] == ' ' || cp[7] == '\n')
311 state = 0;
312 skip_eol(&cp, end);
313 } else {
314 char *t = cp;
315 copyline(&r1, &t, end);
316 copyline(&r3, &cp, end);
318 break;
321 *f1 = r1;
322 *f2 = r2;
323 *f3 = r3;
324 return state == 0;