New release: v1.3
[wiggle/upstream.git] / extract.c
blob345b9da3b7b86b38bd57daf909a3e4a06f057851
1 /*
2 * wiggle - apply rejected patches
4 * Copyright (C) 2003 Neil Brown <neilb@cse.unsw.edu.au>
5 * Copyright (C) 2010-2013 Neil Brown <neilb@suse.de>
6 * Copyright (C) 2014-2020 Neil Brown <neil@brown.name>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program.
22 * Author: Neil Brown
23 * Email: <neil@brown.name>
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 wiggle_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];
70 char func[100];
72 f1->body = f2->body = NULL;
74 r1.body = wiggle_xmalloc(f.len);
75 r2.body = wiggle_xmalloc(f.len);
76 r1.len = r2.len = 0;
77 func[0] = 0;
79 cp = f.body;
80 end = f.body+f.len;
81 while (cp < end) {
82 /* state:
83 * 0 not in a patch
84 * 1 first half of context
85 * 2 second half of context
86 * 3 unified
88 lineno++;
89 switch (state) {
90 case 0:
91 if (sscanf(cp, "@@ -%99s +%99s @@%99[^\n]", before, after, func) >= 2) {
92 int ok = 1;
93 if (sscanf(before, "%d,%d", &a, &b) == 2)
94 acnt = b;
95 else if (sscanf(before, "%d", &a) == 1)
96 acnt = 1;
97 else
98 ok = 0;
100 if (sscanf(after, "%d,%d", &c, &d) == 2)
101 bcnt = d;
102 else if (sscanf(after, "%d", &c) == 1)
103 bcnt = 1;
104 else
105 ok = 0;
106 if (ok)
107 state = 3;
108 else
109 state = 0;
110 } else if (sscanf(cp, "*** %d,%d ****", &a, &b) == 2) {
111 acnt = b-a+1;
112 state = 1;
113 } else if (sscanf(cp, "--- %d,%d ----", &c, &d) == 2) {
114 bcnt = d-c+1;
115 state = 2;
116 } else
117 sscanf(cp, "***************%99[^\n]", func);
119 skip_eol(&cp, end);
120 if (state == 1 || state == 3) {
121 char *f;
122 int slen;
123 /* Reserve enough space for 3 integers separated
124 * by a single space, and prefixed and terminated
125 * with a null character.
127 char buf[(3*12)+1];
128 buf[0] = 0;
129 chunks++;
130 slen = sprintf(buf+1, "%5d %5d %5d", chunks, a, acnt)+1;
131 memcpy(r1.body+r1.len, buf, slen);
132 r1.len += slen;
133 f = func;
134 while (*f == ' ')
135 f++;
136 if (*f) {
137 r1.body[r1.len++] = ' ';
138 strcpy(r1.body + r1.len, f);
139 r1.len += strlen(f);
141 r1.body[r1.len++] = '\n';
142 r1.body[r1.len++] = '\0';
144 if (state == 2 || state == 3) {
145 int slen;
146 /* Reserve enough space for 3 integers separated
147 * by a single space, prefixed with a null character
148 * and terminated with a new line and null character.
150 char buf[(3*12)+2];
151 buf[0] = 0;
152 slen = sprintf(buf+1, "%5d %5d %5d\n", chunks, c, bcnt)+2;
153 memcpy(r2.body+r2.len, buf, slen);
154 r2.len += slen;
156 if (state)
157 func[0] = 0;
158 break;
159 case 1:
160 if ((*cp == ' ' || *cp == '!' || *cp == '-' || *cp == '+')
161 && cp[1] == ' ') {
162 cp += 2;
163 copyline(&r1, &cp, end);
164 acnt--;
165 if (acnt == 0)
166 state = 0;
167 } else {
168 fprintf(stderr, "%s: bad context patch at line %d\n",
169 wiggle_Cmd, lineno);
170 return 0;
172 break;
173 case 2:
174 if ((*cp == ' ' || *cp == '!' || *cp == '-' || *cp == '+')
175 && cp[1] == ' ') {
176 cp += 2;
177 copyline(&r2, &cp, end);
178 bcnt--;
179 if (bcnt == 0)
180 state = 0;
181 } else {
182 fprintf(stderr, "%s: bad context patch/2 at line %d\n",
183 wiggle_Cmd, lineno);
184 return 0;
186 break;
187 case 3:
188 if (*cp == ' ') {
189 char *cp2;
190 cp++;
191 cp2 = cp;
192 copyline(&r1, &cp, end);
193 copyline(&r2, &cp2, end);
194 acnt--; bcnt--;
195 } else if (*cp == '-') {
196 cp++;
197 copyline(&r1, &cp, end);
198 acnt--;
199 } else if (*cp == '+') {
200 cp++;
201 copyline(&r2, &cp, end);
202 bcnt--;
203 } else if (*cp == '\n') {
204 /* Empty line - treat like " \n" - a blank line in both */
205 char *cp2 = cp;
206 copyline(&r1, &cp, end);
207 copyline(&r2, &cp2, end);
208 acnt --; bcnt--;
209 } else {
210 fprintf(stderr, "%s: bad unified patch at line %d\n",
211 wiggle_Cmd, lineno);
212 return 0;
214 if (acnt <= 0 && bcnt <= 0)
215 state = 0;
216 break;
219 if (r1.len > f.len || r2.len > f.len)
220 abort();
221 *f1 = r1;
222 *f2 = r2;
223 return chunks;
227 * extract parts of a "diff3 -m" or "wiggle -m" output
229 int wiggle_split_merge(struct stream f, struct stream *f1, struct stream *f2,
230 struct stream *f3)
232 int state = 0;
233 char *cp, *end;
234 struct stream r1, r2, r3;
235 f1->body = NULL;
236 f2->body = NULL;
238 r1.body = wiggle_xmalloc(f.len);
239 r2.body = wiggle_xmalloc(f.len);
240 r3.body = wiggle_xmalloc(f.len);
241 r1.len = r2.len = r3.len = 0;
243 cp = f.body;
244 end = f.body+f.len;
245 while (cp < end) {
246 /* state:
247 * 0 not in conflict
248 * 1 in file 1 of conflict
249 * 2 in file 2 of conflict
250 * 3 in file 3 of conflict
251 * 4 in file 2 but expecting 1/3 next
252 * 5 in file 1/3
254 int len = end-cp;
255 switch (state) {
256 case 0:
257 if (len >= 8 &&
258 strncmp(cp, "<<<<<<<", 7) == 0 &&
259 (cp[7] == ' ' || cp[7] == '\n')
261 char *peek;
262 state = 1;
263 skip_eol(&cp, end);
264 /* diff3 will do something a bit strange in
265 * the 1st and 3rd sections are the same.
266 * it reports
267 * <<<<<<<
268 * 2nd
269 * =======
270 * 1st and 3rd
271 * >>>>>>>
272 * Without a ||||||| at all.
273 * so to know if we are in '1' or '2', skip forward
274 * having a peek.
276 peek = cp;
277 while (peek < end) {
278 if (end-peek >= 8 &&
279 (peek[7] == ' ' || peek[7] == '\n')) {
280 if (strncmp(peek, "|||||||", 7) == 0 ||
281 strncmp(peek, ">>>>>>>", 7) == 0)
282 break;
283 else if (strncmp(peek, "=======", 7) == 0) {
284 state = 4;
285 break;
288 skip_eol(&peek, end);
290 } else {
291 char *cp2 = cp;
292 copyline(&r1, &cp2, end);
293 cp2 = cp;
294 copyline(&r2, &cp2, end);
295 copyline(&r3, &cp, end);
297 break;
298 case 1:
299 if (len >= 8 &&
300 strncmp(cp, "|||||||", 7) == 0 &&
301 (cp[7] == ' ' || cp[7] == '\n')
303 state = 2;
304 skip_eol(&cp, end);
305 } else
306 copyline(&r1, &cp, end);
307 break;
308 case 2:
309 if (len >= 8 &&
310 strncmp(cp, "=======", 7) == 0 &&
311 (cp[7] == ' ' || cp[7] == '\n')
313 state = 3;
314 skip_eol(&cp, end);
315 } else
316 copyline(&r2, &cp, end);
317 break;
318 case 3:
319 if (len >= 8 &&
320 strncmp(cp, ">>>>>>>", 7) == 0 &&
321 (cp[7] == ' ' || cp[7] == '\n')
323 state = 0;
324 skip_eol(&cp, end);
325 } else
326 copyline(&r3, &cp, end);
327 break;
328 case 4:
329 if (len >= 8 &&
330 strncmp(cp, "=======", 7) == 0 &&
331 (cp[7] == ' ' || cp[7] == '\n')
333 state = 5;
334 skip_eol(&cp, end);
335 } else
336 copyline(&r2, &cp, end);
337 break;
338 case 5:
339 if (len >= 8 &&
340 strncmp(cp, ">>>>>>>", 7) == 0 &&
341 (cp[7] == ' ' || cp[7] == '\n')
343 state = 0;
344 skip_eol(&cp, end);
345 } else {
346 char *t = cp;
347 copyline(&r1, &t, end);
348 copyline(&r3, &cp, end);
350 break;
353 if (cp > end)
354 abort();
355 *f1 = r1;
356 *f2 = r2;
357 *f3 = r3;
358 return state == 0;