2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* LINTLIBRARY */
2N/A
2N/A/*
2N/A * wgetch.c
2N/A *
2N/A * XCurses Library
2N/A *
2N/A * Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved.
2N/A *
2N/A */
2N/A
2N/A#ifdef M_RCSID
2N/A#ifndef lint
2N/Astatic char rcsID[] =
2N/A"$Header: /team/ps/sun_xcurses/archive/local_changes/xcurses/src/lib/"
2N/A"libxcurses/src/libc/xcurses/rcs/wgetch.c 1.23 1998/06/05 16:38:43 "
2N/A"cbates Exp $";
2N/A#endif
2N/A#endif
2N/A
2N/A#include <private.h>
2N/A#include <string.h>
2N/A#include <errno.h>
2N/A
2N/Astatic struct termios read_termios;
2N/A
2N/Aint
2N/AiqContainsFullLine(void)
2N/A{
2N/A int i;
2N/A
2N/A if (!(PTERMIOS(_prog)->c_lflag & ICANON)) {
2N/A /*
2N/A * Non-canonical mode ...
2N/A * Don't care about full lines ... continue
2N/A */
2N/A return (1);
2N/A }
2N/A if (read_termios.c_lflag & ICANON) {
2N/A /*
2N/A * Terminal subsystem worries about lines etc. ...
2N/A * continue ...
2N/A */
2N/A return (1);
2N/A }
2N/A /* We turned off ICANON so we have to do it ourselves */
2N/A if ((read_termios.c_cc[VMIN] == 0) &&
2N/A (read_termios.c_cc[VTIME] != 0)) {
2N/A /* We set delay mode. Only error if noting in the read */
2N/A return (!iqIsEmpty());
2N/A }
2N/A for (i = __m_screen->_unget._count - 1; i >= 0; i--) {
2N/A int ch = __m_screen->_unget._stack[i];
2N/A if (PTERMIOS(_shell)->c_cc[VEOL] == ch)
2N/A return (1);
2N/A if ('\n' == ch)
2N/A return (1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/AiqPush(unsigned int ch)
2N/A{
2N/A if (__m_screen->_unget._count >= __m_screen->_unget._size)
2N/A return;
2N/A __m_screen->_unget._stack[__m_screen->_unget._count++] = (int)ch;
2N/A}
2N/A
2N/Avoid
2N/AiqAdd(unsigned int ch)
2N/A{
2N/A int count;
2N/A
2N/A if (++(__m_screen->_unget._count) >= __m_screen->_unget._size)
2N/A __m_screen->_unget._count = __m_screen->_unget._size - 1;
2N/A count = __m_screen->_unget._count - 1;
2N/A if (count) {
2N/A (void) memmove(__m_screen->_unget._stack + 1,
2N/A __m_screen->_unget._stack, count * sizeof (int));
2N/A }
2N/A __m_screen->_unget._stack[0] = (int)ch;
2N/A}
2N/A
2N/Aint
2N/AiqIsEmpty(void)
2N/A{
2N/A return (__m_screen->_unget._count == 0);
2N/A}
2N/A
2N/Avoid
2N/AiqReset(void)
2N/A{
2N/A __m_screen->_unget._count = 0;
2N/A}
2N/A
2N/A/* Assumes count > 0 */
2N/Aint
2N/AiqPull(void)
2N/A{
2N/A int ch;
2N/A
2N/A ch = __m_screen->_unget._stack[--(__m_screen->_unget._count)];
2N/A return (ch);
2N/A}
2N/A
2N/A/* Discard n characters from front of Q */
2N/Avoid
2N/AiqTrash(int n)
2N/A{
2N/A __m_screen->_unget._count -= n;
2N/A if (__m_screen->_unget._count < 0) {
2N/A __m_screen->_unget._count = 0;
2N/A }
2N/A}
2N/A
2N/Aint
2N/AiqGetNth(int n)
2N/A{
2N/A int ch;
2N/A
2N/A if (__m_screen->_unget._count - n <= 0) {
2N/A return (EOF);
2N/A }
2N/A ch = __m_screen->_unget._stack[__m_screen->_unget._count - n - 1];
2N/A return (ch);
2N/A}
2N/A
2N/A
2N/Astruct termios
2N/A__m_tty_override_mode(int vmin, int vtime)
2N/A{
2N/A struct termios rval;
2N/A struct termios newstuff;
2N/A
2N/A rval = newstuff = *PTERMIOS(_actual);
2N/A
2N/A /* If halfdelay mode. Leave canonical mode intact */
2N/A if (!(vmin == 0 && vtime == 0) &&
2N/A (cur_term->_flags & __TERM_HALF_DELAY))
2N/A return (rval);
2N/A
2N/A /* If blocking mode. Leave canonical mode intact */
2N/A if (vmin == 1)
2N/A return (rval);
2N/A
2N/A /* VMIN and VTIME trash VEOL and VEOF so canonical cannot work */
2N/A newstuff.c_cc[VMIN] = (cc_t)vmin;
2N/A newstuff.c_cc[VTIME] = (cc_t)vtime;
2N/A newstuff.c_lflag &= ~ICANON;
2N/A
2N/A (void) __m_tty_set(&newstuff);
2N/A return (rval);
2N/A}
2N/A
2N/Aint
2N/A__m_read_input_char(int *pChar)
2N/A{
2N/A if (req_for_input != NULL) {
2N/A (void) TPUTS(req_for_input, 1, __m_outc);
2N/A }
2N/A clearerr(__m_screen->_if);
2N/A *pChar = 0;
2N/A /* save actual setting for later test */
2N/A read_termios = *PTERMIOS(_actual);
2N/A
2N/A errno = 0;
2N/A if ((*pChar = fgetc(__m_screen->_if)) == EOF) {
2N/A return ((errno) ? ERR : OK);
2N/A }
2N/A
2N/A if (((PTERMIOS(_prog)->c_cflag & CSIZE) != CS8) && (*pChar != EOF))
2N/A *pChar &= 0x7f;
2N/A return (OK);
2N/A}
2N/A
2N/Aint
2N/A__m_typeahead_read_input_char(int *pChar)
2N/A{
2N/A unsigned char ch;
2N/A ssize_t r;
2N/A
2N/A if (req_for_input != NULL) {
2N/A (void) TPUTS(req_for_input, 1, __m_outc);
2N/A }
2N/A
2N/A *pChar = 0;
2N/A /* save actual setting for later test */
2N/A read_termios = *PTERMIOS(_actual);
2N/A
2N/A errno = 0;
2N/A if ((r = read(__m_screen->_kfd, (void *)&ch, 1)) > 0) {
2N/A if ((PTERMIOS(_prog)->c_cflag & CSIZE) != CS8) {
2N/A *pChar = ch & 0x7f;
2N/A } else {
2N/A *pChar = (int)ch;
2N/A }
2N/A return (OK);
2N/A } else if (r == 0) {
2N/A *pChar = EOF;
2N/A return (OK);
2N/A } else {
2N/A return (ERR);
2N/A }
2N/A}
2N/A
2N/A
2N/Astatic int klugeTypeaheadInGetch = 0;
2N/A
2N/Aint
2N/ApollTypeahead(void)
2N/A{
2N/A struct termios save;
2N/A int ch;
2N/A
2N/A if (!(__m_screen->_flags & S_ISATTY) ||
2N/A !(__m_screen->_flags & S_TYPEAHEAD_OK)) {
2N/A /* Typeahead disabled */
2N/A return (0);
2N/A }
2N/A save = __m_tty_override_mode(0, 0);
2N/A while (__m_typeahead_read_input_char(&ch) == OK) {
2N/A if (ch == EOF)
2N/A break;
2N/A iqAdd(ch);
2N/A }
2N/A (void) __m_tty_set(&save);
2N/A /* if in wgetch, always do refresh */
2N/A return ((klugeTypeaheadInGetch) ? 0 : !iqIsEmpty());
2N/A}
2N/A
2N/A/*
2N/A * Push single-byte character back onto the input queue.
2N/A *
2N/A * MKS EXTENSION permits the return value of wgetch(), which
2N/A * can be a KEY_ value, to be pushed back.
2N/A */
2N/Aint
2N/Aungetch(int ch)
2N/A{
2N/A iqPush(ch);
2N/A return (OK);
2N/A}
2N/A
2N/A/*
2N/A * Return true if the SCREEN's stream has an I/O error.
2N/A * Ignore the window parameter.
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/A__xc_ferror(void *w)
2N/A{
2N/A return (ferror(__m_screen->_if));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/A__xc_ungetc(int ch, void *w)
2N/A{
2N/A iqPush(ch);
2N/A return (1);
2N/A}
2N/A
2N/A/*
2N/A * Return true if the SCREEN's stream has seen EOF.
2N/A * Ignore the window parameter.
2N/A */
2N/A/* ARGSUSED */
2N/Aint
2N/A__xc_feof(void *w)
2N/A{
2N/A return (feof(__m_screen->_if));
2N/A}
2N/A
2N/A/*
2N/A * Clear the error and eof flags of the SCREEN's stream.
2N/A * Ignore the window parameter.
2N/A */
2N/A/* ARGSUSED */
2N/Avoid
2N/A__xc_clearerr(void *w)
2N/A{
2N/A clearerr(__m_screen->_if);
2N/A}
2N/A
2N/Aint
2N/A__m_echo(WINDOW *w, int ch)
2N/A{
2N/A if (!(__m_screen->_flags & S_ECHO))
2N/A return (ch);
2N/A if (!(0 <= ch && ch != EOF)) {
2N/A (void) beep();
2N/A return (ERR);
2N/A }
2N/A if (ch == '\b') {
2N/A if (w->_curx <= 0) {
2N/A (void) beep();
2N/A return (ch);
2N/A }
2N/A w->_curx--;
2N/A (void) wdelch(w);
2N/A } else {
2N/A (void) waddch(w, ch);
2N/A }
2N/A (void) wrefresh(w);
2N/A return (ch);
2N/A}
2N/A
2N/Aint
2N/Awgetch(WINDOW *w)
2N/A{
2N/A t_decode *node;
2N/A int ch, i, timeout;
2N/A struct termios save;
2N/A
2N/A __m_screen->_flags |= S_TYPEAHEAD_OK;
2N/A
2N/A klugeTypeaheadInGetch = 1;
2N/A (void) wrefresh(w);
2N/A klugeTypeaheadInGetch = 0;
2N/A
2N/A if (iqIsEmpty()) {
2N/A save = __m_tty_override_mode(w->_vmin, w->_vtime);
2N/A if (__m_read_input_char(&ch) == ERR) {
2N/A (void) __m_tty_set(&save);
2N/A return (ERR);
2N/A }
2N/A if (!((ch == EOF) && (PTERMIOS(_prog)->c_lflag & ICANON))) {
2N/A /* Put EOF on Q only in non-canonical mode */
2N/A iqAdd(ch);
2N/A }
2N/A (void) __m_tty_set(&save);
2N/A }
2N/A ch = iqGetNth(0);
2N/A if (!iqContainsFullLine()) {
2N/A return (ERR);
2N/A }
2N/A
2N/A /*
2N/A * Only check for function keys if keypad is true and we
2N/A * did not read a KEY_ value (which are < 0), nor EOF.
2N/A * It is conceivable that a KEY_ was pushed back with
2N/A * ungetch().
2N/A */
2N/A if ((w->_flags & W_USE_KEYPAD) && 0 <= ch && ch != EOF) {
2N/A /*
2N/A * Treat the termios ERASE key the same as key_backspace.
2N/A *
2N/A * We used to change the key_backspace entry to be a string
2N/A * containing the ERASE key in setupterm(), but this would
2N/A * then disable the real terminfo entry for the backspace key.
2N/A * Apparently VT300 terminals change the key code/sequence
2N/A * of the backspace key in application keypad mode.
2N/A * See SR 6014.
2N/A *
2N/A * Refer to _shell instead of _prog, since _shell will
2N/A * correctly reflect the user's prefered settings, whereas
2N/A * _prog may not have been initialised if both input and
2N/A * output have been redirected.
2N/A */
2N/A#ifdef _POSIX_VDISABLE
2N/A if (PTERMIOS(_shell)->c_cc[VERASE] != _POSIX_VDISABLE)
2N/A#endif
2N/A if (ch == PTERMIOS(_shell)->c_cc[VERASE]) {
2N/A /* Discard ch from Q */
2N/A (void) iqPull();
2N/A return (KEY_BACKSPACE);
2N/A }
2N/A
2N/A /* Begin check for function key. */
2N/A node = (t_decode *) __m_screen->_decode;
2N/A
2N/A /* Use input stack as a queue. */
2N/A timeout = w->_flags & W_USE_TIMEOUT;
2N/A for (i = 1; ; i++) {
2N/A while (node->ch != ch) {
2N/A node = node->sibling;
2N/A if (node == NULL)
2N/A goto uncoded;
2N/A }
2N/A
2N/A /* Found funuction key? */
2N/A if (node->key != 0) {
2N/A /* Trash all input used to make the FKey */
2N/A iqTrash(i);
2N/A return (__m_echo(w, node->key));
2N/A }
2N/A
2N/A /*
2N/A * Get next candidate character -
2N/A * either from Q or input
2N/A */
2N/A if ((ch = iqGetNth(i)) == EOF) {
2N/A int overridden = 0;
2N/A /*
2N/A * Setup interbyte timer (once only).
2N/A * fgetc() will return EOF if no input received,
2N/A * which may not be a true EOF.
2N/A */
2N/A if (timeout) {
2N/A save = __m_tty_override_mode(0,
2N/A M_CURSES_INTERBYTE_TIME);
2N/A overridden = 1;
2N/A }
2N/A timeout = 0;
2N/A if (__m_read_input_char(&ch) == ERR) {
2N/A if (overridden)
2N/A (void) __m_tty_set(&save);
2N/A return (ERR);
2N/A }
2N/A if (overridden)
2N/A (void) __m_tty_set(&save);
2N/A /* Timeout or real eof. */
2N/A if (ch == EOF)
2N/A break;
2N/A iqAdd(ch);
2N/A }
2N/A
2N/A /* Incomplete sequence, continue. */
2N/A node = node->child;
2N/A }
2N/A }
2N/Auncoded:
2N/A /* Return first byte received or EOF. */
2N/A ch = iqPull();
2N/A return (__m_echo(w, ch));
2N/A}