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 }