xref: /aosp_15_r20/external/toybox/toys/posix/patch.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* patch.c - Apply a "universal" diff.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2007 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * see http://opengroup.org/onlinepubs/9699919799/utilities/patch.html
6*cf5a6c84SAndroid Build Coastguard Worker  * (But only does -u, because who still cares about "ed"?)
7*cf5a6c84SAndroid Build Coastguard Worker  *
8*cf5a6c84SAndroid Build Coastguard Worker  * TODO:
9*cf5a6c84SAndroid Build Coastguard Worker  * -b backup
10*cf5a6c84SAndroid Build Coastguard Worker  * -N ignore already applied
11*cf5a6c84SAndroid Build Coastguard Worker  * -D define wrap #ifdef and #ifndef around changes
12*cf5a6c84SAndroid Build Coastguard Worker  * -o outfile output here instead of in place
13*cf5a6c84SAndroid Build Coastguard Worker  * -r rejectfile write rejected hunks to this file
14*cf5a6c84SAndroid Build Coastguard Worker  * -E remove empty files --remove-empty-files
15*cf5a6c84SAndroid Build Coastguard Worker  * git syntax (rename, etc)
16*cf5a6c84SAndroid Build Coastguard Worker 
17*cf5a6c84SAndroid Build Coastguard Worker USE_PATCH(NEWTOY(patch, ">2(no-backup-if-mismatch)(dry-run)F#g#fulp#v(verbose)@d:i:Rs(quiet)[!sv]", TOYFLAG_USR|TOYFLAG_BIN))
18*cf5a6c84SAndroid Build Coastguard Worker 
19*cf5a6c84SAndroid Build Coastguard Worker config PATCH
20*cf5a6c84SAndroid Build Coastguard Worker   bool "patch"
21*cf5a6c84SAndroid Build Coastguard Worker   default y
22*cf5a6c84SAndroid Build Coastguard Worker   help
23*cf5a6c84SAndroid Build Coastguard Worker     usage: patch [-Rlsuv] [-d DIR] [-i FILE] [-p DEPTH] [-F FUZZ] [--dry-run] [FILE [PATCH]]
24*cf5a6c84SAndroid Build Coastguard Worker 
25*cf5a6c84SAndroid Build Coastguard Worker     Apply a unified diff to one or more files.
26*cf5a6c84SAndroid Build Coastguard Worker 
27*cf5a6c84SAndroid Build Coastguard Worker     -d	Modify files in DIR
28*cf5a6c84SAndroid Build Coastguard Worker     -F	Fuzz factor (number of non-matching context lines allowed per hunk)
29*cf5a6c84SAndroid Build Coastguard Worker     -i	Input patch from FILE (default=stdin)
30*cf5a6c84SAndroid Build Coastguard Worker     -l	Loose match (ignore whitespace)
31*cf5a6c84SAndroid Build Coastguard Worker     -p	Number of '/' to strip from start of file paths (default=all)
32*cf5a6c84SAndroid Build Coastguard Worker     -R	Reverse patch
33*cf5a6c84SAndroid Build Coastguard Worker     -s	Silent except for errors
34*cf5a6c84SAndroid Build Coastguard Worker     -v	Verbose (-vv to see decisions)
35*cf5a6c84SAndroid Build Coastguard Worker     --dry-run Don't change files, just confirm patch applies
36*cf5a6c84SAndroid Build Coastguard Worker 
37*cf5a6c84SAndroid Build Coastguard Worker     Only handles "unified" diff format (-u is assumed and ignored). Only
38*cf5a6c84SAndroid Build Coastguard Worker     modifies files when all hunks to that file apply. Prints failed hunks
39*cf5a6c84SAndroid Build Coastguard Worker     to stderr, and exits with nonzero status if any hunks fail.
40*cf5a6c84SAndroid Build Coastguard Worker 
41*cf5a6c84SAndroid Build Coastguard Worker     Files compared against /dev/null (or with a date <= the unix epoch) are
42*cf5a6c84SAndroid Build Coastguard Worker     created/deleted as appropriate. Default -F value is the number of
43*cf5a6c84SAndroid Build Coastguard Worker     leading/trailing context lines minus one (usually 2).
44*cf5a6c84SAndroid Build Coastguard Worker */
45*cf5a6c84SAndroid Build Coastguard Worker 
46*cf5a6c84SAndroid Build Coastguard Worker #define FOR_patch
47*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
48*cf5a6c84SAndroid Build Coastguard Worker 
49*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
50*cf5a6c84SAndroid Build Coastguard Worker   char *i, *d;
51*cf5a6c84SAndroid Build Coastguard Worker   long v, p, g, F;
52*cf5a6c84SAndroid Build Coastguard Worker 
53*cf5a6c84SAndroid Build Coastguard Worker   void *current_hunk;
54*cf5a6c84SAndroid Build Coastguard Worker   long oldline, oldlen, newline, newlen, linenum, outnum;
55*cf5a6c84SAndroid Build Coastguard Worker   int context, state, filein, fileout, filepatch, hunknum;
56*cf5a6c84SAndroid Build Coastguard Worker   char *tempname;
57*cf5a6c84SAndroid Build Coastguard Worker )
58*cf5a6c84SAndroid Build Coastguard Worker 
59*cf5a6c84SAndroid Build Coastguard Worker // TODO xgetline() instead, but replace_tempfile() wants fd...
get_line(int fd)60*cf5a6c84SAndroid Build Coastguard Worker char *get_line(int fd)
61*cf5a6c84SAndroid Build Coastguard Worker {
62*cf5a6c84SAndroid Build Coastguard Worker   char c, *buf = 0;
63*cf5a6c84SAndroid Build Coastguard Worker   long len = 0;
64*cf5a6c84SAndroid Build Coastguard Worker 
65*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
66*cf5a6c84SAndroid Build Coastguard Worker     if (1>read(fd, &c, 1)) break;
67*cf5a6c84SAndroid Build Coastguard Worker     if (!(len & 63)) buf=xrealloc(buf, len+65);
68*cf5a6c84SAndroid Build Coastguard Worker     if ((buf[len++]=c) == '\n') break;
69*cf5a6c84SAndroid Build Coastguard Worker   }
70*cf5a6c84SAndroid Build Coastguard Worker   if (buf) {
71*cf5a6c84SAndroid Build Coastguard Worker     buf[len]=0;
72*cf5a6c84SAndroid Build Coastguard Worker     if (buf[--len]=='\n') buf[len]=0;
73*cf5a6c84SAndroid Build Coastguard Worker   }
74*cf5a6c84SAndroid Build Coastguard Worker 
75*cf5a6c84SAndroid Build Coastguard Worker   return buf;
76*cf5a6c84SAndroid Build Coastguard Worker }
77*cf5a6c84SAndroid Build Coastguard Worker 
78*cf5a6c84SAndroid Build Coastguard Worker // Dispose of a line of input, either by writing it out or discarding it.
79*cf5a6c84SAndroid Build Coastguard Worker 
80*cf5a6c84SAndroid Build Coastguard Worker // state < 2: just free
81*cf5a6c84SAndroid Build Coastguard Worker // state = 2: write whole line to stderr
82*cf5a6c84SAndroid Build Coastguard Worker // state = 3: write whole line to fileout
83*cf5a6c84SAndroid Build Coastguard Worker // state > 3: write line+1 to fileout when *line != state
84*cf5a6c84SAndroid Build Coastguard Worker 
do_line(void * data)85*cf5a6c84SAndroid Build Coastguard Worker static void do_line(void *data)
86*cf5a6c84SAndroid Build Coastguard Worker {
87*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *dlist = data;
88*cf5a6c84SAndroid Build Coastguard Worker 
89*cf5a6c84SAndroid Build Coastguard Worker   TT.outnum++;
90*cf5a6c84SAndroid Build Coastguard Worker   if (TT.state>1)
91*cf5a6c84SAndroid Build Coastguard Worker     if (0>dprintf(TT.state==2 ? 2 : TT.fileout,"%s\n",dlist->data+(TT.state>3)))
92*cf5a6c84SAndroid Build Coastguard Worker       perror_exit("write");
93*cf5a6c84SAndroid Build Coastguard Worker 
94*cf5a6c84SAndroid Build Coastguard Worker   llist_free_double(data);
95*cf5a6c84SAndroid Build Coastguard Worker }
96*cf5a6c84SAndroid Build Coastguard Worker 
finish_oldfile(void)97*cf5a6c84SAndroid Build Coastguard Worker static void finish_oldfile(void)
98*cf5a6c84SAndroid Build Coastguard Worker {
99*cf5a6c84SAndroid Build Coastguard Worker   if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname);
100*cf5a6c84SAndroid Build Coastguard Worker   TT.fileout = TT.filein = -1;
101*cf5a6c84SAndroid Build Coastguard Worker }
102*cf5a6c84SAndroid Build Coastguard Worker 
fail_hunk(void)103*cf5a6c84SAndroid Build Coastguard Worker static void fail_hunk(void)
104*cf5a6c84SAndroid Build Coastguard Worker {
105*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.current_hunk) return;
106*cf5a6c84SAndroid Build Coastguard Worker 
107*cf5a6c84SAndroid Build Coastguard Worker   fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n",
108*cf5a6c84SAndroid Build Coastguard Worker       TT.hunknum, TT.oldline, TT.newline);
109*cf5a6c84SAndroid Build Coastguard Worker   toys.exitval = 1;
110*cf5a6c84SAndroid Build Coastguard Worker 
111*cf5a6c84SAndroid Build Coastguard Worker   // If we got to this point, we've seeked to the end.  Discard changes to
112*cf5a6c84SAndroid Build Coastguard Worker   // this file and advance to next file.
113*cf5a6c84SAndroid Build Coastguard Worker 
114*cf5a6c84SAndroid Build Coastguard Worker   TT.state = 2;
115*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(TT.current_hunk, do_line);
116*cf5a6c84SAndroid Build Coastguard Worker   TT.current_hunk = 0;
117*cf5a6c84SAndroid Build Coastguard Worker   if (!FLAG(dry_run)) delete_tempfile(TT.filein, TT.fileout, &TT.tempname);
118*cf5a6c84SAndroid Build Coastguard Worker   TT.state = 0;
119*cf5a6c84SAndroid Build Coastguard Worker }
120*cf5a6c84SAndroid Build Coastguard Worker 
121*cf5a6c84SAndroid Build Coastguard Worker // Compare ignoring whitespace. Just returns 0/1, no > or <
loosecmp(char * aa,char * bb)122*cf5a6c84SAndroid Build Coastguard Worker static int loosecmp(char *aa, char *bb)
123*cf5a6c84SAndroid Build Coastguard Worker {
124*cf5a6c84SAndroid Build Coastguard Worker   int a = 0, b = 0;
125*cf5a6c84SAndroid Build Coastguard Worker 
126*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
127*cf5a6c84SAndroid Build Coastguard Worker     while (isspace(aa[a])) a++;
128*cf5a6c84SAndroid Build Coastguard Worker     while (isspace(bb[b])) b++;
129*cf5a6c84SAndroid Build Coastguard Worker     if (aa[a] != bb[b]) return 1;
130*cf5a6c84SAndroid Build Coastguard Worker     if (!aa[a]) return 0;
131*cf5a6c84SAndroid Build Coastguard Worker     a++, b++;
132*cf5a6c84SAndroid Build Coastguard Worker   }
133*cf5a6c84SAndroid Build Coastguard Worker }
134*cf5a6c84SAndroid Build Coastguard Worker 
135*cf5a6c84SAndroid Build Coastguard Worker // Given a hunk of a unified diff, make the appropriate change to the file.
136*cf5a6c84SAndroid Build Coastguard Worker // This does not use the location information, but instead treats a hunk
137*cf5a6c84SAndroid Build Coastguard Worker // as a sort of regex. Copies data from input to output until it finds
138*cf5a6c84SAndroid Build Coastguard Worker // the change to be made, then outputs the changed data and returns.
139*cf5a6c84SAndroid Build Coastguard Worker // (Finding EOF first is an error.) This is a single pass operation, so
140*cf5a6c84SAndroid Build Coastguard Worker // multiple hunks must occur in order in the file.
141*cf5a6c84SAndroid Build Coastguard Worker 
apply_one_hunk(void)142*cf5a6c84SAndroid Build Coastguard Worker static int apply_one_hunk(void)
143*cf5a6c84SAndroid Build Coastguard Worker {
144*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *plist, *buf = 0, *check = 0;
145*cf5a6c84SAndroid Build Coastguard Worker   int matcheof, trail = 0, allfuzz = 0, fuzz, ii;
146*cf5a6c84SAndroid Build Coastguard Worker   int (*lcmp)(char *aa, char *bb) = FLAG(l) ? (void *)loosecmp : (void *)strcmp;
147*cf5a6c84SAndroid Build Coastguard Worker   long backwarn = 0;
148*cf5a6c84SAndroid Build Coastguard Worker   char *data = toybuf;
149*cf5a6c84SAndroid Build Coastguard Worker 
150*cf5a6c84SAndroid Build Coastguard Worker   if (TT.v>1) printf("START %d\n", TT.hunknum);
151*cf5a6c84SAndroid Build Coastguard Worker 
152*cf5a6c84SAndroid Build Coastguard Worker   // Match EOF if there aren't as many ending context lines as beginning
153*cf5a6c84SAndroid Build Coastguard Worker   dlist_terminate(TT.current_hunk);
154*cf5a6c84SAndroid Build Coastguard Worker   for (fuzz = 0, plist = TT.current_hunk; plist; plist = plist->next) {
155*cf5a6c84SAndroid Build Coastguard Worker     char *s = plist->data, c = *s;
156*cf5a6c84SAndroid Build Coastguard Worker 
157*cf5a6c84SAndroid Build Coastguard Worker     if (c==' ') trail++;
158*cf5a6c84SAndroid Build Coastguard Worker     else trail = 0;
159*cf5a6c84SAndroid Build Coastguard Worker 
160*cf5a6c84SAndroid Build Coastguard Worker     // Only allow fuzz if 2 context lines have multiple nonwhitespace chars.
161*cf5a6c84SAndroid Build Coastguard Worker     // avoids the "all context was blank or } lines" issue. Removed lines
162*cf5a6c84SAndroid Build Coastguard Worker     // count as context since they're matched.
163*cf5a6c84SAndroid Build Coastguard Worker     if (c==' ' || c=="-+"[FLAG(R)]) {
164*cf5a6c84SAndroid Build Coastguard Worker       while (isspace(*++s));
165*cf5a6c84SAndroid Build Coastguard Worker       if (*s && s[1] && !isspace(s[1])) fuzz++;
166*cf5a6c84SAndroid Build Coastguard Worker     }
167*cf5a6c84SAndroid Build Coastguard Worker   }
168*cf5a6c84SAndroid Build Coastguard Worker   matcheof = !trail || trail < TT.context;
169*cf5a6c84SAndroid Build Coastguard Worker   if (fuzz>1) allfuzz = TT.F ? : TT.context ? TT.context-1 : 0;
170*cf5a6c84SAndroid Build Coastguard Worker 
171*cf5a6c84SAndroid Build Coastguard Worker   // Loop through input data searching for this hunk. Match all context
172*cf5a6c84SAndroid Build Coastguard Worker   // lines and lines to be removed until we've found end of complete hunk.
173*cf5a6c84SAndroid Build Coastguard Worker   plist = TT.current_hunk;
174*cf5a6c84SAndroid Build Coastguard Worker   fuzz = 0;
175*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
176*cf5a6c84SAndroid Build Coastguard Worker     if (data) {
177*cf5a6c84SAndroid Build Coastguard Worker       data = get_line(TT.filein);
178*cf5a6c84SAndroid Build Coastguard Worker       check = data ? dlist_add(&buf, data) : 0;
179*cf5a6c84SAndroid Build Coastguard Worker       TT.linenum++;
180*cf5a6c84SAndroid Build Coastguard Worker     }
181*cf5a6c84SAndroid Build Coastguard Worker     if (TT.v>1) printf("READ[%ld] %s\n", TT.linenum, data ? : "(NULL)");
182*cf5a6c84SAndroid Build Coastguard Worker 
183*cf5a6c84SAndroid Build Coastguard Worker     // Compare buffered line(s) with expected lines of hunk. Match can fail
184*cf5a6c84SAndroid Build Coastguard Worker     // because next line doesn't match, or because we hit end of a hunk that
185*cf5a6c84SAndroid Build Coastguard Worker     // needed EOF and this isn't EOF.
186*cf5a6c84SAndroid Build Coastguard Worker     for (;;) {
187*cf5a6c84SAndroid Build Coastguard Worker       // Find hunk line to match (skip added lines) and detect reverse matches
188*cf5a6c84SAndroid Build Coastguard Worker       while (plist && *plist->data == "+-"[FLAG(R)]) {
189*cf5a6c84SAndroid Build Coastguard Worker         // TODO: proper backwarn = full hunk applies in reverse, not just 1 line
190*cf5a6c84SAndroid Build Coastguard Worker         if (data) {
191*cf5a6c84SAndroid Build Coastguard Worker           ii = strcspn(data, " \t");
192*cf5a6c84SAndroid Build Coastguard Worker           if (data[ii+!!data[ii]] && !lcmp(data, plist->data+1))
193*cf5a6c84SAndroid Build Coastguard Worker             backwarn = TT.linenum;
194*cf5a6c84SAndroid Build Coastguard Worker         }
195*cf5a6c84SAndroid Build Coastguard Worker         plist = plist->next;
196*cf5a6c84SAndroid Build Coastguard Worker       }
197*cf5a6c84SAndroid Build Coastguard Worker       if (TT.v>1 && plist)
198*cf5a6c84SAndroid Build Coastguard Worker         printf("HUNK %s\nLINE %s\n", plist->data+1, check ? check->data : "");
199*cf5a6c84SAndroid Build Coastguard Worker 
200*cf5a6c84SAndroid Build Coastguard Worker       // End of hunk?
201*cf5a6c84SAndroid Build Coastguard Worker       if (!plist) {
202*cf5a6c84SAndroid Build Coastguard Worker         if (TT.v>1) printf("END OF HUNK\n");
203*cf5a6c84SAndroid Build Coastguard Worker         if (matcheof == !data) goto out;
204*cf5a6c84SAndroid Build Coastguard Worker 
205*cf5a6c84SAndroid Build Coastguard Worker       // Compare line and handle match
206*cf5a6c84SAndroid Build Coastguard Worker       } else if (check && !lcmp(check->data, plist->data+1)) {
207*cf5a6c84SAndroid Build Coastguard Worker         if (TT.v>1) printf("MATCH\n");
208*cf5a6c84SAndroid Build Coastguard Worker handle_match:
209*cf5a6c84SAndroid Build Coastguard Worker         plist = plist->next;
210*cf5a6c84SAndroid Build Coastguard Worker         if ((check = check->next) == buf) {
211*cf5a6c84SAndroid Build Coastguard Worker           if (plist || matcheof) break;
212*cf5a6c84SAndroid Build Coastguard Worker           goto out;
213*cf5a6c84SAndroid Build Coastguard Worker         } else continue;
214*cf5a6c84SAndroid Build Coastguard Worker       }
215*cf5a6c84SAndroid Build Coastguard Worker 
216*cf5a6c84SAndroid Build Coastguard Worker       // Did we hit EOF?
217*cf5a6c84SAndroid Build Coastguard Worker       if (!data) {
218*cf5a6c84SAndroid Build Coastguard Worker         if (TT.v>1) printf("EOF\n");
219*cf5a6c84SAndroid Build Coastguard Worker         if (backwarn && !FLAG(s))
220*cf5a6c84SAndroid Build Coastguard Worker           fprintf(stderr, "Possibly reversed hunk %d at %ld\n",
221*cf5a6c84SAndroid Build Coastguard Worker               TT.hunknum, backwarn);
222*cf5a6c84SAndroid Build Coastguard Worker 
223*cf5a6c84SAndroid Build Coastguard Worker         // File ended before we found a place for this hunk.
224*cf5a6c84SAndroid Build Coastguard Worker         fail_hunk();
225*cf5a6c84SAndroid Build Coastguard Worker         goto done;
226*cf5a6c84SAndroid Build Coastguard Worker       }
227*cf5a6c84SAndroid Build Coastguard Worker       if (TT.v>1) printf("NOT MATCH\n");
228*cf5a6c84SAndroid Build Coastguard Worker 
229*cf5a6c84SAndroid Build Coastguard Worker       // Match failed: can we fuzz it?
230*cf5a6c84SAndroid Build Coastguard Worker       if (plist && *plist->data == ' ' && fuzz<allfuzz) {
231*cf5a6c84SAndroid Build Coastguard Worker         fuzz++;
232*cf5a6c84SAndroid Build Coastguard Worker         if (TT.v>1) printf("FUZZ %d %s\n", fuzz, check->data);
233*cf5a6c84SAndroid Build Coastguard Worker         goto handle_match;
234*cf5a6c84SAndroid Build Coastguard Worker       }
235*cf5a6c84SAndroid Build Coastguard Worker 
236*cf5a6c84SAndroid Build Coastguard Worker       // If this hunk must match start of file, fail if it didn't.
237*cf5a6c84SAndroid Build Coastguard Worker       if (!TT.context || trail>TT.context) {
238*cf5a6c84SAndroid Build Coastguard Worker         fail_hunk();
239*cf5a6c84SAndroid Build Coastguard Worker         goto done;
240*cf5a6c84SAndroid Build Coastguard Worker       }
241*cf5a6c84SAndroid Build Coastguard Worker 
242*cf5a6c84SAndroid Build Coastguard Worker       // Write out first line of buffer and recheck rest for new match.
243*cf5a6c84SAndroid Build Coastguard Worker       TT.state = 3;
244*cf5a6c84SAndroid Build Coastguard Worker       if (TT.v>1) printf("WRITE %s\n", buf->data);
245*cf5a6c84SAndroid Build Coastguard Worker       do_line(check = dlist_pop(&buf));
246*cf5a6c84SAndroid Build Coastguard Worker       plist = TT.current_hunk;
247*cf5a6c84SAndroid Build Coastguard Worker       fuzz = 0;
248*cf5a6c84SAndroid Build Coastguard Worker 
249*cf5a6c84SAndroid Build Coastguard Worker       // If end of the buffer without finishing a match, read more lines.
250*cf5a6c84SAndroid Build Coastguard Worker       if (!buf) break;
251*cf5a6c84SAndroid Build Coastguard Worker       check = buf;
252*cf5a6c84SAndroid Build Coastguard Worker     }
253*cf5a6c84SAndroid Build Coastguard Worker   }
254*cf5a6c84SAndroid Build Coastguard Worker out:
255*cf5a6c84SAndroid Build Coastguard Worker   if (TT.v) xprintf("Hunk #%d succeeded at %ld.\n", TT.hunknum, TT.linenum);
256*cf5a6c84SAndroid Build Coastguard Worker   // We have a match.  Emit changed data.
257*cf5a6c84SAndroid Build Coastguard Worker   TT.state = "-+"[FLAG(R)];
258*cf5a6c84SAndroid Build Coastguard Worker   while ((plist = dlist_pop(&TT.current_hunk))) {
259*cf5a6c84SAndroid Build Coastguard Worker     if (TT.state == *plist->data || *plist->data == ' ') {
260*cf5a6c84SAndroid Build Coastguard Worker       if (*plist->data == ' ') dprintf(TT.fileout, "%s\n", buf->data);
261*cf5a6c84SAndroid Build Coastguard Worker       llist_free_double(dlist_pop(&buf));
262*cf5a6c84SAndroid Build Coastguard Worker     } else dprintf(TT.fileout, "%s\n", plist->data+1);
263*cf5a6c84SAndroid Build Coastguard Worker     llist_free_double(plist);
264*cf5a6c84SAndroid Build Coastguard Worker   }
265*cf5a6c84SAndroid Build Coastguard Worker   TT.current_hunk = 0;
266*cf5a6c84SAndroid Build Coastguard Worker   TT.state = 1;
267*cf5a6c84SAndroid Build Coastguard Worker done:
268*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(buf, do_line);
269*cf5a6c84SAndroid Build Coastguard Worker 
270*cf5a6c84SAndroid Build Coastguard Worker   return TT.state;
271*cf5a6c84SAndroid Build Coastguard Worker }
272*cf5a6c84SAndroid Build Coastguard Worker 
273*cf5a6c84SAndroid Build Coastguard Worker // read a filename that has been quoted or escaped
unquote_file(char * filename)274*cf5a6c84SAndroid Build Coastguard Worker static char *unquote_file(char *filename)
275*cf5a6c84SAndroid Build Coastguard Worker {
276*cf5a6c84SAndroid Build Coastguard Worker   char *s = filename, *t, *newfile;
277*cf5a6c84SAndroid Build Coastguard Worker 
278*cf5a6c84SAndroid Build Coastguard Worker   // Return copy of file that wasn't quoted
279*cf5a6c84SAndroid Build Coastguard Worker   if (*s++ != '"' || !*s) return xstrdup(filename);
280*cf5a6c84SAndroid Build Coastguard Worker 
281*cf5a6c84SAndroid Build Coastguard Worker   // quoted and escaped filenames are larger than the original
282*cf5a6c84SAndroid Build Coastguard Worker   for (t = newfile = xmalloc(strlen(s) + 1); *s != '"'; s++) {
283*cf5a6c84SAndroid Build Coastguard Worker     if (!s[1]) error_exit("bad %s", filename);
284*cf5a6c84SAndroid Build Coastguard Worker 
285*cf5a6c84SAndroid Build Coastguard Worker     // don't accept escape sequences unless the filename is quoted
286*cf5a6c84SAndroid Build Coastguard Worker     if (*s != '\\') *t++ = *s;
287*cf5a6c84SAndroid Build Coastguard Worker     else if (*++s >= '0' && *s < '8') {
288*cf5a6c84SAndroid Build Coastguard Worker       *t++ = strtoul(s, &s, 8);
289*cf5a6c84SAndroid Build Coastguard Worker       s--;
290*cf5a6c84SAndroid Build Coastguard Worker     } else {
291*cf5a6c84SAndroid Build Coastguard Worker       if (!(*t = unescape(*s))) *t = *s;;
292*cf5a6c84SAndroid Build Coastguard Worker       t++;
293*cf5a6c84SAndroid Build Coastguard Worker     }
294*cf5a6c84SAndroid Build Coastguard Worker   }
295*cf5a6c84SAndroid Build Coastguard Worker   *t = 0;
296*cf5a6c84SAndroid Build Coastguard Worker 
297*cf5a6c84SAndroid Build Coastguard Worker   return newfile;
298*cf5a6c84SAndroid Build Coastguard Worker }
299*cf5a6c84SAndroid Build Coastguard Worker 
300*cf5a6c84SAndroid Build Coastguard Worker // Read a patch file and find hunks, opening/creating/deleting files.
301*cf5a6c84SAndroid Build Coastguard Worker // Call apply_one_hunk() on each hunk.
302*cf5a6c84SAndroid Build Coastguard Worker 
303*cf5a6c84SAndroid Build Coastguard Worker // state 0: Not in a hunk, look for +++.
304*cf5a6c84SAndroid Build Coastguard Worker // state 1: Found +++ file indicator, look for @@
305*cf5a6c84SAndroid Build Coastguard Worker // state 2: In hunk: counting initial context lines
306*cf5a6c84SAndroid Build Coastguard Worker // state 3: In hunk: getting body
307*cf5a6c84SAndroid Build Coastguard Worker 
patch_main(void)308*cf5a6c84SAndroid Build Coastguard Worker void patch_main(void)
309*cf5a6c84SAndroid Build Coastguard Worker {
310*cf5a6c84SAndroid Build Coastguard Worker   int state = 0, patchlinenum = 0, strip = 0;
311*cf5a6c84SAndroid Build Coastguard Worker   char *oldname = 0, *newname = 0;
312*cf5a6c84SAndroid Build Coastguard Worker 
313*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optc == 2) TT.i = toys.optargs[1];
314*cf5a6c84SAndroid Build Coastguard Worker   if (TT.i) TT.filepatch = xopenro(TT.i);
315*cf5a6c84SAndroid Build Coastguard Worker   TT.filein = TT.fileout = -1;
316*cf5a6c84SAndroid Build Coastguard Worker 
317*cf5a6c84SAndroid Build Coastguard Worker   if (TT.d) xchdir(TT.d);
318*cf5a6c84SAndroid Build Coastguard Worker 
319*cf5a6c84SAndroid Build Coastguard Worker   // Loop through the lines in the patch file (-i or stdin) collecting hunks
320*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
321*cf5a6c84SAndroid Build Coastguard Worker     char *patchline;
322*cf5a6c84SAndroid Build Coastguard Worker 
323*cf5a6c84SAndroid Build Coastguard Worker     if (!(patchline = get_line(TT.filepatch))) break;
324*cf5a6c84SAndroid Build Coastguard Worker 
325*cf5a6c84SAndroid Build Coastguard Worker     // Other versions of patch accept damaged patches, so we need to also.
326*cf5a6c84SAndroid Build Coastguard Worker     if (strip || !patchlinenum++) {
327*cf5a6c84SAndroid Build Coastguard Worker       int len = strlen(patchline);
328*cf5a6c84SAndroid Build Coastguard Worker       if (len && patchline[len-1] == '\r') {
329*cf5a6c84SAndroid Build Coastguard Worker         if (!strip && !FLAG(s)) fprintf(stderr, "Removing DOS newlines\n");
330*cf5a6c84SAndroid Build Coastguard Worker         strip = 1;
331*cf5a6c84SAndroid Build Coastguard Worker         patchline[len-1] = 0;
332*cf5a6c84SAndroid Build Coastguard Worker       }
333*cf5a6c84SAndroid Build Coastguard Worker     }
334*cf5a6c84SAndroid Build Coastguard Worker     if (!*patchline) {
335*cf5a6c84SAndroid Build Coastguard Worker       free(patchline);
336*cf5a6c84SAndroid Build Coastguard Worker       patchline = xstrdup(" ");
337*cf5a6c84SAndroid Build Coastguard Worker     }
338*cf5a6c84SAndroid Build Coastguard Worker 
339*cf5a6c84SAndroid Build Coastguard Worker     // Are we assembling a hunk?
340*cf5a6c84SAndroid Build Coastguard Worker     if (state >= 2) {
341*cf5a6c84SAndroid Build Coastguard Worker       if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
342*cf5a6c84SAndroid Build Coastguard Worker         dlist_add((void *)&TT.current_hunk, patchline);
343*cf5a6c84SAndroid Build Coastguard Worker 
344*cf5a6c84SAndroid Build Coastguard Worker         if (*patchline != '+') TT.oldlen--;
345*cf5a6c84SAndroid Build Coastguard Worker         if (*patchline != '-') TT.newlen--;
346*cf5a6c84SAndroid Build Coastguard Worker 
347*cf5a6c84SAndroid Build Coastguard Worker         // Context line?
348*cf5a6c84SAndroid Build Coastguard Worker         if (*patchline==' ' && state==2) TT.context++;
349*cf5a6c84SAndroid Build Coastguard Worker         else state=3;
350*cf5a6c84SAndroid Build Coastguard Worker 
351*cf5a6c84SAndroid Build Coastguard Worker         // If we've consumed all expected hunk lines, apply the hunk.
352*cf5a6c84SAndroid Build Coastguard Worker         if (!TT.oldlen && !TT.newlen) state = apply_one_hunk();
353*cf5a6c84SAndroid Build Coastguard Worker       } else {
354*cf5a6c84SAndroid Build Coastguard Worker         dlist_terminate(TT.current_hunk);
355*cf5a6c84SAndroid Build Coastguard Worker         fail_hunk();
356*cf5a6c84SAndroid Build Coastguard Worker         state = 0;
357*cf5a6c84SAndroid Build Coastguard Worker       }
358*cf5a6c84SAndroid Build Coastguard Worker       continue;
359*cf5a6c84SAndroid Build Coastguard Worker     }
360*cf5a6c84SAndroid Build Coastguard Worker 
361*cf5a6c84SAndroid Build Coastguard Worker     // Open a new file?
362*cf5a6c84SAndroid Build Coastguard Worker     if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) {
363*cf5a6c84SAndroid Build Coastguard Worker       char *s, **name = &oldname;
364*cf5a6c84SAndroid Build Coastguard Worker       int i;
365*cf5a6c84SAndroid Build Coastguard Worker 
366*cf5a6c84SAndroid Build Coastguard Worker       if (*patchline == '+') {
367*cf5a6c84SAndroid Build Coastguard Worker         name = &newname;
368*cf5a6c84SAndroid Build Coastguard Worker         state = 1;
369*cf5a6c84SAndroid Build Coastguard Worker       }
370*cf5a6c84SAndroid Build Coastguard Worker 
371*cf5a6c84SAndroid Build Coastguard Worker       free(*name);
372*cf5a6c84SAndroid Build Coastguard Worker       finish_oldfile();
373*cf5a6c84SAndroid Build Coastguard Worker 
374*cf5a6c84SAndroid Build Coastguard Worker       // Trim date from end of filename (if any). Date<=epoch means delete.
375*cf5a6c84SAndroid Build Coastguard Worker       for (s = patchline+4; *s && *s!='\t'; s++);
376*cf5a6c84SAndroid Build Coastguard Worker       i = atoi(s);
377*cf5a6c84SAndroid Build Coastguard Worker       if (i>1900 && i<=1970) *name = xstrdup("/dev/null");
378*cf5a6c84SAndroid Build Coastguard Worker       else {
379*cf5a6c84SAndroid Build Coastguard Worker         *s = 0;
380*cf5a6c84SAndroid Build Coastguard Worker         *name = unquote_file(patchline+4);
381*cf5a6c84SAndroid Build Coastguard Worker       }
382*cf5a6c84SAndroid Build Coastguard Worker 
383*cf5a6c84SAndroid Build Coastguard Worker       // We defer actually opening the file because svn produces broken
384*cf5a6c84SAndroid Build Coastguard Worker       // patches that don't signal they want to create a new file the
385*cf5a6c84SAndroid Build Coastguard Worker       // way the patch man page says, so you have to read the first hunk
386*cf5a6c84SAndroid Build Coastguard Worker       // and _guess_.
387*cf5a6c84SAndroid Build Coastguard Worker 
388*cf5a6c84SAndroid Build Coastguard Worker     // Start a new hunk?  Usually @@ -oldline,oldlen +newline,newlen @@
389*cf5a6c84SAndroid Build Coastguard Worker     // but a missing ,value means the value is 1.
390*cf5a6c84SAndroid Build Coastguard Worker     } else if (state == 1 && !strncmp("@@ -", patchline, 4)) {
391*cf5a6c84SAndroid Build Coastguard Worker       int i;
392*cf5a6c84SAndroid Build Coastguard Worker       char *s = patchline+4;
393*cf5a6c84SAndroid Build Coastguard Worker 
394*cf5a6c84SAndroid Build Coastguard Worker       // Read oldline[,oldlen] +newline[,newlen]
395*cf5a6c84SAndroid Build Coastguard Worker 
396*cf5a6c84SAndroid Build Coastguard Worker       TT.oldlen = TT.newlen = 1;
397*cf5a6c84SAndroid Build Coastguard Worker       TT.oldline = strtol(s, &s, 10);
398*cf5a6c84SAndroid Build Coastguard Worker       if (*s == ',') TT.oldlen=strtol(s+1, &s, 10);
399*cf5a6c84SAndroid Build Coastguard Worker       TT.newline = strtol(s+2, &s, 10);
400*cf5a6c84SAndroid Build Coastguard Worker       if (*s == ',') TT.newlen = strtol(s+1, &s, 10);
401*cf5a6c84SAndroid Build Coastguard Worker 
402*cf5a6c84SAndroid Build Coastguard Worker       TT.context = 0;
403*cf5a6c84SAndroid Build Coastguard Worker       state = 2;
404*cf5a6c84SAndroid Build Coastguard Worker 
405*cf5a6c84SAndroid Build Coastguard Worker       // If this is the first hunk, open the file.
406*cf5a6c84SAndroid Build Coastguard Worker       if (TT.filein == -1) {
407*cf5a6c84SAndroid Build Coastguard Worker         int oldsum, newsum, del = 0;
408*cf5a6c84SAndroid Build Coastguard Worker         char *name;
409*cf5a6c84SAndroid Build Coastguard Worker 
410*cf5a6c84SAndroid Build Coastguard Worker         oldsum = TT.oldline + TT.oldlen;
411*cf5a6c84SAndroid Build Coastguard Worker         newsum = TT.newline + TT.newlen;
412*cf5a6c84SAndroid Build Coastguard Worker 
413*cf5a6c84SAndroid Build Coastguard Worker         // If an original file was provided on the command line, it overrides
414*cf5a6c84SAndroid Build Coastguard Worker         // *all* files mentioned in the patch, not just the first.
415*cf5a6c84SAndroid Build Coastguard Worker         if (toys.optc) {
416*cf5a6c84SAndroid Build Coastguard Worker           char **which = FLAG(R) ? &oldname : &newname;
417*cf5a6c84SAndroid Build Coastguard Worker 
418*cf5a6c84SAndroid Build Coastguard Worker           free(*which);
419*cf5a6c84SAndroid Build Coastguard Worker           *which = xstrdup(toys.optargs[0]);
420*cf5a6c84SAndroid Build Coastguard Worker           // The supplied path should be taken literally with or without -p.
421*cf5a6c84SAndroid Build Coastguard Worker           toys.optflags |= FLAG_p;
422*cf5a6c84SAndroid Build Coastguard Worker           TT.p = 0;
423*cf5a6c84SAndroid Build Coastguard Worker         }
424*cf5a6c84SAndroid Build Coastguard Worker 
425*cf5a6c84SAndroid Build Coastguard Worker         name = FLAG(R) ? oldname : newname;
426*cf5a6c84SAndroid Build Coastguard Worker 
427*cf5a6c84SAndroid Build Coastguard Worker         // We're deleting oldname if new file is /dev/null (before -p)
428*cf5a6c84SAndroid Build Coastguard Worker         // or if new hunk is empty (zero context) after patching
429*cf5a6c84SAndroid Build Coastguard Worker         if (!strcmp(name, "/dev/null") || !(FLAG(R) ? oldsum : newsum)) {
430*cf5a6c84SAndroid Build Coastguard Worker           name = FLAG(R) ? newname : oldname;
431*cf5a6c84SAndroid Build Coastguard Worker           del++;
432*cf5a6c84SAndroid Build Coastguard Worker         }
433*cf5a6c84SAndroid Build Coastguard Worker 
434*cf5a6c84SAndroid Build Coastguard Worker         // handle -p path truncation.
435*cf5a6c84SAndroid Build Coastguard Worker         for (i = 0, s = name; *s;) {
436*cf5a6c84SAndroid Build Coastguard Worker           if (FLAG(p) && TT.p == i) break;
437*cf5a6c84SAndroid Build Coastguard Worker           if (*s++ != '/') continue;
438*cf5a6c84SAndroid Build Coastguard Worker           while (*s == '/') s++;
439*cf5a6c84SAndroid Build Coastguard Worker           name = s;
440*cf5a6c84SAndroid Build Coastguard Worker           i++;
441*cf5a6c84SAndroid Build Coastguard Worker         }
442*cf5a6c84SAndroid Build Coastguard Worker 
443*cf5a6c84SAndroid Build Coastguard Worker         if (del) {
444*cf5a6c84SAndroid Build Coastguard Worker           if (!FLAG(s)) printf("removing %s\n", name);
445*cf5a6c84SAndroid Build Coastguard Worker           if (!FLAG(dry_run)) xunlink(name);
446*cf5a6c84SAndroid Build Coastguard Worker           state = 0;
447*cf5a6c84SAndroid Build Coastguard Worker         // If we've got a file to open, do so.
448*cf5a6c84SAndroid Build Coastguard Worker         } else if (!FLAG(p) || i <= TT.p) {
449*cf5a6c84SAndroid Build Coastguard Worker           // If the old file was null, we're creating a new one.
450*cf5a6c84SAndroid Build Coastguard Worker           if ((!strcmp(oldname, "/dev/null") || !oldsum) && access(name, F_OK))
451*cf5a6c84SAndroid Build Coastguard Worker           {
452*cf5a6c84SAndroid Build Coastguard Worker             if (!FLAG(s)) printf("creating %s\n", name);
453*cf5a6c84SAndroid Build Coastguard Worker             if (FLAG(dry_run)) TT.filein = xopen("/dev/null", O_RDWR);
454*cf5a6c84SAndroid Build Coastguard Worker             else {
455*cf5a6c84SAndroid Build Coastguard Worker               if (mkpath(name)) perror_exit("mkpath %s", name);
456*cf5a6c84SAndroid Build Coastguard Worker               TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666);
457*cf5a6c84SAndroid Build Coastguard Worker             }
458*cf5a6c84SAndroid Build Coastguard Worker           } else {
459*cf5a6c84SAndroid Build Coastguard Worker             if (!FLAG(s)) printf("patching %s\n", name);
460*cf5a6c84SAndroid Build Coastguard Worker             TT.filein = xopenro(name);
461*cf5a6c84SAndroid Build Coastguard Worker           }
462*cf5a6c84SAndroid Build Coastguard Worker           if (FLAG(dry_run)) TT.fileout = xopen("/dev/null", O_RDWR);
463*cf5a6c84SAndroid Build Coastguard Worker           else TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname);
464*cf5a6c84SAndroid Build Coastguard Worker           TT.linenum = TT.outnum = TT.hunknum = 0;
465*cf5a6c84SAndroid Build Coastguard Worker         }
466*cf5a6c84SAndroid Build Coastguard Worker       }
467*cf5a6c84SAndroid Build Coastguard Worker 
468*cf5a6c84SAndroid Build Coastguard Worker       TT.hunknum++;
469*cf5a6c84SAndroid Build Coastguard Worker 
470*cf5a6c84SAndroid Build Coastguard Worker       continue;
471*cf5a6c84SAndroid Build Coastguard Worker     }
472*cf5a6c84SAndroid Build Coastguard Worker 
473*cf5a6c84SAndroid Build Coastguard Worker     // If we didn't continue above, discard this line.
474*cf5a6c84SAndroid Build Coastguard Worker     free(patchline);
475*cf5a6c84SAndroid Build Coastguard Worker   }
476*cf5a6c84SAndroid Build Coastguard Worker 
477*cf5a6c84SAndroid Build Coastguard Worker   finish_oldfile();
478*cf5a6c84SAndroid Build Coastguard Worker 
479*cf5a6c84SAndroid Build Coastguard Worker   if (CFG_TOYBOX_FREE) {
480*cf5a6c84SAndroid Build Coastguard Worker     close(TT.filepatch);
481*cf5a6c84SAndroid Build Coastguard Worker     free(oldname);
482*cf5a6c84SAndroid Build Coastguard Worker     free(newname);
483*cf5a6c84SAndroid Build Coastguard Worker   }
484*cf5a6c84SAndroid Build Coastguard Worker }
485