Fix buffering bug: use read() for reading instead of fgets()

stdin is buffered and using fgets() invokes read(), which could read
multiple lines at one, while reporting only first of them.

Testcase:

    { echo a; echo b; while sleep 1; do :; done; } | lemonbar

only outputs a.
This commit is contained in:
shdown 2017-02-06 13:14:17 +03:00
parent 50fe7d2083
commit eb0e9e79b9

View File

@ -1263,6 +1263,7 @@ main (int argc, char **argv)
xcb_expose_event_t *expose_ev; xcb_expose_event_t *expose_ev;
xcb_button_press_event_t *press_ev; xcb_button_press_event_t *press_ev;
char input[4096] = {0, }; char input[4096] = {0, };
size_t input_off = 0;
bool permanent = false; bool permanent = false;
int geom_v[4] = { -1, -1, 0, 0 }; int geom_v[4] = { -1, -1, 0, 0 };
int ch, areas; int ch, areas;
@ -1352,16 +1353,50 @@ main (int argc, char **argv)
break; break;
if (poll(pollin, 2, -1) > 0) { if (poll(pollin, 2, -1) > 0) {
if (pollin[0].revents & POLLHUP) { // No more data... if (pollin[0].revents & (POLLIN | POLLHUP)) { // New input (or no more data)
if (input_off == sizeof(input)) {
input_off = 0;
}
ssize_t r;
while ((r = read(0, input + input_off, sizeof(input) - input_off)) < 0 && errno == EINTR)
;
if (r < 0) {
perror("read");
break;
} else if (r == 0) { // No more data...
if (permanent) pollin[0].fd = -1; // ...null the fd and continue polling :D if (permanent) pollin[0].fd = -1; // ...null the fd and continue polling :D
else break; // ...bail out else break; // ...bail out
} else {
const size_t end = input_off + r;
// find the last occurence of \n and one before it
size_t last = -1, prelast = -1;
while (1) {
const size_t from = last + 1;
if (from == end) {
break;
} }
if (pollin[0].revents & POLLIN) { // New input, process it const char *t = memchr(input + from, '\n', end - from);
if (fgets(input, sizeof(input), stdin) == NULL) if (!t) {
break; // EOF received break;
}
parse(input); prelast = last;
last = t - input;
}
if (last == -1) {
// no newline found
input_off = end;
} else {
input[last] = '\0';
parse(input + (prelast + 1));
redraw = true; redraw = true;
const size_t n = end - (last + 1);
if (n) {
memmove(input, input + (last + 1), n);
}
input_off = n;
}
}
} }
if (pollin[1].revents & POLLIN) { // The event comes from the Xorg server if (pollin[1].revents & POLLIN) { // The event comes from the Xorg server
while ((ev = xcb_poll_for_event(c))) { while ((ev = xcb_poll_for_event(c))) {