From d3c8a942b99443abf0c11d9759994022ed6da597 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 25 Jan 2023 08:19:08 +0200 Subject: [PATCH] local navigation --- src/ftp.c | 36 ++++++------ src/ftp.h | 19 +++---- src/input.h | 15 ++++- src/main.c | 160 +++++++++++++++++++++++++++++++++++++++++++++--------- src/tui.c | 18 ++++++ src/tui.h | 5 ++ src/tui_list.c | 14 ++++- src/tuipriv.h | 2 +- src/unix/input.c | 3 + 9 files changed, 213 insertions(+), 59 deletions(-) diff --git a/src/ftp.c b/src/ftp.c index 0a0c721..07cec45 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -49,8 +49,7 @@ struct ftp *ftp_alloc(void) ftp->ctl = ftp->data = ftp->lis = -1; ftp->passive = 1; - ftp->dirent[0] = darr_alloc(0, sizeof *ftp->dirent[0]); - ftp->dirent[1] = darr_alloc(0, sizeof *ftp->dirent[1]); + ftp->dirent = darr_alloc(0, sizeof *ftp->dirent); return ftp; } @@ -62,8 +61,7 @@ void ftp_free(struct ftp *ftp) ftp_close(ftp); } - free_dir(ftp->dirent[0]); - free_dir(ftp->dirent[1]); + free_dir(ftp->dirent); } static void free_dir(struct ftp_dirent *dir) @@ -740,9 +738,9 @@ static int cproc_pwd(struct ftp *ftp, int code, const char *buf, void *cls) return -1; } - free(ftp->curdir[FTP_REMOTE]); - ftp->curdir[FTP_REMOTE] = strdup_nf(dirname); - ftp->modified = FTP_MOD_REMDIR; + free(ftp->curdir); + ftp->curdir = strdup_nf(dirname); + ftp->modified = FTP_MOD_DIR; return 0; } @@ -816,7 +814,7 @@ static int parse_dirent(struct ftp_dirent *ent, const char *line) return 0; } -static int direntcmp(const void *a, const void *b) +int ftp_direntcmp(const void *a, const void *b) { const struct ftp_dirent *da = a, *db = b; @@ -837,23 +835,23 @@ static void dproc_list(struct ftp *ftp, const char *buf, int sz, void *cls) char *end = rbuf->buf + rbuf->size; struct ftp_dirent ent; - darr_clear(ftp->dirent[FTP_REMOTE]); + darr_clear(ftp->dirent); while(ptr < end) { if(parse_dirent(&ent, ptr) != -1) { - darr_push(ftp->dirent[FTP_REMOTE], &ent); + darr_push(ftp->dirent, &ent); } while(ptr < end && *ptr != '\n' && *ptr != '\r') ptr++; while(ptr < end && (*ptr == '\r' || *ptr == '\n')) ptr++; } - ftp->modified |= FTP_MOD_REMDIR; + ftp->modified |= FTP_MOD_DIR; free(rbuf->buf); free(rbuf); ftp->dproc = 0; - num = darr_size(ftp->dirent[FTP_REMOTE]); - qsort(ftp->dirent[FTP_REMOTE], num, sizeof *ftp->dirent[FTP_REMOTE], direntcmp); + num = darr_size(ftp->dirent); + qsort(ftp->dirent, num, sizeof *ftp->dirent, ftp_direntcmp); return; } @@ -873,17 +871,17 @@ static void dproc_list(struct ftp *ftp, const char *buf, int sz, void *cls) rbuf->size += sz; } -const char *ftp_curdir(struct ftp *ftp, int whichdir) +const char *ftp_curdir(struct ftp *ftp) { - return ftp->curdir[whichdir]; + return ftp->curdir; } -int ftp_num_dirent(struct ftp *ftp, int whichdir) +int ftp_num_dirent(struct ftp *ftp) { - return darr_size(ftp->dirent[whichdir]); + return darr_size(ftp->dirent); } -struct ftp_dirent *ftp_dirent(struct ftp *ftp, int whichdir, int idx) +struct ftp_dirent *ftp_dirent(struct ftp *ftp, int idx) { - return ftp->dirent[whichdir] + idx; + return ftp->dirent + idx; } diff --git a/src/ftp.h b/src/ftp.h index faf057b..5765b62 100644 --- a/src/ftp.h +++ b/src/ftp.h @@ -22,13 +22,7 @@ enum { }; enum { - FTP_REMOTE, - FTP_LOCAL -}; - -enum { - FTP_MOD_REMDIR = 0x100, - FTP_MOD_LOCDIR = 0x200 + FTP_MOD_DIR = 0x100 }; struct ftp_op { @@ -62,8 +56,8 @@ struct ftp { int num_crecv; char drecv[256]; - char *curdir[2]; - struct ftp_dirent *dirent[2]; /* dynamic array */ + char *curdir; + struct ftp_dirent *dirent; /* dynamic array */ int last_resp; int modified; @@ -94,9 +88,10 @@ int ftp_list(struct ftp *ftp); int ftp_retrieve(struct ftp *ftp, const char *fname); int ftp_store(struct ftp *ftp, const char *fname); -const char *ftp_curdir(struct ftp *ftp, int whichdir); -int ftp_num_dirent(struct ftp *ftp, int whichdir); -struct ftp_dirent *ftp_dirent(struct ftp *ftp, int whichdir, int idx); +const char *ftp_curdir(struct ftp *ftp); +int ftp_num_dirent(struct ftp *ftp); +struct ftp_dirent *ftp_dirent(struct ftp *ftp, int idx); +int ftp_direntcmp(const void *a, const void *b); #endif /* FTP_H_ */ diff --git a/src/input.h b/src/input.h index ac1a546..d6f372a 100644 --- a/src/input.h +++ b/src/input.h @@ -11,7 +11,20 @@ enum { KB_HOME, KB_END, KB_PGUP, - KB_PGDN + KB_PGDN, + + KB_F1, + KB_F2, + KB_F3, + KB_F4, + KB_F5, + KB_F6, + KB_F7, + KB_F8, + KB_F9, + KB_F10, + KB_F11, + KB_F12 }; enum { diff --git a/src/main.c b/src/main.c index a3e8647..9b4f9d5 100644 --- a/src/main.c +++ b/src/main.c @@ -3,24 +3,39 @@ #include #include #include +#ifdef __MSDOS__ +#include +#else +#include +#include +#endif +#include #include #include "tgfx.h" #include "input.h" #include "util.h" #include "tui.h" #include "ftp.h" +#include "darray.h" void updateui(void); +int update_localdir(void); int proc_input(void); int keypress(int key); int parse_args(int argc, char **argv); static struct ftp *ftp; -static struct tui_widget *uilist; +static struct tui_widget *uilist[2]; + +static int focus; static char *host = "localhost"; static int port = 21; +static char curdir[PATH_MAX + 1]; +static struct ftp_dirent *localdir; + + int main(int argc, char **argv) { int i, numsock, maxfd; @@ -32,6 +47,10 @@ int main(int argc, char **argv) return 1; } + localdir = darr_alloc(0, sizeof *localdir); + getcwd(curdir, sizeof curdir); + update_localdir(); + if(!(ftp = ftp_alloc())) { return 1; } @@ -47,11 +66,15 @@ int main(int argc, char **argv) tg_bgchar(' '); tg_clear(); - uilist = tui_list("Remote", 0, 0, 40, 23, 0, 0); + uilist[0] = tui_list("Remote", 0, 0, 40, 23, 0, 0); + uilist[1] = tui_list("Local", 40, 0, 40, 23, 0, 0); + focus = 0; + tui_focus(uilist[focus], 1); tg_setcursor(0, 23); - tui_draw(uilist); + tui_draw(uilist[0]); + tui_draw(uilist[1]); for(;;) { FD_ZERO(&rdset); @@ -107,35 +130,92 @@ void updateui(void) char buf[128]; const char *remdir; - remdir = ftp_curdir(ftp, FTP_REMOTE); - if(remdir && strcmp(tui_get_title(uilist), remdir) != 0) { - tui_set_title(uilist, remdir); + remdir = ftp_curdir(ftp); + if(remdir && strcmp(tui_get_title(uilist[0]), remdir) != 0) { + tui_set_title(uilist[0], remdir); upd |= 1; } - if(ftp->modified & FTP_MOD_REMDIR) { - tui_clear_list(uilist); + if(ftp->modified & FTP_MOD_DIR) { + tui_clear_list(uilist[0]); - num = ftp_num_dirent(ftp, FTP_REMOTE); + num = ftp_num_dirent(ftp); for(i=0; itype == FTP_DIR) { sprintf(buf, "%s/", ent->name); - tui_add_list_item(uilist, buf); + tui_add_list_item(uilist[0], buf); } else { - tui_add_list_item(uilist, ent->name); + tui_add_list_item(uilist[0], ent->name); } } - tui_list_select(uilist, 0); + tui_list_select(uilist[0], 0); - ftp->modified &= ~FTP_MOD_REMDIR; + ftp->modified &= ~FTP_MOD_DIR; upd |= 1; } - if(tui_isdirty(uilist) || upd & 1) { - tui_draw(uilist); + if(strcmp(tui_get_title(uilist[1]), curdir) != 0) { + tui_clear_list(uilist[1]); + num = darr_size(localdir); + for(i=0; itype == FTP_DIR) { + sprintf(buf, "%s/", ent->name); + tui_add_list_item(uilist[1], buf); + } else { + tui_add_list_item(uilist[1], ent->name); + } + } + tui_list_select(uilist[1], 0); + tui_set_title(uilist[1], curdir); + upd |= 2; + } + + if(tui_isdirty(uilist[0]) || upd & 1) { + tui_draw(uilist[0]); + } + if(tui_isdirty(uilist[1]) || upd & 2) { + tui_draw(uilist[1]); + } +} + +int update_localdir(void) +{ + DIR *dir; + struct dirent *dent; + struct stat st; + struct ftp_dirent ent; + + if(!(dir = opendir(curdir))) { + errmsg("failed to open directory: %s\n", curdir); + return -1; + } + + darr_clear(localdir); + while((dent = readdir(dir))) { + ent.name = strdup_nf(dent->d_name); + if(strcmp(dent->d_name, ".") == 0) continue; + + if(stat(dent->d_name, &st) == 0) { + if(S_ISDIR(st.st_mode)) { + ent.type = FTP_DIR; + } else { + ent.type = FTP_FILE; + } + ent.size = st.st_size; + } else { + ent.type = FTP_FILE; + ent.size = 0; + } + + darr_push(localdir, &ent); } + closedir(dir); + + qsort(localdir, darr_size(localdir), sizeof *localdir, ftp_direntcmp); + return 0; } int proc_input(void) @@ -160,34 +240,64 @@ int proc_input(void) int keypress(int key) { int sel; - const char *name; switch(key) { case 27: case 'q': + case KB_F10: return -1; + case '\t': + tui_focus(uilist[focus], 0); + focus ^= 1; + tui_focus(uilist[focus], 1); + break; + case KB_UP: - tui_list_sel_prev(uilist); + tui_list_sel_prev(uilist[focus]); break; case KB_DOWN: - tui_list_sel_next(uilist); + tui_list_sel_next(uilist[focus]); break; case KB_LEFT: - tui_list_sel_start(uilist); + tui_list_sel_start(uilist[focus]); break; case KB_RIGHT: - tui_list_sel_end(uilist); + tui_list_sel_end(uilist[focus]); break; case '\n': - sel = tui_get_list_sel(uilist); - name = ftp_dirent(ftp, FTP_REMOTE, sel)->name; - ftp_queue(ftp, FTP_CHDIR, name); + sel = tui_get_list_sel(uilist[focus]); + if(focus == 0) { + struct ftp_dirent *ent = ftp_dirent(ftp, sel); + if(ent->type == FTP_DIR) { + ftp_queue(ftp, FTP_CHDIR, ent->name); + } else { + /* TODO */ + } + } else { + if(localdir[sel].type == FTP_DIR) { + if(chdir(localdir[sel].name) == -1) { + errmsg("failed to change directory: %s\n", localdir[sel].name); + } else { + getcwd(curdir, sizeof curdir); + update_localdir(); + } + } else { + /* TODO */ + } + } break; case '\b': - ftp_queue(ftp, FTP_CDUP, 0); + if(focus == 0) { + ftp_queue(ftp, FTP_CDUP, 0); + } else { + if(chdir("..") == 0) { + getcwd(curdir, sizeof curdir); + update_localdir(); + } + } break; default: diff --git a/src/tui.c b/src/tui.c index 1cdad05..7f20e94 100644 --- a/src/tui.c +++ b/src/tui.c @@ -108,6 +108,24 @@ void tui_set_callback(struct tui_widget *w, int type, tui_callback func, void *c w->cbcls[type] = cls; } +void tui_call_callback(struct tui_widget *w, int type) +{ + if(w->cbfunc[type]) { + w->cbfunc[type](w, w->cbcls[type]); + } +} + +void tui_focus(struct tui_widget *w, int focus) +{ + focus = focus ? 1 : 0; + if(w->focus == focus) { + return; + } + w->focus = focus; + w->dirty = 1; + tui_call_callback(w, TUI_ONFOCUS); +} + int tui_set_title(struct tui_widget *w, const char *s) { free(w->title); diff --git a/src/tui.h b/src/tui.h index 2a3bfa7..59a07c9 100644 --- a/src/tui.h +++ b/src/tui.h @@ -14,6 +14,7 @@ enum { TUI_UNKNOWN, TUI_WINDOW, TUI_BUTTON, TUI_LIST }; enum { TUI_ONCLICK, TUI_ONMODIFY, + TUI_ONFOCUS, TUI_NUM_CALLBACKS }; @@ -31,10 +32,14 @@ int tui_isdirty(struct tui_widget *w); void tui_draw(struct tui_widget *w); void tui_set_callback(struct tui_widget *w, int type, tui_callback func, void *cls); +void tui_call_callback(struct tui_widget *w, int type); int tui_set_title(struct tui_widget *w, const char *s); const char *tui_get_title(struct tui_widget *w); +void tui_focus(struct tui_widget *w, int focus); +int tui_hasfocus(struct tui_widget *w); + struct tui_widget *tui_window(const char *title, int x, int y, int w, int h); struct tui_widget *tui_button(const char *title, int x, int y, tui_callback cbfunc, void *cbdata); struct tui_widget *tui_list(const char *title, int x, int y, int w, int h, tui_callback cbfunc, void *cbdata); diff --git a/src/tui_list.c b/src/tui_list.c index b57e5ff..c5f510c 100644 --- a/src/tui_list.c +++ b/src/tui_list.c @@ -56,6 +56,8 @@ void tui_clear_list(struct tui_widget *w) } darr_clear(wl->entries); wl->dirty = 1; + + tui_call_callback(w, TUI_ONMODIFY); } void tui_add_list_item(struct tui_widget *w, const char *text) @@ -66,6 +68,8 @@ void tui_add_list_item(struct tui_widget *w, const char *text) str = strdup_nf(text); darr_push(wl->entries, &str); wl->dirty = 1; + + tui_call_callback(w, TUI_ONMODIFY); } int tui_num_list_items(struct tui_widget *w) @@ -106,6 +110,7 @@ int tui_list_select(struct tui_widget *w, int idx) } wl->dirty = 1; + tui_call_callback(w, TUI_ONMODIFY); return 0; } @@ -132,6 +137,7 @@ int tui_list_sel_next(struct tui_widget *w) wl->view_offs = wl->sel - wl->height; } wl->dirty = 1; + tui_call_callback(w, TUI_ONMODIFY); return 0; } @@ -147,6 +153,7 @@ int tui_list_sel_prev(struct tui_widget *w) wl->view_offs = wl->sel; } wl->dirty = 1; + tui_call_callback(w, TUI_ONMODIFY); return 0; } @@ -158,6 +165,7 @@ int tui_list_sel_start(struct tui_widget *w) wl->sel = 0; wl->view_offs = 0; wl->dirty = 1; + tui_call_callback(w, TUI_ONMODIFY); return 0; } @@ -173,6 +181,7 @@ int tui_list_sel_end(struct tui_widget *w) wl->view_offs = nelem - wl->height; if(wl->view_offs < 0) wl->view_offs = 0; wl->dirty = 1; + tui_call_callback(w, TUI_ONMODIFY); return 0; } @@ -188,6 +197,9 @@ void tui_sort_list(struct tui_widget *w, int (*cmpfunc)(const void*, const void* nelem = darr_size(wl->entries); qsort(wl->entries, nelem, sizeof *wl->entries, cmpfunc); + + wl->dirty = 1; + tui_call_callback(w, TUI_ONMODIFY); } static void draw_list(struct tui_widget *w, void *cls) @@ -209,7 +221,7 @@ static void draw_list(struct tui_widget *w, void *cls) x++; for(i=0; iview_offs; - if(idx == wl->sel) { + if(w->focus && idx == wl->sel) { tg_bgcolor(TGFX_CYAN); tg_fgcolor(TGFX_BLUE); diff --git a/src/tuipriv.h b/src/tuipriv.h index 45632a8..9a9c328 100644 --- a/src/tuipriv.h +++ b/src/tuipriv.h @@ -12,7 +12,7 @@ enum { int type; \ char *title; \ int x, y, width, height; \ - int dirty; \ + int focus, dirty; \ tui_callback cbfunc[TUI_NUM_CALLBACKS]; \ void *cbcls[TUI_NUM_CALLBACKS]; \ struct tui_widget *par, *child, *next diff --git a/src/unix/input.c b/src/unix/input.c index 6fba0fc..f39c04f 100644 --- a/src/unix/input.c +++ b/src/unix/input.c @@ -42,6 +42,9 @@ static int convkey(int key) default: break; } + if(key >= KEY_F(1) && key <= KEY_F(12)) { + return KB_F1 + (key - KEY_F(1)); + } if(key < 128) { return key; } -- 1.7.10.4