]> git.neil.brown.name Git - wiggle.git/blob - extract.c
Add --output option to redirect output.
[wiggle.git] / extract.c
1 /*
2  * wiggle - apply rejected patches
3  *
4  * Copyright (C) 2003 Neil Brown <neilb@cse.unsw.edu.au>
5  * Copyright (C) 2010 Neil Brown <neilb@suse.de>
6  *
7  *
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.
12  *
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.
17  *
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.
21  *
22  *    Author: Neil Brown
23  *    Email: <neilb@suse.de>
24  */
25
26 /*
27  * split patch or merge files.
28  */
29
30 #include        "wiggle.h"
31 #include        <stdlib.h>
32
33 /* skip 'cp' past the new '\n', or all the way to 'end' */
34 static void skip_eol(char **cp, char *end)
35 {
36         char *c = *cp;
37         while (c < end && *c != '\n')
38                 c++;
39         if (c < end)
40                 c++;
41         *cp = c;
42 }
43
44 /* copy one line, or to end, from 'cp' into the stream, extending
45  * the stream.
46  */
47 static void copyline(struct stream *s, char **cp, char *end)
48 {
49         char *from = *cp;
50         char *to = s->body+s->len;
51
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;
58 }
59
60 int split_patch(struct stream f, struct stream *f1, struct stream *f2)
61 {
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];
71
72         f1->body = f2->body = NULL;
73
74         r1.body = xmalloc(f.len);
75         r2.body = xmalloc(f.len);
76         r1.len = r2.len = 0;
77         func[0] = 0;
78
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
87                  */
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;
99
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);
118
119                         skip_eol(&cp, end);
120                         if (state == 1 || state == 3) {
121                                 char *f;
122                                 char buf[20];
123                                 buf[0] = 0;
124                                 chunks++;
125                                 sprintf(buf+1, "%5d %5d %5d", chunks, a, acnt);
126                                 memcpy(r1.body+r1.len, buf, 18);
127                                 r1.len += 18;
128                                 f = func;
129                                 while (*f == ' ')
130                                         f++;
131                                 if (*f) {
132                                         r1.body[r1.len++] = ' ';
133                                         strcpy(r1.body + r1.len, f);
134                                         r1.len += strlen(f);
135                                 }
136                                 r1.body[r1.len++] = '\n';
137                                 r1.body[r1.len++] = '\0';
138                         }
139                         if (state == 2 || state == 3) {
140                                 char buf[20];
141                                 buf[0] = 0;
142                                 sprintf(buf+1, "%5d %5d %5d\n", chunks, c, bcnt);
143                                 memcpy(r2.body+r2.len, buf, 20);
144                                 r2.len += 20;
145                         }
146                         if (state)
147                                 func[0] = 0;
148                         break;
149                 case 1:
150                         if ((*cp == ' ' || *cp == '!' || *cp == '-' || *cp == '+')
151                             && cp[1] == ' ') {
152                                 cp += 2;
153                                 copyline(&r1, &cp, end);
154                                 acnt--;
155                                 if (acnt == 0)
156                                         state = 0;
157                         } else {
158                                 fprintf(stderr, "%s: bad context patch at line %d\n",
159                                         Cmd, lineno);
160                                 return 0;
161                         }
162                         break;
163                 case 2:
164                         if ((*cp == ' ' || *cp == '!' || *cp == '-' || *cp == '+')
165                             && cp[1] == ' ') {
166                                 cp += 2;
167                                 copyline(&r2, &cp, end);
168                                 bcnt--;
169                                 if (bcnt == 0)
170                                         state = 0;
171                         } else {
172                                 fprintf(stderr, "%s: bad context patch/2 at line %d\n",
173                                         Cmd, lineno);
174                                 return 0;
175                         }
176                         break;
177                 case 3:
178                         if (*cp == ' ') {
179                                 char *cp2;
180                                 cp++;
181                                 cp2 = cp;
182                                 copyline(&r1, &cp, end);
183                                 copyline(&r2, &cp2, end);
184                                 acnt--; bcnt--;
185                         } else if (*cp == '-') {
186                                 cp++;
187                                 copyline(&r1, &cp, end);
188                                 acnt--;
189                         } else if (*cp == '+') {
190                                 cp++;
191                                 copyline(&r2, &cp, end);
192                                 bcnt--;
193                         } else {
194                                 fprintf(stderr, "%s: bad unified patch at line %d\n",
195                                         Cmd, lineno);
196                                 return 0;
197                         }
198                         if (acnt <= 0 && bcnt <= 0)
199                                 state = 0;
200                         break;
201                 }
202         }
203         if (r1.len > f.len || r2.len > f.len)
204                 abort();
205         *f1 = r1;
206         *f2 = r2;
207         return chunks;
208 }
209
210 /*
211  * extract parts of a "diff3 -m" or "wiggle -m" output
212  */
213 int split_merge(struct stream f, struct stream *f1, struct stream *f2, struct stream *f3)
214 {
215         int state = 0;
216         char *cp, *end;
217         struct stream r1, r2, r3;
218         f1->body = NULL;
219         f2->body = NULL;
220
221         r1.body = xmalloc(f.len);
222         r2.body = xmalloc(f.len);
223         r3.body = xmalloc(f.len);
224         r1.len = r2.len = r3.len = 0;
225
226         cp = f.body;
227         end = f.body+f.len;
228         while (cp < end) {
229                 /* state:
230                  *  0 not in conflict
231                  *  1 in file 1 of conflict
232                  *  2 in file 2 of conflict
233                  *  3 in file 3 of conflict
234                  *  4 in file 2 but expecting 1/3 next
235                  *  5 in file 1/3
236                  */
237                 int len = end-cp;
238                 switch (state) {
239                 case 0:
240                         if (len >= 8 &&
241                             strncmp(cp, "<<<<<<<", 7) == 0 &&
242                             (cp[7] == ' ' || cp[7] == '\n')
243                                 ) {
244                                 char *peek;
245                                 state = 1;
246                                 skip_eol(&cp, end);
247                                 /* diff3 will do something a bit strange in
248                                  * the 1st and 3rd sections are the same.
249                                  * it reports
250                                  * <<<<<<<
251                                  * 2nd
252                                  * =======
253                                  * 1st and 3rd
254                                  * >>>>>>>
255                                  * Without a ||||||| at all.
256                                  * so to know if we are in '1' or '2', skip forward
257                                  * having a peek.
258                                  */
259                                 peek = cp;
260                                 while (peek < end) {
261                                         if (end-peek >= 8 &&
262                                             (peek[7] == ' ' || peek[7] == '\n')) {
263                                                 if (strncmp(peek, "|||||||", 7) == 0 ||
264                                                     strncmp(peek, ">>>>>>>", 7) == 0)
265                                                         break;
266                                                 else if (strncmp(peek, "=======", 7) == 0) {
267                                                         state = 4;
268                                                         break;
269                                                 }
270                                         }
271                                         skip_eol(&peek, end);
272                                 }
273                         } else {
274                                 char *cp2 = cp;
275                                 copyline(&r1, &cp2, end);
276                                 cp2 = cp;
277                                 copyline(&r2, &cp2, end);
278                                 copyline(&r3, &cp, end);
279                         }
280                         break;
281                 case 1:
282                         if (len >= 8 &&
283                             strncmp(cp, "|||||||", 7) == 0 &&
284                             (cp[7] == ' ' || cp[7] == '\n')
285                                 ) {
286                                 state = 2;
287                                 skip_eol(&cp, end);
288                         } else
289                                 copyline(&r1, &cp, end);
290                         break;
291                 case 2:
292                         if (len >= 8 &&
293                             strncmp(cp, "=======", 7) == 0 &&
294                             (cp[7] == ' ' || cp[7] == '\n')
295                                 ) {
296                                 state = 3;
297                                 skip_eol(&cp, end);
298                         } else
299                                 copyline(&r2, &cp, end);
300                         break;
301                 case 3:
302                         if (len >= 8 &&
303                             strncmp(cp, ">>>>>>>", 7) == 0 &&
304                             (cp[7] == ' ' || cp[7] == '\n')
305                                 ) {
306                                 state = 0;
307                                 skip_eol(&cp, end);
308                         } else
309                                 copyline(&r3, &cp, end);
310                         break;
311                 case 4:
312                         if (len >= 8 &&
313                             strncmp(cp, "=======", 7) == 0 &&
314                             (cp[7] == ' ' || cp[7] == '\n')
315                                 ) {
316                                 state = 5;
317                                 skip_eol(&cp, end);
318                         } else
319                                 copyline(&r2, &cp, end);
320                         break;
321                 case 5:
322                         if (len >= 8 &&
323                             strncmp(cp, ">>>>>>>", 7) == 0 &&
324                             (cp[7] == ' ' || cp[7] == '\n')
325                                 ) {
326                                 state = 0;
327                                 skip_eol(&cp, end);
328                         } else {
329                                 char *t = cp;
330                                 copyline(&r1, &t, end);
331                                 copyline(&r3, &cp, end);
332                         }
333                         break;
334                 }
335         }
336         if (cp > end)
337                 abort();
338         *f1 = r1;
339         *f2 = r2;
340         *f3 = r3;
341         return state == 0;
342 }