readstdin: reduce memory-usage by duplicating the line from getline() dfbbf7f6
Improves upon commit 32db2b125190d366be472ccb7cad833248696144

The getline() implementation often uses a more greedy way of allocating memory.
Using this buffer directly and forcing an allocation (by setting it to NULL)
would waste a bit of extra space, depending on the implementation of course.

Tested on musl libc and glibc.
The current glibc version allocates a minimum of 120 bytes per line.
For smaller lines musl libc seems less wasteful but still wastes a few bytes
per line.

On a dmenu_path listing on my system the memory usage was about 350kb (old) vs
30kb (new) on Void Linux glibc.

Side-note that getline() also reads NUL bytes in lines, while strdup() would
read until the NUL byte. Since dmenu reads text lines either is probably
fine(tm). Also rename junk to linesiz.
Hiltjo Posthuma · 2023-03-08 21:20 1 file(s) · +5 −4
dmenu.c +5 −4
550 550
readstdin(void)
551 551
{
552 552
	char *line = NULL;
553 -
	size_t i, junk, itemsiz = 0;
553 +
	size_t i, itemsiz = 0, linesiz = 0;
554 554
	ssize_t len;
555 555
556 556
	/* read each line from stdin and add it to the item list */
557 -
	for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++) {
557 +
	for (i = 0; (len = getline(&line, &linesiz, stdin)) != -1; i++) {
558 558
		if (i + 1 >= itemsiz) {
559 559
			itemsiz += 256;
560 560
			if (!(items = realloc(items, itemsiz * sizeof(*items))))
562 562
		}
563 563
		if (line[len - 1] == '\n')
564 564
			line[len - 1] = '\0';
565 -
		items[i].text = line;
565 +
		if (!(items[i].text = strdup(line)))
566 +
			die("strdup:");
567 +
566 568
		items[i].out = 0;
567 -
		line = NULL; /* next call of getline() allocates a new line */
568 569
	}
569 570
	free(line);
570 571
	if (items)