Skip to content

Commit

Permalink
Fix the long-standing multiline input problem
Browse files Browse the repository at this point in the history
Closes #107
  • Loading branch information
LemonBoy committed Nov 5, 2020
1 parent abc006e commit 9e35bd6
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ifneq "$(GIT_DESC)" ""
endif

CC ?= gcc
CFLAGS += -Wall -std=c99 -Os -DVERSION="\"$(VERSION)\""
CFLAGS += -Wall -std=c99 -Os -DVERSION="\"$(VERSION)\"" -D_GNU_SOURCE
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
Expand Down
43 changes: 39 additions & 4 deletions lemonbar.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
#if WITH_XINERAMA
Expand Down Expand Up @@ -1347,6 +1348,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_offset = 0;
bool permanent = false;
int geom_v[4] = { -1, -1, 0, 0 };
int ch, areas;
Expand Down Expand Up @@ -1443,11 +1445,44 @@ main (int argc, char **argv)
else break; // ...bail out
}
if (pollin[0].revents & POLLIN) { // New input, process it
if (fgets(input, sizeof(input), stdin) == NULL)
break; // EOF received
while (true) {
ssize_t r = read(STDIN_FILENO, input + input_offset,
sizeof(input) - input_offset);
if (r == 0) break;
if (r < 0) {
if (errno == EINTR) continue;
exit(EXIT_FAILURE);
}

input_offset += r;

// Try to find the last complete input line in the buffer.
char *input_end = input + input_offset;
char *last_nl = memrchr(input, '\n', input_end - input);

if (last_nl) {
char *prev_nl = (last_nl != input) ?
memrchr(input, '\n', last_nl - 1 - input) : NULL;
char *begin = prev_nl? prev_nl + 1: input;

*last_nl = '\0';

parse(begin);
redraw = true;

parse(input);
redraw = true;
// Move the unparsed part back to the beginning.
memmove(input, last_nl + 1, input_end - (last_nl + 1));

This comment has been minimized.

Copy link
@shdown

shdown Nov 5, 2020

memmove expects dereferenceable pointers even if the size argument is 0. If last_nl is input + 4095, last_nl + 1 is not dereferenceable.

This comment has been minimized.

Copy link
@LemonBoy

LemonBoy Nov 5, 2020

Author Owner

Good catch, can you send a pr to skip the memmove if there's nothing to copy?

input_offset = input_end - (last_nl + 1);

break;
}

// The input buffer is full and we haven't seen a newline
// yet, discard everything and start from zero.
if (sizeof(input) == input_offset) {
input_offset = 0;
}
}
}
if (pollin[1].revents & POLLIN) { // The event comes from the Xorg server
while ((ev = xcb_poll_for_event(c))) {
Expand Down

1 comment on commit 9e35bd6

@Anachron
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @LemonBoy !

Please sign in to comment.