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