1/*	$NetBSD: ttzapple.c,v 1.8 2006/12/18 20:04:55 christos Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Edward Wang at The University of California, Berkeley.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)ttzapple.c	8.1 (Berkeley) 6/6/93";
39#else
40__RCSID("$NetBSD: ttzapple.c,v 1.8 2006/12/18 20:04:55 christos Exp $");
41#endif
42#endif /* not lint */
43
44#include <stdio.h>
45#include "ww.h"
46#include "tt.h"
47#include "char.h"
48
49/*
50zz|zapple|perfect apple:\
51	:am:pt:co#80:li#24:le=^H:nd=^F:up=^K:do=^J:\
52	:ho=\E0:ll=\E1:cm=\E=%+ %+ :ch=\E<%+ :cv=\E>%+ :\
53	:cl=\E4:ce=\E2:cd=\E3:rp=\E@%.%+ :\
54	:so=\E+:se=\E-:\
55	:dc=\Ec:DC=\EC%+ :ic=\Ei:IC=\EI%+ :\
56	:al=\Ea:AL=\EA%+ :dl=\Ed:DL=\ED%+ :\
57	:sf=\Ef:SF=\EF%+ :sr=\Er:SR=\ER%+ :cs=\E?%+ %+ :\
58	:is=\E-\ET :
59*/
60
61#define NCOL		80
62#define NROW		24
63#define TOKEN_MAX	32
64
65extern short gen_frame[];
66
67	/* for error correction */
68int zz_ecc;
69int zz_lastc;
70
71	/* for checkpointing */
72int zz_sum;
73
74void	zz_checkpoint(void);
75void	zz_checksum(char *, int);
76void	zz_clear(void);
77void	zz_clreol(void);
78void	zz_clreos(void);
79void	zz_compress(int);
80void	zz_delchar(int);
81void	zz_delline(int);
82void	zz_end(void);
83void	zz_insline(int);
84void	zz_insspace(int);
85void	zz_move(int, int);
86void	zz_put_token(int, const char *, int);
87void	zz_putc(char);
88void	zz_reset(void);
89int	zz_rint(char *, int);
90void	zz_scroll_down(int);
91void	zz_scroll_up(int);
92void	zz_setmodes(int);
93void	zz_setscroll(int, int);
94void	zz_set_token(int, char *, int);
95void	zz_start(void);
96void	zz_write(const char *, int);
97
98void
99zz_setmodes(int new)
100{
101	if (new & WWM_REV) {
102		if ((tt.tt_modes & WWM_REV) == 0)
103			ttesc('+');
104	} else
105		if (tt.tt_modes & WWM_REV)
106			ttesc('-');
107	tt.tt_modes = new;
108}
109
110void
111zz_insline(int n)
112{
113	if (n == 1)
114		ttesc('a');
115	else {
116		ttesc('A');
117		ttputc(n + ' ');
118	}
119}
120
121void
122zz_delline(int n)
123{
124	if (n == 1)
125		ttesc('d');
126	else {
127		ttesc('D');
128		ttputc(n + ' ');
129	}
130}
131
132void
133zz_putc(char c)
134{
135	if (tt.tt_nmodes != tt.tt_modes)
136		zz_setmodes(tt.tt_nmodes);
137	ttputc(c);
138	if (++tt.tt_col == NCOL)
139		tt.tt_col = 0, tt.tt_row++;
140}
141
142void
143zz_write(const char *p, int n)
144{
145	if (tt.tt_nmodes != tt.tt_modes)
146		zz_setmodes(tt.tt_nmodes);
147	ttwrite(p, n);
148	tt.tt_col += n;
149	if (tt.tt_col == NCOL)
150		tt.tt_col = 0, tt.tt_row++;
151}
152
153void
154zz_move(int row, int col)
155{
156	int x;
157
158	if (tt.tt_row == row) {
159same_row:
160		if ((x = col - tt.tt_col) == 0)
161			return;
162		if (col == 0) {
163			ttctrl('m');
164			goto out;
165		}
166		switch (x) {
167		case 2:
168			ttctrl('f');
169		case 1:
170			ttctrl('f');
171			goto out;
172		case -2:
173			ttctrl('h');
174		case -1:
175			ttctrl('h');
176			goto out;
177		}
178		if ((col & 7) == 0 && x > 0 && x <= 16) {
179			ttctrl('i');
180			if (x > 8)
181				ttctrl('i');
182			goto out;
183		}
184		ttesc('<');
185		ttputc(col + ' ');
186		goto out;
187	}
188	if (tt.tt_col == col) {
189		switch (row - tt.tt_row) {
190		case 2:
191			ttctrl('j');
192		case 1:
193			ttctrl('j');
194			goto out;
195		case -2:
196			ttctrl('k');
197		case -1:
198			ttctrl('k');
199			goto out;
200		}
201		if (col == 0) {
202			if (row == 0)
203				goto home;
204			if (row == NROW - 1)
205				goto ll;
206		}
207		ttesc('>');
208		ttputc(row + ' ');
209		goto out;
210	}
211	if (col == 0) {
212		if (row == 0) {
213home:
214			ttesc('0');
215			goto out;
216		}
217		if (row == tt.tt_row + 1) {
218			/*
219			 * Do newline first to match the sequence
220			 * for scroll down and return
221			 */
222			ttctrl('j');
223			ttctrl('m');
224			goto out;
225		}
226		if (row == NROW - 1) {
227ll:
228			ttesc('1');
229			goto out;
230		}
231	}
232	/* favor local motion for better compression */
233	if (row == tt.tt_row + 1) {
234		ttctrl('j');
235		goto same_row;
236	}
237	if (row == tt.tt_row - 1) {
238		ttctrl('k');
239		goto same_row;
240	}
241	ttesc('=');
242	ttputc(' ' + row);
243	ttputc(' ' + col);
244out:
245	tt.tt_col = col;
246	tt.tt_row = row;
247}
248
249void
250zz_start(void)
251{
252	ttesc('T');
253	ttputc(TOKEN_MAX + ' ');
254	ttesc('U');
255	ttputc('!');
256	zz_ecc = 1;
257	zz_lastc = -1;
258	ttesc('v');
259	ttflush();
260	zz_sum = 0;
261	zz_setscroll(0, NROW - 1);
262	zz_clear();
263	zz_setmodes(0);
264}
265
266void
267zz_reset(void)
268{
269	zz_setscroll(0, NROW - 1);
270	tt.tt_modes = WWM_REV;
271	zz_setmodes(0);
272	tt.tt_col = tt.tt_row = -10;
273}
274
275void
276zz_end(void)
277{
278	ttesc('T');
279	ttputc(' ');
280	ttesc('U');
281	ttputc(' ');
282	zz_ecc = 0;
283}
284
285void
286zz_clreol(void)
287{
288	ttesc('2');
289}
290
291void
292zz_clreos(void)
293{
294	ttesc('3');
295}
296
297void
298zz_clear(void)
299{
300	ttesc('4');
301	tt.tt_col = tt.tt_row = 0;
302}
303
304void
305zz_insspace(int n)
306{
307	if (n == 1)
308		ttesc('i');
309	else {
310		ttesc('I');
311		ttputc(n + ' ');
312	}
313}
314
315void
316zz_delchar(int n)
317{
318	if (n == 1)
319		ttesc('c');
320	else {
321		ttesc('C');
322		ttputc(n + ' ');
323	}
324}
325
326void
327zz_scroll_down(int n)
328{
329	if (n == 1) {
330		if (tt.tt_row == NROW - 1)
331			ttctrl('j');
332		else
333			ttesc('f');
334	} else {
335		ttesc('F');
336		ttputc(n + ' ');
337	}
338}
339
340void
341zz_scroll_up(int n)
342{
343	if (n == 1)
344		ttesc('r');
345	else {
346		ttesc('R');
347		ttputc(n + ' ');
348	}
349}
350
351void
352zz_setscroll(int top, int bot)
353{
354	ttesc('?');
355	ttputc(top + ' ');
356	ttputc(bot + ' ');
357	tt.tt_scroll_top = top;
358	tt.tt_scroll_bot = bot;
359}
360
361int zz_debug = 0;
362
363void
364zz_set_token(int t, char *s, int n)
365{
366	if (tt.tt_nmodes != tt.tt_modes)
367		zz_setmodes(tt.tt_nmodes);
368	if (zz_debug) {
369		char buf[100];
370		zz_setmodes(WWM_REV);
371		(void) sprintf(buf, "%02x=", t);
372		ttputs(buf);
373		tt.tt_col += 3;
374	}
375	ttputc(0x80);
376	ttputc(t + 1);
377	s[n - 1] |= 0x80;
378	ttwrite(s, n);
379	s[n - 1] &= ~0x80;
380}
381
382void
383zz_put_token(int t, const char *s __unused, int n __unused)
384{
385	if (tt.tt_nmodes != tt.tt_modes)
386		zz_setmodes(tt.tt_nmodes);
387	if (zz_debug) {
388		char buf[100];
389		zz_setmodes(WWM_REV);
390		(void) sprintf(buf, "%02x>", t);
391		ttputs(buf);
392		tt.tt_col += 3;
393	}
394	ttputc(t + 0x81);
395}
396
397int
398zz_rint(char *p, int n)
399{
400	int i;
401	char *q;
402
403	if (!zz_ecc)
404		return n;
405	for (i = n, q = p; --i >= 0;) {
406		int c = (unsigned char) *p++;
407
408		if (zz_lastc == 0) {
409			switch (c) {
410			case 0:
411				*q++ = 0;
412				zz_lastc = -1;
413				break;
414			case 1:		/* start input ecc */
415				zz_ecc = 2;
416				zz_lastc = -1;
417				wwnreadstat++;
418				break;
419			case 2:		/* ack checkpoint */
420				tt.tt_ack = 1;
421				zz_lastc = -1;
422				wwnreadack++;
423				break;
424			case 3:		/* nack checkpoint */
425				tt.tt_ack = -1;
426				zz_lastc = -1;
427				wwnreadnack++;
428				break;
429			default:
430				zz_lastc = c;
431				wwnreadec++;
432			}
433		} else if (zz_ecc == 1) {
434			if (c)
435				*q++ = c;
436			else
437				zz_lastc = 0;
438		} else {
439			if (zz_lastc < 0) {
440				zz_lastc = c;
441			} else if (zz_lastc == c) {
442				*q++ = zz_lastc;
443				zz_lastc = -1;
444			} else {
445				wwnreadec++;
446				zz_lastc = c;
447			}
448		}
449	}
450	return q - (p - n);
451}
452
453void
454zz_checksum(char *p, int n)
455{
456	while (--n >= 0) {
457		int c = *p++ & 0x7f;
458		c ^= zz_sum;
459		zz_sum = c << 1 | (c >> 11 & 1);
460	}
461}
462
463void
464zz_compress(int flag)
465{
466	if (flag)
467		tt.tt_checksum = 0;
468	else
469		tt.tt_checksum = zz_checksum;
470}
471
472void
473zz_checkpoint(void)
474{
475	static char x[] = { ctrl('['), 'V', 0, 0 };
476
477	zz_checksum(x, sizeof x);
478	ttesc('V');
479	ttputc(' ' + (zz_sum & 0x3f));
480	ttputc(' ' + (zz_sum >> 6 & 0x3f));
481	ttflush();
482	zz_sum = 0;
483}
484
485int
486tt_zapple(void)
487{
488	tt.tt_insspace = zz_insspace;
489	tt.tt_delchar = zz_delchar;
490	tt.tt_insline = zz_insline;
491	tt.tt_delline = zz_delline;
492	tt.tt_clreol = zz_clreol;
493	tt.tt_clreos = zz_clreos;
494	tt.tt_scroll_down = zz_scroll_down;
495	tt.tt_scroll_up = zz_scroll_up;
496	tt.tt_setscroll = zz_setscroll;
497	tt.tt_availmodes = WWM_REV;
498	tt.tt_wrap = 1;
499	tt.tt_retain = 0;
500	tt.tt_ncol = NCOL;
501	tt.tt_nrow = NROW;
502	tt.tt_start = zz_start;
503	tt.tt_reset = zz_reset;
504	tt.tt_end = zz_end;
505	tt.tt_write = zz_write;
506	tt.tt_putc = zz_putc;
507	tt.tt_move = zz_move;
508	tt.tt_clear = zz_clear;
509	tt.tt_setmodes = zz_setmodes;
510	tt.tt_frame = gen_frame;
511	tt.tt_padc = TT_PADC_NONE;
512	tt.tt_ntoken = 127;
513	tt.tt_set_token = zz_set_token;
514	tt.tt_put_token = zz_put_token;
515	tt.tt_token_min = 1;
516	tt.tt_token_max = TOKEN_MAX;
517	tt.tt_set_token_cost = 2;
518	tt.tt_put_token_cost = 1;
519	tt.tt_compress = zz_compress;
520	tt.tt_checksum = zz_checksum;
521	tt.tt_checkpoint = zz_checkpoint;
522	tt.tt_reset = zz_reset;
523	tt.tt_rint = zz_rint;
524	return 0;
525}
526