tmus

TUI Music Player
git clone https://git.sinitax.com/sinitax/tmus
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

commit 53cb5a2a0d1540a37e6e5d1c1673e8354d5208a5
parent 3dad446ab7a6e207229b56af552dd3304a9ab11b
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 26 Feb 2022 00:41:29 +0100

Migrate away from wchar_t, default to utf8

Diffstat:
Msrc/cmd.c | 155++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/cmd.h | 13++++++-------
Msrc/data.c | 207++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/data.h | 18+++++++++++-------
Msrc/history.c | 149+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/history.h | 18++++++++++--------
Msrc/pane.c | 24++++++++++++++++++++----
Msrc/pane.h | 8+++++---
Msrc/player_mpd.c | 2+-
Msrc/ref.c | 4+++-
Msrc/ref.h | 2+-
Asrc/strbuf.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/strbuf.h | 12++++++++++++
Msrc/tag.c | 17++++-------------
Msrc/tag.h | 8++------
Msrc/track.c | 11+----------
Msrc/track.h | 3+--
Msrc/tui.c | 250+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/tui.h | 1-
Msrc/util.c | 43-------------------------------------------
Msrc/util.h | 5-----
21 files changed, 626 insertions(+), 379 deletions(-)

diff --git a/src/cmd.c b/src/cmd.c @@ -10,6 +10,7 @@ #include "util.h" #include <stdbool.h> +#include <string.h> #define CMD_ERROR(...) do { \ CMD_SET_STATUS(__VA_ARGS__); \ @@ -17,31 +18,35 @@ } while (0) static const struct cmd *last_cmd; -static wchar_t *last_args; +static char *last_args; -static bool cmd_save(const wchar_t *args); -static bool cmd_move(const wchar_t *args); -static bool cmd_add(const wchar_t *args); -static bool cmd_reindex(const wchar_t *args); +static bool cmd_save(const char *args); +static bool cmd_move(const char *args); +static bool cmd_copy(const char *args); +static bool cmd_reindex(const char *args); +static bool cmd_add_tag(const char *args); +static bool cmd_rm_tag(const char *args); const struct cmd commands[] = { - { L"save", cmd_save }, - { L"move", cmd_move }, - { L"add", cmd_add }, - { L"reindex", cmd_reindex }, + { "save", cmd_save }, + { "move", cmd_move }, + { "copy", cmd_copy }, + { "reindex", cmd_reindex }, + { "addtag", cmd_add_tag }, + { "rmtag", cmd_rm_tag }, }; const size_t command_count = ARRLEN(commands); bool -cmd_save(const wchar_t *args) +cmd_save(const char *args) { data_save(); return 0; } bool -cmd_move(const wchar_t *name) +cmd_move(const char *name) { struct link *link; struct track *track; @@ -55,10 +60,11 @@ cmd_move(const wchar_t *name) if (!link) CMD_ERROR("No track selected"); track = UPCAST(link, struct ref)->data; - newpath = aprintf("%s/%s", tag->fpath, track->fname); + newpath = aprintf("%s/%s", tag->fpath, track->name); OOM_CHECK(newpath); - move_file(track->fpath, newpath); + if (!move_file(track->fpath, newpath)) + CMD_ERROR("Failed to move file"); free(track->fpath); track->fpath = newpath; @@ -69,7 +75,7 @@ cmd_move(const wchar_t *name) } bool -cmd_add(const wchar_t *name) +cmd_copy(const char *name) { struct link *link; struct track *track; @@ -84,21 +90,21 @@ cmd_add(const wchar_t *name) if (!link) return 0; track = UPCAST(link, struct ref)->data; - newpath = aprintf("%s/%s", tag->fpath, track->fname); + newpath = aprintf("%s/%s", tag->fpath, track->name); OOM_CHECK(newpath); copy_file(track->fpath, newpath); track->fpath = newpath; - track = track_alloc(tag->fpath, track->fname, get_fid(tag->fpath)); - ref = ref_init(track); + track = track_alloc(tag->fpath, track->name, get_fid(tag->fpath)); + ref = ref_alloc(track); list_push_back(&tag->tracks, &ref->link); return 1; } bool -cmd_reindex(const wchar_t *name) +cmd_reindex(const char *name) { struct link *link; struct tag *tag; @@ -108,19 +114,19 @@ cmd_reindex(const wchar_t *name) if (!*name) { link = list_at(&tags, tag_nav.sel); + if (!link) return false; tag = UPCAST(link, struct tag); - if (tag == NULL) return false; - list_push_back(&matches, LINK(ref_init(tag))); - } else if (!wcscmp(name, L"*")) { + list_push_back(&matches, LINK(ref_alloc(tag))); + } else if (!strcmp(name, "*")) { for (LIST_ITER(&tags, link)) { tag = UPCAST(link, struct tag); - list_push_back(&matches, LINK(ref_init(tag))); + list_push_back(&matches, LINK(ref_alloc(tag))); } } else { for (LIST_ITER(&tags, link)) { tag = UPCAST(link, struct tag); - if (!wcscmp(tag->name, name)) { - list_push_back(&matches, LINK(ref_init(tag))); + if (!strcmp(tag->name, name)) { + list_push_back(&matches, LINK(ref_alloc(tag))); break; } } @@ -130,7 +136,8 @@ cmd_reindex(const wchar_t *name) for (LIST_ITER(&matches, link)) { tag = UPCAST(link, struct ref)->data; - index_update(tag); + if (!tracks_update(tag)) + return false; } refs_free(&matches); @@ -138,6 +145,76 @@ cmd_reindex(const wchar_t *name) return true; } +bool +cmd_add_tag(const char *name) +{ + struct link *link; + struct tag *tag; + char *fname, *fpath; + + for (LIST_ITER(&tags, link)) { + tag = UPCAST(link, struct tag); + if (!strcmp(tag->name, name)) + CMD_ERROR("Tag already exists"); + } + + fname = aprintf("%s", name); + OOM_CHECK(fname); + + fpath = aprintf("%s/%s", datadir, fname); + OOM_CHECK(fpath); + + if (!make_dir(fpath)) { + CMD_SET_STATUS("Failed to create dir"); + free(fname); + free(fpath); + return false; + } + + tag = tag_alloc(datadir, fname); + OOM_CHECK(tag); + + list_push_back(&tags, LINK(tag)); + + free(fname); + free(fpath); + + return true; +} + +bool +cmd_rm_tag(const char *name) +{ + struct link *link; + struct tag *tag; + char *fname, *fpath; + + if (!*name) { + link = list_at(&tags, tag_nav.sel); + if (!link) return false; + tag = UPCAST(link, struct tag); + } else { + for (LIST_ITER(&tags, link)) { + tag = UPCAST(link, struct tag); + if (!strcmp(tag->name, name)) + break; + } + + if (!LIST_INNER(link)) + CMD_ERROR("No such tag"); + } + + if (!rm_dir(tag->fpath, true)) { + tracks_update(tag); /* in case some deleted, some not */ + CMD_ERROR("Failed to remove dir"); + } + + link_pop(LINK(tag)); + tag_free(tag); + + return true; +} + void cmd_init(void) { @@ -152,19 +229,25 @@ cmd_deinit(void) } bool -cmd_run(const wchar_t *query) +cmd_run(const char *query, bool *found) { - const wchar_t *sep, *args; + const char *sep, *args; int i, cmdlen; bool success; - sep = wcschr(query, L' '); - cmdlen = sep ? sep - query : wcslen(query); + *found = false; + sep = strchr(query, ' '); + cmdlen = sep ? sep - query : strlen(query); for (i = 0; i < command_count; i++) { - if (!wcsncmp(commands[i].name, query, cmdlen)) { + if (!strncmp(commands[i].name, query, cmdlen)) { last_cmd = &commands[i]; - args = sep ? sep + 1 : L""; - last_args = wcsdup(args); + args = sep ? sep + 1 : ""; + + free(last_args); + last_args = strdup(args); + OOM_CHECK(last_args); + + *found = true; return commands[i].func(args); } } @@ -181,12 +264,12 @@ cmd_rerun(void) } const struct cmd * -cmd_get(const wchar_t *name) +cmd_get(const char *name) { int i; for (i = 0; i < command_count; i++) { - if (!wcscmp(commands[i].name, name)) + if (!strcmp(commands[i].name, name)) return &commands[i]; } @@ -194,12 +277,12 @@ cmd_get(const wchar_t *name) } const struct cmd * -cmd_find(const wchar_t *name) +cmd_find(const char *name) { int i; for (i = 0; i < command_count; i++) { - if (wcsstr(commands[i].name, name)) + if (strcmp(commands[i].name, name)) return &commands[i]; } diff --git a/src/cmd.h b/src/cmd.h @@ -1,7 +1,6 @@ #pragma once -#include <wchar.h> - +#include <stdlib.h> #include <stdbool.h> #define CMD_SET_STATUS(...) do { \ @@ -9,21 +8,21 @@ cmd_status = aprintf(__VA_ARGS__); \ } while (0) -typedef bool (*cmd_func)(const wchar_t *args); +typedef bool (*cmd_func)(const char *args); struct cmd { - const wchar_t *name; + const char *name; cmd_func func; }; void cmd_init(void); void cmd_deinit(void); -bool cmd_run(const wchar_t *name); +bool cmd_run(const char *name, bool *found); bool cmd_rerun(void); -const struct cmd *cmd_get(const wchar_t *name); -const struct cmd *cmd_find(const wchar_t *name); +const struct cmd *cmd_get(const char *name); +const struct cmd *cmd_find(const char *name); extern const struct cmd commands[]; extern const size_t command_count; diff --git a/src/data.c b/src/data.c @@ -1,11 +1,13 @@ #include "data.h" +#include "player.h" #include "list.h" #include "log.h" #include "ref.h" #include "track.h" #include "tag.h" +#include <fts.h> #include <dirent.h> #include <sys/stat.h> #include <unistd.h> @@ -48,7 +50,8 @@ data_load(void) OOM_CHECK(path); if (!stat(path, &st) && S_ISDIR(st.st_mode)) { - tag = tag_init(datadir, ent->d_name); + tag = tag_alloc(datadir, ent->d_name); + OOM_CHECK(tag); tracks_load(tag); list_push_back(&tags, LINK(tag)); } @@ -57,8 +60,7 @@ data_load(void) } closedir(dir); - /* TODO: ensure this is ok and remove */ - ASSERT(!list_empty(&tags)); + list_sort(&tracks, track_fid_compare); } void @@ -105,13 +107,21 @@ get_fid(const char *path) return stat(path, &st) ? -1 : st.st_ino; } +int +track_fid_compare(struct link *a, struct link *b) +{ + struct track *ta, *tb; + + ta = UPCAST(a, struct ref)->data; + tb = UPCAST(b, struct ref)->data; + + return ta->fid - tb->fid; +} + void index_update(struct tag *tag) { - struct track *track, *track_iter; struct dirent *ent; - struct link *iter; - struct ref *ref; struct stat st; char *path; FILE *file; @@ -152,6 +162,80 @@ index_update(struct tag *tag) fclose(file); } +bool +tracks_update(struct tag *tag) +{ + struct dirent *ent; + struct stat st; + struct link *link; + struct ref *ref; + struct track *track; + char *path; + DIR *dir; + int fid; + + dir = opendir(tag->fpath); + if (!dir) return false; + + while (!list_empty(&tag->tracks)) { + link = list_pop_front(&tag->tracks); + ref = UPCAST(link, struct ref); + track = ref->data; + ref_free(ref); + for (LIST_ITER(&tracks, link)) { + ref = UPCAST(link, struct ref); + if (ref->data == track) { + link = link_pop(link); + ref_free(ref); + break; + } + } + if (player.track == track) + player.track = NULL; + track_free(track); + } + + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, ".")) + continue; + if (!strcmp(ent->d_name, "..")) + continue; + if (!strcmp(ent->d_name, "index")) + continue; + + /* skip files without extension */ + if (!strchr(ent->d_name + 1, '.')) + continue; + + path = aprintf("%s/%s", tag->fpath, ent->d_name); + OOM_CHECK(path); + + fid = get_fid(path); + + track = track_alloc(tag->fpath, ent->d_name, fid); + OOM_CHECK(track); + + ref = ref_alloc(tag); + OOM_CHECK(ref); + list_push_back(&track->tags, LINK(ref)); + + ref = ref_alloc(track); + OOM_CHECK(ref); + list_push_back(&tag->tracks, LINK(ref)); + + ref = ref_alloc(track); + OOM_CHECK(ref); + list_push_back(&tracks, LINK(ref)); + + free(path); + } + + list_sort(&tracks, track_fid_compare); + + closedir(dir); + return true; +} + void tracks_load(struct tag *tag) { @@ -163,7 +247,6 @@ tracks_load(struct tag *tag) char *index_path; char *track_name, *sep; int track_fid; - bool new_track; FILE *file; index_path = aprintf("%s/index", tag->fpath); @@ -188,26 +271,17 @@ tracks_load(struct tag *tag) track_name = sep + 1; track = track_alloc(tag->fpath, track_name, track_fid); - ref = ref_init(tag); + ref = ref_alloc(tag); OOM_CHECK(ref); list_push_back(&track->tags, LINK(ref)); - ref = ref_init(track); + ref = ref_alloc(track); OOM_CHECK(ref); list_push_back(&tag->tracks, LINK(ref)); - new_track = true; - for (LIST_ITER(&tracks, link)) { - track2 = UPCAST(link, struct ref)->data; - if (track->fid > 0 && track->fid == track2->fid) - new_track = false; - } - - if (new_track) { - ref = ref_init(track); - OOM_CHECK(ref); - list_push_back(&tracks, LINK(ref)); - } + ref = ref_alloc(track); + OOM_CHECK(ref); + list_push_back(&tracks, LINK(ref)); } fclose(file); @@ -228,65 +302,122 @@ tracks_save(struct tag *tag) OOM_CHECK(index_path); file = fopen(index_path, "w+"); - if (!file) ERROR("Failed to write to index file: %s\n", index_path); + if (!file) { + fprintf(stderr, "Failed to write to index file: %s\n", + index_path); + free(index_path); + return; + } for (LIST_ITER(&tag->tracks, link)) { track = UPCAST(link, struct ref)->data; - fprintf(file, "%i:%s\n", track->fid, track->fname); + fprintf(file, "%i:%s\n", track->fid, track->name); } fclose(file); free(index_path); } -void +bool +make_dir(const char *path) +{ + return mkdir(path, S_IRWXU | S_IRWXG) == 0; +} + +bool +rm_dir(const char *path, bool recursive) +{ + char *files[] = { (char *) path, NULL }; + FTSENT *ent; + FTS *fts; + int flags; + + if (recursive) { + flags = FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV; + fts = fts_open(files, flags, NULL); + if (!fts) return false; + + while ((ent = fts_read(fts))) { + switch (ent->fts_info) { + case FTS_NS: + case FTS_DNR: + case FTS_ERR: + fts_close(fts); + return false; + case FTS_D: + break; + default: + if (remove(ent->fts_accpath) < 0) { + fts_close(fts); + return false; + } + break; + } + } + + fts_close(fts); + } else { + if (rmdir(path) != 0) + return false; + } + + return true; +} + +bool rm_file(const char *path) { - ASSERT(unlink(path) == 0); + return unlink(path) == 0; } -void +bool copy_file(const char *src, const char *dst) { FILE *in, *out; char buf[4096]; int len, nread; + bool ok; + + ok = false; + in = out = NULL; in = fopen(src, "r"); - if (in == NULL) - ERROR("Failed to read from file: %s\n", src); + if (in == NULL) goto cleanup; out = fopen(dst, "w+"); - if (out == NULL) - ERROR("Failed to write to file: %s\n", dst); + if (out == NULL) goto cleanup; while ((nread = fread(buf, 1, sizeof(buf), in)) > 0) { fwrite(buf, 1, nread, out); } if (nread < 0) - ERROR("Failed to copy file from %s to %s\n", src, dst); + goto cleanup; + + ok = true; - fclose(in); - fclose(out); +cleanup: + if (in) fclose(in); + if (out) fclose(out); + + return ok; } -void +bool move_file(const char *src, const char *dst) { - copy_file(src, dst); - rm_file(src); + return rename(src, dst) == 0; } struct tag * -tag_find(const wchar_t *query) +tag_find(const char *query) { struct link *iter; struct tag *tag; for (LIST_ITER(&tags, iter)) { tag = UPCAST(iter, struct tag); - if (!wcscmp(tag->name, query)) { + if (!strcmp(tag->name, query)) { return tag; } } diff --git a/src/data.h b/src/data.h @@ -7,18 +7,22 @@ void data_save(void); void data_free(void); int get_fid(const char *path); +int track_fid_compare(struct link *a, struct link *b); void index_update(struct tag *tag); +bool tracks_update(struct tag *tag); void tracks_load(struct tag *tag); void tracks_save(struct tag *tag); -void rm_file(const char *path); -void copy_file(const char *dst, const char *src); -void move_file(const char *dst, const char *src); +bool make_dir(const char *path); +bool rm_dir(const char *path, bool recursive); +bool rm_file(const char *path); +bool copy_file(const char *dst, const char *src); +bool move_file(const char *dst, const char *src); -struct tag *tag_find(const wchar_t *query); +struct tag *tag_find(const char *query); extern const char *datadir; -extern struct list tracks; -extern struct list tags; -extern struct list tags_sel; +extern struct list tracks; /* struct ref */ +extern struct list tags; /* struct tag */ +extern struct list tags_sel; /* struct ref */ diff --git a/src/history.c b/src/history.c @@ -1,61 +1,25 @@ +#define _GNU_SOURCE + #include "history.h" #include "util.h" #include <string.h> -#include <wchar.h> -void -history_init(struct history *history) -{ - list_init(&history->list); - history->input = inputln_alloc(); - history->sel = history->input; -} +static struct inputln * +history_list_prev(struct inputln *cur, const char *search); -void -history_submit(struct history *history) -{ - /* if chose from history free input */ - if (history->sel != history->input) { - link_pop(LINK(history->input)); - inputln_free(history->input); - } - - /* pop first in case already in history */ - link_pop(LINK(history->sel)); - history_add(history, history->sel); - - /* create new input buf and add to hist */ - history->input = inputln_alloc(); - history->sel = history->input; - history_add(history, history->sel); -} - -void -history_free(struct history *history) -{ - struct link *iter, *next; - struct link *ln; - - ln = link_pop(LINK(history->input)); - inputln_free(UPCAST(ln, struct inputln)); - - list_free(&history->list, (link_free_func) inputln_free, - LINK_OFFSET(struct inputln, link)); - - history->input = NULL; - history->sel = NULL; -} +static struct inputln * +history_list_next(struct inputln *cur, const char *search); struct inputln * -history_list_prev(struct inputln *cur, const wchar_t *search) +history_list_prev(struct inputln *cur, const char *search) { struct link *iter; struct inputln *ln; for (iter = cur->link.prev; iter && iter->prev; iter = iter->prev) { ln = UPCAST(iter, struct inputln); - if (!search || !*search || wcscasestr(ln->buf, search)) + if (!search || !*search || strcasestr(ln->buf, search)) return ln; } @@ -63,7 +27,7 @@ history_list_prev(struct inputln *cur, const wchar_t *search) } struct inputln * -history_list_next(struct inputln *cur, const wchar_t *search) +history_list_next(struct inputln *cur, const char *search) { struct link *iter; struct inputln *ln; @@ -71,7 +35,7 @@ history_list_next(struct inputln *cur, const wchar_t *search) iter = cur->link.next; while (LIST_INNER(iter)) { ln = UPCAST(iter, struct inputln); - if (!search || !*search || wcscasestr(ln->buf, search)) + if (!search || !*search || strcasestr(ln->buf, search)) return ln; iter = iter->next; } @@ -80,6 +44,50 @@ history_list_next(struct inputln *cur, const wchar_t *search) } void +history_init(struct history *history) +{ + list_init(&history->list); + history->input = inputln_alloc(); + history->sel = history->input; +} + +void +history_deinit(struct history *history) +{ + struct link *link; + struct inputln *ln; + + link = link_pop(LINK(history->input)); + ln = UPCAST(link, struct inputln); + inputln_free(ln); + history->input = NULL; + + list_free(&history->list, (link_free_func) inputln_free, + LINK_OFFSET(struct inputln, link)); + + history->sel = NULL; +} + +void +history_submit(struct history *history) +{ + /* if chose from history free input */ + if (history->sel != history->input) { + link_pop(LINK(history->input)); + inputln_free(history->input); + } + + /* pop first in case already in history */ + link_pop(LINK(history->sel)); + history_add(history, history->sel); + + /* create new input buf and add to hist */ + history->input = inputln_alloc(); + history->sel = history->input; + history_add(history, history->sel); +} + +void history_prev(struct history *history) { history->sel = history_list_prev(history->sel, history->input->buf); @@ -100,7 +108,8 @@ history_add(struct history *history, struct inputln *line) if (list_len(&history->list) == HISTORY_MAX) { /* pop last item to make space */ back = list_pop_back(&history->list); - inputln_free(UPCAST(back, struct inputln)); + ln = UPCAST(back, struct inputln); + inputln_free(ln); } list_push_front(&history->list, LINK(line)); @@ -114,9 +123,16 @@ inputln_init(struct inputln *ln) ln->cap = 0; ln->cur = 0; ln->link = LINK_EMPTY; + inputln_resize(ln, 128); } +void +inputln_deinit(struct inputln *ln) +{ + free(ln->buf); +} + struct inputln * inputln_alloc(void) { @@ -132,11 +148,23 @@ inputln_alloc(void) void inputln_free(struct inputln *ln) { - free(ln->buf); + inputln_deinit(ln); free(ln); } void +inputln_resize(struct inputln *ln, size_t size) +{ + ASSERT(size != 0); + + ln->cap = size; + ln->buf = realloc(ln->buf, ln->cap * sizeof(char)); + OOM_CHECK(ln->buf); + ln->len = MIN(ln->len, ln->cap-1); + ln->buf[ln->len] = '\0'; +} + +void inputln_left(struct inputln *ln) { ln->cur = MAX(0, ln->cur-1); @@ -149,14 +177,13 @@ inputln_right(struct inputln *ln) } void -inputln_addch(struct inputln *line, wchar_t c) +inputln_addch(struct inputln *line, char c) { int i; if (line->len + 1 >= line->cap) { line->cap *= 2; - line->buf = realloc(line->buf, - line->cap * sizeof(wchar_t)); + line->buf = realloc(line->buf, line->cap); } for (i = line->len; i > line->cur; i--) @@ -195,31 +222,19 @@ inputln_copy(struct inputln *dst, struct inputln *src) dst->buf = NULL; } dst->len = src->len; - dst->buf = wcsdup(src->buf); + dst->buf = strdup(src->buf); OOM_CHECK(dst->buf); dst->cap = src->len + 1; dst->cur = dst->len; } void -inputln_replace(struct inputln *line, const wchar_t *str) +inputln_replace(struct inputln *line, const char *str) { - line->len = wcslen(str); + line->len = strlen(str); if (line->cap <= line->len) inputln_resize(line, line->len + 1); - line->buf = wcscpy(line->buf, str); + strncpy(line->buf, str, line->len); line->cur = line->len; } -void -inputln_resize(struct inputln *ln, size_t size) -{ - ASSERT(size != 0); - - ln->cap = size; - ln->buf = realloc(ln->buf, ln->cap * sizeof(wchar_t)); - OOM_CHECK(ln->buf); - ln->len = MIN(ln->len, ln->cap-1); - ln->buf[ln->len] = '\0'; -} - diff --git a/src/history.h b/src/history.h @@ -2,12 +2,10 @@ #include "list.h" -#include "wchar.h" - #define HISTORY_MAX 100 struct inputln { - wchar_t *buf; + char *buf; int len, cap; int cur; @@ -20,7 +18,7 @@ struct history { }; void history_init(struct history *history); -void history_free(struct history *history); +void history_deinit(struct history *history); void history_submit(struct history *history); @@ -29,16 +27,20 @@ void history_next(struct history *history); void history_add(struct history *history, struct inputln *line); -struct inputln *inputln_alloc(void); void inputln_init(struct inputln *ln); -void inputln_resize(struct inputln *ln, size_t size); +void inputln_deinit(struct inputln *ln); + +struct inputln *inputln_alloc(void); void inputln_free(struct inputln *ln); +void inputln_resize(struct inputln *ln, size_t size); + void inputln_left(struct inputln *line); void inputln_right(struct inputln *line); -void inputln_addch(struct inputln *line, wchar_t c); +void inputln_addch(struct inputln *line, char c); void inputln_del(struct inputln *line, int n); void inputln_copy(struct inputln *dst, struct inputln *src); -void inputln_replace(struct inputln *line, const wchar_t *str); +void inputln_replace(struct inputln *line, const char *str); + diff --git a/src/pane.c b/src/pane.c @@ -1,5 +1,13 @@ +#define _XOPEN_SOURCE + #include "pane.h" + #include "util.h" +#include "strbuf.h" + +#include <stdlib.h> +#include <string.h> +#include <wchar.h> void pane_init(struct pane *pane, pane_handler handle, pane_updater update) @@ -11,6 +19,12 @@ pane_init(struct pane *pane, pane_handler handle, pane_updater update) } void +pane_deinit(struct pane *pane) +{ + delwin(pane->win); +} + +void pane_resize(struct pane *pane, int sx, int sy, int ex, int ey) { pane->sx = sx; @@ -29,18 +43,20 @@ pane_resize(struct pane *pane, int sx, int sy, int ex, int ey) } void -pane_clearln(struct pane *pane, int y) +pane_clearln(struct pane *pane, int row) { int i; - wmove(pane->win, y, 0); + wmove(pane->win, row, 0); for (i = 0; i < pane->w; i++) waddch(pane->win, ' '); } void -pane_free(struct pane *pane) +pane_writeln(struct pane *pane, int row, const char *str) { - delwin(pane->win); + pane_clearln(pane, row); + wmove(pane->win, row, 0); + waddstr(pane->win, str); } diff --git a/src/pane.h b/src/pane.h @@ -4,11 +4,11 @@ #include <ncurses.h> -#include <wchar.h> +#include <stdbool.h> struct pane; -typedef int (*pane_handler)(wint_t c); +typedef bool (*pane_handler)(wint_t c); typedef void (*pane_updater)(struct pane *pane, int sel); struct pane { @@ -22,7 +22,9 @@ struct pane { }; void pane_init(struct pane *pane, pane_handler handle, pane_updater update); +void pane_deinit(struct pane *pane); + void pane_resize(struct pane *pane, int sx, int sy, int ex, int ey); void pane_clearln(struct pane *pane, int y); -void pane_free(struct pane *p); +void pane_writeln(struct pane *pane, int y, const char *line); diff --git a/src/player_mpd.c b/src/player_mpd.c @@ -217,7 +217,7 @@ player_add_history(struct track *track) if (ref->data == track) return; } - ref = ref_init(track); + ref = ref_alloc(track); list_push_back(&player.history, LINK(ref)); } diff --git a/src/ref.c b/src/ref.c @@ -2,14 +2,16 @@ #include "util.h" struct ref * -ref_init(void *data) +ref_alloc(void *data) { struct ref *ref; ref = malloc(sizeof(struct ref)); if (!ref) return NULL; + ref->link = LINK_EMPTY; ref->data = data; + return ref; } diff --git a/src/ref.h b/src/ref.h @@ -8,7 +8,7 @@ struct ref { struct link link; }; -struct ref *ref_init(void *data); +struct ref *ref_alloc(void *data); void ref_free(void *ref); void refs_free(struct list *list); diff --git a/src/strbuf.c b/src/strbuf.c @@ -0,0 +1,55 @@ +#include "strbuf.h" + +#include "util.h" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +void +strbuf_init(struct strbuf *strbuf) +{ + strbuf->buf = NULL; + strbuf->cap = 0; +} + +void +strbuf_deinit(struct strbuf *strbuf) +{ + free(strbuf->buf); +} + +void +strbuf_clear(struct strbuf *strbuf) +{ + if (!strbuf->buf) + strbuf_append(strbuf, ""); + + strbuf->buf[0] = '\0'; +} + +void +strbuf_append(struct strbuf *strbuf, const char *fmt, ...) +{ + va_list ap, cpy; + int blen, slen; + + va_copy(cpy, ap); + + blen = strbuf->buf ? strlen(strbuf->buf) : 0; + + va_start(cpy, fmt); + slen = vsnprintf(NULL, 0, fmt, cpy); + ASSERT(slen >= 0); + va_end(cpy); + + if (blen + slen + 1 > strbuf->cap) { + strbuf->cap = blen + slen + 1; + strbuf->buf = realloc(strbuf->buf, strbuf->cap); + OOM_CHECK(strbuf->buf); + } + + va_start(ap, fmt); + vsnprintf(strbuf->buf + blen, slen + 1, fmt, ap); + va_end(ap); +} diff --git a/src/strbuf.h b/src/strbuf.h @@ -0,0 +1,12 @@ +#include <stdlib.h> + +struct strbuf { + char *buf; + size_t cap; +}; + +void strbuf_init(struct strbuf *strbuf); +void strbuf_deinit(struct strbuf *strbuf); + +void strbuf_clear(struct strbuf *strbuf); +void strbuf_append(struct strbuf *strbuf, const char *fmt, ...); diff --git a/src/tag.c b/src/tag.c @@ -1,11 +1,13 @@ #include "tag.h" + #include "link.h" #include "ref.h" +#include "util.h" #include <string.h> struct tag * -tag_init(const char *path, const char *fname) +tag_alloc(const char *path, const char *fname) { struct tag *tag; int len; @@ -13,19 +15,11 @@ tag_init(const char *path, const char *fname) tag = malloc(sizeof(struct tag)); ASSERT(tag != NULL); - tag->fname = strdup(fname); - ASSERT(tag->fname != NULL); - - tag->new_fname = NULL; - tag->fpath = aprintf("%s/%s", path, fname); ASSERT(tag->fpath != NULL); - len = mbstowcs(NULL, tag->fname, 0); - ASSERT(len > 0); - tag->name = calloc(len + 1, sizeof(wchar_t)); + tag->name = strdup(fname); ASSERT(tag->name != NULL); - mbstowcs(tag->name, tag->fname, len + 1); tag->link = LINK_EMPTY; @@ -37,11 +31,8 @@ tag_init(const char *path, const char *fname) void tag_free(struct tag *tag) { - free(tag->fname); free(tag->fpath); free(tag->name); - refs_free(&tag->tracks); - free(tag); } diff --git a/src/tag.h b/src/tag.h @@ -1,18 +1,14 @@ #pragma once #include "list.h" -#include "util.h" struct tag { - wchar_t *name; - char *fname, *fpath; - - char *new_fname; + char *name, *fpath; struct list tracks; struct link link; }; -struct tag *tag_init(const char *path, const char *fname); +struct tag *tag_alloc(const char *path, const char *fname); void tag_free(struct tag *tag); diff --git a/src/track.c b/src/track.c @@ -14,17 +14,11 @@ track_alloc(const char *dir, const char *fname, int fid) track = malloc(sizeof(struct track)); ASSERT(track != NULL); - track->fname = strdup(fname); - ASSERT(track->fname != NULL); - track->fpath = aprintf("%s/%s", dir, fname); ASSERT(track->fpath != NULL); - len = mbstowcs(NULL, track->fname, 0); - ASSERT(len >= 0); - track->name = calloc(len + 1, sizeof(wchar_t)); + track->name = strdup(fname); ASSERT(track->name != NULL); - mbstowcs(track->name, track->fname, len + 1); track->fid = fid; @@ -36,11 +30,8 @@ track_alloc(const char *dir, const char *fname, int fid) void track_free(struct track *t) { - free(t->fname); free(t->fpath); free(t->name); - refs_free(&t->tags); - free(t); } diff --git a/src/track.h b/src/track.h @@ -4,9 +4,8 @@ #include "util.h" struct track { - wchar_t *name; + char *name, *fpath; struct list tags; - char *fname, *fpath; int fid; }; diff --git a/src/tui.c b/src/tui.c @@ -1,4 +1,5 @@ #define NCURSES_WIDECHAR 1 +#define _GNU_SOURCE #include "tui.h" @@ -11,15 +12,15 @@ #include "listnav.h" #include "ref.h" #include "style.h" +#include "strbuf.h" #include "util.h" #include <ncurses.h> +#include <ctype.h> +#include <string.h> #include <unistd.h> -#include <wchar.h> -#include <wctype.h> - #undef KEY_ENTER #define KEY_ENTER '\n' #define KEY_SPACE ' ' @@ -35,27 +36,28 @@ enum { IMODE_COUNT }; -typedef wchar_t *(*completion_gen)(const wchar_t *text, int fwd, int state); +typedef char *(*completion_gen)(const char *text, int fwd, int state); static void pane_title(struct pane *pane, const char *title, int highlight); -static wchar_t *command_name_gen(const wchar_t *text, int fwd, int state); -static wchar_t *track_name_gen(const wchar_t *text, int fwd, int state); -static wchar_t *tag_name_gen(const wchar_t *text, int fwd, int state); +static char *command_name_gen(const char *text, int fwd, int state); +static char *track_name_gen(const char *text, int fwd, int state); +static char *tag_name_gen(const char *text, int fwd, int state); static void toggle_current_tag(void); -static int tag_pane_input(wint_t c); + +static bool tag_pane_input(wint_t c); static void tag_pane_vis(struct pane *pane, int sel); -static int track_pane_input(wint_t c); +static bool track_pane_input(wint_t c); static void track_pane_vis(struct pane *pane, int sel); -static bool run_cmd(const wchar_t *name); -static bool play_track(const wchar_t *name); -static bool select_track(const wchar_t *name); -static bool select_tag(const wchar_t *name); +static bool run_cmd(const char *name); +static bool play_track(const char *name); +static bool select_track(const char *name); +static bool select_tag(const char *name); -static int cmd_pane_input(wint_t c); +static bool cmd_pane_input(wint_t c); static void cmd_pane_vis(struct pane *pane, int sel); static void queue_hover(void); @@ -125,36 +127,41 @@ pane_title(struct pane *pane, const char *title, int highlight) style_off(pane->win, STYLE_TITLE); } -wchar_t * -command_name_gen(const wchar_t *text, int fwd, int reset) +char * +command_name_gen(const char *text, int fwd, int reset) { static int index, len; + char *dup; int dir; dir = fwd ? 1 : -1; if (reset) { index = 0; - len = wcslen(text); + len = strlen(text); } else if (index >= -1 && index <= command_count) { index += dir; } while (index >= 0 && index < command_count) { - if (!wcsncmp(commands[index].name, text, len)) - return wcsdup(commands[index].name); + if (!strncmp(commands[index].name, text, len)) { + dup = strdup(commands[index].name); + OOM_CHECK(dup); + return dup; + } index += dir; } return NULL; } -wchar_t * -track_name_gen(const wchar_t *text, int fwd, int reset) +char * +track_name_gen(const char *text, int fwd, int reset) { static struct link *cur; struct link *iter; struct track *track; + char *dup; if (reset) { cur = tracks.head.next; @@ -165,9 +172,11 @@ track_name_gen(const wchar_t *text, int fwd, int reset) while (LIST_INNER(iter)) { track = UPCAST(iter, struct ref)->data; - if (wcscasestr(track->name, text)) { + if (strcasestr(track->name, text)) { cur = iter; - return wcsdup(track->name); + dup = strdup(track->name); + OOM_CHECK(dup); + return dup; } iter = fwd ? iter->next : iter->prev; } @@ -175,12 +184,13 @@ track_name_gen(const wchar_t *text, int fwd, int reset) return NULL; } -wchar_t * -tag_name_gen(const wchar_t *text, int fwd, int reset) +char * +tag_name_gen(const char *text, int fwd, int reset) { static struct link *cur; struct link *iter; struct tag *tag; + char *dup; if (reset) { cur = tags.head.next; @@ -191,9 +201,11 @@ tag_name_gen(const wchar_t *text, int fwd, int reset) while (LIST_INNER(iter)) { tag = UPCAST(iter, struct tag); - if (wcscasestr(tag->name, text)) { + if (strcasestr(tag->name, text)) { cur = iter; - return wcsdup(tag->name); + dup = strdup(tag->name); + OOM_CHECK(dup); + return dup; } iter = fwd ? iter->next : iter->prev; } @@ -220,7 +232,7 @@ toggle_current_tag(void) if (refs_incl(&tags_sel, tag)) { refs_rm(&tags_sel, tag); } else { - ref = ref_init(tag); + ref = ref_alloc(tag); list_push_back(&tags_sel, LINK(ref)); } @@ -229,36 +241,36 @@ toggle_current_tag(void) for (LIST_ITER(&tags_sel, link)) { tag = UPCAST(link, struct ref)->data; for (LIST_ITER(&tag->tracks, iter)) { - ref = ref_init(UPCAST(iter, struct ref)->data); + ref = ref_alloc(UPCAST(iter, struct ref)->data); ASSERT(ref != NULL); list_push_back(&player.playlist, LINK(ref)); } } } -int +bool tag_pane_input(wint_t c) { switch (c) { case KEY_UP: listnav_update_sel(&tag_nav, tag_nav.sel - 1); - return 1; + return true; case KEY_DOWN: listnav_update_sel(&tag_nav, tag_nav.sel + 1); - return 1; + return true; case KEY_SPACE: toggle_current_tag(); - return 1; + return true; case KEY_ENTER: refs_free(&tags_sel); toggle_current_tag(); - return 1; + return true; case KEY_PPAGE: listnav_update_sel(&tag_nav, tag_nav.sel - tag_nav.wlen / 2); - return 1; + return true; case KEY_NPAGE: listnav_update_sel(&tag_nav, tag_nav.sel + tag_nav.wlen / 2); - return 1; + return true; case 'g': listnav_update_sel(&tag_nav, 0); break; @@ -267,7 +279,7 @@ tag_pane_input(wint_t c) break; } - return 0; + return false; } void @@ -301,8 +313,7 @@ tag_pane_vis(struct pane *pane, int sel) else if (index == tag_nav.sel) style_on(pane->win, STYLE_PREV); - wmove(pane->win, 1 + index - tag_nav.wmin, 0); - wprintw(pane->win, "%-*.*ls", pane->w, pane->w, tag->name); + pane_writeln(pane, 1 + index - tag_nav.wmin, tag->name); if (sel && tagsel && index == tag_nav.sel) style_off(pane->win, STYLE_ITEM_HOVER_SEL); @@ -315,7 +326,7 @@ tag_pane_vis(struct pane *pane, int sel) } } -int +bool track_pane_input(wint_t c) { struct link *link; @@ -324,24 +335,24 @@ track_pane_input(wint_t c) switch (c) { case KEY_UP: listnav_update_sel(&track_nav, track_nav.sel - 1); - return 1; + return true; case KEY_DOWN: listnav_update_sel(&track_nav, track_nav.sel + 1); - return 1; + return true; case KEY_ENTER: link = list_at(tracks_vis, track_nav.sel); - if (!link) return 1; + if (!link) return true; track = UPCAST(link, struct ref)->data; player_play_track(track); - return 1; + return true; case KEY_PPAGE: listnav_update_sel(&track_nav, track_nav.sel - track_nav.wlen / 2); - return 1; + return true; case KEY_NPAGE: listnav_update_sel(&track_nav, track_nav.sel + track_nav.wlen / 2); - return 1; + return true; case 'g': listnav_update_sel(&track_nav, 0); break; @@ -350,7 +361,7 @@ track_pane_input(wint_t c) break; } - return 0; + return false; } void @@ -384,8 +395,7 @@ track_pane_vis(struct pane *pane, int sel) else if (index == track_nav.sel) style_on(pane->win, STYLE_PREV); - wmove(pane->win, 1 + index - track_nav.wmin, 0); - wprintw(pane->win, "%-*.*ls", pane->w, pane->w, track->name); + pane_writeln(pane, 1 + index - track_nav.wmin, track->name); if (sel && index == track_nav.sel && track == player.track) style_off(pane->win, STYLE_ITEM_HOVER_SEL); @@ -399,35 +409,44 @@ track_pane_vis(struct pane *pane, int sel) } bool -run_cmd(const wchar_t *query) +run_cmd(const char *query) { - bool success; + bool success, found; - success = cmd_run(query); + success = cmd_run(query, &found); if (!success && !cmd_status) - CMD_SET_STATUS("Command Failed!"); - return true; + CMD_SET_STATUS("FAIL"); + else if (success && !cmd_status) + CMD_SET_STATUS("OK"); + + return found; } bool -play_track(const wchar_t *query) +play_track(const char *query) { struct track *track; struct link *iter; + int fid; + fid = -1; for (LIST_ITER(&tracks, iter)) { track = UPCAST(iter, struct ref)->data; - if (!wcscmp(track->name, query)) { + if (fid == track->fid) continue; + + if (!strcmp(track->name, query)) { player_play_track(track); return true; } + + fid = track->fid; } return false; } bool -select_track(const wchar_t *query) +select_track(const char *query) { struct track *track; struct link *link; @@ -436,7 +455,7 @@ select_track(const wchar_t *query) index = 0; for (LIST_ITER(tracks_vis, link)) { track = UPCAST(link, struct ref)->data; - if (!wcscmp(track->name, query)) { + if (!strcmp(track->name, query)) { listnav_update_sel(&track_nav, index); pane_after_cmd = track_pane; return true; @@ -448,7 +467,7 @@ select_track(const wchar_t *query) } bool -select_tag(const wchar_t *query) +select_tag(const char *query) { struct tag *tag; struct link *iter; @@ -458,7 +477,7 @@ select_tag(const wchar_t *query) for (LIST_ITER(&tags, iter)) { index += 1; tag = UPCAST(iter, struct tag); - if (!wcscmp(tag->name, query)) { + if (!strcmp(tag->name, query)) { listnav_update_sel(&tag_nav, index); pane_after_cmd = tag_pane; return true; @@ -468,19 +487,19 @@ select_tag(const wchar_t *query) return false; } -int +bool cmd_pane_input(wint_t c) { - wchar_t *res; + char *res; int match; switch (c) { case KEY_ESC: - match = wcscmp(completion_query.buf, history->input->buf); + match = strcmp(completion_query.buf, history->input->buf); if (!completion_reset && match) { inputln_copy(history->input, &completion_query); } else if (history->sel == history->input) { - inputln_replace(history->input, L""); + inputln_replace(history->input, ""); pane_sel = pane_after_cmd; } else { history->sel = history->input; @@ -550,82 +569,61 @@ cmd_pane_input(wint_t c) completion_reset = 1; break; default: - if (!iswprint(c)) return 0; + /* TODO: wide char input support */ + if (!isprint(c)) return 0; inputln_addch(history->sel, c); completion_reset = 1; break; } - return 1; /* grab everything */ + return true; /* grab everything */ } void cmd_pane_vis(struct pane *pane, int sel) { - static wchar_t *linebuf = NULL; - static int linecap = 0; + static struct strbuf line = { 0 }; struct inputln *cmd; struct link *iter; - wchar_t *line, *end; int index, offset; werase(pane->win); - /* static line buffer for perf */ - if (pane->w > linecap) { - linecap = MAX(linecap, pane->w); - linebuf = realloc(linebuf, linecap * sizeof(wchar_t)); - } - end = linebuf + linecap; - /* track name */ style_on(pane->win, STYLE_TITLE); pane_clearln(pane, 0); if (player.loaded && player.track) { - swprintf(linebuf, linecap, L"%ls", player.track->name); - mvwaddwstr(pane->win, 0, 1, linebuf); + strbuf_clear(&line); + strbuf_append(&line, " %s", player.track->name); + pane_writeln(pane, 0, line.buf); } style_off(pane->win, STYLE_TITLE); if (player.loaded) { /* status line */ - line = linebuf; - line += swprintf(line, end - line, L"%c ", - player_state_chars[player.state]); - line += swprintf(line, end - line, L"%s / ", - timestr(player.time_pos)); - line += swprintf(line, end - line, L"%s", - timestr(player.time_end)); - - if (player.volume >= 0) { - line += swprintf(line, end - line, L" - vol: %u%%", - player.volume); - } + strbuf_clear(&line); + strbuf_append(&line, "%c ", player_state_chars[player.state]); + strbuf_append(&line, "%s / ", timestr(player.time_pos)); + strbuf_append(&line, "%s", timestr(player.time_end)); - if (player.status) { - line += swprintf(line, end - line, L" | [PLAYER] %s", - player.status); - } + if (player.volume >= 0) + strbuf_append(&line, " - vol: %u%%", player.volume); - if (list_len(&player.queue)) { - line += swprintf(line, end - line, - L" | [QUEUE] %i tracks", + if (player.status) + strbuf_append(&line, " | [PLAYER] %s", player.status); + + if (list_len(&player.queue) > 0) + strbuf_append(&line, " | [QUEUE] %i tracks", list_len(&player.queue)); - } ATTR_ON(pane->win, A_REVERSE); - pane_clearln(pane, 1); - mvwaddwstr(pane->win, 1, 0, linebuf); + pane_writeln(pane, 1, line.buf); ATTR_OFF(pane->win, A_REVERSE); } else if (player.status) { /* player message */ - line = linebuf; - line += swprintf(line, linecap, L"[PLAYER] %s", player.status); - line += swprintf(line, end - line, L"%*.*s", - pane->w, pane->w, L" "); - - pane_clearln(pane, 1); - mvwaddwstr(pane->win, 1, 0, linebuf); + strbuf_clear(&line); + strbuf_append(&line, "[PLAYER] %s", player.status); + pane_writeln(pane, 1, line.buf); } /* status bits on right of status line */ @@ -638,7 +636,7 @@ cmd_pane_vis(struct pane *pane, int sel) if (sel || cmd_show) { /* cmd and search input */ - line = linebuf; + strbuf_clear(&line); free(cmd_status); cmd_status = NULL; @@ -651,18 +649,15 @@ cmd_pane_vis(struct pane *pane, int sel) break; index += 1; } - line += swprintf(line, end - line, L"[%i] ", - iter ? index : -1); + strbuf_append(&line, "[%i] ", iter ? index : -1); } else { - line += swprintf(line, end - line, L"%c", - imode_prefix[cmd_input_mode]); + strbuf_append(&line, "%c", imode_prefix[cmd_input_mode]); } - offset = wcslen(linebuf); + offset = strlen(line.buf); - line += swprintf(line, end - line, L"%ls", cmd->buf); + strbuf_append(&line, "%s", cmd->buf); - pane_clearln(pane, 2); - mvwaddwstr(pane->win, 2, 0, linebuf); + pane_writeln(pane, 2, line.buf); if (sel) { /* show cursor in text */ ATTR_ON(pane->win, A_REVERSE); @@ -672,8 +667,9 @@ cmd_pane_vis(struct pane *pane, int sel) ATTR_OFF(pane->win, A_REVERSE); } } else if (cmd_status) { - pane_clearln(pane, 2); - mvwprintw(pane->win, 2, 0, " %.*s", pane->w - 1, cmd_status); + strbuf_clear(&line); + strbuf_append(&line, " %s", cmd_status); + pane_writeln(pane, 2, line.buf); } } @@ -888,7 +884,7 @@ tui_resize(void) leftw = 0; for (LIST_ITER(&tags, iter)) { tag = UPCAST(iter, struct tag); - leftw = MAX(leftw, wcslen(tag->name)); + leftw = MAX(leftw, strlen(tag->name)); } leftw = MAX(leftw + 1, 0.2f * scrw); @@ -939,14 +935,16 @@ tui_deinit(void) { free(cmd_status); - pane_free(&pane_left); - pane_free(&pane_right); - pane_free(&pane_bot); + inputln_deinit(&completion_query); + + pane_deinit(&pane_left); + pane_deinit(&pane_right); + pane_deinit(&pane_bot); - history_free(&track_play_history); - history_free(&track_select_history); - history_free(&tag_select_history); - history_free(&command_history); + history_deinit(&track_play_history); + history_deinit(&track_select_history); + history_deinit(&tag_select_history); + history_deinit(&command_history); if (!isendwin()) endwin(); } diff --git a/src/tui.h b/src/tui.h @@ -5,7 +5,6 @@ #include "pane.h" #include <stdbool.h> -#include <wchar.h> void tui_init(void); void tui_deinit(void); diff --git a/src/util.c b/src/util.c @@ -9,53 +9,10 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> -#include <wchar.h> -#include <wctype.h> static const char *allowed = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;-_(){}[]"; -int -strnwidth(const char *s, int n) -{ - mbstate_t shift_state; - wchar_t wc; - size_t wc_len; - size_t width = 0; - - memset(&shift_state, '\0', sizeof shift_state); - - for (size_t i = 0; i < n; i += wc_len) { - wc_len = mbrtowc(&wc, s + i, MB_CUR_MAX, &shift_state); - if (!wc_len) { - break; - } else if (wc_len >= (size_t)-2) { - width += MIN(n - 1, strlen(s + i)); - break; - } else { - width += iswcntrl(wc) ? 2 : MAX(0, wcwidth(wc)); - } - } - -done: - return width; -} - -const wchar_t * -wcscasestr(const wchar_t *haystack, const wchar_t *needle) -{ - int hslen, nlen, i; - - nlen = wcslen(needle); - hslen = wcslen(haystack) - nlen; - for (i = 0; i < hslen; i++) { - if (!wcsncasecmp(haystack + i, needle, nlen)) - return haystack + i; - } - - return NULL; -} - void panic(const char *file, int line, const char *msg, ...) { diff --git a/src/util.h b/src/util.h @@ -1,7 +1,6 @@ #pragma once #include <stdio.h> -#include <wchar.h> #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) > (b) ? (b) : (a)) @@ -15,10 +14,6 @@ #define LINK(p) (&(p)->link) #define UPCAST(iter, type) LINK_UPCAST(iter, type, link) -int strnwidth(const char *s, int n); - -const wchar_t *wcscasestr(const wchar_t *haystack, const wchar_t *needle); - void panic(const char *file, int line, const char *msg, ...); void assert(int cond, const char *file, int line, const char *condstr); void error(const char *fmtstr, ...);