/* * terminal.c: * * Copyright (c) 2008 James McKenzie , * All rights reserved. * */ static char rcsid[] = "$Id$"; /* * $Log$ * Revision 1.25 2012/06/22 10:22:25 james * *** empty log message *** * * Revision 1.24 2008/03/12 10:47:26 james * @@ * * Revision 1.23 2008/03/12 01:30:23 james * *** empty log message *** * * Revision 1.22 2008/03/11 17:56:50 james * *** empty log message *** * * Revision 1.21 2008/03/11 17:56:04 james * *** empty log message *** * * Revision 1.20 2008/03/10 11:49:33 james * *** empty log message *** * * Revision 1.19 2008/03/07 14:16:44 james * *** empty log message *** * * Revision 1.18 2008/03/07 14:13:40 james * *** empty log message *** * * Revision 1.17 2008/03/07 13:16:02 james * *** empty log message *** * * Revision 1.16 2008/03/07 12:42:08 james * *** empty log message *** * * Revision 1.15 2008/03/07 12:37:04 james * *** empty log message *** * * Revision 1.14 2008/03/03 06:04:42 james * *** empty log message *** * * Revision 1.13 2008/03/02 10:37:56 james * *** empty log message *** * * Revision 1.12 2008/02/28 16:57:52 james * *** empty log message *** * * Revision 1.11 2008/02/26 23:56:12 james * *** empty log message *** * * Revision 1.10 2008/02/26 23:23:17 james * *** empty log message *** * * Revision 1.9 2008/02/15 03:32:07 james * *** empty log message *** * * Revision 1.8 2008/02/14 10:39:14 james * *** empty log message *** * * Revision 1.7 2008/02/14 01:55:57 james * *** empty log message *** * * Revision 1.6 2008/02/14 00:57:58 james * *** empty log message *** * * Revision 1.5 2008/02/13 18:05:06 james * *** empty log message *** * * Revision 1.4 2008/02/13 16:57:29 james * *** empty log message *** * * Revision 1.3 2008/02/13 09:12:21 james * *** empty log message *** * * Revision 1.2 2008/02/13 01:08:18 james * *** empty log message *** * * Revision 1.1 2008/02/12 22:36:46 james * *** empty log message *** * * Revision 1.1 2008/02/09 15:47:28 james * *** empty log message *** * * Revision 1.2 2008/02/07 11:11:14 staffcvs * *** empty log message *** * * Revision 1.1 2008/02/07 01:02:52 james * *** empty log message *** * * Revision 1.3 2008/02/06 17:53:28 james * *** empty log message *** * * Revision 1.2 2008/02/04 02:05:06 james * *** empty log message *** * * Revision 1.1 2008/02/04 01:32:39 james * *** empty log message *** * */ #include "project.h" typedef struct TERMINAL_struct { TTY_SIGNATURE; struct termios orig_termios; struct TERMINAL_struct *next; } TERMINAL; static TERMINAL *terminal_list = NULL; int terminal_winches; static void terminal_close (TTY * _t) { char buf[32]; int i; TERMINAL *t = (TERMINAL *) _t; TERMINAL **ptr = &terminal_list; if (!t) return; /* Take out of cleanup list */ while (*ptr && (*ptr != t)) ptr = &((*ptr)->next); if (*ptr) *ptr = t->next; tcsetattr (t->wfd, TCSANOW, &t->orig_termios); set_nonblocking (t->wfd); t->xmit (_t, "\033%@", 3); // Leave UTF-8 t->xmit (_t, "\033(B", 3); // US-ASCII in G0 t->xmit (_t, "\033)B", 3); // US-ASCII in G1 t->xmit (_t, "\017", 1); // Select G0 t->xmit (_t, "\033[?25h", 6); // Show cursor t->xmit (_t, "\033[r", 3); // No margins t->xmit (_t, "\033[0m", 4); // Default attributes i = sprintf (buf, "\033[%d;%dH", t->displayed_length ? (t->displayed_length + 1) : (CRT_ROWS + 1), 1); // Cursor to bottom t->xmit (_t, buf, i); t->xmit (_t, "\033[J", 3); // erase rest of screen set_blocking (t->rfd); set_blocking (t->wfd); free (t); } void terminal_atexit (void) { while (terminal_list) terminal_close ((TTY *) terminal_list); } static void sigint (int dummy) { terminal_atexit (); exit (-1); } static void sigwinch (int not) { terminal_winches++; } void terminal_getsize (TTY * _t) { TERMINAL *t = (TERMINAL *) _t; struct winsize sz = { 0 }; if (!t) return; if (ioctl (t->wfd, TIOCGWINSZ, &sz)) { t->size.x = CRT_COLS; t->size.y = CRT_ROWS; } else { t->size.x = sz.ws_col; t->size.y = sz.ws_row; } } void terminal_dispatch (void) { TERMINAL *t; if (!terminal_winches) return; terminal_winches = 0; for (t = terminal_list; t; t = t->next) terminal_getsize ((TTY *) t); } static int terminal_read (TTY * _t, void *buf, int len) { TERMINAL *t = (TERMINAL *) _t; int red, done = 0; terminal_dispatch (); set_nonblocking (t->rfd); do { red = wrap_read (t->rfd, buf, len); if (red < 0) return -1; if (!red) return done; buf += red; len -= red; done += red; } while (len); return done; } static int terminal_write (TTY * _t, void *buf, int len) { int writ, done = 0; TERMINAL *t = (TERMINAL *) _t; terminal_dispatch (); set_blocking (t->wfd); do { writ = wrap_write (t->wfd, buf, len); if (writ < 0) return -1; if (!writ) usleep (1000); buf += writ; len -= writ; done += writ; } while (len); return done; } void terminal_register_handlers (void) { struct sigaction sa = { {0} }; sa.sa_handler = sigwinch; sa.sa_flags = SA_RESTART; sigaction (SIGWINCH, &sa, NULL); sa.sa_handler = sigint; sa.sa_flags = SA_RESTART; sigaction (SIGINT, &sa, NULL); } TTY * terminal_open (int rfd, int wfd) { TERMINAL *t; struct termios termios; t = (TERMINAL *) xmalloc (sizeof (TERMINAL)); strcpy (t->name, "terminal"); t->rfd = rfd; t->wfd = wfd; tcgetattr (wfd, &t->orig_termios); t->next = terminal_list; terminal_list = t; tcgetattr (wfd, &termios); set_nonblocking (rfd); set_nonblocking (wfd); cfmakeraw (&termios); // raw_termios (&termios); tcsetattr (wfd, TCSANOW, &termios); t->recv = terminal_read; t->xmit = terminal_write; t->close = terminal_close; t->blocked = 0; terminal_getsize ((TTY *) t); return (TTY *) t; }