244 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* 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';
 | 
						|
}
 |