]> git.neil.brown.name Git - wiggle.git/blob - extract.c
Browse: make sure 'X' doesn't loop forever searching backwards.
[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
71         f1->body = f2->body = NULL;
72
73         r1.body = xmalloc(f.len);
74         r2.body = xmalloc(f.len);
75         r1.len = r2.len = 0;
76
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
85                  */
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;
97
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;
114                         }
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;
123                         }
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;
130                         }
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;
144                         }
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;
158                         }
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;
180                         }
181                         if (acnt <= 0 && bcnt <= 0)
182                                 state = 0;
183                         break;
184                 }
185         }
186         if (r1.len > f.len || r2.len > f.len)
187                 abort();
188         *f1 = r1;
189         *f2 = r2;
190         return chunks;
191 }
192
193 /*
194  * extract parts of a "diff3 -m" or "wiggle -m" output
195  */
196 int split_merge(struct stream f, struct stream *f1, struct stream *f2, struct stream *f3)
197 {
198         int state = 0;
199         char *cp, *end;
200         struct stream r1, r2, r3;
201         f1->body = NULL;
202         f2->body = NULL;
203
204         r1.body = xmalloc(f.len);
205         r2.body = xmalloc(f.len);
206         r3.body = xmalloc(f.len);
207         r1.len = r2.len = r3.len = 0;
208
209         cp = f.body;
210         end = f.body+f.len;
211         while (cp < end) {
212                 /* state:
213                  *  0 not in conflict
214                  *  1 in file 1 of conflict
215                  *  2 in file 2 of conflict
216                  *  3 in file 3 of conflict
217                  *  4 in file 2 but expecting 1/3 next
218                  *  5 in file 1/3
219                  */
220                 int len = end-cp;
221                 switch (state) {
222                 case 0:
223                         if (len >= 8 &&
224                             strncmp(cp, "<<<<<<<", 7) == 0 &&
225                             (cp[7] == ' ' || cp[7] == '\n')
226                                 ) {
227                                 char *peek;
228                                 state = 1;
229                                 skip_eol(&cp, end);
230                                 /* diff3 will do something a bit strange in
231                                  * the 1st and 3rd sections are the same.
232                                  * it reports
233                                  * <<<<<<<
234                                  * 2nd
235                                  * =======
236                                  * 1st and 3rd
237                                  * >>>>>>>
238                                  * Without a ||||||| at all.
239                                  * so to know if we are in '1' or '2', skip forward
240                                  * having a peek.
241                                  */
242                                 peek = cp;
243                                 while (peek < end) {
244                                         if (end-peek >= 8 &&
245                                             (peek[7] == ' ' || peek[7] == '\n')) {
246                                                 if (strncmp(peek, "|||||||", 7) == 0 ||
247                                                     strncmp(peek, ">>>>>>>", 7) == 0)
248                                                         break;
249                                                 else if (strncmp(peek, "=======", 7) == 0) {
250                                                         state = 4;
251                                                         break;
252                                                 }
253                                         }
254                                         skip_eol(&peek, end);
255                                 }
256                         } else {
257                                 char *cp2 = cp;
258                                 copyline(&r1, &cp2, end);
259                                 cp2 = cp;
260                                 copyline(&r2, &cp2, end);
261                                 copyline(&r3, &cp, end);
262                         }
263                         break;
264                 case 1:
265                         if (len >= 8 &&
266                             strncmp(cp, "|||||||", 7) == 0 &&
267                             (cp[7] == ' ' || cp[7] == '\n')
268                                 ) {
269                                 state = 2;
270                                 skip_eol(&cp, end);
271                         } else
272                                 copyline(&r1, &cp, end);
273                         break;
274                 case 2:
275                         if (len >= 8 &&
276                             strncmp(cp, "=======", 7) == 0 &&
277                             (cp[7] == ' ' || cp[7] == '\n')
278                                 ) {
279                                 state = 3;
280                                 skip_eol(&cp, end);
281                         } else
282                                 copyline(&r2, &cp, end);
283                         break;
284                 case 3:
285                         if (len >= 8 &&
286                             strncmp(cp, ">>>>>>>", 7) == 0 &&
287                             (cp[7] == ' ' || cp[7] == '\n')
288                                 ) {
289                                 state = 0;
290                                 skip_eol(&cp, end);
291                         } else
292                                 copyline(&r3, &cp, end);
293                         break;
294                 case 4:
295                         if (len >= 8 &&
296                             strncmp(cp, "=======", 7) == 0 &&
297                             (cp[7] == ' ' || cp[7] == '\n')
298                                 ) {
299                                 state = 5;
300                                 skip_eol(&cp, end);
301                         } else
302                                 copyline(&r2, &cp, end);
303                         break;
304                 case 5:
305                         if (len >= 8 &&
306                             strncmp(cp, ">>>>>>>", 7) == 0 &&
307                             (cp[7] == ' ' || cp[7] == '\n')
308                                 ) {
309                                 state = 0;
310                                 skip_eol(&cp, end);
311                         } else {
312                                 char *t = cp;
313                                 copyline(&r1, &t, end);
314                                 copyline(&r3, &cp, end);
315                         }
316                         break;
317                 }
318         }
319         *f1 = r1;
320         *f2 = r2;
321         *f3 = r3;
322         return state == 0;
323 }