Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / window / wwwrite.c
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 }