Exemple #1
0
wchar_t input_common_readch(int timed) {
    if (!has_lookahead()) {
        if (timed) {
            fd_set fds;
            FD_ZERO(&fds);
            FD_SET(0, &fds);
            struct timeval tm = {wait_on_escape_ms / 1000, 1000 * (wait_on_escape_ms % 1000)};
            int count = select(1, &fds, 0, 0, &tm);
            if (count <= 0) {
                return R_TIMEOUT;
            }
        }

        wchar_t res;
        mbstate_t state = {};

        while (1) {
            wint_t b = readb();

            if (b >= R_NULL && b < R_END_INPUT_FUNCTIONS) return b;

            if (MB_CUR_MAX == 1) {
                // return (unsigned char)b;  // single-byte locale, all values are legal
                return b;  // single-byte locale, all values are legal
            }

            char bb = b;
            size_t sz = mbrtowc(&res, &bb, 1, &state);

            switch (sz) {
                case (size_t)(-1): {
                    memset(&state, '\0', sizeof(state));
                    debug(2, L"Illegal input");
                    return R_NULL;
                }
                case (size_t)(-2): {
                    break;
                }
                case 0: {
                    return 0;
                }
                default: { return res; }
            }
        }
    } else {
        if (!timed) {
            while (has_lookahead() && lookahead_front() == R_TIMEOUT) lookahead_pop();
            if (!has_lookahead()) return input_common_readch(0);
        }

        return lookahead_pop();
    }
}
Exemple #2
0
/// \return the next lookahead char, or none if none. Discards timeouts.
static maybe_t<char_event_t> lookahead_pop_evt() {
    while (has_lookahead()) {
        auto evt = lookahead_pop();
        if (! evt.is_timeout()) {
            return evt;
        }
    }
    return none();
}
Exemple #3
0
char_event_t input_common_readch_timed(bool dequeue_timeouts) {
    char_event_t result{char_event_type_t::timeout};
    if (has_lookahead()) {
        result = lookahead_pop();
    } else {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(STDIN_FILENO, &fds);
        struct timeval tm = {wait_on_escape_ms / 1000, 1000 * (wait_on_escape_ms % 1000)};
        if (select(1, &fds, 0, 0, &tm) > 0) {
            result = input_common_readch();
        }
    }
    // If we got a timeout, either through dequeuing or creating, ensure it stays on the queue.
    if (result.is_timeout()) {
        if (!dequeue_timeouts) lookahead_push_front(char_event_type_t::timeout);
        return char_event_type_t::timeout;
    }
    return result;
}
Exemple #4
0
/// Internal function used by input_common_readch to read one byte from fd 0. This function should
/// only be called by input_common_readch().
static wint_t readb() {
    // do_loop must be set on every path through the loop; leaving it uninitialized allows the
    // static analyzer to assist in catching mistakes.
    unsigned char arr[1];
    bool do_loop;

    do {
        // Flush callbacks.
        input_flush_callbacks();

        fd_set fdset;
        int fd_max = 0;
        int ioport = iothread_port();
        int res;

        FD_ZERO(&fdset);
        FD_SET(0, &fdset);
        if (ioport > 0) {
            FD_SET(ioport, &fdset);
            fd_max = maxi(fd_max, ioport);
        }

        // Get our uvar notifier.
        universal_notifier_t &notifier = universal_notifier_t::default_notifier();

        // Get the notification fd (possibly none).
        int notifier_fd = notifier.notification_fd();
        if (notifier_fd > 0) {
            FD_SET(notifier_fd, &fdset);
            fd_max = maxi(fd_max, notifier_fd);
        }

        // Get its suggested delay (possibly none).
        struct timeval tv = {};
        const unsigned long usecs_delay = notifier.usec_delay_between_polls();
        if (usecs_delay > 0) {
            unsigned long usecs_per_sec = 1000000;
            tv.tv_sec = (int)(usecs_delay / usecs_per_sec);
            tv.tv_usec = (int)(usecs_delay % usecs_per_sec);
        }

        res = select(fd_max + 1, &fdset, 0, 0, usecs_delay > 0 ? &tv : NULL);
        if (res == -1) {
            if (errno == EINTR || errno == EAGAIN) {
                if (interrupt_handler) {
                    int res = interrupt_handler();
                    if (res) return res;
                    if (has_lookahead()) return lookahead_pop();
                }

                do_loop = true;
            } else {
                // The terminal has been closed. Save and exit.
                return R_EOF;
            }
        } else {
            // Assume we loop unless we see a character in stdin.
            do_loop = true;

            // Check to see if we want a universal variable barrier.
            bool barrier_from_poll = notifier.poll();
            bool barrier_from_readability = false;
            if (notifier_fd > 0 && FD_ISSET(notifier_fd, &fdset)) {
                barrier_from_readability = notifier.notification_fd_became_readable(notifier_fd);
            }
            if (barrier_from_poll || barrier_from_readability) {
                env_universal_barrier();
            }

            if (ioport > 0 && FD_ISSET(ioport, &fdset)) {
                iothread_service_completion();
                if (has_lookahead()) {
                    return lookahead_pop();
                }
            }

            if (FD_ISSET(STDIN_FILENO, &fdset)) {
                if (read_blocked(0, arr, 1) != 1) {
                    // The teminal has been closed. Save and exit.
                    return R_EOF;
                }

                // We read from stdin, so don't loop.
                do_loop = false;
            }
        }
    } while (do_loop);

    return arr[0];
}
Exemple #5
0
wchar_t input_common_readch(int timed)
{
    if (! has_lookahead())
    {
        if (timed)
        {
            int count;
            fd_set fds;
            struct timeval tm=
            {
                0,
                1000 * WAIT_ON_ESCAPE
            }
            ;

            FD_ZERO(&fds);
            FD_SET(0, &fds);
            count = select(1, &fds, 0, 0, &tm);

            switch (count)
            {
                case 0:
                    return WEOF;

                case -1:
                    return WEOF;
                    break;
                default:
                    break;

            }
        }

        wchar_t res;
        mbstate_t state = {};

        while (1)
        {
            wint_t b = readb();
            char bb;

            size_t sz;

            if ((b >= R_NULL) && (b < R_NULL + 1000))
                return b;

            bb=b;

            sz = mbrtowc(&res, &bb, 1, &state);

            switch (sz)
            {
                case (size_t)(-1):
                    memset(&state, '\0', sizeof(state));
                    debug(2, L"Illegal input");
                    return R_NULL;
                case (size_t)(-2):
                    break;
                case 0:
                    return 0;
                default:
                    return res;
            }
        }
    }
    else
    {
        if (!timed)
        {
            while (has_lookahead() && lookahead_top() == WEOF)
                lookahead_pop();
            if (! has_lookahead())
                return input_common_readch(0);
        }

        return lookahead_pop();
    }
}