/* See LICENSE file for copyright and license details. */ #include "common.h" #define DEFER_EINTR(ERROR_CONDITION)\ DEFER_EINTR_(device, ERROR_CONDITION, fail) int libgamepad_drain__(struct libgamepad_device *device) { struct input_event buf[4 * 8]; int flags, saved_errno = errno; ssize_t r; if (device->internals->deferred_error) { errno = device->internals->deferred_error; device->internals->deferred_error = 0; return -1; } flags = fcntl(device->fd, F_GETFL); if (flags < 0) return -1; if (!(flags & O_NONBLOCK)) if (fcntl(device->fd, F_GETFL, flags | O_NONBLOCK) < 0) goto fail; for (;;) { r = read(device->fd, buf, sizeof(buf)); if (r < (ssize_t)sizeof(buf)) { if (r > 0) break; else if (!r) goto nodev; else if (errno == EAGAIN) break; else if (errno == EINTR) device->internals->deferred_error = EINTR; else goto fail; } } if (!(flags & O_NONBLOCK)) DEFER_EINTR(fcntl(device->fd, F_SETFL, flags) < 0); errno = saved_errno; return 0; nodev: errno = ENODEV; fail: return -1; }