/* regsub.c */ /* This file contains the regsub() function, which performs substitutions * after a regexp match has been found. */ #include #include #include #include "config.h" #include "vi.h" #include "regexp.h" static char *previous; /* a copy of the text from the previous substitution */ /* perform substitutions after a regexp match */ void regsub(re, src, dst) regexp *re; REG char *src; REG char *dst; { REG char *cpy; REG char *end; REG char c; char *start; #ifndef CRUNCH int mod; mod = 0; #endif 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 if (c == '~' && *o_magic) { cpy = previous; if (cpy) end = cpy + strlen(cpy); } 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; case '~': /* "\~" means "previous text, if any" */ if (*o_magic) { *dst++ = c; continue; } cpy = previous; if (cpy) end = cpy + strlen(cpy); break; #else /* NO_MAGIC */ case '&': /* "\&" means "original text" */ cpy = re->startp[0]; end = re->endp[0]; break; case '~': /* "\~" means "previous text, if any" */ cpy = previous; if (cpy) end = cpy + strlen(cpy); break; #endif /* NO_MAGIC */ default: /* ordinary char preceded by backslash */ *dst++ = c; continue; } } 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 */ if (isascii(*cpy) && islower(*cpy)) { *dst++ = toupper(*cpy); cpy++; } else { *dst++ = *cpy++; } break; case 'L': case 'l': /* convert to lowercase */ if (isascii(*cpy) && isupper(*cpy)) { *dst++ = tolower(*cpy); cpy++; } else { *dst++ = *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'; #ifndef NO_MAGIC /* Don't copy the pattern if it is '~'; leave previous copy alone */ if (! (*start == '~' && *o_magic)) { #endif /* remember what text we inserted this time */ if (previous) free(previous); previous = (char *)malloc((unsigned)(strlen(start) + 1)); if (previous) strcpy(previous, start); #ifndef NO_MAGIC } #endif }