/* regsub.c */ /* This file contains the regsub() function, which performs substitutions * after a regexp match has been found. */ #include "config.h" #include "ctype.h" #include "vi.h" #include "regexp.h" /* perform substitutions after a regexp match */ void regsub(re, src, dst) regexp *re; /* the regexp with pointers into matched text */ REG char *src; /* the replacement string */ REG char *dst; /* where to put the result of the subst */ { REG char *cpy; /* pointer to start of text to copy */ REG char *end; /* pointer to end of text to copy */ REG char c; char *start; #ifndef CRUNCH int mod = 0;/* used to track \U, \L, \u, \l, and \E */ int len; /* used to calculate length of subst string */ static char *prev; /* a copy of the text from the previous subst */ /* replace \~ (or maybe ~) by previous substitution text */ /* step 1: calculate the length of the new substitution text */ for (len = strlen(src), c = '\0', cpy = src; *cpy; cpy++) { # ifdef NO_MAGIC if (c == '\\' && *cpy == '~') # else if (c == (*o_magic ? '\0' : '\\') && *cpy == '~') # endif { if (!prev) { regerror("No prev text to substitute for ~"); return; } len += strlen(prev) - 1; # ifndef NO_MAGIC if (!*o_magic) # endif len -= 1; /* because we lose the \ too */ } /* watch backslash quoting */ if (c != '\\' && *cpy == '\\') c = '\\'; else c = '\0'; } /* allocate memory for the ~ed version of src */ start = cpy = (char *)malloc((unsigned)(len + 1)); if (!cpy) { regerror("Not enough memory for ~ expansion"); return; } /* copy src into start, replacing the ~s by the previous text */ while (*src) { # ifndef NO_MAGIC if (*o_magic && *src == '~') { strcpy(cpy, prev); cpy += strlen(prev); src++; } else if (!*o_magic && *src == '\\' && *(src + 1) == '~') # else /* NO_MAGIC */ if (*src == '\\' && *(src + 1) == '~') # endif /* NO_MAGIC */ { strcpy(cpy, prev); cpy += strlen(prev); src += 2; } else { *cpy++ = *src++; } } *cpy = '\0'; #ifdef DEBUG if ((int)(cpy - start) != len) { msg("Bug in regsub.c! Predicted length = %d, Actual length = %d", len, (int)(cpy - start)); } #endif /* remember this as the "previous" for next time */ if (prev) free(prev); prev = src = start; #endif /* undef CRUNCH */ start = src; while ((c = *src++) != '\0') { #ifndef NO_MAGIC /* recognize any meta characters */ if (c == '&' && *o_magic) { cpy = re->startp[0]; end = re->endp[0]; } else #endif /* not NO_MAGIC */ if (c == '\\') { c = *src++; switch (c) { #ifndef NO_MAGIC case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* \0 thru \9 mean "copy subexpression" */ c -= '0'; cpy = re->startp[c]; end = re->endp[c]; break; # ifndef CRUNCH case 'U': case 'u': case 'L': case 'l': /* \U and \L mean "convert to upper/lowercase" */ mod = c; continue; case 'E': case 'e': /* \E ends the \U or \L */ mod = 0; continue; # endif /* not CRUNCH */ case '&': /* "\&" means "original text" */ if (*o_magic) { *dst++ = c; continue; } cpy = re->startp[0]; end = re->endp[0]; break; #else /* NO_MAGIC */ case '&': /* "\&" means "original text" */ cpy = re->startp[0]; end = re->endp[0]; break; #endif /* NO_MAGIC */ default: /* ordinary char preceded by backslash */ *dst++ = c; continue; } } #ifndef CRUNCH # if OSK else if (c == '\l') # else else if (c == '\r') # endif { /* transliterate ^M into newline */ *dst++ = '\n'; continue; } #endif /* !CRUNCH */ else { /* ordinary character, so just copy it */ *dst++ = c; continue; } /* Note: to reach this point in the code, we must have evaded * all "continue" statements. To do that, we must have hit * a metacharacter that involves copying. */ /* if there is nothing to copy, loop */ if (!cpy) continue; /* copy over a portion of the original */ while (cpy < end) { #ifndef NO_MAGIC # ifndef CRUNCH switch (mod) { case 'U': case 'u': /* convert to uppercase */ *dst++ = toupper(*cpy++); break; case 'L': case 'l': /* convert to lowercase */ *dst++ = tolower(*cpy++); break; default: /* copy without any conversion */ *dst++ = *cpy++; } /* \u and \l end automatically after the first char */ if (mod && (mod == 'u' || mod == 'l')) { mod = 0; } # else /* CRUNCH */ *dst++ = *cpy++; # endif /* CRUNCH */ #else /* NO_MAGIC */ *dst++ = *cpy++; #endif /* NO_MAGIC */ } } *dst = '\0'; }