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;
}
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)
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;
}
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;
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;
}
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;
}
};
enum {
- FTP_REMOTE,
- FTP_LOCAL
-};
-
-enum {
- FTP_MOD_REMDIR = 0x100,
- FTP_MOD_LOCDIR = 0x200
+ FTP_MOD_DIR = 0x100
};
struct ftp_op {
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;
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_ */
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 {
#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;
return 1;
}
+ localdir = darr_alloc(0, sizeof *localdir);
+ getcwd(curdir, sizeof curdir);
+ update_localdir();
+
if(!(ftp = ftp_alloc())) {
return 1;
}
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);
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)
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:
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);
enum {
TUI_ONCLICK,
TUI_ONMODIFY,
+ TUI_ONFOCUS,
TUI_NUM_CALLBACKS
};
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);
}
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)
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)
}
wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
return 0;
}
wl->view_offs = wl->sel - wl->height;
}
wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
return 0;
}
wl->view_offs = wl->sel;
}
wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
return 0;
}
wl->sel = 0;
wl->view_offs = 0;
wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
return 0;
}
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;
}
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)
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);
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
default:
break;
}
+ if(key >= KEY_F(1) && key <= KEY_F(12)) {
+ return KB_F1 + (key - KEY_F(1));
+ }
if(key < 128) {
return key;
}