Mercurial > hg > toybox
comparison toys/patch.c @ 216:5697a3f7c8cf
Make patch's file add actually work, including directory creating and
understanding zero-context hunks.
author | Rob Landley <rob@landley.net> |
---|---|
date | Thu, 27 Dec 2007 21:36:33 -0600 |
parents | 98820d1eaa79 |
children | cfa11e043e2b |
comparison
equal
deleted
inserted
replaced
215:34e36dffd47a | 216:5697a3f7c8cf |
---|---|
35 static void do_line(void *data) | 35 static void do_line(void *data) |
36 { | 36 { |
37 struct double_list *dlist = (struct double_list *)data; | 37 struct double_list *dlist = (struct double_list *)data; |
38 | 38 |
39 if (TT.state && *dlist->data != TT.state) | 39 if (TT.state && *dlist->data != TT.state) |
40 fdprintf(TT.fileout, "%s\n", dlist->data+(TT.state>1 ? 1 : 0)); | 40 fdprintf(TT.state == 2 ? 2: TT.fileout, |
41 "%s\n", dlist->data+(TT.state>2 ? 1 : 0)); | |
41 free(dlist->data); | 42 free(dlist->data); |
42 free(dlist); | 43 free(dlist); |
43 } | 44 } |
44 | 45 |
45 | 46 |
77 if (i<TT.context) temp = plist; | 78 if (i<TT.context) temp = plist; |
78 i++; | 79 i++; |
79 } else i = 0; | 80 } else i = 0; |
80 } | 81 } |
81 if (i < TT.context) goto fail_hunk; | 82 if (i < TT.context) goto fail_hunk; |
82 llist_free(temp->next, do_line); | 83 if (temp) { |
83 temp->next = NULL; | 84 llist_free(temp->next, do_line); |
84 | 85 temp->next = NULL; |
85 // Search for a place to apply this hunk | 86 } |
87 | |
88 // Search for a place to apply this hunk. Match all context lines and | |
89 // lines to be removed. | |
86 plist = TT.plines; | 90 plist = TT.plines; |
87 buf = NULL; | 91 buf = NULL; |
88 i = 0; | 92 i = 0; |
89 for (;;) { | 93 if (TT.context) for (;;) { |
90 char *data = get_line(TT.filein); | 94 char *data = get_line(TT.filein); |
91 TT.linenum++; | 95 TT.linenum++; |
92 | 96 |
93 // If the file ended before we found a home for this hunk, fail. | 97 // If the file ended before we found a home for this hunk, fail. |
94 if (!data) break; | 98 if (!data) goto fail_hunk; |
95 | 99 |
96 dlist_add(&buf, data); | 100 dlist_add(&buf, data); |
97 if (!backwards && *plist->data == "+-"[reverse]) { | 101 if (!backwards && *plist->data == "+-"[reverse]) { |
98 backwards = 1; | 102 backwards = 1; |
99 if (!strcmp(data, plist->data+1)) | 103 if (!strcmp(data, plist->data+1)) |
108 llist_free(buf, do_line); | 112 llist_free(buf, do_line); |
109 buf = NULL; | 113 buf = NULL; |
110 plist = TT.plines; | 114 plist = TT.plines; |
111 } else { | 115 } else { |
112 plist = plist->next; | 116 plist = plist->next; |
113 if (!plist) { | 117 if (!plist) break; |
114 // Got it. Emit changed data. | 118 } |
115 TT.state = "-+"[reverse]; | 119 } |
116 llist_free(TT.plines, do_line); | 120 |
117 TT.plines = NULL; | 121 // Got it. Emit changed data. |
118 buf->prev->next = NULL; | 122 TT.state = "-+"[reverse]; |
119 TT.state = 0; | 123 llist_free(TT.plines, do_line); |
120 llist_free(buf, do_line); | 124 TT.plines = NULL; |
121 return; | 125 TT.state = 0; |
122 } | 126 if (buf) { |
123 } | 127 buf->prev->next = NULL; |
124 } | 128 llist_free(buf, do_line); |
129 } | |
130 return; | |
131 | |
125 fail_hunk: | 132 fail_hunk: |
126 printf("Hunk FAILED.\n"); | 133 printf("Hunk FAILED.\n"); |
127 | 134 |
128 // If we got to this point, we've seeked to the end. Discard changes to | 135 // If we got to this point, we've seeked to the end. Discard changes to |
129 // this file and advance to next file. | 136 // this file and advance to next file. |
130 | 137 |
131 TT.state = 0; | 138 TT.state = 2; |
132 llist_free(TT.plines, do_line); | 139 llist_free(TT.plines, do_line); |
133 TT.plines = 0; | 140 TT.plines = 0; |
134 if (buf) { | 141 if (buf) { |
135 buf->prev->next = NULL; | 142 buf->prev->next = NULL; |
136 llist_free(buf, do_line); | 143 llist_free(buf, do_line); |
137 } | 144 } |
138 delete_tempfile(TT.filein, TT.fileout, &TT.tempname); | 145 delete_tempfile(TT.filein, TT.fileout, &TT.tempname); |
139 TT.filein = -1; | 146 TT.filein = -1; |
147 TT.state = 0; | |
140 } | 148 } |
141 | 149 |
142 // state 0: Not in a hunk, look for +++. | 150 // state 0: Not in a hunk, look for +++. |
143 // state 1: Found +++ file indicator, look for @@ | 151 // state 1: Found +++ file indicator, look for @@ |
144 // state 2: In hunk: counting initial context lines | 152 // state 2: In hunk: counting initial context lines |
179 free(TT.oldname); | 187 free(TT.oldname); |
180 | 188 |
181 // Trim date from end of filename (if any). We don't care. | 189 // Trim date from end of filename (if any). We don't care. |
182 for (s = patchline+4; *s && *s!='\t'; s++) | 190 for (s = patchline+4; *s && *s!='\t'; s++) |
183 if (*s=='\\' && s[1]) s++; | 191 if (*s=='\\' && s[1]) s++; |
192 *s = 0; | |
184 | 193 |
185 TT.oldname = xstrdup(patchline+4); | 194 TT.oldname = xstrdup(patchline+4); |
186 } else if (!strncmp("+++ ", patchline, 4)) { | 195 } else if (!strncmp("+++ ", patchline, 4)) { |
187 int i = 0, del = 0; | 196 int i = 0, del = 0; |
188 char *s, *start; | 197 char *s, *start; |
217 // If we've got a file to open, do so. | 226 // If we've got a file to open, do so. |
218 else if (!(toys.optflags & FLAG_PATHLEN) || i <= TT.prefix) { | 227 else if (!(toys.optflags & FLAG_PATHLEN) || i <= TT.prefix) { |
219 // If the old file was null, we're creating a new one. | 228 // If the old file was null, we're creating a new one. |
220 if (!strcmp(TT.oldname, "/dev/null")) { | 229 if (!strcmp(TT.oldname, "/dev/null")) { |
221 printf("creating %s\n", start); | 230 printf("creating %s\n", start); |
231 s = strrchr(start, '/'); | |
232 if (s) { | |
233 *s = 0; | |
234 xmkpath(start, -1); | |
235 *s = '/'; | |
236 } | |
222 TT.filein = xcreate(start, O_CREAT|O_RDWR, 0666); | 237 TT.filein = xcreate(start, O_CREAT|O_RDWR, 0666); |
223 } else { | 238 } else { |
224 printf("patching %s\n", start); | 239 printf("patching %s\n", start); |
225 TT.filein = xopen(start, O_RDWR); | 240 TT.filein = xopen(start, O_RDWR); |
226 } | 241 } |