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