]> git.neil.brown.name Git - wiggle.git/blob - extract.c
Disable *all* backups when --no-backups used
[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-2013 Neil Brown <neilb@suse.de>
6  * Copyright (C) 2014-2020 Neil Brown <neil@brown.name>
7  *
8  *
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.
13  *
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.
18  *
19  *    You should have received a copy of the GNU General Public License
20  *    along with this program.
21  *
22  *    Author: Neil Brown
23  *    Email: <neil@brown.name>
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 wiggle_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 = wiggle_xmalloc(f.len);
75         r2.body = wiggle_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                                 int slen;
123                                 /* Reserve enough space for 3 integers separated
124                                  * by a single space, and prefixed and terminated
125                                  * with a null character.
126                                  */
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);
140                                 }
141                                 r1.body[r1.len++] = '\n';
142                                 r1.body[r1.len++] = '\0';
143                         }
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.
149                                  */
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;
155                         }
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;
171                         }
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;
185                         }
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;
213                         }
214                         if (acnt <= 0 && bcnt <= 0)
215                                 state = 0;
216                         break;
217                 }
218         }
219         if (r1.len > f.len || r2.len > f.len)
220                 abort();
221         *f1 = r1;
222         *f2 = r2;
223         return chunks;
224 }
225
226 /*
227  * extract parts of a "diff3 -m" or "wiggle -m" output
228  */
229 int wiggle_split_merge(struct stream f, struct stream *f1, struct stream *f2,
230                        struct stream *f3)
231 {
232         int state = 0;
233         char *cp, *end;
234         struct stream r1, r2, r3;
235         f1->body = NULL;
236         f2->body = NULL;
237
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;
242
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
253                  */
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')
260                                 ) {
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.
275                                  */
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;
286                                                 }
287                                         }
288                                         skip_eol(&peek, end);
289                                 }
290                         } else {
291                                 char *cp2 = cp;
292                                 copyline(&r1, &cp2, end);
293                                 cp2 = cp;
294                                 copyline(&r2, &cp2, end);
295                                 copyline(&r3, &cp, end);
296                         }
297                         break;
298                 case 1:
299                         if (len >= 8 &&
300                             strncmp(cp, "|||||||", 7) == 0 &&
301                             (cp[7] == ' ' || cp[7] == '\n')
302                                 ) {
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')
312                                 ) {
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')
322                                 ) {
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')
332                                 ) {
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')
342                                 ) {
343                                 state = 0;
344                                 skip_eol(&cp, end);
345                         } else {
346                                 char *t = cp;
347                                 copyline(&r1, &t, end);
348                                 copyline(&r3, &cp, end);
349                         }
350                         break;
351                 }
352         }
353         if (cp > end)
354                 abort();
355         *f1 = r1;
356         *f2 = r2;
357         *f3 = r3;
358         return state == 0;
359 }