xref: /dragonfly/usr.bin/window/wwwrite.c (revision bcc8941083d0b963b673c93192148e2e23a76740)
1 /*        @(#)wwwrite.c       8.1 (Berkeley) 6/6/93         */
2 /*        $NetBSD: wwwrite.c,v 1.9 2009/04/14 08:50:06 lukem 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 "xx.h"
39 #include "char.h"
40 
41 #define UPDATE() \
42           if (!ISSET(w->ww_wflags, WWW_NOUPDATE) && w->ww_cur.r >= 0 && \
43               w->ww_cur.r < wwnrow && wwtouched[w->ww_cur.r]) \
44                     wwupdate1(w->ww_cur.r, w->ww_cur.r + 1)
45 
46 /*
47  * To support control character expansion, we save the old
48  * p and q values in r and s, and point p at the beginning
49  * of the expanded string, and q at some safe place beyond it
50  * (p + 10).  At strategic points in the loops, we check
51  * for (r && !*p) and restore the saved values back into
52  * p and q.  Essentially, we implement a stack of depth 2,
53  * to avoid recursion, which might be a better idea.
54  */
55 int
wwwrite(struct ww * w,const char * p,int n)56 wwwrite(struct ww *w, const char *p, int n)
57 {
58           int hascursor;
59           const char *savep = p;
60           const char *q = p + n;
61           const char *r = NULL;
62           const char *s = NULL;
63 
64           hascursor = ISSET(w->ww_wflags, WWW_HASCURSOR);
65           if (hascursor)
66                     wwcursor(w, 0);
67           while (p < q && !ISSET(w->ww_pflags, WWP_STOPPED) &&
68               (!wwinterrupt() || ISSET(w->ww_wflags, WWW_NOINTR))) {
69                     if (r && !*p) {
70                               p = r;
71                               q = s;
72                               r = NULL;
73                               continue;
74                     }
75                     if (w->ww_wstate == 0 &&
76                         (isprt(*p) ||
77                         (ISSET(w->ww_wflags, WWW_UNCTRL) && isunctrl(*p)))) {
78                               int i;
79                               union ww_char *bp;
80                               int col, col1;
81 
82                               if (ISSET(w->ww_wflags, WWW_INSERT)) {
83                                         /* this is very slow */
84                                         if (*p == '\t') {
85                                                   p++;
86                                                   w->ww_cur.c += 8 -
87                                                             ((w->ww_cur.c - w->ww_w.l) & 7);
88                                                   goto chklf;
89                                         }
90                                         if (!isprt(*p)) {
91                                                   r = p + 1;
92                                                   s = q;
93                                                   p = unctrl(*p);
94                                                   q = p + 10;
95                                         }
96                                         wwinschar(w, w->ww_cur.r, w->ww_cur.c,
97                                                   *p++, w->ww_modes);
98                                         goto right;
99                               }
100 
101                               bp = &w->ww_buf[w->ww_cur.r][w->ww_cur.c];
102                               i = w->ww_cur.c;
103                               while (i < w->ww_w.r && p < q)
104                                         if (!*p && r) {
105                                                   p = r;
106                                                   q = s;
107                                                   r = NULL;
108                                         } else if (*p == '\t') {
109                                                   int tmp = 8 - ((i - w->ww_w.l) & 7);
110                                                   p++;
111                                                   i += tmp;
112                                                   bp += tmp;
113                                         } else if (isprt(*p)) {
114                                                   bp++->c_w = *p++
115                                                             | w->ww_modes << WWC_MSHIFT;
116                                                   i++;
117                                         } else if (ISSET(w->ww_wflags, WWW_UNCTRL) &&
118                                                      isunctrl(*p)) {
119                                                   r = p + 1;
120                                                   s = q;
121                                                   p = unctrl(*p);
122                                                   q = p + 10;
123                                         } else
124                                                   break;
125                               col = MAX(w->ww_cur.c, w->ww_i.l);
126                               col1 = MIN(i, w->ww_i.r);
127                               w->ww_cur.c = i;
128                               if (w->ww_cur.r >= w->ww_i.t
129                                   && w->ww_cur.r < w->ww_i.b) {
130                                         union ww_char *ns = wwns[w->ww_cur.r];
131                                         unsigned char *smap =
132                                             &wwsmap[w->ww_cur.r][col];
133                                         char *win = w->ww_win[w->ww_cur.r];
134                                         int nchanged = 0;
135 
136                                         bp = w->ww_buf[w->ww_cur.r];
137                                         for (i = col; i < col1; i++)
138                                                   if (*smap++ == w->ww_index) {
139                                                             nchanged++;
140                                                             ns[i].c_w = bp[i].c_w
141                                                                       ^ win[i] << WWC_MSHIFT;
142                                                   }
143                                         if (nchanged > 0)
144                                                   wwtouched[w->ww_cur.r] |= WWU_TOUCHED;
145                               }
146                     chklf:
147                               if (w->ww_cur.c >= w->ww_w.r)
148                                         goto crlf;
149                     } else switch (w->ww_wstate) {
150                     case 0:
151                               switch (*p++) {
152                               case '\n':
153                                         if (ISSET(w->ww_wflags, WWW_MAPNL))
154                     crlf:
155                                                   w->ww_cur.c = w->ww_w.l;
156                     lf:
157                                         UPDATE();
158                                         if (++w->ww_cur.r >= w->ww_w.b) {
159                                                   w->ww_cur.r = w->ww_w.b - 1;
160                                                   if (w->ww_w.b < w->ww_b.b) {
161                                                             (void) wwscroll1(w, w->ww_i.t,
162                                                                       w->ww_i.b, 1, 0);
163                                                             w->ww_buf++;
164                                                             w->ww_b.t--;
165                                                             w->ww_b.b--;
166                                                   } else
167                                                             wwdelline(w, w->ww_b.t);
168                                         }
169                                         break;
170                               case '\b':
171                                         if (--w->ww_cur.c < w->ww_w.l) {
172                                                   w->ww_cur.c = w->ww_w.r - 1;
173                                                   goto up;
174                                         }
175                                         break;
176                               case '\r':
177                                         w->ww_cur.c = w->ww_w.l;
178                                         break;
179                               case ctrl('g'):
180                                         ttputc(ctrl('g'));
181                                         break;
182                               case ctrl('['):
183                                         w->ww_wstate = 1;
184                                         break;
185                               }
186                               break;
187                     case 1:
188                               w->ww_wstate = 0;
189                               switch (*p++) {
190                               case '@':
191                                         SET(w->ww_wflags, WWW_INSERT);
192                                         break;
193                               case 'A':
194                     up:
195                                         UPDATE();
196                                         if (--w->ww_cur.r < w->ww_w.t) {
197                                                   w->ww_cur.r = w->ww_w.t;
198                                                   if (w->ww_w.t > w->ww_b.t) {
199                                                             (void) wwscroll1(w, w->ww_i.t,
200                                                                       w->ww_i.b, -1, 0);
201                                                             w->ww_buf--;
202                                                             w->ww_b.t++;
203                                                             w->ww_b.b++;
204                                                   } else
205                                                             wwinsline(w, w->ww_b.t);
206                                         }
207                                         break;
208                               case 'B':
209                                         goto lf;
210                               case 'C':
211                     right:
212                                         w->ww_cur.c++;
213                                         goto chklf;
214                               case 'E':
215                                         w->ww_buf -= w->ww_w.t - w->ww_b.t;
216                                         w->ww_b.t = w->ww_w.t;
217                                         w->ww_b.b = w->ww_b.t + w->ww_b.nr;
218                                         w->ww_cur.r = w->ww_w.t;
219                                         w->ww_cur.c = w->ww_w.l;
220                                         wwclreos(w, w->ww_w.t, w->ww_w.l);
221                                         break;
222                               case 'H':
223                                         UPDATE();
224                                         w->ww_cur.r = w->ww_w.t;
225                                         w->ww_cur.c = w->ww_w.l;
226                                         break;
227                               case 'J':
228                                         wwclreos(w, w->ww_cur.r, w->ww_cur.c);
229                                         break;
230                               case 'K':
231                                         wwclreol(w, w->ww_cur.r, w->ww_cur.c);
232                                         break;
233                               case 'L':
234                                         UPDATE();
235                                         wwinsline(w, w->ww_cur.r);
236                                         break;
237                               case 'M':
238                                         wwdelline(w, w->ww_cur.r);
239                                         break;
240                               case 'N':
241                                         wwdelchar(w, w->ww_cur.r, w->ww_cur.c);
242                                         break;
243                               case 'O':
244                                         CLR(w->ww_wflags, WWW_INSERT);
245                                         break;
246                               case 'P':
247                                         wwinschar(w, w->ww_cur.r, w->ww_cur.c, ' ', 0);
248                                         break;
249                               case 'X':
250                                         wwupdate();
251                                         break;
252                               case 'Y':
253                                         UPDATE();
254                                         w->ww_wstate = 2;
255                                         break;
256                               case 'Z':
257                                         wwupdate();
258                                         xxflush(0);
259                                         break;
260                               case 's':
261                                         w->ww_wstate = 4;
262                                         break;
263                               case 'r':
264                                         w->ww_wstate = 5;
265                                         break;
266                               }
267                               break;
268                     case 2:
269                               w->ww_cur.r = w->ww_w.t +
270                                         (unsigned)(*p++ - ' ') % w->ww_w.nr;
271                               w->ww_wstate = 3;
272                               break;
273                     case 3:
274                               w->ww_cur.c = w->ww_w.l +
275                                         (unsigned)(*p++ - ' ') % w->ww_w.nc;
276                               w->ww_wstate = 0;
277                               break;
278                     case 4:
279                               w->ww_modes |= *p++ & wwavailmodes;
280                               w->ww_wstate = 0;
281                               break;
282                     case 5:
283                               w->ww_modes &= ~*p++;
284                               w->ww_wstate = 0;
285                               break;
286                     }
287           }
288           if (hascursor)
289                     wwcursor(w, 1);
290           wwnwwr++;
291           wwnwwra += n;
292           n = p - savep;
293           wwnwwrc += n;
294           return n;
295 }
296