1 /* @(#)substcmds.c	1.23 09/07/09 Copyright 1986-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)substcmds.c	1.23 09/07/09 Copyright 1986-2009 J. Schilling";
6 #endif
7 /*
8  *	Substitution commands called from ECS : command line
9  *
10  *	Copyright (c) 1986-2009 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include "ved.h"
27 
28 #define	OLDSIZE	4096
29 
30 #define	iswhite(c)	((c) == ' ' || (c) == '\t')
31 
32 LOCAL	BOOL	subverbose;
33 
34 EXPORT	void	subst		__PR((ewin_t *wp, Uchar* cmd, int cmdlen));
35 LOCAL	void	substitute	__PR((ewin_t *wp, Uchar* from, long fromlen, Uchar* to, long tolen));
36 LOCAL	BOOL	simpleto	__PR((Uchar* s, long len));
37 LOCAL	void	catsub		__PR((ewin_t *wp, Uchar* old, long oldlen, Uchar* to, long tolen));
38 
39 /*
40  * This is the external callable subsitution command routine.
41  * It parses the command line and then calls the 'real' substitution command.
42  * Syntax is: ESC: sub /old/new/v
43  */
44 EXPORT void
subst(wp,cmd,cmdlen)45 subst(wp, cmd, cmdlen)
46 	ewin_t	*wp;
47 	Uchar	*cmd;
48 	int	cmdlen;
49 {
50 	register Uchar	*from;
51 	register Uchar	*to;
52 	register Uchar	*cp;
53 	register Uchar	*endp;
54 	register Uchar	c = '/';
55 	register Uchar	dc;
56 		long	fromlen;
57 		long	tolen;
58 
59 	from = cmd;
60 	endp = &cmd[cmdlen];
61 
62 	while (from < endp) {
63 		c = *from;
64 		if (iswhite(c))
65 			from++;
66 		else
67 			break;
68 	}
69 	dc = c;
70 	to = ++from;
71 	while (to < endp) {
72 		c = *to;
73 		if (c != dc)
74 			to++;
75 		else
76 			break;
77 	}
78 	fromlen = to-from;
79 	*to++ = '\0';
80 	cp = to;
81 	while (cp < endp) {
82 		c = *cp;
83 		if (c != dc)
84 			cp++;
85 		else
86 			break;
87 	}
88 	tolen = cp-to;
89 	*cp = '\0';
90 	subverbose = FALSE;
91 	if (++cp < endp && *cp == 'v')
92 		subverbose = TRUE;
93 
94 	if (subverbose) {
95 		writeerr(wp, "'%s'%s'(%ld,%ld)", from, to, fromlen, tolen);
96 		sleep(1);
97 	}
98 	substitute(wp, from, fromlen, to, tolen);
99 }
100 
101 /*
102  * This is the 'real' sunstitution routine.
103  * It gets called with pre-parsed strings.
104  */
105 LOCAL void
substitute(wp,from,fromlen,to,tolen)106 substitute(wp, from, fromlen, to, tolen)
107 	ewin_t	*wp;
108 	Uchar	*from;
109 	long	fromlen;
110 	Uchar	*to;
111 	long	tolen;
112 {
113 /*	epos_t	savedot = dot;*/
114 	epos_t	newdot;
115 	epos_t	omark = wp->mark;
116 	int	omarkvalid = wp->markvalid;
117 	ecnt_t	n = wp->curnum;
118 	Uchar	old[NAMESIZE+1];
119 	long	oldlen = 0;
120 	BOOL	tosimple;
121 
122 	if (fromlen == 0)
123 		return;
124 	tosimple = simpleto(to, tolen);
125 
126 	while (n--) {
127 		/*
128 		 * Search the next occurence of the 'from' string.
129 		 * Use a temporary mark to tell whre the found pattern starts.
130 		 */
131 		if ((newdot = search(wp, wp->dot, from, fromlen, 1)) > wp->eof) {
132 			if (newdot == (wp->eof+2))
133 			not_found(wp);
134 			break;
135 		} else {
136 			wp->dot = newdot;
137 		}
138 
139 		if (!tosimple) {
140 			/*
141 			 * We need to remember the old 'from' string before.
142 			 */
143 			oldlen = wp->dot-wp->mark > NAMESIZE ?
144 					NAMESIZE : (long)wp->dot-wp->mark;
145 			oldlen = extract(wp, wp->mark, old, (int)oldlen);
146 			if (subverbose) {
147 				writeerr(wp, "%ld'%s'", oldlen, old);
148 				sleep(1);
149 			}
150 		}
151 		/*
152 		 * Now delete the old string in the buffer
153 		 * and insert substitution
154 		 */
155 		rubchars(wp, wp->dot-wp->mark);	/* Mark is before dot */
156 		if (tosimple)
157 			insert(wp, to, tolen);
158 		else
159 			catsub(wp, old, oldlen, to, tolen);
160 		dispup(wp, wp->dot, wp->mark);
161 	}
162 
163 	/*
164 	 * Re-set mark to remembered place
165 	 */
166 	resetmark(wp);
167 	if (omarkvalid)
168 		setmark(wp, omark);
169 }
170 
171 /*
172  * Check is this is a 'simple' 'to'-substitution string
173  * that does not require to be expanded via 'catsub()'.
174  */
175 LOCAL BOOL
simpleto(s,len)176 simpleto(s, len)
177 	register Uchar	*s;
178 	register long	len;
179 {
180 	register Uchar	c;
181 
182 	if (len <= 0)
183 		return (TRUE);
184 	while (--len >= 0) {
185 		c = *s++;
186 		if (c == '\\' || c == '&')
187 			return (FALSE);
188 	}
189 	return (TRUE);
190 }
191 
192 /*
193  * Insert the substitution string.
194  * The '&' character in the to string is substituted with the old from string.
195  */
196 LOCAL void
catsub(wp,old,oldlen,to,tolen)197 catsub(wp, old, oldlen, to, tolen)
198 		ewin_t	*wp;
199 	register Uchar	*old;
200 	register long	oldlen;
201 	register Uchar	*to;
202 	register long	tolen;
203 {
204 	if (tolen <= 0)
205 		return;
206 
207 	while (--tolen >= 0) {
208 		if (*to == '\\') {
209 			if (--tolen >= 0)
210 				insert(wp, ++to, 1L);
211 		} else if (*to == '&') {
212 			insert(wp, old, oldlen);
213 		} else {
214 			insert(wp, to, 1L);
215 		}
216 		to++;
217 	}
218 }
219