sub.c revision 1297
178189Sbrian/* sub.c: This file contains the substitution routines for the ed
278189Sbrian   line editor */
378189Sbrian/*-
478189Sbrian * Copyright (c) 1993 Andrew Moore, Talke Studio.
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai */
2850479Speter
296059Samurai#ifndef lint
3078189Sbrianstatic char *rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
3143313Sbrian#endif /* not lint */
3230715Sbrian
3330715Sbrian#include "ed.h"
3430715Sbrian
3581634Sbrian
3636285Sbrianchar *rhbuf;			/* rhs substitution buffer */
3730715Sbrianint rhbufsz;			/* rhs substitution buffer size */
3831061Sbrianint rhbufi;			/* rhs substitution buffer index */
3949472Sbrian
4046686Sbrian/* extract_subst_tail: extract substitution tail from the command buffer */
4130715Sbrianint
4246686Sbrianextract_subst_tail(flagp, np)
4330715Sbrian	int *flagp;
4430715Sbrian	int *np;
4530715Sbrian{
466059Samurai	char delimiter;
4746686Sbrian
486059Samurai	*flagp = *np = 0;
4936285Sbrian	if ((delimiter = *ibufp) == '\n') {
506059Samurai		rhbufi = 0;
5136285Sbrian		*flagp = GPR;
5236285Sbrian		return 0;
5336285Sbrian	} else if (extract_subst_template() == NULL)
5481634Sbrian		return  ERR;
5581634Sbrian	else if (*ibufp == '\n') {
566059Samurai		*flagp = GPR;
5736285Sbrian		return 0;
5836285Sbrian	} else if (*ibufp == delimiter)
5936285Sbrian		ibufp++;
6036285Sbrian	if ('1' <= *ibufp && *ibufp <= '9') {
6136285Sbrian		STRTOL(*np, ibufp);
6236285Sbrian		return 0;
6343313Sbrian	} else if (*ibufp == 'g') {
6443313Sbrian		ibufp++;
6543313Sbrian		*flagp = GSG;
6681634Sbrian		return 0;
6781634Sbrian	}
6836285Sbrian	return 0;
6930715Sbrian}
706059Samurai
7128679Sbrian
726059Samurai/* extract_subst_template: return pointer to copy of substitution template
7346686Sbrian   in the command buffer */
7446686Sbrianchar *
7546686Sbrianextract_subst_template()
766059Samurai{
776059Samurai	int n = 0;
7845103Sbrian	int i = 0;
7936285Sbrian	char c;
806059Samurai	char delimiter = *ibufp++;
8154912Sbrian
8245103Sbrian	if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
8346686Sbrian		ibufp++;
8446686Sbrian		if (!rhbuf) sprintf(errmsg, "no previous substitution");
8545103Sbrian		return rhbuf;
8636285Sbrian	}
8736285Sbrian	while (*ibufp != delimiter) {
8846686Sbrian		REALLOC(rhbuf, rhbufsz, i + 2, NULL);
896059Samurai		if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
906059Samurai			i--, ibufp--;
916059Samurai			break;
9246686Sbrian		} else if (c != '\\')
936059Samurai			;
9446686Sbrian		else if ((rhbuf[i++] = *ibufp++) != '\n')
9547061Sbrian			;
9654912Sbrian		else if (!isglobal) {
976059Samurai			while ((n = get_tty_line()) == 0 ||
9846686Sbrian			    n > 0 && ibuf[n - 1] != '\n')
996059Samurai				clearerr(stdin);
10046686Sbrian			if (n < 0)
10147061Sbrian				return NULL;
10254912Sbrian		}
1036059Samurai	}
10446686Sbrian	REALLOC(rhbuf, rhbufsz, i + 1, NULL);
1056059Samurai	rhbuf[rhbufi = i] = '\0';
10647061Sbrian	return  rhbuf;
10754912Sbrian}
10846686Sbrian
1096059Samurai
11046686Sbrianchar *rbuf;			/* substitute_matching_text buffer */
11136285Sbrianint rbufsz;			/* substitute_matching_text buffer size */
11246686Sbrian
1136059Samurai/* search_and_replace: for each line in a range, change text matching a pattern
1146059Samurai   according to a substitution template; return status  */
1156059Samuraiint
11646828Sbriansearch_and_replace(pat, gflag, kth)
1176059Samurai	pattern_t *pat;
1186059Samurai	int gflag;
1196059Samurai	int kth;
12028679Sbrian{
1216059Samurai	undo_t *up;
12254912Sbrian	char *txt;
12354912Sbrian	char *eot;
1246059Samurai	long lc;
1256059Samurai	int nsubs = 0;
12628679Sbrian	line_t *lp;
12728679Sbrian	int len;
1286059Samurai
1296059Samurai	current_addr = first_addr - 1;
13036960Sbrian	for (lc = 0; lc <= second_addr - first_addr; lc++) {
13136960Sbrian		lp = get_addressed_line_node(++current_addr);
1326735Samurai		if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
13354912Sbrian			return ERR;
13432663Sbrian		else if (len) {
13547695Sbrian			up = NULL;
13654912Sbrian			if (delete_lines(current_addr, current_addr) < 0)
13746686Sbrian				return ERR;
1386059Samurai			txt = rbuf;
13928679Sbrian			eot = rbuf + len;
1406059Samurai			SPL1();
14128679Sbrian			do {
14293465Sbrian				if ((txt = put_sbuf_line(txt)) == NULL) {
14328679Sbrian					SPL0();
1446059Samurai					return ERR;
14528679Sbrian				} else if (up)
14628679Sbrian					up->t = get_addressed_line_node(current_addr);
1476059Samurai				else if ((up = push_undo_stack(UADD,
1486059Samurai				    current_addr, current_addr)) == NULL) {
14936285Sbrian					SPL0();
15036960Sbrian					return ERR;
15136960Sbrian				}
1526735Samurai			} while (txt != eot);
15354912Sbrian			SPL0();
15432663Sbrian			nsubs++;
1556735Samurai		}
1566059Samurai	}
1576059Samurai	if  (nsubs == 0 && !(gflag & GLB)) {
15854913Sbrian		sprintf(errmsg, "no match");
15954913Sbrian		return ERR;
16054912Sbrian	} else if ((gflag & (GPR | GLS | GNP)) &&
16154913Sbrian	    display_lines(current_addr, current_addr, gflag) < 0)
16254913Sbrian		return ERR;
1636059Samurai	return 0;
1646059Samurai}
16546686Sbrian
16646686Sbrian
16746686Sbrian/* substitute_matching_text: replace text matched by a pattern according to
1686059Samurai   a substitution template; return pointer to the modified text */
1696059Samuraiint
1706059Samuraisubstitute_matching_text(pat, lp, gflag, kth)
17146686Sbrian	pattern_t *pat;
1726059Samurai	line_t *lp;
1736059Samurai	int gflag;
17447061Sbrian	int kth;
1756059Samurai{
1766059Samurai	int off = 0;
1776059Samurai	int changed = 0;
17847061Sbrian	int matchno = 0;
1796059Samurai	int i = 0;
1806059Samurai	regmatch_t rm[SE_MAX];
18146686Sbrian	char *txt;
1826059Samurai	char *eot;
18346686Sbrian
18446686Sbrian	if ((txt = get_sbuf_line(lp)) == NULL)
18546686Sbrian		return ERR;
1866059Samurai	if (isbinary)
18731514Sbrian		NUL_TO_NEWLINE(txt, lp->len);
18831514Sbrian	eot = txt + lp->len;
18932439Sbrian	if (!regexec(pat, txt, SE_MAX, rm, 0)) {
19031514Sbrian		do {
19137010Sbrian			if (!kth || kth == ++matchno) {
19231514Sbrian				changed++;
19336285Sbrian				i = rm[0].rm_so;
19446686Sbrian				REALLOC(rbuf, rbufsz, off + i, ERR);
19546686Sbrian				if (isbinary)
19636285Sbrian					NEWLINE_TO_NUL(txt, rm[0].rm_eo);
19736285Sbrian				memcpy(rbuf + off, txt, i);
19831514Sbrian				off += i;
19931514Sbrian				if ((off = apply_subst_template(txt, rm, off,
20046686Sbrian				    pat->re_nsub)) < 0)
20146686Sbrian					return ERR;
202			} else {
203				i = rm[0].rm_eo;
204				REALLOC(rbuf, rbufsz, off + i, ERR);
205				if (isbinary)
206					NEWLINE_TO_NUL(txt, i);
207				memcpy(rbuf + off, txt, i);
208				off += i;
209			}
210			txt += rm[0].rm_eo;
211		} while (*txt && (!changed || (gflag & GSG) && rm[0].rm_eo) &&
212		    !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
213		i = eot - txt;
214		REALLOC(rbuf, rbufsz, off + i + 2, ERR);
215		if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
216			sprintf(errmsg, "infinite substitution loop");
217			return  ERR;
218		}
219		if (isbinary)
220			NEWLINE_TO_NUL(txt, i);
221		memcpy(rbuf + off, txt, i);
222		memcpy(rbuf + off + i, "\n", 2);
223	}
224	return changed ? off + i + 1 : 0;
225}
226
227
228/* apply_subst_template: modify text according to a substitution template;
229   return offset to end of modified text */
230int
231apply_subst_template(boln, rm, off, re_nsub)
232	char *boln;
233	regmatch_t *rm;
234	int off;
235	int re_nsub;
236{
237	int j = 0;
238	int k = 0;
239	int n;
240	char *sub = rhbuf;
241
242	for (; sub - rhbuf < rhbufi; sub++)
243		if (*sub == '&') {
244			j = rm[0].rm_so;
245			k = rm[0].rm_eo;
246			REALLOC(rbuf, rbufsz, off + k - j, ERR);
247			while (j < k)
248				rbuf[off++] = boln[j++];
249		} else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
250		    (n = *sub - '0') <= re_nsub) {
251			j = rm[n].rm_so;
252			k = rm[n].rm_eo;
253			REALLOC(rbuf, rbufsz, off + k - j, ERR);
254			while (j < k)
255				rbuf[off++] = boln[j++];
256		} else {
257			REALLOC(rbuf, rbufsz, off + 1, ERR);
258			rbuf[off++] = *sub;
259		}
260	REALLOC(rbuf, rbufsz, off + 1, ERR);
261	rbuf[off] = '\0';
262	return off;
263}
264