- Added support for semicolon delimited command lines. (woo-hoo!)
authorMark Whitley <markw@lineo.com>
Fri, 14 Jul 2000 19:06:30 +0000 (19:06 -0000)
committerMark Whitley <markw@lineo.com>
Fri, 14 Jul 2000 19:06:30 +0000 (19:06 -0000)
 - 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.

editors/sed.c
sed.c

index 3a7360fc59980b30dc9965ccef8a36263b6e691b..40400fe3ae3a6cca94f6b2e5b328b01899e1d9cc 100644 (file)
@@ -132,11 +132,13 @@ static void destroy_cmd_strs()
 }
 #endif
 
+#if 0
 /*
  * trim_str - trims leading and trailing space from a string
  * 
  * 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 is now obsolete. Maybe it belongs nowhere.
  */
 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:
         * 
-        * retstr[strlen(retstr) - strrspn(retstr, " \n\t\v") + 1] = 0;
+        * retstr[strrspn(retstr, " \n\t\v") + 1] = 0;
         */
        
        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
@@ -225,7 +244,7 @@ static char *strdup_substr(const char *str, int start, int end)
        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;
        char *match;
@@ -261,24 +280,31 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
        /* process the flags */
        while (substr[++idx]) {
                switch (substr[idx]) {
-               case 'g':
-                       sed_cmd->sub_g = 1;
-                       break;
-               case 'I':
-                       cflags |= REG_ICASE;
-                       break;
-               default:
-                       fatalError("bad option in substitution expression\n");
+                       case 'g':
+                               sed_cmd->sub_g = 1;
+                               break;
+                       case 'I':
+                               cflags |= REG_ICASE;
+                               break;
+                       default:
+                               /* 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 */
        sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
        xregcomp(sed_cmd->sub_match, match, cflags);
        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;
        char *ptr; /* shorthand */
@@ -322,7 +348,7 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
                        if (!ptr[idx]) {
                                ptr[idx] = '\n';
                                ptr[idx+1] = 0;
-                               return;
+                               return idx;
                        }
                }
                /* 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')
                        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;
 
@@ -344,6 +372,7 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
         *            part1 part2  part3
         */
 
+
        /* first part (if present) is an address: either a number or a /regex/ */
        if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
                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];
 
        /* special-case handling for (s)ubstitution */
-       if (sed_cmd->cmd == 's')
-               parse_subst_cmd(sed_cmd, &cmdstr[idx]);
-       
+       if (sed_cmd->cmd == 's') {
+               idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
+       }
        /* 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)
                        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)
 {
-       char *my_cmdstr = trim_str(cmdstr);
+       char *mystr = (char *)cmdstr;
 
-       /* if this is a comment, don't even bother */
-       if (my_cmdstr[0] == '#') {
-               free(my_cmdstr);
-               return;
-       }
+       do {
 
-       /* 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 */
-       parse_cmd_str(&sed_cmds[ncmds-1], my_cmdstr);
+               /* trim leading whitespace and semicolons */
+               memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
+               /* if we ate the whole thing, that means there was just trailing
+                * whitespace or a final semicolon. either way, get out */
+               if (strlen(mystr) == 0)
+                       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);
 }
 
 
diff --git a/sed.c b/sed.c
index 3a7360fc59980b30dc9965ccef8a36263b6e691b..40400fe3ae3a6cca94f6b2e5b328b01899e1d9cc 100644 (file)
--- a/sed.c
+++ b/sed.c
@@ -132,11 +132,13 @@ static void destroy_cmd_strs()
 }
 #endif
 
+#if 0
 /*
  * trim_str - trims leading and trailing space from a string
  * 
  * 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 is now obsolete. Maybe it belongs nowhere.
  */
 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:
         * 
-        * retstr[strlen(retstr) - strrspn(retstr, " \n\t\v") + 1] = 0;
+        * retstr[strrspn(retstr, " \n\t\v") + 1] = 0;
         */
        
        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
@@ -225,7 +244,7 @@ static char *strdup_substr(const char *str, int start, int end)
        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;
        char *match;
@@ -261,24 +280,31 @@ static void parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr)
        /* process the flags */
        while (substr[++idx]) {
                switch (substr[idx]) {
-               case 'g':
-                       sed_cmd->sub_g = 1;
-                       break;
-               case 'I':
-                       cflags |= REG_ICASE;
-                       break;
-               default:
-                       fatalError("bad option in substitution expression\n");
+                       case 'g':
+                               sed_cmd->sub_g = 1;
+                               break;
+                       case 'I':
+                               cflags |= REG_ICASE;
+                               break;
+                       default:
+                               /* 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 */
        sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t));
        xregcomp(sed_cmd->sub_match, match, cflags);
        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;
        char *ptr; /* shorthand */
@@ -322,7 +348,7 @@ static void parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr)
                        if (!ptr[idx]) {
                                ptr[idx] = '\n';
                                ptr[idx+1] = 0;
-                               return;
+                               return idx;
                        }
                }
                /* 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')
                        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;
 
@@ -344,6 +372,7 @@ static void parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr)
         *            part1 part2  part3
         */
 
+
        /* first part (if present) is an address: either a number or a /regex/ */
        if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/')
                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];
 
        /* special-case handling for (s)ubstitution */
-       if (sed_cmd->cmd == 's')
-               parse_subst_cmd(sed_cmd, &cmdstr[idx]);
-       
+       if (sed_cmd->cmd == 's') {
+               idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]);
+       }
        /* 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)
                        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)
 {
-       char *my_cmdstr = trim_str(cmdstr);
+       char *mystr = (char *)cmdstr;
 
-       /* if this is a comment, don't even bother */
-       if (my_cmdstr[0] == '#') {
-               free(my_cmdstr);
-               return;
-       }
+       do {
 
-       /* 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 */
-       parse_cmd_str(&sed_cmds[ncmds-1], my_cmdstr);
+               /* trim leading whitespace and semicolons */
+               memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr));
+               /* if we ate the whole thing, that means there was just trailing
+                * whitespace or a final semicolon. either way, get out */
+               if (strlen(mystr) == 0)
+                       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);
 }