NetBSD/usr.bin/elvis/regsub.c
1993-03-21 09:45:37 +00:00

244 lines
4.7 KiB
C

/* 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';
}