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