- 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:
parent
add09fd558
commit
70705d7c96
103
editors/sed.c
103
editors/sed.c
@ -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
103
sed.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user