1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172#define FOR_sed
173#include "toys.h"
174
175GLOBALS(
176 char *i;
177 struct arg_list *f, *e;
178
179
180 struct double_list *pattern;
181
182 char *nextline, *remember;
183 void *restart, *lastregex;
184 long nextlen, rememberlen, count;
185 int fdout, noeol;
186 unsigned xx;
187 char delim;
188)
189
190
191
192
193
194
195struct sedcmd {
196 struct sedcmd *next, *prev;
197
198
199 long lmatch[2];
200 int rmatch[2];
201 int arg1, arg2, w;
202 unsigned not, hit;
203 unsigned sflags;
204 char c;
205};
206
207
208static int emit(char *line, long len, int eol)
209{
210 int l, old = line[len];
211
212 if (TT.noeol && !writeall(TT.fdout, "\n", 1)) return 1;
213 TT.noeol = !eol;
214 if (eol) line[len++] = '\n';
215 if (!len) return 0;
216 l = writeall(TT.fdout, line, len);
217 if (eol) line[len-1] = old;
218 if (l != len) {
219 if (TT.fdout != 1) perror_msg("short write");
220
221 return 1;
222 }
223
224 return 0;
225}
226
227
228
229static char *extend_string(char **old, char *new, int oldlen, int newlen)
230{
231 int newline = newlen < 0;
232 char *s;
233
234 if (newline) newlen = -newlen;
235 s = *old = xrealloc(*old, oldlen+newlen+newline+1);
236 if (newline) s[oldlen++] = '\n';
237 memcpy(s+oldlen, new, newlen);
238 s[oldlen+newlen] = 0;
239
240 return s+oldlen+newlen+1;
241}
242
243
244static void *get_regex(void *command, int offset)
245{
246 if (!offset) {
247 if (!TT.lastregex) error_exit("no previous regex");
248 return TT.lastregex;
249 }
250
251 return TT.lastregex = offset+(char *)command;
252}
253
254
255static void sed_line(char **pline, long plen)
256{
257 struct append {
258 struct append *next, *prev;
259 int file;
260 char *str;
261 } *append = 0;
262 char *line = TT.nextline;
263 long len = TT.nextlen;
264 struct sedcmd *command;
265 int eol = 0, tea = 0;
266
267
268 if (!pline && !FLAG(i)) return;
269
270
271
272
273 TT.nextline = 0;
274 TT.nextlen = 0;
275 if (pline) {
276 TT.nextline = *pline;
277 TT.nextlen = plen;
278 *pline = 0;
279 }
280
281 if (!line || !len) return;
282 if (line[len-1] == '\n') line[--len] = eol++;
283 TT.count++;
284
285
286
287 command = TT.restart ? ((struct sedcmd *)TT.restart)-1 : (void *)TT.pattern;
288 TT.restart = 0;
289
290 while (command) {
291 char *str, c = command->c;
292
293
294 if (*command->lmatch || *command->rmatch) {
295 int miss = 0;
296 long lm;
297
298
299 if (command->hit) {
300 if (!(lm = command->lmatch[1])) {
301 if (!command->rmatch[1]) command->hit = 0;
302 else {
303 void *rm = get_regex(command, command->rmatch[1]);
304
305
306 if (line && !regexec0(rm, line, len, 0, 0, 0)) miss = 1;
307 }
308 } else if (lm > 0 && lm < TT.count) command->hit = 0;
309 else if (lm < -1 && TT.count == command->hit+(-lm-1)) command->hit = 0;
310
311
312 } else {
313 if (!(lm = *command->lmatch)) {
314 void *rm = get_regex(command, *command->rmatch);
315
316 if (line && !regexec0(rm, line, len, 0, 0, 0))
317 command->hit = TT.count;
318 } else if (lm == TT.count || (lm == -1 && !pline))
319 command->hit = TT.count;
320
321 if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
322 }
323
324
325 lm = !(command->not^!!command->hit);
326
327
328 if (miss || command->lmatch[1] == TT.count) command->hit = 0;
329
330 if (lm) {
331
332 if (c == '{') {
333 int curly = 1;
334
335 while (curly) {
336 command = command->next;
337 if (command->c == '{') curly++;
338 if (command->c == '}') curly--;
339 }
340 }
341 command = command->next;
342 continue;
343 }
344 }
345
346
347 if (!line) {
348 command = command->next;
349 continue;
350 }
351
352
353
354 if (c=='a' || c=='r') {
355 struct append *a = xzalloc(sizeof(struct append));
356 if (command->arg1) a->str = command->arg1+(char *)command;
357 a->file = c=='r';
358 dlist_add_nomalloc((void *)&append, (void *)a);
359 } else if (c=='b' || c=='t' || c=='T') {
360 int t = tea;
361
362 if (c != 'b') tea = 0;
363 if (c=='b' || t^(c=='T')) {
364 if (!command->arg1) break;
365 str = command->arg1+(char *)command;
366 for (command = (void *)TT.pattern; command; command = command->next)
367 if (command->c == ':' && !strcmp(command->arg1+(char *)command, str))
368 break;
369 if (!command) error_exit("no :%s", str);
370 }
371 } else if (c=='c') {
372 str = command->arg1+(char *)command;
373 if (!command->hit) emit(str, strlen(str), 1);
374 free(line);
375 line = 0;
376 continue;
377 } else if (c=='d') {
378 free(line);
379 line = 0;
380 continue;
381 } else if (c=='D') {
382
383 str = line;
384 while ((str-line)<len) if (*(str++) == '\n') break;
385 len -= str - line;
386 memmove(line, str, len);
387
388
389
390 if (!len) {
391 free(line);
392 line = 0;
393 } else {
394 line[len] = 0;
395 command = (void *)TT.pattern;
396 }
397 continue;
398 } else if (c=='g') {
399 free(line);
400 line = xstrdup(TT.remember);
401 len = TT.rememberlen;
402 } else if (c=='G') {
403 line = xrealloc(line, len+TT.rememberlen+2);
404 line[len++] = '\n';
405 memcpy(line+len, TT.remember, TT.rememberlen);
406 line[len += TT.rememberlen] = 0;
407 } else if (c=='h') {
408 free(TT.remember);
409 TT.remember = xstrdup(line);
410 TT.rememberlen = len;
411 } else if (c=='H') {
412 TT.remember = xrealloc(TT.remember, TT.rememberlen+len+2);
413 TT.remember[TT.rememberlen++] = '\n';
414 memcpy(TT.remember+TT.rememberlen, line, len);
415 TT.remember[TT.rememberlen += len] = 0;
416 } else if (c=='i') {
417 str = command->arg1+(char *)command;
418 emit(str, strlen(str), 1);
419 } else if (c=='l') {
420 int i, x, off;
421
422 if (!TT.xx) {
423 terminal_size(&TT.xx, 0);
424 if (!TT.xx) TT.xx = 80;
425 if (TT.xx > sizeof(toybuf)-10) TT.xx = sizeof(toybuf)-10;
426 if (TT.xx > 4) TT.xx -= 4;
427 }
428
429 for (i = off = 0; i<len; i++) {
430 if (off >= TT.xx) {
431 toybuf[off++] = '\\';
432 emit(toybuf, off, 1);
433 off = 0;
434 }
435 x = stridx("\\\a\b\f\r\t\v", line[i]);
436 if (x != -1) {
437 toybuf[off++] = '\\';
438 toybuf[off++] = "\\abfrtv"[x];
439 } else if (line[i] >= ' ') toybuf[off++] = line[i];
440 else off += sprintf(toybuf+off, "\\%03o", line[i]);
441 }
442 toybuf[off++] = '$';
443 emit(toybuf, off, 1);
444 } else if (c=='n') {
445 TT.restart = command->next+1;
446
447 break;
448 } else if (c=='N') {
449
450
451 if (pline) {
452 TT.restart = command->next+1;
453 extend_string(&line, TT.nextline, len, -TT.nextlen);
454 free(TT.nextline);
455 TT.nextline = line;
456 TT.nextlen += len + 1;
457 line = 0;
458 }
459
460
461 goto done;
462 } else if (c=='p' || c=='P') {
463 char *l = (c=='P') ? strchr(line, '\n') : 0;
464
465 if (emit(line, l ? l-line : len, eol)) break;
466 } else if (c=='q' || c=='Q') {
467 if (pline) *pline = (void *)1;
468 free(TT.nextline);
469 if (!toys.exitval && command->arg1)
470 toys.exitval = atoi(command->arg1+(char *)command);
471 TT.nextline = 0;
472 TT.nextlen = 0;
473 if (c=='Q') line = 0;
474
475 break;
476 } else if (c=='s') {
477 char *rline = line, *new = command->arg2 + (char *)command, *l2 = 0;
478 regmatch_t *match = (void *)toybuf;
479 regex_t *reg = get_regex(command, command->arg1);
480 int mflags = 0, count = 0, l2used = 0, zmatch = 1, l2l = len, l2old = 0,
481 mlen, off, newlen;
482
483
484 while (!regexec0(reg, rline, len-(rline-line), 10, match, mflags)) {
485 mflags = REG_NOTBOL;
486
487
488 mlen = match[0].rm_eo-match[0].rm_so;
489 if (!mlen && !zmatch) {
490 if (rline-line == len) break;
491 l2[l2used++] = *rline++;
492 zmatch++;
493 continue;
494 } else zmatch = 0;
495
496
497 off = command->sflags>>3;
498 if (off && off != ++count) {
499 memcpy(l2+l2used, rline, match[0].rm_eo);
500 l2used += match[0].rm_eo;
501 rline += match[0].rm_eo;
502
503 continue;
504 }
505
506
507 if (match[0].rm_eo > INT_MAX) perror_exit(0);
508
509
510 for (off = newlen = 0; new[off]; off++) {
511 int cc = -1;
512
513 if (new[off] == '&') cc = 0;
514 else if (new[off] == '\\') cc = new[++off] - '0';
515 if (cc < 0 || cc > 9) {
516 newlen++;
517 continue;
518 }
519 newlen += match[cc].rm_eo-match[cc].rm_so;
520 }
521
522
523
524
525 l2l += newlen-mlen;
526 if ((l2l|0xfff) > l2old) l2 = xrealloc(l2, l2old = (l2l|0xfff)+1);
527 if (match[0].rm_so) {
528 memcpy(l2+l2used, rline, match[0].rm_so);
529 l2used += match[0].rm_so;
530 }
531
532
533 for (off = mlen = 0; new[off]; off++) {
534 int cc = 0, ll;
535
536 if (new[off] == '\\') {
537 cc = new[++off] - '0';
538 if (cc<0 || cc>9) {
539 if (!(l2[l2used+mlen++] = unescape(new[off])))
540 l2[l2used+mlen-1] = new[off];
541
542 continue;
543 } else if (cc > reg->re_nsub) error_exit("no s//\\%d/", cc);
544 } else if (new[off] != '&') {
545 l2[l2used+mlen++] = new[off];
546
547 continue;
548 }
549
550 if (match[cc].rm_so != -1) {
551 ll = match[cc].rm_eo-match[cc].rm_so;
552 memcpy(l2+l2used+mlen, rline+match[cc].rm_so, ll);
553 mlen += ll;
554 }
555 }
556 l2used += newlen;
557 rline += match[0].rm_eo;
558
559
560 if (!(command->sflags & 2)) break;
561 }
562
563
564 if (l2) {
565
566 mlen = len-(rline-line);
567 memcpy(l2+l2used, rline, mlen+1);
568 len = l2used + mlen;
569 free(line);
570 line = l2;
571 }
572
573 if (mflags) {
574
575 if (command->sflags & 4) emit(line, len, eol);
576
577 tea = 1;
578 if (command->w) goto writenow;
579 }
580 } else if (c=='w') {
581 int fd, noeol;
582 char *name;
583
584writenow:
585
586 fd = TT.fdout;
587 noeol = TT.noeol;
588
589
590 name = command->w + (char *)command;
591 memcpy(&TT.fdout, name, 4);
592 name += 4;
593 TT.noeol = *(name++);
594
595
596 if (emit(line, len, eol))
597 perror_exit("w '%s'", command->arg1+(char *)command);
598 *(--name) = TT.noeol;
599 TT.noeol = noeol;
600 TT.fdout = fd;
601 } else if (c=='x') {
602 long swap = TT.rememberlen;
603
604 str = TT.remember;
605 TT.remember = line;
606 line = str;
607 TT.rememberlen = len;
608 len = swap;
609 } else if (c=='y') {
610 char *from, *to = (char *)command;
611 int i, j;
612
613 from = to+command->arg1;
614 to += command->arg2;
615
616 for (i = 0; i < len; i++) {
617 j = stridx(from, line[i]);
618 if (j != -1) line[i] = to[j];
619 }
620 } else if (c=='=') {
621 sprintf(toybuf, "%ld", TT.count);
622 if (emit(toybuf, strlen(toybuf), 1)) break;
623 }
624
625 command = command->next;
626 }
627
628 if (line && !FLAG(n)) emit(line, len, eol);
629
630done:
631 if (dlist_terminate(append)) while (append) {
632 struct append *a = append->next;
633
634 if (append->file) {
635 int fd = open(append->str, O_RDONLY);
636
637
638 if (fd != -1) {
639 if (TT.noeol) xwrite(TT.fdout, "\n", 1);
640 TT.noeol = 0;
641 xsendfile(fd, TT.fdout);
642 close(fd);
643 }
644 } else if (append->str) emit(append->str, strlen(append->str), 1);
645 else emit(line, 0, 0);
646 free(append);
647 append = a;
648 }
649 free(line);
650}
651
652
653static void do_sed_file(int fd, char *name)
654{
655 char *tmp;
656
657 if (FLAG(i)) {
658 struct sedcmd *command;
659
660 if (!fd) return error_msg("-i on stdin");
661 TT.fdout = copy_tempfile(fd, name, &tmp);
662 TT.count = 0;
663 for (command = (void *)TT.pattern; command; command = command->next)
664 command->hit = 0;
665 }
666 do_lines(fd, TT.delim, sed_line);
667 if (FLAG(i)) {
668 if (TT.i && *TT.i) {
669 char *s = xmprintf("%s%s", name, TT.i);
670
671 xrename(name, s);
672 free(s);
673 }
674 replace_tempfile(-1, TT.fdout, &tmp);
675 TT.fdout = 1;
676 TT.nextline = 0;
677 TT.nextlen = TT.noeol = 0;
678 }
679}
680
681
682
683
684
685static char *unescape_delimited_string(char **pstr, char *delim)
686{
687 char *to, *from, mode = 0, d;
688
689
690 from = *pstr;
691 if (!delim || !*delim) {
692 if (!(d = *(from++))) return 0;
693 if (d == '\\') d = *(from++);
694 if (!d || d == '\\') return 0;
695 if (delim) *delim = d;
696 } else d = *delim;
697 to = delim = xmalloc(strlen(*pstr)+1);
698
699 while (mode || *from != d) {
700 if (!*from) return 0;
701
702
703 if (*from == '[') {
704 if (!mode) {
705 mode = ']';
706 if (from[1]=='-' || from[1]==']') *(to++) = *(from++);
707 } else if (mode == ']' && strchr(".=:", from[1])) {
708 *(to++) = *(from++);
709 mode = *from;
710 }
711 } else if (*from == mode) {
712 if (mode == ']') mode = 0;
713 else {
714 *(to++) = *(from++);
715 mode = ']';
716 }
717
718
719 } else if (mode && *from == '-' && from[-1] == from[1]) {
720 from+=2;
721 continue;
722 } else if (*from == '\\') {
723 if (!from[1]) return 0;
724
725
726 if (from[1] == d) from++;
727 else if (from[1]=='\\') *(to++) = *(from++);
728 else {
729 char c = unescape(from[1]);
730
731 if (c) {
732 *(to++) = c;
733 from+=2;
734 continue;
735 } else if (!mode) *(to++) = *(from++);
736 }
737 }
738 *(to++) = *(from++);
739 }
740 *to = 0;
741 *pstr = from+1;
742
743 return delim;
744}
745
746
747
748static void parse_pattern(char **pline, long len)
749{
750 struct sedcmd *command = (void *)TT.pattern;
751 char *line, *reg, c, *errstart;
752 int i;
753
754 line = errstart = pline ? *pline : "";
755 if (len && line[len-1]=='\n') line[--len] = 0;
756
757
758
759
760
761 if (command && command->prev->hit) {
762
763 TT.pattern = TT.pattern->prev;
764 command = dlist_pop(&TT.pattern);
765 c = command->c;
766 reg = (char *)command;
767 reg += command->arg1 + strlen(reg + command->arg1);
768
769
770
771
772 if (command->hit < 256) goto resume_s;
773 else goto resume_a;
774 }
775
776
777
778 command = 0;
779 for (;;) {
780 if (command) dlist_add_nomalloc(&TT.pattern, (void *)command);
781
782
783 for (;;) {
784 while (isspace(*line) || *line == ';') line++;
785 if (*line == '#') while (*line && *line != '\n') line++;
786 else break;
787 }
788 if (!*line) return;
789
790
791
792 errstart = line;
793 memset(toybuf, 0, sizeof(struct sedcmd));
794 command = (void *)toybuf;
795 reg = toybuf + sizeof(struct sedcmd);
796
797
798 for (i = 0; i < 2; i++) {
799 if (*line == ',') line++;
800 else if (i) break;
801
802 if (i && *line == '+' && isdigit(line[1])) {
803 line++;
804 command->lmatch[i] = -2-strtol(line, &line, 0);
805 } else if (isdigit(*line)) command->lmatch[i] = strtol(line, &line, 0);
806 else if (*line == '$') {
807 command->lmatch[i] = -1;
808 line++;
809 } else if (*line == '/' || *line == '\\') {
810 char *s = line;
811
812 if (!(s = unescape_delimited_string(&line, 0))) goto error;
813 if (!*s) command->rmatch[i] = 0;
814 else {
815 xregcomp((void *)reg, s, REG_EXTENDED*!!FLAG(r));
816 command->rmatch[i] = reg-toybuf;
817 reg += sizeof(regex_t);
818 }
819 free(s);
820 } else break;
821 }
822
823 while (isspace(*line)) line++;
824 if (!*line) break;
825
826 if (*line == '!') {
827 command->not = 1;
828 line++;
829 }
830 while (isspace(*line)) line++;
831 if (!*line) break;
832
833 c = command->c = *(line++);
834 if (strchr("}:", c) && i) break;
835 if (strchr("aiqQr=", c) && i>1) break;
836
837
838 command = xmemdup(toybuf, reg-toybuf);
839 reg = (reg-toybuf) + (char *)command;
840
841
842 if (c == '{') TT.nextlen++;
843 else if (c == '}') {
844 if (!TT.nextlen--) break;
845 } else if (c == 's') {
846 char *end, delim = 0;
847
848
849
850
851
852
853
854
855 command->arg2 = reg - (char *)command;
856 if (!(TT.remember = unescape_delimited_string(&line, &delim)))
857 goto error;
858
859 reg += sizeof(regex_t);
860 command->arg1 = reg-(char *)command;
861 command->hit = delim;
862resume_s:
863
864
865 end = line;
866 while (*end != command->hit) {
867 if (!*end) goto error;
868 if (*end++ == '\\') {
869 if (!*end || *end == '\n') {
870 end[-1] = '\n';
871 break;
872 }
873 end++;
874 }
875 }
876
877 reg = extend_string((void *)&command, line, reg-(char *)command,end-line);
878 line = end;
879
880 if (*line == command->hit) command->hit = 0;
881 else {
882 if (!*line) continue;
883 reg--;
884 line++;
885 goto resume_s;
886 }
887
888
889 i = command->arg1;
890 command->arg1 = command->arg2;
891 command->arg2 = i;
892
893
894 for (line++; *line; line++) {
895 long l;
896
897 if (isspace(*line) && *line != '\n') continue;
898
899 if (0 <= (l = stridx("igp", *line))) command->sflags |= 1<<l;
900 else if (!(command->sflags>>3) && 0<(l = strtol(line, &line, 10))) {
901 command->sflags |= l << 3;
902 line--;
903 } else break;
904 }
905
906
907
908 if (!*TT.remember) command->arg1 = 0;
909 else xregcomp((void *)(command->arg1 + (char *)command), TT.remember,
910 (REG_EXTENDED*!!FLAG(r))|((command->sflags&1)*REG_ICASE));
911 free(TT.remember);
912 TT.remember = 0;
913 if (*line == 'w') {
914 line++;
915 goto writenow;
916 }
917 } else if (c == 'w') {
918 int fd, delim;
919 char *cc;
920
921
922
923
924
925
926writenow:
927 while (isspace(*line)) line++;
928 if (!*line) goto error;
929 for (cc = line; *cc; cc++) if (*cc == '\\' && cc[1] == ';') break;
930 delim = *cc;
931 *cc = 0;
932 fd = xcreate(line, O_WRONLY|O_CREAT|O_TRUNC, 0644);
933 *cc = delim;
934
935 command->w = reg - (char *)command;
936 command = xrealloc(command, command->w+(cc-line)+6);
937 reg = command->w + (char *)command;
938
939 memcpy(reg, &fd, 4);
940 reg += 4;
941 *(reg++) = 0;
942 memcpy(reg, line, delim);
943 reg += delim;
944 *(reg++) = 0;
945
946 line = cc;
947 if (delim) line += 2;
948 } else if (c == 'y') {
949 char *s, delim = 0;
950 int len;
951
952 if (!(s = unescape_delimited_string(&line, &delim))) goto error;
953 command->arg1 = reg-(char *)command;
954 len = strlen(s);
955 reg = extend_string((void *)&command, s, reg-(char *)command, len);
956 free(s);
957 command->arg2 = reg-(char *)command;
958 if (!(s = unescape_delimited_string(&line, &delim))) goto error;
959 if (len != strlen(s)) goto error;
960 reg = extend_string((void *)&command, s, reg-(char*)command, len);
961 free(s);
962 } else if (strchr("abcirtTqQw:", c)) {
963 int end;
964
965
966 while (isspace(*line) && *line != '\n') line++;
967
968
969
970resume_a:
971 command->hit = 0;
972
973
974 if (!(end = strcspn(line, strchr(":btTqQ", c) ? "}; \t\r\n\v\f" : "\n"))){
975
976 if (strchr("btTqQ", c)) continue;
977 else if (!command->arg1) break;
978 }
979
980 if (c=='q' || c=='Q') {
981 for (i = 0; i<end && isdigit(line[i]); i++);
982 if (i != end) {
983 line += i;
984 break;
985 }
986 }
987
988
989
990
991 if (!command->arg1) command->arg1 = reg - (char*)command;
992 else if (*(command->arg1+(char *)command)) *(reg++) = '\n';
993 else if (!pline) {
994 command->arg1 = 0;
995 continue;
996 }
997 reg = extend_string((void *)&command, line, reg - (char *)command, end);
998
999
1000 if (strchr("aci", c)) {
1001 reg -= end+1;
1002 for (i = end; i; i--) {
1003 if ((*reg++ = *line++)=='\\') {
1004
1005
1006
1007 if (!--i) {
1008 *--reg = 0;
1009 if (*line) {
1010 line++;
1011 goto resume_a;
1012 }
1013 command->hit = 256;
1014 break;
1015 }
1016 if (!(reg[-1] = unescape(*line))) reg[-1] = *line;
1017 line++;
1018 }
1019 }
1020 *reg = 0;
1021 } else line += end;
1022
1023
1024 } else if (!strchr("{dDgGhHlnNpPx=", c)) break;
1025 }
1026
1027error:
1028 error_exit("bad pattern '%s'@%ld (%c)", errstart, line-errstart+1L, *line);
1029}
1030
1031void sed_main(void)
1032{
1033 struct arg_list *al;
1034 char **args = toys.optargs;
1035
1036 if (!FLAG(z)) TT.delim = '\n';
1037
1038
1039
1040
1041 if (FLAG(version)) {
1042 xprintf("This is not GNU sed version 9.0\n");
1043 return;
1044 }
1045
1046
1047 if (FLAG(help)) help_exit(0);
1048
1049
1050
1051
1052 if (!TT.e && !TT.f) {
1053 if (!*toys.optargs) error_exit("no pattern");
1054 (TT.e = xzalloc(sizeof(struct arg_list)))->arg = *(args++);
1055 }
1056
1057
1058
1059
1060 for (al = TT.e; al; al = al->next) parse_pattern(&al->arg, strlen(al->arg));
1061 parse_pattern(0, 0);
1062 for (al = TT.f; al; al = al->next)
1063 do_lines(xopenro(al->arg), TT.delim, parse_pattern);
1064 dlist_terminate(TT.pattern);
1065 if (TT.nextlen) error_exit("no }");
1066
1067 TT.fdout = 1;
1068 TT.remember = xstrdup("");
1069
1070
1071 loopfiles_rw(args, O_RDONLY|WARN_ONLY, 0, do_sed_file);
1072
1073
1074 if (!FLAG(i)) {
1075 toys.optflags |= FLAG_i;
1076 sed_line(0, 0);
1077 }
1078
1079
1080}
1081