Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ AM_CFLAGS=-Wall -Wextra
AM_CPPFLAGS=-D_GNU_SOURCE

bin_PROGRAMS=pick
pick_SOURCES=pick.c compat-reallocarray.c compat-strtonum.c compat.h
pick_SOURCES=compat-reallocarray.c \
compat-strtonum.c \
compat-xpoll.c \
compat.h \
pick.c
pick_CPPFLAGS=$(AM_CPPFLAGS) $(NCURSES_CFLAGS)
pick_LDADD=$(NCURSES_LIBS)

Expand Down
121 changes: 121 additions & 0 deletions compat-xpoll.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <poll.h>

#include "compat.h"

#ifdef HAVE_BROKEN_POLL

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

static int tty_peekc(int);

int
xpoll(struct pollfd *fds, nfds_t nfds, int timeout)
{
static int state;
int flags, inready, ttyready;
int nready = 0;

/* XXX filter_choices() poll disabled */
if (nfds == 1 && timeout == 0)
return 0;

if (state == 0) {
assert(nfds == 2);

flags = fcntl(fds[0].fd, F_GETFL, 0);
if (flags == -1)
return -1;
flags |= O_NONBLOCK;
if (fcntl(fds[0].fd, F_SETFL, flags) == -1)
return -1;
state++;
}

if (state == 1) {
if (timeout < 0)
timeout = 100;
while (nready == 0) {
if (nfds == 1) {
state++;
break;
}

inready = poll(&fds[1], 1, timeout);
if (inready == -1)
return -1;
nready += inready;

ttyready = tty_peekc(fds[0].fd);
if (ttyready == -1) {
return -1;
} else if (ttyready > 0) {
fds[0].revents = POLLIN;
nready++;
} else {
fds[0].revents = 0;
}
}
}

if (state == 2) {
flags = fcntl(fds[0].fd, F_GETFL, 0);
if (flags == -1)
return -1;
flags &= ~O_NONBLOCK;
if (fcntl(fds[0].fd, F_SETFL, flags) == -1)
return -1;
state++;
}

if (state == 3) {
ttyready = tty_peekc(fds[0].fd);
if (ttyready == -1) {
return -1;
} else if (ttyready > 0) {
fds[0].revents = POLLIN;
nready++;
} else {
fds[0].revents = 0;
}
}

return nready;
}

static int
tty_peekc(int fd)
{
extern int tty_getc_peek;
ssize_t n;
unsigned char c;

n = read(fd, &c, sizeof(c));
if (n == -1) {
if (errno == EAGAIN)
return 0;
return -1;
}
if (n > 0) {
assert(tty_getc_peek == -1);
tty_getc_peek = c;
}
return n;
}

#else

int
xpoll(struct pollfd *fds, nfds_t nfds, int timeout)
{
return poll(fds, nfds, timeout);
}

#endif /* HAVE_BROKEN_POLL */
2 changes: 2 additions & 0 deletions compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ long long strtonum(const char *, long long, long long, const char **);
#endif /* !HAVE_STRTONUM */

#endif /* COMPAT_H */

int xpoll(struct pollfd *fds, nfds_t nfds, int timeout);
3 changes: 3 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* config.h.in. Generated from configure.ac by autoheader. */

/* Define if poll does not support character devices */
#undef HAVE_BROKEN_POLL

/* Define if ncursesw is available */
#undef HAVE_NCURSESW_H

Expand Down
17 changes: 16 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ AC_PREREQ([2.61])
AC_INIT([pick], [2.0.2], [pick-maintainers@calleerlandsson.com])
AM_INIT_AUTOMAKE([subdir-objects])
AC_CONFIG_HEADERS([config.h])
AC_CANONICAL_HOST
AC_PROG_CC
AM_PROG_CC_C_O
AC_CHECK_FUNCS([pledge reallocarray strtonum])
Expand All @@ -16,7 +17,6 @@ AC_SEARCH_LIBS([setupterm], [curses], [], [
)
])
AC_DEFUN([AC_MALLOC_OPTIONS], [
AC_CANONICAL_HOST
AC_MSG_CHECKING([for $host_os malloc hardening options])
case "$host_os" in
openbsd*) malloc_options="RS";;
Expand All @@ -30,5 +30,20 @@ AC_DEFUN([AC_MALLOC_OPTIONS], [
AC_SUBST([MALLOC_OPTIONS], [$malloc_options])
])
AC_MALLOC_OPTIONS
AC_DEFUN([AC_BROKEN_POLL], [
AC_MSG_CHECKING([for broken poll implementation])
case "$host_os" in
darwin*) broken=1;;
*) broken=0;;
esac
if test "$broken" -eq 1; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_BROKEN_POLL], [1], [
Define if poll does not support character devices])
else
AC_MSG_RESULT([no])
fi
])
AC_BROKEN_POLL
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Loading