sub.c revision 99109
159769Sgrog/* sub.c: This file contains the substitution routines for the ed
259769Sgrog   line editor */
324424Swosch/*-
424424Swosch * Copyright (c) 1993 Andrew Moore, Talke Studio.
524424Swosch * All rights reserved.
624424Swosch *
724424Swosch * Redistribution and use in source and binary forms, with or without
824424Swosch * modification, are permitted provided that the following conditions
924424Swosch * are met:
1024424Swosch * 1. Redistributions of source code must retain the above copyright
1124424Swosch *    notice, this list of conditions and the following disclaimer.
1224424Swosch * 2. Redistributions in binary form must reproduce the above copyright
1324424Swosch *    notice, this list of conditions and the following disclaimer in the
1424424Swosch *    documentation and/or other materials provided with the distribution.
1542704Swosch *
1642704Swosch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1742704Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1824424Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1942704Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2042704Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2142704Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2242704Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2342704Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2442704Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2542704Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2642704Swosch * SUCH DAMAGE.
2742704Swosch */
2842704Swosch
2942704Swosch#include <sys/cdefs.h>
3059769Sgrog__FBSDID("$FreeBSD: head/bin/ed/sub.c 99109 2002-06-30 05:13:54Z obrien $");
3159769Sgrog
3259769Sgrog#include "ed.h"
3359769Sgrog
3459769Sgrog
3559769Sgrogchar *rhbuf;			/* rhs substitution buffer */
3659769Sgrogint rhbufsz;			/* rhs substitution buffer size */
3759769Sgrogint rhbufi;			/* rhs substitution buffer index */
3859769Sgrog
3924424Swosch/* extract_subst_tail: extract substitution tail from the command buffer */
4042704Swoschint
4124424Swoschextract_subst_tail(int *flagp, long *np)
4242704Swosch{
4324424Swosch	char delimiter;
4442704Swosch
4524424Swosch	*flagp = *np = 0;
4624424Swosch	if ((delimiter = *ibufp) == '\n') {
4724424Swosch		rhbufi = 0;
4842704Swosch		*flagp = GPR;
4925031Swosch		return 0;
5059156Swosch	} else if (extract_subst_template() == NULL)
5125031Swosch		return  ERR;
5225031Swosch	else if (*ibufp == '\n') {
5324424Swosch		*flagp = GPR;
5424424Swosch		return 0;
5524424Swosch	} else if (*ibufp == delimiter)
5624424Swosch		ibufp++;
5771231Sitojun	if ('1' <= *ibufp && *ibufp <= '9') {
5824424Swosch		STRTOL(*np, ibufp);
5971231Sitojun		return 0;
6025031Swosch	} else if (*ibufp == 'g') {
6171231Sitojun		ibufp++;
6224424Swosch		*flagp = GSG;
6325031Swosch		return 0;
6425031Swosch	}
6571231Sitojun	return 0;
6625031Swosch}
6771231Sitojun
6870110Swosch
6970110Swosch/* extract_subst_template: return pointer to copy of substitution template
7070110Swosch   in the command buffer */
7170110Swoschchar *
7270110Swoschextract_subst_template(void)
7370110Swosch{
7470110Swosch	int n = 0;
7570110Swosch	int i = 0;
7670110Swosch	char c;
7770110Swosch	char delimiter = *ibufp++;
7870110Swosch
7980675Sasmodai	if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
8080675Sasmodai		ibufp++;
8180675Sasmodai		if (!rhbuf)
8280675Sasmodai			errmsg = "no previous substitution";
8380675Sasmodai		return rhbuf;
8480675Sasmodai	}
8580675Sasmodai	while (*ibufp != delimiter) {
8680675Sasmodai		REALLOC(rhbuf, rhbufsz, i + 2, NULL);
8780675Sasmodai		if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
8880675Sasmodai			i--, ibufp--;
8980675Sasmodai			break;
9080675Sasmodai		} else if (c != '\\')
9180675Sasmodai			;
9280675Sasmodai		else if ((rhbuf[i++] = *ibufp++) != '\n')
9380675Sasmodai			;
9480675Sasmodai		else if (!isglobal) {
9580675Sasmodai			while ((n = get_tty_line()) == 0 ||
9680675Sasmodai			    (n > 0 && ibuf[n - 1] != '\n'))
9780675Sasmodai				clearerr(stdin);
9880675Sasmodai			if (n < 0)
9980675Sasmodai				return NULL;
10080675Sasmodai		}
10180675Sasmodai	}
10280675Sasmodai	REALLOC(rhbuf, rhbufsz, i + 1, NULL);
10380675Sasmodai	rhbuf[rhbufi = i] = '\0';
10480675Sasmodai	return  rhbuf;
10580675Sasmodai}
10680675Sasmodai
10780675Sasmodai
10880675Sasmodaichar *rbuf;			/* substitute_matching_text buffer */
10980675Sasmodaiint rbufsz;			/* substitute_matching_text buffer size */
11080675Sasmodai
11180675Sasmodai/* search_and_replace: for each line in a range, change text matching a pattern
11280675Sasmodai   according to a substitution template; return status  */
11380675Sasmodaiint
11480675Sasmodaisearch_and_replace(pattern_t *pat, int gflag, int kth)
11580675Sasmodai{
11680675Sasmodai	undo_t *up;
11780675Sasmodai	const char *txt;
11880675Sasmodai	const char *eot;
11980675Sasmodai	long lc;
12080675Sasmodai	long xa = current_addr;
12180675Sasmodai	int nsubs = 0;
12280675Sasmodai	line_t *lp;
12380675Sasmodai	int len;
12480675Sasmodai
12580675Sasmodai	current_addr = first_addr - 1;
12680675Sasmodai	for (lc = 0; lc <= second_addr - first_addr; lc++) {
12780675Sasmodai		lp = get_addressed_line_node(++current_addr);
12880675Sasmodai		if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
12980675Sasmodai			return ERR;
13080675Sasmodai		else if (len) {
13180675Sasmodai			up = NULL;
13280675Sasmodai			if (delete_lines(current_addr, current_addr) < 0)
13380675Sasmodai				return ERR;
13480675Sasmodai			txt = rbuf;
13580675Sasmodai			eot = rbuf + len;
13680675Sasmodai			SPL1();
13780675Sasmodai			do {
138101401Swosch				if ((txt = put_sbuf_line(txt)) == NULL) {
13980675Sasmodai					SPL0();
140147593Shrs					return ERR;
14187200Swosch				} else if (up)
142147593Shrs					up->t = get_addressed_line_node(current_addr);
14380675Sasmodai				else if ((up = push_undo_stack(UADD,
144104772Smaxim				    current_addr, current_addr)) == NULL) {
145104772Smaxim					SPL0();
146104772Smaxim					return ERR;
147104772Smaxim				}
148104781Sjhb			} while (txt != eot);
149104781Sjhb			SPL0();
150104781Sjhb			nsubs++;
151104781Sjhb			xa = current_addr;
152104781Sjhb		}
153104781Sjhb	}
154119217Smurray	current_addr = xa;
155147593Shrs	if  (nsubs == 0 && !(gflag & GLB)) {
156147593Shrs		errmsg = "no match";
157119217Smurray		return ERR;
158119217Smurray	} else if ((gflag & (GPR | GLS | GNP)) &&
159119217Smurray	    display_lines(current_addr, current_addr, gflag) < 0)
160119217Smurray		return ERR;
161132652Sosa	return 0;
162132652Sosa}
163132652Sosa
164132652Sosa
165132652Sosa/* substitute_matching_text: replace text matched by a pattern according to
166132652Sosa   a substitution template; return pointer to the modified text */
167132652Sosaint
168132652Sosasubstitute_matching_text(pattern_t *pat, line_t *lp, int gflag, int kth)
169132652Sosa{
170132652Sosa	int off = 0;
171140831Smaxim	int changed = 0;
172140831Smaxim	int matchno = 0;
173132652Sosa	int i = 0;
174132652Sosa	regmatch_t rm[SE_MAX];
175132652Sosa	char *txt;
176132652Sosa	char *eot;
177137120Smaxim
178132652Sosa	if ((txt = get_sbuf_line(lp)) == NULL)
179132652Sosa		return ERR;
180132652Sosa	if (isbinary)
181132652Sosa		NUL_TO_NEWLINE(txt, lp->len);
182132652Sosa	eot = txt + lp->len;
183132652Sosa	if (!regexec(pat, txt, SE_MAX, rm, 0)) {
184132652Sosa		do {
185158916Smaxim			if (!kth || kth == ++matchno) {
186158916Smaxim				changed++;
187158916Smaxim				i = rm[0].rm_so;
188158916Smaxim				REALLOC(rbuf, rbufsz, off + i, ERR);
189158916Smaxim				if (isbinary)
190158916Smaxim					NEWLINE_TO_NUL(txt, rm[0].rm_eo);
191158916Smaxim				memcpy(rbuf + off, txt, i);
192158916Smaxim				off += i;
193158916Smaxim				if ((off = apply_subst_template(txt, rm, off,
194158916Smaxim				    pat->re_nsub)) < 0)
195158916Smaxim					return ERR;
196158916Smaxim			} else {
197158916Smaxim				i = rm[0].rm_eo;
198158916Smaxim				REALLOC(rbuf, rbufsz, off + i, ERR);
199158916Smaxim				if (isbinary)
200158916Smaxim					NEWLINE_TO_NUL(txt, i);
201160663Smaxim				memcpy(rbuf + off, txt, i);
202160663Smaxim				off += i;
203160663Smaxim			}
204160663Smaxim			txt += rm[0].rm_eo;
205160663Smaxim		} while (*txt &&
206160663Smaxim                        (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
207160663Smaxim		        !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
208152003Smaxim		i = eot - txt;
209152003Smaxim		REALLOC(rbuf, rbufsz, off + i + 2, ERR);
210132652Sosa		if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
21124424Swosch			errmsg = "infinite substitution loop";
21224424Swosch			return  ERR;
21324424Swosch		}
21424424Swosch		if (isbinary)
21569277Sasmodai			NEWLINE_TO_NUL(txt, i);
21669277Sasmodai		memcpy(rbuf + off, txt, i);
21724424Swosch		memcpy(rbuf + off + i, "\n", 2);
21825031Swosch	}
21925031Swosch	return changed ? off + i + 1 : 0;
22025031Swosch}
22180675Sasmodai
222104782Sjhb
223144864Smaxim/* apply_subst_template: modify text according to a substitution template;
22425031Swosch   return offset to end of modified text */
225104782Sjhbint
226104782Sjhbapply_subst_template(const char *boln, regmatch_t *rm, int off, int re_nsub)
227104782Sjhb{
228104797Sjhb	int j = 0;
229104797Sjhb	int k = 0;
23025031Swosch	int n;
23125031Swosch	char *sub = rhbuf;
23225031Swosch
23345349Swosch	for (; sub - rhbuf < rhbufi; sub++)
23445349Swosch		if (*sub == '&') {
235104782Sjhb			j = rm[0].rm_so;
236104782Sjhb			k = rm[0].rm_eo;
237104782Sjhb			REALLOC(rbuf, rbufsz, off + k - j, ERR);
238104782Sjhb			while (j < k)
23942704Swosch				rbuf[off++] = boln[j++];
24025031Swosch		} else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
24124424Swosch		    (n = *sub - '0') <= re_nsub) {
24259769Sgrog			j = rm[n].rm_so;
24325031Swosch			k = rm[n].rm_eo;
24425031Swosch			REALLOC(rbuf, rbufsz, off + k - j, ERR);
24525031Swosch			while (j < k)
24625031Swosch				rbuf[off++] = boln[j++];
24759769Sgrog		} else {
24825031Swosch			REALLOC(rbuf, rbufsz, off + 1, ERR);
24925031Swosch			rbuf[off++] = *sub;
25025031Swosch		}
25125031Swosch	REALLOC(rbuf, rbufsz, off + 1, ERR);
25224424Swosch	rbuf[off] = '\0';
25325031Swosch	return off;
25425031Swosch}
25525031Swosch