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:
parent
50fe7d2083
commit
eb0e9e79b9
47
lemonbar.c
47
lemonbar.c
|
@ -1263,6 +1263,7 @@ main (int argc, char **argv)
|
|||
xcb_expose_event_t *expose_ev;
|
||||
xcb_button_press_event_t *press_ev;
|
||||
char input[4096] = {0, };
|
||||
size_t input_off = 0;
|
||||
bool permanent = false;
|
||||
int geom_v[4] = { -1, -1, 0, 0 };
|
||||
int ch, areas;
|
||||
|
@ -1352,16 +1353,50 @@ main (int argc, char **argv)
|
|||
break;
|
||||
|
||||
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
|
||||
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
|
||||
if (fgets(input, sizeof(input), stdin) == NULL)
|
||||
break; // EOF received
|
||||
|
||||
parse(input);
|
||||
const char *t = memchr(input + from, '\n', end - from);
|
||||
if (!t) {
|
||||
break;
|
||||
}
|
||||
prelast = last;
|
||||
last = t - input;
|
||||
}
|
||||
if (last == -1) {
|
||||
// no newline found
|
||||
input_off = end;
|
||||
} else {
|
||||
input[last] = '\0';
|
||||
parse(input + (prelast + 1));
|
||||
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
|
||||
while ((ev = xcb_poll_for_event(c))) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user