1*cf5a6c84SAndroid Build Coastguard Worker /* sed.c - stream editor. Thing that does s/// and other stuff.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2014 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * xform See https://www.gnu.org/software/tar/manual/html_section/transform.html
8*cf5a6c84SAndroid Build Coastguard Worker *
9*cf5a6c84SAndroid Build Coastguard Worker * TODO: lines > 2G could wrap signed int length counters. Not just getline()
10*cf5a6c84SAndroid Build Coastguard Worker * but N and s///
11*cf5a6c84SAndroid Build Coastguard Worker * TODO: make y// handle unicode, unicode delimiters
12*cf5a6c84SAndroid Build Coastguard Worker * TODO: handle error return from emit(), error_msg/exit consistently
13*cf5a6c84SAndroid Build Coastguard Worker * What's the right thing to do for -i when write fails? Skip to next?
14*cf5a6c84SAndroid Build Coastguard Worker * test '//q' with no previous regex, also repeat previous regex?
15*cf5a6c84SAndroid Build Coastguard Worker *
16*cf5a6c84SAndroid Build Coastguard Worker * Deviations from POSIX: allow extended regular expressions with -r,
17*cf5a6c84SAndroid Build Coastguard Worker * editing in place with -i, separate with -s, NUL-delimited strings with -z,
18*cf5a6c84SAndroid Build Coastguard Worker * printf escapes in text, line continuations, semicolons after all commands,
19*cf5a6c84SAndroid Build Coastguard Worker * 2-address anywhere an address is allowed, "T" command, multiline
20*cf5a6c84SAndroid Build Coastguard Worker * continuations for [abc], \; to end [abc] argument before end of line.
21*cf5a6c84SAndroid Build Coastguard Worker * Explicit violations of stuff posix says NOT to do: N at EOF does default
22*cf5a6c84SAndroid Build Coastguard Worker * print, l escapes \n
23*cf5a6c84SAndroid Build Coastguard Worker * Added --tarxform mode to support tar --xform
24*cf5a6c84SAndroid Build Coastguard Worker
25*cf5a6c84SAndroid Build Coastguard Worker USE_SED(NEWTOY(sed, "(help)(version)(tarxform)e*f*i:;nErz(null-data)s[+Er]", TOYFLAG_BIN|TOYFLAG_AUTOCONF))
26*cf5a6c84SAndroid Build Coastguard Worker
27*cf5a6c84SAndroid Build Coastguard Worker config SED
28*cf5a6c84SAndroid Build Coastguard Worker bool "sed"
29*cf5a6c84SAndroid Build Coastguard Worker default y
30*cf5a6c84SAndroid Build Coastguard Worker help
31*cf5a6c84SAndroid Build Coastguard Worker usage: sed [-inrszE] [-e SCRIPT]...|SCRIPT [-f SCRIPT_FILE]... [FILE...]
32*cf5a6c84SAndroid Build Coastguard Worker
33*cf5a6c84SAndroid Build Coastguard Worker Stream editor. Apply editing SCRIPTs to lines of input.
34*cf5a6c84SAndroid Build Coastguard Worker
35*cf5a6c84SAndroid Build Coastguard Worker -e Add SCRIPT to list
36*cf5a6c84SAndroid Build Coastguard Worker -f Add contents of SCRIPT_FILE to list
37*cf5a6c84SAndroid Build Coastguard Worker -i Edit each file in place (-iEXT keeps backup file with extension EXT)
38*cf5a6c84SAndroid Build Coastguard Worker -n No default output (use the p command to output matched lines)
39*cf5a6c84SAndroid Build Coastguard Worker -r Use extended regular expression syntax
40*cf5a6c84SAndroid Build Coastguard Worker -E POSIX alias for -r
41*cf5a6c84SAndroid Build Coastguard Worker -s Treat input files separately (implied by -i)
42*cf5a6c84SAndroid Build Coastguard Worker -z Use \0 rather than \n as input line separator
43*cf5a6c84SAndroid Build Coastguard Worker
44*cf5a6c84SAndroid Build Coastguard Worker A SCRIPT is one or more COMMANDs separated by newlines or semicolons.
45*cf5a6c84SAndroid Build Coastguard Worker All -e SCRIPTs and -f SCRIPT_FILE contents are combined in order as if
46*cf5a6c84SAndroid Build Coastguard Worker separated by newlines. If no -e or -f then first argument is the SCRIPT.
47*cf5a6c84SAndroid Build Coastguard Worker
48*cf5a6c84SAndroid Build Coastguard Worker COMMANDs apply to every line unless prefixed with an ADDRESS of the form:
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker [ADDRESS[,ADDRESS]][!]COMMAND
51*cf5a6c84SAndroid Build Coastguard Worker
52*cf5a6c84SAndroid Build Coastguard Worker ADDRESS is a line number (starting at 1), a /REGULAR EXPRESSION/, or $ for
53*cf5a6c84SAndroid Build Coastguard Worker last line (-s or -i makes it last line of each file). One address matches one
54*cf5a6c84SAndroid Build Coastguard Worker line, ADDRESS,ADDRESS matches from first to second inclusive. Two regexes can
55*cf5a6c84SAndroid Build Coastguard Worker match multiple ranges. ADDRESS,+N ends N lines later. ! inverts the match.
56*cf5a6c84SAndroid Build Coastguard Worker
57*cf5a6c84SAndroid Build Coastguard Worker REGULAR EXPRESSIONS start and end with the same character (anything but
58*cf5a6c84SAndroid Build Coastguard Worker backslash or newline). To use the delimiter in the regex escape it with a
59*cf5a6c84SAndroid Build Coastguard Worker backslash, and printf escapes (\abcefnrtv and octal, hex, and unicode) work.
60*cf5a6c84SAndroid Build Coastguard Worker An empty regex repeats the previous one. ADDRESS regexes require any
61*cf5a6c84SAndroid Build Coastguard Worker first delimiter except / to be \escaped to distinguish it from COMMANDs.
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker Sed reads each line of input, processes it, and writes it out or discards it
64*cf5a6c84SAndroid Build Coastguard Worker before reading the next. Sed can remember one additional line in a separate
65*cf5a6c84SAndroid Build Coastguard Worker buffer (the h, H, g, G, and x commands), and can read the next line of input
66*cf5a6c84SAndroid Build Coastguard Worker early (the n and N commands), but otherwise operates on individual lines.
67*cf5a6c84SAndroid Build Coastguard Worker
68*cf5a6c84SAndroid Build Coastguard Worker Each COMMAND starts with a single character. Commands with no arguments are:
69*cf5a6c84SAndroid Build Coastguard Worker
70*cf5a6c84SAndroid Build Coastguard Worker ! Run this command when the ADDRESS _didn't_ match.
71*cf5a6c84SAndroid Build Coastguard Worker { Start new command block, continuing until a corresponding "}".
72*cf5a6c84SAndroid Build Coastguard Worker Command blocks nest and can have ADDRESSes applying to the whole block.
73*cf5a6c84SAndroid Build Coastguard Worker } End command block (this COMMAND cannot have an address)
74*cf5a6c84SAndroid Build Coastguard Worker d Delete this line and move on to the next one
75*cf5a6c84SAndroid Build Coastguard Worker (ignores remaining COMMANDs)
76*cf5a6c84SAndroid Build Coastguard Worker D Delete one line of input and restart command SCRIPT (same as "d"
77*cf5a6c84SAndroid Build Coastguard Worker unless you've glued lines together with "N" or similar)
78*cf5a6c84SAndroid Build Coastguard Worker g Get remembered line (overwriting current line)
79*cf5a6c84SAndroid Build Coastguard Worker G Get remembered line (appending to current line)
80*cf5a6c84SAndroid Build Coastguard Worker h Remember this line (overwriting remembered line)
81*cf5a6c84SAndroid Build Coastguard Worker H Remember this line (appending to remembered line, if any)
82*cf5a6c84SAndroid Build Coastguard Worker l Print line escaping \abfrtvn, octal escape other nonprintng chars,
83*cf5a6c84SAndroid Build Coastguard Worker wrap lines to terminal width with \, append $ to end of line.
84*cf5a6c84SAndroid Build Coastguard Worker n Print default output and read next line over current line (quit at EOF)
85*cf5a6c84SAndroid Build Coastguard Worker N Append \n and next line of input to this line. Quit at EOF without
86*cf5a6c84SAndroid Build Coastguard Worker default output. Advances line counter for ADDRESS and "=".
87*cf5a6c84SAndroid Build Coastguard Worker p Print this line
88*cf5a6c84SAndroid Build Coastguard Worker P Print this line up to first newline (from "N")
89*cf5a6c84SAndroid Build Coastguard Worker q Quit (print default output, no more commands processed or lines read)
90*cf5a6c84SAndroid Build Coastguard Worker x Exchange this line with remembered line (overwrite in both directions)
91*cf5a6c84SAndroid Build Coastguard Worker = Print the current line number (plus newline)
92*cf5a6c84SAndroid Build Coastguard Worker # Comment, ignores rest of this line of SCRIPT (until newline)
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker Commands that take an argument:
95*cf5a6c84SAndroid Build Coastguard Worker
96*cf5a6c84SAndroid Build Coastguard Worker : LABEL Target for jump commands
97*cf5a6c84SAndroid Build Coastguard Worker a TEXT Append text to output before reading next line
98*cf5a6c84SAndroid Build Coastguard Worker b LABEL Branch, jumps to :LABEL (with no LABEL to end of SCRIPT)
99*cf5a6c84SAndroid Build Coastguard Worker c TEXT Delete matching ADDRESS range and output TEXT instead
100*cf5a6c84SAndroid Build Coastguard Worker i TEXT Insert text (output immediately)
101*cf5a6c84SAndroid Build Coastguard Worker r FILE Append contents of FILE to output before reading next line.
102*cf5a6c84SAndroid Build Coastguard Worker s/S/R/F Search for regex S replace match with R using flags F. Delimiter
103*cf5a6c84SAndroid Build Coastguard Worker is anything but \n or \, escape with \ to use in S or R. Printf
104*cf5a6c84SAndroid Build Coastguard Worker escapes work. Unescaped & in R becomes full matched text, \1
105*cf5a6c84SAndroid Build Coastguard Worker through \9 = parenthetical subexpression from S. \ at end of
106*cf5a6c84SAndroid Build Coastguard Worker line appends next line of SCRIPT. The flags in F are:
107*cf5a6c84SAndroid Build Coastguard Worker [0-9] A number N, substitute only Nth match
108*cf5a6c84SAndroid Build Coastguard Worker g Global, substitute all matches
109*cf5a6c84SAndroid Build Coastguard Worker i/I Ignore case when matching
110*cf5a6c84SAndroid Build Coastguard Worker p Print resulting line when match found and replaced
111*cf5a6c84SAndroid Build Coastguard Worker w [file] Write (append) line to file when match replaced
112*cf5a6c84SAndroid Build Coastguard Worker t LABEL Test, jump if s/// command matched this line since last test
113*cf5a6c84SAndroid Build Coastguard Worker T LABEL Test false, jump to :LABEL only if no s/// found a match
114*cf5a6c84SAndroid Build Coastguard Worker w FILE Write (append) line to file
115*cf5a6c84SAndroid Build Coastguard Worker y/old/new/ Change each character in 'old' to corresponding character
116*cf5a6c84SAndroid Build Coastguard Worker in 'new' (with standard backslash escapes, delimiter can be
117*cf5a6c84SAndroid Build Coastguard Worker any repeated character except \ or \n)
118*cf5a6c84SAndroid Build Coastguard Worker
119*cf5a6c84SAndroid Build Coastguard Worker The TEXT arguments (to a c i) may end with an unescaped "\" to append
120*cf5a6c84SAndroid Build Coastguard Worker the next line (leading whitespace is not skipped), and treat ";" as a
121*cf5a6c84SAndroid Build Coastguard Worker literal character (use "\;" instead).
122*cf5a6c84SAndroid Build Coastguard Worker */
123*cf5a6c84SAndroid Build Coastguard Worker
124*cf5a6c84SAndroid Build Coastguard Worker #define FOR_sed
125*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
126*cf5a6c84SAndroid Build Coastguard Worker
127*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
128*cf5a6c84SAndroid Build Coastguard Worker char *i;
129*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *f, *e;
130*cf5a6c84SAndroid Build Coastguard Worker
131*cf5a6c84SAndroid Build Coastguard Worker // processed pattern list
132*cf5a6c84SAndroid Build Coastguard Worker struct double_list *pattern;
133*cf5a6c84SAndroid Build Coastguard Worker
134*cf5a6c84SAndroid Build Coastguard Worker char *nextline, *remember, *tarxform;
135*cf5a6c84SAndroid Build Coastguard Worker void *restart, *lastregex;
136*cf5a6c84SAndroid Build Coastguard Worker long nextlen, rememberlen, count;
137*cf5a6c84SAndroid Build Coastguard Worker int fdout, noeol;
138*cf5a6c84SAndroid Build Coastguard Worker unsigned xx, tarxlen, xflags;
139*cf5a6c84SAndroid Build Coastguard Worker char delim, xftype;
140*cf5a6c84SAndroid Build Coastguard Worker )
141*cf5a6c84SAndroid Build Coastguard Worker
142*cf5a6c84SAndroid Build Coastguard Worker // Linked list of parsed sed commands. Offset fields indicate location where
143*cf5a6c84SAndroid Build Coastguard Worker // regex or string starts, ala offset+(char *)struct, because we remalloc()
144*cf5a6c84SAndroid Build Coastguard Worker // these to expand them for multiline inputs, and pointers would have to be
145*cf5a6c84SAndroid Build Coastguard Worker // individually adjusted.
146*cf5a6c84SAndroid Build Coastguard Worker
147*cf5a6c84SAndroid Build Coastguard Worker struct sedcmd {
148*cf5a6c84SAndroid Build Coastguard Worker struct sedcmd *next, *prev;
149*cf5a6c84SAndroid Build Coastguard Worker
150*cf5a6c84SAndroid Build Coastguard Worker // Begin and end of each match
151*cf5a6c84SAndroid Build Coastguard Worker long lmatch[2]; // line number of match
152*cf5a6c84SAndroid Build Coastguard Worker int rmatch[2]; // offset of regex struct for prefix matches (/abc/,/def/p)
153*cf5a6c84SAndroid Build Coastguard Worker int arg1, arg2, w; // offset of two arguments per command, plus s//w filename
154*cf5a6c84SAndroid Build Coastguard Worker unsigned not, hit;
155*cf5a6c84SAndroid Build Coastguard Worker unsigned sflags; // s///flag bits, see SFLAG macros below
156*cf5a6c84SAndroid Build Coastguard Worker char c; // action
157*cf5a6c84SAndroid Build Coastguard Worker };
158*cf5a6c84SAndroid Build Coastguard Worker
159*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_i 1
160*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_g 2
161*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_p 4
162*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_x 8
163*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_slash 16
164*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_R 32
165*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_S 64
166*cf5a6c84SAndroid Build Coastguard Worker #define SFLAG_H 128
167*cf5a6c84SAndroid Build Coastguard Worker
168*cf5a6c84SAndroid Build Coastguard Worker // Write out line with potential embedded NUL, handling eol/noeol
emit(char * line,long len,int eol)169*cf5a6c84SAndroid Build Coastguard Worker static int emit(char *line, long len, int eol)
170*cf5a6c84SAndroid Build Coastguard Worker {
171*cf5a6c84SAndroid Build Coastguard Worker int l = len, old = line[len];
172*cf5a6c84SAndroid Build Coastguard Worker
173*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform)) {
174*cf5a6c84SAndroid Build Coastguard Worker TT.tarxform = xrealloc(TT.tarxform, TT.tarxlen+len+TT.noeol+eol);
175*cf5a6c84SAndroid Build Coastguard Worker if (TT.noeol) TT.tarxform[TT.tarxlen++] = TT.delim;
176*cf5a6c84SAndroid Build Coastguard Worker memcpy(TT.tarxform+TT.tarxlen, line, len);
177*cf5a6c84SAndroid Build Coastguard Worker TT.tarxlen += len;
178*cf5a6c84SAndroid Build Coastguard Worker if (eol) TT.tarxform[TT.tarxlen++] = TT.delim;
179*cf5a6c84SAndroid Build Coastguard Worker } else {
180*cf5a6c84SAndroid Build Coastguard Worker if (TT.noeol && !writeall(TT.fdout, &TT.delim, 1)) return 1;
181*cf5a6c84SAndroid Build Coastguard Worker if (eol) line[len++] = TT.delim;
182*cf5a6c84SAndroid Build Coastguard Worker if (!len) return 0;
183*cf5a6c84SAndroid Build Coastguard Worker l = writeall(TT.fdout, line, len);
184*cf5a6c84SAndroid Build Coastguard Worker if (eol) line[len-1] = old;
185*cf5a6c84SAndroid Build Coastguard Worker }
186*cf5a6c84SAndroid Build Coastguard Worker TT.noeol = !eol;
187*cf5a6c84SAndroid Build Coastguard Worker if (l != len) {
188*cf5a6c84SAndroid Build Coastguard Worker if (TT.fdout != 1) perror_msg("short write");
189*cf5a6c84SAndroid Build Coastguard Worker
190*cf5a6c84SAndroid Build Coastguard Worker return 1;
191*cf5a6c84SAndroid Build Coastguard Worker }
192*cf5a6c84SAndroid Build Coastguard Worker
193*cf5a6c84SAndroid Build Coastguard Worker return 0;
194*cf5a6c84SAndroid Build Coastguard Worker }
195*cf5a6c84SAndroid Build Coastguard Worker
196*cf5a6c84SAndroid Build Coastguard Worker // Extend allocation to include new string, with newline between if newlen<0
197*cf5a6c84SAndroid Build Coastguard Worker
extend_string(char ** old,char * new,int oldlen,int newlen)198*cf5a6c84SAndroid Build Coastguard Worker static char *extend_string(char **old, char *new, int oldlen, int newlen)
199*cf5a6c84SAndroid Build Coastguard Worker {
200*cf5a6c84SAndroid Build Coastguard Worker int newline = newlen < 0;
201*cf5a6c84SAndroid Build Coastguard Worker char *s;
202*cf5a6c84SAndroid Build Coastguard Worker
203*cf5a6c84SAndroid Build Coastguard Worker if (newline) newlen = -newlen;
204*cf5a6c84SAndroid Build Coastguard Worker s = *old = xrealloc(*old, oldlen+newlen+newline+1);
205*cf5a6c84SAndroid Build Coastguard Worker if (newline) s[oldlen++] = TT.delim;
206*cf5a6c84SAndroid Build Coastguard Worker memcpy(s+oldlen, new, newlen);
207*cf5a6c84SAndroid Build Coastguard Worker s[oldlen+newlen] = 0;
208*cf5a6c84SAndroid Build Coastguard Worker
209*cf5a6c84SAndroid Build Coastguard Worker return s+oldlen+newlen+1;
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker // An empty regex repeats the previous one
get_regex(void * command,int offset)213*cf5a6c84SAndroid Build Coastguard Worker static void *get_regex(void *command, int offset)
214*cf5a6c84SAndroid Build Coastguard Worker {
215*cf5a6c84SAndroid Build Coastguard Worker if (!offset) {
216*cf5a6c84SAndroid Build Coastguard Worker if (!TT.lastregex) error_exit("no previous regex");
217*cf5a6c84SAndroid Build Coastguard Worker return TT.lastregex;
218*cf5a6c84SAndroid Build Coastguard Worker }
219*cf5a6c84SAndroid Build Coastguard Worker
220*cf5a6c84SAndroid Build Coastguard Worker return TT.lastregex = offset+(char *)command;
221*cf5a6c84SAndroid Build Coastguard Worker }
222*cf5a6c84SAndroid Build Coastguard Worker
223*cf5a6c84SAndroid Build Coastguard Worker // Apply pattern to line from input file
sed_line(char ** pline,long plen)224*cf5a6c84SAndroid Build Coastguard Worker static void sed_line(char **pline, long plen)
225*cf5a6c84SAndroid Build Coastguard Worker {
226*cf5a6c84SAndroid Build Coastguard Worker struct append {
227*cf5a6c84SAndroid Build Coastguard Worker struct append *next, *prev;
228*cf5a6c84SAndroid Build Coastguard Worker int file;
229*cf5a6c84SAndroid Build Coastguard Worker char *str;
230*cf5a6c84SAndroid Build Coastguard Worker } *append = 0;
231*cf5a6c84SAndroid Build Coastguard Worker char *line;
232*cf5a6c84SAndroid Build Coastguard Worker long len;
233*cf5a6c84SAndroid Build Coastguard Worker struct sedcmd *command;
234*cf5a6c84SAndroid Build Coastguard Worker int eol = 0, tea = 0;
235*cf5a6c84SAndroid Build Coastguard Worker
236*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform)) {
237*cf5a6c84SAndroid Build Coastguard Worker if (!pline) return;
238*cf5a6c84SAndroid Build Coastguard Worker
239*cf5a6c84SAndroid Build Coastguard Worker line = *pline;
240*cf5a6c84SAndroid Build Coastguard Worker len = plen;
241*cf5a6c84SAndroid Build Coastguard Worker *pline = 0;
242*cf5a6c84SAndroid Build Coastguard Worker pline = 0;
243*cf5a6c84SAndroid Build Coastguard Worker } else {
244*cf5a6c84SAndroid Build Coastguard Worker line = TT.nextline;
245*cf5a6c84SAndroid Build Coastguard Worker len = TT.nextlen;
246*cf5a6c84SAndroid Build Coastguard Worker
247*cf5a6c84SAndroid Build Coastguard Worker // Ignore EOF for all files before last unless -i or -s
248*cf5a6c84SAndroid Build Coastguard Worker if (!pline && !FLAG(i) && !FLAG(s)) return;
249*cf5a6c84SAndroid Build Coastguard Worker
250*cf5a6c84SAndroid Build Coastguard Worker // Grab next line for deferred processing (EOF detection: we get a NULL
251*cf5a6c84SAndroid Build Coastguard Worker // pline at EOF to flush last line). Note that only end of _last_ input
252*cf5a6c84SAndroid Build Coastguard Worker // file matches $ (unless we're doing -i).
253*cf5a6c84SAndroid Build Coastguard Worker TT.nextline = 0;
254*cf5a6c84SAndroid Build Coastguard Worker TT.nextlen = 0;
255*cf5a6c84SAndroid Build Coastguard Worker if (pline) {
256*cf5a6c84SAndroid Build Coastguard Worker TT.nextline = *pline;
257*cf5a6c84SAndroid Build Coastguard Worker TT.nextlen = plen;
258*cf5a6c84SAndroid Build Coastguard Worker *pline = 0;
259*cf5a6c84SAndroid Build Coastguard Worker }
260*cf5a6c84SAndroid Build Coastguard Worker }
261*cf5a6c84SAndroid Build Coastguard Worker
262*cf5a6c84SAndroid Build Coastguard Worker if (!line || !len) return;
263*cf5a6c84SAndroid Build Coastguard Worker if (line[len-1] == TT.delim) line[--len] = eol++;
264*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform) && len) {
265*cf5a6c84SAndroid Build Coastguard Worker TT.xftype = line[--len];
266*cf5a6c84SAndroid Build Coastguard Worker line[len] = 0;
267*cf5a6c84SAndroid Build Coastguard Worker }
268*cf5a6c84SAndroid Build Coastguard Worker TT.count++;
269*cf5a6c84SAndroid Build Coastguard Worker
270*cf5a6c84SAndroid Build Coastguard Worker // To prevent N as last command from restarting script, we added 1 to restart
271*cf5a6c84SAndroid Build Coastguard Worker // so we'd use it here even when NULL. Alas, compilers that think C has
272*cf5a6c84SAndroid Build Coastguard Worker // references instead of pointers assume ptr-1 can never be NULL (demonstrably
273*cf5a6c84SAndroid Build Coastguard Worker // untrue) and inappropriately dead code eliminate, so use LP64 math until
274*cf5a6c84SAndroid Build Coastguard Worker // we get a -fpointers-are-not-references compiler option.
275*cf5a6c84SAndroid Build Coastguard Worker command = (void *)(TT.restart ? ((unsigned long)TT.restart)-1
276*cf5a6c84SAndroid Build Coastguard Worker : (unsigned long)TT.pattern);
277*cf5a6c84SAndroid Build Coastguard Worker TT.restart = 0;
278*cf5a6c84SAndroid Build Coastguard Worker
279*cf5a6c84SAndroid Build Coastguard Worker while (command) {
280*cf5a6c84SAndroid Build Coastguard Worker char *str, c = command->c;
281*cf5a6c84SAndroid Build Coastguard Worker
282*cf5a6c84SAndroid Build Coastguard Worker // Have we got a line or regex matching range for this rule?
283*cf5a6c84SAndroid Build Coastguard Worker if (*command->lmatch || *command->rmatch) {
284*cf5a6c84SAndroid Build Coastguard Worker int miss = 0;
285*cf5a6c84SAndroid Build Coastguard Worker long lm;
286*cf5a6c84SAndroid Build Coastguard Worker
287*cf5a6c84SAndroid Build Coastguard Worker // In a match that might end?
288*cf5a6c84SAndroid Build Coastguard Worker if (command->hit) {
289*cf5a6c84SAndroid Build Coastguard Worker if (!(lm = command->lmatch[1])) {
290*cf5a6c84SAndroid Build Coastguard Worker if (!command->rmatch[1]) command->hit = 0;
291*cf5a6c84SAndroid Build Coastguard Worker else {
292*cf5a6c84SAndroid Build Coastguard Worker void *rm = get_regex(command, command->rmatch[1]);
293*cf5a6c84SAndroid Build Coastguard Worker
294*cf5a6c84SAndroid Build Coastguard Worker // regex match end includes matching line, so defer deactivation
295*cf5a6c84SAndroid Build Coastguard Worker if (line && !regexec0(rm, line, len, 0, 0, 0)) miss = 1;
296*cf5a6c84SAndroid Build Coastguard Worker }
297*cf5a6c84SAndroid Build Coastguard Worker } else if (lm > 0 && lm < TT.count) command->hit = 0;
298*cf5a6c84SAndroid Build Coastguard Worker else if (lm < -1 && TT.count == command->hit+(-lm-1)) command->hit = 0;
299*cf5a6c84SAndroid Build Coastguard Worker
300*cf5a6c84SAndroid Build Coastguard Worker // Start a new match?
301*cf5a6c84SAndroid Build Coastguard Worker } else {
302*cf5a6c84SAndroid Build Coastguard Worker if (!(lm = *command->lmatch)) {
303*cf5a6c84SAndroid Build Coastguard Worker void *rm = get_regex(command, *command->rmatch);
304*cf5a6c84SAndroid Build Coastguard Worker
305*cf5a6c84SAndroid Build Coastguard Worker if (line && !regexec0(rm, line, len, 0, 0, 0))
306*cf5a6c84SAndroid Build Coastguard Worker command->hit = TT.count;
307*cf5a6c84SAndroid Build Coastguard Worker } else if (lm == TT.count || (lm == -1 && !pline))
308*cf5a6c84SAndroid Build Coastguard Worker command->hit = TT.count;
309*cf5a6c84SAndroid Build Coastguard Worker
310*cf5a6c84SAndroid Build Coastguard Worker if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
311*cf5a6c84SAndroid Build Coastguard Worker }
312*cf5a6c84SAndroid Build Coastguard Worker
313*cf5a6c84SAndroid Build Coastguard Worker // Didn't match?
314*cf5a6c84SAndroid Build Coastguard Worker lm = !(command->not^!!command->hit);
315*cf5a6c84SAndroid Build Coastguard Worker
316*cf5a6c84SAndroid Build Coastguard Worker // Deferred disable from regex end match
317*cf5a6c84SAndroid Build Coastguard Worker if (miss || command->lmatch[1] == TT.count) command->hit = 0;
318*cf5a6c84SAndroid Build Coastguard Worker
319*cf5a6c84SAndroid Build Coastguard Worker if (lm) {
320*cf5a6c84SAndroid Build Coastguard Worker // Handle skipping curly bracket command group
321*cf5a6c84SAndroid Build Coastguard Worker if (c == '{') {
322*cf5a6c84SAndroid Build Coastguard Worker int curly = 1;
323*cf5a6c84SAndroid Build Coastguard Worker
324*cf5a6c84SAndroid Build Coastguard Worker while (curly) {
325*cf5a6c84SAndroid Build Coastguard Worker command = command->next;
326*cf5a6c84SAndroid Build Coastguard Worker if (command->c == '{') curly++;
327*cf5a6c84SAndroid Build Coastguard Worker if (command->c == '}') curly--;
328*cf5a6c84SAndroid Build Coastguard Worker }
329*cf5a6c84SAndroid Build Coastguard Worker }
330*cf5a6c84SAndroid Build Coastguard Worker command = command->next;
331*cf5a6c84SAndroid Build Coastguard Worker continue;
332*cf5a6c84SAndroid Build Coastguard Worker }
333*cf5a6c84SAndroid Build Coastguard Worker }
334*cf5a6c84SAndroid Build Coastguard Worker
335*cf5a6c84SAndroid Build Coastguard Worker // A deleted line can still update line match state for later commands
336*cf5a6c84SAndroid Build Coastguard Worker if (!line) {
337*cf5a6c84SAndroid Build Coastguard Worker command = command->next;
338*cf5a6c84SAndroid Build Coastguard Worker continue;
339*cf5a6c84SAndroid Build Coastguard Worker }
340*cf5a6c84SAndroid Build Coastguard Worker
341*cf5a6c84SAndroid Build Coastguard Worker // Process command
342*cf5a6c84SAndroid Build Coastguard Worker
343*cf5a6c84SAndroid Build Coastguard Worker if (c=='a' || c=='r') {
344*cf5a6c84SAndroid Build Coastguard Worker struct append *a = xzalloc(sizeof(struct append));
345*cf5a6c84SAndroid Build Coastguard Worker if (command->arg1) a->str = command->arg1+(char *)command;
346*cf5a6c84SAndroid Build Coastguard Worker a->file = c=='r';
347*cf5a6c84SAndroid Build Coastguard Worker dlist_add_nomalloc((void *)&append, (void *)a);
348*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='b' || c=='t' || c=='T') {
349*cf5a6c84SAndroid Build Coastguard Worker int t = tea;
350*cf5a6c84SAndroid Build Coastguard Worker
351*cf5a6c84SAndroid Build Coastguard Worker if (c != 'b') tea = 0;
352*cf5a6c84SAndroid Build Coastguard Worker if (c=='b' || t^(c=='T')) {
353*cf5a6c84SAndroid Build Coastguard Worker if (!command->arg1) break;
354*cf5a6c84SAndroid Build Coastguard Worker str = command->arg1+(char *)command;
355*cf5a6c84SAndroid Build Coastguard Worker for (command = (void *)TT.pattern; command; command = command->next)
356*cf5a6c84SAndroid Build Coastguard Worker if (command->c == ':' && !strcmp(command->arg1+(char *)command, str))
357*cf5a6c84SAndroid Build Coastguard Worker break;
358*cf5a6c84SAndroid Build Coastguard Worker if (!command) error_exit("no :%s", str);
359*cf5a6c84SAndroid Build Coastguard Worker }
360*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='c') {
361*cf5a6c84SAndroid Build Coastguard Worker str = command->arg1+(char *)command;
362*cf5a6c84SAndroid Build Coastguard Worker if (!command->hit) emit(str, strlen(str), 1);
363*cf5a6c84SAndroid Build Coastguard Worker free(line);
364*cf5a6c84SAndroid Build Coastguard Worker line = 0;
365*cf5a6c84SAndroid Build Coastguard Worker continue;
366*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='d') {
367*cf5a6c84SAndroid Build Coastguard Worker free(line);
368*cf5a6c84SAndroid Build Coastguard Worker line = 0;
369*cf5a6c84SAndroid Build Coastguard Worker continue;
370*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='D') {
371*cf5a6c84SAndroid Build Coastguard Worker // Delete up to \n or end of buffer
372*cf5a6c84SAndroid Build Coastguard Worker str = line;
373*cf5a6c84SAndroid Build Coastguard Worker while ((str-line)<len) if (*(str++) == TT.delim) break;
374*cf5a6c84SAndroid Build Coastguard Worker len -= str - line;
375*cf5a6c84SAndroid Build Coastguard Worker memmove(line, str, len);
376*cf5a6c84SAndroid Build Coastguard Worker
377*cf5a6c84SAndroid Build Coastguard Worker // if "delete" blanks line, disable further processing
378*cf5a6c84SAndroid Build Coastguard Worker // otherwise trim and restart script
379*cf5a6c84SAndroid Build Coastguard Worker if (!len) {
380*cf5a6c84SAndroid Build Coastguard Worker free(line);
381*cf5a6c84SAndroid Build Coastguard Worker line = 0;
382*cf5a6c84SAndroid Build Coastguard Worker } else {
383*cf5a6c84SAndroid Build Coastguard Worker line[len] = 0;
384*cf5a6c84SAndroid Build Coastguard Worker command = (void *)TT.pattern;
385*cf5a6c84SAndroid Build Coastguard Worker }
386*cf5a6c84SAndroid Build Coastguard Worker continue;
387*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='g') {
388*cf5a6c84SAndroid Build Coastguard Worker free(line);
389*cf5a6c84SAndroid Build Coastguard Worker line = xmemdup(TT.remember, TT.rememberlen+1);
390*cf5a6c84SAndroid Build Coastguard Worker len = TT.rememberlen;
391*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='G') {
392*cf5a6c84SAndroid Build Coastguard Worker line = xrealloc(line, len+TT.rememberlen+2);
393*cf5a6c84SAndroid Build Coastguard Worker line[len++] = TT.delim;
394*cf5a6c84SAndroid Build Coastguard Worker memcpy(line+len, TT.remember, TT.rememberlen);
395*cf5a6c84SAndroid Build Coastguard Worker line[len += TT.rememberlen] = 0;
396*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='h') {
397*cf5a6c84SAndroid Build Coastguard Worker free(TT.remember);
398*cf5a6c84SAndroid Build Coastguard Worker TT.remember = xstrdup(line);
399*cf5a6c84SAndroid Build Coastguard Worker TT.rememberlen = len;
400*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='H') {
401*cf5a6c84SAndroid Build Coastguard Worker TT.remember = xrealloc(TT.remember, TT.rememberlen+len+2);
402*cf5a6c84SAndroid Build Coastguard Worker TT.remember[TT.rememberlen++] = TT.delim;
403*cf5a6c84SAndroid Build Coastguard Worker memcpy(TT.remember+TT.rememberlen, line, len);
404*cf5a6c84SAndroid Build Coastguard Worker TT.remember[TT.rememberlen += len] = 0;
405*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='i') {
406*cf5a6c84SAndroid Build Coastguard Worker str = command->arg1+(char *)command;
407*cf5a6c84SAndroid Build Coastguard Worker emit(str, strlen(str), 1);
408*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='l') {
409*cf5a6c84SAndroid Build Coastguard Worker int i, x, off;
410*cf5a6c84SAndroid Build Coastguard Worker
411*cf5a6c84SAndroid Build Coastguard Worker if (!TT.xx) {
412*cf5a6c84SAndroid Build Coastguard Worker terminal_size(&TT.xx, 0);
413*cf5a6c84SAndroid Build Coastguard Worker if (!TT.xx) TT.xx = 80;
414*cf5a6c84SAndroid Build Coastguard Worker if (TT.xx > sizeof(toybuf)-10) TT.xx = sizeof(toybuf)-10;
415*cf5a6c84SAndroid Build Coastguard Worker if (TT.xx > 4) TT.xx -= 4;
416*cf5a6c84SAndroid Build Coastguard Worker }
417*cf5a6c84SAndroid Build Coastguard Worker
418*cf5a6c84SAndroid Build Coastguard Worker for (i = off = 0; i<len; i++) {
419*cf5a6c84SAndroid Build Coastguard Worker if (off >= TT.xx) {
420*cf5a6c84SAndroid Build Coastguard Worker toybuf[off++] = '\\';
421*cf5a6c84SAndroid Build Coastguard Worker emit(toybuf, off, 1);
422*cf5a6c84SAndroid Build Coastguard Worker off = 0;
423*cf5a6c84SAndroid Build Coastguard Worker }
424*cf5a6c84SAndroid Build Coastguard Worker x = stridx("\\\a\b\f\r\t\v\n", line[i]);
425*cf5a6c84SAndroid Build Coastguard Worker if (x != -1) {
426*cf5a6c84SAndroid Build Coastguard Worker toybuf[off++] = '\\';
427*cf5a6c84SAndroid Build Coastguard Worker toybuf[off++] = "\\abfrtvn"[x];
428*cf5a6c84SAndroid Build Coastguard Worker } else if (line[i] >= ' ') toybuf[off++] = line[i];
429*cf5a6c84SAndroid Build Coastguard Worker else off += sprintf(toybuf+off, "\\%03o", line[i]);
430*cf5a6c84SAndroid Build Coastguard Worker }
431*cf5a6c84SAndroid Build Coastguard Worker toybuf[off++] = '$';
432*cf5a6c84SAndroid Build Coastguard Worker emit(toybuf, off, 1);
433*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='n') {
434*cf5a6c84SAndroid Build Coastguard Worker // The +1 forces restart processing even when next is null
435*cf5a6c84SAndroid Build Coastguard Worker TT.restart = (void *)(((unsigned long)command->next)+1);
436*cf5a6c84SAndroid Build Coastguard Worker
437*cf5a6c84SAndroid Build Coastguard Worker break;
438*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='N') {
439*cf5a6c84SAndroid Build Coastguard Worker // Can't just grab next line because we could have multiple N and
440*cf5a6c84SAndroid Build Coastguard Worker // we need to actually read ahead to get N;$p EOF detection right.
441*cf5a6c84SAndroid Build Coastguard Worker if (pline) {
442*cf5a6c84SAndroid Build Coastguard Worker // The +1 forces restart processing even when next is null
443*cf5a6c84SAndroid Build Coastguard Worker TT.restart = (void *)(((unsigned long)command->next)+1);
444*cf5a6c84SAndroid Build Coastguard Worker extend_string(&line, TT.nextline, len, -TT.nextlen);
445*cf5a6c84SAndroid Build Coastguard Worker free(TT.nextline);
446*cf5a6c84SAndroid Build Coastguard Worker TT.nextline = line;
447*cf5a6c84SAndroid Build Coastguard Worker TT.nextlen += len + 1;
448*cf5a6c84SAndroid Build Coastguard Worker line = 0;
449*cf5a6c84SAndroid Build Coastguard Worker }
450*cf5a6c84SAndroid Build Coastguard Worker
451*cf5a6c84SAndroid Build Coastguard Worker // Pending append goes out right after N
452*cf5a6c84SAndroid Build Coastguard Worker goto done;
453*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='p' || c=='P') {
454*cf5a6c84SAndroid Build Coastguard Worker char *l = (c=='P') ? strchr(line, TT.delim) : 0;
455*cf5a6c84SAndroid Build Coastguard Worker
456*cf5a6c84SAndroid Build Coastguard Worker if (emit(line, l ? l-line : len, eol)) break;
457*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='q' || c=='Q') {
458*cf5a6c84SAndroid Build Coastguard Worker if (pline) *pline = (void *)1;
459*cf5a6c84SAndroid Build Coastguard Worker free(TT.nextline);
460*cf5a6c84SAndroid Build Coastguard Worker if (!toys.exitval && command->arg1)
461*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = atoi(command->arg1+(char *)command);
462*cf5a6c84SAndroid Build Coastguard Worker TT.nextline = 0;
463*cf5a6c84SAndroid Build Coastguard Worker TT.nextlen = 0;
464*cf5a6c84SAndroid Build Coastguard Worker if (c=='Q') line = 0;
465*cf5a6c84SAndroid Build Coastguard Worker
466*cf5a6c84SAndroid Build Coastguard Worker break;
467*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='s') {
468*cf5a6c84SAndroid Build Coastguard Worker char *rline = line, *new = command->arg2 + (char *)command, *l2 = 0;
469*cf5a6c84SAndroid Build Coastguard Worker regmatch_t *match = (void *)toybuf;
470*cf5a6c84SAndroid Build Coastguard Worker regex_t *reg = get_regex(command, command->arg1);
471*cf5a6c84SAndroid Build Coastguard Worker int mflags = 0, count = 0, l2used = 0, zmatch = 1, l2l = len, l2old = 0,
472*cf5a6c84SAndroid Build Coastguard Worker bonk = 0, mlen, off, newlen;
473*cf5a6c84SAndroid Build Coastguard Worker
474*cf5a6c84SAndroid Build Coastguard Worker // Skip suppressed --tarxform types
475*cf5a6c84SAndroid Build Coastguard Worker if (TT.xftype && (command->sflags & (SFLAG_R<<stridx("rsh", TT.xftype))));
476*cf5a6c84SAndroid Build Coastguard Worker
477*cf5a6c84SAndroid Build Coastguard Worker // Loop finding match in remaining line (up to remaining len)
478*cf5a6c84SAndroid Build Coastguard Worker else while (!regexec0(reg, rline, len-(rline-line), 10, match, mflags)) {
479*cf5a6c84SAndroid Build Coastguard Worker mlen = match[0].rm_eo-match[0].rm_so;
480*cf5a6c84SAndroid Build Coastguard Worker
481*cf5a6c84SAndroid Build Coastguard Worker // xform matches ending in / aren't allowed to match entire line
482*cf5a6c84SAndroid Build Coastguard Worker if ((command->sflags & SFLAG_slash) && mlen==len) {
483*cf5a6c84SAndroid Build Coastguard Worker while (len && ++bonk && line[--len]=='/');
484*cf5a6c84SAndroid Build Coastguard Worker continue;
485*cf5a6c84SAndroid Build Coastguard Worker }
486*cf5a6c84SAndroid Build Coastguard Worker
487*cf5a6c84SAndroid Build Coastguard Worker mflags = REG_NOTBOL;
488*cf5a6c84SAndroid Build Coastguard Worker
489*cf5a6c84SAndroid Build Coastguard Worker // Zero length matches don't count immediately after a previous match
490*cf5a6c84SAndroid Build Coastguard Worker if (!mlen && !zmatch) {
491*cf5a6c84SAndroid Build Coastguard Worker if (rline-line == len) break;
492*cf5a6c84SAndroid Build Coastguard Worker if (l2) l2[l2used++] = *rline++;
493*cf5a6c84SAndroid Build Coastguard Worker zmatch++;
494*cf5a6c84SAndroid Build Coastguard Worker continue;
495*cf5a6c84SAndroid Build Coastguard Worker } else zmatch = 0;
496*cf5a6c84SAndroid Build Coastguard Worker
497*cf5a6c84SAndroid Build Coastguard Worker // If we're replacing only a specific match, skip if this isn't it
498*cf5a6c84SAndroid Build Coastguard Worker off = command->sflags>>8;
499*cf5a6c84SAndroid Build Coastguard Worker if (off && off != ++count) {
500*cf5a6c84SAndroid Build Coastguard Worker if (l2) memcpy(l2+l2used, rline, match[0].rm_eo);
501*cf5a6c84SAndroid Build Coastguard Worker l2used += match[0].rm_eo;
502*cf5a6c84SAndroid Build Coastguard Worker rline += match[0].rm_eo;
503*cf5a6c84SAndroid Build Coastguard Worker
504*cf5a6c84SAndroid Build Coastguard Worker continue;
505*cf5a6c84SAndroid Build Coastguard Worker }
506*cf5a6c84SAndroid Build Coastguard Worker // The fact getline() can allocate unbounded amounts of memory is
507*cf5a6c84SAndroid Build Coastguard Worker // a bigger issue, but while we're here check for integer overflow
508*cf5a6c84SAndroid Build Coastguard Worker if (match[0].rm_eo > INT_MAX) perror_exit(0);
509*cf5a6c84SAndroid Build Coastguard Worker
510*cf5a6c84SAndroid Build Coastguard Worker // newlen = strlen(new) but with \1 and & and printf escapes
511*cf5a6c84SAndroid Build Coastguard Worker for (off = newlen = 0; new[off]; off++) {
512*cf5a6c84SAndroid Build Coastguard Worker int cc = -1;
513*cf5a6c84SAndroid Build Coastguard Worker
514*cf5a6c84SAndroid Build Coastguard Worker if (new[off] == '&') cc = 0;
515*cf5a6c84SAndroid Build Coastguard Worker else if (new[off] == '\\') cc = new[++off] - '0';
516*cf5a6c84SAndroid Build Coastguard Worker if (cc < 0 || cc > 9) {
517*cf5a6c84SAndroid Build Coastguard Worker newlen++;
518*cf5a6c84SAndroid Build Coastguard Worker continue;
519*cf5a6c84SAndroid Build Coastguard Worker }
520*cf5a6c84SAndroid Build Coastguard Worker newlen += match[cc].rm_eo-match[cc].rm_so;
521*cf5a6c84SAndroid Build Coastguard Worker }
522*cf5a6c84SAndroid Build Coastguard Worker
523*cf5a6c84SAndroid Build Coastguard Worker // Copy changed data to new string
524*cf5a6c84SAndroid Build Coastguard Worker
525*cf5a6c84SAndroid Build Coastguard Worker // Adjust allocation size of new string, copy data we know we'll keep
526*cf5a6c84SAndroid Build Coastguard Worker l2l += newlen-mlen;
527*cf5a6c84SAndroid Build Coastguard Worker if ((mlen = l2l|0xfff) > l2old) {
528*cf5a6c84SAndroid Build Coastguard Worker l2 = xrealloc(l2, ++mlen);
529*cf5a6c84SAndroid Build Coastguard Worker if (l2used && !l2old) memcpy(l2, rline-l2used, l2used);
530*cf5a6c84SAndroid Build Coastguard Worker l2old = mlen;
531*cf5a6c84SAndroid Build Coastguard Worker }
532*cf5a6c84SAndroid Build Coastguard Worker if (match[0].rm_so) {
533*cf5a6c84SAndroid Build Coastguard Worker memcpy(l2+l2used, rline, match[0].rm_so);
534*cf5a6c84SAndroid Build Coastguard Worker l2used += match[0].rm_so;
535*cf5a6c84SAndroid Build Coastguard Worker }
536*cf5a6c84SAndroid Build Coastguard Worker
537*cf5a6c84SAndroid Build Coastguard Worker // copy in new replacement text
538*cf5a6c84SAndroid Build Coastguard Worker for (off = mlen = 0; new[off]; off++) {
539*cf5a6c84SAndroid Build Coastguard Worker int cc = 0, ll;
540*cf5a6c84SAndroid Build Coastguard Worker
541*cf5a6c84SAndroid Build Coastguard Worker if (new[off] == '\\') {
542*cf5a6c84SAndroid Build Coastguard Worker cc = new[++off] - '0';
543*cf5a6c84SAndroid Build Coastguard Worker if (cc<0 || cc>9) {
544*cf5a6c84SAndroid Build Coastguard Worker if (!(l2[l2used+mlen++] = unescape(new[off])))
545*cf5a6c84SAndroid Build Coastguard Worker l2[l2used+mlen-1] = new[off];
546*cf5a6c84SAndroid Build Coastguard Worker
547*cf5a6c84SAndroid Build Coastguard Worker continue;
548*cf5a6c84SAndroid Build Coastguard Worker } else if (cc > reg->re_nsub) error_exit("no s//\\%d/", cc);
549*cf5a6c84SAndroid Build Coastguard Worker } else if (new[off] != '&') {
550*cf5a6c84SAndroid Build Coastguard Worker l2[l2used+mlen++] = new[off];
551*cf5a6c84SAndroid Build Coastguard Worker
552*cf5a6c84SAndroid Build Coastguard Worker continue;
553*cf5a6c84SAndroid Build Coastguard Worker }
554*cf5a6c84SAndroid Build Coastguard Worker
555*cf5a6c84SAndroid Build Coastguard Worker if (match[cc].rm_so != -1) {
556*cf5a6c84SAndroid Build Coastguard Worker ll = match[cc].rm_eo-match[cc].rm_so;
557*cf5a6c84SAndroid Build Coastguard Worker memcpy(l2+l2used+mlen, rline+match[cc].rm_so, ll);
558*cf5a6c84SAndroid Build Coastguard Worker mlen += ll;
559*cf5a6c84SAndroid Build Coastguard Worker }
560*cf5a6c84SAndroid Build Coastguard Worker }
561*cf5a6c84SAndroid Build Coastguard Worker l2used += newlen;
562*cf5a6c84SAndroid Build Coastguard Worker rline += match[0].rm_eo;
563*cf5a6c84SAndroid Build Coastguard Worker
564*cf5a6c84SAndroid Build Coastguard Worker if (!(command->sflags & SFLAG_g)) break;
565*cf5a6c84SAndroid Build Coastguard Worker }
566*cf5a6c84SAndroid Build Coastguard Worker len += bonk;
567*cf5a6c84SAndroid Build Coastguard Worker
568*cf5a6c84SAndroid Build Coastguard Worker // If we made any changes, finish off l2 and swap it for line
569*cf5a6c84SAndroid Build Coastguard Worker if (l2) {
570*cf5a6c84SAndroid Build Coastguard Worker // grab trailing unmatched data and null terminator, swap with original
571*cf5a6c84SAndroid Build Coastguard Worker mlen = len-(rline-line);
572*cf5a6c84SAndroid Build Coastguard Worker memcpy(l2+l2used, rline, mlen+1);
573*cf5a6c84SAndroid Build Coastguard Worker len = l2used + mlen;
574*cf5a6c84SAndroid Build Coastguard Worker free(line);
575*cf5a6c84SAndroid Build Coastguard Worker line = l2;
576*cf5a6c84SAndroid Build Coastguard Worker }
577*cf5a6c84SAndroid Build Coastguard Worker
578*cf5a6c84SAndroid Build Coastguard Worker if (mflags) {
579*cf5a6c84SAndroid Build Coastguard Worker if (command->sflags & SFLAG_p) emit(line, len, eol);
580*cf5a6c84SAndroid Build Coastguard Worker
581*cf5a6c84SAndroid Build Coastguard Worker tea = 1;
582*cf5a6c84SAndroid Build Coastguard Worker if (command->w) goto writenow;
583*cf5a6c84SAndroid Build Coastguard Worker }
584*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='w') {
585*cf5a6c84SAndroid Build Coastguard Worker int fd, noeol;
586*cf5a6c84SAndroid Build Coastguard Worker char *name;
587*cf5a6c84SAndroid Build Coastguard Worker
588*cf5a6c84SAndroid Build Coastguard Worker writenow:
589*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform)) error_exit("tilt");
590*cf5a6c84SAndroid Build Coastguard Worker
591*cf5a6c84SAndroid Build Coastguard Worker // Swap out emit() context
592*cf5a6c84SAndroid Build Coastguard Worker fd = TT.fdout;
593*cf5a6c84SAndroid Build Coastguard Worker noeol = TT.noeol;
594*cf5a6c84SAndroid Build Coastguard Worker
595*cf5a6c84SAndroid Build Coastguard Worker // We save filehandle and newline status before filename
596*cf5a6c84SAndroid Build Coastguard Worker name = command->w + (char *)command;
597*cf5a6c84SAndroid Build Coastguard Worker memcpy(&TT.fdout, name, 4);
598*cf5a6c84SAndroid Build Coastguard Worker name += 4;
599*cf5a6c84SAndroid Build Coastguard Worker TT.noeol = *(name++);
600*cf5a6c84SAndroid Build Coastguard Worker
601*cf5a6c84SAndroid Build Coastguard Worker // write, then save/restore context
602*cf5a6c84SAndroid Build Coastguard Worker if (emit(line, len, eol))
603*cf5a6c84SAndroid Build Coastguard Worker perror_exit("w '%s'", command->arg1+(char *)command);
604*cf5a6c84SAndroid Build Coastguard Worker *(--name) = TT.noeol;
605*cf5a6c84SAndroid Build Coastguard Worker TT.noeol = noeol;
606*cf5a6c84SAndroid Build Coastguard Worker TT.fdout = fd;
607*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='x') {
608*cf5a6c84SAndroid Build Coastguard Worker long swap = TT.rememberlen;
609*cf5a6c84SAndroid Build Coastguard Worker
610*cf5a6c84SAndroid Build Coastguard Worker str = TT.remember;
611*cf5a6c84SAndroid Build Coastguard Worker TT.remember = line;
612*cf5a6c84SAndroid Build Coastguard Worker line = str;
613*cf5a6c84SAndroid Build Coastguard Worker TT.rememberlen = len;
614*cf5a6c84SAndroid Build Coastguard Worker len = swap;
615*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='y') {
616*cf5a6c84SAndroid Build Coastguard Worker char *from, *to = (char *)command;
617*cf5a6c84SAndroid Build Coastguard Worker int i, j;
618*cf5a6c84SAndroid Build Coastguard Worker
619*cf5a6c84SAndroid Build Coastguard Worker from = to+command->arg1;
620*cf5a6c84SAndroid Build Coastguard Worker to += command->arg2;
621*cf5a6c84SAndroid Build Coastguard Worker
622*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
623*cf5a6c84SAndroid Build Coastguard Worker j = stridx(from, line[i]);
624*cf5a6c84SAndroid Build Coastguard Worker if (j != -1) line[i] = to[j];
625*cf5a6c84SAndroid Build Coastguard Worker }
626*cf5a6c84SAndroid Build Coastguard Worker } else if (c=='=') {
627*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%ld", TT.count);
628*cf5a6c84SAndroid Build Coastguard Worker if (emit(toybuf, strlen(toybuf), 1)) break;
629*cf5a6c84SAndroid Build Coastguard Worker }
630*cf5a6c84SAndroid Build Coastguard Worker
631*cf5a6c84SAndroid Build Coastguard Worker command = command->next;
632*cf5a6c84SAndroid Build Coastguard Worker }
633*cf5a6c84SAndroid Build Coastguard Worker
634*cf5a6c84SAndroid Build Coastguard Worker done:
635*cf5a6c84SAndroid Build Coastguard Worker if (line && !FLAG(n)) emit(line, len, eol);
636*cf5a6c84SAndroid Build Coastguard Worker
637*cf5a6c84SAndroid Build Coastguard Worker // TODO: should "sed -z ax" use \n instead of NUL?
638*cf5a6c84SAndroid Build Coastguard Worker if (dlist_terminate(append)) while (append) {
639*cf5a6c84SAndroid Build Coastguard Worker struct append *a = append->next;
640*cf5a6c84SAndroid Build Coastguard Worker
641*cf5a6c84SAndroid Build Coastguard Worker if (append->file) {
642*cf5a6c84SAndroid Build Coastguard Worker int fd = open(append->str, O_RDONLY);
643*cf5a6c84SAndroid Build Coastguard Worker
644*cf5a6c84SAndroid Build Coastguard Worker // Force newline if noeol pending
645*cf5a6c84SAndroid Build Coastguard Worker if (fd != -1) {
646*cf5a6c84SAndroid Build Coastguard Worker if (TT.noeol) xwrite(TT.fdout, &TT.delim, 1);
647*cf5a6c84SAndroid Build Coastguard Worker TT.noeol = 0;
648*cf5a6c84SAndroid Build Coastguard Worker xsendfile(fd, TT.fdout);
649*cf5a6c84SAndroid Build Coastguard Worker close(fd);
650*cf5a6c84SAndroid Build Coastguard Worker }
651*cf5a6c84SAndroid Build Coastguard Worker } else if (append->str) emit(append->str, strlen(append->str), 1);
652*cf5a6c84SAndroid Build Coastguard Worker else emit(line, 0, 0);
653*cf5a6c84SAndroid Build Coastguard Worker free(append);
654*cf5a6c84SAndroid Build Coastguard Worker append = a;
655*cf5a6c84SAndroid Build Coastguard Worker }
656*cf5a6c84SAndroid Build Coastguard Worker free(line);
657*cf5a6c84SAndroid Build Coastguard Worker
658*cf5a6c84SAndroid Build Coastguard Worker if (TT.tarxlen) {
659*cf5a6c84SAndroid Build Coastguard Worker dprintf(TT.fdout, "%08x", --TT.tarxlen);
660*cf5a6c84SAndroid Build Coastguard Worker writeall(TT.fdout, TT.tarxform, TT.tarxlen);
661*cf5a6c84SAndroid Build Coastguard Worker TT.tarxlen = 0;
662*cf5a6c84SAndroid Build Coastguard Worker }
663*cf5a6c84SAndroid Build Coastguard Worker }
664*cf5a6c84SAndroid Build Coastguard Worker
665*cf5a6c84SAndroid Build Coastguard Worker // Callback called on each input file
do_sed_file(int fd,char * name)666*cf5a6c84SAndroid Build Coastguard Worker static void do_sed_file(int fd, char *name)
667*cf5a6c84SAndroid Build Coastguard Worker {
668*cf5a6c84SAndroid Build Coastguard Worker char *tmp, *s;
669*cf5a6c84SAndroid Build Coastguard Worker
670*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(i)) {
671*cf5a6c84SAndroid Build Coastguard Worker if (!fd) return error_msg("-i on stdin");
672*cf5a6c84SAndroid Build Coastguard Worker TT.fdout = copy_tempfile(fd, name, &tmp);
673*cf5a6c84SAndroid Build Coastguard Worker }
674*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(i) || FLAG(s)) {
675*cf5a6c84SAndroid Build Coastguard Worker struct sedcmd *command;
676*cf5a6c84SAndroid Build Coastguard Worker
677*cf5a6c84SAndroid Build Coastguard Worker TT.count = 0;
678*cf5a6c84SAndroid Build Coastguard Worker for (command = (void *)TT.pattern; command; command = command->next)
679*cf5a6c84SAndroid Build Coastguard Worker command->hit = 0;
680*cf5a6c84SAndroid Build Coastguard Worker }
681*cf5a6c84SAndroid Build Coastguard Worker do_lines(fd, TT.delim, sed_line);
682*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(i)) {
683*cf5a6c84SAndroid Build Coastguard Worker if (TT.i && *TT.i) {
684*cf5a6c84SAndroid Build Coastguard Worker xrename(name, s = xmprintf("%s%s", name, TT.i));
685*cf5a6c84SAndroid Build Coastguard Worker free(s);
686*cf5a6c84SAndroid Build Coastguard Worker }
687*cf5a6c84SAndroid Build Coastguard Worker replace_tempfile(-1, TT.fdout, &tmp);
688*cf5a6c84SAndroid Build Coastguard Worker TT.fdout = 1;
689*cf5a6c84SAndroid Build Coastguard Worker }
690*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(i) || FLAG(s)) {
691*cf5a6c84SAndroid Build Coastguard Worker TT.nextline = 0;
692*cf5a6c84SAndroid Build Coastguard Worker TT.nextlen = TT.noeol = 0;
693*cf5a6c84SAndroid Build Coastguard Worker }
694*cf5a6c84SAndroid Build Coastguard Worker }
695*cf5a6c84SAndroid Build Coastguard Worker
696*cf5a6c84SAndroid Build Coastguard Worker // Copy chunk of string between two delimiters, converting printf escapes.
697*cf5a6c84SAndroid Build Coastguard Worker // returns processed copy of string (0 if error), *pstr advances to next
698*cf5a6c84SAndroid Build Coastguard Worker // unused char. if delim (or *delim) is 0 uses/saves starting char as delimiter
699*cf5a6c84SAndroid Build Coastguard Worker // if regxex, ignore delimiter in [ranges]
unescape_delimited_string(char ** pstr,char * delim)700*cf5a6c84SAndroid Build Coastguard Worker static char *unescape_delimited_string(char **pstr, char *delim)
701*cf5a6c84SAndroid Build Coastguard Worker {
702*cf5a6c84SAndroid Build Coastguard Worker char *to, *from, mode = 0, d;
703*cf5a6c84SAndroid Build Coastguard Worker
704*cf5a6c84SAndroid Build Coastguard Worker // Grab leading delimiter (if necessary), allocate space for new string
705*cf5a6c84SAndroid Build Coastguard Worker from = *pstr;
706*cf5a6c84SAndroid Build Coastguard Worker if (!delim || !*delim) {
707*cf5a6c84SAndroid Build Coastguard Worker if (!(d = *(from++))) return 0;
708*cf5a6c84SAndroid Build Coastguard Worker if (d == '\\') d = *(from++);
709*cf5a6c84SAndroid Build Coastguard Worker if (!d || d == '\\') return 0;
710*cf5a6c84SAndroid Build Coastguard Worker if (delim) *delim = d;
711*cf5a6c84SAndroid Build Coastguard Worker } else d = *delim;
712*cf5a6c84SAndroid Build Coastguard Worker to = delim = xmalloc(strlen(*pstr)+1);
713*cf5a6c84SAndroid Build Coastguard Worker
714*cf5a6c84SAndroid Build Coastguard Worker while (mode || *from != d) {
715*cf5a6c84SAndroid Build Coastguard Worker if (!*from) return 0;
716*cf5a6c84SAndroid Build Coastguard Worker
717*cf5a6c84SAndroid Build Coastguard Worker // delimiter in regex character range doesn't count
718*cf5a6c84SAndroid Build Coastguard Worker if (*from == '[') {
719*cf5a6c84SAndroid Build Coastguard Worker if (!mode) {
720*cf5a6c84SAndroid Build Coastguard Worker mode = ']';
721*cf5a6c84SAndroid Build Coastguard Worker if (from[1]=='-' || from[1]==']') *(to++) = *(from++);
722*cf5a6c84SAndroid Build Coastguard Worker } else if (mode == ']' && strchr(".=:", from[1])) {
723*cf5a6c84SAndroid Build Coastguard Worker *(to++) = *(from++);
724*cf5a6c84SAndroid Build Coastguard Worker mode = *from;
725*cf5a6c84SAndroid Build Coastguard Worker }
726*cf5a6c84SAndroid Build Coastguard Worker } else if (*from == mode) {
727*cf5a6c84SAndroid Build Coastguard Worker if (mode == ']') mode = 0;
728*cf5a6c84SAndroid Build Coastguard Worker else {
729*cf5a6c84SAndroid Build Coastguard Worker *(to++) = *(from++);
730*cf5a6c84SAndroid Build Coastguard Worker mode = ']';
731*cf5a6c84SAndroid Build Coastguard Worker }
732*cf5a6c84SAndroid Build Coastguard Worker // Length 1 range (X-X with same X) is "undefined" and makes regcomp err,
733*cf5a6c84SAndroid Build Coastguard Worker // but the perl build does it, so we need to filter it out.
734*cf5a6c84SAndroid Build Coastguard Worker } else if (mode && *from == '-' && from[-1] == from[1]) {
735*cf5a6c84SAndroid Build Coastguard Worker from+=2;
736*cf5a6c84SAndroid Build Coastguard Worker continue;
737*cf5a6c84SAndroid Build Coastguard Worker } else if (*from == '\\') {
738*cf5a6c84SAndroid Build Coastguard Worker if (!from[1]) return 0;
739*cf5a6c84SAndroid Build Coastguard Worker
740*cf5a6c84SAndroid Build Coastguard Worker // Check escaped end delimiter before printf style escapes.
741*cf5a6c84SAndroid Build Coastguard Worker if (from[1] == d) from++;
742*cf5a6c84SAndroid Build Coastguard Worker else if (from[1]=='\\') *(to++) = *(from++);
743*cf5a6c84SAndroid Build Coastguard Worker else {
744*cf5a6c84SAndroid Build Coastguard Worker char c = unescape(from[1]);
745*cf5a6c84SAndroid Build Coastguard Worker
746*cf5a6c84SAndroid Build Coastguard Worker if (c) {
747*cf5a6c84SAndroid Build Coastguard Worker *(to++) = c;
748*cf5a6c84SAndroid Build Coastguard Worker from+=2;
749*cf5a6c84SAndroid Build Coastguard Worker continue;
750*cf5a6c84SAndroid Build Coastguard Worker } else if (!mode) *(to++) = *(from++);
751*cf5a6c84SAndroid Build Coastguard Worker }
752*cf5a6c84SAndroid Build Coastguard Worker }
753*cf5a6c84SAndroid Build Coastguard Worker *(to++) = *(from++);
754*cf5a6c84SAndroid Build Coastguard Worker }
755*cf5a6c84SAndroid Build Coastguard Worker *to = 0;
756*cf5a6c84SAndroid Build Coastguard Worker *pstr = from+1;
757*cf5a6c84SAndroid Build Coastguard Worker
758*cf5a6c84SAndroid Build Coastguard Worker return delim;
759*cf5a6c84SAndroid Build Coastguard Worker }
760*cf5a6c84SAndroid Build Coastguard Worker
761*cf5a6c84SAndroid Build Coastguard Worker // Translate pattern strings into command structures. Each command structure
762*cf5a6c84SAndroid Build Coastguard Worker // is a single allocation (which requires some math and remalloc at times).
parse_pattern(char ** pline,long len)763*cf5a6c84SAndroid Build Coastguard Worker static void parse_pattern(char **pline, long len)
764*cf5a6c84SAndroid Build Coastguard Worker {
765*cf5a6c84SAndroid Build Coastguard Worker struct sedcmd *command = (void *)TT.pattern;
766*cf5a6c84SAndroid Build Coastguard Worker char *line, *reg, c, *errstart;
767*cf5a6c84SAndroid Build Coastguard Worker int i;
768*cf5a6c84SAndroid Build Coastguard Worker
769*cf5a6c84SAndroid Build Coastguard Worker line = errstart = pline ? *pline : "";
770*cf5a6c84SAndroid Build Coastguard Worker if (len && line[len-1]=='\n') line[--len] = 0;
771*cf5a6c84SAndroid Build Coastguard Worker
772*cf5a6c84SAndroid Build Coastguard Worker // Append this line to previous multiline command? (hit indicates type.)
773*cf5a6c84SAndroid Build Coastguard Worker // During parsing "hit" stores data about line continuations, but in
774*cf5a6c84SAndroid Build Coastguard Worker // sed_line() it means the match range attached to this command
775*cf5a6c84SAndroid Build Coastguard Worker // is active, so processing the continuation must zero it again.
776*cf5a6c84SAndroid Build Coastguard Worker if (command && command->prev->hit) {
777*cf5a6c84SAndroid Build Coastguard Worker // Remove half-finished entry from list so remalloc() doesn't confuse it
778*cf5a6c84SAndroid Build Coastguard Worker TT.pattern = TT.pattern->prev;
779*cf5a6c84SAndroid Build Coastguard Worker command = dlist_pop(&TT.pattern);
780*cf5a6c84SAndroid Build Coastguard Worker c = command->c;
781*cf5a6c84SAndroid Build Coastguard Worker reg = (char *)command;
782*cf5a6c84SAndroid Build Coastguard Worker reg += command->arg1 + strlen(reg + command->arg1);
783*cf5a6c84SAndroid Build Coastguard Worker
784*cf5a6c84SAndroid Build Coastguard Worker // Resume parsing for 'a' or 's' command. (Only two that can do this.)
785*cf5a6c84SAndroid Build Coastguard Worker // TODO: using 256 to indicate 'a' means our s/// delimiter can't be
786*cf5a6c84SAndroid Build Coastguard Worker // a unicode character.
787*cf5a6c84SAndroid Build Coastguard Worker if (command->hit < 256) goto resume_s;
788*cf5a6c84SAndroid Build Coastguard Worker else goto resume_a;
789*cf5a6c84SAndroid Build Coastguard Worker }
790*cf5a6c84SAndroid Build Coastguard Worker
791*cf5a6c84SAndroid Build Coastguard Worker // Loop through commands in this line.
792*cf5a6c84SAndroid Build Coastguard Worker
793*cf5a6c84SAndroid Build Coastguard Worker command = 0;
794*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
795*cf5a6c84SAndroid Build Coastguard Worker if (command) dlist_add_nomalloc(&TT.pattern, (void *)command);
796*cf5a6c84SAndroid Build Coastguard Worker
797*cf5a6c84SAndroid Build Coastguard Worker // If there's no more data on this line, return.
798*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
799*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*line) || *line == ';') line++;
800*cf5a6c84SAndroid Build Coastguard Worker if (*line == '#') while (*line && *line != '\n') line++;
801*cf5a6c84SAndroid Build Coastguard Worker else break;
802*cf5a6c84SAndroid Build Coastguard Worker }
803*cf5a6c84SAndroid Build Coastguard Worker if (!*line) return;
804*cf5a6c84SAndroid Build Coastguard Worker
805*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform) && strstart(&line, "flags=")) {
806*cf5a6c84SAndroid Build Coastguard Worker TT.xflags = 7;
807*cf5a6c84SAndroid Build Coastguard Worker while (0<=(i = stridx("rRsShH", *line))) {
808*cf5a6c84SAndroid Build Coastguard Worker if (i&1) TT.xflags |= 1<<(i>>1);
809*cf5a6c84SAndroid Build Coastguard Worker else TT.xflags &= ~(1<<(i>>1));
810*cf5a6c84SAndroid Build Coastguard Worker line++;
811*cf5a6c84SAndroid Build Coastguard Worker }
812*cf5a6c84SAndroid Build Coastguard Worker continue;
813*cf5a6c84SAndroid Build Coastguard Worker }
814*cf5a6c84SAndroid Build Coastguard Worker
815*cf5a6c84SAndroid Build Coastguard Worker // Start by writing data into toybuf.
816*cf5a6c84SAndroid Build Coastguard Worker
817*cf5a6c84SAndroid Build Coastguard Worker errstart = line;
818*cf5a6c84SAndroid Build Coastguard Worker memset(toybuf, 0, sizeof(struct sedcmd));
819*cf5a6c84SAndroid Build Coastguard Worker command = (void *)toybuf;
820*cf5a6c84SAndroid Build Coastguard Worker reg = toybuf + sizeof(struct sedcmd);
821*cf5a6c84SAndroid Build Coastguard Worker
822*cf5a6c84SAndroid Build Coastguard Worker // Parse address range (if any)
823*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < 2; i++) {
824*cf5a6c84SAndroid Build Coastguard Worker if (*line == ',') line++;
825*cf5a6c84SAndroid Build Coastguard Worker else if (i) break;
826*cf5a6c84SAndroid Build Coastguard Worker
827*cf5a6c84SAndroid Build Coastguard Worker if (i && *line == '+' && isdigit(line[1])) {
828*cf5a6c84SAndroid Build Coastguard Worker line++;
829*cf5a6c84SAndroid Build Coastguard Worker command->lmatch[i] = -2-strtol(line, &line, 0);
830*cf5a6c84SAndroid Build Coastguard Worker } else if (isdigit(*line)) command->lmatch[i] = strtol(line, &line, 0);
831*cf5a6c84SAndroid Build Coastguard Worker else if (*line == '$') {
832*cf5a6c84SAndroid Build Coastguard Worker command->lmatch[i] = -1;
833*cf5a6c84SAndroid Build Coastguard Worker line++;
834*cf5a6c84SAndroid Build Coastguard Worker } else if (*line == '/' || *line == '\\') {
835*cf5a6c84SAndroid Build Coastguard Worker char *s = line;
836*cf5a6c84SAndroid Build Coastguard Worker
837*cf5a6c84SAndroid Build Coastguard Worker if (!(s = unescape_delimited_string(&line, 0))) goto error;
838*cf5a6c84SAndroid Build Coastguard Worker if (!*s) command->rmatch[i] = 0;
839*cf5a6c84SAndroid Build Coastguard Worker else {
840*cf5a6c84SAndroid Build Coastguard Worker xregcomp((void *)reg, s, REG_EXTENDED*FLAG(r));
841*cf5a6c84SAndroid Build Coastguard Worker command->rmatch[i] = reg-toybuf;
842*cf5a6c84SAndroid Build Coastguard Worker reg += sizeof(regex_t);
843*cf5a6c84SAndroid Build Coastguard Worker }
844*cf5a6c84SAndroid Build Coastguard Worker free(s);
845*cf5a6c84SAndroid Build Coastguard Worker } else break;
846*cf5a6c84SAndroid Build Coastguard Worker }
847*cf5a6c84SAndroid Build Coastguard Worker
848*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*line)) line++;
849*cf5a6c84SAndroid Build Coastguard Worker if (!*line) break;
850*cf5a6c84SAndroid Build Coastguard Worker
851*cf5a6c84SAndroid Build Coastguard Worker if (*line == '!') {
852*cf5a6c84SAndroid Build Coastguard Worker command->not = 1;
853*cf5a6c84SAndroid Build Coastguard Worker line++;
854*cf5a6c84SAndroid Build Coastguard Worker }
855*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*line)) line++;
856*cf5a6c84SAndroid Build Coastguard Worker if (!*line) break;
857*cf5a6c84SAndroid Build Coastguard Worker
858*cf5a6c84SAndroid Build Coastguard Worker c = command->c = *(line++);
859*cf5a6c84SAndroid Build Coastguard Worker if (strchr("}:", c) && i) break;
860*cf5a6c84SAndroid Build Coastguard Worker if (strchr("aiqQr=", c) && i>1) break;
861*cf5a6c84SAndroid Build Coastguard Worker
862*cf5a6c84SAndroid Build Coastguard Worker // Allocate memory and copy out of toybuf now that we know how big it is
863*cf5a6c84SAndroid Build Coastguard Worker command = xmemdup(toybuf, reg-toybuf);
864*cf5a6c84SAndroid Build Coastguard Worker reg = (reg-toybuf) + (char *)command;
865*cf5a6c84SAndroid Build Coastguard Worker
866*cf5a6c84SAndroid Build Coastguard Worker // Parse arguments by command type
867*cf5a6c84SAndroid Build Coastguard Worker if (c == '{') TT.nextlen++;
868*cf5a6c84SAndroid Build Coastguard Worker else if (c == '}') {
869*cf5a6c84SAndroid Build Coastguard Worker if (!TT.nextlen--) break;
870*cf5a6c84SAndroid Build Coastguard Worker } else if (c == 's') {
871*cf5a6c84SAndroid Build Coastguard Worker char *end, delim = 0;
872*cf5a6c84SAndroid Build Coastguard Worker int flags;
873*cf5a6c84SAndroid Build Coastguard Worker
874*cf5a6c84SAndroid Build Coastguard Worker // s/pattern/replacement/flags
875*cf5a6c84SAndroid Build Coastguard Worker
876*cf5a6c84SAndroid Build Coastguard Worker // line continuations use arg1 (back at the start of the function),
877*cf5a6c84SAndroid Build Coastguard Worker // so let's fill out arg2 first (since the regex part can't be multiple
878*cf5a6c84SAndroid Build Coastguard Worker // lines) and swap them back later.
879*cf5a6c84SAndroid Build Coastguard Worker
880*cf5a6c84SAndroid Build Coastguard Worker // get pattern (just record, we parse it later)
881*cf5a6c84SAndroid Build Coastguard Worker command->arg2 = reg - (char *)command;
882*cf5a6c84SAndroid Build Coastguard Worker if (!(TT.remember = unescape_delimited_string(&line, &delim)))
883*cf5a6c84SAndroid Build Coastguard Worker goto error;
884*cf5a6c84SAndroid Build Coastguard Worker
885*cf5a6c84SAndroid Build Coastguard Worker reg += sizeof(regex_t);
886*cf5a6c84SAndroid Build Coastguard Worker command->arg1 = reg-(char *)command;
887*cf5a6c84SAndroid Build Coastguard Worker command->hit = delim;
888*cf5a6c84SAndroid Build Coastguard Worker resume_s:
889*cf5a6c84SAndroid Build Coastguard Worker // get replacement - don't replace escapes yet because \1 and \& need
890*cf5a6c84SAndroid Build Coastguard Worker // processing later, after we replace \\ with \ we can't tell \\1 from \1
891*cf5a6c84SAndroid Build Coastguard Worker end = line;
892*cf5a6c84SAndroid Build Coastguard Worker while (*end != command->hit) {
893*cf5a6c84SAndroid Build Coastguard Worker if (!*end) goto error;
894*cf5a6c84SAndroid Build Coastguard Worker if (*end++ == '\\') {
895*cf5a6c84SAndroid Build Coastguard Worker if (!*end || *end == '\n') {
896*cf5a6c84SAndroid Build Coastguard Worker end[-1] = '\n';
897*cf5a6c84SAndroid Build Coastguard Worker break;
898*cf5a6c84SAndroid Build Coastguard Worker }
899*cf5a6c84SAndroid Build Coastguard Worker end++;
900*cf5a6c84SAndroid Build Coastguard Worker }
901*cf5a6c84SAndroid Build Coastguard Worker }
902*cf5a6c84SAndroid Build Coastguard Worker
903*cf5a6c84SAndroid Build Coastguard Worker reg = extend_string((void *)&command, line, reg-(char *)command,end-line);
904*cf5a6c84SAndroid Build Coastguard Worker line = end;
905*cf5a6c84SAndroid Build Coastguard Worker // line continuation? (note: '\n' can't be a valid delim).
906*cf5a6c84SAndroid Build Coastguard Worker if (*line == command->hit) command->hit = 0;
907*cf5a6c84SAndroid Build Coastguard Worker else {
908*cf5a6c84SAndroid Build Coastguard Worker if (!*line) continue;
909*cf5a6c84SAndroid Build Coastguard Worker reg--;
910*cf5a6c84SAndroid Build Coastguard Worker line++;
911*cf5a6c84SAndroid Build Coastguard Worker goto resume_s;
912*cf5a6c84SAndroid Build Coastguard Worker }
913*cf5a6c84SAndroid Build Coastguard Worker
914*cf5a6c84SAndroid Build Coastguard Worker // swap arg1/arg2 so they're back in order arguments occur.
915*cf5a6c84SAndroid Build Coastguard Worker i = command->arg1;
916*cf5a6c84SAndroid Build Coastguard Worker command->arg1 = command->arg2;
917*cf5a6c84SAndroid Build Coastguard Worker command->arg2 = i;
918*cf5a6c84SAndroid Build Coastguard Worker command->sflags = TT.xflags*SFLAG_R;
919*cf5a6c84SAndroid Build Coastguard Worker
920*cf5a6c84SAndroid Build Coastguard Worker // get flags
921*cf5a6c84SAndroid Build Coastguard Worker for (line++; *line; line++) {
922*cf5a6c84SAndroid Build Coastguard Worker long l;
923*cf5a6c84SAndroid Build Coastguard Worker
924*cf5a6c84SAndroid Build Coastguard Worker if (isspace(*line) && *line != '\n') continue;
925*cf5a6c84SAndroid Build Coastguard Worker if (0 <= (l = stridx("igpx", *line))) command->sflags |= 1<<l;
926*cf5a6c84SAndroid Build Coastguard Worker else if (*line == 'I') command->sflags |= 1<<0;
927*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(tarxform) && 0 <= (l = stridx("RSH", *line)))
928*cf5a6c84SAndroid Build Coastguard Worker command->sflags |= SFLAG_R<<l;
929*cf5a6c84SAndroid Build Coastguard Worker // Given that the default is rsh all enabled... why do these exist?
930*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(tarxform) && 0 <= (l = stridx("rsh", *line)))
931*cf5a6c84SAndroid Build Coastguard Worker command->sflags &= ~(SFLAG_R<<l);
932*cf5a6c84SAndroid Build Coastguard Worker else if (!(command->sflags>>8) && 0<(l = strtol(line, &line, 10))) {
933*cf5a6c84SAndroid Build Coastguard Worker command->sflags |= l << 8;
934*cf5a6c84SAndroid Build Coastguard Worker line--;
935*cf5a6c84SAndroid Build Coastguard Worker } else break;
936*cf5a6c84SAndroid Build Coastguard Worker }
937*cf5a6c84SAndroid Build Coastguard Worker flags = (FLAG(r) || (command->sflags & SFLAG_x)) ? REG_EXTENDED : 0;
938*cf5a6c84SAndroid Build Coastguard Worker if (command->sflags & SFLAG_i) flags |= REG_ICASE;
939*cf5a6c84SAndroid Build Coastguard Worker
940*cf5a6c84SAndroid Build Coastguard Worker // We deferred actually parsing the regex until we had the s///i flag
941*cf5a6c84SAndroid Build Coastguard Worker // allocating the space was done by extend_string() above
942*cf5a6c84SAndroid Build Coastguard Worker if (!*TT.remember) command->arg1 = 0;
943*cf5a6c84SAndroid Build Coastguard Worker else {
944*cf5a6c84SAndroid Build Coastguard Worker xregcomp((void *)(command->arg1+(char *)command), TT.remember, flags);
945*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform) && TT.remember[strlen(TT.remember)-1]=='/')
946*cf5a6c84SAndroid Build Coastguard Worker command->sflags |= SFLAG_slash;
947*cf5a6c84SAndroid Build Coastguard Worker }
948*cf5a6c84SAndroid Build Coastguard Worker free(TT.remember);
949*cf5a6c84SAndroid Build Coastguard Worker TT.remember = 0;
950*cf5a6c84SAndroid Build Coastguard Worker if (*line == 'w') {
951*cf5a6c84SAndroid Build Coastguard Worker line++;
952*cf5a6c84SAndroid Build Coastguard Worker goto writenow;
953*cf5a6c84SAndroid Build Coastguard Worker }
954*cf5a6c84SAndroid Build Coastguard Worker } else if (c == 'w') {
955*cf5a6c84SAndroid Build Coastguard Worker int fd, delim;
956*cf5a6c84SAndroid Build Coastguard Worker char *cc;
957*cf5a6c84SAndroid Build Coastguard Worker
958*cf5a6c84SAndroid Build Coastguard Worker // Since s/// uses arg1 and arg2, and w needs a persistent filehandle and
959*cf5a6c84SAndroid Build Coastguard Worker // eol status, and to retain the filename for error messages, we'd need
960*cf5a6c84SAndroid Build Coastguard Worker // to go up to arg5 just for this. Compromise: dynamically allocate the
961*cf5a6c84SAndroid Build Coastguard Worker // filehandle and eol status.
962*cf5a6c84SAndroid Build Coastguard Worker
963*cf5a6c84SAndroid Build Coastguard Worker writenow:
964*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*line)) line++;
965*cf5a6c84SAndroid Build Coastguard Worker if (!*line) goto error;
966*cf5a6c84SAndroid Build Coastguard Worker for (cc = line; *cc; cc++) if (*cc == '\\' && cc[1] == ';') break;
967*cf5a6c84SAndroid Build Coastguard Worker delim = *cc;
968*cf5a6c84SAndroid Build Coastguard Worker *cc = 0;
969*cf5a6c84SAndroid Build Coastguard Worker fd = xcreate(line, O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0644);
970*cf5a6c84SAndroid Build Coastguard Worker *cc = delim;
971*cf5a6c84SAndroid Build Coastguard Worker
972*cf5a6c84SAndroid Build Coastguard Worker command->w = reg - (char *)command;
973*cf5a6c84SAndroid Build Coastguard Worker command = xrealloc(command, command->w+(cc-line)+6);
974*cf5a6c84SAndroid Build Coastguard Worker reg = command->w + (char *)command;
975*cf5a6c84SAndroid Build Coastguard Worker
976*cf5a6c84SAndroid Build Coastguard Worker memcpy(reg, &fd, 4);
977*cf5a6c84SAndroid Build Coastguard Worker reg += 4;
978*cf5a6c84SAndroid Build Coastguard Worker *(reg++) = 0;
979*cf5a6c84SAndroid Build Coastguard Worker memcpy(reg, line, delim);
980*cf5a6c84SAndroid Build Coastguard Worker reg += delim;
981*cf5a6c84SAndroid Build Coastguard Worker *(reg++) = 0;
982*cf5a6c84SAndroid Build Coastguard Worker
983*cf5a6c84SAndroid Build Coastguard Worker line = cc;
984*cf5a6c84SAndroid Build Coastguard Worker if (delim) line += 2;
985*cf5a6c84SAndroid Build Coastguard Worker } else if (c == 'y') {
986*cf5a6c84SAndroid Build Coastguard Worker char *s, delim = 0;
987*cf5a6c84SAndroid Build Coastguard Worker int len;
988*cf5a6c84SAndroid Build Coastguard Worker
989*cf5a6c84SAndroid Build Coastguard Worker if (!(s = unescape_delimited_string(&line, &delim))) goto error;
990*cf5a6c84SAndroid Build Coastguard Worker command->arg1 = reg-(char *)command;
991*cf5a6c84SAndroid Build Coastguard Worker len = strlen(s);
992*cf5a6c84SAndroid Build Coastguard Worker reg = extend_string((void *)&command, s, reg-(char *)command, len);
993*cf5a6c84SAndroid Build Coastguard Worker free(s);
994*cf5a6c84SAndroid Build Coastguard Worker command->arg2 = reg-(char *)command;
995*cf5a6c84SAndroid Build Coastguard Worker if (!(s = unescape_delimited_string(&line, &delim))) goto error;
996*cf5a6c84SAndroid Build Coastguard Worker if (len != strlen(s)) goto error;
997*cf5a6c84SAndroid Build Coastguard Worker reg = extend_string((void *)&command, s, reg-(char*)command, len);
998*cf5a6c84SAndroid Build Coastguard Worker free(s);
999*cf5a6c84SAndroid Build Coastguard Worker } else if (strchr("abcirtTqQw:", c)) {
1000*cf5a6c84SAndroid Build Coastguard Worker int end;
1001*cf5a6c84SAndroid Build Coastguard Worker
1002*cf5a6c84SAndroid Build Coastguard Worker // trim leading spaces
1003*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*line) && *line != '\n') line++;
1004*cf5a6c84SAndroid Build Coastguard Worker
1005*cf5a6c84SAndroid Build Coastguard Worker // Resume logic differs from 's' case because we don't add a newline
1006*cf5a6c84SAndroid Build Coastguard Worker // unless it's after something, so we add it on return instead.
1007*cf5a6c84SAndroid Build Coastguard Worker resume_a:
1008*cf5a6c84SAndroid Build Coastguard Worker command->hit = 0;
1009*cf5a6c84SAndroid Build Coastguard Worker
1010*cf5a6c84SAndroid Build Coastguard Worker // btTqQ: end with space or semicolon, aicrw continue to newline.
1011*cf5a6c84SAndroid Build Coastguard Worker if (!(end = strcspn(line, strchr(":btTqQ", c) ? "}; \t\r\n\v\f" : "\n"))){
1012*cf5a6c84SAndroid Build Coastguard Worker // Argument's optional for btTqQ
1013*cf5a6c84SAndroid Build Coastguard Worker if (strchr("btTqQ", c)) continue;
1014*cf5a6c84SAndroid Build Coastguard Worker else if (!command->arg1) break;
1015*cf5a6c84SAndroid Build Coastguard Worker }
1016*cf5a6c84SAndroid Build Coastguard Worker // Error checking: qQ can only have digits after them
1017*cf5a6c84SAndroid Build Coastguard Worker if (c=='q' || c=='Q') {
1018*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<end && isdigit(line[i]); i++);
1019*cf5a6c84SAndroid Build Coastguard Worker if (i != end) {
1020*cf5a6c84SAndroid Build Coastguard Worker line += i;
1021*cf5a6c84SAndroid Build Coastguard Worker break;
1022*cf5a6c84SAndroid Build Coastguard Worker }
1023*cf5a6c84SAndroid Build Coastguard Worker }
1024*cf5a6c84SAndroid Build Coastguard Worker
1025*cf5a6c84SAndroid Build Coastguard Worker // Extend allocation to include new string. We use offsets instead of
1026*cf5a6c84SAndroid Build Coastguard Worker // pointers so realloc() moving stuff doesn't break things. Ok to write
1027*cf5a6c84SAndroid Build Coastguard Worker // \n over NUL terminator because call to extend_string() adds it back.
1028*cf5a6c84SAndroid Build Coastguard Worker if (!command->arg1) command->arg1 = reg - (char*)command;
1029*cf5a6c84SAndroid Build Coastguard Worker else if (*(command->arg1+(char *)command)) *(reg++) = '\n';
1030*cf5a6c84SAndroid Build Coastguard Worker else if (!pline) {
1031*cf5a6c84SAndroid Build Coastguard Worker command->arg1 = 0;
1032*cf5a6c84SAndroid Build Coastguard Worker continue;
1033*cf5a6c84SAndroid Build Coastguard Worker }
1034*cf5a6c84SAndroid Build Coastguard Worker reg = extend_string((void *)&command, line, reg - (char *)command, end);
1035*cf5a6c84SAndroid Build Coastguard Worker
1036*cf5a6c84SAndroid Build Coastguard Worker // Recopy data to remove escape sequences and handle line continuation.
1037*cf5a6c84SAndroid Build Coastguard Worker if (strchr("aci", c)) {
1038*cf5a6c84SAndroid Build Coastguard Worker reg -= end+1;
1039*cf5a6c84SAndroid Build Coastguard Worker for (i = end; i; i--) {
1040*cf5a6c84SAndroid Build Coastguard Worker if ((*reg++ = *line++)=='\\') {
1041*cf5a6c84SAndroid Build Coastguard Worker
1042*cf5a6c84SAndroid Build Coastguard Worker // escape at end of line: resume if -e escaped literal newline,
1043*cf5a6c84SAndroid Build Coastguard Worker // else request callback and resume with next line
1044*cf5a6c84SAndroid Build Coastguard Worker if (!--i) {
1045*cf5a6c84SAndroid Build Coastguard Worker *--reg = 0;
1046*cf5a6c84SAndroid Build Coastguard Worker if (*line) {
1047*cf5a6c84SAndroid Build Coastguard Worker line++;
1048*cf5a6c84SAndroid Build Coastguard Worker goto resume_a;
1049*cf5a6c84SAndroid Build Coastguard Worker }
1050*cf5a6c84SAndroid Build Coastguard Worker command->hit = 256;
1051*cf5a6c84SAndroid Build Coastguard Worker break;
1052*cf5a6c84SAndroid Build Coastguard Worker }
1053*cf5a6c84SAndroid Build Coastguard Worker if (!(reg[-1] = unescape(*line))) reg[-1] = *line;
1054*cf5a6c84SAndroid Build Coastguard Worker line++;
1055*cf5a6c84SAndroid Build Coastguard Worker }
1056*cf5a6c84SAndroid Build Coastguard Worker }
1057*cf5a6c84SAndroid Build Coastguard Worker *reg = 0;
1058*cf5a6c84SAndroid Build Coastguard Worker } else line += end;
1059*cf5a6c84SAndroid Build Coastguard Worker
1060*cf5a6c84SAndroid Build Coastguard Worker // Commands that take no arguments
1061*cf5a6c84SAndroid Build Coastguard Worker } else if (!strchr("{dDgGhHlnNpPx=", c)) break;
1062*cf5a6c84SAndroid Build Coastguard Worker }
1063*cf5a6c84SAndroid Build Coastguard Worker
1064*cf5a6c84SAndroid Build Coastguard Worker error:
1065*cf5a6c84SAndroid Build Coastguard Worker error_exit("bad pattern '%s'@%ld (%c)", errstart, line-errstart+1L, *line);
1066*cf5a6c84SAndroid Build Coastguard Worker }
1067*cf5a6c84SAndroid Build Coastguard Worker
1068*cf5a6c84SAndroid Build Coastguard Worker // Is the pointer "find" within the string "range".
instr(char * find,char * range)1069*cf5a6c84SAndroid Build Coastguard Worker static int instr(char *find, char *range)
1070*cf5a6c84SAndroid Build Coastguard Worker {
1071*cf5a6c84SAndroid Build Coastguard Worker return find>=range && range+strlen(range)>=find;
1072*cf5a6c84SAndroid Build Coastguard Worker }
1073*cf5a6c84SAndroid Build Coastguard Worker
sed_main(void)1074*cf5a6c84SAndroid Build Coastguard Worker void sed_main(void)
1075*cf5a6c84SAndroid Build Coastguard Worker {
1076*cf5a6c84SAndroid Build Coastguard Worker char **args = toys.optargs, **aa;
1077*cf5a6c84SAndroid Build Coastguard Worker
1078*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(tarxform)) toys.optflags |= FLAG_z;
1079*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(z)) TT.delim = '\n';
1080*cf5a6c84SAndroid Build Coastguard Worker
1081*cf5a6c84SAndroid Build Coastguard Worker // Parse pattern into commands.
1082*cf5a6c84SAndroid Build Coastguard Worker
1083*cf5a6c84SAndroid Build Coastguard Worker // If no -e or -f, first argument is the pattern.
1084*cf5a6c84SAndroid Build Coastguard Worker if (!TT.e && !TT.f) {
1085*cf5a6c84SAndroid Build Coastguard Worker if (!*toys.optargs) error_exit("no pattern");
1086*cf5a6c84SAndroid Build Coastguard Worker (TT.e = xzalloc(sizeof(struct arg_list)))->arg = *(args++);
1087*cf5a6c84SAndroid Build Coastguard Worker }
1088*cf5a6c84SAndroid Build Coastguard Worker
1089*cf5a6c84SAndroid Build Coastguard Worker // -e and -f care about order, so use argv[] to recreate original order
1090*cf5a6c84SAndroid Build Coastguard Worker for (aa = toys.argv+1; *aa; aa++) {
1091*cf5a6c84SAndroid Build Coastguard Worker if (TT.e && instr(TT.e->arg, *aa)) {
1092*cf5a6c84SAndroid Build Coastguard Worker parse_pattern(&TT.e->arg, strlen(TT.e->arg));
1093*cf5a6c84SAndroid Build Coastguard Worker free(llist_pop(&TT.e));
1094*cf5a6c84SAndroid Build Coastguard Worker }
1095*cf5a6c84SAndroid Build Coastguard Worker if (TT.f && instr(TT.f->arg, *aa)) {
1096*cf5a6c84SAndroid Build Coastguard Worker do_lines(xopenro(TT.f->arg), TT.delim, parse_pattern);
1097*cf5a6c84SAndroid Build Coastguard Worker free(llist_pop(&TT.f));
1098*cf5a6c84SAndroid Build Coastguard Worker }
1099*cf5a6c84SAndroid Build Coastguard Worker }
1100*cf5a6c84SAndroid Build Coastguard Worker parse_pattern(0, 0);
1101*cf5a6c84SAndroid Build Coastguard Worker dlist_terminate(TT.pattern);
1102*cf5a6c84SAndroid Build Coastguard Worker if (TT.nextlen) error_exit("no }");
1103*cf5a6c84SAndroid Build Coastguard Worker
1104*cf5a6c84SAndroid Build Coastguard Worker TT.fdout = 1;
1105*cf5a6c84SAndroid Build Coastguard Worker TT.remember = xstrdup("");
1106*cf5a6c84SAndroid Build Coastguard Worker
1107*cf5a6c84SAndroid Build Coastguard Worker // Inflict pattern upon input files. Long version because !O_CLOEXEC
1108*cf5a6c84SAndroid Build Coastguard Worker loopfiles_rw(args, O_RDONLY|WARN_ONLY, 0, do_sed_file);
1109*cf5a6c84SAndroid Build Coastguard Worker
1110*cf5a6c84SAndroid Build Coastguard Worker // Provide EOF flush at end of cumulative input for non-i mode.
1111*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(i) && !FLAG(s)) {
1112*cf5a6c84SAndroid Build Coastguard Worker toys.optflags |= FLAG_s;
1113*cf5a6c84SAndroid Build Coastguard Worker sed_line(0, 0);
1114*cf5a6c84SAndroid Build Coastguard Worker }
1115*cf5a6c84SAndroid Build Coastguard Worker
1116*cf5a6c84SAndroid Build Coastguard Worker // TODO: need to close fd when done for TOYBOX_FREE?
1117*cf5a6c84SAndroid Build Coastguard Worker }
1118