window(1): Add some format safety.
[dragonfly.git] / usr.bin / window / ttzapple.c
1 /*      @(#)ttzapple.c  8.1 (Berkeley) 6/6/93   */
2 /*      $NetBSD: ttzapple.c,v 1.9 2009/04/14 08:50:06 lukem Exp $       */
3
4 /*
5  * Copyright (c) 1989, 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 <stdio.h>
37 #include "ww.h"
38 #include "tt.h"
39 #include "char.h"
40
41 /*
42 zz|zapple|perfect apple:\
43         :am:pt:co#80:li#24:le=^H:nd=^F:up=^K:do=^J:\
44         :ho=\E0:ll=\E1:cm=\E=%+ %+ :ch=\E<%+ :cv=\E>%+ :\
45         :cl=\E4:ce=\E2:cd=\E3:rp=\E@%.%+ :\
46         :so=\E+:se=\E-:\
47         :dc=\Ec:DC=\EC%+ :ic=\Ei:IC=\EI%+ :\
48         :al=\Ea:AL=\EA%+ :dl=\Ed:DL=\ED%+ :\
49         :sf=\Ef:SF=\EF%+ :sr=\Er:SR=\ER%+ :cs=\E?%+ %+ :\
50         :is=\E-\ET :
51 */
52
53 #define NCOL            80
54 #define NROW            24
55 #define TOKEN_MAX       32
56
57 extern short gen_frame[];
58
59         /* for error correction */
60 int zz_ecc;
61 int zz_lastc;
62
63         /* for checkpointing */
64 int zz_sum;
65
66 void    zz_checkpoint(void);
67 void    zz_checksum(char *, int);
68 void    zz_clear(void);
69 void    zz_clreol(void);
70 void    zz_clreos(void);
71 void    zz_compress(int);
72 void    zz_delchar(int);
73 void    zz_delline(int);
74 void    zz_end(void);
75 void    zz_insline(int);
76 void    zz_insspace(int);
77 void    zz_move(int, int);
78 void    zz_put_token(int, const char *, int);
79 void    zz_putc(char);
80 void    zz_reset(void);
81 int     zz_rint(char *, int);
82 void    zz_scroll_down(int);
83 void    zz_scroll_up(int);
84 void    zz_setmodes(int);
85 void    zz_setscroll(int, int);
86 void    zz_set_token(int, char *, int);
87 void    zz_start(void);
88 void    zz_write(const char *, int);
89
90 void
91 zz_setmodes(int new)
92 {
93         if (new & WWM_REV) {
94                 if ((tt.tt_modes & WWM_REV) == 0)
95                         ttesc('+');
96         } else
97                 if (tt.tt_modes & WWM_REV)
98                         ttesc('-');
99         tt.tt_modes = new;
100 }
101
102 void
103 zz_insline(int n)
104 {
105         if (n == 1)
106                 ttesc('a');
107         else {
108                 ttesc('A');
109                 ttputc(n + ' ');
110         }
111 }
112
113 void
114 zz_delline(int n)
115 {
116         if (n == 1)
117                 ttesc('d');
118         else {
119                 ttesc('D');
120                 ttputc(n + ' ');
121         }
122 }
123
124 void
125 zz_putc(char c)
126 {
127         if (tt.tt_nmodes != tt.tt_modes)
128                 zz_setmodes(tt.tt_nmodes);
129         ttputc(c);
130         if (++tt.tt_col == NCOL)
131                 tt.tt_col = 0, tt.tt_row++;
132 }
133
134 void
135 zz_write(const char *p, int n)
136 {
137         if (tt.tt_nmodes != tt.tt_modes)
138                 zz_setmodes(tt.tt_nmodes);
139         ttwrite(p, n);
140         tt.tt_col += n;
141         if (tt.tt_col == NCOL)
142                 tt.tt_col = 0, tt.tt_row++;
143 }
144
145 void
146 zz_move(int row, int col)
147 {
148         int x;
149
150         if (tt.tt_row == row) {
151 same_row:
152                 if ((x = col - tt.tt_col) == 0)
153                         return;
154                 if (col == 0) {
155                         ttctrl('m');
156                         goto out;
157                 }
158                 switch (x) {
159                 case 2:
160                         ttctrl('f');
161                         /* FALLTHROUGH */
162                 case 1:
163                         ttctrl('f');
164                         goto out;
165                 case -2:
166                         ttctrl('h');
167                         /* FALLTHROUGH */
168                 case -1:
169                         ttctrl('h');
170                         goto out;
171                 }
172                 if ((col & 7) == 0 && x > 0 && x <= 16) {
173                         ttctrl('i');
174                         if (x > 8)
175                                 ttctrl('i');
176                         goto out;
177                 }
178                 ttesc('<');
179                 ttputc(col + ' ');
180                 goto out;
181         }
182         if (tt.tt_col == col) {
183                 switch (row - tt.tt_row) {
184                 case 2:
185                         ttctrl('j');
186                         /* FALLTHROUGH */
187                 case 1:
188                         ttctrl('j');
189                         goto out;
190                 case -2:
191                         ttctrl('k');
192                         /* FALLTHROUGH */
193                 case -1:
194                         ttctrl('k');
195                         goto out;
196                 }
197                 if (col == 0) {
198                         if (row == 0)
199                                 goto home;
200                         if (row == NROW - 1)
201                                 goto ll;
202                 }
203                 ttesc('>');
204                 ttputc(row + ' ');
205                 goto out;
206         }
207         if (col == 0) {
208                 if (row == 0) {
209 home:
210                         ttesc('0');
211                         goto out;
212                 }
213                 if (row == tt.tt_row + 1) {
214                         /*
215                          * Do newline first to match the sequence
216                          * for scroll down and return
217                          */
218                         ttctrl('j');
219                         ttctrl('m');
220                         goto out;
221                 }
222                 if (row == NROW - 1) {
223 ll:
224                         ttesc('1');
225                         goto out;
226                 }
227         }
228         /* favor local motion for better compression */
229         if (row == tt.tt_row + 1) {
230                 ttctrl('j');
231                 goto same_row;
232         }
233         if (row == tt.tt_row - 1) {
234                 ttctrl('k');
235                 goto same_row;
236         }
237         ttesc('=');
238         ttputc(' ' + row);
239         ttputc(' ' + col);
240 out:
241         tt.tt_col = col;
242         tt.tt_row = row;
243 }
244
245 void
246 zz_start(void)
247 {
248         ttesc('T');
249         ttputc(TOKEN_MAX + ' ');
250         ttesc('U');
251         ttputc('!');
252         zz_ecc = 1;
253         zz_lastc = -1;
254         ttesc('v');
255         ttflush();
256         zz_sum = 0;
257         zz_setscroll(0, NROW - 1);
258         zz_clear();
259         zz_setmodes(0);
260 }
261
262 void
263 zz_reset(void)
264 {
265         zz_setscroll(0, NROW - 1);
266         tt.tt_modes = WWM_REV;
267         zz_setmodes(0);
268         tt.tt_col = tt.tt_row = -10;
269 }
270
271 void
272 zz_end(void)
273 {
274         ttesc('T');
275         ttputc(' ');
276         ttesc('U');
277         ttputc(' ');
278         zz_ecc = 0;
279 }
280
281 void
282 zz_clreol(void)
283 {
284         ttesc('2');
285 }
286
287 void
288 zz_clreos(void)
289 {
290         ttesc('3');
291 }
292
293 void
294 zz_clear(void)
295 {
296         ttesc('4');
297         tt.tt_col = tt.tt_row = 0;
298 }
299
300 void
301 zz_insspace(int n)
302 {
303         if (n == 1)
304                 ttesc('i');
305         else {
306                 ttesc('I');
307                 ttputc(n + ' ');
308         }
309 }
310
311 void
312 zz_delchar(int n)
313 {
314         if (n == 1)
315                 ttesc('c');
316         else {
317                 ttesc('C');
318                 ttputc(n + ' ');
319         }
320 }
321
322 void
323 zz_scroll_down(int n)
324 {
325         if (n == 1) {
326                 if (tt.tt_row == NROW - 1)
327                         ttctrl('j');
328                 else
329                         ttesc('f');
330         } else {
331                 ttesc('F');
332                 ttputc(n + ' ');
333         }
334 }
335
336 void
337 zz_scroll_up(int n)
338 {
339         if (n == 1)
340                 ttesc('r');
341         else {
342                 ttesc('R');
343                 ttputc(n + ' ');
344         }
345 }
346
347 void
348 zz_setscroll(int top, int bot)
349 {
350         ttesc('?');
351         ttputc(top + ' ');
352         ttputc(bot + ' ');
353         tt.tt_scroll_top = top;
354         tt.tt_scroll_bot = bot;
355 }
356
357 int zz_debug = 0;
358
359 void
360 zz_set_token(int t, char *s, int n)
361 {
362         if (tt.tt_nmodes != tt.tt_modes)
363                 zz_setmodes(tt.tt_nmodes);
364         if (zz_debug) {
365                 char buf[100];
366                 zz_setmodes(WWM_REV);
367                 (void) sprintf(buf, "%02x=", t);
368                 ttputs(buf);
369                 tt.tt_col += 3;
370         }
371         ttputc(0x80);
372         ttputc(t + 1);
373         s[n - 1] |= 0x80;
374         ttwrite(s, n);
375         s[n - 1] &= ~0x80;
376 }
377
378 void
379 zz_put_token(int t, const char *s __unused, int n __unused)
380 {
381         if (tt.tt_nmodes != tt.tt_modes)
382                 zz_setmodes(tt.tt_nmodes);
383         if (zz_debug) {
384                 char buf[100];
385                 zz_setmodes(WWM_REV);
386                 (void) sprintf(buf, "%02x>", t);
387                 ttputs(buf);
388                 tt.tt_col += 3;
389         }
390         ttputc(t + 0x81);
391 }
392
393 int
394 zz_rint(char *p, int n)
395 {
396         int i;
397         char *q;
398
399         if (!zz_ecc)
400                 return n;
401         for (i = n, q = p; --i >= 0;) {
402                 int c = (unsigned char) *p++;
403
404                 if (zz_lastc == 0) {
405                         switch (c) {
406                         case 0:
407                                 *q++ = 0;
408                                 zz_lastc = -1;
409                                 break;
410                         case 1:         /* start input ecc */
411                                 zz_ecc = 2;
412                                 zz_lastc = -1;
413                                 wwnreadstat++;
414                                 break;
415                         case 2:         /* ack checkpoint */
416                                 tt.tt_ack = 1;
417                                 zz_lastc = -1;
418                                 wwnreadack++;
419                                 break;
420                         case 3:         /* nack checkpoint */
421                                 tt.tt_ack = -1;
422                                 zz_lastc = -1;
423                                 wwnreadnack++;
424                                 break;
425                         default:
426                                 zz_lastc = c;
427                                 wwnreadec++;
428                         }
429                 } else if (zz_ecc == 1) {
430                         if (c)
431                                 *q++ = c;
432                         else
433                                 zz_lastc = 0;
434                 } else {
435                         if (zz_lastc < 0) {
436                                 zz_lastc = c;
437                         } else if (zz_lastc == c) {
438                                 *q++ = zz_lastc;
439                                 zz_lastc = -1;
440                         } else {
441                                 wwnreadec++;
442                                 zz_lastc = c;
443                         }
444                 }
445         }
446         return q - (p - n);
447 }
448
449 void
450 zz_checksum(char *p, int n)
451 {
452         while (--n >= 0) {
453                 int c = *p++ & 0x7f;
454                 c ^= zz_sum;
455                 zz_sum = c << 1 | (c >> 11 & 1);
456         }
457 }
458
459 void
460 zz_compress(int flag)
461 {
462         if (flag)
463                 tt.tt_checksum = 0;
464         else
465                 tt.tt_checksum = zz_checksum;
466 }
467
468 void
469 zz_checkpoint(void)
470 {
471         static char x[] = { ctrl('['), 'V', 0, 0 };
472
473         zz_checksum(x, sizeof x);
474         ttesc('V');
475         ttputc(' ' + (zz_sum & 0x3f));
476         ttputc(' ' + (zz_sum >> 6 & 0x3f));
477         ttflush();
478         zz_sum = 0;
479 }
480
481 int
482 tt_zapple(void)
483 {
484         tt.tt_insspace = zz_insspace;
485         tt.tt_delchar = zz_delchar;
486         tt.tt_insline = zz_insline;
487         tt.tt_delline = zz_delline;
488         tt.tt_clreol = zz_clreol;
489         tt.tt_clreos = zz_clreos;
490         tt.tt_scroll_down = zz_scroll_down;
491         tt.tt_scroll_up = zz_scroll_up;
492         tt.tt_setscroll = zz_setscroll;
493         tt.tt_availmodes = WWM_REV;
494         tt.tt_wrap = 1;
495         tt.tt_retain = 0;
496         tt.tt_ncol = NCOL;
497         tt.tt_nrow = NROW;
498         tt.tt_start = zz_start;
499         tt.tt_reset = zz_reset;
500         tt.tt_end = zz_end;
501         tt.tt_write = zz_write;
502         tt.tt_putc = zz_putc;
503         tt.tt_move = zz_move;
504         tt.tt_clear = zz_clear;
505         tt.tt_setmodes = zz_setmodes;
506         tt.tt_frame = gen_frame;
507         tt.tt_padc = TT_PADC_NONE;
508         tt.tt_ntoken = 127;
509         tt.tt_set_token = zz_set_token;
510         tt.tt_put_token = zz_put_token;
511         tt.tt_token_min = 1;
512         tt.tt_token_max = TOKEN_MAX;
513         tt.tt_set_token_cost = 2;
514         tt.tt_put_token_cost = 1;
515         tt.tt_compress = zz_compress;
516         tt.tt_checksum = zz_checksum;
517         tt.tt_checkpoint = zz_checkpoint;
518         tt.tt_reset = zz_reset;
519         tt.tt_rint = zz_rint;
520         return 0;
521 }