Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/editors/sed.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1123 - (hide annotations) (download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 36937 byte(s)
-updated to busybox-1.17.1
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * sed.c - very minimalist version of sed
4     *
5     * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
6     * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
7     * Copyright (C) 2002 Matt Kraai
8 niro 816 * Copyright (C) 2003 by Glenn McGrath
9 niro 532 * Copyright (C) 2003,2004 by Rob Landley <rob@landley.net>
10     *
11     * MAINTAINER: Rob Landley <rob@landley.net>
12     *
13     * Licensed under GPL version 2, see file LICENSE in this tarball for details.
14     */
15    
16     /* Code overview.
17    
18     Files are laid out to avoid unnecessary function declarations. So for
19     example, every function add_cmd calls occurs before add_cmd in this file.
20    
21     add_cmd() is called on each line of sed command text (from a file or from
22     the command line). It calls get_address() and parse_cmd_args(). The
23     resulting sed_cmd_t structures are appended to a linked list
24 niro 816 (G.sed_cmd_head/G.sed_cmd_tail).
25 niro 532
26 niro 816 add_input_file() adds a FILE* to the list of input files. We need to
27 niro 532 know all input sources ahead of time to find the last line for the $ match.
28    
29     process_files() does actual sedding, reading data lines from each input FILE *
30     (which could be stdin) and applying the sed command list (sed_cmd_head) to
31     each of the resulting lines.
32    
33     sed_main() is where external code calls into this, with a command line.
34     */
35    
36    
37     /*
38     Supported features and commands in this version of sed:
39    
40     - comments ('#')
41     - address matching: num|/matchstr/[,num|/matchstr/|$]command
42     - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
43     - edit commands: (a)ppend, (i)nsert, (c)hange
44     - file commands: (r)ead
45     - backreferences in substitution expressions (\0, \1, \2...\9)
46     - grouped commands: {cmd1;cmd2}
47     - transliteration (y/source-chars/dest-chars/)
48     - pattern space hold space storing / swapping (g, h, x)
49     - labels / branching (: label, b, t, T)
50    
51     (Note: Specifying an address (range) to match is *optional*; commands
52     default to the whole pattern space if no specific address match was
53     requested.)
54    
55     Todo:
56     - Create a wrapper around regex to make libc's regex conform with sed
57    
58     Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
59     */
60    
61 niro 816 #include "libbb.h"
62 niro 532 #include "xregex.h"
63    
64     /* Each sed command turns into one of these structures. */
65     typedef struct sed_cmd_s {
66     /* Ordered by alignment requirements: currently 36 bytes on x86 */
67 niro 816 struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */
68 niro 532
69     /* address storage */
70     regex_t *beg_match; /* sed -e '/match/cmd' */
71     regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
72     regex_t *sub_match; /* For 's/sub_match/string/' */
73     int beg_line; /* 'sed 1p' 0 == apply commands to all lines */
74     int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
75    
76 niro 816 FILE *sw_file; /* File (sw) command writes to, -1 for none. */
77 niro 532 char *string; /* Data string for (saicytb) commands. */
78    
79 niro 816 unsigned which_match; /* (s) Which match to replace (0 for all) */
80 niro 532
81     /* Bitfields (gcc won't group them if we don't) */
82 niro 816 unsigned invert:1; /* the '!' after the address */
83     unsigned in_match:1; /* Next line also included in match? */
84     unsigned sub_p:1; /* (s) print option */
85 niro 532
86 niro 816 char sw_last_char; /* Last line written by (sw) had no '\n' */
87 niro 532
88     /* GENERAL FIELDS */
89     char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
90     } sed_cmd_t;
91    
92 niro 816 static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
93 niro 532
94 niro 816 struct globals {
95 niro 532 /* options */
96     int be_quiet, regex_type;
97     FILE *nonstdout;
98     char *outname, *hold_space;
99    
100     /* List of input files */
101     int input_file_count, current_input_file;
102     FILE **input_file_list;
103    
104     regmatch_t regmatch[10];
105     regex_t *previous_regex_ptr;
106    
107     /* linked list of sed commands */
108     sed_cmd_t sed_cmd_head, *sed_cmd_tail;
109    
110     /* Linked list of append lines */
111     llist_t *append_head;
112    
113     char *add_cmd_line;
114    
115     struct pipeline {
116     char *buf; /* Space to hold string */
117     int idx; /* Space used */
118     int len; /* Space allocated */
119     } pipeline;
120 niro 1123 } FIX_ALIASING;
121     #define G (*(struct globals*)&bb_common_bufsiz1)
122     struct BUG_G_too_big {
123     char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
124 niro 816 };
125     #define INIT_G() do { \
126     G.sed_cmd_tail = &G.sed_cmd_head; \
127     } while (0)
128 niro 532
129    
130     #if ENABLE_FEATURE_CLEAN_UP
131     static void sed_free_and_close_stuff(void)
132     {
133 niro 816 sed_cmd_t *sed_cmd = G.sed_cmd_head.next;
134 niro 532
135 niro 816 llist_free(G.append_head, free);
136 niro 532
137     while (sed_cmd) {
138     sed_cmd_t *sed_cmd_next = sed_cmd->next;
139    
140 niro 816 if (sed_cmd->sw_file)
141     xprint_and_close_file(sed_cmd->sw_file);
142 niro 532
143     if (sed_cmd->beg_match) {
144     regfree(sed_cmd->beg_match);
145     free(sed_cmd->beg_match);
146     }
147     if (sed_cmd->end_match) {
148     regfree(sed_cmd->end_match);
149     free(sed_cmd->end_match);
150     }
151     if (sed_cmd->sub_match) {
152     regfree(sed_cmd->sub_match);
153     free(sed_cmd->sub_match);
154     }
155     free(sed_cmd->string);
156     free(sed_cmd);
157     sed_cmd = sed_cmd_next;
158     }
159    
160 niro 816 free(G.hold_space);
161 niro 532
162 niro 816 while (G.current_input_file < G.input_file_count)
163     fclose(G.input_file_list[G.current_input_file++]);
164 niro 532 }
165     #else
166     void sed_free_and_close_stuff(void);
167     #endif
168    
169     /* If something bad happens during -i operation, delete temp file */
170    
171     static void cleanup_outname(void)
172     {
173 niro 816 if (G.outname) unlink(G.outname);
174 niro 532 }
175    
176 niro 816 /* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */
177 niro 532
178 niro 816 static void parse_escapes(char *dest, const char *string, int len, char from, char to)
179 niro 532 {
180     int i = 0;
181    
182     while (i < len) {
183     if (string[i] == '\\') {
184     if (!to || string[i+1] == from) {
185     *dest++ = to ? to : string[i+1];
186     i += 2;
187     continue;
188     }
189     *dest++ = string[i++];
190     }
191 niro 816 /* TODO: is it safe wrt a string with trailing '\\' ? */
192 niro 532 *dest++ = string[i++];
193     }
194 niro 816 *dest = '\0';
195 niro 532 }
196    
197 niro 816 static char *copy_parsing_escapes(const char *string, int len)
198 niro 532 {
199     char *dest = xmalloc(len + 1);
200    
201     parse_escapes(dest, string, len, 'n', '\n');
202 niro 816 /* GNU sed also recognizes \t */
203     parse_escapes(dest, dest, strlen(dest), 't', '\t');
204 niro 532 return dest;
205     }
206    
207    
208     /*
209     * index_of_next_unescaped_regexp_delim - walks left to right through a string
210     * beginning at a specified index and returns the index of the next regular
211 niro 816 * expression delimiter (typically a forward slash ('/')) not preceded by
212 niro 532 * a backslash ('\'). A negative delimiter disables square bracket checking.
213     */
214 niro 816 static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
215 niro 532 {
216     int bracket = -1;
217     int escaped = 0;
218     int idx = 0;
219     char ch;
220    
221     if (delimiter < 0) {
222     bracket--;
223     delimiter = -delimiter;
224     }
225    
226     for (; (ch = str[idx]); idx++) {
227     if (bracket >= 0) {
228     if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2
229     && str[idx - 1] == '^')))
230     bracket = -1;
231     } else if (escaped)
232     escaped = 0;
233     else if (ch == '\\')
234     escaped = 1;
235     else if (bracket == -1 && ch == '[')
236     bracket = idx;
237     else if (ch == delimiter)
238     return idx;
239     }
240    
241     /* if we make it to here, we've hit the end of the string */
242     bb_error_msg_and_die("unmatched '%c'", delimiter);
243     }
244    
245     /*
246     * Returns the index of the third delimiter
247     */
248 niro 816 static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
249 niro 532 {
250 niro 816 const char *cmdstr_ptr = cmdstr;
251 niro 532 char delimiter;
252     int idx = 0;
253    
254     /* verify that the 's' or 'y' is followed by something. That something
255     * (typically a 'slash') is now our regexp delimiter... */
256     if (*cmdstr == '\0')
257     bb_error_msg_and_die("bad format in substitution expression");
258     delimiter = *cmdstr_ptr++;
259    
260     /* save the match string */
261     idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr);
262     *match = copy_parsing_escapes(cmdstr_ptr, idx);
263    
264     /* save the replacement string */
265     cmdstr_ptr += idx + 1;
266     idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr);
267     *replace = copy_parsing_escapes(cmdstr_ptr, idx);
268    
269     return ((cmdstr_ptr - cmdstr) + idx);
270     }
271    
272     /*
273     * returns the index in the string just past where the address ends.
274     */
275 niro 816 static int get_address(const char *my_str, int *linenum, regex_t ** regex)
276 niro 532 {
277 niro 816 const char *pos = my_str;
278 niro 532
279     if (isdigit(*my_str)) {
280 niro 816 *linenum = strtol(my_str, (char**)&pos, 10);
281 niro 532 /* endstr shouldnt ever equal NULL */
282     } else if (*my_str == '$') {
283     *linenum = -1;
284     pos++;
285     } else if (*my_str == '/' || *my_str == '\\') {
286     int next;
287     char delimiter;
288     char *temp;
289    
290     delimiter = '/';
291     if (*my_str == '\\') delimiter = *++pos;
292     next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
293     temp = copy_parsing_escapes(pos, next);
294     *regex = xmalloc(sizeof(regex_t));
295 niro 816 xregcomp(*regex, temp, G.regex_type|REG_NEWLINE);
296 niro 532 free(temp);
297     /* Move position to next character after last delimiter */
298     pos += (next+1);
299     }
300     return pos - my_str;
301     }
302    
303     /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */
304 niro 816 static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval)
305 niro 532 {
306     int start = 0, idx, hack = 0;
307    
308     /* Skip whitespace, then grab filename to end of line */
309 niro 816 while (isspace(filecmdstr[start]))
310     start++;
311 niro 532 idx = start;
312 niro 816 while (filecmdstr[idx] && filecmdstr[idx] != '\n')
313     idx++;
314 niro 532
315     /* If lines glued together, put backslash back. */
316 niro 816 if (filecmdstr[idx] == '\n')
317     hack = 1;
318 niro 532 if (idx == start)
319     bb_error_msg_and_die("empty filename");
320     *retval = xstrndup(filecmdstr+start, idx-start+hack+1);
321 niro 816 if (hack)
322     (*retval)[idx] = '\\';
323 niro 532
324     return idx;
325     }
326    
327 niro 816 static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
328 niro 532 {
329 niro 816 int cflags = G.regex_type;
330 niro 532 char *match;
331 niro 816 int idx;
332 niro 532
333     /*
334     * A substitution command should look something like this:
335     * s/match/replace/ #gIpw
336     * || | |||
337     * mandatory optional
338     */
339     idx = parse_regex_delim(substr, &match, &sed_cmd->string);
340    
341     /* determine the number of back references in the match string */
342     /* Note: we compute this here rather than in the do_subst_command()
343     * function to save processor time, at the expense of a little more memory
344     * (4 bits) per sed_cmd */
345    
346     /* process the flags */
347    
348     sed_cmd->which_match = 1;
349     while (substr[++idx]) {
350     /* Parse match number */
351     if (isdigit(substr[idx])) {
352     if (match[0] != '^') {
353     /* Match 0 treated as all, multiple matches we take the last one. */
354 niro 816 const char *pos = substr + idx;
355     /* FIXME: error check? */
356     sed_cmd->which_match = (unsigned)strtol(substr+idx, (char**) &pos, 10);
357 niro 532 idx = pos - substr;
358     }
359     continue;
360     }
361     /* Skip spaces */
362 niro 984 if (isspace(substr[idx]))
363     continue;
364 niro 532
365     switch (substr[idx]) {
366     /* Replace all occurrences */
367     case 'g':
368 niro 816 if (match[0] != '^')
369     sed_cmd->which_match = 0;
370 niro 532 break;
371     /* Print pattern space */
372     case 'p':
373     sed_cmd->sub_p = 1;
374     break;
375     /* Write to file */
376     case 'w':
377     {
378     char *temp;
379 niro 816 idx += parse_file_cmd(/*sed_cmd,*/ substr+idx, &temp);
380 niro 532 break;
381     }
382     /* Ignore case (gnu exension) */
383     case 'I':
384     cflags |= REG_ICASE;
385     break;
386     /* Comment */
387     case '#':
388 niro 1123 // while (substr[++idx]) continue;
389     idx += strlen(substr + idx); // same
390 niro 532 /* Fall through */
391     /* End of command */
392     case ';':
393     case '}':
394     goto out;
395     default:
396     bb_error_msg_and_die("bad option in substitution expression");
397     }
398     }
399 niro 1123 out:
400 niro 532 /* compile the match string into a regex */
401     if (*match != '\0') {
402     /* If match is empty, we use last regex used at runtime */
403     sed_cmd->sub_match = xmalloc(sizeof(regex_t));
404     xregcomp(sed_cmd->sub_match, match, cflags);
405     }
406     free(match);
407    
408     return idx;
409     }
410    
411     /*
412     * Process the commands arguments
413     */
414 niro 816 static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
415 niro 532 {
416     /* handle (s)ubstitution command */
417     if (sed_cmd->cmd == 's')
418     cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
419     /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
420     else if (strchr("aic", sed_cmd->cmd)) {
421     if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
422 niro 984 bb_error_msg_and_die("only a beginning address can be specified for edit commands");
423 niro 532 for (;;) {
424     if (*cmdstr == '\n' || *cmdstr == '\\') {
425     cmdstr++;
426     break;
427 niro 984 }
428     if (!isspace(*cmdstr))
429 niro 532 break;
430 niro 984 cmdstr++;
431 niro 532 }
432     sed_cmd->string = xstrdup(cmdstr);
433 niro 816 /* "\anychar" -> "anychar" */
434     parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0');
435 niro 532 cmdstr += strlen(cmdstr);
436     /* handle file cmds: (r)ead */
437     } else if (strchr("rw", sed_cmd->cmd)) {
438     if (sed_cmd->end_line || sed_cmd->end_match)
439     bb_error_msg_and_die("command only uses one address");
440 niro 816 cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string);
441     if (sed_cmd->cmd == 'w') {
442     sed_cmd->sw_file = xfopen_for_write(sed_cmd->string);
443     sed_cmd->sw_last_char = '\n';
444     }
445 niro 532 /* handle branch commands */
446     } else if (strchr(":btT", sed_cmd->cmd)) {
447     int length;
448    
449     cmdstr = skip_whitespace(cmdstr);
450     length = strcspn(cmdstr, semicolon_whitespace);
451     if (length) {
452     sed_cmd->string = xstrndup(cmdstr, length);
453     cmdstr += length;
454     }
455     }
456     /* translation command */
457     else if (sed_cmd->cmd == 'y') {
458     char *match, *replace;
459     int i = cmdstr[0];
460    
461     cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1;
462     /* \n already parsed, but \delimiter needs unescaping. */
463     parse_escapes(match, match, strlen(match), i, i);
464     parse_escapes(replace, replace, strlen(replace), i, i);
465    
466     sed_cmd->string = xzalloc((strlen(match) + 1) * 2);
467     for (i = 0; match[i] && replace[i]; i++) {
468     sed_cmd->string[i*2] = match[i];
469     sed_cmd->string[i*2+1] = replace[i];
470     }
471     free(match);
472     free(replace);
473     }
474     /* if it wasnt a single-letter command that takes no arguments
475     * then it must be an invalid command.
476     */
477     else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {
478     bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd);
479     }
480    
481     /* give back whatever's left over */
482     return cmdstr;
483     }
484    
485    
486     /* Parse address+command sets, skipping comment lines. */
487    
488 niro 816 static void add_cmd(const char *cmdstr)
489 niro 532 {
490     sed_cmd_t *sed_cmd;
491 niro 992 unsigned len, n;
492 niro 532
493     /* Append this line to any unfinished line from last time. */
494 niro 816 if (G.add_cmd_line) {
495     char *tp = xasprintf("%s\n%s", G.add_cmd_line, cmdstr);
496     free(G.add_cmd_line);
497     cmdstr = G.add_cmd_line = tp;
498 niro 532 }
499    
500 niro 992 /* If this line ends with unescaped backslash, request next line. */
501     n = len = strlen(cmdstr);
502     while (n && cmdstr[n-1] == '\\')
503     n--;
504     if ((len - n) & 1) { /* if odd number of trailing backslashes */
505 niro 816 if (!G.add_cmd_line)
506     G.add_cmd_line = xstrdup(cmdstr);
507 niro 992 G.add_cmd_line[len-1] = '\0';
508 niro 532 return;
509     }
510    
511     /* Loop parsing all commands in this line. */
512     while (*cmdstr) {
513     /* Skip leading whitespace and semicolons */
514     cmdstr += strspn(cmdstr, semicolon_whitespace);
515    
516     /* If no more commands, exit. */
517     if (!*cmdstr) break;
518    
519     /* if this is a comment, jump past it and keep going */
520     if (*cmdstr == '#') {
521     /* "#n" is the same as using -n on the command line */
522     if (cmdstr[1] == 'n')
523 niro 816 G.be_quiet++;
524 niro 532 cmdstr = strpbrk(cmdstr, "\n\r");
525     if (!cmdstr) break;
526     continue;
527     }
528    
529     /* parse the command
530     * format is: [addr][,addr][!]cmd
531     * |----||-----||-|
532     * part1 part2 part3
533     */
534    
535     sed_cmd = xzalloc(sizeof(sed_cmd_t));
536    
537     /* first part (if present) is an address: either a '$', a number or a /regex/ */
538     cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
539    
540     /* second part (if present) will begin with a comma */
541     if (*cmdstr == ',') {
542     int idx;
543    
544     cmdstr++;
545     idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
546     if (!idx)
547     bb_error_msg_and_die("no address after comma");
548     cmdstr += idx;
549     }
550    
551     /* skip whitespace before the command */
552     cmdstr = skip_whitespace(cmdstr);
553    
554     /* Check for inversion flag */
555     if (*cmdstr == '!') {
556     sed_cmd->invert = 1;
557     cmdstr++;
558    
559     /* skip whitespace before the command */
560     cmdstr = skip_whitespace(cmdstr);
561     }
562    
563     /* last part (mandatory) will be a command */
564     if (!*cmdstr)
565     bb_error_msg_and_die("missing command");
566 niro 1123 sed_cmd->cmd = *cmdstr++;
567 niro 532 cmdstr = parse_cmd_args(sed_cmd, cmdstr);
568    
569     /* Add the command to the command array */
570 niro 816 G.sed_cmd_tail->next = sed_cmd;
571     G.sed_cmd_tail = G.sed_cmd_tail->next;
572 niro 532 }
573    
574     /* If we glued multiple lines together, free the memory. */
575 niro 816 free(G.add_cmd_line);
576     G.add_cmd_line = NULL;
577 niro 532 }
578    
579     /* Append to a string, reallocating memory as necessary. */
580    
581     #define PIPE_GROW 64
582    
583     static void pipe_putc(char c)
584     {
585 niro 816 if (G.pipeline.idx == G.pipeline.len) {
586     G.pipeline.buf = xrealloc(G.pipeline.buf,
587     G.pipeline.len + PIPE_GROW);
588     G.pipeline.len += PIPE_GROW;
589 niro 532 }
590 niro 816 G.pipeline.buf[G.pipeline.idx++] = c;
591 niro 532 }
592    
593     static void do_subst_w_backrefs(char *line, char *replace)
594     {
595 niro 984 int i, j;
596 niro 532
597     /* go through the replacement string */
598     for (i = 0; replace[i]; i++) {
599     /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
600     if (replace[i] == '\\') {
601     unsigned backref = replace[++i] - '0';
602     if (backref <= 9) {
603 niro 816 /* print out the text held in G.regmatch[backref] */
604     if (G.regmatch[backref].rm_so != -1) {
605     j = G.regmatch[backref].rm_so;
606     while (j < G.regmatch[backref].rm_eo)
607 niro 532 pipe_putc(line[j++]);
608     }
609     continue;
610     }
611     /* I _think_ it is impossible to get '\' to be
612     * the last char in replace string. Thus we dont check
613     * for replace[i] == NUL. (counterexample anyone?) */
614     /* if we find a backslash escaped character, print the character */
615     pipe_putc(replace[i]);
616     continue;
617     }
618     /* if we find an unescaped '&' print out the whole matched text. */
619     if (replace[i] == '&') {
620 niro 816 j = G.regmatch[0].rm_so;
621     while (j < G.regmatch[0].rm_eo)
622 niro 532 pipe_putc(line[j++]);
623     continue;
624     }
625     /* Otherwise just output the character. */
626     pipe_putc(replace[i]);
627     }
628     }
629    
630 niro 984 static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
631 niro 532 {
632 niro 984 char *line = *line_p;
633 niro 532 int altered = 0;
634 niro 816 unsigned match_count = 0;
635 niro 532 regex_t *current_regex;
636    
637 niro 984 current_regex = sed_cmd->sub_match;
638 niro 532 /* Handle empty regex. */
639 niro 984 if (!current_regex) {
640 niro 816 current_regex = G.previous_regex_ptr;
641 niro 532 if (!current_regex)
642     bb_error_msg_and_die("no previous regexp");
643 niro 984 }
644     G.previous_regex_ptr = current_regex;
645 niro 532
646     /* Find the first match */
647 niro 984 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0))
648 niro 532 return 0;
649    
650     /* Initialize temporary output buffer. */
651 niro 816 G.pipeline.buf = xmalloc(PIPE_GROW);
652     G.pipeline.len = PIPE_GROW;
653     G.pipeline.idx = 0;
654 niro 532
655     /* Now loop through, substituting for matches */
656     do {
657     int i;
658    
659     /* Work around bug in glibc regexec, demonstrated by:
660     echo " a.b" | busybox sed 's [^ .]* x g'
661     The match_count check is so not to break
662     echo "hi" | busybox sed 's/^/!/g' */
663 niro 816 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
664 niro 984 pipe_putc(*line++);
665 niro 532 continue;
666     }
667    
668     match_count++;
669    
670     /* If we aren't interested in this match, output old line to
671     end of match and continue */
672 niro 816 if (sed_cmd->which_match
673     && (sed_cmd->which_match != match_count)
674     ) {
675     for (i = 0; i < G.regmatch[0].rm_eo; i++)
676 niro 984 pipe_putc(*line++);
677 niro 532 continue;
678     }
679    
680     /* print everything before the match */
681 niro 816 for (i = 0; i < G.regmatch[0].rm_so; i++)
682 niro 984 pipe_putc(line[i]);
683 niro 532
684     /* then print the substitution string */
685 niro 984 do_subst_w_backrefs(line, sed_cmd->string);
686 niro 532
687     /* advance past the match */
688 niro 984 line += G.regmatch[0].rm_eo;
689 niro 532 /* flag that something has changed */
690     altered++;
691    
692     /* if we're not doing this globally, get out now */
693 niro 816 if (sed_cmd->which_match)
694     break;
695 niro 532
696 niro 984 //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
697     } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);
698    
699 niro 532 /* Copy rest of string into output pipeline */
700 niro 984 while (1) {
701     char c = *line++;
702     pipe_putc(c);
703     if (c == '\0')
704     break;
705     }
706 niro 532
707 niro 984 free(*line_p);
708     *line_p = G.pipeline.buf;
709 niro 532 return altered;
710     }
711    
712     /* Set command pointer to point to this label. (Does not handle null label.) */
713     static sed_cmd_t *branch_to(char *label)
714     {
715     sed_cmd_t *sed_cmd;
716    
717 niro 816 for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
718 niro 532 if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
719     return sed_cmd;
720     }
721     }
722     bb_error_msg_and_die("can't find label for jump to '%s'", label);
723     }
724    
725     static void append(char *s)
726     {
727 niro 816 llist_add_to_end(&G.append_head, xstrdup(s));
728 niro 532 }
729    
730     static void flush_append(void)
731     {
732     char *data;
733    
734     /* Output appended lines. */
735 niro 816 while ((data = (char *)llist_pop(&G.append_head))) {
736     fprintf(G.nonstdout, "%s\n", data);
737 niro 532 free(data);
738     }
739     }
740    
741     static void add_input_file(FILE *file)
742     {
743 niro 816 G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count);
744     G.input_file_list[G.input_file_count++] = file;
745 niro 532 }
746    
747 niro 816 /* Get next line of input from G.input_file_list, flushing append buffer and
748 niro 532 * noting if we ran out of files without a newline on the last line we read.
749     */
750 niro 816 enum {
751     NO_EOL_CHAR = 1,
752     LAST_IS_NUL = 2,
753     };
754     static char *get_next_line(char *gets_char)
755 niro 532 {
756     char *temp = NULL;
757 niro 816 int len;
758     char gc;
759 niro 532
760     flush_append();
761 niro 816
762     /* will be returned if last line in the file
763     * doesn't end with either '\n' or '\0' */
764     gc = NO_EOL_CHAR;
765     while (G.current_input_file < G.input_file_count) {
766     FILE *fp = G.input_file_list[G.current_input_file];
767 niro 532 /* Read line up to a newline or NUL byte, inclusive,
768     * return malloc'ed char[]. length of the chunk read
769     * is stored in len. NULL if EOF/error */
770 niro 816 temp = bb_get_chunk_from_file(fp, &len);
771 niro 532 if (temp) {
772     /* len > 0 here, it's ok to do temp[len-1] */
773     char c = temp[len-1];
774     if (c == '\n' || c == '\0') {
775     temp[len-1] = '\0';
776 niro 816 gc = c;
777     if (c == '\0') {
778     int ch = fgetc(fp);
779     if (ch != EOF)
780     ungetc(ch, fp);
781     else
782     gc = LAST_IS_NUL;
783     }
784 niro 532 }
785 niro 816 /* else we put NO_EOL_CHAR into *gets_char */
786 niro 532 break;
787 niro 816
788     /* NB: I had the idea of peeking next file(s) and returning
789     * NO_EOL_CHAR only if it is the *last* non-empty
790     * input file. But there is a case where this won't work:
791     * file1: "a woo\nb woo"
792     * file2: "c no\nd no"
793     * sed -ne 's/woo/bang/p' input1 input2 => "a bang\nb bang"
794     * (note: *no* newline after "b bang"!) */
795 niro 532 }
796     /* Close this file and advance to next one */
797 niro 816 fclose(fp);
798     G.current_input_file++;
799 niro 532 }
800 niro 816 *gets_char = gc;
801 niro 532 return temp;
802     }
803    
804     /* Output line of text. */
805     /* Note:
806 niro 816 * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
807 niro 532 * Without them, we had this:
808     * echo -n thingy >z1
809     * echo -n again >z2
810     * >znull
811     * sed "s/i/z/" z1 z2 znull | hexdump -vC
812     * output:
813     * gnu sed 4.1.5:
814     * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn|
815     * bbox:
816     * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
817     */
818 niro 816 static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
819 niro 532 {
820 niro 816 char lpc = *last_puts_char;
821 niro 532
822 niro 816 /* Need to insert a '\n' between two files because first file's
823     * last line wasn't terminated? */
824     if (lpc != '\n' && lpc != '\0') {
825 niro 532 fputc('\n', file);
826 niro 816 lpc = '\n';
827 niro 532 }
828     fputs(s, file);
829 niro 816
830     /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
831 niro 532 if (s[0])
832 niro 816 lpc = 'x';
833    
834     /* had trailing '\0' and it was last char of file? */
835     if (last_gets_char == LAST_IS_NUL) {
836     fputc('\0', file);
837     lpc = 'x'; /* */
838     } else
839     /* had trailing '\n' or '\0'? */
840     if (last_gets_char != NO_EOL_CHAR) {
841     fputc(last_gets_char, file);
842     lpc = last_gets_char;
843 niro 532 }
844    
845     if (ferror(file)) {
846     xfunc_error_retval = 4; /* It's what gnu sed exits with... */
847     bb_error_msg_and_die(bb_msg_write_error);
848     }
849 niro 816 *last_puts_char = lpc;
850     }
851 niro 532
852 niro 816 #define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n))
853    
854     static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space)
855     {
856     int retval = sed_cmd->beg_match && !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0);
857     if (retval)
858     G.previous_regex_ptr = sed_cmd->beg_match;
859     return retval;
860 niro 532 }
861    
862     /* Process all the lines in all the files */
863    
864     static void process_files(void)
865     {
866     char *pattern_space, *next_line;
867 niro 816 int linenum = 0;
868     char last_puts_char = '\n';
869     char last_gets_char, next_gets_char;
870 niro 532 sed_cmd_t *sed_cmd;
871     int substituted;
872    
873     /* Prime the pump */
874 niro 816 next_line = get_next_line(&next_gets_char);
875 niro 532
876 niro 984 /* Go through every line in each file */
877 niro 816 again:
878 niro 532 substituted = 0;
879    
880     /* Advance to next line. Stop if out of lines. */
881     pattern_space = next_line;
882 niro 984 if (!pattern_space)
883     return;
884 niro 816 last_gets_char = next_gets_char;
885 niro 532
886     /* Read one line in advance so we can act on the last line,
887     * the '$' address */
888 niro 816 next_line = get_next_line(&next_gets_char);
889 niro 532 linenum++;
890 niro 984
891     /* For every line, go through all the commands */
892 niro 816 restart:
893     for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
894 niro 532 int old_matched, matched;
895    
896     old_matched = sed_cmd->in_match;
897    
898     /* Determine if this command matches this line: */
899    
900 niro 1123 //bb_error_msg("match1:%d", sed_cmd->in_match);
901     //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
902     // && !sed_cmd->beg_match && !sed_cmd->end_match));
903     //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0
904     // && (sed_cmd->end_line || sed_cmd->end_match
905     // ? (sed_cmd->beg_line <= linenum)
906     // : (sed_cmd->beg_line == linenum)
907     // )
908     // )
909     //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space)));
910     //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));
911    
912 niro 532 /* Are we continuing a previous multi-line match? */
913     sed_cmd->in_match = sed_cmd->in_match
914     /* Or is no range necessary? */
915     || (!sed_cmd->beg_line && !sed_cmd->end_line
916     && !sed_cmd->beg_match && !sed_cmd->end_match)
917     /* Or did we match the start of a numerical range? */
918 niro 1123 || (sed_cmd->beg_line > 0
919     && (sed_cmd->end_line || sed_cmd->end_match
920     /* note: even if end is numeric and is < linenum too,
921     * GNU sed matches! We match too */
922     ? (sed_cmd->beg_line <= linenum) /* N,end */
923     : (sed_cmd->beg_line == linenum) /* N */
924     )
925     )
926 niro 532 /* Or does this line match our begin address regex? */
927 niro 816 || (beg_match(sed_cmd, pattern_space))
928 niro 532 /* Or did we match last line of input? */
929     || (sed_cmd->beg_line == -1 && next_line == NULL);
930    
931     /* Snapshot the value */
932     matched = sed_cmd->in_match;
933    
934 niro 984 //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
935     //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);
936    
937 niro 532 /* Is this line the end of the current match? */
938    
939     if (matched) {
940 niro 984 /* once matched, "n,xxx" range is dead, disabling it */
941     if (sed_cmd->beg_line > 0)
942     sed_cmd->beg_line = -2;
943 niro 532 sed_cmd->in_match = !(
944     /* has the ending line come, or is this a single address command? */
945     (sed_cmd->end_line ?
946     sed_cmd->end_line == -1 ?
947     !next_line
948     : (sed_cmd->end_line <= linenum)
949     : !sed_cmd->end_match
950     )
951     /* or does this line matches our last address regex */
952     || (sed_cmd->end_match && old_matched
953     && (regexec(sed_cmd->end_match,
954 niro 816 pattern_space, 0, NULL, 0) == 0))
955 niro 532 );
956     }
957    
958 niro 984 /* Skip blocks of commands we didn't match */
959 niro 532 if (sed_cmd->cmd == '{') {
960 niro 816 if (sed_cmd->invert ? matched : !matched) {
961 niro 992 unsigned nest_cnt = 0;
962     while (1) {
963     if (sed_cmd->cmd == '{')
964     nest_cnt++;
965     if (sed_cmd->cmd == '}') {
966     nest_cnt--;
967     if (nest_cnt == 0)
968     break;
969     }
970 niro 532 sed_cmd = sed_cmd->next;
971 niro 816 if (!sed_cmd)
972     bb_error_msg_and_die("unterminated {");
973     }
974     }
975 niro 532 continue;
976     }
977    
978     /* Okay, so did this line match? */
979 niro 984 if (sed_cmd->invert ? matched : !matched)
980     continue; /* no */
981 niro 532
982 niro 984 /* Update last used regex in case a blank substitute BRE is found */
983     if (sed_cmd->beg_match) {
984     G.previous_regex_ptr = sed_cmd->beg_match;
985     }
986 niro 532
987 niro 984 /* actual sedding */
988     switch (sed_cmd->cmd) {
989 niro 532
990 niro 984 /* Print line number */
991     case '=':
992     fprintf(G.nonstdout, "%d\n", linenum);
993     break;
994 niro 532
995 niro 984 /* Write the current pattern space up to the first newline */
996     case 'P':
997     {
998     char *tmp = strchr(pattern_space, '\n');
999     if (tmp) {
1000     *tmp = '\0';
1001     /* TODO: explain why '\n' below */
1002 niro 816 sed_puts(pattern_space, '\n');
1003 niro 984 *tmp = '\n';
1004 niro 532 break;
1005     }
1006 niro 984 /* Fall Through */
1007     }
1008 niro 532
1009 niro 984 /* Write the current pattern space to output */
1010     case 'p':
1011     /* NB: we print this _before_ the last line
1012     * (of current file) is printed. Even if
1013     * that line is nonterminated, we print
1014     * '\n' here (gnu sed does the same) */
1015     sed_puts(pattern_space, '\n');
1016     break;
1017     /* Delete up through first newline */
1018     case 'D':
1019     {
1020     char *tmp = strchr(pattern_space, '\n');
1021     if (tmp) {
1022 niro 1123 overlapping_strcpy(pattern_space, tmp + 1);
1023 niro 984 goto restart;
1024     }
1025     }
1026     /* discard this line. */
1027     case 'd':
1028     goto discard_line;
1029 niro 532
1030 niro 984 /* Substitute with regex */
1031     case 's':
1032     if (!do_subst_command(sed_cmd, &pattern_space))
1033 niro 532 break;
1034 niro 984 substituted |= 1;
1035 niro 532
1036 niro 984 /* handle p option */
1037     if (sed_cmd->sub_p)
1038     sed_puts(pattern_space, last_gets_char);
1039     /* handle w option */
1040     if (sed_cmd->sw_file)
1041     puts_maybe_newline(
1042     pattern_space, sed_cmd->sw_file,
1043     &sed_cmd->sw_last_char, last_gets_char);
1044     break;
1045 niro 532
1046 niro 984 /* Append line to linked list to be printed later */
1047     case 'a':
1048     append(sed_cmd->string);
1049     break;
1050 niro 532
1051 niro 984 /* Insert text before this line */
1052     case 'i':
1053     sed_puts(sed_cmd->string, '\n');
1054     break;
1055 niro 532
1056 niro 984 /* Cut and paste text (replace) */
1057     case 'c':
1058     /* Only triggers on last line of a matching range. */
1059     if (!sed_cmd->in_match)
1060 niro 992 sed_puts(sed_cmd->string, '\n');
1061 niro 984 goto discard_line;
1062 niro 532
1063 niro 984 /* Read file, append contents to output */
1064     case 'r':
1065     {
1066     FILE *rfile;
1067     rfile = fopen_for_read(sed_cmd->string);
1068     if (rfile) {
1069     char *line;
1070    
1071     while ((line = xmalloc_fgetline(rfile))
1072     != NULL)
1073     append(line);
1074     xprint_and_close_file(rfile);
1075 niro 532 }
1076    
1077 niro 984 break;
1078     }
1079 niro 532
1080 niro 984 /* Write pattern space to file. */
1081     case 'w':
1082     puts_maybe_newline(
1083     pattern_space, sed_cmd->sw_file,
1084     &sed_cmd->sw_last_char, last_gets_char);
1085     break;
1086 niro 532
1087 niro 984 /* Read next line from input */
1088     case 'n':
1089     if (!G.be_quiet)
1090     sed_puts(pattern_space, last_gets_char);
1091     if (next_line) {
1092     free(pattern_space);
1093     pattern_space = next_line;
1094 niro 816 last_gets_char = next_gets_char;
1095     next_line = get_next_line(&next_gets_char);
1096 niro 984 substituted = 0;
1097 niro 532 linenum++;
1098     break;
1099     }
1100 niro 984 /* fall through */
1101 niro 532
1102 niro 984 /* Quit. End of script, end of input. */
1103     case 'q':
1104     /* Exit the outer while loop */
1105     free(next_line);
1106     next_line = NULL;
1107     goto discard_commands;
1108 niro 532
1109 niro 984 /* Append the next line to the current line */
1110     case 'N':
1111     {
1112     int len;
1113     /* If no next line, jump to end of script and exit. */
1114     if (next_line == NULL) {
1115     free(next_line);
1116     next_line = NULL;
1117     goto discard_line;
1118     }
1119 niro 1123 /* Append next_line, read new next_line. */
1120 niro 984 len = strlen(pattern_space);
1121     pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2);
1122     pattern_space[len] = '\n';
1123     strcpy(pattern_space + len+1, next_line);
1124     last_gets_char = next_gets_char;
1125     next_line = get_next_line(&next_gets_char);
1126     linenum++;
1127     break;
1128     }
1129    
1130     /* Test/branch if substitution occurred */
1131     case 't':
1132     if (!substituted) break;
1133     substituted = 0;
1134     /* Fall through */
1135     /* Test/branch if substitution didn't occur */
1136     case 'T':
1137     if (substituted) break;
1138     /* Fall through */
1139     /* Branch to label */
1140     case 'b':
1141     if (!sed_cmd->string) goto discard_commands;
1142     else sed_cmd = branch_to(sed_cmd->string);
1143     break;
1144     /* Transliterate characters */
1145     case 'y':
1146     {
1147     int i, j;
1148     for (i = 0; pattern_space[i]; i++) {
1149     for (j = 0; sed_cmd->string[j]; j += 2) {
1150     if (pattern_space[i] == sed_cmd->string[j]) {
1151     pattern_space[i] = sed_cmd->string[j + 1];
1152     break;
1153 niro 532 }
1154     }
1155     }
1156    
1157 niro 984 break;
1158     }
1159     case 'g': /* Replace pattern space with hold space */
1160     free(pattern_space);
1161     pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
1162     break;
1163     case 'G': /* Append newline and hold space to pattern space */
1164     {
1165     int pattern_space_size = 2;
1166     int hold_space_size = 0;
1167 niro 532
1168 niro 984 if (pattern_space)
1169     pattern_space_size += strlen(pattern_space);
1170     if (G.hold_space)
1171     hold_space_size = strlen(G.hold_space);
1172     pattern_space = xrealloc(pattern_space,
1173     pattern_space_size + hold_space_size);
1174     if (pattern_space_size == 2)
1175     pattern_space[0] = 0;
1176     strcat(pattern_space, "\n");
1177     if (G.hold_space)
1178     strcat(pattern_space, G.hold_space);
1179     last_gets_char = '\n';
1180 niro 532
1181 niro 984 break;
1182     }
1183     case 'h': /* Replace hold space with pattern space */
1184     free(G.hold_space);
1185     G.hold_space = xstrdup(pattern_space);
1186     break;
1187     case 'H': /* Append newline and pattern space to hold space */
1188     {
1189     int hold_space_size = 2;
1190     int pattern_space_size = 0;
1191 niro 532
1192 niro 984 if (G.hold_space)
1193     hold_space_size += strlen(G.hold_space);
1194     if (pattern_space)
1195     pattern_space_size = strlen(pattern_space);
1196     G.hold_space = xrealloc(G.hold_space,
1197     hold_space_size + pattern_space_size);
1198 niro 532
1199 niro 984 if (hold_space_size == 2)
1200     *G.hold_space = 0;
1201     strcat(G.hold_space, "\n");
1202     if (pattern_space)
1203     strcat(G.hold_space, pattern_space);
1204    
1205     break;
1206 niro 532 }
1207 niro 984 case 'x': /* Exchange hold and pattern space */
1208     {
1209     char *tmp = pattern_space;
1210     pattern_space = G.hold_space ? G.hold_space : xzalloc(1);
1211     last_gets_char = '\n';
1212     G.hold_space = tmp;
1213     break;
1214     }
1215     } /* switch */
1216     } /* for each cmd */
1217 niro 532
1218     /*
1219 niro 984 * Exit point from sedding...
1220 niro 532 */
1221 niro 816 discard_commands:
1222 niro 532 /* we will print the line unless we were told to be quiet ('-n')
1223     or if the line was suppressed (ala 'd'elete) */
1224 niro 816 if (!G.be_quiet)
1225     sed_puts(pattern_space, last_gets_char);
1226 niro 532
1227     /* Delete and such jump here. */
1228 niro 816 discard_line:
1229 niro 532 flush_append();
1230     free(pattern_space);
1231    
1232     goto again;
1233     }
1234    
1235     /* It is possible to have a command line argument with embedded
1236 niro 816 * newlines. This counts as multiple command lines.
1237     * However, newline can be escaped: 's/e/z\<newline>z/'
1238     * We check for this.
1239     */
1240 niro 532
1241     static void add_cmd_block(char *cmdstr)
1242     {
1243 niro 816 char *sv, *eol;
1244 niro 532
1245 niro 816 cmdstr = sv = xstrdup(cmdstr);
1246     do {
1247     eol = strchr(cmdstr, '\n');
1248     next:
1249     if (eol) {
1250     /* Count preceding slashes */
1251     int slashes = 0;
1252     char *sl = eol;
1253 niro 532
1254 niro 816 while (sl != cmdstr && *--sl == '\\')
1255     slashes++;
1256     /* Odd number of preceding slashes - newline is escaped */
1257     if (slashes & 1) {
1258     overlapping_strcpy(eol - 1, eol);
1259     eol = strchr(eol, '\n');
1260     goto next;
1261     }
1262     *eol = '\0';
1263     }
1264     add_cmd(cmdstr);
1265     cmdstr = eol + 1;
1266     } while (eol);
1267     free(sv);
1268 niro 532 }
1269    
1270 niro 816 int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1271     int sed_main(int argc UNUSED_PARAM, char **argv)
1272 niro 532 {
1273     enum {
1274     OPT_in_place = 1 << 0,
1275     };
1276     unsigned opt;
1277     llist_t *opt_e, *opt_f;
1278     int status = EXIT_SUCCESS;
1279    
1280 niro 816 INIT_G();
1281 niro 532
1282     /* destroy command strings on exit */
1283     if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff);
1284    
1285     /* Lie to autoconf when it starts asking stupid questions. */
1286 niro 816 if (argv[1] && !strcmp(argv[1], "--version")) {
1287 niro 532 puts("This is not GNU sed version 4.0");
1288     return 0;
1289     }
1290    
1291     /* do normal option parsing */
1292     opt_e = opt_f = NULL;
1293     opt_complementary = "e::f::" /* can occur multiple times */
1294     "nn"; /* count -n */
1295 niro 816 opt = getopt32(argv, "irne:f:", &opt_e, &opt_f,
1296     &G.be_quiet); /* counter for -n */
1297     //argc -= optind;
1298 niro 532 argv += optind;
1299     if (opt & OPT_in_place) { // -i
1300     atexit(cleanup_outname);
1301     }
1302 niro 816 if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r
1303     //if (opt & 0x4) G.be_quiet++; // -n
1304     while (opt_e) { // -e
1305     add_cmd_block(llist_pop(&opt_e));
1306 niro 532 }
1307 niro 816 while (opt_f) { // -f
1308     char *line;
1309     FILE *cmdfile;
1310     cmdfile = xfopen_for_read(llist_pop(&opt_f));
1311     while ((line = xmalloc_fgetline(cmdfile)) != NULL) {
1312     add_cmd(line);
1313     free(line);
1314     }
1315     fclose(cmdfile);
1316 niro 532 }
1317     /* if we didn't get a pattern from -e or -f, use argv[0] */
1318     if (!(opt & 0x18)) {
1319 niro 816 if (!*argv)
1320 niro 532 bb_show_usage();
1321     add_cmd_block(*argv++);
1322     }
1323     /* Flush any unfinished commands. */
1324     add_cmd("");
1325    
1326     /* By default, we write to stdout */
1327 niro 816 G.nonstdout = stdout;
1328 niro 532
1329     /* argv[0..(argc-1)] should be names of file to process. If no
1330     * files were specified or '-' was specified, take input from stdin.
1331     * Otherwise, we process all the files specified. */
1332     if (argv[0] == NULL) {
1333     if (opt & OPT_in_place)
1334     bb_error_msg_and_die(bb_msg_requires_arg, "-i");
1335     add_input_file(stdin);
1336     } else {
1337     int i;
1338     FILE *file;
1339    
1340 niro 816 for (i = 0; argv[i]; i++) {
1341 niro 532 struct stat statbuf;
1342     int nonstdoutfd;
1343    
1344     if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
1345     add_input_file(stdin);
1346     process_files();
1347     continue;
1348     }
1349     file = fopen_or_warn(argv[i], "r");
1350     if (!file) {
1351     status = EXIT_FAILURE;
1352     continue;
1353     }
1354     if (!(opt & OPT_in_place)) {
1355     add_input_file(file);
1356     continue;
1357     }
1358    
1359 niro 816 G.outname = xasprintf("%sXXXXXX", argv[i]);
1360     nonstdoutfd = mkstemp(G.outname);
1361 niro 532 if (-1 == nonstdoutfd)
1362 niro 984 bb_perror_msg_and_die("can't create temp file %s", G.outname);
1363     G.nonstdout = xfdopen_for_write(nonstdoutfd);
1364 niro 532
1365 niro 984 /* Set permissions/owner of output file */
1366 niro 532 fstat(fileno(file), &statbuf);
1367 niro 1123 /* chmod'ing AFTER chown would preserve suid/sgid bits,
1368     * but GNU sed 4.2.1 does not preserve them either */
1369 niro 532 fchmod(nonstdoutfd, statbuf.st_mode);
1370 niro 984 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);
1371 niro 532 add_input_file(file);
1372     process_files();
1373 niro 816 fclose(G.nonstdout);
1374 niro 532
1375 niro 816 G.nonstdout = stdout;
1376 niro 532 /* unlink(argv[i]); */
1377 niro 816 xrename(G.outname, argv[i]);
1378     free(G.outname);
1379     G.outname = NULL;
1380 niro 532 }
1381 niro 1123 /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
1382     * if (G.current_input_file >= G.input_file_count)
1383     * return status;
1384     * but it's not needed since process_files() works correctly
1385     * in this case too. */
1386 niro 532 }
1387 niro 1123 process_files();
1388 niro 532
1389     return status;
1390     }