1186681Sed/*-
2186681Sed * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3186681Sed * All rights reserved.
4186681Sed *
5186681Sed * Redistribution and use in source and binary forms, with or without
6186681Sed * modification, are permitted provided that the following conditions
7186681Sed * are met:
8186681Sed * 1. Redistributions of source code must retain the above copyright
9186681Sed *    notice, this list of conditions and the following disclaimer.
10186681Sed * 2. Redistributions in binary form must reproduce the above copyright
11186681Sed *    notice, this list of conditions and the following disclaimer in the
12186681Sed *    documentation and/or other materials provided with the distribution.
13186681Sed *
14186681Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15186681Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16186681Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17186681Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18186681Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19186681Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20186681Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21186681Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22186681Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23186681Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24186681Sed * SUCH DAMAGE.
25186681Sed *
26186681Sed * $FreeBSD$
27186681Sed */
28186681Sed
29186681Sed#include <sys/ioctl.h>
30186681Sed
31186681Sed#include <assert.h>
32186681Sed#include <errno.h>
33186681Sed#include <inttypes.h>
34187562Sed#include <locale.h>
35186681Sed#include <stdio.h>
36186681Sed#include <stdlib.h>
37186681Sed#include <unistd.h>
38186681Sed
39186681Sed#include <ncurses.h>
40186681Sed#if defined(__FreeBSD__)
41186681Sed#include <libutil.h>
42186681Sed#elif defined(__linux__)
43186681Sed#include <pty.h>
44186681Sed#else
45186681Sed#include <util.h>
46186681Sed#endif
47186681Sed
48221698Sed#include <teken.h>
49186681Sed
50186681Sedstatic tf_bell_t	test_bell;
51186681Sedstatic tf_cursor_t	test_cursor;
52186681Sedstatic tf_putchar_t	test_putchar;
53186681Sedstatic tf_fill_t	test_fill;
54186681Sedstatic tf_copy_t	test_copy;
55186681Sedstatic tf_param_t	test_param;
56186681Sedstatic tf_respond_t	test_respond;
57186681Sed
58186681Sedstatic teken_funcs_t tf = {
59186681Sed	.tf_bell	= test_bell,
60186681Sed	.tf_cursor	= test_cursor,
61186681Sed	.tf_putchar	= test_putchar,
62186681Sed	.tf_fill	= test_fill,
63186681Sed	.tf_copy	= test_copy,
64186681Sed	.tf_param	= test_param,
65186681Sed	.tf_respond	= test_respond,
66186681Sed};
67186681Sed
68186681Sedstruct pixel {
69186681Sed	teken_char_t	c;
70186681Sed	teken_attr_t	a;
71186681Sed};
72186681Sed
73186681Sed#define NCOLS	80
74187469Sed#define NROWS	24
75286797Sedstatic struct pixel buffer[NCOLS][NROWS];
76186681Sed
77186681Sedstatic int ptfd;
78186681Sed
79186681Sedstatic void
80186681Sedprintchar(const teken_pos_t *p)
81186681Sed{
82186681Sed	int y, x, attr = 0;
83187562Sed	struct pixel *px;
84187562Sed	char str[5] = { 0 };
85186681Sed
86186681Sed	assert(p->tp_row < NROWS);
87186681Sed	assert(p->tp_col < NCOLS);
88186681Sed
89223574Sed	px = &buffer[p->tp_col][p->tp_row];
90259667Sed	/* No need to print right hand side of CJK character manually. */
91259667Sed	if (px->a.ta_format & TF_CJK_RIGHT)
92259667Sed		return;
93186681Sed
94187562Sed	/* Convert Unicode to UTF-8. */
95187562Sed	if (px->c < 0x80) {
96187562Sed		str[0] = px->c;
97187562Sed	} else if (px->c < 0x800) {
98187562Sed		str[0] = 0xc0 | (px->c >> 6);
99187562Sed		str[1] = 0x80 | (px->c & 0x3f);
100187562Sed	} else if (px->c < 0x10000) {
101187562Sed		str[0] = 0xe0 | (px->c >> 12);
102187562Sed		str[1] = 0x80 | ((px->c >> 6) & 0x3f);
103187562Sed		str[2] = 0x80 | (px->c & 0x3f);
104187562Sed	} else {
105187562Sed		str[0] = 0xf0 | (px->c >> 18);
106187562Sed		str[1] = 0x80 | ((px->c >> 12) & 0x3f);
107187562Sed		str[2] = 0x80 | ((px->c >> 6) & 0x3f);
108187562Sed		str[3] = 0x80 | (px->c & 0x3f);
109186681Sed	}
110186681Sed
111186681Sed	if (px->a.ta_format & TF_BOLD)
112186681Sed		attr |= A_BOLD;
113186681Sed	if (px->a.ta_format & TF_UNDERLINE)
114186681Sed		attr |= A_UNDERLINE;
115186681Sed	if (px->a.ta_format & TF_BLINK)
116186681Sed		attr |= A_BLINK;
117196786Sed	if (px->a.ta_format & TF_REVERSE)
118196786Sed		attr |= A_REVERSE;
119186681Sed
120197522Sed	bkgdset(attr | COLOR_PAIR(teken_256to8(px->a.ta_fgcolor) +
121197522Sed	      8 * teken_256to8(px->a.ta_bgcolor)));
122259667Sed	getyx(stdscr, y, x);
123187562Sed	mvaddstr(p->tp_row, p->tp_col, str);
124186681Sed	move(y, x);
125186681Sed}
126186681Sed
127186681Sedstatic void
128186681Sedtest_bell(void *s __unused)
129186681Sed{
130186681Sed
131186681Sed	beep();
132186681Sed}
133186681Sed
134186681Sedstatic void
135186681Sedtest_cursor(void *s __unused, const teken_pos_t *p)
136186681Sed{
137186681Sed
138186681Sed	move(p->tp_row, p->tp_col);
139186681Sed}
140186681Sed
141186681Sedstatic void
142186681Sedtest_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c,
143186681Sed    const teken_attr_t *a)
144186681Sed{
145186681Sed
146186681Sed	buffer[p->tp_col][p->tp_row].c = c;
147186681Sed	buffer[p->tp_col][p->tp_row].a = *a;
148186681Sed	printchar(p);
149186681Sed}
150186681Sed
151186681Sedstatic void
152186681Sedtest_fill(void *s, const teken_rect_t *r, teken_char_t c,
153186681Sed    const teken_attr_t *a)
154186681Sed{
155186681Sed	teken_pos_t p;
156186681Sed
157186681Sed	/* Braindead implementation of fill() - just call putchar(). */
158186681Sed	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; p.tp_row++)
159186681Sed		for (p.tp_col = r->tr_begin.tp_col; p.tp_col < r->tr_end.tp_col; p.tp_col++)
160186681Sed			test_putchar(s, &p, c, a);
161186681Sed}
162186681Sed
163186681Sedstatic void
164186681Sedtest_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p)
165186681Sed{
166186681Sed	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
167186681Sed	teken_pos_t d;
168186681Sed
169186681Sed	/*
170186681Sed	 * Copying is a little tricky. We must make sure we do it in
171186681Sed	 * correct order, to make sure we don't overwrite our own data.
172186681Sed	 */
173223574Sed
174186681Sed	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
175186681Sed	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
176223574Sed
177186681Sed	if (p->tp_row < r->tr_begin.tp_row) {
178186681Sed		/* Copy from top to bottom. */
179186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
180186681Sed			/* Copy from left to right. */
181186681Sed			for (y = 0; y < nrow; y++) {
182186681Sed				d.tp_row = p->tp_row + y;
183186681Sed				for (x = 0; x < ncol; x++) {
184186681Sed					d.tp_col = p->tp_col + x;
185186681Sed					buffer[d.tp_col][d.tp_row] =
186186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
187186681Sed					printchar(&d);
188186681Sed				}
189186681Sed			}
190186681Sed		} else {
191186681Sed			/* Copy from right to left. */
192186681Sed			for (y = 0; y < nrow; y++) {
193186681Sed				d.tp_row = p->tp_row + y;
194186681Sed				for (x = ncol - 1; x >= 0; x--) {
195186681Sed					d.tp_col = p->tp_col + x;
196186681Sed					buffer[d.tp_col][d.tp_row] =
197186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
198186681Sed					printchar(&d);
199186681Sed				}
200186681Sed			}
201186681Sed		}
202186681Sed	} else {
203186681Sed		/* Copy from bottom to top. */
204186681Sed		if (p->tp_col < r->tr_begin.tp_col) {
205186681Sed			/* Copy from left to right. */
206186681Sed			for (y = nrow - 1; y >= 0; y--) {
207186681Sed				d.tp_row = p->tp_row + y;
208186681Sed				for (x = 0; x < ncol; x++) {
209186681Sed					d.tp_col = p->tp_col + x;
210186681Sed					buffer[d.tp_col][d.tp_row] =
211186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
212186681Sed					printchar(&d);
213186681Sed				}
214186681Sed			}
215186681Sed		} else {
216186681Sed			/* Copy from right to left. */
217186681Sed			for (y = nrow - 1; y >= 0; y--) {
218186681Sed				d.tp_row = p->tp_row + y;
219186681Sed				for (x = ncol - 1; x >= 0; x--) {
220186681Sed					d.tp_col = p->tp_col + x;
221186681Sed					buffer[d.tp_col][d.tp_row] =
222186681Sed					    buffer[r->tr_begin.tp_col + x][r->tr_begin.tp_row + y];
223186681Sed					printchar(&d);
224186681Sed				}
225186681Sed			}
226186681Sed		}
227186681Sed	}
228186681Sed}
229186681Sed
230186681Sedstatic void
231193940Sedtest_param(void *s __unused, int cmd, unsigned int value)
232186681Sed{
233186681Sed
234186681Sed	switch (cmd) {
235186681Sed	case TP_SHOWCURSOR:
236186681Sed		curs_set(value);
237186681Sed		break;
238186681Sed	case TP_KEYPADAPP:
239186681Sed		keypad(stdscr, value ? TRUE : FALSE);
240186681Sed		break;
241186681Sed	}
242186681Sed}
243186681Sed
244186681Sedstatic void
245186681Sedtest_respond(void *s __unused, const void *buf, size_t len)
246186681Sed{
247186681Sed
248186681Sed	write(ptfd, buf, len);
249186681Sed}
250186681Sed
251186681Sedstatic void
252186681Sedredraw_border(void)
253186681Sed{
254186681Sed	unsigned int i;
255186681Sed
256186681Sed	for (i = 0; i < NROWS; i++)
257186681Sed		mvaddch(i, NCOLS, '|');
258186681Sed	for (i = 0; i < NCOLS; i++)
259186681Sed		mvaddch(NROWS, i, '-');
260186681Sed
261186681Sed	mvaddch(NROWS, NCOLS, '+');
262186681Sed}
263186681Sed
264186681Sedstatic void
265186681Sedredraw_all(void)
266186681Sed{
267186681Sed	teken_pos_t tp;
268186681Sed
269186681Sed	for (tp.tp_row = 0; tp.tp_row < NROWS; tp.tp_row++)
270186681Sed		for (tp.tp_col = 0; tp.tp_col < NCOLS; tp.tp_col++)
271186681Sed			printchar(&tp);
272186681Sed
273186681Sed	redraw_border();
274186681Sed}
275186681Sed
276186681Sedint
277186681Sedmain(int argc __unused, char *argv[] __unused)
278186681Sed{
279186681Sed	struct winsize ws;
280186681Sed	teken_t t;
281186681Sed	teken_pos_t tp;
282186681Sed	fd_set rfds;
283186681Sed	char b[256];
284186681Sed	ssize_t bl;
285187562Sed	const int ccolors[8] = {
286187562Sed	    COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
287187562Sed	    COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
288187562Sed	};
289186681Sed	int i, j;
290186681Sed
291187562Sed	setlocale(LC_CTYPE, "UTF-8");
292187562Sed
293186681Sed	tp.tp_row = ws.ws_row = NROWS;
294186681Sed	tp.tp_col = ws.ws_col = NCOLS;
295186681Sed
296186681Sed	switch (forkpty(&ptfd, NULL, NULL, &ws)) {
297186681Sed	case -1:
298186681Sed		perror("forkpty");
299186681Sed		exit(1);
300186681Sed	case 0:
301187367Sed		setenv("TERM", "xterm", 1);
302186681Sed		setenv("LC_CTYPE", "UTF-8", 0);
303186681Sed		execlp("zsh", "-zsh", NULL);
304186681Sed		execlp("bash", "-bash", NULL);
305186681Sed		execlp("sh", "-sh", NULL);
306186681Sed		_exit(1);
307186681Sed	}
308186681Sed
309186681Sed	teken_init(&t, &tf, NULL);
310186681Sed	teken_set_winsize(&t, &tp);
311186681Sed
312186681Sed	initscr();
313186681Sed	raw();
314186681Sed	start_color();
315186681Sed	for (i = 0; i < 8; i++)
316186681Sed		for (j = 0; j < 8; j++)
317187469Sed			init_pair(i + 8 * j, ccolors[i], ccolors[j]);
318186681Sed
319186681Sed	redraw_border();
320186681Sed
321186681Sed	FD_ZERO(&rfds);
322186681Sed
323186681Sed	for (;;) {
324186681Sed		FD_SET(STDIN_FILENO, &rfds);
325186681Sed		FD_SET(ptfd, &rfds);
326186681Sed
327186681Sed		if (select(ptfd + 1, &rfds, NULL, NULL, NULL) < 0) {
328186681Sed			if (errno == EINTR) {
329186681Sed				redraw_all();
330186681Sed				refresh();
331186681Sed				continue;
332186681Sed			}
333186681Sed			break;
334186681Sed		}
335186681Sed
336186681Sed		if (FD_ISSET(STDIN_FILENO, &rfds)) {
337186681Sed			bl = read(STDIN_FILENO, b, sizeof b);
338186681Sed			if (bl <= 0)
339186681Sed				break;
340186681Sed			write(ptfd, b, bl);
341186681Sed		}
342186681Sed
343186681Sed		if (FD_ISSET(ptfd, &rfds)) {
344186681Sed			bl = read(ptfd, b, sizeof b);
345186681Sed			if (bl <= 0)
346186681Sed				break;
347186681Sed			teken_input(&t, b, bl);
348186681Sed			refresh();
349186681Sed		}
350186681Sed	}
351186681Sed
352186681Sed	endwin();
353186681Sed
354186681Sed	return (0);
355186681Sed}
356