- Added support for semicolon delimited command lines. (woo-hoo!)

- Obsoleted the trim_str function (#if 0'ed out -- maybedelete later) in
   favor of strrspn.
 - Obsoleted the strrspn function (#if 0'ed out as well) as soon as I
   discovered that it wasn't needed either.
 - Fixed a subtle bug in parse_subst_cmd where it would choke with an error if
   there was any trailing space after the s/match/replace/ expression.
This commit is contained in:
Mark Whitley 2000-07-14 19:06:30 +00:00
parent add09fd558
commit 70705d7c96
2 changed files with 144 additions and 62 deletions

View File

@ -132,11 +132,13 @@ static void destroy_cmd_strs()
} }
#endif #endif
#if 0
/* /*
* trim_str - trims leading and trailing space from a string * trim_str - trims leading and trailing space from a string
* *
* Note: This returns a malloc'ed string so you must store and free it * Note: This returns a malloc'ed string so you must store and free it
* XXX: This should be in the utility.c file. * XXX: This should be in the utility.c file.
* XXX: This is now obsolete. Maybe it belongs nowhere.
*/ */
static char *trim_str(const char *str) static char *trim_str(const char *str)
{ {
@ -156,11 +158,28 @@ static char *trim_str(const char *str)
* *
* you know, a strrspn() would really be nice cuz then we could say: * you know, a strrspn() would really be nice cuz then we could say:
* *
* retstr[strlen(retstr) - strrspn(retstr, " \n\t\v") + 1] = 0; * retstr[strrspn(retstr, " \n\t\v") + 1] = 0;
*/ */
return retstr; return retstr;
} }
#endif
#if 0
/*
* strrspn - works just like strspn() but goes from right to left instead of
* left to right
*/
static size_t strrspn(const char *s, const char *accept)
{
size_t i = strlen(s);
while (strchr(accept, s[--i]))
;
return i;
}
#endif
/* /*
* index_of_unescaped_slash - walks left to right through a string beginning * index_of_unescaped_slash - walks left to right through a string beginning
@ -225,7 +244,7 @@ static char *strdup_substr(const char *str, int start, int end)
return newstr; return newstr;
} }
static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
{ {
int oldidx, cflags = REG_NEWLINE; int oldidx, cflags = REG_NEWLINE;
char *match; char *match;
@ -261,24 +280,31 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
/* process the flags */ /* process the flags */
while (substr[++idx]) { while (substr[++idx]) {
switch (substr[idx]) { switch (substr[idx]) {
case 'g': case 'g':
sed_cmd->sub_g = 1; sed_cmd->sub_g = 1;
break; break;
case 'I': case 'I':
cflags |= REG_ICASE; cflags |= REG_ICASE;
break; break;
default: default:
fatalError("bad option in substitution expression\n"); /* any whitespace or semicolon trailing after a s/// is ok */
if (strchr("; \t\v\n\r", substr[idx]))
goto out;
/* else */
fatalError("bad option in substitution expression\n");
} }
} }
out:
/* compile the regex */ /* compile the regex */
sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
xregcomp(sed_cmd->sub_match, match, cflags); xregcomp(sed_cmd->sub_match, match, cflags);
free(match); free(match);
return idx;
} }
static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
{ {
int idx = 0; int idx = 0;
char *ptr; /* shorthand */ char *ptr; /* shorthand */
@ -322,7 +348,7 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
if (!ptr[idx]) { if (!ptr[idx]) {
ptr[idx] = '\n'; ptr[idx] = '\n';
ptr[idx+1] = 0; ptr[idx+1] = 0;
return; return idx;
} }
} }
/* move the newline over the '\' before it (effectively eats the '\') */ /* move the newline over the '\' before it (effectively eats the '\') */
@ -332,9 +358,11 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
if (ptr[idx] == '\r') if (ptr[idx] == '\r')
ptr[idx] = '\n'; ptr[idx] = '\n';
} }
return idx;
} }
static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
{ {
int idx = 0; int idx = 0;
@ -344,6 +372,7 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
* part1 part2 part3 * part1 part2 part3
*/ */
/* first part (if present) is an address: either a number or a /regex/ */ /* first part (if present) is an address: either a number or a /regex/ */
if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
@ -360,33 +389,45 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
sed_cmd->cmd = cmdstr[idx]; sed_cmd->cmd = cmdstr[idx];
/* special-case handling for (s)ubstitution */ /* special-case handling for (s)ubstitution */
if (sed_cmd->cmd == 's') if (sed_cmd->cmd == 's') {
parse_subst_cmd(sed_cmd, &cmdstr[idx]); idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
}
/* special-case handling for (a)ppend, (i)nsert, and (c)hange */ /* special-case handling for (a)ppend, (i)nsert, and (c)hange */
if (strchr("aic", cmdstr[idx])) { else if (strchr("aic", cmdstr[idx])) {
if (sed_cmd->end_line || sed_cmd->end_match) if (sed_cmd->end_line || sed_cmd->end_match)
fatalError("only a beginning address can be specified for edit commands\n"); fatalError("only a beginning address can be specified for edit commands\n");
parse_edit_cmd(sed_cmd, &cmdstr[idx]); idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
} }
/* give back whatever's left over */
return (char *)&cmdstr[++idx];
} }
static void add_cmd_str(const char *cmdstr) static void add_cmd_str(const char *cmdstr)
{ {
char *my_cmdstr = trim_str(cmdstr); char *mystr = (char *)cmdstr;
/* if this is a comment, don't even bother */ do {
if (my_cmdstr[0] == '#') {
free(my_cmdstr);
return;
}
/* grow the array */ /* trim leading whitespace and semicolons */
sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
/* zero new element */ /* if we ate the whole thing, that means there was just trailing
memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); * whitespace or a final semicolon. either way, get out */
/* load command string into new array element */ if (strlen(mystr) == 0)
parse_cmd_str(&sed_cmds[ncmds-1], my_cmdstr); return;
/* if this is a comment, jump past it and keep going */
if (mystr[0] == '#') {
mystr = strpbrk(mystr, ";\n\r");
continue;
}
/* grow the array */
sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds));
/* zero new element */
memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd));
/* load command string into new array element, get remainder */
mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr);
} while (mystr);
} }

103
sed.c
View File

@ -132,11 +132,13 @@ static void destroy_cmd_strs()
} }
#endif #endif
#if 0
/* /*
* trim_str - trims leading and trailing space from a string * trim_str - trims leading and trailing space from a string
* *
* Note: This returns a malloc'ed string so you must store and free it * Note: This returns a malloc'ed string so you must store and free it
* XXX: This should be in the utility.c file. * XXX: This should be in the utility.c file.
* XXX: This is now obsolete. Maybe it belongs nowhere.
*/ */
static char *trim_str(const char *str) static char *trim_str(const char *str)
{ {
@ -156,11 +158,28 @@ static char *trim_str(const char *str)
* *
* you know, a strrspn() would really be nice cuz then we could say: * you know, a strrspn() would really be nice cuz then we could say:
* *
* retstr[strlen(retstr) - strrspn(retstr, " \n\t\v") + 1] = 0; * retstr[strrspn(retstr, " \n\t\v") + 1] = 0;
*/ */
return retstr; return retstr;
} }
#endif
#if 0
/*
* strrspn - works just like strspn() but goes from right to left instead of
* left to right
*/
static size_t strrspn(const char *s, const char *accept)
{
size_t i = strlen(s);
while (strchr(accept, s[--i]))
;
return i;
}
#endif
/* /*
* index_of_unescaped_slash - walks left to right through a string beginning * index_of_unescaped_slash - walks left to right through a string beginning
@ -225,7 +244,7 @@ static char *strdup_substr(const char *str, int start, int end)
return newstr; return newstr;
} }
static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
{ {
int oldidx, cflags = REG_NEWLINE; int oldidx, cflags = REG_NEWLINE;
char *match; char *match;
@ -261,24 +280,31 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
/* process the flags */ /* process the flags */
while (substr[++idx]) { while (substr[++idx]) {
switch (substr[idx]) { switch (substr[idx]) {
case 'g': case 'g':
sed_cmd->sub_g = 1; sed_cmd->sub_g = 1;
break; break;
case 'I': case 'I':
cflags |= REG_ICASE; cflags |= REG_ICASE;
break; break;
default: default:
fatalError("bad option in substitution expression\n"); /* any whitespace or semicolon trailing after a s/// is ok */
if (strchr("; \t\v\n\r", substr[idx]))
goto out;
/* else */
fatalError("bad option in substitution expression\n");
} }
} }
out:
/* compile the regex */ /* compile the regex */
sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
xregcomp(sed_cmd->sub_match, match, cflags); xregcomp(sed_cmd->sub_match, match, cflags);
free(match); free(match);
return idx;
} }
static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
{ {
int idx = 0; int idx = 0;
char *ptr; /* shorthand */ char *ptr; /* shorthand */
@ -322,7 +348,7 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
if (!ptr[idx]) { if (!ptr[idx]) {
ptr[idx] = '\n'; ptr[idx] = '\n';
ptr[idx+1] = 0; ptr[idx+1] = 0;
return; return idx;
} }
} }
/* move the newline over the '\' before it (effectively eats the '\') */ /* move the newline over the '\' before it (effectively eats the '\') */
@ -332,9 +358,11 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
if (ptr[idx] == '\r') if (ptr[idx] == '\r')
ptr[idx] = '\n'; ptr[idx] = '\n';
} }
return idx;
} }
static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
{ {
int idx = 0; int idx = 0;
@ -344,6 +372,7 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
* part1 part2 part3 * part1 part2 part3
*/ */
/* first part (if present) is an address: either a number or a /regex/ */ /* first part (if present) is an address: either a number or a /regex/ */
if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); idx = get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
@ -360,33 +389,45 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
sed_cmd->cmd = cmdstr[idx]; sed_cmd->cmd = cmdstr[idx];
/* special-case handling for (s)ubstitution */ /* special-case handling for (s)ubstitution */
if (sed_cmd->cmd == 's') if (sed_cmd->cmd == 's') {
parse_subst_cmd(sed_cmd, &cmdstr[idx]); idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
}
/* special-case handling for (a)ppend, (i)nsert, and (c)hange */ /* special-case handling for (a)ppend, (i)nsert, and (c)hange */
if (strchr("aic", cmdstr[idx])) { else if (strchr("aic", cmdstr[idx])) {
if (sed_cmd->end_line || sed_cmd->end_match) if (sed_cmd->end_line || sed_cmd->end_match)
fatalError("only a beginning address can be specified for edit commands\n"); fatalError("only a beginning address can be specified for edit commands\n");
parse_edit_cmd(sed_cmd, &cmdstr[idx]); idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]);
} }
/* give back whatever's left over */
return (char *)&cmdstr[++idx];
} }
static void add_cmd_str(const char *cmdstr) static void add_cmd_str(const char *cmdstr)
{ {
char *my_cmdstr = trim_str(cmdstr); char *mystr = (char *)cmdstr;
/* if this is a comment, don't even bother */ do {
if (my_cmdstr[0] == '#') {
free(my_cmdstr);
return;
}
/* grow the array */ /* trim leading whitespace and semicolons */
sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
/* zero new element */ /* if we ate the whole thing, that means there was just trailing
memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); * whitespace or a final semicolon. either way, get out */
/* load command string into new array element */ if (strlen(mystr) == 0)
parse_cmd_str(&sed_cmds[ncmds-1], my_cmdstr); return;
/* if this is a comment, jump past it and keep going */
if (mystr[0] == '#') {
mystr = strpbrk(mystr, ";\n\r");
continue;
}
/* grow the array */
sed_cmds = realloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds));
/* zero new element */
memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd));
/* load command string into new array element, get remainder */
mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr);
} while (mystr);
} }