sub.c revision 3044
1/* sub.c: This file contains the substitution routines for the ed
2   line editor */
3/*-
4 * Copyright (c) 1993 Andrew Moore, Talke Studio.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *	$Id$
29 */
30
31#ifndef lint
32static char *rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
33#endif /* not lint */
34
35#include "ed.h"
36
37
38char *rhbuf;			/* rhs substitution buffer */
39int rhbufsz;			/* rhs substitution buffer size */
40int rhbufi;			/* rhs substitution buffer index */
41
42/* extract_subst_tail: extract substitution tail from the command buffer */
43int
44extract_subst_tail(flagp, np)
45	int *flagp;
46	int *np;
47{
48	char delimiter;
49
50	*flagp = *np = 0;
51	if ((delimiter = *ibufp) == '\n') {
52		rhbufi = 0;
53		*flagp = GPR;
54		return 0;
55	} else if (extract_subst_template() == NULL)
56		return  ERR;
57	else if (*ibufp == '\n') {
58		*flagp = GPR;
59		return 0;
60	} else if (*ibufp == delimiter)
61		ibufp++;
62	if ('1' <= *ibufp && *ibufp <= '9') {
63		STRTOL(*np, ibufp);
64		return 0;
65	} else if (*ibufp == 'g') {
66		ibufp++;
67		*flagp = GSG;
68		return 0;
69	}
70	return 0;
71}
72
73
74/* extract_subst_template: return pointer to copy of substitution template
75   in the command buffer */
76char *
77extract_subst_template()
78{
79	int n = 0;
80	int i = 0;
81	char c;
82	char delimiter = *ibufp++;
83
84	if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
85		ibufp++;
86		if (!rhbuf) sprintf(errmsg, "no previous substitution");
87		return rhbuf;
88	}
89	while (*ibufp != delimiter) {
90		REALLOC(rhbuf, rhbufsz, i + 2, NULL);
91		if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
92			i--, ibufp--;
93			break;
94		} else if (c != '\\')
95			;
96		else if ((rhbuf[i++] = *ibufp++) != '\n')
97			;
98		else if (!isglobal) {
99			while ((n = get_tty_line()) == 0 ||
100			    n > 0 && ibuf[n - 1] != '\n')
101				clearerr(stdin);
102			if (n < 0)
103				return NULL;
104		}
105	}
106	REALLOC(rhbuf, rhbufsz, i + 1, NULL);
107	rhbuf[rhbufi = i] = '\0';
108	return  rhbuf;
109}
110
111
112char *rbuf;			/* substitute_matching_text buffer */
113int rbufsz;			/* substitute_matching_text buffer size */
114
115/* search_and_replace: for each line in a range, change text matching a pattern
116   according to a substitution template; return status  */
117int
118search_and_replace(pat, gflag, kth)
119	pattern_t *pat;
120	int gflag;
121	int kth;
122{
123	undo_t *up;
124	char *txt;
125	char *eot;
126	long lc;
127	int nsubs = 0;
128	line_t *lp;
129	int len;
130
131	current_addr = first_addr - 1;
132	for (lc = 0; lc <= second_addr - first_addr; lc++) {
133		lp = get_addressed_line_node(++current_addr);
134		if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
135			return ERR;
136		else if (len) {
137			up = NULL;
138			if (delete_lines(current_addr, current_addr) < 0)
139				return ERR;
140			txt = rbuf;
141			eot = rbuf + len;
142			SPL1();
143			do {
144				if ((txt = put_sbuf_line(txt)) == NULL) {
145					SPL0();
146					return ERR;
147				} else if (up)
148					up->t = get_addressed_line_node(current_addr);
149				else if ((up = push_undo_stack(UADD,
150				    current_addr, current_addr)) == NULL) {
151					SPL0();
152					return ERR;
153				}
154			} while (txt != eot);
155			SPL0();
156			nsubs++;
157		}
158	}
159	if  (nsubs == 0 && !(gflag & GLB)) {
160		sprintf(errmsg, "no match");
161		return ERR;
162	} else if ((gflag & (GPR | GLS | GNP)) &&
163	    display_lines(current_addr, current_addr, gflag) < 0)
164		return ERR;
165	return 0;
166}
167
168
169/* substitute_matching_text: replace text matched by a pattern according to
170   a substitution template; return pointer to the modified text */
171int
172substitute_matching_text(pat, lp, gflag, kth)
173	pattern_t *pat;
174	line_t *lp;
175	int gflag;
176	int kth;
177{
178	int off = 0;
179	int changed = 0;
180	int matchno = 0;
181	int i = 0;
182	regmatch_t rm[SE_MAX];
183	char *txt;
184	char *eot;
185
186	if ((txt = get_sbuf_line(lp)) == NULL)
187		return ERR;
188	if (isbinary)
189		NUL_TO_NEWLINE(txt, lp->len);
190	eot = txt + lp->len;
191	if (!regexec(pat, txt, SE_MAX, rm, 0)) {
192		do {
193			if (!kth || kth == ++matchno) {
194				changed++;
195				i = rm[0].rm_so;
196				REALLOC(rbuf, rbufsz, off + i, ERR);
197				if (isbinary)
198					NEWLINE_TO_NUL(txt, rm[0].rm_eo);
199				memcpy(rbuf + off, txt, i);
200				off += i;
201				if ((off = apply_subst_template(txt, rm, off,
202				    pat->re_nsub)) < 0)
203					return ERR;
204			} else {
205				i = rm[0].rm_eo;
206				REALLOC(rbuf, rbufsz, off + i, ERR);
207				if (isbinary)
208					NEWLINE_TO_NUL(txt, i);
209				memcpy(rbuf + off, txt, i);
210				off += i;
211			}
212			txt += rm[0].rm_eo;
213		} while (*txt && (!changed || (gflag & GSG) && rm[0].rm_eo) &&
214		    !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
215		i = eot - txt;
216		REALLOC(rbuf, rbufsz, off + i + 2, ERR);
217		if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
218			sprintf(errmsg, "infinite substitution loop");
219			return  ERR;
220		}
221		if (isbinary)
222			NEWLINE_TO_NUL(txt, i);
223		memcpy(rbuf + off, txt, i);
224		memcpy(rbuf + off + i, "\n", 2);
225	}
226	return changed ? off + i + 1 : 0;
227}
228
229
230/* apply_subst_template: modify text according to a substitution template;
231   return offset to end of modified text */
232int
233apply_subst_template(boln, rm, off, re_nsub)
234	char *boln;
235	regmatch_t *rm;
236	int off;
237	int re_nsub;
238{
239	int j = 0;
240	int k = 0;
241	int n;
242	char *sub = rhbuf;
243
244	for (; sub - rhbuf < rhbufi; sub++)
245		if (*sub == '&') {
246			j = rm[0].rm_so;
247			k = rm[0].rm_eo;
248			REALLOC(rbuf, rbufsz, off + k - j, ERR);
249			while (j < k)
250				rbuf[off++] = boln[j++];
251		} else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
252		    (n = *sub - '0') <= re_nsub) {
253			j = rm[n].rm_so;
254			k = rm[n].rm_eo;
255			REALLOC(rbuf, rbufsz, off + k - j, ERR);
256			while (j < k)
257				rbuf[off++] = boln[j++];
258		} else {
259			REALLOC(rbuf, rbufsz, off + 1, ERR);
260			rbuf[off++] = *sub;
261		}
262	REALLOC(rbuf, rbufsz, off + 1, ERR);
263	rbuf[off] = '\0';
264	return off;
265}
266