summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compgen.c91
-rw-r--r--src/compgen.h10
-rw-r--r--src/desktop_vec.c10
-rw-r--r--src/desktop_vec.h2
-rw-r--r--src/entry.h5
-rw-r--r--src/input.c14
-rw-r--r--src/log.c12
-rw-r--r--src/main.c90
-rw-r--r--src/main_compgen.c12
-rw-r--r--src/string_vec.c91
-rw-r--r--src/string_vec.h49
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);
diff --git a/src/log.c b/src/log.c
index b564a49..e90df3c 100644
--- a/src/log.c
+++ b/src/log.c
@@ -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);
diff --git a/src/main.c b/src/main.c
index 689e824..48de680 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 */