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