xref: /aosp_15_r20/external/toybox/toys/posix/sed.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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