- Fixed bug where you couldn't mix line number and regexes in two-address cmds

- Fixed bug where you couldn't use two addresses for a 'c' cmd
 - Moved the do_sed_cmd function into process_file to simplify some things
 - Reduced a buncha lines of code in the process
This commit is contained in:
Mark Whitley 2001-06-11 23:50:06 +00:00
parent bf0a010cf7
commit 0915c4b985
3 changed files with 277 additions and 239 deletions

View File

@ -156,7 +156,7 @@ static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const c
/* /*
* returns the index in the string just past where the address ends. * returns the index in the string just past where the address ends.
*/ */
static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, regex_t **regex) static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex)
{ {
char *my_str = strdup(str); char *my_str = strdup(str);
int idx = 0; int idx = 0;
@ -169,10 +169,10 @@ static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, rege
idx++; idx++;
} while (isdigit(my_str[idx])); } while (isdigit(my_str[idx]));
my_str[idx] = 0; my_str[idx] = 0;
*line = atoi(my_str); *linenum = atoi(my_str);
} }
else if (my_str[idx] == '$') { else if (my_str[idx] == '$') {
*line = -1; *linenum = -1;
idx++; idx++;
} }
else if (my_str[idx] == '/') { else if (my_str[idx] == '/') {
@ -423,13 +423,13 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
if (strchr("pd", cmdstr[idx])) { if (strchr("pd", cmdstr[idx])) {
idx++; idx++;
} }
/* handle (s)ubstitution */ /* handle (s)ubstitution command */
else if (sed_cmd->cmd == 's') { else if (sed_cmd->cmd == 's') {
idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
} }
/* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
else if (strchr("aic", cmdstr[idx])) { else if (strchr("aic", sed_cmd->cmd)) {
if (sed_cmd->end_line || sed_cmd->end_match) if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
error_msg_and_die("only a beginning address can be specified for edit commands"); error_msg_and_die("only a beginning address can be specified for edit commands");
idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
} }
@ -584,11 +584,42 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line)
return altered; return altered;
} }
static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line)
{
int altered = 0;
switch (sed_cmd->cmd) { static void process_file(FILE *file)
{
char *line = NULL;
static int linenum = 0; /* GNU sed does not restart counting lines at EOF */
unsigned int still_in_range = 0;
int altered;
int i;
/* go through every line in the file */
while ((line = get_line_from_file(file)) != NULL) {
chomp(line);
linenum++;
altered = 0;
/* for every line, go through all the commands */
for (i = 0; i < ncmds; i++) {
/*
* entry point into sedding...
*/
if (
/* this line number is the first address we're looking for */
(sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) ||
/* this line matches our first address regex */
(sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) ||
/* we are currently within the beginning & ending address range */
still_in_range
) {
/*
* actual sedding
*/
switch (sed_cmds[i].cmd) {
case 'p': case 'p':
puts(line); puts(line);
@ -619,108 +650,92 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line)
/* if the user specified that they didn't want anything printed (i.e., a -n /* if the user specified that they didn't want anything printed (i.e., a -n
* flag and no 'p' flag after the s///), then there's really no point doing * flag and no 'p' flag after the s///), then there's really no point doing
* anything here. */ * anything here. */
if (be_quiet && !sed_cmd->sub_p) if (be_quiet && !sed_cmds[i].sub_p)
break; break;
/* we print the line once, unless we were told to be quiet */ /* we print the line once, unless we were told to be quiet */
if (!be_quiet) if (!be_quiet)
altered = do_subst_command(sed_cmd, line); altered = do_subst_command(&sed_cmds[i], line);
/* we also print the line if we were given the 'p' flag /* we also print the line if we were given the 'p' flag
* (this is quite possibly the second printing) */ * (this is quite possibly the second printing) */
if (sed_cmd->sub_p) if (sed_cmds[i].sub_p)
altered = do_subst_command(sed_cmd, line); altered = do_subst_command(&sed_cmds[i], line);
break; break;
case 'a': case 'a':
puts(line); puts(line);
fputs(sed_cmd->editline, stdout); fputs(sed_cmds[i].editline, stdout);
altered++; altered++;
break; break;
case 'i': case 'i':
fputs(sed_cmd->editline, stdout); fputs(sed_cmds[i].editline, stdout);
break; break;
case 'c': case 'c':
fputs(sed_cmd->editline, stdout); /* single-address case */
if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) {
fputs(sed_cmds[i].editline, stdout);
}
/* multi-address case */
else {
/* matching text */
if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
fputs(sed_cmds[i].editline, stdout);
/* matching line numbers */
if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum)
fputs(sed_cmds[i].editline, stdout);
}
altered++; altered++;
break; break;
case 'r': { case 'r': {
FILE *file; FILE *outfile;
puts(line); puts(line);
file = fopen(sed_cmd->filename, "r"); outfile = fopen(sed_cmds[i].filename, "r");
if (file) if (outfile)
print_file(file); print_file(outfile);
/* else if we couldn't open the file, no biggie, just don't print anything */ /* else if we couldn't open the output file,
* no biggie, just don't print anything */
altered++; altered++;
} }
break; break;
} }
return altered; /*
} * exit point from sedding...
*/
static void process_file(FILE *file) if (
{ /* this is a single-address command or... */
char *line = NULL; (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || (
static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ /* we were in the middle of our address range (this
unsigned int still_in_range = 0; * isn't the first time through) and.. */
int line_altered; (still_in_range == 1) && (
int i; /* this line number is the last address we're looking for or... */
(sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) ||
/* go through every line in the file */ /* this line matches our last address regex */
while ((line = get_line_from_file(file)) != NULL) { (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
)
chomp(line); )
linenum++; ) {
line_altered = 0; /* we're out of our address range */
/* for every line, go through all the commands */
for (i = 0; i < ncmds; i++) {
/* are we acting on a range of matched lines? */
if (sed_cmds[i].beg_match && sed_cmds[i].end_match) {
if (still_in_range || regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0) {
line_altered += do_sed_command(&sed_cmds[i], line);
if (still_in_range && regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)
still_in_range = 0; still_in_range = 0;
else }
/* didn't hit the exit? then we're still in the middle of an address range */
else {
still_in_range = 1; still_in_range = 1;
} }
} }
/* are we trying to match a single line? */
else if (sed_cmds[i].beg_match) {
if (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)
line_altered += do_sed_command(&sed_cmds[i], line);
}
/* are we acting on a range of line numbers? */
else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) {
if (linenum >= sed_cmds[i].beg_line &&
(sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line))
line_altered += do_sed_command(&sed_cmds[i], line);
}
/* are we acting on a specified line number */
else if (sed_cmds[i].beg_line > 0) {
if (linenum == sed_cmds[i].beg_line)
line_altered += do_sed_command(&sed_cmds[i], line);
}
/* not acting on matches or line numbers. act on every line */
else
line_altered += do_sed_command(&sed_cmds[i], line);
} }
/* we will print the line unless we were told to be quiet or if the /* we will print the line unless we were told to be quiet or if the
* line was altered (via a 'd'elete or 's'ubstitution), in which case * line was altered (via a 'd'elete or 's'ubstitution), in which case
* the altered line was already printed */ * the altered line was already printed */
if (!be_quiet && !line_altered) if (!be_quiet && !altered)
puts(line); puts(line);
free(line); free(line);

163
sed.c
View File

@ -156,7 +156,7 @@ static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const c
/* /*
* returns the index in the string just past where the address ends. * returns the index in the string just past where the address ends.
*/ */
static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, regex_t **regex) static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex)
{ {
char *my_str = strdup(str); char *my_str = strdup(str);
int idx = 0; int idx = 0;
@ -169,10 +169,10 @@ static int get_address(struct sed_cmd *sed_cmd, const char *str, int *line, rege
idx++; idx++;
} while (isdigit(my_str[idx])); } while (isdigit(my_str[idx]));
my_str[idx] = 0; my_str[idx] = 0;
*line = atoi(my_str); *linenum = atoi(my_str);
} }
else if (my_str[idx] == '$') { else if (my_str[idx] == '$') {
*line = -1; *linenum = -1;
idx++; idx++;
} }
else if (my_str[idx] == '/') { else if (my_str[idx] == '/') {
@ -423,13 +423,13 @@ static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
if (strchr("pd", cmdstr[idx])) { if (strchr("pd", cmdstr[idx])) {
idx++; idx++;
} }
/* handle (s)ubstitution */ /* handle (s)ubstitution command */
else if (sed_cmd->cmd == 's') { else if (sed_cmd->cmd == 's') {
idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
} }
/* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
else if (strchr("aic", cmdstr[idx])) { else if (strchr("aic", sed_cmd->cmd)) {
if (sed_cmd->end_line || sed_cmd->end_match) if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
error_msg_and_die("only a beginning address can be specified for edit commands"); error_msg_and_die("only a beginning address can be specified for edit commands");
idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
} }
@ -584,11 +584,42 @@ static int do_subst_command(const struct sed_cmd *sed_cmd, const char *line)
return altered; return altered;
} }
static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line)
{
int altered = 0;
switch (sed_cmd->cmd) { static void process_file(FILE *file)
{
char *line = NULL;
static int linenum = 0; /* GNU sed does not restart counting lines at EOF */
unsigned int still_in_range = 0;
int altered;
int i;
/* go through every line in the file */
while ((line = get_line_from_file(file)) != NULL) {
chomp(line);
linenum++;
altered = 0;
/* for every line, go through all the commands */
for (i = 0; i < ncmds; i++) {
/*
* entry point into sedding...
*/
if (
/* this line number is the first address we're looking for */
(sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) ||
/* this line matches our first address regex */
(sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) ||
/* we are currently within the beginning & ending address range */
still_in_range
) {
/*
* actual sedding
*/
switch (sed_cmds[i].cmd) {
case 'p': case 'p':
puts(line); puts(line);
@ -619,108 +650,92 @@ static int do_sed_command(const struct sed_cmd *sed_cmd, const char *line)
/* if the user specified that they didn't want anything printed (i.e., a -n /* if the user specified that they didn't want anything printed (i.e., a -n
* flag and no 'p' flag after the s///), then there's really no point doing * flag and no 'p' flag after the s///), then there's really no point doing
* anything here. */ * anything here. */
if (be_quiet && !sed_cmd->sub_p) if (be_quiet && !sed_cmds[i].sub_p)
break; break;
/* we print the line once, unless we were told to be quiet */ /* we print the line once, unless we were told to be quiet */
if (!be_quiet) if (!be_quiet)
altered = do_subst_command(sed_cmd, line); altered = do_subst_command(&sed_cmds[i], line);
/* we also print the line if we were given the 'p' flag /* we also print the line if we were given the 'p' flag
* (this is quite possibly the second printing) */ * (this is quite possibly the second printing) */
if (sed_cmd->sub_p) if (sed_cmds[i].sub_p)
altered = do_subst_command(sed_cmd, line); altered = do_subst_command(&sed_cmds[i], line);
break; break;
case 'a': case 'a':
puts(line); puts(line);
fputs(sed_cmd->editline, stdout); fputs(sed_cmds[i].editline, stdout);
altered++; altered++;
break; break;
case 'i': case 'i':
fputs(sed_cmd->editline, stdout); fputs(sed_cmds[i].editline, stdout);
break; break;
case 'c': case 'c':
fputs(sed_cmd->editline, stdout); /* single-address case */
if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) {
fputs(sed_cmds[i].editline, stdout);
}
/* multi-address case */
else {
/* matching text */
if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
fputs(sed_cmds[i].editline, stdout);
/* matching line numbers */
if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum)
fputs(sed_cmds[i].editline, stdout);
}
altered++; altered++;
break; break;
case 'r': { case 'r': {
FILE *file; FILE *outfile;
puts(line); puts(line);
file = fopen(sed_cmd->filename, "r"); outfile = fopen(sed_cmds[i].filename, "r");
if (file) if (outfile)
print_file(file); print_file(outfile);
/* else if we couldn't open the file, no biggie, just don't print anything */ /* else if we couldn't open the output file,
* no biggie, just don't print anything */
altered++; altered++;
} }
break; break;
} }
return altered; /*
} * exit point from sedding...
*/
static void process_file(FILE *file) if (
{ /* this is a single-address command or... */
char *line = NULL; (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || (
static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ /* we were in the middle of our address range (this
unsigned int still_in_range = 0; * isn't the first time through) and.. */
int line_altered; (still_in_range == 1) && (
int i; /* this line number is the last address we're looking for or... */
(sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) ||
/* go through every line in the file */ /* this line matches our last address regex */
while ((line = get_line_from_file(file)) != NULL) { (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0))
)
chomp(line); )
linenum++; ) {
line_altered = 0; /* we're out of our address range */
/* for every line, go through all the commands */
for (i = 0; i < ncmds; i++) {
/* are we acting on a range of matched lines? */
if (sed_cmds[i].beg_match && sed_cmds[i].end_match) {
if (still_in_range || regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0) {
line_altered += do_sed_command(&sed_cmds[i], line);
if (still_in_range && regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)
still_in_range = 0; still_in_range = 0;
else }
/* didn't hit the exit? then we're still in the middle of an address range */
else {
still_in_range = 1; still_in_range = 1;
} }
} }
/* are we trying to match a single line? */
else if (sed_cmds[i].beg_match) {
if (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)
line_altered += do_sed_command(&sed_cmds[i], line);
}
/* are we acting on a range of line numbers? */
else if (sed_cmds[i].beg_line > 0 && sed_cmds[i].end_line != 0) {
if (linenum >= sed_cmds[i].beg_line &&
(sed_cmds[i].end_line == -1 || linenum <= sed_cmds[i].end_line))
line_altered += do_sed_command(&sed_cmds[i], line);
}
/* are we acting on a specified line number */
else if (sed_cmds[i].beg_line > 0) {
if (linenum == sed_cmds[i].beg_line)
line_altered += do_sed_command(&sed_cmds[i], line);
}
/* not acting on matches or line numbers. act on every line */
else
line_altered += do_sed_command(&sed_cmds[i], line);
} }
/* we will print the line unless we were told to be quiet or if the /* we will print the line unless we were told to be quiet or if the
* line was altered (via a 'd'elete or 's'ubstitution), in which case * line was altered (via a 'd'elete or 's'ubstitution), in which case
* the altered line was already printed */ * the altered line was already printed */
if (!be_quiet && !line_altered) if (!be_quiet && !altered)
puts(line); puts(line);
free(line); free(line);

View File

@ -294,11 +294,19 @@ route
# rpmunpack # rpmunpack
# sed - we can do some one-liners here; probably needs it's own input file # sed - we can do some one-liners here, some testing is a little
# difficult to do in just this space (like a,i,c cmds).
# test ^$ matching
echo foo | sed -ne '/^$/p' echo foo | sed -ne '/^$/p'
echo -e "foo\\n\\nbar" | sed -ne '/^$/p'
sed -e '/test$/d' testcases sed -e '/test$/d' testcases
sed -e '/^echo/d' testcases sed -e '/^echo/d' testcases
sed -e '/test/s/dangerous/PELIGROSO/' testcases sed -e '/test/s/dangerous/PELIGROSO/' testcases
sed -ne '1,/getopt/p' ../pwd.c
sed -e '/getopt/r ../pwd.c' ../sed.c
# setkeycodes # setkeycodes