diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compgen.c | 91 | ||||
-rw-r--r-- | src/compgen.h | 10 | ||||
-rw-r--r-- | src/desktop_vec.c | 10 | ||||
-rw-r--r-- | src/desktop_vec.h | 2 | ||||
-rw-r--r-- | src/entry.h | 5 | ||||
-rw-r--r-- | src/input.c | 14 | ||||
-rw-r--r-- | src/log.c | 12 | ||||
-rw-r--r-- | src/main.c | 90 | ||||
-rw-r--r-- | src/main_compgen.c | 12 | ||||
-rw-r--r-- | src/string_vec.c | 91 | ||||
-rw-r--r-- | src/string_vec.h | 49 |
11 files changed, 257 insertions, 129 deletions
diff --git a/src/compgen.c b/src/compgen.c index 6cc21a2..2fb2a04 100644 --- a/src/compgen.c +++ b/src/compgen.c @@ -50,7 +50,60 @@ static char *get_cache_path() { return cache_name; } -struct string_vec compgen_cached() +static void write_cache(const char *buffer, const char *filename) +{ + errno = 0; + FILE *fp = fopen(filename, "wb"); + if (!fp) { + log_error("Failed to open cache file \"%s\": %s\n", filename, strerror(errno)); + return; + } + size_t len = strlen(buffer); + errno = 0; + if (fwrite(buffer, len, 1, fp) != len) { + log_error("Error writing cache file \"%s\": %s\n", filename, strerror(errno)); + } + fclose(fp); +} + +static char *read_cache(const char *filename) +{ + errno = 0; + FILE *fp = fopen(filename, "rb"); + if (!fp) { + log_error("Failed to open cache file \"%s\": %s\n", filename, strerror(errno)); + return NULL; + } + if (fseek(fp, 0, SEEK_END)) { + log_error("Failed to seek in cache file: %s\n", strerror(errno)); + fclose(fp); + return NULL; + } + size_t size; + { + long ssize = ftell(fp); + if (ssize < 0) { + log_error("Failed to determine cache file size: %s\n", strerror(errno)); + fclose(fp); + return NULL; + } + size = (size_t)ssize; + } + char *cache = xmalloc(size + 1); + rewind(fp); + if (fread(cache, 1, size, fp) != size) { + log_error("Failed to read cache file: %s\n", strerror(errno)); + free(cache); + fclose(fp); + return NULL; + } + fclose(fp); + cache[size] = '\0'; + + return cache; +} + +char *compgen_cached() { log_debug("Retrieving PATH.\n"); const char *env_path = getenv("PATH"); @@ -71,15 +124,12 @@ struct string_vec compgen_cached() errno = 0; if (stat(cache_path, &sb) == -1) { if (errno == ENOENT) { - struct string_vec commands = compgen(); + char *commands = compgen(); if (!mkdirp(cache_path)) { free(cache_path); return commands; } - FILE *cache = fopen(cache_path, "wb"); - string_vec_save(&commands, cache); - fclose(cache); - free(cache_path); + write_cache(commands, cache_path); return commands; } free(cache_path); @@ -103,26 +153,22 @@ struct string_vec compgen_cached() } free(path); - struct string_vec commands; + char *commands; if (out_of_date) { log_debug("Cache out of date, updating.\n"); log_indent(); commands = compgen(); log_unindent(); - FILE *cache = fopen(cache_path, "wb"); - string_vec_save(&commands, cache); - fclose(cache); + write_cache(commands, cache_path); } else { log_debug("Cache up to date, loading.\n"); - FILE *cache = fopen(cache_path, "rb"); - commands = string_vec_load(cache); - fclose(cache); + commands = read_cache(cache_path); } free(cache_path); return commands; } -struct string_vec compgen() +char *compgen() { log_debug("Retrieving PATH.\n"); const char *env_path = getenv("PATH"); @@ -167,7 +213,18 @@ struct string_vec compgen() log_debug("Making unique.\n"); string_vec_uniq(&programs); - return programs; + size_t buf_len = 0; + for (size_t i = 0; i < programs.count; i++) { + buf_len += strlen(programs.buf[i].string) + 1; + } + char *buf = xmalloc(buf_len + 1); + size_t bytes_written = 0; + for (size_t i = 0; i < programs.count; i++) { + bytes_written += sprintf(&buf[bytes_written], "%s\n", programs.buf[i].string); + } + buf[bytes_written] = '\0'; + + return buf; } static int cmpscorep(const void *restrict a, const void *restrict b) @@ -177,11 +234,11 @@ static int cmpscorep(const void *restrict a, const void *restrict b) return str2->history_score - str1->history_score; } -void compgen_history_sort(struct string_vec *programs, struct history *history) +void compgen_history_sort(struct string_ref_vec *programs, struct history *history) { log_debug("Moving already known programs to the front.\n"); for (size_t i = 0; i < history->count; i++) { - struct scored_string *res = string_vec_find_sorted(programs, history->buf[i].name); + struct scored_string_ref *res = string_ref_vec_find_sorted(programs, history->buf[i].name); if (res == NULL) { log_debug("History entry \"%s\" not found.\n", history->buf[i].name); continue; diff --git a/src/compgen.h b/src/compgen.h index a80c62b..5e36576 100644 --- a/src/compgen.h +++ b/src/compgen.h @@ -4,8 +4,12 @@ #include "history.h" #include "string_vec.h" -struct string_vec compgen(void); -struct string_vec compgen_cached(void); -void compgen_history_sort(struct string_vec *programs, struct history *history); +[[nodiscard("memory leaked")]] +char *compgen(void); + +[[nodiscard("memory leaked")]] +char *compgen_cached(void); + +void compgen_history_sort(struct string_ref_vec *programs, struct history *history); #endif /* COMPGEN_H */ diff --git a/src/desktop_vec.c b/src/desktop_vec.c index a9aa1f7..de7fcd7 100644 --- a/src/desktop_vec.c +++ b/src/desktop_vec.c @@ -145,12 +145,12 @@ struct desktop_entry *desktop_vec_find_sorted(struct desktop_vec *restrict vec, return bsearch(&tmp, vec->buf, vec->count, sizeof(vec->buf[0]), cmpdesktopp); } -struct string_vec desktop_vec_filter( +struct string_ref_vec desktop_vec_filter( const struct desktop_vec *restrict vec, const char *restrict substr, bool fuzzy) { - struct string_vec filt = string_vec_create(); + struct string_ref_vec filt = string_ref_vec_create(); for (size_t i = 0; i < vec->count; i++) { int32_t search_score; if (fuzzy) { @@ -159,7 +159,7 @@ struct string_vec desktop_vec_filter( search_score = fuzzy_match_simple_words(substr, vec->buf[i].name); } if (search_score != INT32_MIN) { - string_vec_add(&filt, vec->buf[i].name); + string_ref_vec_add(&filt, vec->buf[i].name); /* * Store the position of the match in the string as * its search_score, for later sorting. @@ -174,7 +174,7 @@ struct string_vec desktop_vec_filter( search_score = fuzzy_match_simple_words(substr, vec->buf[i].keywords); } if (search_score != INT32_MIN) { - string_vec_add(&filt, vec->buf[i].name); + string_ref_vec_add(&filt, vec->buf[i].name); /* * Arbitrary score addition to make name * matches preferred over keyword matches. @@ -254,7 +254,6 @@ bool match_current_desktop(char * const *desktop_list, gsize length) string_vec_add(&desktops, desktop); desktop = strtok_r(NULL, ":", &saveptr); } - free(tmp); string_vec_sort(&desktops); for (gsize i = 0; i < length; i++) { @@ -264,6 +263,7 @@ bool match_current_desktop(char * const *desktop_list, gsize length) } string_vec_destroy(&desktops); + free(tmp); return false; } diff --git a/src/desktop_vec.h b/src/desktop_vec.h index 760db30..f8d0b79 100644 --- a/src/desktop_vec.h +++ b/src/desktop_vec.h @@ -34,7 +34,7 @@ void desktop_vec_add_file(struct desktop_vec *desktop, const char *id, const cha void desktop_vec_sort(struct desktop_vec *restrict vec); struct desktop_entry *desktop_vec_find_sorted(struct desktop_vec *restrict vec, const char *name); -struct string_vec desktop_vec_filter( +struct string_ref_vec desktop_vec_filter( const struct desktop_vec *restrict vec, const char *restrict substr, bool fuzzy); diff --git a/src/entry.h b/src/entry.h index a9353a5..4ee6316 100644 --- a/src/entry.h +++ b/src/entry.h @@ -55,8 +55,9 @@ struct entry { uint32_t selection; uint32_t first_result; - struct string_vec results; - struct string_vec commands; + char *command_buffer; + struct string_ref_vec results; + struct string_ref_vec commands; struct desktop_vec apps; struct history history; bool use_pango; diff --git a/src/input.c b/src/input.c index 5864cd1..9be16e9 100644 --- a/src/input.c +++ b/src/input.c @@ -130,13 +130,13 @@ void add_character(struct tofi *tofi, xkb_keycode_t keycode) N_ELEM(buf)); entry->input_utf8_length += len; if (entry->drun) { - struct string_vec results = desktop_vec_filter(&entry->apps, entry->input_utf8, tofi->fuzzy_match); - string_vec_destroy(&entry->results); + struct string_ref_vec results = desktop_vec_filter(&entry->apps, entry->input_utf8, tofi->fuzzy_match); + string_ref_vec_destroy(&entry->results); entry->results = results; } else { - struct string_vec tmp = entry->results; - entry->results = string_vec_filter(&entry->results, entry->input_utf8, tofi->fuzzy_match); - string_vec_destroy(&tmp); + struct string_ref_vec tmp = entry->results; + entry->results = string_ref_vec_filter(&entry->results, entry->input_utf8, tofi->fuzzy_match); + string_ref_vec_destroy(&tmp); } reset_selection(tofi); @@ -154,11 +154,11 @@ void input_refresh_results(struct tofi *tofi) } entry->input_utf8[bytes_written] = '\0'; entry->input_utf8_length = bytes_written; - string_vec_destroy(&entry->results); + string_ref_vec_destroy(&entry->results); if (entry->drun) { entry->results = desktop_vec_filter(&entry->apps, entry->input_utf8, tofi->fuzzy_match); } else { - entry->results = string_vec_filter(&entry->commands, entry->input_utf8, tofi->fuzzy_match); + entry->results = string_ref_vec_filter(&entry->commands, entry->input_utf8, tofi->fuzzy_match); } reset_selection(tofi); @@ -53,11 +53,11 @@ void log_warning(const char *const fmt, ...) void log_debug(const char *const fmt, ...) { #ifndef DEBUG - return; + //return; #endif static struct timespec start_time; if (start_time.tv_nsec == 0) { - fprintf(stderr, "[ real, cpu, maxRSS]\n"); + fprintf(stderr, "[ real, cpu, maxRSS]\n"); clock_gettime(CLOCK_REALTIME, &start_time); } struct timespec real_time; @@ -73,11 +73,11 @@ void log_debug(const char *const fmt, ...) va_start(args, fmt); fprintf( stderr, - "[%ld.%03ld, %ld.%03ld, %5ld KB][DEBUG]: ", + "[%ld.%06ld, %ld.%06ld, %5ld KB][DEBUG]: ", real_time.tv_sec, - real_time.tv_nsec / 1000000, + real_time.tv_nsec / 1000, cpu_time.tv_sec, - cpu_time.tv_nsec / 1000000, + cpu_time.tv_nsec / 1000, usage.ru_maxrss ); print_indent(stderr); @@ -114,7 +114,7 @@ void log_append_warning(const char *const fmt, ...) void log_append_debug(const char *const fmt, ...) { #ifndef DEBUG - return; + //return; #endif va_list args; va_start(args, fmt); @@ -46,6 +46,35 @@ static uint32_t gettime_ms() { return ms; } + +/* Read all of stdin into a buffer. */ +static char *read_stdin() { + const size_t block_size = BUFSIZ; + size_t num_blocks = 1; + size_t buf_size = block_size; + + char *buf = xmalloc(buf_size); + for (size_t block = 0; ; block++) { + if (block == num_blocks) { + num_blocks *= 2; + buf = xrealloc(buf, num_blocks * block_size); + } + size_t bytes_read = fread( + &buf[block * block_size], + 1, + block_size, + stdin); + if (bytes_read != block_size) { + if (!feof(stdin) && ferror(stdin)) { + log_error("Error reading stdin\n"); + } + buf[block * block_size + bytes_read] = '\0'; + break; + } + } + return buf; +} + static void zwlr_layer_surface_configure( void *data, struct zwlr_layer_surface_v1 *zwlr_layer_surface, @@ -100,14 +129,15 @@ static void wl_keyboard_keymap( { struct tofi *tofi = data; assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); - log_debug("Configuring keyboard.\n"); char *map_shm = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); assert(map_shm != MAP_FAILED); if (tofi->late_keyboard_init) { + log_debug("Delaying keyboard configuration.\n"); tofi->xkb_keymap_string = xstrdup(map_shm); } else { + log_debug("Configuring keyboard.\n"); struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string( tofi->xkb_context, map_shm, @@ -121,11 +151,10 @@ static void wl_keyboard_keymap( xkb_state_unref(tofi->xkb_state); tofi->xkb_keymap = xkb_keymap; tofi->xkb_state = xkb_state; + log_debug("Keyboard configured.\n"); } munmap(map_shm, size); close(fd); - - log_debug("Keyboard configured.\n"); } static void wl_keyboard_enter( @@ -1095,6 +1124,7 @@ int main(int argc, char *argv[]) } parse_args(&tofi, argc, argv); + log_debug("Config done\n"); if (!tofi.multiple_instance && lock_check()) { log_error("Another instance of tofi is already running.\n"); @@ -1108,16 +1138,20 @@ int main(int argc, char *argv[]) * to Wayland. */ + log_debug("Connecting to Wayland display.\n"); tofi.wl_display = wl_display_connect(NULL); if (tofi.wl_display == NULL) { log_error("Couldn't connect to Wayland display.\n"); exit(EXIT_FAILURE); } tofi.wl_registry = wl_display_get_registry(tofi.wl_display); - tofi.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (tofi.xkb_context == NULL) { - log_error("Couldn't create an XKB context.\n"); - exit(EXIT_FAILURE); + if (!tofi.late_keyboard_init) { + log_debug("Creating xkb context.\n"); + tofi.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (tofi.xkb_context == NULL) { + log_error("Couldn't create an XKB context.\n"); + exit(EXIT_FAILURE); + } } wl_registry_add_listener( tofi.wl_registry, @@ -1286,7 +1320,8 @@ int main(int argc, char *argv[]) if (strstr(argv[0], "-run")) { log_debug("Generating command list.\n"); log_indent(); - tofi.window.entry.commands = compgen_cached(); + tofi.window.entry.command_buffer = compgen_cached(); + tofi.window.entry.commands = string_ref_vec_from_buffer(tofi.window.entry.command_buffer); if (tofi.use_history) { if (tofi.history_file[0] == 0) { tofi.window.entry.history = history_load_default_file(tofi.window.entry.drun); @@ -1312,36 +1347,30 @@ int main(int argc, char *argv[]) drun_history_sort(&apps, &tofi.window.entry.history); } } - struct string_vec commands = string_vec_create(); + struct string_ref_vec commands = string_ref_vec_create(); for (size_t i = 0; i < apps.count; i++) { - string_vec_add(&commands, apps.buf[i].name); + string_ref_vec_add(&commands, apps.buf[i].name); } tofi.window.entry.commands = commands; tofi.window.entry.apps = apps; log_unindent(); log_debug("App list generated.\n"); } else { - char *line = NULL; - size_t n = 0; - tofi.window.entry.commands = string_vec_create(); - while (getline(&line, &n, stdin) != -1) { - char *c = strchr(line, '\n'); - if (c) { - *c = '\0'; - } - string_vec_add(&tofi.window.entry.commands, line); - } - free(line); + log_debug("Reading stdin.\n"); + char *buf = read_stdin(); + tofi.window.entry.command_buffer = buf; + tofi.window.entry.commands = string_ref_vec_from_buffer(buf); if (tofi.use_history) { if (tofi.history_file[0] == 0) { tofi.use_history = false; } else { tofi.window.entry.history = history_load(tofi.history_file); - string_vec_history_sort(&tofi.window.entry.commands, &tofi.window.entry.history); + string_ref_vec_history_sort(&tofi.window.entry.commands, &tofi.window.entry.history); } } + log_debug("Result list generated.\n"); } - tofi.window.entry.results = string_vec_copy(&tofi.window.entry.commands); + tofi.window.entry.results = string_ref_vec_copy(&tofi.window.entry.commands); /* * Next, we create the Wayland surface, which takes on the @@ -1476,6 +1505,13 @@ int main(int argc, char *argv[]) /* If we delayed keyboard initialisation, do it now */ if (tofi.late_keyboard_init) { + log_debug("Creating xkb context.\n"); + tofi.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (tofi.xkb_context == NULL) { + log_error("Couldn't create an XKB context.\n"); + exit(EXIT_FAILURE); + } + log_debug("Configuring keyboard.\n"); struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string( tofi.xkb_context, tofi.xkb_keymap_string, @@ -1489,6 +1525,7 @@ int main(int argc, char *argv[]) tofi.xkb_state = xkb_state; free(tofi.xkb_keymap_string); tofi.late_keyboard_init = false; + log_debug("Keyboard configured.\n"); } /* @@ -1642,8 +1679,11 @@ int main(int argc, char *argv[]) if (tofi.window.entry.drun) { desktop_vec_destroy(&tofi.window.entry.apps); } - string_vec_destroy(&tofi.window.entry.commands); - string_vec_destroy(&tofi.window.entry.results); + if (tofi.window.entry.command_buffer != NULL) { + free(tofi.window.entry.command_buffer); + } + string_ref_vec_destroy(&tofi.window.entry.commands); + string_ref_vec_destroy(&tofi.window.entry.results); if (tofi.use_history) { history_destroy(&tofi.window.entry.history); } diff --git a/src/main_compgen.c b/src/main_compgen.c index 743d2cc..6375c54 100644 --- a/src/main_compgen.c +++ b/src/main_compgen.c @@ -1,10 +1,16 @@ #include <stdio.h> +#include <stdlib.h> #include "compgen.h" #include "string_vec.h" int main() { - struct string_vec commands = compgen_cached(); - string_vec_save(&commands, stdout); - string_vec_destroy(&commands); + char *buf = compgen_cached(); + struct string_ref_vec commands = string_ref_vec_from_buffer(buf); + for (size_t i = 0; i < commands.count; i++) { + fputs(commands.buf[i].string, stdout); + fputc('\n', stdout); + } + string_ref_vec_destroy(&commands); + free(buf); } diff --git a/src/string_vec.c b/src/string_vec.c index 342fd9f..039d191 100644 --- a/src/string_vec.c +++ b/src/string_vec.c @@ -56,6 +56,16 @@ struct string_vec string_vec_create(void) return vec; } +struct string_ref_vec string_ref_vec_create(void) +{ + struct string_ref_vec vec = { + .count = 0, + .size = 128, + .buf = xcalloc(128, sizeof(*vec.buf)), + }; + return vec; +} + void string_vec_destroy(struct string_vec *restrict vec) { for (size_t i = 0; i < vec->count; i++) { @@ -64,16 +74,21 @@ void string_vec_destroy(struct string_vec *restrict vec) free(vec->buf); } -struct string_vec string_vec_copy(const struct string_vec *restrict vec) +void string_ref_vec_destroy(struct string_ref_vec *restrict vec) +{ + free(vec->buf); +} + +struct string_ref_vec string_ref_vec_copy(const struct string_ref_vec *restrict vec) { - struct string_vec copy = { + struct string_ref_vec copy = { .count = vec->count, .size = vec->size, .buf = xcalloc(vec->size, sizeof(*copy.buf)), }; for (size_t i = 0; i < vec->count; i++) { - copy.buf[i].string = xstrdup(vec->buf[i].string); + copy.buf[i].string = vec->buf[i].string; copy.buf[i].search_score = vec->buf[i].search_score; copy.buf[i].history_score = vec->buf[i].history_score; } @@ -99,14 +114,13 @@ void string_vec_add(struct string_vec *restrict vec, const char *restrict str) vec->count++; } -/* Same as string_vec_add(), but assume str is normalized for speed. */ -static void string_vec_add_normalized(struct string_vec *restrict vec, const char *restrict str) +void string_ref_vec_add(struct string_ref_vec *restrict vec, char *restrict str) { if (vec->count == vec->size) { vec->size *= 2; vec->buf = xrealloc(vec->buf, vec->size * sizeof(vec->buf[0])); } - vec->buf[vec->count].string = xstrdup(str); + vec->buf[vec->count].string = str; vec->buf[vec->count].search_score = 0; vec->buf[vec->count].history_score = 0; vec->count++; @@ -117,7 +131,7 @@ void string_vec_sort(struct string_vec *restrict vec) qsort(vec->buf, vec->count, sizeof(vec->buf[0]), cmpstringp); } -void string_vec_history_sort(struct string_vec *restrict vec, struct history *history) +void string_ref_vec_history_sort(struct string_ref_vec *restrict vec, struct history *history) { /* * To find elements without assuming the vector is pre-sorted, we use a @@ -129,7 +143,7 @@ void string_vec_history_sort(struct string_vec *restrict vec, struct history *hi g_hash_table_insert(hash, vec->buf[i].string, &vec->buf[i]); } for (size_t i = 0; i < history->count; i++) { - struct scored_string *res = g_hash_table_lookup(hash, history->buf[i].name); + struct scored_string_ref *res = g_hash_table_lookup(hash, history->buf[i].name); if (res == NULL) { continue; } @@ -159,15 +173,20 @@ struct scored_string *string_vec_find_sorted(struct string_vec *restrict vec, co return bsearch(&str, vec->buf, vec->count, sizeof(vec->buf[0]), cmpstringp); } -struct string_vec string_vec_filter( - const struct string_vec *restrict vec, +struct scored_string_ref *string_ref_vec_find_sorted(struct string_ref_vec *restrict vec, const char * str) +{ + return bsearch(&str, vec->buf, vec->count, sizeof(vec->buf[0]), cmpstringp); +} + +struct string_ref_vec string_ref_vec_filter( + const struct string_ref_vec *restrict vec, const char *restrict substr, bool fuzzy) { if (substr[0] == '\0') { - return string_vec_copy(vec); + return string_ref_vec_copy(vec); } - struct string_vec filt = string_vec_create(); + struct string_ref_vec filt = string_ref_vec_create(); for (size_t i = 0; i < vec->count; i++) { int32_t search_score; if (fuzzy) { @@ -176,55 +195,25 @@ struct string_vec string_vec_filter( search_score = fuzzy_match_simple_words(substr, vec->buf[i].string); } if (search_score != INT32_MIN) { - /* - * Assume that the vector we're filtering is already - * normalized. - */ - string_vec_add_normalized(&filt, vec->buf[i].string); - /* - * Store the position of the match in the string as - * its search_score, for later sorting. - */ + string_ref_vec_add(&filt, vec->buf[i].string); filt.buf[filt.count - 1].search_score = search_score; filt.buf[filt.count - 1].history_score = vec->buf[i].history_score; } } - /* - * Sort the results by this search_score. This moves matches at the beginnings - * of words to the front of the result list. - */ + /* Sort the results by their search score. */ qsort(filt.buf, filt.count, sizeof(filt.buf[0]), cmpscorep); return filt; } -struct string_vec string_vec_load(FILE *file) +struct string_ref_vec string_ref_vec_from_buffer(char *buffer) { - struct string_vec vec = string_vec_create(); - if (file == NULL) { - return vec; - } + struct string_ref_vec vec = string_ref_vec_create(); - ssize_t bytes_read; - char *line = NULL; - size_t len; - while ((bytes_read = getline(&line, &len, file)) != -1) { - if (line[bytes_read - 1] == '\n') { - line[bytes_read - 1] = '\0'; - } - /* - * Assume that the vector we're loading is already normalized. - */ - string_vec_add_normalized(&vec, line); + char *saveptr = NULL; + char *line = strtok_r(buffer, "\n", &saveptr); + while (line != NULL) { + string_ref_vec_add(&vec, line); + line = strtok_r(NULL, "\n", &saveptr); } - free(line); - return vec; } - -void string_vec_save(struct string_vec *restrict vec, FILE *restrict file) -{ - for (size_t i = 0; i < vec->count; i++) { - fputs(vec->buf[i].string, file); - fputc('\n', file); - } -} diff --git a/src/string_vec.h b/src/string_vec.h index f04b385..6f54d56 100644 --- a/src/string_vec.h +++ b/src/string_vec.h @@ -24,27 +24,58 @@ struct string_vec string_vec_create(void); void string_vec_destroy(struct string_vec *restrict vec); -[[nodiscard("memory leaked")]] -struct string_vec string_vec_copy(const struct string_vec *restrict vec); - void string_vec_add(struct string_vec *restrict vec, const char *restrict str); void string_vec_sort(struct string_vec *restrict vec); -void string_vec_history_sort(struct string_vec *restrict vec, struct history *history); +struct scored_string *string_vec_find_sorted(struct string_vec *restrict vec, const char *str); + + +/* + * Like a string_vec, but only store a reference to the corresponding string + * rather than copying it. Although compatible with the string_vec struct, we + * create a new struct to make the compiler complain if we mix them up. + */ +struct scored_string_ref { + char *string; + int32_t search_score; + int32_t history_score; +}; + +struct string_ref_vec { + size_t count; + size_t size; + struct scored_string_ref *buf; +}; + +/* + * Although some of these functions are identical to the corresponding + * string_vec ones, we create new functions to avoid potentially mixing up + * the two. + */ +[[nodiscard("memory leaked")]] +struct string_ref_vec string_ref_vec_create(void); + +void string_ref_vec_destroy(struct string_ref_vec *restrict vec); + +[[nodiscard("memory leaked")]] +struct string_ref_vec string_ref_vec_copy(const struct string_ref_vec *restrict vec); + +void string_ref_vec_add(struct string_ref_vec *restrict vec, char *restrict str); + +void string_ref_vec_history_sort(struct string_ref_vec *restrict vec, struct history *history); void string_vec_uniq(struct string_vec *restrict vec); -struct scored_string *string_vec_find_sorted(struct string_vec *restrict vec, const char *str); +struct scored_string_ref *string_ref_vec_find_sorted(struct string_ref_vec *restrict vec, const char *str); [[nodiscard("memory leaked")]] -struct string_vec string_vec_filter( - const struct string_vec *restrict vec, +struct string_ref_vec string_ref_vec_filter( + const struct string_ref_vec *restrict vec, const char *restrict substr, bool fuzzy); [[nodiscard("memory leaked")]] -struct string_vec string_vec_load(FILE *file); -void string_vec_save(struct string_vec *restrict vec, FILE *restrict file); +struct string_ref_vec string_ref_vec_from_buffer(char *buffer); #endif /* STRING_VEC_H */ |