summaryrefslogtreecommitdiff
path: root/sed/execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'sed/execute.c')
-rw-r--r--sed/execute.c1464
1 files changed, 707 insertions, 757 deletions
diff --git a/sed/execute.c b/sed/execute.c
index cb84192..009d188 100644
--- a/sed/execute.c
+++ b/sed/execute.c
@@ -1,6 +1,5 @@
/* GNU SED, a batch stream editor.
- Copyright (C) 1989,90,91,92,93,94,95,98,99,2002,2003,2004,2005,2006,2008,2009
- Free Software Foundation, Inc.
+ Copyright (C) 1989-2016 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,6 +35,7 @@
#include <selinux/selinux.h>
#include <selinux/context.h>
#include "acl.h"
+#include "ignore-value.h"
#ifdef __GNUC__
# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7)
@@ -47,7 +47,11 @@
# define UNUSED
#endif
-
+/* The number of extra bytes that must be allocated/usable, beyond
+ the declared "end" of each line buffer that may be passed to
+ match_regex. This is imposed by its use of dfaexec. */
+#define DFA_SLOP 1
+
/* Sed operates a line at a time. */
struct line {
char *text; /* Pointer to line allocated by malloc. */
@@ -79,10 +83,10 @@ struct input {
char **file_list;
/* Count of files we failed to open. */
- countT bad_count;
+ countT bad_count;
/* Current input line number (over all files). */
- countT line_number;
+ countT line_number;
/* True if we'll reset line numbers and addresses before
starting to process the next (possibly the first) file. */
@@ -132,11 +136,8 @@ static struct append_queue *append_tail = NULL;
/* increase a struct line's length, making some attempt at
keeping realloc() calls under control by padding for future growth. */
-static void resize_line (struct line *, size_t);
static void
-resize_line(lb, len)
- struct line *lb;
- size_t len;
+resize_line (struct line *lb, size_t len)
{
int inactive;
inactive = lb->active - lb->text;
@@ -151,7 +152,7 @@ resize_line(lb, len)
inactive = 0;
if (lb->alloc > len)
- return;
+ return;
}
lb->alloc *= 2;
@@ -159,18 +160,14 @@ resize_line(lb, len)
lb->alloc = len;
if (lb->alloc < INITIAL_BUFFER_SIZE)
lb->alloc = INITIAL_BUFFER_SIZE;
-
- lb->text = REALLOC(lb->text, inactive + lb->alloc, char);
+
+ lb->text = REALLOC(lb->text, inactive + lb->alloc + DFA_SLOP, char);
lb->active = lb->text + inactive;
}
-/* Append `length' bytes from `string' to the line `to'. */
-static void str_append (struct line *, const char *, size_t);
+/* Append LENGTH bytes from STRING to the line, TO. */
static void
-str_append(to, string, length)
- struct line *to;
- const char *string;
- size_t length;
+str_append(struct line *to, const char *string, size_t length)
{
size_t new_length = to->length + length;
@@ -184,26 +181,25 @@ str_append(to, string, length)
{
size_t n = MBRLEN (string, length, &to->mbstate);
- /* An invalid or imcomplete sequence is treated like a singlebyte character. */
+ /* Treat an invalid or incomplete sequence like a
+ single-byte character. */
if (n == (size_t) -1 || n == (size_t) -2)
- {
- memset (&to->mbstate, 0, sizeof (to->mbstate));
- n = 1;
- }
-
- if (n > 0)
- {
- string += n;
- length -= n;
- }
- else
- break;
+ {
+ memset (&to->mbstate, 0, sizeof (to->mbstate));
+ n = 1;
+ }
+
+ if (n == 0)
+ break;
+
+ string += n;
+ length -= n;
}
}
static void
str_append_modified(struct line *to, const char *string, size_t length,
- enum replacement_types type)
+ enum replacement_types type)
{
mbstate_t from_stat;
@@ -220,42 +216,58 @@ str_append_modified(struct line *to, const char *string, size_t length,
while (length)
{
wchar_t wc;
- int n = MBRTOWC (&wc, string, length, &from_stat);
+ size_t n = MBRTOWC (&wc, string, length, &from_stat);
- /* An invalid sequence is treated like a singlebyte character. */
- if (n == -1)
+ /* Treat an invalid sequence like a single-byte character. */
+ if (n == (size_t) -1)
{
+ type &= ~(REPL_LOWERCASE_FIRST | REPL_UPPERCASE_FIRST);
+ if (type == REPL_ASIS)
+ {
+ str_append(to, string, length);
+ return;
+ }
+
+ str_append (to, string, 1);
memset (&to->mbstate, 0, sizeof (from_stat));
n = 1;
+ string += n, length -= n;
+ continue;
}
- if (n > 0)
- string += n, length -= n;
- else
- {
- /* Incomplete sequence, copy it manually. */
- str_append(to, string, length);
- return;
- }
+ if (n == 0 || n == (size_t) -2)
+ {
+ /* L'\0' or an incomplete sequence: copy it manually. */
+ str_append(to, string, length);
+ return;
+ }
+
+ string += n, length -= n;
/* Convert the first character specially... */
if (type & (REPL_UPPERCASE_FIRST | REPL_LOWERCASE_FIRST))
- {
+ {
if (type & REPL_UPPERCASE_FIRST)
wc = towupper(wc);
else
wc = towlower(wc);
type &= ~(REPL_LOWERCASE_FIRST | REPL_UPPERCASE_FIRST);
- if (type == REPL_ASIS)
- {
- n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
- to->length += n;
- str_append(to, string, length);
- return;
- }
+ if (type == REPL_ASIS)
+ {
+ /* Copy the new wide character to the end of the string. */
+ n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
+ to->length += n;
+ if (n == (size_t) -1 || n == (size_t) -2)
+ {
+ fprintf (stderr,
+ _("case conversion produced an invalid character"));
+ abort ();
+ }
+ str_append(to, string, length);
+ return;
+ }
}
-
else if (type & REPL_UPPERCASE)
wc = towupper(wc);
else
@@ -265,23 +277,19 @@ str_append_modified(struct line *to, const char *string, size_t length,
n = WCRTOMB (to->active + to->length, wc, &to->mbstate);
to->length += n;
if (n == -1 || n == -2)
- {
- fprintf (stderr, "Case conversion produced an invalid character!");
- abort ();
- }
+ {
+ fprintf (stderr, _("case conversion produced an invalid character"));
+ abort ();
+ }
}
}
/* Initialize a "struct line" buffer. Copy multibyte state from `state'
if not null. */
-static void line_init (struct line *, struct line *, size_t initial_size);
static void
-line_init(buf, state, initial_size)
- struct line *buf;
- struct line *state;
- size_t initial_size;
+line_init(struct line *buf, struct line *state, size_t initial_size)
{
- buf->text = MALLOC(initial_size, char);
+ buf->text = MALLOC(initial_size + DFA_SLOP, char);
buf->active = buf->text;
buf->alloc = initial_size;
buf->length = 0;
@@ -295,10 +303,8 @@ line_init(buf, state, initial_size)
/* Reset a "struct line" buffer to length zero. Copy multibyte state from
`state' if not null. */
-static void line_reset (struct line *, struct line *);
static void
-line_reset(buf, state)
- struct line *buf, *state;
+line_reset(struct line *buf, struct line *state)
{
if (buf->alloc == 0)
line_init(buf, state, INITIAL_BUFFER_SIZE);
@@ -315,12 +321,8 @@ line_reset(buf, state)
/* Copy the contents of the line `from' into the line `to'.
This destroys the old contents of `to'.
Copy the multibyte state if `state' is true. */
-static void line_copy (struct line *from, struct line *to, int state);
static void
-line_copy(from, to, state)
- struct line *from;
- struct line *to;
- int state;
+line_copy(struct line *from, struct line *to, int state)
{
/* Remove the inactive portion in the destination buffer. */
to->alloc += to->active - to->text;
@@ -329,13 +331,13 @@ line_copy(from, to, state)
{
to->alloc *= 2;
if (to->alloc < from->length)
- to->alloc = from->length;
+ to->alloc = from->length;
if (to->alloc < INITIAL_BUFFER_SIZE)
- to->alloc = INITIAL_BUFFER_SIZE;
+ to->alloc = INITIAL_BUFFER_SIZE;
/* Use free()+MALLOC() instead of REALLOC() to
- avoid unnecessary copying of old text. */
+ avoid unnecessary copying of old text. */
free(to->text);
- to->text = MALLOC(to->alloc, char);
+ to->text = MALLOC(to->alloc + DFA_SLOP, char);
}
to->active = to->text;
@@ -349,12 +351,8 @@ line_copy(from, to, state)
/* Append the contents of the line `from' to the line `to'.
Copy the multibyte state if `state' is true. */
-static void line_append (struct line *from, struct line *to, int state);
static void
-line_append(from, to, state)
- struct line *from;
- struct line *to;
- int state;
+line_append (struct line *from, struct line *to, int state)
{
str_append(to, &buffer_delimiter, 1);
str_append(to, from->active, from->length);
@@ -366,12 +364,8 @@ line_append(from, to, state)
/* Exchange two "struct line" buffers.
Copy the multibyte state if `state' is true. */
-static void line_exchange (struct line *a, struct line *b, int state);
static void
-line_exchange(a, b, state)
- struct line *a;
- struct line *b;
- int state;
+line_exchange (struct line *a, struct line *b, int state)
{
struct line t;
@@ -391,18 +385,14 @@ line_exchange(a, b, state)
/* dummy function to simplify read_pattern_space() */
-static bool read_always_fail (struct input *);
static bool
-read_always_fail(input)
- struct input *input UNUSED;
+read_always_fail(struct input *input UNUSED)
{
return false;
}
-static bool read_file_line (struct input *);
static bool
-read_file_line(input)
- struct input *input;
+read_file_line(struct input *input)
{
static char *b;
static size_t blen;
@@ -422,10 +412,8 @@ read_file_line(input)
}
-static inline void output_missing_newline (struct output *);
static inline void
-output_missing_newline(outf)
- struct output *outf;
+output_missing_newline(struct output *outf)
{
if (outf->missing_newline)
{
@@ -434,22 +422,15 @@ output_missing_newline(outf)
}
}
-static inline void flush_output (FILE *);
static inline void
-flush_output(fp)
- FILE *fp;
+flush_output(FILE *fp)
{
if (fp != stdout || unbuffered)
ck_fflush(fp);
}
-static void output_line (const char *, size_t, int, struct output *);
static void
-output_line(text, length, nl, outf)
- const char *text;
- size_t length;
- int nl;
- struct output *outf;
+output_line(const char *text, size_t length, int nl, struct output *outf)
{
if (!text)
return;
@@ -465,9 +446,8 @@ output_line(text, length, nl, outf)
flush_output(outf->fp);
}
-static struct append_queue *next_append_slot (void);
static struct append_queue *
-next_append_slot()
+next_append_slot(void)
{
struct append_queue *n = MALLOC(1, struct append_queue);
@@ -484,9 +464,8 @@ next_append_slot()
return append_tail = n;
}
-static void release_append_queue (void);
static void
-release_append_queue()
+release_append_queue(void)
{
struct append_queue *p, *q;
@@ -501,9 +480,8 @@ release_append_queue()
append_head = append_tail = NULL;
}
-static void dump_append_queue (void);
static void
-dump_append_queue()
+dump_append_queue(void)
{
struct append_queue *p;
@@ -514,23 +492,23 @@ dump_append_queue()
ck_fwrite(p->text, 1, p->textlen, output_file.fp);
if (p->fname)
- {
- char buf[FREAD_BUFFER_SIZE];
- size_t cnt;
- FILE *fp;
-
- /* "If _fname_ does not exist or cannot be read, it shall
- be treated as if it were an empty file, causing no error
- condition." IEEE Std 1003.2-1992
- So, don't fail. */
- fp = ck_fopen(p->fname, read_mode, false);
- if (fp)
- {
- while ((cnt = ck_fread(buf, 1, sizeof buf, fp)) > 0)
- ck_fwrite(buf, 1, cnt, output_file.fp);
- ck_fclose(fp);
- }
- }
+ {
+ char buf[FREAD_BUFFER_SIZE];
+ size_t cnt;
+ FILE *fp;
+
+ /* "If _fname_ does not exist or cannot be read, it shall
+ be treated as if it were an empty file, causing no error
+ condition." IEEE Std 1003.2-1992
+ So, don't fail. */
+ fp = ck_fopen(p->fname, read_mode, false);
+ if (fp)
+ {
+ while ((cnt = ck_fread(buf, 1, sizeof buf, fp)) > 0)
+ ck_fwrite(buf, 1, cnt, output_file.fp);
+ ck_fclose(fp);
+ }
+ }
}
flush_output(output_file.fp);
@@ -539,10 +517,8 @@ dump_append_queue()
/* Compute the name of the backup file for in-place editing */
-static char *get_backup_file_name (const char *);
static char *
-get_backup_file_name(name)
- const char *name;
+get_backup_file_name(const char *name)
{
char *old_asterisk, *asterisk, *backup, *p;
int name_length = strlen(name), backup_length = strlen(in_place_extension);
@@ -572,39 +548,39 @@ get_backup_file_name(name)
}
/* Initialize a struct input for the named file. */
-static void open_next_file (const char *name, struct input *);
static void
-open_next_file(name, input)
- const char *name;
- struct input *input;
+open_next_file(const char *name, struct input *input)
{
buffer.length = 0;
+ input->in_file_name = name;
if (name[0] == '-' && name[1] == '\0' && !in_place_extension)
{
clearerr(stdin); /* clear any stale EOF indication */
-#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) || defined(__EMX__)
+#if defined WIN32 || defined _WIN32 || defined __CYGWIN__ \
+ || defined MSDOS || defined __EMX__
input->fp = ck_fdopen (fileno (stdin), "stdin", read_mode, false);
#else
input->fp = stdin;
#endif
}
- else if ( ! (input->fp = ck_fopen(name, read_mode, false)) )
+ else
{
- const char *ptr = strerror(errno);
- fprintf(stderr, _("%s: can't read %s: %s\n"), myname, name, ptr);
- input->read_fn = read_always_fail; /* a redundancy */
- ++input->bad_count;
- return;
+ if (follow_symlinks)
+ input->in_file_name = follow_symlink (name);
+
+ if ( ! (input->fp = ck_fopen (name, read_mode, false)) )
+ {
+ const char *ptr = strerror (errno);
+ fprintf (stderr, _("%s: can't read %s: %s\n"), myname, name, ptr);
+ input->read_fn = read_always_fail; /* a redundancy */
+ ++input->bad_count;
+ return;
+ }
}
input->read_fn = read_file_line;
- if (follow_symlinks)
- input->in_file_name = follow_symlink (name);
- else
- input->in_file_name = name;
-
if (in_place_extension)
{
int input_fd;
@@ -616,9 +592,9 @@ open_next_file(name, input)
/* get the base name */
tmpdir = ck_strdup(input->in_file_name);
if ((p = strrchr(tmpdir, '/')))
- *p = 0;
+ *p = 0;
else
- strcpy(tmpdir, ".");
+ strcpy(tmpdir, ".");
if (isatty (fileno (input->fp)))
panic(_("couldn't edit %s: is a terminal"), input->in_file_name);
@@ -629,39 +605,43 @@ open_next_file(name, input)
panic(_("couldn't edit %s: not a regular file"), input->in_file_name);
if (is_selinux_enabled () > 0)
- {
+ {
security_context_t con;
- if (getfilecon (input->in_file_name, &con) != -1)
- {
- /* Save and restore the old context for the sake of w and W
- commands. */
- reset_fscreatecon = getfscreatecon (&old_fscreatecon) >= 0;
- if (setfscreatecon (con) < 0)
- fprintf (stderr, _("%s: warning: failed to set default file creation context to %s: %s"),
- myname, con, strerror (errno));
- freecon (con);
- }
- else
- {
- if (errno != ENOSYS)
- fprintf (stderr, _("%s: warning: failed to get security context of %s: %s"),
- myname, input->in_file_name, strerror (errno));
- }
- }
+ if (getfilecon (input->in_file_name, &con) != -1)
+ {
+ /* Save and restore the old context for the sake of w and W
+ commands. */
+ reset_fscreatecon = getfscreatecon (&old_fscreatecon) >= 0;
+ if (setfscreatecon (con) < 0)
+ fprintf (stderr, _("%s: warning: failed to set default" \
+ " file creation context to %s: %s"),
+ myname, con, strerror (errno));
+ freecon (con);
+ }
+ else
+ {
+ if (errno != ENOSYS)
+ fprintf (stderr, _("%s: warning: failed to get" \
+ " security context of %s: %s"),
+ myname, input->in_file_name, strerror (errno));
+ }
+ }
output_file.fp = ck_mkstemp (&input->out_file_name, tmpdir, "sed",
- write_mode);
+ write_mode);
+ register_cleanup_file (input->out_file_name);
output_file.missing_newline = false;
free (tmpdir);
if (reset_fscreatecon)
- {
- setfscreatecon (old_fscreatecon);
- freecon (old_fscreatecon);
- }
+ {
+ setfscreatecon (old_fscreatecon);
+ freecon (old_fscreatecon);
+ }
if (!output_file.fp)
- panic(_("couldn't open temporary file %s: %s"), input->out_file_name, strerror(errno));
+ panic(_("couldn't open temporary file %s: %s"), input->out_file_name,
+ strerror(errno));
}
else
{
@@ -673,10 +653,8 @@ open_next_file(name, input)
/* Clean up an input stream that we are done with. */
-static void closedown (struct input *);
static void
-closedown(input)
- struct input *input;
+closedown(struct input *input)
{
input->read_fn = read_always_fail;
if (!input->fp)
@@ -691,23 +669,26 @@ closedown(input)
input_fd = fileno (input->fp);
output_fd = fileno (output_file.fp);
#ifdef HAVE_FCHOWN
+ /* Try to set both UID and GID, but if that fails,
+ try to set only the GID. Ignore failure. */
if (fchown (output_fd, input->st.st_uid, input->st.st_gid) == -1)
- fchown (output_fd, -1, input->st.st_gid);
+ ignore_value (fchown (output_fd, -1, input->st.st_gid));
#endif
copy_acl (input->in_file_name, input_fd,
- input->out_file_name, output_fd,
- input->st.st_mode);
+ input->out_file_name, output_fd,
+ input->st.st_mode);
ck_fclose (input->fp);
ck_fclose (output_file.fp);
if (strcmp(in_place_extension, "*") != 0)
{
char *backup_file_name = get_backup_file_name(target_name);
- ck_rename (target_name, backup_file_name, input->out_file_name);
+ ck_rename (target_name, backup_file_name, input->out_file_name);
free (backup_file_name);
- }
+ }
ck_rename (input->out_file_name, target_name, input->out_file_name);
+ cancel_cleanup ();
free (input->out_file_name);
}
else
@@ -717,18 +698,16 @@ closedown(input)
}
/* Reset range commands so that they are marked as non-matching */
-static void reset_addresses (struct vector *);
static void
-reset_addresses(vec)
- struct vector *vec;
+reset_addresses(struct vector *vec)
{
struct sed_cmd *cur_cmd;
int n;
for (cur_cmd = vec->v, n = vec->v_length; n--; cur_cmd++)
if (cur_cmd->a1
- && cur_cmd->a1->addr_type == ADDR_IS_NUM
- && cur_cmd->a1->addr_number == 0)
+ && cur_cmd->a1->addr_type == ADDR_IS_NUM
+ && cur_cmd->a1->addr_number == 0)
cur_cmd->range_state = RANGE_ACTIVE;
else
cur_cmd->range_state = RANGE_INACTIVE;
@@ -736,12 +715,8 @@ reset_addresses(vec)
/* Read in the next line of input, and store it in the pattern space.
Return zero if there is nothing left to input. */
-static bool read_pattern_space (struct input *, struct vector *, int);
static bool
-read_pattern_space(input, the_program, append)
- struct input *input;
- struct vector *the_program;
- int append;
+read_pattern_space(struct input *input, struct vector *the_program, int append)
{
if (append_head) /* redundant test to optimize for common case */
dump_append_queue();
@@ -755,23 +730,23 @@ read_pattern_space(input, the_program, append)
closedown(input);
if (!*input->file_list)
- return false;
+ return false;
if (input->reset_at_next_file)
- {
- input->line_number = 0;
- hold.length = 0;
- reset_addresses (the_program);
- rewind_read_files ();
-
- /* If doing in-place editing, we will never append the
- new-line to this file; but if the output goes to stdout,
- we might still have to output the missing new-line. */
- if (in_place_extension)
- output_file.missing_newline = false;
-
- input->reset_at_next_file = separate_files;
- }
+ {
+ input->line_number = 0;
+ hold.length = 0;
+ reset_addresses (the_program);
+ rewind_read_files ();
+
+ /* If doing in-place editing, we will never append the
+ new-line to this file; but if the output goes to stdout,
+ we might still have to output the missing new-line. */
+ if (in_place_extension)
+ output_file.missing_newline = false;
+
+ input->reset_at_next_file = separate_files;
+ }
open_next_file (*input->file_list++, input);
}
@@ -781,10 +756,8 @@ read_pattern_space(input, the_program, append)
}
-static bool last_file_with_data_p (struct input *);
static bool
-last_file_with_data_p(input)
- struct input *input;
+last_file_with_data_p(struct input *input)
{
for (;;)
{
@@ -792,24 +765,22 @@ last_file_with_data_p(input)
closedown(input);
if (!*input->file_list)
- return true;
+ return true;
open_next_file(*input->file_list++, input);
if (input->fp)
- {
- if ((ch = getc(input->fp)) != EOF)
- {
- ungetc(ch, input->fp);
- return false;
- }
- }
+ {
+ if ((ch = getc(input->fp)) != EOF)
+ {
+ ungetc(ch, input->fp);
+ return false;
+ }
+ }
}
}
/* Determine if we match the `$' address. */
-static bool test_eof (struct input *);
static bool
-test_eof(input)
- struct input *input;
+test_eof(struct input *input)
{
int ch;
@@ -827,11 +798,8 @@ test_eof(input)
/* Return non-zero if the current line matches the address
pointed to by `addr'. */
-static bool match_an_address_p (struct addr *, struct input *);
static bool
-match_an_address_p(addr, input)
- struct addr *addr;
- struct input *input;
+match_an_address_p(struct addr *addr, struct input *input)
{
switch (addr->addr_type)
{
@@ -839,11 +807,13 @@ match_an_address_p(addr, input)
return true;
case ADDR_IS_REGEX:
- return match_regex(addr->addr_regex, line.active, line.length, 0, NULL, 0);
+ return match_regex(addr->addr_regex, line.active, line.length, 0,
+ NULL, 0);
case ADDR_IS_NUM_MOD:
return (input->line_number >= addr->addr_number
- && ((input->line_number - addr->addr_number) % addr->addr_step) == 0);
+ && ((input->line_number - addr->addr_number)
+ % addr->addr_step) == 0);
case ADDR_IS_STEP:
case ADDR_IS_STEP_MOD:
@@ -855,8 +825,10 @@ match_an_address_p(addr, input)
case ADDR_IS_LAST:
return test_eof(input);
- /* ADDR_IS_NUM is handled in match_address_p. */
case ADDR_IS_NUM:
+ /* reminder: these are only meaningful for a1 addresses */
+ return (addr->addr_number == input->line_number);
+
default:
panic("INTERNAL ERROR: bad address type");
}
@@ -865,59 +837,54 @@ match_an_address_p(addr, input)
}
/* return non-zero if current address is valid for cmd */
-static bool match_address_p (struct sed_cmd *, struct input *);
static bool
-match_address_p(cmd, input)
- struct sed_cmd *cmd;
- struct input *input;
+match_address_p(struct sed_cmd *cmd, struct input *input)
{
if (!cmd->a1)
return true;
if (cmd->range_state != RANGE_ACTIVE)
{
+ if (!cmd->a2)
+ return match_an_address_p(cmd->a1, input);
+
/* Find if we are going to activate a range. Handle ADDR_IS_NUM
- specially: it represent an "absolute" state, it should not
- be computed like regexes. */
+ specially: it represent an "absolute" state, it should not
+ be computed like regexes. */
if (cmd->a1->addr_type == ADDR_IS_NUM)
- {
- if (!cmd->a2)
- return (input->line_number == cmd->a1->addr_number);
-
- if (cmd->range_state == RANGE_CLOSED
- || input->line_number < cmd->a1->addr_number)
- return false;
- }
+ {
+ if (cmd->range_state == RANGE_CLOSED
+ || input->line_number < cmd->a1->addr_number)
+ return false;
+ }
else
- {
- if (!cmd->a2)
- return match_an_address_p(cmd->a1, input);
-
- if (!match_an_address_p(cmd->a1, input))
+ {
+ if (!match_an_address_p(cmd->a1, input))
return false;
- }
+ }
/* Ok, start a new range. */
cmd->range_state = RANGE_ACTIVE;
switch (cmd->a2->addr_type)
- {
- case ADDR_IS_REGEX:
- /* Always include at least two lines. */
- return true;
- case ADDR_IS_NUM:
- /* Same handling as below, but always include at least one line. */
+ {
+ case ADDR_IS_REGEX:
+ /* Always include at least two lines. */
+ return true;
+ case ADDR_IS_NUM:
+ /* Same handling as below, but always include at least one line. */
if (input->line_number >= cmd->a2->addr_number)
- cmd->range_state = RANGE_CLOSED;
+ cmd->range_state = RANGE_CLOSED;
+ return (input->line_number <= cmd->a2->addr_number
+ || match_an_address_p(cmd->a1, input));
+ case ADDR_IS_STEP:
+ cmd->a2->addr_number = input->line_number + cmd->a2->addr_step;
+ return true;
+ case ADDR_IS_STEP_MOD:
+ cmd->a2->addr_number = input->line_number + cmd->a2->addr_step
+ - (input->line_number%cmd->a2->addr_step);
return true;
- case ADDR_IS_STEP:
- cmd->a2->addr_number = input->line_number + cmd->a2->addr_step;
- return true;
- case ADDR_IS_STEP_MOD:
- cmd->a2->addr_number = input->line_number + cmd->a2->addr_step
- - (input->line_number%cmd->a2->addr_step);
- return true;
- default:
- break;
+ default:
+ break;
}
}
@@ -928,10 +895,10 @@ match_address_p(cmd, input)
{
/* If the second address is a line number, and if we got past
that line, fail to match (it can happen when you jump
- over such addresses with `b' and `t'. Use RANGE_CLOSED
+ over such addresses with `b' and `t'. Use RANGE_CLOSED
so that the range is not re-enabled anymore. */
if (input->line_number >= cmd->a2->addr_number)
- cmd->range_state = RANGE_CLOSED;
+ cmd->range_state = RANGE_CLOSED;
return (input->line_number <= cmd->a2->addr_number);
}
@@ -944,10 +911,8 @@ match_address_p(cmd, input)
}
-static void do_list (int line_len);
static void
-do_list(line_len)
- int line_len;
+do_list(int line_len)
{
unsigned char *p = (unsigned char *)line.active;
countT len = line.length;
@@ -960,53 +925,55 @@ do_list(line_len)
output_missing_newline(&output_file);
for (; len--; ++p) {
o = obuf;
-
+
/* Some locales define 8-bit characters as printable. This makes the
- testsuite fail at 8to7.sed because the `l' command in fact will not
- convert the 8-bit characters. */
+ testsuite fail at 8to7.sed because the `l' command in fact will not
+ convert the 8-bit characters. */
#if defined isascii || defined HAVE_ISASCII
if (isascii(*p) && ISPRINT(*p)) {
#else
if (ISPRINT(*p)) {
#endif
- *o++ = *p;
- if (*p == '\\')
- *o++ = '\\';
+ *o++ = *p;
+ if (*p == '\\')
+ *o++ = '\\';
} else {
- *o++ = '\\';
- switch (*p) {
+ *o++ = '\\';
+ switch (*p) {
#if defined __STDC__ && __STDC__-0
- case '\a': *o++ = 'a'; break;
+ case '\a': *o++ = 'a'; break;
#else /* Not STDC; we'll just assume ASCII */
- case 007: *o++ = 'a'; break;
+ case 007: *o++ = 'a'; break;
#endif
- case '\b': *o++ = 'b'; break;
- case '\f': *o++ = 'f'; break;
- case '\n': *o++ = 'n'; break;
- case '\r': *o++ = 'r'; break;
- case '\t': *o++ = 't'; break;
- case '\v': *o++ = 'v'; break;
- default:
- sprintf(o, "%03o", *p);
- o += strlen(o);
- break;
- }
+ case '\b': *o++ = 'b'; break;
+ case '\f': *o++ = 'f'; break;
+ case '\n': *o++ = 'n'; break;
+ case '\r': *o++ = 'r'; break;
+ case '\t': *o++ = 't'; break;
+ case '\v': *o++ = 'v'; break;
+ default:
+ sprintf(o, "%03o", *p);
+ o += strlen(o);
+ break;
+ }
}
olen = o - obuf;
if (width+olen >= line_len && line_len > 0) {
- ck_fwrite("\\\n", 1, 2, fp);
- width = 0;
+ ck_fwrite("\\", 1, 1, fp);
+ ck_fwrite(&buffer_delimiter, 1, 1, fp);
+ width = 0;
}
ck_fwrite(obuf, 1, olen, fp);
width += olen;
}
- ck_fwrite("$\n", 1, 2, fp);
+ ck_fwrite("$", 1, 1, fp);
+ ck_fwrite(&buffer_delimiter, 1, 1, fp);
flush_output (fp);
}
static void append_replacement (struct line *buf, struct replacement *p,
- struct re_registers *regs)
+ struct re_registers *regs)
{
enum replacement_types repl_mod = 0;
@@ -1026,30 +993,28 @@ static void append_replacement (struct line *buf, struct replacement *p,
if (p->prefix_length)
{
str_append_modified(buf, p->prefix, p->prefix_length,
- curr_type);
+ curr_type);
curr_type &= ~REPL_MODIFIERS;
}
if (0 <= i)
- {
+ {
if (regs->end[i] == regs->start[i] && p->repl_type & REPL_MODIFIERS)
/* Save this modifier, we shall apply it later.
- e.g. in s/()([a-z])/\u\1\2/
- the \u modifier is applied to \2, not \1 */
- repl_mod = curr_type & REPL_MODIFIERS;
-
- else if (regs->end[i] != regs->start[i])
- str_append_modified(buf, line.active + regs->start[i],
- (size_t)(regs->end[i] - regs->start[i]),
- curr_type);
- }
+ e.g. in s/()([a-z])/\u\1\2/
+ the \u modifier is applied to \2, not \1 */
+ repl_mod = curr_type & REPL_MODIFIERS;
+
+ else if (regs->end[i] != regs->start[i])
+ str_append_modified(buf, line.active + regs->start[i],
+ (size_t)(regs->end[i] - regs->start[i]),
+ curr_type);
+ }
}
}
-static void do_subst (struct subst *);
static void
-do_subst(sub)
- struct subst *sub;
+do_subst(struct subst *sub)
{
size_t start = 0; /* where to start scan for (next) match in LINE */
size_t last_end = 0; /* where did the last successful match end in LINE */
@@ -1063,28 +1028,28 @@ do_subst(sub)
/* The first part of the loop optimizes s/xxx// when xxx is at the
start, and s/xxx$// */
if (!match_regex(sub->regx, line.active, line.length, start,
- &regs, sub->max_id + 1))
+ &regs, sub->max_id + 1))
return;
-
+
if (!sub->replacement && sub->numb <= 1)
{
if (regs.start[0] == 0 && !sub->global)
{
- /* We found a match, set the `replaced' flag. */
- replaced = true;
+ /* We found a match, set the `replaced' flag. */
+ replaced = true;
- line.active += regs.end[0];
- line.length -= regs.end[0];
- line.alloc -= regs.end[0];
- goto post_subst;
+ line.active += regs.end[0];
+ line.length -= regs.end[0];
+ line.alloc -= regs.end[0];
+ goto post_subst;
}
else if (regs.end[0] == line.length)
{
- /* We found a match, set the `replaced' flag. */
- replaced = true;
+ /* We found a match, set the `replaced' flag. */
+ replaced = true;
- line.length = regs.start[0];
- goto post_subst;
+ line.length = regs.start[0];
+ goto post_subst;
}
}
@@ -1095,11 +1060,11 @@ do_subst(sub)
/* Copy stuff to the left of this match into the output string. */
if (start < offset)
- str_append(&s_accum, line.active + start, offset - start);
+ str_append(&s_accum, line.active + start, offset - start);
/* If we're counting up to the Nth match, are we there yet?
And even if we are there, there is another case we have to
- skip: are we matching an empty string immediately following
+ skip: are we matching an empty string immediately following
another match?
This latter case avoids that baaaac, when passed through
@@ -1107,41 +1072,41 @@ do_subst(sub)
unacceptable because it is not consistently applied (for
example, `baaaa' gives `xbx', not `xbxx'). */
if ((matched > 0 || count == 0 || offset > last_end)
- && ++count >= sub->numb)
+ && ++count >= sub->numb)
{
/* We found a match, set the `replaced' flag. */
replaced = true;
/* Now expand the replacement string into the output string. */
append_replacement (&s_accum, sub->replacement, &regs);
- again = sub->global;
+ again = sub->global;
}
else
- {
+ {
/* The match was not replaced. Copy the text until its
end; if it was vacuous, skip over one character and
- add that character to the output. */
- if (matched == 0)
- {
- if (start < line.length)
- matched = 1;
- else
- break;
- }
-
- str_append(&s_accum, line.active + offset, matched);
+ add that character to the output. */
+ if (matched == 0)
+ {
+ if (start < line.length)
+ matched = 1;
+ else
+ break;
+ }
+
+ str_append(&s_accum, line.active + offset, matched);
}
/* Start after the match. last_end is the real end of the matched
- substring, excluding characters that were skipped in case the RE
- matched the empty string. */
+ substring, excluding characters that were skipped in case the RE
+ matched the empty string. */
start = offset + matched;
last_end = regs.end[0];
}
while (again
- && start <= line.length
- && match_regex(sub->regx, line.active, line.length, start,
- &regs, sub->max_id + 1));
+ && start <= line.length
+ && match_regex(sub->regx, line.active, line.length, start,
+ &regs, sub->max_id + 1));
/* Copy stuff to the right of the last match into the output string. */
if (start < line.length)
@@ -1159,43 +1124,43 @@ do_subst(sub)
post_subst:
if (sub->print & 1)
output_line(line.active, line.length, line.chomped, &output_file);
-
- if (sub->eval)
+
+ if (sub->eval)
{
#ifdef HAVE_POPEN
FILE *pipe_fp;
line_reset(&s_accum, NULL);
-
+
str_append (&line, "", 1);
pipe_fp = popen(line.active, "r");
-
- if (pipe_fp != NULL)
- {
- while (!feof (pipe_fp))
- {
- char buf[4096];
- int n = fread (buf, sizeof(char), 4096, pipe_fp);
- if (n > 0)
- str_append(&s_accum, buf, n);
- }
-
- pclose (pipe_fp);
-
- /* Exchange line and s_accum. This can be much cheaper than copying
- s_accum.active into line.text (for huge lines). See comment above
- for 'g' as to while the third argument is incorrect anyway. */
- line_exchange(&line, &s_accum, true);
- if (line.length &&
- line.active[line.length - 1] == buffer_delimiter)
- line.length--;
- }
+
+ if (pipe_fp != NULL)
+ {
+ while (!feof (pipe_fp))
+ {
+ char buf[4096];
+ int n = fread (buf, sizeof(char), 4096, pipe_fp);
+ if (n > 0)
+ str_append(&s_accum, buf, n);
+ }
+
+ pclose (pipe_fp);
+
+ /* Exchange line and s_accum. This can be much cheaper than copying
+ s_accum.active into line.text (for huge lines). See comment above
+ for 'g' as to while the third argument is incorrect anyway. */
+ line_exchange(&line, &s_accum, true);
+ if (line.length &&
+ line.active[line.length - 1] == buffer_delimiter)
+ line.length--;
+ }
else
- panic(_("error in subprocess"));
+ panic(_("error in subprocess"));
#else
panic(_("option `e' not supported"));
#endif
- }
-
+ }
+
if (sub->print & 2)
output_line(line.active, line.length, line.chomped, &output_file);
if (sub->outf)
@@ -1207,7 +1172,6 @@ do_subst(sub)
static countT branches;
-static countT count_branches (struct vector *);
static countT
count_branches(program)
struct vector *program;
@@ -1219,18 +1183,17 @@ count_branches(program)
while (isn_cnt-- > 0)
{
switch (cur_cmd->cmd)
- {
- case 'b':
- case 't':
- case 'T':
- case '{':
- ++cnt;
- }
+ {
+ case 'b':
+ case 't':
+ case 'T':
+ case '{':
+ ++cnt;
+ }
}
return cnt;
}
-static struct sed_cmd *shrink_program (struct vector *, struct sed_cmd *);
static struct sed_cmd *
shrink_program(vec, cur_cmd)
struct vector *vec;
@@ -1255,13 +1218,74 @@ shrink_program(vec, cur_cmd)
}
#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/
+/* Translate the global input LINE via TRANS.
+ This function handles the multi-byte case. */
+static void
+translate_mb (char *const *trans)
+{
+ size_t idx; /* index in the input line. */
+ mbstate_t mbstate = { 0, };
+ for (idx = 0; idx < line.length;)
+ {
+ unsigned int i;
+ size_t mbclen = MBRLEN (line.active + idx,
+ line.length - idx, &mbstate);
+ /* An invalid sequence, or a truncated multibyte
+ character. Treat it as a single-byte character. */
+ if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
+ mbclen = 1;
+
+ /* `i' indicate i-th translate pair. */
+ for (i = 0; trans[2*i] != NULL; i++)
+ {
+ if (strncmp(line.active + idx, trans[2*i], mbclen) == 0)
+ {
+ bool move_remain_buffer = false;
+ const char *tr = trans[2*i+1];
+ size_t trans_len = *tr == '\0' ? 1 : strlen (tr);
+
+ if (mbclen < trans_len)
+ {
+ size_t new_len = (line.length + 1
+ + trans_len - mbclen);
+ /* We must extend the line buffer. */
+ if (line.alloc < new_len)
+ {
+ /* And we must resize the buffer. */
+ resize_line(&line, new_len);
+ }
+ move_remain_buffer = true;
+ }
+ else if (mbclen > trans_len)
+ {
+ /* We must truncate the line buffer. */
+ move_remain_buffer = true;
+ }
+ size_t prev_idx = idx;
+ if (move_remain_buffer)
+ {
+ /* Move the remaining with \0. */
+ char const *move_from = (line.active + idx + mbclen);
+ char *move_to = line.active + idx + trans_len;
+ size_t move_len = line.length + 1 - idx - mbclen;
+ size_t move_offset = trans_len - mbclen;
+ memmove(move_to, move_from, move_len);
+ line.length += move_offset;
+ idx += move_offset;
+ }
+ memcpy(line.active + prev_idx, trans[2*i+1],
+ trans_len);
+ break;
+ }
+ }
+ idx += mbclen;
+ }
+}
+
/* Execute the program `vec' on the current input line.
Return exit status if caller should quit, -1 otherwise. */
-static int execute_program (struct vector *, struct input *);
static int
-execute_program(vec, input)
- struct vector *vec;
- struct input *input;
+execute_program(struct vector *vec, struct input *input)
{
struct sed_cmd *cur_cmd;
struct sed_cmd *end_cmd;
@@ -1271,174 +1295,164 @@ execute_program(vec, input)
while (cur_cmd < end_cmd)
{
if (match_address_p(cur_cmd, input) != cur_cmd->addr_bang)
- {
- switch (cur_cmd->cmd)
- {
- case 'a':
- {
- struct append_queue *aq = next_append_slot();
- aq->text = cur_cmd->x.cmd_txt.text;
- aq->textlen = cur_cmd->x.cmd_txt.text_length;
- }
- break;
-
- case '{':
- case 'b':
- cur_cmd = vec->v + cur_cmd->x.jump_index;
- continue;
-
- case '}':
- case '#':
- case ':':
- /* Executing labels and block-ends are easy. */
- break;
-
- case 'c':
- if (cur_cmd->range_state != RANGE_ACTIVE)
- output_line(cur_cmd->x.cmd_txt.text,
- cur_cmd->x.cmd_txt.text_length - 1, true,
- &output_file);
- /* POSIX.2 is silent about c starting a new cycle,
- but it seems to be expected (and make sense). */
- /* Fall Through */
- case 'd':
- return -1;
-
- case 'D':
- {
- char *p = memchr(line.active, buffer_delimiter, line.length);
- if (!p)
- return -1;
-
- ++p;
- line.alloc -= p - line.active;
- line.length -= p - line.active;
- line.active += p - line.active;
-
- /* reset to start next cycle without reading a new line: */
- cur_cmd = vec->v;
- continue;
- }
-
- case 'e': {
-#ifdef HAVE_POPEN
- FILE *pipe_fp;
- int cmd_length = cur_cmd->x.cmd_txt.text_length;
- line_reset(&s_accum, NULL);
-
- if (!cmd_length)
- {
- str_append (&line, "", 1);
- pipe_fp = popen(line.active, "r");
- }
- else
- {
- cur_cmd->x.cmd_txt.text[cmd_length - 1] = 0;
- pipe_fp = popen(cur_cmd->x.cmd_txt.text, "r");
- output_missing_newline(&output_file);
- }
-
- if (pipe_fp != NULL)
- {
- char buf[4096];
- int n;
- while (!feof (pipe_fp))
- if ((n = fread (buf, sizeof(char), 4096, pipe_fp)) > 0)
- {
- if (!cmd_length)
- str_append(&s_accum, buf, n);
- else
- ck_fwrite(buf, 1, n, output_file.fp);
- }
-
- pclose (pipe_fp);
- if (!cmd_length)
- {
- /* Store into pattern space for plain `e' commands */
- if (s_accum.length &&
- s_accum.active[s_accum.length - 1] == buffer_delimiter)
- s_accum.length--;
-
- /* Exchange line and s_accum. This can be much
- cheaper than copying s_accum.active into line.text
- (for huge lines). See comment above for 'g' as
- to while the third argument is incorrect anyway. */
- line_exchange(&line, &s_accum, true);
- }
- else
- flush_output(output_file.fp);
-
- }
- else
- panic(_("error in subprocess"));
+ {
+ switch (cur_cmd->cmd)
+ {
+ case 'a':
+ {
+ struct append_queue *aq = next_append_slot();
+ aq->text = cur_cmd->x.cmd_txt.text;
+ aq->textlen = cur_cmd->x.cmd_txt.text_length;
+ }
+ break;
+
+ case '{':
+ case 'b':
+ cur_cmd = vec->v + cur_cmd->x.jump_index;
+ continue;
+
+ case '}':
+ case '#':
+ case ':':
+ /* Executing labels and block-ends are easy. */
+ break;
+
+ case 'c':
+ if (cur_cmd->range_state != RANGE_ACTIVE)
+ output_line(cur_cmd->x.cmd_txt.text,
+ cur_cmd->x.cmd_txt.text_length - 1, true,
+ &output_file);
+ /* POSIX.2 is silent about c starting a new cycle,
+ but it seems to be expected (and make sense). */
+ /* Fall Through */
+ case 'd':
+ return -1;
+
+ case 'D':
+ {
+ char *p = memchr(line.active, buffer_delimiter, line.length);
+ if (!p)
+ return -1;
+
+ ++p;
+ line.alloc -= p - line.active;
+ line.length -= p - line.active;
+ line.active += p - line.active;
+
+ /* reset to start next cycle without reading a new line: */
+ cur_cmd = vec->v;
+ continue;
+ }
+
+ case 'e': {
+#ifndef HAVE_POPEN
+ panic(_("`e' command not supported"));
#else
- panic(_("`e' command not supported"));
+ FILE *pipe_fp;
+ int cmd_length = cur_cmd->x.cmd_txt.text_length;
+ line_reset(&s_accum, NULL);
+
+ if (!cmd_length)
+ {
+ str_append (&line, "", 1);
+ pipe_fp = popen(line.active, "r");
+ }
+ else
+ {
+ cur_cmd->x.cmd_txt.text[cmd_length - 1] = 0;
+ pipe_fp = popen(cur_cmd->x.cmd_txt.text, "r");
+ output_missing_newline(&output_file);
+ }
+
+ if (pipe_fp == NULL)
+ panic(_("error in subprocess"));
+
+ {
+ char buf[4096];
+ int n;
+ while (!feof (pipe_fp))
+ if ((n = fread (buf, sizeof(char), 4096, pipe_fp)) > 0)
+ {
+ if (!cmd_length)
+ str_append(&s_accum, buf, n);
+ else
+ ck_fwrite(buf, 1, n, output_file.fp);
+ }
+
+ pclose (pipe_fp);
+ if (!cmd_length)
+ {
+ /* Store into pattern space for plain `e' commands */
+ if (s_accum.length &&
+ s_accum.active[s_accum.length - 1] == buffer_delimiter)
+ s_accum.length--;
+
+ /* Exchange line and s_accum. This can be much
+ cheaper than copying s_accum.active into line.text
+ (for huge lines). See comment above for 'g' as
+ to while the third argument is incorrect anyway. */
+ line_exchange(&line, &s_accum, true);
+ }
+ else
+ flush_output(output_file.fp);
+ }
#endif
- break;
- }
-
- case 'g':
- /* We do not have a really good choice for the third parameter.
- The problem is that hold space and the input file might as
- well have different states; copying it from hold space means
- that subsequent input might be read incorrectly, while
- keeping it as in pattern space means that commands operating
- on the moved buffer might consider a wrong character set.
- We keep it true because it's what sed <= 4.1.5 did. */
- line_copy(&hold, &line, true);
- break;
-
- case 'G':
- /* We do not have a really good choice for the third parameter.
- The problem is that hold space and pattern space might as
- well have different states. So, true is as wrong as false.
- We keep it true because it's what sed <= 4.1.5 did, but
- we could consider having line_ap. */
- line_append(&hold, &line, true);
- break;
-
- case 'h':
- /* Here, it is ok to have true. */
- line_copy(&line, &hold, true);
- break;
-
- case 'H':
- /* See comment above for 'G' regarding the third parameter. */
- line_append(&line, &hold, true);
- break;
-
- case 'i':
- output_line(cur_cmd->x.cmd_txt.text,
- cur_cmd->x.cmd_txt.text_length - 1,
- true, &output_file);
- break;
-
- case 'l':
- do_list(cur_cmd->x.int_arg == -1
- ? lcmd_out_line_len
- : cur_cmd->x.int_arg);
- break;
-
- case 'L':
- output_missing_newline(&output_file);
- fmt(line.active, line.active + line.length,
- cur_cmd->x.int_arg == -1
- ? lcmd_out_line_len
- : cur_cmd->x.int_arg,
- output_file.fp);
- flush_output(output_file.fp);
- break;
-
- case 'n':
- if (!no_default_output)
- output_line(line.active, line.length, line.chomped, &output_file);
- if (test_eof(input) || !read_pattern_space(input, vec, false))
- return -1;
- break;
-
- case 'N':
- str_append(&line, &buffer_delimiter, 1);
-
+ break;
+ }
+
+ case 'g':
+ /* We do not have a really good choice for the third parameter.
+ The problem is that hold space and the input file might as
+ well have different states; copying it from hold space means
+ that subsequent input might be read incorrectly, while
+ keeping it as in pattern space means that commands operating
+ on the moved buffer might consider a wrong character set.
+ We keep it true because it's what sed <= 4.1.5 did. */
+ line_copy(&hold, &line, true);
+ break;
+
+ case 'G':
+ /* We do not have a really good choice for the third parameter.
+ The problem is that hold space and pattern space might as
+ well have different states. So, true is as wrong as false.
+ We keep it true because it's what sed <= 4.1.5 did, but
+ we could consider having line_ap. */
+ line_append(&hold, &line, true);
+ break;
+
+ case 'h':
+ /* Here, it is ok to have true. */
+ line_copy(&line, &hold, true);
+ break;
+
+ case 'H':
+ /* See comment above for 'G' regarding the third parameter. */
+ line_append(&line, &hold, true);
+ break;
+
+ case 'i':
+ output_line(cur_cmd->x.cmd_txt.text,
+ cur_cmd->x.cmd_txt.text_length - 1,
+ true, &output_file);
+ break;
+
+ case 'l':
+ do_list(cur_cmd->x.int_arg == -1
+ ? lcmd_out_line_len
+ : cur_cmd->x.int_arg);
+ break;
+
+ case 'n':
+ if (!no_default_output)
+ output_line(line.active, line.length, line.chomped,
+ &output_file);
+ if (test_eof(input) || !read_pattern_space(input, vec, false))
+ return -1;
+ break;
+
+ case 'N':
+ str_append(&line, &buffer_delimiter, 1);
+
if (test_eof(input) || !read_pattern_space(input, vec, true))
{
line.length--;
@@ -1447,199 +1461,137 @@ execute_program(vec, input)
&output_file);
return -1;
}
- break;
+ break;
- case 'p':
- output_line(line.active, line.length, line.chomped, &output_file);
- break;
+ case 'p':
+ output_line(line.active, line.length, line.chomped, &output_file);
+ break;
- case 'P':
- {
- char *p = memchr(line.active, buffer_delimiter, line.length);
- output_line(line.active, p ? p - line.active : line.length,
- p ? true : line.chomped, &output_file);
- }
- break;
+ case 'P':
+ {
+ char *p = memchr(line.active, buffer_delimiter, line.length);
+ output_line(line.active, p ? p - line.active : line.length,
+ p ? true : line.chomped, &output_file);
+ }
+ break;
case 'q':
if (!no_default_output)
- output_line(line.active, line.length, line.chomped, &output_file);
- dump_append_queue();
-
- case 'Q':
- return cur_cmd->x.int_arg == -1 ? 0 : cur_cmd->x.int_arg;
-
- case 'r':
- if (cur_cmd->x.fname)
- {
- struct append_queue *aq = next_append_slot();
- aq->fname = cur_cmd->x.fname;
- }
- break;
-
- case 'R':
- if (cur_cmd->x.fp && !feof (cur_cmd->x.fp))
- {
- struct append_queue *aq;
- size_t buflen;
- char *text = NULL;
- int result;
-
- result = ck_getdelim (&text, &buflen, buffer_delimiter,
- cur_cmd->x.fp);
- if (result != EOF)
- {
- aq = next_append_slot();
- aq->free = true;
- aq->text = text;
- aq->textlen = result;
- }
- }
- break;
-
- case 's':
- do_subst(cur_cmd->x.cmd_subst);
- break;
-
- case 't':
- if (replaced)
- {
- replaced = false;
- cur_cmd = vec->v + cur_cmd->x.jump_index;
- continue;
- }
- break;
-
- case 'T':
- if (!replaced)
- {
- cur_cmd = vec->v + cur_cmd->x.jump_index;
- continue;
- }
- else
- replaced = false;
- break;
-
- case 'w':
- if (cur_cmd->x.fp)
- output_line(line.active, line.length,
- line.chomped, cur_cmd->x.outf);
- break;
-
- case 'W':
- if (cur_cmd->x.fp)
- {
- char *p = memchr(line.active, buffer_delimiter, line.length);
- output_line(line.active, p ? p - line.active : line.length,
- p ? true : line.chomped, cur_cmd->x.outf);
- }
- break;
-
- case 'x':
- /* See comment above for 'g' regarding the third parameter. */
- line_exchange(&line, &hold, false);
- break;
-
- case 'y':
- {
- if (mb_cur_max > 1)
- {
- int idx, prev_idx; /* index in the input line. */
- char **trans;
- mbstate_t mbstate;
- memset(&mbstate, 0, sizeof(mbstate_t));
- for (idx = 0; idx < line.length;)
- {
- int mbclen, i;
- mbclen = MBRLEN (line.active + idx, line.length - idx,
- &mbstate);
- /* An invalid sequence, or a truncated multibyte
- character. We treat it as a singlebyte character.
- */
- if (mbclen == (size_t) -1 || mbclen == (size_t) -2
- || mbclen == 0)
- mbclen = 1;
-
- trans = cur_cmd->x.translatemb;
- /* `i' indicate i-th translate pair. */
- for (i = 0; trans[2*i] != NULL; i++)
- {
- if (strncmp(line.active + idx, trans[2*i], mbclen) == 0)
- {
- bool move_remain_buffer = false;
- int trans_len = strlen(trans[2*i+1]);
-
- if (mbclen < trans_len)
- {
- int new_len;
- new_len = line.length + 1 + trans_len - mbclen;
- /* We must extend the line buffer. */
- if (line.alloc < new_len)
- {
- /* And we must resize the buffer. */
- resize_line(&line, new_len);
- }
- move_remain_buffer = true;
- }
- else if (mbclen > trans_len)
- {
- /* We must truncate the line buffer. */
- move_remain_buffer = true;
- }
- prev_idx = idx;
- if (move_remain_buffer)
- {
- int move_len, move_offset;
- char *move_from, *move_to;
- /* Move the remaining with \0. */
- move_from = line.active + idx + mbclen;
- move_to = line.active + idx + trans_len;
- move_len = line.length + 1 - idx - mbclen;
- move_offset = trans_len - mbclen;
- memmove(move_to, move_from, move_len);
- line.length += move_offset;
- idx += move_offset;
- }
- strncpy(line.active + prev_idx, trans[2*i+1],
- trans_len);
- break;
- }
- }
- idx += mbclen;
- }
- }
- else
- {
- unsigned char *p, *e;
- p = (unsigned char *)line.active;
- for (e=p+line.length; p<e; ++p)
- *p = cur_cmd->x.translate[*p];
- }
- }
- break;
-
- case 'z':
- line.length = 0;
- break;
-
- case '=':
+ output_line(line.active, line.length, line.chomped,
+ &output_file);
+ dump_append_queue();
+ /* FALLTHROUGH */
+
+ case 'Q':
+ return cur_cmd->x.int_arg == -1 ? 0 : cur_cmd->x.int_arg;
+
+ case 'r':
+ if (cur_cmd->x.fname)
+ {
+ struct append_queue *aq = next_append_slot();
+ aq->fname = cur_cmd->x.fname;
+ }
+ break;
+
+ case 'R':
+ if (cur_cmd->x.fp && !feof (cur_cmd->x.fp))
+ {
+ struct append_queue *aq;
+ size_t buflen;
+ char *text = NULL;
+ int result;
+
+ result = ck_getdelim (&text, &buflen, buffer_delimiter,
+ cur_cmd->x.fp);
+ if (result != EOF)
+ {
+ aq = next_append_slot();
+ aq->free = true;
+ aq->text = text;
+ aq->textlen = result;
+ }
+ }
+ break;
+
+ case 's':
+ do_subst(cur_cmd->x.cmd_subst);
+ break;
+
+ case 't':
+ if (replaced)
+ {
+ replaced = false;
+ cur_cmd = vec->v + cur_cmd->x.jump_index;
+ continue;
+ }
+ break;
+
+ case 'T':
+ if (!replaced)
+ {
+ cur_cmd = vec->v + cur_cmd->x.jump_index;
+ continue;
+ }
+ else
+ replaced = false;
+ break;
+
+ case 'w':
+ if (cur_cmd->x.fp)
+ output_line(line.active, line.length,
+ line.chomped, cur_cmd->x.outf);
+ break;
+
+ case 'W':
+ if (cur_cmd->x.fp)
+ {
+ char *p = memchr(line.active, buffer_delimiter, line.length);
+ output_line(line.active, p ? p - line.active : line.length,
+ p ? true : line.chomped, cur_cmd->x.outf);
+ }
+ break;
+
+ case 'x':
+ /* See comment above for 'g' regarding the third parameter. */
+ line_exchange(&line, &hold, false);
+ break;
+
+ case 'y':
+ if (mb_cur_max > 1)
+ translate_mb (cur_cmd->x.translatemb);
+ else
+ {
+ unsigned char *p, *e;
+ p = (unsigned char *)line.active;
+ for (e=p+line.length; p<e; ++p)
+ *p = cur_cmd->x.translate[*p];
+ }
+ break;
+
+ case 'z':
+ line.length = 0;
+ break;
+
+ case '=':
output_missing_newline(&output_file);
- fprintf(output_file.fp, "%lu\n",
- (unsigned long)input->line_number);
+ fprintf(output_file.fp, "%lu%c",
+ (unsigned long)input->line_number,
+ buffer_delimiter);
flush_output(output_file.fp);
break;
case 'F':
output_missing_newline(&output_file);
- fprintf(output_file.fp, "%s\n",
- input->in_file_name);
+ fprintf(output_file.fp, "%s%c",
+ input->in_file_name,
+ buffer_delimiter);
flush_output(output_file.fp);
break;
default:
panic("INTERNAL ERROR: Bad cmd %c", cur_cmd->cmd);
}
- }
+ }
#ifdef EXPERIMENTAL_DASH_N_OPTIMIZATION
/* If our top-level program consists solely of commands with
@@ -1651,42 +1603,42 @@ execute_program(vec, input)
compared against how much time is saved. One semantic
difference (which I think is an improvement) is that *this*
version will terminate after printing line two in the script
- "yes | sed -n 2p".
-
+ "yes | sed -n 2p".
+
Don't use this when in-place editing is active, because line
numbers restart each time then. */
else if (!separate_files)
- {
- if (cur_cmd->a1->addr_type == ADDR_IS_NUM
- && (cur_cmd->a2
- ? cur_cmd->range_state == RANGE_CLOSED
- : cur_cmd->a1->addr_number < input->line_number))
- {
- /* Skip this address next time */
- cur_cmd->addr_bang = !cur_cmd->addr_bang;
- cur_cmd->a1->addr_type = ADDR_IS_NULL;
- if (cur_cmd->a2)
- cur_cmd->a2->addr_type = ADDR_IS_NULL;
-
- /* can we make an optimization? */
- if (cur_cmd->addr_bang)
- {
- if (cur_cmd->cmd == 'b' || cur_cmd->cmd == 't'
- || cur_cmd->cmd == 'T' || cur_cmd->cmd == '}')
- branches--;
-
- cur_cmd->cmd = '#'; /* replace with no-op */
- if (branches == 0)
- cur_cmd = shrink_program(vec, cur_cmd);
- if (!cur_cmd && no_default_output)
- return 0;
- end_cmd = vec->v + vec->v_length;
- if (!cur_cmd)
- cur_cmd = end_cmd;
- continue;
- }
- }
- }
+ {
+ if (cur_cmd->a1->addr_type == ADDR_IS_NUM
+ && (cur_cmd->a2
+ ? cur_cmd->range_state == RANGE_CLOSED
+ : cur_cmd->a1->addr_number < input->line_number))
+ {
+ /* Skip this address next time */
+ cur_cmd->addr_bang = !cur_cmd->addr_bang;
+ cur_cmd->a1->addr_type = ADDR_IS_NULL;
+ if (cur_cmd->a2)
+ cur_cmd->a2->addr_type = ADDR_IS_NULL;
+
+ /* can we make an optimization? */
+ if (cur_cmd->addr_bang)
+ {
+ if (cur_cmd->cmd == 'b' || cur_cmd->cmd == 't'
+ || cur_cmd->cmd == 'T' || cur_cmd->cmd == '}')
+ branches--;
+
+ cur_cmd->cmd = '#'; /* replace with no-op */
+ if (branches == 0)
+ cur_cmd = shrink_program(vec, cur_cmd);
+ if (!cur_cmd && no_default_output)
+ return 0;
+ end_cmd = vec->v + vec->v_length;
+ if (!cur_cmd)
+ cur_cmd = end_cmd;
+ continue;
+ }
+ }
+ }
#endif /*EXPERIMENTAL_DASH_N_OPTIMIZATION*/
/* this is buried down here so that a "continue" statement can skip it */
@@ -1702,9 +1654,7 @@ execute_program(vec, input)
/* Apply the compiled script to all the named files. */
int
-process_files(the_program, argv)
- struct vector *the_program;
- char **argv;
+process_files(struct vector *the_program, char **argv)
{
static char dash[] = "-";
static char *stdin_argv[2] = { dash, NULL };
@@ -1736,9 +1686,9 @@ process_files(the_program, argv)
{
status = execute_program(the_program, &input);
if (status == -1)
- status = EXIT_SUCCESS;
+ status = EXIT_SUCCESS;
else
- break;
+ break;
}
closedown(&input);
@@ -1756,7 +1706,7 @@ process_files(the_program, argv)
#endif /*DEBUG_LEAKS*/
if (input.bad_count)
- status = 2;
+ status = EXIT_BAD_INPUT;
return status;
}