Commits

Evan Gates  committed acca638

rework cmd_s a bit, and fix checking backreferences against groups when
using last regex

  • Participants
  • Parent commits 18599fe

Comments (0)

Files changed (1)

 Command *pop           (Vector *vec);
 size_t   push          (Vector *vec, Command *cmd);
 int      read_line     (char *buf, size_t size, FILE* file);
-int      sized_memcpy  (char *dest, char *src, size_t n, char *buf, size_t buf_size);
+int      sized_memcpy  (char **dest, char *src, size_t n, char *buf, size_t buf_size);
 void     strlcpy       (char *dest, char *src, size_t size);
 void     strlcat       (char *dest, char *src, size_t size);
 int      write_file    (char *in_path, FILE *out_stream);
     return noop;
 }
 
-// FIXME: check overflow on all the *(new++) =
 Action cmd_s(Command *cmd)
 {
     if (!in_range(cmd))
             qflag = 1;
         if ((last_empty || pmatch[0].rm_eo) &&  // don't subst if last match was not empty and this one is
             (++matches == cmd->occurrence || !cmd->occurrence)) {  // correct match or global
-            unsigned escape = 0;
-
             // copy over everything before the match
-            if (sized_memcpy(new, str, pmatch[0].rm_so, buf, sizeof(buf)))
+            if (sized_memcpy(&new, str, pmatch[0].rm_so, buf, sizeof(buf)))
                 break;
-            new += pmatch[0].rm_so;
-            for (char *p = cmd->text; *p; p++) {
-                if (escape) {
-                    escape = 0;
-                    if (isdigit(*p)) { // backreference
-                        regmatch_t *rm  = &pmatch[*p - '0'];
-                        if (rm->rm_so != -1) {
-                            size_t len = rm->rm_eo - rm->rm_so;
-                            if (sized_memcpy(new, str + rm->rm_so, len, buf, sizeof(buf)))
-                                break;
-                            new += len;
-                        }
-                    } else
-                        *(new++) = *p; // now non special character
-                } else switch (*p) {
-                    default  : *(new++) = *p; break;
-                    case '\\': escape = 1;    break;
-                    case '&' :
-                    { // insert matched text
-                        regmatch_t *rm  = pmatch;
-                        size_t      len = rm->rm_eo - rm->rm_so;
-                        if (sized_memcpy(new, str + rm->rm_so, len, buf, sizeof(buf)))
-                            break;
-                        new += len;
-                        break;
-                    }
+
+            size_t len;
+            for (char *p = cmd->text; (len = strcspn(p, "\\&")) || *p; ++p) {
+                if (sized_memcpy(&new, p, len, buf, sizeof(buf)))
+                    break;
+                p += len;
+                switch(*p) {
+                default  : --p; break;
+                case '\\': if (isdigit(*++p)) {
+                               if ((size_t)(*p - '0') > re->re_nsub)
+                                   warn("back reference number (%c) greater than number of groups (%zu)",
+                                           *p, re->re_nsub);
+
+                               regmatch_t *rm = &pmatch[*p - '0'];
+                               if (rm->rm_so != -1)
+                                   sized_memcpy(&new, str + rm->rm_so, rm->rm_eo - rm->rm_so, buf, sizeof(buf));
+                           } else
+                               sized_memcpy(&new, p, 1, buf, sizeof(buf));
+                           break;
+                case '&' : sized_memcpy(&new, str + pmatch->rm_so, pmatch->rm_eo - pmatch->rm_so, buf, sizeof(buf));
+                           break;
                 }
             }
         } else {
             // copy over everything including the match
-            if (sized_memcpy(new, str, pmatch[0].rm_eo, buf, sizeof(buf)))
+            if (sized_memcpy(&new, str, pmatch[0].rm_eo, buf, sizeof(buf)))
                 break;
-            new += pmatch[0].rm_eo;
         }
         if (!pmatch[0].rm_eo)    // both this and last match were empty
             *(new++) = *(str++); // advance one character, add it to output
     if (!matches)
         return noop;
 
-    sized_memcpy(new, str, strlen(str) + 1, buf, sizeof(buf));
+    sized_memcpy(&new, str, strlen(str) + 1, buf, sizeof(buf));
     strlcpy(patt_space, buf, SPACE_BYTES);
     if (cmd->flag_p && check_puts(patt_space, stdout))
         return error;
     for (int escape = 0; *q; q++) {
         if (escape) {
             escape = 0;
-            if (isdigit(*q) && (size_t)('0' - *q) > cmd->regex->re_nsub) {
+            if (isdigit(*q) && !cmd->last_regex && (size_t)(*q - '0') > cmd->regex->re_nsub) {
                 warn("back reference number (%c) greater than number of groups (%zu)",
                      *q, cmd->regex->re_nsub);
                 return NULL;
 
 // memcpy from src to dest min(n, buf_size - (dest - buf)), warn if truncating
 // dest is a pointer to a location inside buf (i.e. dest - buf <= buf_size)
-int sized_memcpy(char *dest, char *src, size_t n, char *buf, size_t buf_size)
+int sized_memcpy(char **dest, char *src, size_t n, char *buf, size_t buf_size)
 {
+    // set to pc and only warn about truncating once per command
+    static Command *cmd = NULL;
     int ret = 0;
 
-    if (dest - buf + n > buf_size) {
-        warn("truncating pattern space to %zu bytes", buf_size);
-        n   = buf_size - (dest - buf);
+    if (*dest - buf + n > buf_size) {
+        if (cmd != pc)
+            warn("truncating pattern space to %zu bytes", buf_size);
+        n   = buf_size - (*dest - buf);
         ret = -1;
     }
-    memcpy(dest, src, n);
+    memcpy(*dest, src, n);
+    *dest += n;
+    cmd    = pc;
     return ret;
 }