This is regsub.c in view mode; [Download] [Up]
/* regsub.c */ /* This file contains the regsub() function, which performs substitutions * after a regexp match has been found. */ #include "elvis.h" /* Allocate a new copy of the replacement string, with all ~'s replaced by * the previous replacement string. * * NOTE: The value returned by this function should never be freed from outside * this function, because this function maintains an internal pointer to the * same memory so it knows what value to substitute for ~ on next invocation. */ CHAR *regtilde(newp) CHAR *newp; /* new text as supplied by user */ { static CHAR *prev; /* previous replacement text */ CHAR *ret; /* returned string */ CHAR *scan; /* used for stepping through chars of "prev" */ /* copy new into ret, replacing the ~s by the previous text */ for (ret = NULL; *newp; ) { if (o_magic && *newp == '~') { if (!prev) goto Fail; for (scan = prev; *scan; scan++) buildCHAR(&ret, *scan); newp++; } else if (!o_magic && *newp == '\\' && *(newp + 1) == '~') { if (!prev) goto Fail; for (scan = prev; *scan; scan++) buildCHAR(&ret, *scan); newp += 2; } else { if (*newp == '\\' && *(newp + 1)) { buildCHAR(&ret, *newp++); } buildCHAR(&ret, *newp++); } } /* if empty string, then allocate a single '\0' character */ if (!ret) ret = safealloc(1, sizeof(CHAR)); /* remember this as the "previous" for next time */ if (prev) safefree(prev); prev = ret; return ret; Fail: msg(MSG_ERROR, "no previous text to substitute for ~"); if (ret) safefree(ret); return NULL; } /* Perform substitutions after a regexp match. "re" is the compiled regular * expression which has been matched to a text string. "new" is a pointer to * the replacement text string. Return the actual replacement text (after all * metacharacters have been processed) if successful, or NULL if error. The * calling function is responsible for calling safefree() on the returned * string. */ CHAR *regsub(re, newp, doit) regexp *re; /* a regular expression that has been matched */ REG CHAR *newp; /* the replacement text */ BOOLEAN doit; /* perform the substitution? (else just return string) */ { MARKBUF cpy; /* start of text to copy */ long end; /* length of text to copy */ REG CHAR c; /* a character from "new" text */ long cval; /* numeric value of 'c', if 'c' is digit */ CHAR *inst; /* the new next, after processing escapes */ int mod = 0;/* used to track \U, \L, \u, \l, and \E */ int len; /* used to calculate length of subst string */ MARKBUF tmp; /* end of replacement region */ CHAR *scan; /* used for scanning a segment of orig text */ /* initialize "cval" just to silence a compiler warning */ cval = 0; /* for each character of the new text... */ for (inst = NULL, len = 0; (c = *newp++) != '\0'; ) { /* recognize any meta characters */ if (c == '&' && o_magic) { (void)marktmp(cpy, re->buffer, re->startp[0]); end = re->endp[0] - re->startp[0]; } else if (c == '\\') { c = *newp++; switch (c) { 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" */ cval = c - '0'; (void)marktmp(cpy, re->buffer, re->startp[cval]); end = re->endp[cval] - re->startp[cval]; break; 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; case '&': /* "\&" means "original text" */ if (o_magic) { len = buildCHAR(&inst, c); continue; } (void)marktmp(cpy, re->buffer, re->startp[0]); end = re->endp[0] - re->startp[0]; break; default: /* ordinary char preceded by backslash */ len = buildCHAR(&inst, c); continue; } } # if OSK else if (c == '\l') # else else if (c == '\r') # endif { /* transliterate ^M into newline */ len = buildCHAR(&inst, '\n'); continue; } else { /* ordinary character, so just copy it */ len = buildCHAR(&inst, c); continue; } /* Note: to reach this point in the code, we 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 (markoffset(&cpy) < 0) { msg(MSG_ERROR, "[d]too few \\\\\\(\\\\\\)s to use \\\\$1", cval); if (inst) safefree(inst); return NULL; } /* copy over a portion of the original */ for (scanalloc(&scan, &cpy); scan && end > 0; scannext(&scan), end--) { switch (mod) { case 'U': case 'u': /* convert to uppercase */ len = buildCHAR(&inst, (_CHAR_)toupper(*scan)); break; case 'L': case 'l': /* convert to lowercase */ len = buildCHAR(&inst, (_CHAR_)tolower(*scan)); break; default: /* copy without any conversion */ len = buildCHAR(&inst, *scan); } /* \u and \l end automatically after the first char */ if (mod == 'u' || mod == 'l') { mod = 0; } } scanfree(&scan); } /* if we're supposed to perform the substitution, then do it */ if (doit) { /* replace the old text with the new text in the buffer */ bufreplace(marktmp(cpy, re->buffer, re->startp[0]), marktmp(tmp, re->buffer, re->endp[0]), inst, len); /* Adjust the offset of the end of the whole expression * to compensate for the change in the length of text. * Also, if this regexp could conceivably match a * zero-length string, then require at least 1 unmatched * character between matches. */ re->endp[0] = re->startp[0] + len; if (re->minlen == 0 && re->endp[0] < o_bufchars(re->buffer) && scanchar(marktmp(tmp, re->buffer, re->endp[0])) != '\n') { re->endp[0]++; } } /* At this point, we know we were successful but the "inst" pointer * will be NULL if the replacement text is 0 characters long. We don't * want to return NULL for a successful substitution, so allocate * a string which contains only a '\0' character and return that. */ if (!inst) { assert(len == 0); buildCHAR(&inst, (_CHAR_)'\0'); assert(inst != NULL); } return inst; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.