diff options
Diffstat (limited to '')
-rw-r--r-- | util/alevt/ui.c | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/util/alevt/ui.c b/util/alevt/ui.c new file mode 100644 index 0000000..70391c7 --- /dev/null +++ b/util/alevt/ui.c @@ -0,0 +1,721 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdarg.h> +#include "vt.h" +#include "misc.h" +#include "xio.h" +#include "vbi.h" +#include "fdset.h" +#include "search.h" +#include "export.h" +#include "ui.h" + +static void vtwin_event(struct vtwin *w, struct vt_event *ev); +static void msg(struct vtwin *w, u8 *str, ...); +static void err(struct vtwin *w, u8 *str, ...); + +#define hist(w,o) ((w)->hist + (((w)->hist_top + (o)) & (N_HISTORY-1))) + + +static int inc_hex(int i, int bcd_mode) +{ + i++; + if (bcd_mode) + { + if ((i & 0x000f) > 0x0009) + i = (i + 0x0010) & 0x0ff0; + if ((i & 0x00f0) > 0x090) + i = (i + 0x0100) & 0x0f00; + if ((i & 0x0f00) > 0x0900) + i = (i + 0x1000) & 0xf000; + } + return i; +} + + +static int dec_hex(int i, int bcd_mode) +{ + i--; + if (bcd_mode) + { + if ((i & 0x000f) > 0x0009) + i = (i & 0xfff0) + 0x0009; + if ((i & 0x00f0) > 0x0090) + i = (i & 0xff00) + 0x0099; + if ((i & 0x0f00) > 0x0900) + i = (i & 0xf000) + 0x0999; + } + return i; +} + + +static void set_title(struct vtwin *w) +{ + char buf[32], buf2[32]; + + if (w->subno == ANY_SUB) + sprintf(buf, "%x", w->pgno); + else + sprintf(buf, "%x/%x", w->pgno, w->subno); + if (w->searching) + sprintf(buf2, "(%s)", buf); + else + sprintf(buf2, "%s", buf); + xio_title(w->xw, buf2); +} + + +static void query_page(struct vtwin *w, int pgno, int subno) +{ + w->pgno = pgno; + w->subno = subno; + w->searching = 1; + w->hold = 0; //subno != ANY_SUB; + xio_set_concealed(w->xw, w->revealed = 0); + + if (hist(w, 0)->pgno != pgno || + (hist(w,0)->subno == ANY_SUB && subno != ANY_SUB)) + w->hist_top++; + hist(w, 0)->pgno = pgno; + hist(w, 0)->subno = subno; + hist(w, 1)->pgno = 0; // end marker + + xio_cancel_selection(w->xw); + if (vbi_query_page(w->vbi, pgno, subno) == 0) + { + w->vtp = 0; + } + set_title(w); +} + + +static void new_or_query(struct vtwin *w, int pgno, int subno, int new_win) +{ + if (new_win) + { + if (w->child) + query_page(w->child, pgno, subno); + else + vtwin_new(w->xw->xio, w->vbi, 0, w, pgno, subno); + } + else + query_page(w, pgno, subno); +} + +static int _next_pgno(int *arg, struct vt_page *vtp) +{ + int pgno = vtp->pgno; + + if (arg[0] == pgno) // want different page + return 0; + if (arg[1]) // and not a hex page + for (; pgno; pgno >>=4) + if ((pgno & 15) > 9) + return 0; + return 1; +} + + +static int _next_subno(int *arg, struct vt_page *vtp) +{ + return vtp->pgno == arg[0]; // only subpages of this page +} + + +static void do_next_pgno(struct vtwin *w, int dir, int bcd_mode, int subs, + int new_win) +{ + struct vt_page *vtp; + struct vtwin *cw = (new_win && w->child) ? w->child : w; + int pgno = cw->pgno; + int subno = cw->subno; + + if (w->vbi->cache) + { + int arg[2]; + arg[0] = pgno; + arg[1] = bcd_mode; + if (vtp = w->vbi->cache->op->foreach_pg(w->vbi->cache, + pgno, subno, dir, subs ? _next_subno:_next_pgno, &arg)) + { + new_or_query(w, vtp->pgno, subs ? vtp->subno : ANY_SUB, new_win); + return; + } + } + err(w, "No page."); +} + +#define notdigit(x) (not isdigit((x))) + + +static int chk_screen_fromto(u8 *p, int x, int *n1, int *n2) +{ + p += x; + + if (x >= 0 && x+5 < 42) + if (notdigit(p[1]) || notdigit(p[0])) + if (isdigit(p[2])) + if (p[3] == '/' || p[3] == ':') + if (isdigit(p[4])) + if (notdigit(p[5]) || notdigit(p[6])) /* p[6] is save here */ + { + *n1 = p[2] % 16; + if (isdigit(p[1])) + *n1 += p[1] % 16 * 16; + *n2 = p[4] % 16; + if (isdigit(p[5])) + *n2 = *n2 * 16 + p[5] % 16; + return 1; + } + return 0; +} + + +static int chk_screen_pgno(u8 *p, int x, int *pgno, int *subno) +{ + p += x; + + if (x >= 0 && x+4 < 42) + if (notdigit(p[0]) && notdigit(p[4])) + if (isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3])) + { + *pgno = p[1] % 16 * 256 + p[2] % 16 * 16 + p[3] % 16; + if (*pgno >= 0x100 && *pgno <= 0x999) + { + *subno = ANY_SUB; + if (x+6 < 42) + if (p[4] == '.' || p[4] == '/') + if (isdigit(p[5])) + if (notdigit(p[6]) || notdigit(p[7])) /* p[7] is save here */ + { + *subno = p[5] % 16; + if (isdigit(p[6])) + *subno = *subno * 16 + p[6] % 16; + } + // hackhackhack: + // pgno followed by start box gets subno 1 + if (x+4 < 42 && p[4] == 11) + *subno = 1; + return 1; + } + } + return 0; +} + + +static void do_screen_pgno(struct vtwin *w, int x, int y, int new_win) +{ + u8 buf[42]; + int n1, n2, i; + + if (x >= 0 && x < 40) + { + if (xio_get_line(w->xw, y, buf+1) == 0) + { + buf[0] = buf[41] = ' '; + x++; + + for (i = -6; i < 35; i++) + { + if (w->vtp == 0 || w->vtp->subno != 0) + if (chk_screen_fromto(buf, x+i, &n1, &n2)) + { + // subno cycling works wrong with children. + // so middle button cycles backwards... + if (w->subno != ANY_SUB) + n1 = w->subno; + n1 = new_win ? dec_hex(n1, 1) : inc_hex(n1, 1); + if (n1 < 1) + n1 = n2; + if (n1 > n2) + n1 = 1; + new_or_query(w, w->pgno, n1, 0); + return; + } + if (i >= -4) + if (chk_screen_pgno(buf, x+i, &n1, &n2)) + { + new_or_query(w, n1, n2, new_win); + return; + } + } + } + } + err(w, "No page."); +} + + +static void do_flof_pgno(struct vtwin *w, int button, int x, int new_win) +{ + struct vt_page *vtp = w->vtp; + int lk = 99, i, c; + + if (vtp && vtp->flof) + { + switch (button) + { + case 1 ... 3: + for (i = 0; i <= x && i < 40; ++i) + if ((c = vtp->data[24][i]) < 8) // fg-color code + lk = c; + lk = "x\0\1\2\3x\3x"[lk]; // color -> link# + break; + case KEY_F(1): lk = 0; break; + case KEY_F(2): lk = 1; break; + case KEY_F(3): lk = 2; break; + case KEY_F(4): lk = 3; break; + case KEY_F(5): lk = 5; break; + } + if (lk < 6 && (vtp->link[lk].pgno & 0xff) != 0xff) + { + new_or_query(w, vtp->link[lk].pgno, vtp->link[lk].subno, new_win); + return; + } + } + else + { + switch (button) + { + case 1 ... 3: lk = x / 8; break; + case KEY_F(1): lk = 0; break; + case KEY_F(2): lk = 1; break; + case KEY_F(3): lk = 2; break; + case KEY_F(4): lk = 3; break; + case KEY_F(5): lk = 4; break; + } + switch (lk) + { + case 0: new_or_query(w, 0x100, ANY_SUB, new_win); return; + case 1: do_next_pgno(w, -1, 1, 0, new_win); return; + case 2: new_or_query(w, 0x900, ANY_SUB, new_win); return; + case 3: do_next_pgno(w, 1, 1, 0, new_win); return; + case 4: new_or_query(w, 0x999, ANY_SUB, new_win); return; + } + } + err(w, "No page."); +} + + +static void do_hist_pgno(struct vtwin *w) +{ + if (hist(w, -1)->pgno) + { + w->hist_top--; + query_page(w, hist(w, 0)->pgno, hist(w, 0)->subno); + } + else + err(w, "Empty history."); +} + + +static void put_head_line(struct vtwin *w, u8 *p) +{ + char buf[40]; + + if (p == 0) + xio_get_line(w->xw, 0, buf); + else + memcpy(buf + 8, p + 8, 32); + + if (w->subno == ANY_SUB) + sprintf(buf, "\2%3x \5\xb7", w->pgno); + else + sprintf(buf, "\2S%02x \5\xb7", w->subno & 0xff); + + if (w->searching) + buf[0] = 1; + if (w->hold) + buf[4] = 'H'; + if (w->xw->concealed) + buf[6] = '*'; + buf[7] = 7; + + xio_put_line(w->xw, 0, buf); +} + + +static void put_menu_line(struct vtwin *w) +{ + if (w->status > 0) + xio_put_line(w->xw, 24, w->statusline); + else if (w->vtp && w->vtp->flof) + xio_put_line(w->xw, 24, w->vtp->data[24]); + else + xio_put_line(w->xw, 24, "\0 100 \4<< \6Help \4>>\0 999 "); +} + + +static void _msg(struct vtwin *w, u8 *str, va_list args) +{ + u8 buf[128]; + int i; + + i = vsprintf(buf, str, args); + if (i > W) + i = W; + memset(w->statusline, ' ', W); + memcpy(w->statusline + (W-i+1)/2, buf, i); + w->status = 6; + put_menu_line(w); +} + + +static void msg(struct vtwin *w, u8 *str, ...) +{ + va_list args; + + va_start(args, str); + _msg(w, str, args); + va_end(args); +} + + +static void err(struct vtwin *w, u8 *str, ...) +{ + va_list args; + + va_start(args, str); + _msg(w, str, args); + va_end(args); +} + + +static void next_search(struct vtwin *w, int rev) +{ + if (w->search) + { + int pgno = w->pgno; + int subno = w->subno; + int dir = rev ? -w->searchdir : w->searchdir; + + if (search_next(w->search, &pgno, &subno, dir) == 0) + { + query_page(w, pgno, subno); + if (not w->searching && w->search->len) + xio_set_selection(w->xw, w->search->x, w->search->y, + w->search->x + w->search->len - 1, w->search->y); + return; + } + else + err(w, "Pattern not found."); + } + else + err(w, "No search pattern."); +} + + +static void start_search(struct vtwin *w, u8 *string) +{ + if (not string) + return; + + if (*string) + { + if (w->search) + search_end(w->search); + w->search = search_start(w->vbi->cache, string); + if (w->search == 0) + { + err(w, "Bad search pattern."); + return; + } + } + next_search(w, 0); +} + + +static void start_save2(struct vtwin *w, u8 *name) +{ + if (name && *name) + if (export(w->export, w->vtp, name)) + err(w, export_errstr()); + + export_close(w->export); + w->export = 0; + put_menu_line(w); +} + + +struct vtwin * vtwin_new(struct xio *xio, struct vbi *vbi, char *geom, + struct vtwin *parent, int pgno, int subno) +{ + struct vtwin *w; + + if (not(w = malloc(sizeof(*w)))) + goto fail1; + + if (not (w->xw = xio_open_win(xio, geom))) + goto fail2; + w->vbi = vbi; + w->vtp = 0; + w->search = 0; + w->export = 0; + w->parent = parent; + w->child = 0; + if (parent && parent->child) + fatal("internal error: parent already has a child != 0"); + if (parent) + parent->child = w; + + w->hist_top = 1; + hist(w,0)->pgno = 0; + hist(w,1)->pgno = 0; + w->status = 0; + xio_set_handler(w->xw, vtwin_event, w); + vbi_add_handler(w->vbi, vtwin_event, w); + query_page(w, pgno, subno); + return w; + +fail2: + free(w); +fail1: + return 0; +} + + +static void vtwin_close(struct vtwin *w) +{ + if (w->parent) + w->parent->child = w->child; + if (w->child) + w->child->parent = w->parent; + + if (w->search) + search_end(w->search); + if (w->export) + export_close(w->export); + + vbi_del_handler(w->vbi, vtwin_event, w); + xio_close_win(w->xw, 1); + free(w); +} + + +static void vtwin_event(struct vtwin *w, struct vt_event *ev) +{ + struct xio_win *xw = w->xw; + int i; + + switch (ev->type) + { + case EV_CLOSE: + vtwin_close(w); + break; + + case EV_TIMER: + if (w->status > 0 && --w->status == 0) + put_menu_line(w); + break; + + case EV_KEY: + { + switch (ev->i1) + { + case '0' ... '9': + i = ev->i1 - '0'; + if (w->pgno >= 0x100) + { + if (i == 0) + break; + w->pgno = i; + } + else + { + w->pgno = w->pgno * 16 + i; + if (w->pgno >= 0x100) + query_page(w, w->pgno, ANY_SUB); + } + break; + case 'q': + case '\e': + vtwin_close(w); + break; + case 'h': + query_page(w, 0x900, ANY_SUB); + break; + case 'e': + if (w->vbi->cache) + { + i = w->vbi->cache->op->mode(w->vbi->cache, + CACHE_MODE_ERC, 0); + w->vbi->cache->op->mode(w->vbi->cache, + CACHE_MODE_ERC, !i); + msg(w, "Error reduction %sabled.", i ? "dis" : "en"); + } + break; + case 'o': + if (vtwin_new(xw->xio, w->vbi, 0, 0, w->pgno, w->subno) == 0) + err(w, "Unable to open new window."); + break; + case KEY_RIGHT: + do_next_pgno(w, 1, not ev->i2, 0, 0); + break; + case KEY_LEFT: + do_next_pgno(w, -1, not ev->i2, 0, 0); + break; + case KEY_UP: + do_next_pgno(w, -1, not ev->i2, 1, 0); + break; + case KEY_DOWN: + do_next_pgno(w, 1, not ev->i2, 1, 0); + break; + case '\b': + do_hist_pgno(w); + break; + case ' ': + w->hold = !w->hold; + break; + case 'c': + vbi_reset(w->vbi); + break; + case 'i': + if (w->vtp && w->vtp->flof && + (w->vtp->link[5].pgno & 0xff) != 0xff) + query_page(w, w->vtp->link[5].pgno, + w->vtp->link[5].subno); + else + query_page(w, 0x100, ANY_SUB); + break; + case 'r': + xio_set_concealed(xw, w->revealed = !w->revealed); + break; + case KEY_F(1) ... KEY_F(5): + do_flof_pgno(w, ev->i1, 0, ev->i2); + break; + case 'n': + next_search(w, 0); + break; + case 'N': + next_search(w, 1); + break; + default: + err(w, "Unused key."); + break; + } + break; + } + case EV_RESET: + { + if (w->search) + search_end(w->search); + w->search = 0; + + query_page(w, w->pgno, w->subno); + msg(w, "Cache cleared!"); + break; + } + case EV_MOUSE: + { + if (ev->i1 == 3) + do_hist_pgno(w); + else if (ev->i1 == 5) // wheel mouse + do_next_pgno(w, 1, not ev->i2, 0, 0); + else if (ev->i1 == 4) // wheel mouse + do_next_pgno(w, -1, not ev->i2, 0, 0); + else if (ev->i1 == 7) // dual wheel mouse + do_next_pgno(w, 1, not ev->i2, 1, 0); + else if (ev->i1 == 6) // dual wheel mouse + do_next_pgno(w, -1, not ev->i2, 1, 0); + else if (ev->i4 == 24) + do_flof_pgno(w, ev->i1, ev->i3, ev->i1 == 2); + else if (ev->i4 == 0 && ev->i3 < 5) + { + if (ev->i1 == 1) + w->hold = !w->hold; + else + vtwin_new(xw->xio, w->vbi, 0, 0, w->pgno, w->subno); + } + else if (ev->i4 == 0 && ev->i3 < 8) + { + if (ev->i1 == 2 && w->child) + w = w->child; + xio_set_concealed(w->xw, w->revealed = !w->revealed); + } + else + do_screen_pgno(w, ev->i3, ev->i4, ev->i1 == 2); + break; + } + case EV_PAGE: + { + struct vt_page *vtp = ev->p1; + + if (0) + if (vtp->errors) + printf("errors=%4d\n",vtp->errors); + if (w->searching || not(w->hold || ev->i1)) + if (vtp->pgno == w->pgno) + if (w->subno == ANY_SUB || vtp->subno == w->subno) + { + w->searching = 0; + w->vtp = vtp; + put_head_line(w, vtp->data[0]); + for (i = 1; i < 24; ++i) + xio_put_line(w->xw, i, vtp->data[i]); + put_menu_line(w); + set_title(w); + } + break; + } + case EV_HEADER: + { + u8 *p = ev->p1; + int hdr_mag = ev->i1 / 256; + int flags = ev->i3; + int mag = w->pgno; + if (mag >= 0x10) + mag = mag >> 4; + if (mag >= 0x10) + mag = mag >> 4; + if (flags & PG_OUTOFSEQ) + p = 0; + else + if (~flags & PG_MAGSERIAL) + if (mag != hdr_mag) + p = 0; + + put_head_line(w, p); + break; + } + case EV_XPACKET: + { +#if 0 /* VPS data (seems to be unused in .de */ + u8 *p = ev->p1; + + if (ev->i1 == 8 && ev->i2 == 30 && p[0]/2 == 1) + { + int i; + int pil, cni, pty, misc; + + for (i = 7; i < 20; ++i) + p[i] = hamm8(p+i, &ev->i3); + if (ev->i3 & 0xf000) /* uncorrectable errors */ + break; + cni = p[9] + p[15]/4*16 + p[16]%4*64 + p[10]%4*256 + + p[16]/4*1024 + p[17]*4096; + pty = p[18] + p[19]*16; + pil = p[10]/4 + p[11]*4 + p[12]*64 + p[13]*1024 + + p[14]*16384 + p[15]%4*262144; + misc = p[7] + p[8]*16; + err(w, "%02x %04x %05x %02x: %.20s", misc, cni, pil, pty, p+20); + } +#endif + break; + } + case EV_ERR: + { + char *errmsg = ev->p1; + if (errmsg != NULL && *errmsg != '\0') + { + err(w, errmsg); + w->status = 30; + ev->p1 = NULL; + free(errmsg); + } + break; + } + } +} |