comparison toys/posix/patch.c @ 694:786841fdb1e0

Reindent to two spaces per level. Remove vi: directives that haven't worked right in years (ubuntu broke its' vim implementation). Remove trailing spaces. Add/remove blank lines. Re-wordwrap in places. Update documentation with new coding style. The actual code should be the same afterward, this is just cosmetic refactoring.
author Rob Landley <rob@landley.net>
date Tue, 13 Nov 2012 17:14:08 -0600
parents a81cf364764d
children 98c396477e0b
comparison
equal deleted inserted replaced
693:4a5a250e0633 694:786841fdb1e0
1 /* vi: set sw=4 ts=4: 1 /* patch.c - Apply a "universal" diff.
2 *
3 * patch.c - Apply a "universal" diff.
4 * 2 *
5 * Copyright 2007 Rob Landley <rob@landley.net> 3 * Copyright 2007 Rob Landley <rob@landley.net>
6 * 4 *
7 * see http://opengroup.org/onlinepubs/9699919799/utilities/patch.html 5 * see http://opengroup.org/onlinepubs/9699919799/utilities/patch.html
8 * (But only does -u, because who still cares about "ed"?) 6 * (But only does -u, because who still cares about "ed"?)
22 * [file] which file to patch 20 * [file] which file to patch
23 21
24 USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN)) 22 USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN))
25 23
26 config PATCH 24 config PATCH
27 bool "patch" 25 bool "patch"
28 default y 26 default y
29 help 27 help
30 usage: patch [-i file] [-p depth] [-Ru] 28 usage: patch [-i file] [-p depth] [-Ru]
31 29
32 Apply a unified diff to one or more files. 30 Apply a unified diff to one or more files.
33 31
34 -i Input file (defaults=stdin) 32 -i Input file (defaults=stdin)
35 -l Loose match (ignore whitespace) 33 -l Loose match (ignore whitespace)
36 -p Number of '/' to strip from start of file paths (default=all) 34 -p Number of '/' to strip from start of file paths (default=all)
37 -R Reverse patch. 35 -R Reverse patch.
38 -u Ignored (only handles "unified" diffs) 36 -u Ignored (only handles "unified" diffs)
39 37
40 This version of patch only handles unified diffs, and only modifies 38 This version of patch only handles unified diffs, and only modifies
41 a file when all all hunks to that file apply. Patch prints failed 39 a file when all all hunks to that file apply. Patch prints failed
42 hunks to stderr, and exits with nonzero status if any hunks fail. 40 hunks to stderr, and exits with nonzero status if any hunks fail.
43 41
44 A file compared against /dev/null (or with a date <= the epoch) is 42 A file compared against /dev/null (or with a date <= the epoch) is
45 created/deleted as appropriate. 43 created/deleted as appropriate.
46 */ 44 */
47 45
48 #define FOR_patch 46 #define FOR_patch
49 #include "toys.h" 47 #include "toys.h"
50 48
51 GLOBALS( 49 GLOBALS(
52 char *infile; 50 char *infile;
53 long prefix; 51 long prefix;
54 52
55 struct double_list *current_hunk; 53 struct double_list *current_hunk;
56 long oldline, oldlen, newline, newlen; 54 long oldline, oldlen, newline, newlen;
57 long linenum; 55 long linenum;
58 int context, state, filein, fileout, filepatch, hunknum; 56 int context, state, filein, fileout, filepatch, hunknum;
59 char *tempname; 57 char *tempname;
60 ) 58 )
61 59
62 // Dispose of a line of input, either by writing it out or discarding it. 60 // Dispose of a line of input, either by writing it out or discarding it.
63 61
64 // state < 2: just free 62 // state < 2: just free
68 66
69 #define PATCH_DEBUG (CFG_TOYBOX_DEBUG && (toys.optflags & 32)) 67 #define PATCH_DEBUG (CFG_TOYBOX_DEBUG && (toys.optflags & 32))
70 68
71 static void do_line(void *data) 69 static void do_line(void *data)
72 { 70 {
73 struct double_list *dlist = (struct double_list *)data; 71 struct double_list *dlist = (struct double_list *)data;
74 72
75 if (TT.state>1 && *dlist->data != TT.state) { 73 if (TT.state>1 && *dlist->data != TT.state) {
76 char *s = dlist->data+(TT.state>3 ? 1 : 0); 74 char *s = dlist->data+(TT.state>3 ? 1 : 0);
77 int i = TT.state == 2 ? 2 : TT.fileout; 75 int i = TT.state == 2 ? 2 : TT.fileout;
78 76
79 xwrite(i, s, strlen(s)); 77 xwrite(i, s, strlen(s));
80 xwrite(i, "\n", 1); 78 xwrite(i, "\n", 1);
81 } 79 }
82 80
83 if (PATCH_DEBUG) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data); 81 if (PATCH_DEBUG) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data);
84 82
85 free(dlist->data); 83 free(dlist->data);
86 free(data); 84 free(data);
87 } 85 }
88 86
89 static void finish_oldfile(void) 87 static void finish_oldfile(void)
90 { 88 {
91 if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); 89 if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname);
92 TT.fileout = TT.filein = -1; 90 TT.fileout = TT.filein = -1;
93 } 91 }
94 92
95 static void fail_hunk(void) 93 static void fail_hunk(void)
96 { 94 {
97 if (!TT.current_hunk) return; 95 if (!TT.current_hunk) return;
98 TT.current_hunk->prev->next = 0; 96 TT.current_hunk->prev->next = 0;
99 97
100 fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n", 98 fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n",
101 TT.hunknum, TT.oldline, TT.newline); 99 TT.hunknum, TT.oldline, TT.newline);
102 toys.exitval = 1; 100 toys.exitval = 1;
103 101
104 // If we got to this point, we've seeked to the end. Discard changes to 102 // If we got to this point, we've seeked to the end. Discard changes to
105 // this file and advance to next file. 103 // this file and advance to next file.
106 104
107 TT.state = 2; 105 TT.state = 2;
108 llist_traverse(TT.current_hunk, do_line); 106 llist_traverse(TT.current_hunk, do_line);
109 TT.current_hunk = NULL; 107 TT.current_hunk = NULL;
110 delete_tempfile(TT.filein, TT.fileout, &TT.tempname); 108 delete_tempfile(TT.filein, TT.fileout, &TT.tempname);
111 TT.state = 0; 109 TT.state = 0;
112 } 110 }
113 111
114 // Compare ignoring whitespace. Just returns 112 // Compare ignoring whitespace. Just returns
115 static int loosecmp(char *aa, char *bb) 113 static int loosecmp(char *aa, char *bb)
116 { 114 {
117 int a = 0, b = 0; 115 int a = 0, b = 0;
118 116
119 for (;;) { 117 for (;;) {
120 while (isspace(aa[a])) a++; 118 while (isspace(aa[a])) a++;
121 while (isspace(bb[b])) b++; 119 while (isspace(bb[b])) b++;
122 if (aa[a] != bb[b]) return 1; 120 if (aa[a] != bb[b]) return 1;
123 if (!aa[a]) return 0; 121 if (!aa[a]) return 0;
124 a++, b++; 122 a++, b++;
125 } 123 }
126 } 124 }
127 125
128 // Given a hunk of a unified diff, make the appropriate change to the file. 126 // Given a hunk of a unified diff, make the appropriate change to the file.
129 // This does not use the location information, but instead treats a hunk 127 // This does not use the location information, but instead treats a hunk
130 // as a sort of regex. Copies data from input to output until it finds 128 // as a sort of regex. Copies data from input to output until it finds
132 // (Finding EOF first is an error.) This is a single pass operation, so 130 // (Finding EOF first is an error.) This is a single pass operation, so
133 // multiple hunks must occur in order in the file. 131 // multiple hunks must occur in order in the file.
134 132
135 static int apply_one_hunk(void) 133 static int apply_one_hunk(void)
136 { 134 {
137 struct double_list *plist, *buf = NULL, *check; 135 struct double_list *plist, *buf = NULL, *check;
138 int matcheof = 0, reverse = toys.optflags & FLAG_R, backwarn = 0; 136 int matcheof = 0, reverse = toys.optflags & FLAG_R, backwarn = 0;
139 int (*lcmp)(char *aa, char *bb); 137 int (*lcmp)(char *aa, char *bb);
140 138
141 lcmp = (toys.optflags & FLAG_l) ? (void *)loosecmp : (void *)strcmp; 139 lcmp = (toys.optflags & FLAG_l) ? (void *)loosecmp : (void *)strcmp;
142 140
143 // Break doubly linked list so we can use singly linked traversal function. 141 // Break doubly linked list so we can use singly linked traversal function.
144 TT.current_hunk->prev->next = NULL; 142 TT.current_hunk->prev->next = NULL;
145 143
146 // Match EOF if there aren't as many ending context lines as beginning 144 // Match EOF if there aren't as many ending context lines as beginning
147 for (plist = TT.current_hunk; plist; plist = plist->next) { 145 for (plist = TT.current_hunk; plist; plist = plist->next) {
148 if (plist->data[0]==' ') matcheof++; 146 if (plist->data[0]==' ') matcheof++;
149 else matcheof = 0; 147 else matcheof = 0;
150 if (PATCH_DEBUG) fprintf(stderr, "HUNK:%s\n", plist->data); 148 if (PATCH_DEBUG) fprintf(stderr, "HUNK:%s\n", plist->data);
151 } 149 }
152 matcheof = matcheof < TT.context; 150 matcheof = matcheof < TT.context;
153 151
154 if (PATCH_DEBUG) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); 152 if (PATCH_DEBUG) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
155 153
156 // Loop through input data searching for this hunk. Match all context 154 // Loop through input data searching for this hunk. Match all context
157 // lines and all lines to be removed until we've found the end of a 155 // lines and all lines to be removed until we've found the end of a
158 // complete hunk. 156 // complete hunk.
159 plist = TT.current_hunk; 157 plist = TT.current_hunk;
160 buf = NULL; 158 buf = NULL;
161 if (TT.context) for (;;) { 159 if (TT.context) for (;;) {
162 char *data = get_line(TT.filein); 160 char *data = get_line(TT.filein);
163 161
164 TT.linenum++; 162 TT.linenum++;
165 163
166 // Figure out which line of hunk to compare with next. (Skip lines 164 // Figure out which line of hunk to compare with next. (Skip lines
167 // of the hunk we'd be adding.) 165 // of the hunk we'd be adding.)
168 while (plist && *plist->data == "+-"[reverse]) { 166 while (plist && *plist->data == "+-"[reverse]) {
169 if (data && !lcmp(data, plist->data+1)) { 167 if (data && !lcmp(data, plist->data+1)) {
170 if (!backwarn) backwarn = TT.linenum; 168 if (!backwarn) backwarn = TT.linenum;
171 } 169 }
172 plist = plist->next; 170 plist = plist->next;
173 } 171 }
174 172
175 // Is this EOF? 173 // Is this EOF?
176 if (!data) { 174 if (!data) {
177 if (PATCH_DEBUG) fprintf(stderr, "INEOF\n"); 175 if (PATCH_DEBUG) fprintf(stderr, "INEOF\n");
178 176
179 // Does this hunk need to match EOF? 177 // Does this hunk need to match EOF?
180 if (!plist && matcheof) break; 178 if (!plist && matcheof) break;
181 179
182 if (backwarn) 180 if (backwarn)
183 fprintf(stderr, "Possibly reversed hunk %d at %ld\n", 181 fprintf(stderr, "Possibly reversed hunk %d at %ld\n",
184 TT.hunknum, TT.linenum); 182 TT.hunknum, TT.linenum);
185 183
186 // File ended before we found a place for this hunk. 184 // File ended before we found a place for this hunk.
187 fail_hunk(); 185 fail_hunk();
188 goto done; 186 goto done;
189 } else if (PATCH_DEBUG) fprintf(stderr, "IN: %s\n", data); 187 } else if (PATCH_DEBUG) fprintf(stderr, "IN: %s\n", data);
190 check = dlist_add(&buf, data); 188 check = dlist_add(&buf, data);
191 189
192 // Compare this line with next expected line of hunk. 190 // Compare this line with next expected line of hunk.
193 191
194 // A match can fail because the next line doesn't match, or because 192 // A match can fail because the next line doesn't match, or because
195 // we hit the end of a hunk that needed EOF, and this isn't EOF. 193 // we hit the end of a hunk that needed EOF, and this isn't EOF.
196 194
197 // If match failed, flush first line of buffered data and 195 // If match failed, flush first line of buffered data and
198 // recheck buffered data for a new match until we find one or run 196 // recheck buffered data for a new match until we find one or run
199 // out of buffer. 197 // out of buffer.
200 198
201 for (;;) { 199 for (;;) {
202 if (!plist || lcmp(check->data, plist->data+1)) { 200 if (!plist || lcmp(check->data, plist->data+1)) {
203 // Match failed. Write out first line of buffered data and 201 // Match failed. Write out first line of buffered data and
204 // recheck remaining buffered data for a new match. 202 // recheck remaining buffered data for a new match.
205 203
206 if (PATCH_DEBUG) 204 if (PATCH_DEBUG) fprintf(stderr, "NOT: %s\n", plist->data);
207 fprintf(stderr, "NOT: %s\n", plist->data); 205
208 206 TT.state = 3;
209 TT.state = 3; 207 check = llist_pop(&buf);
210 check = llist_pop(&buf); 208 check->prev->next = buf;
211 check->prev->next = buf; 209 buf->prev = check->prev;
212 buf->prev = check->prev; 210 do_line(check);
213 do_line(check); 211 plist = TT.current_hunk;
214 plist = TT.current_hunk; 212
215 213 // If we've reached the end of the buffer without confirming a
216 // If we've reached the end of the buffer without confirming a 214 // match, read more lines.
217 // match, read more lines. 215 if (check==buf) {
218 if (check==buf) { 216 buf = 0;
219 buf = 0; 217 break;
220 break; 218 }
221 } 219 check = buf;
222 check = buf; 220 } else {
223 } else { 221 if (PATCH_DEBUG) fprintf(stderr, "MAYBE: %s\n", plist->data);
224 if (PATCH_DEBUG) 222 // This line matches. Advance plist, detect successful match.
225 fprintf(stderr, "MAYBE: %s\n", plist->data); 223 plist = plist->next;
226 // This line matches. Advance plist, detect successful match. 224 if (!plist && !matcheof) goto out;
227 plist = plist->next; 225 check = check->next;
228 if (!plist && !matcheof) goto out; 226 if (check == buf) break;
229 check = check->next; 227 }
230 if (check == buf) break; 228 }
231 } 229 }
232 }
233 }
234 out: 230 out:
235 // We have a match. Emit changed data. 231 // We have a match. Emit changed data.
236 TT.state = "-+"[reverse]; 232 TT.state = "-+"[reverse];
237 llist_traverse(TT.current_hunk, do_line); 233 llist_traverse(TT.current_hunk, do_line);
238 TT.current_hunk = NULL; 234 TT.current_hunk = NULL;
239 TT.state = 1; 235 TT.state = 1;
240 done: 236 done:
241 if (buf) { 237 if (buf) {
242 buf->prev->next = NULL; 238 buf->prev->next = NULL;
243 llist_traverse(buf, do_line); 239 llist_traverse(buf, do_line);
244 } 240 }
245 241
246 return TT.state; 242 return TT.state;
247 } 243 }
248 244
249 // Read a patch file and find hunks, opening/creating/deleting files. 245 // Read a patch file and find hunks, opening/creating/deleting files.
250 // Call apply_one_hunk() on each hunk. 246 // Call apply_one_hunk() on each hunk.
251 247
254 // state 2: In hunk: counting initial context lines 250 // state 2: In hunk: counting initial context lines
255 // state 3: In hunk: getting body 251 // state 3: In hunk: getting body
256 252
257 void patch_main(void) 253 void patch_main(void)
258 { 254 {
259 int reverse = toys.optflags&FLAG_R, state = 0, patchlinenum = 0, 255 int reverse = toys.optflags&FLAG_R, state = 0, patchlinenum = 0,
260 strip = 0; 256 strip = 0;
261 char *oldname = NULL, *newname = NULL; 257 char *oldname = NULL, *newname = NULL;
262 258
263 if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY); 259 if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY);
264 TT.filein = TT.fileout = -1; 260 TT.filein = TT.fileout = -1;
265 261
266 // Loop through the lines in the patch 262 // Loop through the lines in the patch
267 for (;;) { 263 for (;;) {
268 char *patchline; 264 char *patchline;
269 265
270 patchline = get_line(TT.filepatch); 266 patchline = get_line(TT.filepatch);
271 if (!patchline) break; 267 if (!patchline) break;
272 268
273 // Other versions of patch accept damaged patches, 269 // Other versions of patch accept damaged patches,
274 // so we need to also. 270 // so we need to also.
275 if (strip || !patchlinenum++) { 271 if (strip || !patchlinenum++) {
276 int len = strlen(patchline); 272 int len = strlen(patchline);
277 if (patchline[len-1] == '\r') { 273 if (patchline[len-1] == '\r') {
278 if (!strip) fprintf(stderr, "Removing DOS newlines\n"); 274 if (!strip) fprintf(stderr, "Removing DOS newlines\n");
279 strip = 1; 275 strip = 1;
280 patchline[len-1]=0; 276 patchline[len-1]=0;
281 } 277 }
282 } 278 }
283 if (!*patchline) { 279 if (!*patchline) {
284 free(patchline); 280 free(patchline);
285 patchline = xstrdup(" "); 281 patchline = xstrdup(" ");
286 } 282 }
287 283
288 // Are we assembling a hunk? 284 // Are we assembling a hunk?
289 if (state >= 2) { 285 if (state >= 2) {
290 if (*patchline==' ' || *patchline=='+' || *patchline=='-') { 286 if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
291 dlist_add(&TT.current_hunk, patchline); 287 dlist_add(&TT.current_hunk, patchline);
292 288
293 if (*patchline != '+') TT.oldlen--; 289 if (*patchline != '+') TT.oldlen--;
294 if (*patchline != '-') TT.newlen--; 290 if (*patchline != '-') TT.newlen--;
295 291
296 // Context line? 292 // Context line?
297 if (*patchline==' ' && state==2) TT.context++; 293 if (*patchline==' ' && state==2) TT.context++;
298 else state=3; 294 else state=3;
299 295
300 // If we've consumed all expected hunk lines, apply the hunk. 296 // If we've consumed all expected hunk lines, apply the hunk.
301 297
302 if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); 298 if (!TT.oldlen && !TT.newlen) state = apply_one_hunk();
303 continue; 299 continue;
304 } 300 }
305 fail_hunk(); 301 fail_hunk();
306 state = 0; 302 state = 0;
307 continue; 303 continue;
308 } 304 }
309 305
310 // Open a new file? 306 // Open a new file?
311 if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { 307 if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) {
312 char *s, **name = &oldname; 308 char *s, **name = &oldname;
313 int i; 309 int i;
314 310
315 if (*patchline == '+') { 311 if (*patchline == '+') {
316 name = &newname; 312 name = &newname;
317 state = 1; 313 state = 1;
318 } 314 }
319 315
320 free(*name); 316 free(*name);
321 finish_oldfile(); 317 finish_oldfile();
322 318
323 // Trim date from end of filename (if any). We don't care. 319 // Trim date from end of filename (if any). We don't care.
324 for (s = patchline+4; *s && *s!='\t'; s++) 320 for (s = patchline+4; *s && *s!='\t'; s++)
325 if (*s=='\\' && s[1]) s++; 321 if (*s=='\\' && s[1]) s++;
326 i = atoi(s); 322 i = atoi(s);
327 if (i>1900 && i<=1970) 323 if (i>1900 && i<=1970) *name = xstrdup("/dev/null");
328 *name = xstrdup("/dev/null"); 324 else {
329 else { 325 *s = 0;
330 *s = 0; 326 *name = xstrdup(patchline+4);
331 *name = xstrdup(patchline+4); 327 }
332 } 328
333 329 // We defer actually opening the file because svn produces broken
334 // We defer actually opening the file because svn produces broken 330 // patches that don't signal they want to create a new file the
335 // patches that don't signal they want to create a new file the 331 // way the patch man page says, so you have to read the first hunk
336 // way the patch man page says, so you have to read the first hunk 332 // and _guess_.
337 // and _guess_. 333
338 334 // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@
339 // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ 335 // but a missing ,value means the value is 1.
340 // but a missing ,value means the value is 1. 336 } else if (state == 1 && !strncmp("@@ -", patchline, 4)) {
341 } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { 337 int i;
342 int i; 338 char *s = patchline+4;
343 char *s = patchline+4; 339
344 340 // Read oldline[,oldlen] +newline[,newlen]
345 // Read oldline[,oldlen] +newline[,newlen] 341
346 342 TT.oldlen = TT.newlen = 1;
347 TT.oldlen = TT.newlen = 1; 343 TT.oldline = strtol(s, &s, 10);
348 TT.oldline = strtol(s, &s, 10); 344 if (*s == ',') TT.oldlen=strtol(s+1, &s, 10);
349 if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); 345 TT.newline = strtol(s+2, &s, 10);
350 TT.newline = strtol(s+2, &s, 10); 346 if (*s == ',') TT.newlen = strtol(s+1, &s, 10);
351 if (*s == ',') TT.newlen = strtol(s+1, &s, 10); 347
352 348 TT.context = 0;
353 TT.context = 0; 349 state = 2;
354 state = 2; 350
355 351 // If this is the first hunk, open the file.
356 // If this is the first hunk, open the file. 352 if (TT.filein == -1) {
357 if (TT.filein == -1) { 353 int oldsum, newsum, del = 0;
358 int oldsum, newsum, del = 0; 354 char *name;
359 char *name; 355
360 356 oldsum = TT.oldline + TT.oldlen;
361 oldsum = TT.oldline + TT.oldlen; 357 newsum = TT.newline + TT.newlen;
362 newsum = TT.newline + TT.newlen; 358
363 359 name = reverse ? oldname : newname;
364 name = reverse ? oldname : newname; 360
365 361 // We're deleting oldname if new file is /dev/null (before -p)
366 // We're deleting oldname if new file is /dev/null (before -p) 362 // or if new hunk is empty (zero context) after patching
367 // or if new hunk is empty (zero context) after patching 363 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum))
368 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) 364 {
369 { 365 name = reverse ? newname : oldname;
370 name = reverse ? newname : oldname; 366 del++;
371 del++; 367 }
372 } 368
373 369 // handle -p path truncation.
374 // handle -p path truncation. 370 for (i = 0, s = name; *s;) {
375 for (i = 0, s = name; *s;) { 371 if ((toys.optflags & FLAG_p) && TT.prefix == i) break;
376 if ((toys.optflags & FLAG_p) && TT.prefix == i) break; 372 if (*s++ != '/') continue;
377 if (*s++ != '/') continue; 373 while (*s == '/') s++;
378 while (*s == '/') s++; 374 name = s;
379 name = s; 375 i++;
380 i++; 376 }
381 } 377
382 378 if (del) {
383 if (del) { 379 printf("removing %s\n", name);
384 printf("removing %s\n", name); 380 xunlink(name);
385 xunlink(name); 381 state = 0;
386 state = 0; 382 // If we've got a file to open, do so.
387 // If we've got a file to open, do so. 383 } else if (!(toys.optflags & FLAG_p) || i <= TT.prefix) {
388 } else if (!(toys.optflags & FLAG_p) || i <= TT.prefix) { 384 // If the old file was null, we're creating a new one.
389 // If the old file was null, we're creating a new one. 385 if ((!strcmp(oldname, "/dev/null") || !oldsum) && access(name, F_OK))
390 if ((!strcmp(oldname, "/dev/null") || !oldsum) 386 {
391 && access(name, F_OK)) 387 printf("creating %s\n", name);
392 { 388 s = strrchr(name, '/');
393 printf("creating %s\n", name); 389 if (s) {
394 s = strrchr(name, '/'); 390 *s = 0;
395 if (s) { 391 xmkpath(name, -1);
396 *s = 0; 392 *s = '/';
397 xmkpath(name, -1); 393 }
398 *s = '/'; 394 TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666);
399 } 395 } else {
400 TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666); 396 printf("patching %s\n", name);
401 } else { 397 TT.filein = xopen(name, O_RDWR);
402 printf("patching %s\n", name); 398 }
403 TT.filein = xopen(name, O_RDWR); 399 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname);
404 } 400 TT.linenum = 0;
405 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); 401 TT.hunknum = 0;
406 TT.linenum = 0; 402 }
407 TT.hunknum = 0; 403 }
408 } 404
409 } 405 TT.hunknum++;
410 406
411 TT.hunknum++; 407 continue;
412 408 }
413 continue; 409
414 } 410 // If we didn't continue above, discard this line.
415 411 free(patchline);
416 // If we didn't continue above, discard this line. 412 }
417 free(patchline); 413
418 } 414 finish_oldfile();
419 415
420 finish_oldfile(); 416 if (CFG_TOYBOX_FREE) {
421 417 close(TT.filepatch);
422 if (CFG_TOYBOX_FREE) { 418 free(oldname);
423 close(TT.filepatch); 419 free(newname);
424 free(oldname); 420 }
425 free(newname); 421 }
426 }
427 }