This would allow reading from multiple files (which we don't need) as
well as allowing us to free the buffer with the rest of the choices
structure (which is nice).
| ... | ... |
@@ -6,7 +6,7 @@ |
| 6 | 6 |
#include "match.h" |
| 7 | 7 |
|
| 8 | 8 |
/* Initial size of buffer for storing input in memory */ |
| 9 |
-#define INITIAL_BUFFER_SIZE 4096 |
|
| 9 |
+#define INITIAL_BUFFER_CAPACITY 4096 |
|
| 10 | 10 |
|
| 11 | 11 |
/* Initial size of choices array */ |
| 12 | 12 |
#define INITIAL_CHOICE_CAPACITY 128 |
| ... | ... |
@@ -34,23 +34,32 @@ static void *safe_realloc(void *buffer, size_t size) {
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
void choices_fread(choices_t *c, FILE *file) {
|
| 37 |
- size_t bufsize = INITIAL_BUFFER_SIZE, pos = 0; |
|
| 38 |
- char *buf = safe_realloc(NULL, bufsize); |
|
| 37 |
+ /* Save current position for parsing later */ |
|
| 38 |
+ size_t buffer_start = c->buffer_size; |
|
| 39 |
+ |
|
| 40 |
+ /* Resize buffer to at least one byte more capacity than our current |
|
| 41 |
+ * size. This uses a power of two of INITIAL_BUFFER_CAPACITY. |
|
| 42 |
+ * This must work even when c->buffer is NULL and c->buffer_size is 0 |
|
| 43 |
+ */ |
|
| 44 |
+ size_t capacity = INITIAL_BUFFER_CAPACITY; |
|
| 45 |
+ while (capacity <= c->buffer_size) |
|
| 46 |
+ capacity *= 2; |
|
| 47 |
+ c->buffer = safe_realloc(c->buffer, capacity); |
|
| 39 | 48 |
|
| 40 | 49 |
/* Continue reading until we get a "short" read, indicating EOF */ |
| 41 |
- while ((pos += fread(buf + pos, 1, bufsize - pos, file)) == bufsize) {
|
|
| 42 |
- bufsize *= 2; |
|
| 43 |
- buf = safe_realloc(buf, bufsize); |
|
| 50 |
+ while ((c->buffer_size += fread(c->buffer + c->buffer_size, 1, capacity - c->buffer_size, file)) == capacity) {
|
|
| 51 |
+ capacity *= 2; |
|
| 52 |
+ c->buffer = safe_realloc(c->buffer, capacity); |
|
| 44 | 53 |
} |
| 45 |
- buf[pos] = 0; |
|
| 54 |
+ c->buffer = safe_realloc(c->buffer, c->buffer_size + 1); |
|
| 55 |
+ c->buffer[c->buffer_size++] = 0; |
|
| 46 | 56 |
|
| 47 | 57 |
/* Truncate buffer to used size, (maybe) freeing some memory for |
| 48 | 58 |
* future allocations. |
| 49 | 59 |
*/ |
| 50 |
- buf = safe_realloc(buf, pos + 1); |
|
| 51 | 60 |
|
| 52 | 61 |
/* Tokenize input and add to choices */ |
| 53 |
- char *line = buf; |
|
| 62 |
+ char *line = c->buffer + buffer_start; |
|
| 54 | 63 |
do {
|
| 55 | 64 |
char *nl = strchr(line, '\n'); |
| 56 | 65 |
if (nl) |
| ... | ... |
@@ -78,14 +87,28 @@ static void choices_reset_search(choices_t *c) {
|
| 78 | 87 |
void choices_init(choices_t *c) {
|
| 79 | 88 |
c->strings = NULL; |
| 80 | 89 |
c->results = NULL; |
| 90 |
+ |
|
| 91 |
+ c->buffer_size = 0; |
|
| 92 |
+ c->buffer = NULL; |
|
| 93 |
+ |
|
| 81 | 94 |
c->capacity = c->size = 0; |
| 82 |
- choices_reset_search(c); |
|
| 83 | 95 |
choices_resize(c, INITIAL_CHOICE_CAPACITY); |
| 96 |
+ |
|
| 97 |
+ choices_reset_search(c); |
|
| 84 | 98 |
} |
| 85 | 99 |
|
| 86 | 100 |
void choices_free(choices_t *c) {
|
| 101 |
+ free(c->buffer); |
|
| 102 |
+ c->buffer = NULL; |
|
| 103 |
+ c->buffer_size = 0; |
|
| 104 |
+ |
|
| 87 | 105 |
free(c->strings); |
| 106 |
+ c->strings = NULL; |
|
| 107 |
+ c->capacity = c->size = 0; |
|
| 108 |
+ |
|
| 88 | 109 |
free(c->results); |
| 110 |
+ c->results = NULL; |
|
| 111 |
+ c->available = c->selection = 0; |
|
| 89 | 112 |
} |
| 90 | 113 |
|
| 91 | 114 |
void choices_add(choices_t *c, const char *choice) {
|