local navigation
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 25 Jan 2023 06:19:08 +0000 (08:19 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 25 Jan 2023 06:19:08 +0000 (08:19 +0200)
src/ftp.c
src/ftp.h
src/input.h
src/main.c
src/tui.c
src/tui.h
src/tui_list.c
src/tuipriv.h
src/unix/input.c

index 0a0c721..07cec45 100644 (file)
--- 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;
 }
index faf057b..5765b62 100644 (file)
--- 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_ */
index ac1a546..d6f372a 100644 (file)
@@ -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 {
index a3e8647..9b4f9d5 100644 (file)
@@ -3,24 +3,39 @@
 #include <signal.h>
 #include <errno.h>
 #include <assert.h>
+#ifdef __MSDOS__
+#include <direct.h>
+#else
+#include <unistd.h>
+#include <dirent.h>
+#endif
+#include <sys/stat.h>
 #include <sys/select.h>
 #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; i<num; i++) {
-                       ent = ftp_dirent(ftp, FTP_REMOTE, i);
+                       ent = ftp_dirent(ftp, i);
                        if(ent->type == 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; i<num; i++) {
+                       ent = localdir + i;
+                       if(ent->type == 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:
index 1cdad05..7f20e94 100644 (file)
--- 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);
index 2a3bfa7..59a07c9 100644 (file)
--- 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);
index b57e5ff..c5f510c 100644 (file)
@@ -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; i<num; i++) {
                idx = i + wl->view_offs;
-               if(idx == wl->sel) {
+               if(w->focus && idx == wl->sel) {
                        tg_bgcolor(TGFX_CYAN);
                        tg_fgcolor(TGFX_BLUE);
 
index 45632a8..9a9c328 100644 (file)
@@ -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
index 6fba0fc..f39c04f 100644 (file)
@@ -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;
        }