commit 1a4491e52655784bd60ea3de287121314a03ffcd from: Omar Polo date: Wed Sep 19 14:53:34 2018 UTC Simplified stdin reading A big buffer is allocated and all text is stored there. The overall time for reading/freeing the memory for the completion should be improved, no statistics made though. commit - 845963e5c302bb5f612a56968d0081f5f61feba4 commit + 1a4491e52655784bd60ea3de287121314a03ffcd blob - 5d7e58e4aaf497fa9135558aa218a19b681f45a9 blob + 6caf9fbf02dcbd1835de562398550930b3515557 --- mymenu.c +++ mymenu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include // XLookupString @@ -54,8 +55,11 @@ # define strcasestr strstr #endif -// The initial number of items to read -#define INITIAL_ITEMS 64 +// The number of char to read +#define STDIN_CHUNKS 64 + +// the number of lines to allocate in advance +#define LINES_CHUNK 32 // Abort if a is nil #define check_allocation(a) { \ @@ -365,44 +369,72 @@ char *normalize_str(const char *str) { return s; } -// read an arbitrary amount of text until an EOF and store it in -// lns. `items` is the capacity of lns. It may increase lns with -// `realloc(3)` to store more line. Return the number of lines -// read. The last item will always be a NULL pointer. It ignore the -// "null" (empty) lines -size_t readlines(char ***lns, size_t items) { - size_t n = 0; - char **lines = *lns; - while (true) { - size_t linelen = 0; - ssize_t l = getline(lines + n, &linelen, stdin); +size_t read_stdin(char **buf) { + size_t offset = 0; + size_t len = STDIN_CHUNKS; + *buf = malloc(len * sizeof(char)); + if (*buf == nil) + goto err; - if (l == -1) { - break; - } + while (true) { + ssize_t r = read(0, *buf + offset, STDIN_CHUNKS); + if (r < 1) + return len; - if (linelen == 0 || lines[n][0] == '\n') { - free(lines[n]); - lines[n] = nil; - continue; // forget about this line - } + offset += r; - strtok(lines[n], "\n"); // get rid of the \n + len += STDIN_CHUNKS; + *buf = realloc(*buf, len); + if (*buf == nil) + goto err; - ++n; + for (size_t i = offset; i < len; ++i) + (*buf)[i] = '\0'; + } - if (n == items - 1) { - items += items >>1; - char **l = realloc(lines, sizeof(char*) * items); - check_allocation(l); - *lns = l; - lines = l; + err: + fprintf(stderr, "Error in allocating memory for stdin.\n"); + exit(EX_UNAVAILABLE); +} + +// +size_t readlines(char ***lns, char **buf) { + *buf = nil; + size_t len = read_stdin(buf); + + size_t ll = LINES_CHUNK; + *lns = malloc(ll * sizeof(char*)); + size_t lines = 0; + bool in_line = false; + for (size_t i = 0; i < len; i++) { + char c = (*buf)[i]; + + if (c == '\0') + break; + + if (c == '\n') + (*buf)[i] = '\0'; + + if (in_line && c == '\n') + in_line = false; + + if (!in_line && c != '\n') { + in_line = true; + (*lns)[lines] = (*buf) + i; + lines++; + + if (lines == ll) { // resize + ll += LINES_CHUNK; + *lns = realloc(*lns, ll * sizeof(char*)); + if (*lns == nil) { + fprintf(stderr, "Error in memory allocation.\n"); + exit(EX_UNAVAILABLE); + } + } } } - n++; - lines[n] = nil; - return items; + return lines; } // Compute the dimension of the string str once rendered, return the @@ -1113,9 +1145,10 @@ int main(int argc, char **argv) { } // read the lines from stdin - char **lines = calloc(INITIAL_ITEMS, sizeof(char*)); - check_allocation(lines); - size_t nlines = readlines(&lines, INITIAL_ITEMS); + char **lines = nil; + char *buf = nil; + size_t nlines = readlines(&lines, &buf); + char **vlines = nil; if (sep != nil) { int l = strlen(sep); @@ -1668,13 +1701,7 @@ int main(int argc, char **argv) { free(fontname); free(text); - char *l = nil; - char **lns = lines; - while ((l = *lns) != nil) { - free(l); - ++lns; - } - + free(buf); free(lines); free(vlines); compls_delete(cs);