source: trunk/src/oldsed/sed/execute.c@ 3670

Last change on this file since 3670 was 1301, checked in by bird, 18 years ago

Added options for sending the output to a file without having to make use of redirection (-o, --output, --output-text, --output-binary).

File size: 44.9 KB
Line 
1/* GNU SED, a batch stream editor.
2 Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003,2004,2005,2006
3 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19#undef EXPERIMENTAL_DASH_N_OPTIMIZATION /*don't use -- is very buggy*/
20#define INITIAL_BUFFER_SIZE 50
21#define FREAD_BUFFER_SIZE 8192
22
23#include "sed.h"
24
25#include <stdio.h>
26#include <ctype.h>
27
28#include <errno.h>
29#ifndef errno
30extern int errno;
31#endif
32
33#ifdef HAVE_UNISTD_H
34# include <unistd.h>
35#endif
36
37#ifdef __GNUC__
38# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7)
39 /* silence warning about unused parameter even for "gcc -W -Wunused" */
40# define UNUSED __attribute__((unused))
41# endif
42#endif
43#ifndef UNUSED
44# define UNUSED
45#endif
46
47#ifdef HAVE_STRINGS_H
48# include <strings.h>
49#else
50# include <string.h>
51#endif /*HAVE_STRINGS_H*/
52#ifdef HAVE_MEMORY_H
53# include <memory.h>
54#endif
55
56#ifndef HAVE_STRCHR
57# define strchr index
58# define strrchr rindex
59#endif
60
61#ifdef HAVE_STDLIB_H
62# include <stdlib.h>
63#endif
64#ifndef EXIT_SUCCESS
65# define EXIT_SUCCESS 0
66#endif
67
68#ifdef HAVE_SYS_TYPES_H
69# include <sys/types.h>
70#endif
71
72#include <sys/stat.h>
73
74
75
76/* Sed operates a line at a time. */
77struct line {
78 char *text; /* Pointer to line allocated by malloc. */
79 char *active; /* Pointer to non-consumed part of text. */
80 size_t length; /* Length of text (or active, if used). */
81 size_t alloc; /* Allocated space for active. */
82 bool chomped; /* Was a trailing newline dropped? */
83#ifdef HAVE_MBRTOWC
84 mbstate_t mbstate;
85#endif
86};
87
88/* A queue of text to write out at the end of a cycle
89 (filled by the "a", "r" and "R" commands.) */
90struct append_queue {
91 const char *fname;
92 char *text;
93 size_t textlen;
94 struct append_queue *next;
95 bool free;
96};
97
98/* State information for the input stream. */
99struct input {
100 /* The list of yet-to-be-opened files. It is invalid for file_list
101 to be NULL. When *file_list is NULL we are currently processing
102 the last file. */
103
104 char **file_list;
105
106 /* Count of files we failed to open. */
107 countT bad_count;
108
109 /* Current input line number (over all files). */
110 countT line_number;
111
112 /* True if we'll reset line numbers and addresses before
113 starting to process the next (possibly the first) file. */
114 bool reset_at_next_file;
115
116 /* Function to read one line. If FP is NULL, read_fn better not
117 be one which uses fp; in particular, read_always_fail() is
118 recommended. */
119 bool (*read_fn) P_((struct input *)); /* read one line */
120
121 char *out_file_name;
122
123 const char *in_file_name;
124
125 /* if NULL, none of the following are valid */
126 FILE *fp;
127
128 bool no_buffering;
129};
130
131
132/* Have we done any replacements lately? This is used by the `t' command. */
133static bool replaced = false;
134
135/* The current output file (stdout if -i is not being used. */
136static struct output output_file;
137
138/* The `current' input line. */
139static struct line line;
140
141/* An input line used to accumulate the result of the s and e commands. */
142static struct line s_accum;
143
144/* An input line that's been stored by later use by the program */
145static struct line hold;
146
147/* The buffered input look-ahead. The only field that should be
148 used outside of read_mem_line() or line_init() is buffer.length. */
149static struct line buffer;
150
151static struct append_queue *append_head = NULL;
152static struct append_queue *append_tail = NULL;
153
154
155
156#ifdef BOOTSTRAP
157/* We can't be sure that the system we're boostrapping on has
158 memchr(), and ../lib/memchr.c requires configuration knowledge
159 about how many bits are in a `long'. This implementation
160 is far from ideal, but it should get us up-and-limping well
161 enough to run the configure script, which is all that matters.
162*/
163# ifdef memchr
164# undef memchr
165# endif
166# define memchr bootstrap_memchr
167
168static VOID *bootstrap_memchr P_((const VOID *s, int c, size_t n));
169static VOID *
170bootstrap_memchr(s, c, n)
171 const VOID *s;
172 int c;
173 size_t n;
174{
175 char *p;
176
177 for (p=(char *)s; n-- > 0; ++p)
178 if (*p == c)
179 return p;
180 return CAST(VOID *)0;
181}
182#endif /*BOOTSTRAP*/
183
184/* increase a struct line's length, making some attempt at
185 keeping realloc() calls under control by padding for future growth. */
186static void resize_line P_((struct line *, size_t));
187static void
188resize_line(lb, len)
189 struct line *lb;
190 size_t len;
191{
192 int inactive;
193 inactive = lb->active - lb->text;
194
195 /* If the inactive part has got to more than two thirds of the buffer,
196 * remove it. */
197 if (inactive > lb->alloc * 2)
198 {
199 MEMMOVE(lb->text, lb->active, lb->length);
200 lb->alloc += lb->active - lb->text;
201 lb->active = lb->text;
202 inactive = 0;
203
204 if (lb->alloc > len)
205 return;
206 }
207
208 lb->alloc *= 2;
209 if (lb->alloc < len)
210 lb->alloc = len;
211 if (lb->alloc < INITIAL_BUFFER_SIZE)
212 lb->alloc = INITIAL_BUFFER_SIZE;
213
214 lb->text = REALLOC(lb->text, inactive + lb->alloc, char);
215 lb->active = lb->text + inactive;
216}
217
218/* Append `length' bytes from `string' to the line `to'. */
219static void str_append P_((struct line *, const char *, size_t));
220static void
221str_append(to, string, length)
222 struct line *to;
223 const char *string;
224 size_t length;
225{
226 size_t new_length = to->length + length;
227
228 if (to->alloc < new_length)
229 resize_line(to, new_length);
230 MEMCPY(to->active + to->length, string, length);
231 to->length = new_length;
232
233#ifdef HAVE_MBRTOWC
234 if (mb_cur_max == 1)
235 return;
236
237 while (length)
238 {
239 int n = MBRLEN (string, length, &to->mbstate);
240
241 /* An invalid sequence is treated like a singlebyte character. */
242 if (n == -1)
243 {
244 memset (&to->mbstate, 0, sizeof (to->mbstate));
245 n = 1;
246 }
247
248 if (n > 0)
249 length -= n;
250 else
251 break;
252 }
253#endif
254}
255
256static void str_append_modified P_((struct line *, const char *, size_t,
257 enum replacement_types));
258static void
259str_append_modified(to, string, length, type)
260 struct line *to;
261 const char *string;
262 size_t length;
263 enum replacement_types type;
264{
265 size_t old_length = to->length;
266 char *start, *end;
267
268 if (length == 0)
269 return;
270
271#ifdef HAVE_MBRTOWC
272 {
273 mbstate_t from_stat;
274
275 if (type == REPL_ASIS)
276 {
277 str_append(to, string, length);
278 return;
279 }
280
281 if (to->alloc - to->length < length * mb_cur_max)
282 resize_line(to, to->length + length * mb_cur_max);
283
284 MEMCPY (&from_stat, &to->mbstate, sizeof(mbstate_t));
285 while (length)
286 {
287 wchar_t wc;
288 int n = MBRTOWC (&wc, string, length, &from_stat);
289
290 /* An invalid sequence is treated like a singlebyte character. */
291 if (n == -1)
292 {
293 memset (&to->mbstate, 0, sizeof (from_stat));
294 n = 1;
295 }
296
297 if (n > 0)
298 string += n, length -= n;
299 else
300 {
301 /* Incomplete sequence, copy it manually. */
302 str_append(to, string, length);
303 return;
304 }
305
306 /* Convert the first character specially... */
307 if (type & (REPL_UPPERCASE_FIRST | REPL_LOWERCASE_FIRST))
308 {
309 if (type & REPL_UPPERCASE_FIRST)
310 wc = towupper(wc);
311 else
312 wc = towlower(wc);
313
314 type &= ~(REPL_LOWERCASE_FIRST | REPL_UPPERCASE_FIRST);
315 if (type == REPL_ASIS)
316 {
317 n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
318 to->length += n;
319 str_append(to, string, length);
320 return;
321 }
322 }
323
324 else if (type & REPL_UPPERCASE)
325 wc = towupper(wc);
326 else
327 wc = towlower(wc);
328
329 /* Copy the new wide character to the end of the string. */
330 n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
331 to->length += n;
332 if (n == -1)
333 {
334 fprintf (stderr, "Case conversion produced an invalid character!");
335 abort ();
336 }
337 }
338 }
339#else
340 str_append(to, string, length);
341 start = to->active + old_length;
342 end = start + length;
343
344 /* Now do the required modifications. First \[lu]... */
345 if (type & REPL_UPPERCASE_FIRST)
346 {
347 *start = toupper(*start);
348 start++;
349 type &= ~REPL_UPPERCASE_FIRST;
350 }
351 else if (type & REPL_LOWERCASE_FIRST)
352 {
353 *start = tolower(*start);
354 start++;
355 type &= ~REPL_LOWERCASE_FIRST;
356 }
357
358 if (type == REPL_ASIS)
359 return;
360
361 /* ...and then \[LU] */
362 if (type == REPL_UPPERCASE)
363 for (; start != end; start++)
364 *start = toupper(*start);
365 else
366 for (; start != end; start++)
367 *start = tolower(*start);
368#endif
369}
370
371/* initialize a "struct line" buffer */
372static void line_init P_((struct line *, size_t initial_size));
373static void
374line_init(buf, initial_size)
375 struct line *buf;
376 size_t initial_size;
377{
378 buf->text = MALLOC(initial_size, char);
379 buf->active = buf->text;
380 buf->alloc = initial_size;
381 buf->length = 0;
382 buf->chomped = true;
383
384#ifdef HAVE_MBRTOWC
385 memset (&buf->mbstate, 0, sizeof (buf->mbstate));
386#endif
387
388}
389
390/* Copy the contents of the line `from' into the line `to'.
391 This destroys the old contents of `to'. */
392static void line_copy P_((struct line *from, struct line *to));
393static void
394line_copy(from, to)
395 struct line *from;
396 struct line *to;
397{
398 /* Remove the inactive portion in the destination buffer. */
399 to->alloc += to->active - to->text;
400
401 if (to->alloc < from->length)
402 {
403 to->alloc *= 2;
404 if (to->alloc < from->length)
405 to->alloc = from->length;
406 if (to->alloc < INITIAL_BUFFER_SIZE)
407 to->alloc = INITIAL_BUFFER_SIZE;
408 /* Use FREE()+MALLOC() instead of REALLOC() to
409 avoid unnecessary copying of old text. */
410 FREE(to->text);
411 to->text = MALLOC(to->alloc, char);
412 }
413
414 to->active = to->text;
415 to->length = from->length;
416 to->chomped = from->chomped;
417 MEMCPY(to->active, from->active, from->length);
418
419#ifdef HAVE_MBRTOWC
420 MEMCPY(&to->mbstate, &from->mbstate, sizeof (from->mbstate));
421#endif
422}
423
424/* Append the contents of the line `from' to the line `to'. */
425static void line_append P_((struct line *from, struct line *to));
426static void
427line_append(from, to)
428 struct line *from;
429 struct line *to;
430{
431 str_append(to, "\n", 1);
432 str_append(to, from->active, from->length);
433 to->chomped = from->chomped;
434
435#ifdef HAVE_MBRTOWC
436 MEMCPY (&to->mbstate, &from->mbstate, sizeof (from->mbstate));
437#endif
438}
439
440/* Exchange the contents of two "struct line" buffers. */
441static void line_exchange P_((struct line *, struct line *));
442static void
443line_exchange(a, b)
444 struct line *a;
445 struct line *b;
446{
447 struct line t;
448
449 MEMCPY(&t, a, sizeof(struct line));
450 MEMCPY( a, b, sizeof(struct line));
451 MEMCPY( b, &t, sizeof(struct line));
452}
453
454
455
456/* dummy function to simplify read_pattern_space() */
457static bool read_always_fail P_((struct input *));
458static bool
459read_always_fail(input)
460 struct input *input UNUSED;
461{
462 return false;
463}
464
465static bool read_file_line P_((struct input *));
466static bool
467read_file_line(input)
468 struct input *input;
469{
470 static char *b;
471 static size_t blen;
472
473 long result = ck_getline (&b, &blen, input->fp);
474 if (result <= 0)
475 return false;
476
477 /* Remove the trailing new-line that is left by getline. */
478 if (b[result - 1] == '\n')
479 --result;
480 else
481 line.chomped = false;
482
483 str_append(&line, b, result);
484 return true;
485}
486
487
488
489static inline void output_missing_newline P_((struct output *));
490static inline void
491output_missing_newline(outf)
492 struct output *outf;
493{
494 if (outf->missing_newline)
495 {
496 ck_fwrite("\n", 1, 1, outf->fp);
497 outf->missing_newline = false;
498 }
499}
500
501static inline void flush_output P_((FILE *));
502static inline void
503flush_output(fp)
504 FILE *fp;
505{
506#ifndef CONFIG_WITHOUT_O_OPT
507 if (fp != sed_stdout || unbuffered_output)
508#else
509 if (fp != stdout || unbuffered_output)
510#endif
511 ck_fflush(fp);
512}
513
514static void output_line P_((const char *, size_t, bool, struct output *));
515static void
516output_line(text, length, nl, outf)
517 const char *text;
518 size_t length;
519 bool nl;
520 struct output *outf;
521{
522 output_missing_newline(outf);
523
524 if (length)
525 ck_fwrite(text, 1, length, outf->fp);
526
527 if (nl)
528 ck_fwrite("\n", 1, 1, outf->fp);
529 else
530 outf->missing_newline = true;
531
532 flush_output(outf->fp);
533}
534
535static struct append_queue *next_append_slot P_((void));
536static struct append_queue *
537next_append_slot()
538{
539 struct append_queue *n = MALLOC(1, struct append_queue);
540
541 n->fname = NULL;
542 n->text = NULL;
543 n->textlen = 0;
544 n->next = NULL;
545 n->free = false;
546
547 if (append_tail)
548 append_tail->next = n;
549 else
550 append_head = n;
551 return append_tail = n;
552}
553
554static void release_append_queue P_((void));
555static void
556release_append_queue()
557{
558 struct append_queue *p, *q;
559
560 for (p=append_head; p; p=q)
561 {
562 if (p->free)
563 FREE(p->text);
564
565 q = p->next;
566 FREE(p);
567 }
568 append_head = append_tail = NULL;
569}
570
571static void dump_append_queue P_((void));
572static void
573dump_append_queue()
574{
575 struct append_queue *p;
576
577 output_missing_newline(&output_file);
578 for (p=append_head; p; p=p->next)
579 {
580 if (p->text)
581 ck_fwrite(p->text, 1, p->textlen, output_file.fp);
582
583 if (p->fname)
584 {
585 char buf[FREAD_BUFFER_SIZE];
586 size_t cnt;
587 FILE *fp;
588
589 /* "If _fname_ does not exist or cannot be read, it shall
590 be treated as if it were an empty file, causing no error
591 condition." IEEE Std 1003.2-1992
592 So, don't fail. */
593 fp = ck_fopen(p->fname, "r", false);
594 if (fp)
595 {
596 while ((cnt = ck_fread(buf, 1, sizeof buf, fp)) > 0)
597 ck_fwrite(buf, 1, cnt, output_file.fp);
598 ck_fclose(fp);
599 }
600 }
601 }
602
603 flush_output(output_file.fp);
604 release_append_queue();
605}
606
607
608
609/* Compute the name of the backup file for in-place editing */
610static char *get_backup_file_name P_((const char *));
611static char *
612get_backup_file_name(name)
613 const char *name;
614{
615 char *old_asterisk, *asterisk, *backup, *p;
616 int name_length = strlen(name), backup_length = strlen(in_place_extension);
617
618 /* Compute the length of the backup file */
619 for (asterisk = in_place_extension - 1, old_asterisk = asterisk + 1;
620 asterisk = strchr(old_asterisk, '*');
621 old_asterisk = asterisk + 1)
622 backup_length += name_length - 1;
623
624 p = backup = xmalloc(backup_length + 1);
625
626 /* Each iteration gobbles up to an asterisk */
627 for (asterisk = in_place_extension - 1, old_asterisk = asterisk + 1;
628 asterisk = strchr(old_asterisk, '*');
629 old_asterisk = asterisk + 1)
630 {
631 MEMCPY (p, old_asterisk, asterisk - old_asterisk);
632 p += asterisk - old_asterisk;
633 strcpy (p, name);
634 p += name_length;
635 }
636
637 /* Tack on what's after the last asterisk */
638 strcpy (p, old_asterisk);
639 return backup;
640}
641
642/* Initialize a struct input for the named file. */
643static void open_next_file P_((const char *name, struct input *));
644static void
645open_next_file(name, input)
646 const char *name;
647 struct input *input;
648{
649 buffer.length = 0;
650
651 if (name[0] == '-' && name[1] == '\0' && !in_place_extension)
652 {
653 clearerr(stdin); /* clear any stale EOF indication */
654 input->fp = stdin;
655 }
656 else if ( ! (input->fp = ck_fopen(name, "r", false)) )
657 {
658 const char *ptr = strerror(errno);
659 fprintf(stderr, _("%s: can't read %s: %s\n"), myname, name, ptr);
660 input->read_fn = read_always_fail; /* a redundancy */
661 ++input->bad_count;
662 return;
663 }
664
665 input->read_fn = read_file_line;
666
667 if (in_place_extension)
668 {
669 int output_fd;
670 char *tmpdir = ck_strdup(name), *p;
671 struct stat st;
672
673 /* get the base name */
674 if (p = strrchr(tmpdir, '/'))
675 *(p + 1) = 0;
676 else
677 strcpy(tmpdir, ".");
678
679 input->in_file_name = name;
680
681 if (isatty (fileno (input->fp)))
682 panic(_("couldn't edit %s: is a terminal"), input->in_file_name);
683
684 fstat (fileno (input->fp), &st);
685 if (!S_ISREG (st.st_mode))
686 panic(_("couldn't edit %s: not a regular file"), input->in_file_name);
687
688 output_file.fp = ck_mkstemp (&input->out_file_name, tmpdir, "sed");
689 output_file.missing_newline = false;
690 free (tmpdir);
691
692 if (!output_file.fp)
693 panic(_("couldn't open temporary file %s: %s"), input->out_file_name, strerror(errno));
694
695 output_fd = fileno (output_file.fp);
696#ifdef HAVE_FCHMOD
697 fchmod (output_fd, st.st_mode);
698#endif
699#ifdef HAVE_FCHOWN
700 if (fchown (output_fd, st.st_uid, st.st_gid) == -1)
701 fchown (output_fd, -1, st.st_gid);
702#endif
703 }
704 else
705#ifndef CONFIG_WITHOUT_O_OPT
706 output_file.fp = sed_stdout;
707#else
708 output_file.fp = stdout;
709#endif
710}
711
712
713/* Clean up an input stream that we are done with. */
714static void closedown P_((struct input *));
715static void
716closedown(input)
717 struct input *input;
718{
719 input->read_fn = read_always_fail;
720 if (!input->fp)
721 return;
722 if (input->fp != stdin) /* stdin can be reused on tty and tape devices */
723 ck_fclose(input->fp);
724
725 if (in_place_extension && output_file.fp != NULL)
726 {
727 ck_fclose (output_file.fp);
728 if (strcmp(in_place_extension, "*") != 0)
729 {
730 char *backup_file_name = get_backup_file_name(input->in_file_name);
731 ck_rename (input->in_file_name, backup_file_name, input->out_file_name);
732 free (backup_file_name);
733 }
734
735 ck_rename (input->out_file_name, input->in_file_name, input->out_file_name);
736 free (input->out_file_name);
737 }
738
739 input->fp = NULL;
740}
741
742/* Reset range commands so that they are marked as non-matching */
743static void reset_addresses P_((struct vector *));
744static void
745reset_addresses(vec)
746 struct vector *vec;
747{
748 struct sed_cmd *cur_cmd;
749 int n;
750
751 for (cur_cmd = vec->v, n = vec->v_length; n--; cur_cmd++)
752 if (cur_cmd->a1
753 && cur_cmd->a1->addr_type == ADDR_IS_NUM
754 && cur_cmd->a1->addr_number == 0)
755 cur_cmd->range_state = RANGE_ACTIVE;
756 else
757 cur_cmd->range_state = RANGE_INACTIVE;
758}
759
760/* Read in the next line of input, and store it in the pattern space.
761 Return zero if there is nothing left to input. */
762static bool read_pattern_space P_((struct input *, struct vector *, bool));
763static bool
764read_pattern_space(input, the_program, append)
765 struct input *input;
766 struct vector *the_program;
767 bool append;
768{
769 if (append_head) /* redundant test to optimize for common case */
770 dump_append_queue();
771 replaced = false;
772 if (!append)
773 line.length = 0;
774 line.chomped = true; /* default, until proved otherwise */
775
776 while ( ! (*input->read_fn)(input) )
777 {
778 closedown(input);
779
780 if (!*input->file_list)
781 return false;
782
783 if (input->reset_at_next_file)
784 {
785 input->line_number = 0;
786 reset_addresses (the_program);
787 rewind_read_files ();
788
789 /* If doing in-place editing, we will never append the
790 new-line to this file; but if the output goes to stdout,
791 we might still have to output the missing new-line. */
792 if (in_place_extension)
793 output_file.missing_newline = false;
794
795 input->reset_at_next_file = separate_files;
796 }
797
798 open_next_file (*input->file_list++, input);
799 }
800
801 ++input->line_number;
802 return true;
803}
804
805
806
807static bool last_file_with_data_p P_((struct input *));
808static bool
809last_file_with_data_p(input)
810 struct input *input;
811{
812 for (;;)
813 {
814 int ch;
815
816 closedown(input);
817 if (!*input->file_list)
818 return true;
819 open_next_file(*input->file_list++, input);
820 if (input->fp)
821 {
822 if ((ch = getc(input->fp)) != EOF)
823 {
824 ungetc(ch, input->fp);
825 return false;
826 }
827 }
828 }
829}
830
831/* Determine if we match the `$' address. */
832static bool test_eof P_((struct input *));
833static bool
834test_eof(input)
835 struct input *input;
836{
837 int ch;
838
839 if (buffer.length)
840 return false;
841 if (!input->fp)
842 return separate_files || last_file_with_data_p(input);
843 if (feof(input->fp))
844 return separate_files || last_file_with_data_p(input);
845 if ((ch = getc(input->fp)) == EOF)
846 return separate_files || last_file_with_data_p(input);
847 ungetc(ch, input->fp);
848 return false;
849}
850
851/* Return non-zero if the current line matches the address
852 pointed to by `addr'. */
853static bool match_an_address_p P_((struct addr *, struct input *));
854static bool
855match_an_address_p(addr, input)
856 struct addr *addr;
857 struct input *input;
858{
859 switch (addr->addr_type)
860 {
861 case ADDR_IS_NULL:
862 return true;
863
864 case ADDR_IS_REGEX:
865 return match_regex(addr->addr_regex, line.active, line.length, 0, NULL, 0);
866
867 case ADDR_IS_NUM_MOD:
868 return (input->line_number >= addr->addr_number
869 && ((input->line_number - addr->addr_number) % addr->addr_step) == 0);
870
871 case ADDR_IS_STEP:
872 case ADDR_IS_STEP_MOD:
873 /* reminder: these are only meaningful for a2 addresses */
874 /* a2->addr_number needs to be recomputed each time a1 address
875 matches for the step and step_mod types */
876 return (addr->addr_number <= input->line_number);
877
878 case ADDR_IS_LAST:
879 return test_eof(input);
880
881 /* ADDR_IS_NUM is handled in match_address_p. */
882 case ADDR_IS_NUM:
883 default:
884 panic("INTERNAL ERROR: bad address type");
885 }
886 /*NOTREACHED*/
887 return false;
888}
889
890/* return non-zero if current address is valid for cmd */
891static bool match_address_p P_((struct sed_cmd *, struct input *));
892static bool
893match_address_p(cmd, input)
894 struct sed_cmd *cmd;
895 struct input *input;
896{
897 if (!cmd->a1)
898 return true;
899
900 if (cmd->range_state != RANGE_ACTIVE)
901 {
902 /* Find if we are going to activate a range. Handle ADDR_IS_NUM
903 specially: it represent an "absolute" state, it should not
904 be computed like regexes. */
905 if (cmd->a1->addr_type == ADDR_IS_NUM)
906 {
907 if (!cmd->a2)
908 return (input->line_number == cmd->a1->addr_number);
909
910 if (cmd->range_state == RANGE_CLOSED
911 || input->line_number < cmd->a1->addr_number)
912 return false;
913 }
914 else
915 {
916 if (!cmd->a2)
917 return match_an_address_p(cmd->a1, input);
918
919 if (!match_an_address_p(cmd->a1, input))
920 return false;
921 }
922
923 /* Ok, start a new range. */
924 cmd->range_state = RANGE_ACTIVE;
925 switch (cmd->a2->addr_type)
926 {
927 case ADDR_IS_REGEX:
928 /* Always include at least two lines. */
929 return true;
930 case ADDR_IS_NUM:
931 /* Same handling as below, but always include at least one line. */
932 if (input->line_number >= cmd->a2->addr_number)
933 cmd->range_state = RANGE_CLOSED;
934 return true;
935 case ADDR_IS_STEP:
936 cmd->a2->addr_number = input->line_number + cmd->a2->addr_step;
937 return true;
938 case ADDR_IS_STEP_MOD:
939 cmd->a2->addr_number = input->line_number + cmd->a2->addr_step
940 - (input->line_number%cmd->a2->addr_step);
941 return true;
942 default:
943 break;
944 }
945 }
946
947 /* cmd->range_state == RANGE_ACTIVE. Check if the range is
948 ending; also handle ADDR_IS_NUM specially in this case. */
949
950 if (cmd->a2->addr_type == ADDR_IS_NUM)
951 {
952 /* If the second address is a line number, and if we got past
953 that line, fail to match (it can happen when you jump
954 over such addresses with `b' and `t'. Use RANGE_CLOSED
955 so that the range is not re-enabled anymore. */
956 if (input->line_number >= cmd->a2->addr_number)
957 cmd->range_state = RANGE_CLOSED;
958
959 return (input->line_number <= cmd->a2->addr_number);
960 }
961
962 /* Other addresses are treated as usual. */
963 if (match_an_address_p(cmd->a2, input))
964 cmd->range_state = RANGE_CLOSED;
965
966 return true;
967}
968
969
970
971static void do_list P_((int line_len));
972static void
973do_list(line_len)
974 int line_len;
975{
976 unsigned char *p = CAST(unsigned char *)line.active;
977 countT len = line.length;
978 countT width = 0;
979 char obuf[180]; /* just in case we encounter a 512-bit char (;-) */
980 char *o;
981 size_t olen;
982 FILE *fp = output_file.fp;
983
984 output_missing_newline(&output_file);
985 for (; len--; ++p) {
986 o = obuf;
987
988 /* Some locales define 8-bit characters as printable. This makes the
989 testsuite fail at 8to7.sed because the `l' command in fact will not
990 convert the 8-bit characters. */
991#if defined isascii || defined HAVE_ISASCII
992 if (isascii(*p) && ISPRINT(*p)) {
993#else
994 if (ISPRINT(*p)) {
995#endif
996 *o++ = *p;
997 if (*p == '\\')
998 *o++ = '\\';
999 } else {
1000 *o++ = '\\';
1001 switch (*p) {
1002#if defined __STDC__ && __STDC__-0
1003 case '\a': *o++ = 'a'; break;
1004#else /* Not STDC; we'll just assume ASCII */
1005 case 007: *o++ = 'a'; break;
1006#endif
1007 case '\b': *o++ = 'b'; break;
1008 case '\f': *o++ = 'f'; break;
1009 case '\n': *o++ = 'n'; break;
1010 case '\r': *o++ = 'r'; break;
1011 case '\t': *o++ = 't'; break;
1012 case '\v': *o++ = 'v'; break;
1013 default:
1014 sprintf(o, "%03o", *p);
1015 o += strlen(o);
1016 break;
1017 }
1018 }
1019 olen = o - obuf;
1020 if (width+olen >= line_len && line_len > 0) {
1021 ck_fwrite("\\\n", 1, 2, fp);
1022 width = 0;
1023 }
1024 ck_fwrite(obuf, 1, olen, fp);
1025 width += olen;
1026 }
1027 ck_fwrite("$\n", 1, 2, fp);
1028 flush_output (fp);
1029}
1030
1031
1032static enum replacement_types append_replacement P_((struct line *, struct replacement *,
1033 struct re_registers *,
1034 enum replacement_types));
1035static enum replacement_types
1036append_replacement (buf, p, regs, repl_mod)
1037 struct line *buf;
1038 struct replacement *p;
1039 struct re_registers *regs;
1040 enum replacement_types repl_mod;
1041{
1042 for (; p; p=p->next)
1043 {
1044 int i = p->subst_id;
1045 enum replacement_types curr_type;
1046
1047 /* Apply a \[lu] modifier that was given earlier, but which we
1048 have not had yet the occasion to apply. But don't do it
1049 if this replacement has a modifier of its own. */
1050 curr_type = (p->repl_type & REPL_MODIFIERS)
1051 ? p->repl_type
1052 : p->repl_type | repl_mod;
1053
1054 repl_mod = 0;
1055 if (p->prefix_length)
1056 {
1057 str_append_modified(buf, p->prefix, p->prefix_length,
1058 curr_type);
1059 curr_type &= ~REPL_MODIFIERS;
1060 }
1061
1062 if (0 <= i)
1063 if (regs->end[i] == regs->start[i] && p->repl_type & REPL_MODIFIERS)
1064 /* Save this modifier, we shall apply it later.
1065 e.g. in s/()([a-z])/\u\1\2/
1066 the \u modifier is applied to \2, not \1 */
1067 repl_mod = curr_type & REPL_MODIFIERS;
1068
1069 else
1070 str_append_modified(buf, line.active + regs->start[i],
1071 CAST(size_t)(regs->end[i] - regs->start[i]),
1072 curr_type);
1073 }
1074
1075 return repl_mod;
1076}
1077
1078static void do_subst P_((struct subst *));
1079static void
1080do_subst(sub)
1081 struct subst *sub;
1082{
1083 size_t start = 0; /* where to start scan for (next) match in LINE */
1084 size_t last_end = 0; /* where did the last successful match end in LINE */
1085 countT count = 0; /* number of matches found */
1086 bool again = true;
1087
1088 static struct re_registers regs;
1089
1090 if (s_accum.alloc == 0)
1091 line_init(&s_accum, INITIAL_BUFFER_SIZE);
1092 s_accum.length = 0;
1093
1094 /* The first part of the loop optimizes s/xxx// when xxx is at the
1095 start, and s/xxx$// */
1096 if (!match_regex(sub->regx, line.active, line.length, start,
1097 &regs, sub->max_id + 1))
1098 return;
1099
1100 if (!sub->replacement && sub->numb <= 1)
1101 if (regs.start[0] == 0 && !sub->global)
1102 {
1103 /* We found a match, set the `replaced' flag. */
1104 replaced = true;
1105
1106 line.active += regs.end[0];
1107 line.length -= regs.end[0];
1108 line.alloc -= regs.end[0];
1109 goto post_subst;
1110 }
1111 else if (regs.end[0] == line.length)
1112 {
1113 /* We found a match, set the `replaced' flag. */
1114 replaced = true;
1115
1116 line.length = regs.start[0];
1117 goto post_subst;
1118 }
1119
1120 do
1121 {
1122 enum replacement_types repl_mod = 0;
1123
1124 size_t offset = regs.start[0];
1125 size_t matched = regs.end[0] - regs.start[0];
1126
1127 /* Copy stuff to the left of this match into the output string. */
1128 if (start < offset)
1129 str_append(&s_accum, line.active + start, offset - start);
1130
1131 /* If we're counting up to the Nth match, are we there yet?
1132 And even if we are there, there is another case we have to
1133 skip: are we matching an empty string immediately following
1134 another match?
1135
1136 This latter case avoids that baaaac, when passed through
1137 s,a*,x,g, gives `xbxxcx' instead of xbxcx. This behavior is
1138 unacceptable because it is not consistently applied (for
1139 example, `baaaa' gives `xbx', not `xbxx'). */
1140 if ((matched > 0 || count == 0 || offset > last_end)
1141 && ++count >= sub->numb)
1142 {
1143 /* We found a match, set the `replaced' flag. */
1144 replaced = true;
1145
1146 /* Now expand the replacement string into the output string. */
1147 repl_mod = append_replacement (&s_accum, sub->replacement, &regs, repl_mod);
1148 again = sub->global;
1149 }
1150 else
1151 {
1152 /* The match was not replaced. Copy the text until its
1153 end; if it was vacuous, skip over one character and
1154 add that character to the output. */
1155 if (matched == 0)
1156 {
1157 if (start < line.length)
1158 matched = 1;
1159 else
1160 break;
1161 }
1162
1163 str_append(&s_accum, line.active + offset, matched);
1164 }
1165
1166 /* Start after the match. last_end is the real end of the matched
1167 substring, excluding characters that were skipped in case the RE
1168 matched the empty string. */
1169 start = offset + matched;
1170 last_end = regs.end[0];
1171 }
1172 while (again
1173 && start <= line.length
1174 && match_regex(sub->regx, line.active, line.length, start,
1175 &regs, sub->max_id + 1));
1176
1177 /* Copy stuff to the right of the last match into the output string. */
1178 if (start < line.length)
1179 str_append(&s_accum, line.active + start, line.length-start);
1180 s_accum.chomped = line.chomped;
1181
1182 /* Exchange line and s_accum. This can be much cheaper
1183 than copying s_accum.active into line.text (for huge lines). */
1184 line_exchange(&line, &s_accum);
1185
1186 /* Finish up. */
1187 if (count < sub->numb)
1188 return;
1189
1190 post_subst:
1191 if (sub->print & 1)
1192 output_line(line.active, line.length, line.chomped, &output_file);
1193
1194 if (sub->eval)
1195 {
1196#ifdef HAVE_POPEN
1197 FILE *pipe;
1198 s_accum.length = 0;
1199
1200 str_append (&line, "", 1);
1201 pipe = popen(line.active, "r");
1202
1203 if (pipe != NULL)
1204 {
1205 while (!feof (pipe))
1206 {
1207 char buf[4096];
1208 int n = fread (buf, sizeof(char), 4096, pipe);
1209 if (n > 0)
1210 str_append(&s_accum, buf, n);
1211 }
1212
1213 pclose (pipe);
1214
1215 line_exchange(&line, &s_accum);
1216 if (line.length &&
1217 line.active[line.length - 1] == '\n')
1218 line.length--;
1219 }
1220 else
1221 panic(_("error in subprocess"));
1222#else
1223 panic(_("option `e' not supported"));
1224#endif
1225 }
1226
1227 if (sub->print & 2)
1228 output_line(line.active, line.length, line.chomped, &output_file);
1229 if (sub->outf)
1230 output_line(line.active, line.length, line.chomped, sub->outf);
1231}
1232
1233#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION
1234/* Used to attempt a simple-minded optimization. */
1235
1236static countT branches;
1237
1238static countT count_branches P_((struct vector *));
1239static countT
1240count_branches(program)
1241 struct vector *program;
1242{
1243 struct sed_cmd *cur_cmd = program->v;
1244 countT isn_cnt = program->v_length;
1245 countT cnt = 0;
1246
1247 while (isn_cnt-- > 0)
1248 {
1249 switch (cur_cmd->cmd)
1250 {
1251 case 'b':
1252 case 't':
1253 case 'T':
1254 case '{':
1255 ++cnt;
1256 }
1257 }
1258 return cnt;
1259}
1260
1261static struct sed_cmd *shrink_program P_((struct vector *, struct sed_cmd *));
1262static struct sed_cmd *
1263shrink_program(vec, cur_cmd)
1264 struct vector *vec;
1265 struct sed_cmd *cur_cmd;
1266{
1267 struct sed_cmd *v = vec->v;
1268 struct sed_cmd *last_cmd = v + vec->v_length;
1269 struct sed_cmd *p;
1270 countT cmd_cnt;
1271
1272 for (p=v; p < cur_cmd; ++p)
1273 if (p->cmd != '#')
1274 MEMCPY(v++, p, sizeof *v);
1275 cmd_cnt = v - vec->v;
1276
1277 for (; p < last_cmd; ++p)
1278 if (p->cmd != '#')
1279 MEMCPY(v++, p, sizeof *v);
1280 vec->v_length = v - vec->v;
1281
1282 return (0 < vec->v_length) ? (vec->v + cmd_cnt) : CAST(struct sed_cmd *)0;
1283}
1284#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/
1285
1286/* Execute the program `vec' on the current input line.
1287 Return exit status if caller should quit, -1 otherwise. */
1288static int execute_program P_((struct vector *, struct input *));
1289static int
1290execute_program(vec, input)
1291 struct vector *vec;
1292 struct input *input;
1293{
1294 struct sed_cmd *cur_cmd;
1295 struct sed_cmd *end_cmd;
1296
1297 cur_cmd = vec->v;
1298 end_cmd = vec->v + vec->v_length;
1299 while (cur_cmd < end_cmd)
1300 {
1301 if (match_address_p(cur_cmd, input) != cur_cmd->addr_bang)
1302 {
1303 switch (cur_cmd->cmd)
1304 {
1305 case 'a':
1306 {
1307 struct append_queue *aq = next_append_slot();
1308 aq->text = cur_cmd->x.cmd_txt.text;
1309 aq->textlen = cur_cmd->x.cmd_txt.text_length;
1310 }
1311 break;
1312
1313 case '{':
1314 case 'b':
1315 cur_cmd = vec->v + cur_cmd->x.jump_index;
1316 continue;
1317
1318 case '}':
1319 case '#':
1320 case ':':
1321 /* Executing labels and block-ends are easy. */
1322 break;
1323
1324 case 'c':
1325 if (cur_cmd->range_state != RANGE_ACTIVE)
1326 output_line(cur_cmd->x.cmd_txt.text,
1327 cur_cmd->x.cmd_txt.text_length - 1, true,
1328 &output_file);
1329 /* POSIX.2 is silent about c starting a new cycle,
1330 but it seems to be expected (and make sense). */
1331 /* Fall Through */
1332 case 'd':
1333 return -1;
1334
1335 case 'D':
1336 {
1337 char *p = memchr(line.active, '\n', line.length);
1338 if (!p)
1339 return -1;
1340
1341 ++p;
1342 line.alloc -= p - line.active;
1343 line.length -= p - line.active;
1344 line.active += p - line.active;
1345
1346 /* reset to start next cycle without reading a new line: */
1347 cur_cmd = vec->v;
1348 continue;
1349 }
1350
1351 case 'e': {
1352#ifdef HAVE_POPEN
1353 FILE *pipe;
1354 int cmd_length = cur_cmd->x.cmd_txt.text_length;
1355 if (s_accum.alloc == 0)
1356 line_init(&s_accum, INITIAL_BUFFER_SIZE);
1357 s_accum.length = 0;
1358
1359 if (!cmd_length)
1360 {
1361 str_append (&line, "", 1);
1362 pipe = popen(line.active, "r");
1363 }
1364 else
1365 {
1366 cur_cmd->x.cmd_txt.text[cmd_length - 1] = 0;
1367 pipe = popen(cur_cmd->x.cmd_txt.text, "r");
1368 output_missing_newline(&output_file);
1369 }
1370
1371 if (pipe != NULL)
1372 {
1373 while (!feof (pipe))
1374 {
1375 char buf[4096];
1376 int n = fread (buf, sizeof(char), 4096, pipe);
1377 if (n > 0)
1378 if (!cmd_length)
1379 str_append(&s_accum, buf, n);
1380 else
1381 ck_fwrite(buf, 1, n, output_file.fp);
1382 }
1383
1384 pclose (pipe);
1385 if (!cmd_length)
1386 {
1387 /* Store into pattern space for plain `e' commands */
1388 if (s_accum.length &&
1389 s_accum.active[s_accum.length - 1] == '\n')
1390 s_accum.length--;
1391
1392 /* Exchange line and s_accum. This can be much
1393 cheaper than copying s_accum.active into line.text
1394 (for huge lines). */
1395 line_exchange(&line, &s_accum);
1396 }
1397 else
1398 flush_output(output_file.fp);
1399
1400 }
1401 else
1402 panic(_("error in subprocess"));
1403#else
1404 panic(_("`e' command not supported"));
1405#endif
1406 break;
1407 }
1408
1409 case 'g':
1410 line_copy(&hold, &line);
1411 break;
1412
1413 case 'G':
1414 line_append(&hold, &line);
1415 break;
1416
1417 case 'h':
1418 line_copy(&line, &hold);
1419 break;
1420
1421 case 'H':
1422 line_append(&line, &hold);
1423 break;
1424
1425 case 'i':
1426 output_line(cur_cmd->x.cmd_txt.text,
1427 cur_cmd->x.cmd_txt.text_length - 1,
1428 true, &output_file);
1429 break;
1430
1431 case 'l':
1432 do_list(cur_cmd->x.int_arg == -1
1433 ? lcmd_out_line_len
1434 : cur_cmd->x.int_arg);
1435 break;
1436
1437 case 'L':
1438 output_missing_newline(&output_file);
1439 fmt(line.active, line.active + line.length,
1440 cur_cmd->x.int_arg == -1
1441 ? lcmd_out_line_len
1442 : cur_cmd->x.int_arg,
1443 output_file.fp);
1444 flush_output(output_file.fp);
1445 break;
1446
1447 case 'n':
1448 if (!no_default_output)
1449 output_line(line.active, line.length, line.chomped, &output_file);
1450 if (test_eof(input) || !read_pattern_space(input, vec, false))
1451 return -1;
1452 break;
1453
1454 case 'N':
1455 str_append(&line, "\n", 1);
1456
1457 if (test_eof(input) || !read_pattern_space(input, vec, true))
1458 {
1459 line.length--;
1460 if (posixicity == POSIXLY_EXTENDED && !no_default_output)
1461 output_line(line.active, line.length, line.chomped,
1462 &output_file);
1463 return -1;
1464 }
1465 break;
1466
1467 case 'p':
1468 output_line(line.active, line.length, line.chomped, &output_file);
1469 break;
1470
1471 case 'P':
1472 {
1473 char *p = memchr(line.active, '\n', line.length);
1474 output_line(line.active, p ? p - line.active : line.length,
1475 p ? true : line.chomped, &output_file);
1476 }
1477 break;
1478
1479 case 'q':
1480 if (!no_default_output)
1481 output_line(line.active, line.length, line.chomped, &output_file);
1482 dump_append_queue();
1483
1484 case 'Q':
1485 return cur_cmd->x.int_arg == -1 ? 0 : cur_cmd->x.int_arg;
1486
1487 case 'r':
1488 if (cur_cmd->x.fname)
1489 {
1490 struct append_queue *aq = next_append_slot();
1491 aq->fname = cur_cmd->x.fname;
1492 }
1493 break;
1494
1495 case 'R':
1496 if (cur_cmd->x.fp && !feof (cur_cmd->x.fp))
1497 {
1498 struct append_queue *aq;
1499 size_t buflen;
1500 char *text = NULL;
1501 int result;
1502
1503 result = ck_getline (&text, &buflen, cur_cmd->x.fp);
1504 if (result != EOF)
1505 {
1506 aq = next_append_slot();
1507 aq->free = true;
1508 aq->text = text;
1509 aq->textlen = result;
1510 }
1511 }
1512 break;
1513
1514 case 's':
1515 do_subst(cur_cmd->x.cmd_subst);
1516 break;
1517
1518 case 't':
1519 if (replaced)
1520 {
1521 replaced = false;
1522 cur_cmd = vec->v + cur_cmd->x.jump_index;
1523 continue;
1524 }
1525 break;
1526
1527 case 'T':
1528 if (!replaced)
1529 {
1530 cur_cmd = vec->v + cur_cmd->x.jump_index;
1531 continue;
1532 }
1533 else
1534 replaced = false;
1535 break;
1536
1537 case 'w':
1538 if (cur_cmd->x.fp)
1539 output_line(line.active, line.length,
1540 line.chomped, cur_cmd->x.outf);
1541 break;
1542
1543 case 'W':
1544 if (cur_cmd->x.fp)
1545 {
1546 char *p = memchr(line.active, '\n', line.length);
1547 output_line(line.active, p ? p - line.active : line.length,
1548 p ? true : line.chomped, cur_cmd->x.outf);
1549 }
1550 break;
1551
1552 case 'x':
1553 line_exchange(&line, &hold);
1554 break;
1555
1556 case 'y':
1557 {
1558#ifdef HAVE_MBRTOWC
1559 if (mb_cur_max > 1)
1560 {
1561 int idx, prev_idx; /* index in the input line. */
1562 char **trans;
1563 mbstate_t mbstate;
1564 memset(&mbstate, 0, sizeof(mbstate_t));
1565 for (idx = 0; idx < line.length;)
1566 {
1567 int mbclen, i;
1568 mbclen = MBRLEN (line.active + idx, line.length - idx,
1569 &mbstate);
1570 /* An invalid sequence, or a truncated multibyte
1571 character. We treat it as a singlebyte character.
1572 */
1573 if (mbclen == (size_t) -1 || mbclen == (size_t) -2
1574 || mbclen == 0)
1575 mbclen = 1;
1576
1577 trans = cur_cmd->x.translatemb;
1578 /* `i' indicate i-th translate pair. */
1579 for (i = 0; trans[2*i] != NULL; i++)
1580 {
1581 if (strncmp(line.active + idx, trans[2*i], mbclen) == 0)
1582 {
1583 bool move_remain_buffer = false;
1584 int trans_len = strlen(trans[2*i+1]);
1585
1586 if (mbclen < trans_len)
1587 {
1588 int new_len;
1589 new_len = line.length + 1 + trans_len - mbclen;
1590 /* We must extend the line buffer. */
1591 if (line.alloc < new_len)
1592 {
1593 /* And we must resize the buffer. */
1594 resize_line(&line, new_len);
1595 }
1596 move_remain_buffer = true;
1597 }
1598 else if (mbclen > trans_len)
1599 {
1600 /* We must truncate the line buffer. */
1601 move_remain_buffer = true;
1602 }
1603 prev_idx = idx;
1604 if (move_remain_buffer)
1605 {
1606 int move_len, move_offset;
1607 char *move_from, *move_to;
1608 /* Move the remaining with \0. */
1609 move_from = line.active + idx + mbclen;
1610 move_to = line.active + idx + trans_len;
1611 move_len = line.length + 1 - idx - mbclen;
1612 move_offset = trans_len - mbclen;
1613 memmove(move_to, move_from, move_len);
1614 line.length += move_offset;
1615 idx += move_offset;
1616 }
1617 strncpy(line.active + prev_idx, trans[2*i+1],
1618 trans_len);
1619 break;
1620 }
1621 }
1622 idx += mbclen;
1623 }
1624 }
1625 else
1626#endif /* HAVE_MBRTOWC */
1627 {
1628 unsigned char *p, *e;
1629 p = CAST(unsigned char *)line.active;
1630 for (e=p+line.length; p<e; ++p)
1631 *p = cur_cmd->x.translate[*p];
1632 }
1633 }
1634 break;
1635
1636 case '=':
1637 output_missing_newline(&output_file);
1638 fprintf(output_file.fp, "%lu\n",
1639 CAST(unsigned long)input->line_number);
1640 flush_output(output_file.fp);
1641 break;
1642
1643 default:
1644 panic("INTERNAL ERROR: Bad cmd %c", cur_cmd->cmd);
1645 }
1646 }
1647
1648#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION
1649 /* If our top-level program consists solely of commands with
1650 ADDR_IS_NUM addresses then once we past the last mentioned
1651 line we should be able to quit if no_default_output is true,
1652 or otherwise quickly copy input to output. Now whether this
1653 optimization is a win or not depends on how cheaply we can
1654 implement this for the cases where it doesn't help, as
1655 compared against how much time is saved. One semantic
1656 difference (which I think is an improvement) is that *this*
1657 version will terminate after printing line two in the script
1658 "yes | sed -n 2p".
1659
1660 Don't use this when in-place editing is active, because line
1661 numbers restart each time then. */
1662 else if (!separate_files)
1663 {
1664 if (cur_cmd->a1->addr_type == ADDR_IS_NUM
1665 && (cur_cmd->a2
1666 ? cur_cmd->range_state == RANGE_CLOSED
1667 : cur_cmd->a1->addr_number < input->line_number))
1668 {
1669 /* Skip this address next time */
1670 cur_cmd->addr_bang = !cur_cmd->addr_bang;
1671 cur_cmd->a1->addr_type = ADDR_IS_NULL;
1672 if (cur_cmd->a2)
1673 cur_cmd->a2->addr_type = ADDR_IS_NULL;
1674
1675 /* can we make an optimization? */
1676 if (cur_cmd->addr_bang)
1677 {
1678 if (cur_cmd->cmd == 'b' || cur_cmd->cmd == 't'
1679 || cur_cmd->cmd == 'T' || cur_cmd->cmd == '}')
1680 branches--;
1681
1682 cur_cmd->cmd = '#'; /* replace with no-op */
1683 if (branches == 0)
1684 cur_cmd = shrink_program(vec, cur_cmd);
1685 if (!cur_cmd && no_default_output)
1686 return 0;
1687 end_cmd = vec->v + vec->v_length;
1688 if (!cur_cmd)
1689 cur_cmd = end_cmd;
1690 continue;
1691 }
1692 }
1693 }
1694#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/
1695
1696 /* this is buried down here so that a "continue" statement can skip it */
1697 ++cur_cmd;
1698 }
1699
1700 if (!no_default_output)
1701 output_line(line.active, line.length, line.chomped, &output_file);
1702 return -1;
1703}
1704
1705
1706
1707
1708/* Apply the compiled script to all the named files. */
1709int
1710process_files(the_program, argv)
1711 struct vector *the_program;
1712 char **argv;
1713{
1714 static char dash[] = "-";
1715 static char *stdin_argv[2] = { dash, NULL };
1716 struct input input;
1717 int status;
1718
1719 line_init(&line, INITIAL_BUFFER_SIZE);
1720 line_init(&hold, 0);
1721 line_init(&buffer, 0);
1722
1723#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION
1724 branches = count_branches(the_program);
1725#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/
1726 input.reset_at_next_file = true;
1727 if (argv && *argv)
1728 input.file_list = argv;
1729 else if (in_place_extension)
1730 panic(_("no input files"));
1731 else
1732 input.file_list = stdin_argv;
1733
1734 input.bad_count = 0;
1735 input.line_number = 0;
1736 input.read_fn = read_always_fail;
1737 input.fp = NULL;
1738
1739 status = EXIT_SUCCESS;
1740 while (read_pattern_space(&input, the_program, false))
1741 {
1742 status = execute_program(the_program, &input);
1743 if (status == -1)
1744 status = EXIT_SUCCESS;
1745 else
1746 break;
1747 }
1748 closedown(&input);
1749
1750#ifdef DEBUG_LEAKS
1751 /* We're about to exit, so these free()s are redundant.
1752 But if we're running under a memory-leak detecting
1753 implementation of malloc(), we want to explicitly
1754 deallocate in order to avoid extraneous noise from
1755 the allocator. */
1756 release_append_queue();
1757 FREE(buffer.text);
1758 FREE(hold.text);
1759 FREE(line.text);
1760 FREE(s_accum.text);
1761#endif /*DEBUG_LEAKS*/
1762
1763 if (input.bad_count)
1764 status = 2;
1765
1766 return status;
1767}
Note: See TracBrowser for help on using the repository browser.