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