aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
Diffstat (limited to 'editors')
-rw-r--r--editors/Config.src6
-rw-r--r--editors/Kbuild.src1
-rw-r--r--editors/awk.c14
-rw-r--r--editors/cmp.c9
-rw-r--r--editors/diff.c2
-rw-r--r--editors/patch.c336
-rw-r--r--editors/sed.c6
7 files changed, 144 insertions, 230 deletions
diff --git a/editors/Config.src b/editors/Config.src
index fc824ccd5..201ee6eb9 100644
--- a/editors/Config.src
+++ b/editors/Config.src
@@ -60,12 +60,6 @@ config ED
60 Small, simple, evil. Part of SUSv3. If you're not already using 60 Small, simple, evil. Part of SUSv3. If you're not already using
61 this, you don't need it. 61 this, you don't need it.
62 62
63config PATCH
64 bool "patch"
65 default y
66 help
67 Apply a unified diff formatted patch.
68
69config SED 63config SED
70 bool "sed" 64 bool "sed"
71 default y 65 default y
diff --git a/editors/Kbuild.src b/editors/Kbuild.src
index 98128064d..2f23ae12f 100644
--- a/editors/Kbuild.src
+++ b/editors/Kbuild.src
@@ -11,6 +11,5 @@ lib-$(CONFIG_AWK) += awk.o
11lib-$(CONFIG_CMP) += cmp.o 11lib-$(CONFIG_CMP) += cmp.o
12lib-$(CONFIG_DIFF) += diff.o 12lib-$(CONFIG_DIFF) += diff.o
13lib-$(CONFIG_ED) += ed.o 13lib-$(CONFIG_ED) += ed.o
14lib-$(CONFIG_PATCH) += patch.o
15lib-$(CONFIG_SED) += sed.o 14lib-$(CONFIG_SED) += sed.o
16lib-$(CONFIG_VI) += vi.o 15lib-$(CONFIG_VI) += vi.o
diff --git a/editors/awk.c b/editors/awk.c
index 8bc56756c..2eeb9d77a 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -277,10 +277,10 @@ enum {
277 277
278/* tokens and their corresponding info values */ 278/* tokens and their corresponding info values */
279 279
280#define NTC "\377" /* switch to next token class (tc<<1) */ 280#define NTC "\377" /* switch to next token class (tc<<1) */
281#define NTCC '\377' 281#define NTCC '\377'
282 282
283#define OC_B OC_BUILTIN 283#define OC_B OC_BUILTIN
284 284
285static const char tokenlist[] ALIGN1 = 285static const char tokenlist[] ALIGN1 =
286 "\1(" NTC 286 "\1(" NTC
@@ -368,7 +368,7 @@ static const uint32_t tokeninfo[] = {
368 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), 368 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), 369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
370 OC_GETLINE|SV|P(0), 370 OC_GETLINE|SV|P(0),
371 0, 0, 371 0, 0,
372 0, 372 0,
373 0 /* END */ 373 0 /* END */
374}; 374};
@@ -380,7 +380,7 @@ enum {
380 ORS, RS, RT, FILENAME, 380 ORS, RS, RT, FILENAME,
381 SUBSEP, F0, ARGIND, ARGC, 381 SUBSEP, F0, ARGIND, ARGC,
382 ARGV, ERRNO, FNR, NR, 382 ARGV, ERRNO, FNR, NR,
383 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS 383 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
384}; 384};
385 385
386static const char vNames[] ALIGN1 = 386static const char vNames[] ALIGN1 =
@@ -2335,7 +2335,7 @@ static var *evaluate(node *op, var *res)
2335#define fnargs (G.evaluate__fnargs) 2335#define fnargs (G.evaluate__fnargs)
2336/* seed is initialized to 1 */ 2336/* seed is initialized to 1 */
2337#define seed (G.evaluate__seed) 2337#define seed (G.evaluate__seed)
2338#define sreg (G.evaluate__sreg) 2338#define sreg (G.evaluate__sreg)
2339 2339
2340 var *v1; 2340 var *v1;
2341 2341
@@ -2611,7 +2611,7 @@ static var *evaluate(node *op, var *res)
2611 rsm->F = popen(L.s, "r"); 2611 rsm->F = popen(L.s, "r");
2612 rsm->is_pipe = TRUE; 2612 rsm->is_pipe = TRUE;
2613 } else { 2613 } else {
2614 rsm->F = fopen_for_read(L.s); /* not xfopen! */ 2614 rsm->F = fopen_for_read(L.s); /* not xfopen! */
2615 } 2615 }
2616 } 2616 }
2617 } else { 2617 } else {
diff --git a/editors/cmp.c b/editors/cmp.c
index f495da7d2..f84a56e3e 100644
--- a/editors/cmp.c
+++ b/editors/cmp.c
@@ -33,8 +33,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
33 unsigned opt; 33 unsigned opt;
34 int retval = 0; 34 int retval = 0;
35 35
36 xfunc_error_retval = 2; /* 1 is returned if files are different. */
37
38 opt_complementary = "-1" 36 opt_complementary = "-1"
39 IF_DESKTOP(":?4") 37 IF_DESKTOP(":?4")
40 IF_NOT_DESKTOP(":?2") 38 IF_NOT_DESKTOP(":?2")
@@ -43,8 +41,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
43 argv += optind; 41 argv += optind;
44 42
45 filename1 = *argv; 43 filename1 = *argv;
46 fp1 = xfopen_stdin(filename1);
47
48 if (*++argv) { 44 if (*++argv) {
49 filename2 = *argv; 45 filename2 = *argv;
50 if (ENABLE_DESKTOP && *++argv) { 46 if (ENABLE_DESKTOP && *++argv) {
@@ -55,6 +51,10 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
55 } 51 }
56 } 52 }
57 53
54 xfunc_error_retval = 2; /* missing file results in exitcode 2 */
55 if (opt & CMP_OPT_s)
56 logmode = 0; /* -s suppresses open error messages */
57 fp1 = xfopen_stdin(filename1);
58 fp2 = xfopen_stdin(filename2); 58 fp2 = xfopen_stdin(filename2);
59 if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */ 59 if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */
60 /* Note that we don't bother reading stdin. Neither does gnu wc. 60 /* Note that we don't bother reading stdin. Neither does gnu wc.
@@ -63,6 +63,7 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
63 */ 63 */
64 return 0; 64 return 0;
65 } 65 }
66 logmode = LOGMODE_STDIO;
66 67
67 if (opt & CMP_OPT_l) 68 if (opt & CMP_OPT_l)
68 fmt = fmt_l_opt; 69 fmt = fmt_l_opt;
diff --git a/editors/diff.c b/editors/diff.c
index d9d709db6..cc7ba472e 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -230,7 +230,7 @@ static int search(const int *c, int k, int y, const struct cand *list)
230{ 230{
231 int i, j; 231 int i, j;
232 232
233 if (list[c[k]].y < y) /* quick look for typical case */ 233 if (list[c[k]].y < y) /* quick look for typical case */
234 return k + 1; 234 return k + 1;
235 235
236 for (i = 0, j = k + 1;;) { 236 for (i = 0, j = k + 1;;) {
diff --git a/editors/patch.c b/editors/patch.c
index 33ff8b569..9c6d967b9 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -1,8 +1,7 @@
1/* Adapted from toybox's patch. */
2
3/* vi: set sw=4 ts=4: 1/* vi: set sw=4 ts=4:
4 * 2 *
5 * patch.c - Apply a "universal" diff. 3 * Apply a "universal" diff.
4 * Adapted from toybox's patch implementation.
6 * 5 *
7 * Copyright 2007 Rob Landley <rob@landley.net> 6 * Copyright 2007 Rob Landley <rob@landley.net>
8 * 7 *
@@ -20,30 +19,45 @@
20 * -f force (no questions asked) 19 * -f force (no questions asked)
21 * -F fuzz (number, default 2) 20 * -F fuzz (number, default 2)
22 * [file] which file to patch 21 * [file] which file to patch
22 */
23
24//applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP))
25
26//kbuild:lib-$(CONFIG_PATCH) += patch.o
27
28//config:config PATCH
29//config: bool "patch"
30//config: default y
31//config: help
32//config: Apply a unified diff formatted patch.
33
34//usage:#define patch_trivial_usage
35//usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]"
36//usage:#define patch_full_usage "\n\n"
37//usage: IF_LONG_OPTS(
38//usage: " -p,--strip N Strip N leading components from file names"
39//usage: "\n -i,--input DIFF Read DIFF instead of stdin"
40//usage: "\n -R,--reverse Reverse patch"
41//usage: "\n -N,--forward Ignore already applied patches"
42//usage: "\n --dry-run Don't actually change files"
43//usage: "\n -E,--remove-empty-files Remove output files if they become empty"
44//usage: )
45//usage: IF_NOT_LONG_OPTS(
46//usage: " -p N Strip N leading components from file names"
47//usage: "\n -i DIFF Read DIFF instead of stdin"
48//usage: "\n -R Reverse patch"
49//usage: "\n -N Ignore already applied patches"
50//usage: "\n -E Remove output files if they become empty"
51//usage: )
52//usage:
53//usage:#define patch_example_usage
54//usage: "$ patch -p1 < example.diff\n"
55//usage: "$ patch -p0 -i example.diff"
23 56
24USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) 57#include "libbb.h"
25
26config PATCH
27 bool "patch"
28 default y
29 help
30 usage: patch [-i file] [-p depth] [-Ru]
31
32 Apply a unified diff to one or more files.
33 58
34 -i Input file (defaults=stdin)
35 -p number of '/' to strip from start of file paths (default=all)
36 -R Reverse patch.
37 -u Ignored (only handles "unified" diffs)
38 59
39 This version of patch only handles unified diffs, and only modifies 60// libbb candidate?
40 a file when all all hunks to that file apply. Patch prints failed
41 hunks to stderr, and exits with nonzero status if any hunks fail.
42
43 A file compared against /dev/null (or with a date <= the epoch) is
44 created or deleted if -E or --remove-empty-files set.
45*/
46#include "libbb.h"
47 61
48struct double_list { 62struct double_list {
49 struct double_list *next; 63 struct double_list *next;
@@ -51,188 +65,55 @@ struct double_list {
51 char *data; 65 char *data;
52}; 66};
53 67
54// Return the first item from the list, advancing the list (which must be called
55// as &list)
56static
57void *TOY_llist_pop(void *list)
58{
59 // I'd use a void ** for the argument, and even accept the typecast in all
60 // callers as documentation you need the &, except the stupid compiler
61 // would then scream about type-punned pointers. Screw it.
62 void **llist = (void **)list;
63 void **next = (void **)*llist;
64 *llist = *next;
65
66 return (void *)next;
67}
68
69// Free all the elements of a linked list 68// Free all the elements of a linked list
70// if freeit!=NULL call freeit() on each element before freeing it. 69// Call freeit() on each element before freeing it.
71static 70static
72void TOY_llist_free(void *list, void (*freeit)(void *data)) 71void dlist_free(struct double_list *list, void (*freeit)(void *data))
73{ 72{
74 while (list) { 73 while (list) {
75 void *pop = TOY_llist_pop(&list); 74 void *pop = list;
76 if (freeit) freeit(pop); 75 list = list->next;
77 else free(pop); 76 freeit(pop);
78 77 // Bail out also if list is circular.
79 // End doubly linked list too. 78 if (list == pop) break;
80 if (list==pop) break;
81 } 79 }
82} 80}
83//Override bbox's names
84#define llist_pop TOY_llist_pop
85#define llist_free TOY_llist_free
86 81
87// Add an entry to the end off a doubly linked list 82// Add an entry before "list" element in (circular) doubly linked list
88static 83static
89struct double_list *dlist_add(struct double_list **list, char *data) 84struct double_list *dlist_add(struct double_list **list, char *data)
90{ 85{
91 struct double_list *line = xmalloc(sizeof(struct double_list)); 86 struct double_list *llist;
87 struct double_list *line = xmalloc(sizeof(*line));
92 88
93 line->data = data; 89 line->data = data;
94 if (*list) { 90 llist = *list;
95 line->next = *list; 91 if (llist) {
96 line->prev = (*list)->prev; 92 struct double_list *p;
97 (*list)->prev->next = line; 93 line->next = llist;
98 (*list)->prev = line; 94 p = line->prev = llist->prev;
99 } else *list = line->next = line->prev = line; 95 // (list is circular, we assume p is never NULL)
96 p->next = line;
97 llist->prev = line;
98 } else
99 *list = line->next = line->prev = line;
100 100
101 return line; 101 return line;
102} 102}
103 103
104// Ensure entire path exists.
105// If mode != -1 set permissions on newly created dirs.
106// Requires that path string be writable (for temporary null terminators).
107static
108void xmkpath(char *path, int mode)
109{
110 char *p, old;
111 mode_t mask;
112 int rc;
113 struct stat st;
114
115 for (p = path; ; p++) {
116 if (!*p || *p == '/') {
117 old = *p;
118 *p = rc = 0;
119 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
120 if (mode != -1) {
121 mask = umask(0);
122 rc = mkdir(path, mode);
123 umask(mask);
124 } else rc = mkdir(path, 0777);
125 }
126 *p = old;
127 if(rc) bb_perror_msg_and_die("mkpath '%s'", path);
128 }
129 if (!*p) break;
130 }
131}
132
133// Slow, but small.
134static
135char *get_rawline(int fd, long *plen, char end)
136{
137 char c, *buf = NULL;
138 long len = 0;
139
140 for (;;) {
141 if (1>read(fd, &c, 1)) break;
142 if (!(len & 63)) buf=xrealloc(buf, len+65);
143 if ((buf[len++]=c) == end) break;
144 }
145 if (buf) buf[len]=0;
146 if (plen) *plen = len;
147
148 return buf;
149}
150
151static
152char *get_line(int fd)
153{
154 long len;
155 char *buf = get_rawline(fd, &len, '\n');
156
157 if (buf && buf[--len]=='\n') buf[len]=0;
158
159 return buf;
160}
161
162// Copy the rest of in to out and close both files.
163static
164void xsendfile(int in, int out)
165{
166 long len;
167 char buf[4096];
168
169 if (in<0) return;
170 for (;;) {
171 len = safe_read(in, buf, 4096);
172 if (len<1) break;
173 xwrite(out, buf, len);
174 }
175}
176
177// Copy the rest of the data and replace the original with the copy.
178static
179void replace_tempfile(int fdin, int fdout, char **tempname)
180{
181 char *temp = xstrdup(*tempname);
182
183 temp[strlen(temp)-6]=0;
184 if (fdin != -1) {
185 xsendfile(fdin, fdout);
186 xclose(fdin);
187 }
188 xclose(fdout);
189 rename(*tempname, temp);
190 free(*tempname);
191 free(temp);
192 *tempname = NULL;
193}
194
195// Open a temporary file to copy an existing file into.
196static
197int copy_tempfile(int fdin, char *name, char **tempname)
198{
199 struct stat statbuf;
200 int fd;
201
202 *tempname = xasprintf("%sXXXXXX", name);
203 fd = xmkstemp(*tempname);
204
205 // Set permissions of output file
206 fstat(fdin, &statbuf);
207 fchmod(fd, statbuf.st_mode);
208
209 return fd;
210}
211
212// Abort the copy and delete the temporary file.
213static
214void delete_tempfile(int fdin, int fdout, char **tempname)
215{
216 close(fdin);
217 close(fdout);
218 unlink(*tempname);
219 free(*tempname);
220 *tempname = NULL;
221}
222
223
224 104
225struct globals { 105struct globals {
226 char *infile; 106 char *infile;
227 long prefix; 107 long prefix;
228 108
229 struct double_list *current_hunk; 109 struct double_list *current_hunk;
110
230 long oldline, oldlen, newline, newlen; 111 long oldline, oldlen, newline, newlen;
231 long linenum; 112 long linenum;
232 int context, state, filein, fileout, filepatch, hunknum; 113 int context, state, hunknum;
114 int filein, fileout;
233 char *tempname; 115 char *tempname;
234 116
235 // was toys.foo:
236 int exitval; 117 int exitval;
237}; 118};
238#define TT (*ptr_to_globals) 119#define TT (*ptr_to_globals)
@@ -263,7 +144,7 @@ struct globals {
263 144
264static void do_line(void *data) 145static void do_line(void *data)
265{ 146{
266 struct double_list *dlist = (struct double_list *)data; 147 struct double_list *dlist = data;
267 148
268 if (TT.state>1 && *dlist->data != TT.state) 149 if (TT.state>1 && *dlist->data != TT.state)
269 fdprintf(TT.state == 2 ? 2 : TT.fileout, 150 fdprintf(TT.state == 2 ? 2 : TT.fileout,
@@ -272,19 +153,35 @@ static void do_line(void *data)
272 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); 153 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data);
273 154
274 free(dlist->data); 155 free(dlist->data);
275 free(data); 156 free(dlist);
276} 157}
277 158
278static void finish_oldfile(void) 159static void finish_oldfile(void)
279{ 160{
280 if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); 161 if (TT.tempname) {
162 // Copy the rest of the data and replace the original with the copy.
163 char *temp;
164
165 if (TT.filein != -1) {
166 bb_copyfd_eof(TT.filein, TT.fileout);
167 xclose(TT.filein);
168 }
169 xclose(TT.fileout);
170
171 temp = xstrdup(TT.tempname);
172 temp[strlen(temp) - 6] = '\0';
173 rename(TT.tempname, temp);
174 free(temp);
175
176 free(TT.tempname);
177 TT.tempname = NULL;
178 }
281 TT.fileout = TT.filein = -1; 179 TT.fileout = TT.filein = -1;
282} 180}
283 181
284static void fail_hunk(void) 182static void fail_hunk(void)
285{ 183{
286 if (!TT.current_hunk) return; 184 if (!TT.current_hunk) return;
287 TT.current_hunk->prev->next = 0;
288 185
289 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); 186 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline);
290 TT.exitval = 1; 187 TT.exitval = 1;
@@ -293,9 +190,17 @@ static void fail_hunk(void)
293 // this file and advance to next file. 190 // this file and advance to next file.
294 191
295 TT.state = 2; 192 TT.state = 2;
296 llist_free(TT.current_hunk, do_line); 193 TT.current_hunk->prev->next = NULL;
194 dlist_free(TT.current_hunk, do_line);
297 TT.current_hunk = NULL; 195 TT.current_hunk = NULL;
298 delete_tempfile(TT.filein, TT.fileout, &TT.tempname); 196
197 // Abort the copy and delete the temporary file.
198 close(TT.filein);
199 close(TT.fileout);
200 unlink(TT.tempname);
201 free(TT.tempname);
202 TT.tempname = NULL;
203
299 TT.state = 0; 204 TT.state = 0;
300} 205}
301 206
@@ -333,8 +238,8 @@ static int apply_one_hunk(void)
333 // complete hunk. 238 // complete hunk.
334 plist = TT.current_hunk; 239 plist = TT.current_hunk;
335 buf = NULL; 240 buf = NULL;
336 if (TT.context) for (;;) { 241 if (reverse ? TT.oldlen : TT.newlen) for (;;) {
337 char *data = get_line(TT.filein); 242 char *data = xmalloc_reads(TT.filein, NULL, NULL);
338 243
339 TT.linenum++; 244 TT.linenum++;
340 245
@@ -368,7 +273,9 @@ static int apply_one_hunk(void)
368 // File ended before we found a place for this hunk. 273 // File ended before we found a place for this hunk.
369 fail_hunk(); 274 fail_hunk();
370 goto done; 275 goto done;
371 } else if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); 276 }
277
278 if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data);
372 check = dlist_add(&buf, data); 279 check = dlist_add(&buf, data);
373 280
374 // Compare this line with next expected line of hunk. 281 // Compare this line with next expected line of hunk.
@@ -390,7 +297,8 @@ static int apply_one_hunk(void)
390 fdprintf(2, "NOT: %s\n", plist->data); 297 fdprintf(2, "NOT: %s\n", plist->data);
391 298
392 TT.state = 3; 299 TT.state = 3;
393 check = llist_pop(&buf); 300 check = buf;
301 buf = buf->next;
394 check->prev->next = buf; 302 check->prev->next = buf;
395 buf->prev = check->prev; 303 buf->prev = check->prev;
396 do_line(check); 304 do_line(check);
@@ -398,8 +306,8 @@ static int apply_one_hunk(void)
398 306
399 // If we've reached the end of the buffer without confirming a 307 // If we've reached the end of the buffer without confirming a
400 // match, read more lines. 308 // match, read more lines.
401 if (check==buf) { 309 if (check == buf) {
402 buf = 0; 310 buf = NULL;
403 break; 311 break;
404 } 312 }
405 check = buf; 313 check = buf;
@@ -417,13 +325,13 @@ static int apply_one_hunk(void)
417out: 325out:
418 // We have a match. Emit changed data. 326 // We have a match. Emit changed data.
419 TT.state = "-+"[reverse ^ dummy_revert]; 327 TT.state = "-+"[reverse ^ dummy_revert];
420 llist_free(TT.current_hunk, do_line); 328 dlist_free(TT.current_hunk, do_line);
421 TT.current_hunk = NULL; 329 TT.current_hunk = NULL;
422 TT.state = 1; 330 TT.state = 1;
423done: 331done:
424 if (buf) { 332 if (buf) {
425 buf->prev->next = NULL; 333 buf->prev->next = NULL;
426 llist_free(buf, do_line); 334 dlist_free(buf, do_line);
427 } 335 }
428 336
429 return TT.state; 337 return TT.state;
@@ -444,6 +352,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
444 int reverse, state = 0; 352 int reverse, state = 0;
445 char *oldname = NULL, *newname = NULL; 353 char *oldname = NULL, *newname = NULL;
446 char *opt_p, *opt_i; 354 char *opt_p, *opt_i;
355 long oldlen = oldlen; /* for compiler */
356 long newlen = newlen; /* for compiler */
447 357
448 INIT_TT(); 358 INIT_TT();
449 359
@@ -453,10 +363,10 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
453 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! 363 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative!
454 TT.filein = TT.fileout = -1; 364 TT.filein = TT.fileout = -1;
455 if (opts & FLAG_INPUT) { 365 if (opts & FLAG_INPUT) {
456 TT.filepatch = xopen_stdin(opt_i); 366 xmove_fd(xopen_stdin(opt_i), STDIN_FILENO);
457 } else { 367 } else {
458 if (argv[0] && argv[1]) { 368 if (argv[0] && argv[1]) {
459 TT.filepatch = xopen_stdin(argv[1]); 369 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
460 } 370 }
461 } 371 }
462 if (argv[0]) { 372 if (argv[0]) {
@@ -468,7 +378,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
468 for(;;) { 378 for(;;) {
469 char *patchline; 379 char *patchline;
470 380
471 patchline = get_line(TT.filepatch); 381 patchline = xmalloc_fgetline(stdin);
472 if (!patchline) break; 382 if (!patchline) break;
473 383
474 // Other versions of patch accept damaged patches, 384 // Other versions of patch accept damaged patches,
@@ -483,8 +393,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
483 if (*patchline==' ' || *patchline=='+' || *patchline=='-') { 393 if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
484 dlist_add(&TT.current_hunk, patchline); 394 dlist_add(&TT.current_hunk, patchline);
485 395
486 if (*patchline != '+') TT.oldlen--; 396 if (*patchline != '+') oldlen--;
487 if (*patchline != '-') TT.newlen--; 397 if (*patchline != '-') newlen--;
488 398
489 // Context line? 399 // Context line?
490 if (*patchline==' ' && state==2) TT.context++; 400 if (*patchline==' ' && state==2) TT.context++;
@@ -492,7 +402,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
492 402
493 // If we've consumed all expected hunk lines, apply the hunk. 403 // If we've consumed all expected hunk lines, apply the hunk.
494 404
495 if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); 405 if (!oldlen && !newlen) state = apply_one_hunk();
496 continue; 406 continue;
497 } 407 }
498 fail_hunk(); 408 fail_hunk();
@@ -539,11 +449,14 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
539 449
540 // Read oldline[,oldlen] +newline[,newlen] 450 // Read oldline[,oldlen] +newline[,newlen]
541 451
542 TT.oldlen = TT.newlen = 1; 452 TT.oldlen = oldlen = TT.newlen = newlen = 1;
543 TT.oldline = strtol(s, &s, 10); 453 TT.oldline = strtol(s, &s, 10);
544 if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); 454 if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10);
545 TT.newline = strtol(s+2, &s, 10); 455 TT.newline = strtol(s+2, &s, 10);
546 if (*s == ',') TT.newlen = strtol(s+1, &s, 10); 456 if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10);
457
458 if (oldlen < 1 && newlen < 1)
459 bb_error_msg_and_die("Really? %s", patchline);
547 460
548 TT.context = 0; 461 TT.context = 0;
549 state = 2; 462 state = 2;
@@ -553,8 +466,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
553 int oldsum, newsum, empty = 0; 466 int oldsum, newsum, empty = 0;
554 char *name; 467 char *name;
555 468
556 oldsum = TT.oldline + TT.oldlen; 469 oldsum = TT.oldline + oldlen;
557 newsum = TT.newline + TT.newlen; 470 newsum = TT.newline + newlen;
558 471
559 name = reverse ? oldname : newname; 472 name = reverse ? oldname : newname;
560 473
@@ -588,13 +501,15 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
588 } 501 }
589 // If we've got a file to open, do so. 502 // If we've got a file to open, do so.
590 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { 503 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) {
504 struct stat statbuf;
505
591 // If the old file was null, we're creating a new one. 506 // If the old file was null, we're creating a new one.
592 if (!strcmp(oldname, "/dev/null") || !oldsum) { 507 if (!strcmp(oldname, "/dev/null") || !oldsum) {
593 printf("creating %s\n", name); 508 printf("creating %s\n", name);
594 s = strrchr(name, '/'); 509 s = strrchr(name, '/');
595 if (s) { 510 if (s) {
596 *s = 0; 511 *s = 0;
597 xmkpath(name, -1); 512 bb_make_directory(name, -1, FILEUTILS_RECUR);
598 *s = '/'; 513 *s = '/';
599 } 514 }
600 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); 515 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
@@ -602,7 +517,13 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
602 printf("patching file %s\n", name); 517 printf("patching file %s\n", name);
603 TT.filein = xopen(name, O_RDONLY); 518 TT.filein = xopen(name, O_RDONLY);
604 } 519 }
605 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); 520
521 TT.tempname = xasprintf("%sXXXXXX", name);
522 TT.fileout = xmkstemp(TT.tempname);
523 // Set permissions of output file
524 fstat(TT.filein, &statbuf);
525 fchmod(TT.fileout, statbuf.st_mode);
526
606 TT.linenum = 0; 527 TT.linenum = 0;
607 TT.hunknum = 0; 528 TT.hunknum = 0;
608 } 529 }
@@ -620,7 +541,6 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
620 finish_oldfile(); 541 finish_oldfile();
621 542
622 if (ENABLE_FEATURE_CLEAN_UP) { 543 if (ENABLE_FEATURE_CLEAN_UP) {
623 close(TT.filepatch);
624 free(oldname); 544 free(oldname);
625 free(newname); 545 free(newname);
626 } 546 }
diff --git a/editors/sed.c b/editors/sed.c
index 964d0405e..b91acfb7f 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -117,9 +117,9 @@ struct globals {
117 char *add_cmd_line; 117 char *add_cmd_line;
118 118
119 struct pipeline { 119 struct pipeline {
120 char *buf; /* Space to hold string */ 120 char *buf; /* Space to hold string */
121 int idx; /* Space used */ 121 int idx; /* Space used */
122 int len; /* Space allocated */ 122 int len; /* Space allocated */
123 } pipeline; 123 } pipeline;
124} FIX_ALIASING; 124} FIX_ALIASING;
125#define G (*(struct globals*)&bb_common_bufsiz1) 125#define G (*(struct globals*)&bb_common_bufsiz1)