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.