xref: /original-bsd/usr.bin/window/wwwrite.c (revision 1a56dd2c)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)wwwrite.c	3.27 (Berkeley) 02/21/88";
15 #endif /* not lint */
16 
17 #include "ww.h"
18 #include "tt.h"
19 #include "char.h"
20 
21 #define UPDATE() \
22 	if (!w->ww_noupdate && w->ww_cur.r >= 0 && w->ww_cur.r < wwnrow && \
23 	    wwtouched[w->ww_cur.r]) \
24 		wwupdate1(w->ww_cur.r, w->ww_cur.r + 1)
25 
26 /*
27  * To support control character expansion, we save the old
28  * p and q values in r and s, and point p at the beginning
29  * of the expanded string, and q at some safe place beyond it
30  * (p + 10).  At strategic points in the loops, we check
31  * for (r && !*p) and restore the saved values back into
32  * p and q.  Essentially, we implement a stack of depth 2,
33  * to avoid recursion, which might be a better idea.
34  */
35 wwwrite(w, p, n)
36 register struct ww *w;
37 register char *p;
38 int n;
39 {
40 	char hascursor;
41 	char *savep = p;
42 	char *q = p + n;
43 	char *r = 0;
44 	char *s;
45 
46 #ifdef lint
47 	s = 0;			/* define it before possible use */
48 #endif
49 	if (hascursor = w->ww_hascursor)
50 		wwcursor(w, 0);
51 	while (p < q && !w->ww_stopped && (!wwinterrupt() || w->ww_nointr)) {
52 		if (r && !*p) {
53 			p = r;
54 			q = s;
55 			r = 0;
56 			continue;
57 		}
58 		if (w->ww_wstate == 0 &&
59 		    (isprt(*p) || w->ww_unctrl && isunctrl(*p))) {
60 			register i;
61 			register union ww_char *bp;
62 			int col, col1;
63 
64 			if (w->ww_insert) {	/* this is very slow */
65 				if (*p == '\t') {
66 					p++;
67 					w->ww_cur.c += 8 -
68 						(w->ww_cur.c - w->ww_w.l & 7);
69 					goto chklf;
70 				}
71 				if (!isprt(*p)) {
72 					r = p + 1;
73 					s = q;
74 					p = unctrl(*p);
75 					q = p + 10;
76 				}
77 				wwinschar(w, w->ww_cur.r, w->ww_cur.c,
78 					*p++ | w->ww_modes << WWC_MSHIFT);
79 				goto right;
80 			}
81 
82 			bp = &w->ww_buf[w->ww_cur.r][w->ww_cur.c];
83 			i = w->ww_cur.c;
84 			while (i < w->ww_w.r && p < q)
85 				if (!*p && r) {
86 					p = r;
87 					q = s;
88 					r = 0;
89 				} else if (*p == '\t') {
90 					register tmp = 8 - (i - w->ww_w.l & 7);
91 					p++;
92 					i += tmp;
93 					bp += tmp;
94 				} else if (isprt(*p)) {
95 					bp++->c_w = *p++
96 						| w->ww_modes << WWC_MSHIFT;
97 					i++;
98 				} else if (w->ww_unctrl && isunctrl(*p)) {
99 					r = p + 1;
100 					s = q;
101 					p = unctrl(*p);
102 					q = p + 10;
103 				} else
104 					break;
105 			col = MAX(w->ww_cur.c, w->ww_i.l);
106 			col1 = MIN(i, w->ww_i.r);
107 			w->ww_cur.c = i;
108 			if (w->ww_cur.r >= w->ww_i.t
109 			    && w->ww_cur.r < w->ww_i.b) {
110 				register union ww_char *ns = wwns[w->ww_cur.r];
111 				register char *smap = &wwsmap[w->ww_cur.r][col];
112 				register char *win = w->ww_win[w->ww_cur.r];
113 				int nchanged = 0;
114 
115 				bp = w->ww_buf[w->ww_cur.r];
116 				for (i = col; i < col1; i++)
117 					if (*smap++ == w->ww_index) {
118 						nchanged++;
119 						ns[i].c_w = bp[i].c_w
120 							^ win[i] << WWC_MSHIFT;
121 					}
122 				if (nchanged > 0)
123 					wwtouched[w->ww_cur.r] |= WWU_TOUCHED;
124 			}
125 		chklf:
126 			if (w->ww_cur.c >= w->ww_w.r)
127 				goto crlf;
128 		} else switch (w->ww_wstate) {
129 		case 0:
130 			switch (*p++) {
131 			case '\n':
132 				if (w->ww_mapnl)
133 		crlf:
134 					w->ww_cur.c = w->ww_w.l;
135 		lf:
136 				UPDATE();
137 				if (++w->ww_cur.r >= w->ww_w.b) {
138 					w->ww_cur.r = w->ww_w.b - 1;
139 					if (w->ww_w.b < w->ww_b.b) {
140 						(void) wwscroll1(w, w->ww_i.t,
141 							w->ww_i.b, 1, 0);
142 						w->ww_buf++;
143 						w->ww_b.t--;
144 						w->ww_b.b--;
145 					} else
146 						wwdelline(w, w->ww_b.t);
147 				}
148 				break;
149 			case '\b':
150 				if (--w->ww_cur.c < w->ww_w.l) {
151 					w->ww_cur.c = w->ww_w.r - 1;
152 					goto up;
153 				}
154 				break;
155 			case '\r':
156 				w->ww_cur.c = w->ww_w.l;
157 				break;
158 			case ctrl('g'):
159 				ttputc(ctrl('g'));
160 				break;
161 			case ctrl('['):
162 				w->ww_wstate = 1;
163 				break;
164 			}
165 			break;
166 		case 1:
167 			w->ww_wstate = 0;
168 			switch (*p++) {
169 			case '@':
170 				w->ww_insert = 1;
171 				break;
172 			case 'A':
173 		up:
174 				UPDATE();
175 				if (--w->ww_cur.r < w->ww_w.t) {
176 					w->ww_cur.r = w->ww_w.t;
177 					if (w->ww_w.t > w->ww_b.t) {
178 						(void) wwscroll1(w, w->ww_i.t,
179 							w->ww_i.b, -1, 0);
180 						w->ww_buf--;
181 						w->ww_b.t++;
182 						w->ww_b.b++;
183 					} else
184 						wwinsline(w, w->ww_b.t);
185 				}
186 				break;
187 			case 'B':
188 				goto lf;
189 			case 'C':
190 		right:
191 				w->ww_cur.c++;
192 				goto chklf;
193 			case 'E':
194 				w->ww_buf -= w->ww_w.t - w->ww_b.t;
195 				w->ww_b.t = w->ww_w.t;
196 				w->ww_b.b = w->ww_b.t + w->ww_b.nr;
197 				w->ww_cur.r = w->ww_w.t;
198 				w->ww_cur.c = w->ww_w.l;
199 				wwclreos(w, w->ww_w.t, w->ww_w.l);
200 				break;
201 			case 'H':
202 				UPDATE();
203 				w->ww_cur.r = w->ww_w.t;
204 				w->ww_cur.c = w->ww_w.l;
205 				break;
206 			case 'J':
207 				wwclreos(w, w->ww_cur.r, w->ww_cur.c);
208 				break;
209 			case 'K':
210 				wwclreol(w, w->ww_cur.r, w->ww_cur.c);
211 				break;
212 			case 'L':
213 				UPDATE();
214 				wwinsline(w, w->ww_cur.r);
215 				break;
216 			case 'M':
217 				wwdelline(w, w->ww_cur.r);
218 				break;
219 			case 'N':
220 				wwdelchar(w, w->ww_cur.r, w->ww_cur.c);
221 				break;
222 			case 'O':
223 				w->ww_insert = 0;
224 				break;
225 			case 'Y':
226 				UPDATE();
227 				w->ww_wstate = 2;
228 				break;
229 			case 's':
230 				w->ww_wstate = 4;
231 				break;
232 			case 'r':
233 				w->ww_wstate = 5;
234 				break;
235 			}
236 			break;
237 		case 2:
238 			w->ww_cur.r = w->ww_w.t +
239 				(unsigned)(*p++ - ' ') % w->ww_w.nr;
240 			w->ww_wstate = 3;
241 			break;
242 		case 3:
243 			w->ww_cur.c = w->ww_w.l +
244 				(unsigned)(*p++ - ' ') % w->ww_w.nc;
245 			w->ww_wstate = 0;
246 			break;
247 		case 4:
248 			w->ww_modes |= *p++ & wwavailmodes;
249 			w->ww_wstate = 0;
250 			break;
251 		case 5:
252 			w->ww_modes &= ~*p++;
253 			w->ww_wstate = 0;
254 			break;
255 		}
256 	}
257 	if (hascursor)
258 		wwcursor(w, 1);
259 	wwnwwr++;
260 	wwnwwra += n;
261 	n = p - savep;
262 	wwnwwrc += n;
263 	return n;
264 }
265