#include #include #include #include #include #include #include #include #include extern const char *__progname; #include "es.h" #include "prf.h" #include "vars.h" #include "ui.h" static volatile sig_atomic_t winched; static int redraw; #define REDRAW_BODY 0x00000001 #define REDRAW_INPUT 0x00000002 #define REDRAW__ALL (REDRAW_BODY | REDRAW_INPUT) static unsigned char *ilbuf; static int ilba; static int ilbl; static int icurs; static int iesc; static ES fold; static int fcols; static ES *idl_v; static int idl_a; static int idl_n; static int lastilines; static int scl; static int scc; #define MAXBODY 1024 static ES **body; static int nfiles; static char **files; static char *filesaw; #define Cisspace(x) isspace((unsigned char)(x)) static void start_playing(WORKER *w, const char *fn) { prf("Starting playing %s",fn); aio_oq_queue_copy(&w->oq,"p",1); aio_oq_queue_copy(&w->oq,fn,AIO_STRLEN); aio_oq_queue_point(&w->oq,"",1); } static void ui_command(WORKER *w, const char *s, int l) { int i; int i0; int n; prf("> %.*s",l,s); for (i=0;(i= l) return; i0 = i; for (;(i= nfiles)) { prf("play: index %d out of range (0..%d)",n,nfiles-1); } else { start_playing(w,files[n]); } return; } break; case 'q': if (! bcmp(s+i0,"quit",4)) { aio_oq_queue_point(&w->oq,"Q",2); return; } break; } break; } prf("Unrecognized command `%.*s'",i-i0,s+i0); } static void il_del_n_at(int at, int n) { if ((at < 0) || (n < 0) || (at > ilbl) || (n > ilbl) || (at+n > ilbl)) abort(); if (at+n < ilbl) bcopy(ilbuf+at+n,ilbuf+at,ilbl-(at+n)); ilbl -= n; } static void il_ins_n_at(int at, const void *data, int n) { if ((at < 0) || (n < 0) || (at > ilbl)) abort(); if (n < 1) return; if (ilbl+n > ilba) { ilba = ilbl + n + 16; ilbuf = realloc(ilbuf,ilba); } if (at < ilbl) bcopy(ilbuf+at,ilbuf+at+n,ilbl-at); bcopy(data,ilbuf+at,n); ilbl += n; } static void ui_ichar_norm(WORKER *w, char c) { switch (c) { case 1: // ^A icurs = 0; break; case 2: // ^B if (icurs > 0) icurs --; break; case 4: // ^D if (icurs < ilbl) il_del_n_at(icurs,1); break; case 5: // ^E icurs = ilbl; break; case 6: // ^F if (icurs < ilbl) icurs ++; break; case 8: // ^H case 127: // DEL if (icurs > 0) { icurs --; il_del_n_at(icurs,1); } break; case 10: // ^J case 13: // ^M il_ins_n_at(ilbl,"",1); ui_command(w,ilbuf,ilbl-1); icurs = 0; ilbl = 0; break; case 11: // ^K ilbl = icurs; break; case 12: // ^L clearok(stdscr,TRUE); break; case 20: // ^T if (icurs >= 2) { unsigned char t; t = ilbuf[icurs-2]; ilbuf[icurs-2] = ilbuf[icurs-1]; ilbuf[icurs-1] = t; } break; case 21: // ^U case 24: // ^X if (ilbl > 0) { icurs = 0; il_del_n_at(0,ilbl); } break; case 27: // ESC iesc = 1; break; default: if ((c == 9) || ((c >= 32) && (c <= 126)) || (c >= 160)) { il_ins_n_at(icurs,&c,1); icurs ++; } else { beep(); } break; } } static void exit_now(void) { move(LINES-1,0); refresh(); endwin(); printf("\n"); exit(0); } static void ui_ichar_esc(WORKER *w, char c) { (void)w; switch (c) { case 'b': break; case 'd': break; case 'f': break; case 'h': break; case 17: // ^Q exit_now(); break; } } static void ui_ichar(WORKER *w, char c) { if (iesc) { iesc = 0; ui_ichar_esc(w,c); } else { ui_ichar_norm(w,c); } } static void ui_rd_stdin(void *wv) { char rbuf[512]; int nr; int i; nr = read(0,&rbuf[0],sizeof(rbuf)); if (nr < 0) { switch (errno) { case EINTR: case EWOULDBLOCK: return; break; } fprintf(stderr,"%s: stdin read: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) exit(0); for (i=0;i= nfiles)) abort(); if ((n >= l) || (s[n] != ' ')) abort(); t = malloc(l-(n+1)+1); bcopy(s+n+1,t,l-(n+1)); t[l-(n+1)] = '\0'; files[x] = t; filesaw[x] = 1; for (n=nfiles-1;n>=0;n--) if (! filesaw[n]) return; prf("file count = %d",nfiles); for (n=0;n= idl_a) { i = idl_a; idl_a = idl_n + 8; idl_v = realloc(idl_v,idl_a*sizeof(ES)); while (i < idl_a) es_init(&idl_v[i++]); } es_clear(&idl_v[idl_n]); es_append_n(&idl_v[idl_n],es_ptr(&fold),es_len(&fold)); idl_n ++; } static void fold_input(void) { int i; char oform[4]; int olen; unsigned char c; idl_n = 0; es_clear(&fold); es_append_n(&fold,"> ",2); scl = -1; for (i=0;i<=ilbl;i++) { c = (i < ilbl) ? ilbuf[i] : ' '; if (i == icurs) { scl = idl_n; scc = es_len(&fold); } if (c < 32) { oform[0] = '^'; oform[1] = c ^ 64; olen = 2; } else if (c < 126) { oform[0] = c; olen = 1; } else if (c == 127) { oform[0] = '^'; oform[1] = '?'; olen = 2; } else if (c < 160) { oform[0] = '\\'; oform[1] = "01234567"[(c>>6)&3]; oform[2] = "01234567"[(c>>3)&7]; oform[3] = "01234567"[c&7]; olen = 4; } else { oform[0] = c; olen = 1; } if (es_len(&fold)+olen > fcols) fold_save(); es_append_n(&fold,&oform[0],olen); } fold_save(); if (scl < 0) abort(); } static int ui_redraw(void *wv) { WORKER *w; int l; ES *e; int i; int j; w = wv; if (winched) { winched = 0; redraw |= REDRAW__ALL; } if (fcols != COLS) { fcols = COLS; redraw |= REDRAW__ALL; } if (redraw == 0) return(AIO_BLOCK_NIL); if (redraw & REDRAW_INPUT) { redraw &= ~REDRAW_INPUT; fold_input(); if (idl_n != lastilines) { lastilines = idl_n; redraw |= REDRAW_BODY; } for (l=1;(l<=idl_n)&&(l<=LINES);l++) { move(LINES-l,0); e = &idl_v[idl_n-l]; addnstr(es_ptr(e),es_len(e)); clrtoeol(); } } if (redraw & REDRAW_BODY) { redraw &= ~REDRAW_BODY; for (l=LINES-1-idl_n,i=0;l>=0;l--,i++) { move(l,0); if ((i >= MAXBODY) || !body[i]) { addnstr("~",1); } else { j = es_len(body[i]); if (j >= fcols) j = fcols - 1; addnstr(es_ptr(body[i]),j); } clrtoeol(); } } move(LINES-idl_n+scl,scc); refresh(); return(AIO_BLOCK_LOOP); } static void handle_winch(int sig __attribute__((__unused__))) { winched = 1; } static void catch_winch(void) { struct sigaction sa; sa.sa_handler = &handle_winch; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGWINCH,&sa,0); winched = 1; } static void setup_body(void) { int i; body = malloc(MAXBODY*sizeof(ES *)); for (i=MAXBODY-1;i>=0;i--) body[i] = 0; } void ui_main(WORKER *w) { ilbuf = 0; ilba = 0; ilbl = 0; icurs = 0; iesc = 0; es_init(&fold); idl_v = 0; idl_a = 0; idl_n = 0; fcols = -1; lastilines = -1; setup_body(); worker_common_startup(w,&ui_cmd); aio_add_poll(0,&aio_rwtest_always,&aio_rwtest_never,&ui_rd_stdin,0,w); aio_add_block(&ui_redraw,w); catch_winch(); initscr(); raw(); noecho(); redraw = REDRAW__ALL; aio_event_loop(); }