1 /*	$OpenBSD: wwwrite.c,v 1.6 2003/06/03 02:56:23 millert Exp $	*/
2 /*	$NetBSD: wwwrite.c,v 1.5 1996/02/08 21:49:19 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Edward Wang at The University of California, Berkeley.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "ww.h"
37 #include "tt.h"
38 #include "char.h"
39 
40 __SCCSID("@(#)wwwrite.c	8.1 (Berkeley) 6/6/93");
41 __RCSID("$MirOS: src/usr.bin/window/wwwrite.c,v 1.2 2006/10/28 19:08:08 tg Exp $");
42 
43 #define UPDATE() \
44 	if (!ISSET(w->ww_wflags, WWW_NOUPDATE) && w->ww_cur.r >= 0 && \
45 	    w->ww_cur.r < wwnrow && wwtouched[w->ww_cur.r]) \
46 		wwupdate1(w->ww_cur.r, w->ww_cur.r + 1)
47 
48 /*
49  * To support control character expansion, we save the old
50  * p and q values in r and s, and point p at the beginning
51  * of the expanded string, and q at some safe place beyond it
52  * (p + 10).  At strategic points in the loops, we check
53  * for (r && !*p) and restore the saved values back into
54  * p and q.  Essentially, we implement a stack of depth 2,
55  * to avoid recursion, which might be a better idea.
56  */
57 wwwrite(w, p, n)
58 struct ww *w;
59 char *p;
60 int n;
61 {
62 	int hascursor;
63 	char *savep = p;
64 	char *q = p + n;
65 	char *r = 0;
66 	char *s;
67 
68 #ifdef lint
69 	s = 0;			/* define it before possible use */
70 #endif
71 	hascursor = ISSET(w->ww_wflags, WWW_HASCURSOR);
72 	if (hascursor)
73 		wwcursor(w, 0);
74 	while (p < q && !ISSET(w->ww_pflags, WWP_STOPPED) &&
75 	    (!wwinterrupt() || ISSET(w->ww_wflags, WWW_NOINTR))) {
76 		if (r && !*p) {
77 			p = r;
78 			q = s;
79 			r = 0;
80 			continue;
81 		}
82 		if (w->ww_wstate == 0 &&
83 		    (isprt(*p) || ISSET(w->ww_wflags, WWW_UNCTRL) &&
84 		     isunctrl(*p))) {
85 			int i;
86 			union ww_char *bp;
87 			int col, col1;
88 
89 			if (ISSET(w->ww_wflags, WWW_INSERT)) {
90 				/* this is very slow */
91 				if (*p == '\t') {
92 					p++;
93 					w->ww_cur.c += 8 -
94 						(w->ww_cur.c - w->ww_w.l & 7);
95 					goto chklf;
96 				}
97 				if (!isprt(*p)) {
98 					r = p + 1;
99 					s = q;
100 					p = (char *)unctrl(*p);
101 					q = p + 10;
102 				}
103 				wwinschar(w, w->ww_cur.r, w->ww_cur.c,
104 					*p++, w->ww_modes);
105 				goto right;
106 			}
107 
108 			bp = &w->ww_buf[w->ww_cur.r][w->ww_cur.c];
109 			i = w->ww_cur.c;
110 			while (i < w->ww_w.r && p < q)
111 				if (!*p && r) {
112 					p = r;
113 					q = s;
114 					r = 0;
115 				} else if (*p == '\t') {
116 					int tmp = 8 - (i - w->ww_w.l & 7);
117 					p++;
118 					i += tmp;
119 					bp += tmp;
120 				} else if (isprt(*p)) {
121 					bp++->c_w = *p++
122 						| w->ww_modes << WWC_MSHIFT;
123 					i++;
124 				} else if (ISSET(w->ww_wflags, WWW_UNCTRL) &&
125 					   isunctrl(*p)) {
126 					r = p + 1;
127 					s = q;
128 					p = (char *)unctrl(*p);
129 					q = p + 10;
130 				} else
131 					break;
132 			col = MAX(w->ww_cur.c, w->ww_i.l);
133 			col1 = MIN(i, w->ww_i.r);
134 			w->ww_cur.c = i;
135 			if (w->ww_cur.r >= w->ww_i.t
136 			    && w->ww_cur.r < w->ww_i.b) {
137 				union ww_char *ns = wwns[w->ww_cur.r];
138 				unsigned char *smap =
139 				    &wwsmap[w->ww_cur.r][col];
140 				char *win = w->ww_win[w->ww_cur.r];
141 				int nchanged = 0;
142 
143 				bp = w->ww_buf[w->ww_cur.r];
144 				for (i = col; i < col1; i++)
145 					if (*smap++ == w->ww_index) {
146 						nchanged++;
147 						ns[i].c_w = bp[i].c_w
148 							^ win[i] << WWC_MSHIFT;
149 					}
150 				if (nchanged > 0)
151 					wwtouched[w->ww_cur.r] |= WWU_TOUCHED;
152 			}
153 		chklf:
154 			if (w->ww_cur.c >= w->ww_w.r)
155 				goto crlf;
156 		} else switch (w->ww_wstate) {
157 		case 0:
158 			switch (*p++) {
159 			case '\n':
160 				if (ISSET(w->ww_wflags, WWW_MAPNL))
161 		crlf:
162 					w->ww_cur.c = w->ww_w.l;
163 		lf:
164 				UPDATE();
165 				if (++w->ww_cur.r >= w->ww_w.b) {
166 					w->ww_cur.r = w->ww_w.b - 1;
167 					if (w->ww_w.b < w->ww_b.b) {
168 						(void) wwscroll1(w, w->ww_i.t,
169 							w->ww_i.b, 1, 0);
170 						w->ww_buf++;
171 						w->ww_b.t--;
172 						w->ww_b.b--;
173 					} else
174 						wwdelline(w, w->ww_b.t);
175 				}
176 				break;
177 			case '\b':
178 				if (--w->ww_cur.c < w->ww_w.l) {
179 					w->ww_cur.c = w->ww_w.r - 1;
180 					goto up;
181 				}
182 				break;
183 			case '\r':
184 				w->ww_cur.c = w->ww_w.l;
185 				break;
186 			case ctrl('g'):
187 				ttputc(ctrl('g'));
188 				break;
189 			case ctrl('['):
190 				w->ww_wstate = 1;
191 				break;
192 			}
193 			break;
194 		case 1:
195 			w->ww_wstate = 0;
196 			switch (*p++) {
197 			case '@':
198 				SET(w->ww_wflags, WWW_INSERT);
199 				break;
200 			case 'A':
201 		up:
202 				UPDATE();
203 				if (--w->ww_cur.r < w->ww_w.t) {
204 					w->ww_cur.r = w->ww_w.t;
205 					if (w->ww_w.t > w->ww_b.t) {
206 						(void) wwscroll1(w, w->ww_i.t,
207 							w->ww_i.b, -1, 0);
208 						w->ww_buf--;
209 						w->ww_b.t++;
210 						w->ww_b.b++;
211 					} else
212 						wwinsline(w, w->ww_b.t);
213 				}
214 				break;
215 			case 'B':
216 				goto lf;
217 			case 'C':
218 		right:
219 				w->ww_cur.c++;
220 				goto chklf;
221 			case 'E':
222 				w->ww_buf -= w->ww_w.t - w->ww_b.t;
223 				w->ww_b.t = w->ww_w.t;
224 				w->ww_b.b = w->ww_b.t + w->ww_b.nr;
225 				w->ww_cur.r = w->ww_w.t;
226 				w->ww_cur.c = w->ww_w.l;
227 				wwclreos(w, w->ww_w.t, w->ww_w.l);
228 				break;
229 			case 'H':
230 				UPDATE();
231 				w->ww_cur.r = w->ww_w.t;
232 				w->ww_cur.c = w->ww_w.l;
233 				break;
234 			case 'J':
235 				wwclreos(w, w->ww_cur.r, w->ww_cur.c);
236 				break;
237 			case 'K':
238 				wwclreol(w, w->ww_cur.r, w->ww_cur.c);
239 				break;
240 			case 'L':
241 				UPDATE();
242 				wwinsline(w, w->ww_cur.r);
243 				break;
244 			case 'M':
245 				wwdelline(w, w->ww_cur.r);
246 				break;
247 			case 'N':
248 				wwdelchar(w, w->ww_cur.r, w->ww_cur.c);
249 				break;
250 			case 'O':
251 				CLR(w->ww_wflags, WWW_INSERT);
252 				break;
253 			case 'P':
254 				wwinschar(w, w->ww_cur.r, w->ww_cur.c, ' ', 0);
255 				break;
256 			case 'X':
257 				wwupdate();
258 				break;
259 			case 'Y':
260 				UPDATE();
261 				w->ww_wstate = 2;
262 				break;
263 			case 'Z':
264 				wwupdate();
265 				xxflush(0);
266 				break;
267 			case 's':
268 				w->ww_wstate = 4;
269 				break;
270 			case 'r':
271 				w->ww_wstate = 5;
272 				break;
273 			}
274 			break;
275 		case 2:
276 			w->ww_cur.r = w->ww_w.t +
277 				(unsigned)(*p++ - ' ') % w->ww_w.nr;
278 			w->ww_wstate = 3;
279 			break;
280 		case 3:
281 			w->ww_cur.c = w->ww_w.l +
282 				(unsigned)(*p++ - ' ') % w->ww_w.nc;
283 			w->ww_wstate = 0;
284 			break;
285 		case 4:
286 			w->ww_modes |= *p++ & wwavailmodes;
287 			w->ww_wstate = 0;
288 			break;
289 		case 5:
290 			w->ww_modes &= ~*p++;
291 			w->ww_wstate = 0;
292 			break;
293 		}
294 	}
295 	if (hascursor)
296 		wwcursor(w, 1);
297 	wwnwwr++;
298 	wwnwwra += n;
299 	n = p - savep;
300 	wwnwwrc += n;
301 	return n;
302 }
303