ui.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. #include <ctype.h>
  7. #include <stdarg.h>
  8. #include "vt.h"
  9. #include "misc.h"
  10. #include "xio.h"
  11. #include "vbi.h"
  12. #include "fdset.h"
  13. #include "search.h"
  14. #include "export.h"
  15. #include "ui.h"
  16. static void vtwin_event(struct vtwin *w, struct vt_event *ev);
  17. static void msg(struct vtwin *w, u8 *str, ...);
  18. static void err(struct vtwin *w, u8 *str, ...);
  19. #define hist(w,o) ((w)->hist + (((w)->hist_top + (o)) & (N_HISTORY-1)))
  20. static int inc_hex(int i, int bcd_mode)
  21. {
  22. i++;
  23. if (bcd_mode)
  24. {
  25. if ((i & 0x000f) > 0x0009)
  26. i = (i + 0x0010) & 0x0ff0;
  27. if ((i & 0x00f0) > 0x090)
  28. i = (i + 0x0100) & 0x0f00;
  29. if ((i & 0x0f00) > 0x0900)
  30. i = (i + 0x1000) & 0xf000;
  31. }
  32. return i;
  33. }
  34. static int dec_hex(int i, int bcd_mode)
  35. {
  36. i--;
  37. if (bcd_mode)
  38. {
  39. if ((i & 0x000f) > 0x0009)
  40. i = (i & 0xfff0) + 0x0009;
  41. if ((i & 0x00f0) > 0x0090)
  42. i = (i & 0xff00) + 0x0099;
  43. if ((i & 0x0f00) > 0x0900)
  44. i = (i & 0xf000) + 0x0999;
  45. }
  46. return i;
  47. }
  48. static void set_title(struct vtwin *w)
  49. {
  50. char buf[32], buf2[32];
  51. if (w->subno == ANY_SUB)
  52. sprintf(buf, "%x", w->pgno);
  53. else
  54. sprintf(buf, "%x/%x", w->pgno, w->subno);
  55. if (w->searching)
  56. sprintf(buf2, "(%s)", buf);
  57. else
  58. sprintf(buf2, "%s", buf);
  59. xio_title(w->xw, buf2);
  60. }
  61. static void query_page(struct vtwin *w, int pgno, int subno)
  62. {
  63. w->pgno = pgno;
  64. w->subno = subno;
  65. w->searching = 1;
  66. w->hold = 0; //subno != ANY_SUB;
  67. xio_set_concealed(w->xw, w->revealed = 0);
  68. if (hist(w, 0)->pgno != pgno ||
  69. (hist(w,0)->subno == ANY_SUB && subno != ANY_SUB))
  70. w->hist_top++;
  71. hist(w, 0)->pgno = pgno;
  72. hist(w, 0)->subno = subno;
  73. hist(w, 1)->pgno = 0; // end marker
  74. xio_cancel_selection(w->xw);
  75. if (vbi_query_page(w->vbi, pgno, subno) == 0)
  76. {
  77. w->vtp = 0;
  78. }
  79. set_title(w);
  80. }
  81. static void new_or_query(struct vtwin *w, int pgno, int subno, int new_win)
  82. {
  83. if (new_win)
  84. {
  85. if (w->child)
  86. query_page(w->child, pgno, subno);
  87. else
  88. vtwin_new(w->xw->xio, w->vbi, 0, w, pgno, subno);
  89. }
  90. else
  91. query_page(w, pgno, subno);
  92. }
  93. static int _next_pgno(int *arg, struct vt_page *vtp)
  94. {
  95. int pgno = vtp->pgno;
  96. if (arg[0] == pgno) // want different page
  97. return 0;
  98. if (arg[1]) // and not a hex page
  99. for (; pgno; pgno >>=4)
  100. if ((pgno & 15) > 9)
  101. return 0;
  102. return 1;
  103. }
  104. static int _next_subno(int *arg, struct vt_page *vtp)
  105. {
  106. return vtp->pgno == arg[0]; // only subpages of this page
  107. }
  108. static void do_next_pgno(struct vtwin *w, int dir, int bcd_mode, int subs,
  109. int new_win)
  110. {
  111. struct vt_page *vtp;
  112. struct vtwin *cw = (new_win && w->child) ? w->child : w;
  113. int pgno = cw->pgno;
  114. int subno = cw->subno;
  115. if (w->vbi->cache)
  116. {
  117. int arg[2];
  118. arg[0] = pgno;
  119. arg[1] = bcd_mode;
  120. if (vtp = w->vbi->cache->op->foreach_pg(w->vbi->cache,
  121. pgno, subno, dir, subs ? _next_subno:_next_pgno, &arg))
  122. {
  123. new_or_query(w, vtp->pgno, subs ? vtp->subno : ANY_SUB, new_win);
  124. return;
  125. }
  126. }
  127. err(w, "No page.");
  128. }
  129. #define notdigit(x) (not isdigit((x)))
  130. static int chk_screen_fromto(u8 *p, int x, int *n1, int *n2)
  131. {
  132. p += x;
  133. if (x >= 0 && x+5 < 42)
  134. if (notdigit(p[1]) || notdigit(p[0]))
  135. if (isdigit(p[2]))
  136. if (p[3] == '/' || p[3] == ':')
  137. if (isdigit(p[4]))
  138. if (notdigit(p[5]) || notdigit(p[6])) /* p[6] is save here */
  139. {
  140. *n1 = p[2] % 16;
  141. if (isdigit(p[1]))
  142. *n1 += p[1] % 16 * 16;
  143. *n2 = p[4] % 16;
  144. if (isdigit(p[5]))
  145. *n2 = *n2 * 16 + p[5] % 16;
  146. return 1;
  147. }
  148. return 0;
  149. }
  150. static int chk_screen_pgno(u8 *p, int x, int *pgno, int *subno)
  151. {
  152. p += x;
  153. if (x >= 0 && x+4 < 42)
  154. if (notdigit(p[0]) && notdigit(p[4]))
  155. if (isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]))
  156. {
  157. *pgno = p[1] % 16 * 256 + p[2] % 16 * 16 + p[3] % 16;
  158. if (*pgno >= 0x100 && *pgno <= 0x999)
  159. {
  160. *subno = ANY_SUB;
  161. if (x+6 < 42)
  162. if (p[4] == '.' || p[4] == '/')
  163. if (isdigit(p[5]))
  164. if (notdigit(p[6]) || notdigit(p[7])) /* p[7] is save here */
  165. {
  166. *subno = p[5] % 16;
  167. if (isdigit(p[6]))
  168. *subno = *subno * 16 + p[6] % 16;
  169. }
  170. // hackhackhack:
  171. // pgno followed by start box gets subno 1
  172. if (x+4 < 42 && p[4] == 11)
  173. *subno = 1;
  174. return 1;
  175. }
  176. }
  177. return 0;
  178. }
  179. static void do_screen_pgno(struct vtwin *w, int x, int y, int new_win)
  180. {
  181. u8 buf[42];
  182. int n1, n2, i;
  183. if (x >= 0 && x < 40)
  184. {
  185. if (xio_get_line(w->xw, y, buf+1) == 0)
  186. {
  187. buf[0] = buf[41] = ' ';
  188. x++;
  189. for (i = -6; i < 35; i++)
  190. {
  191. if (w->vtp == 0 || w->vtp->subno != 0)
  192. if (chk_screen_fromto(buf, x+i, &n1, &n2))
  193. {
  194. // subno cycling works wrong with children.
  195. // so middle button cycles backwards...
  196. if (w->subno != ANY_SUB)
  197. n1 = w->subno;
  198. n1 = new_win ? dec_hex(n1, 1) : inc_hex(n1, 1);
  199. if (n1 < 1)
  200. n1 = n2;
  201. if (n1 > n2)
  202. n1 = 1;
  203. new_or_query(w, w->pgno, n1, 0);
  204. return;
  205. }
  206. if (i >= -4)
  207. if (chk_screen_pgno(buf, x+i, &n1, &n2))
  208. {
  209. new_or_query(w, n1, n2, new_win);
  210. return;
  211. }
  212. }
  213. }
  214. }
  215. err(w, "No page.");
  216. }
  217. static void do_flof_pgno(struct vtwin *w, int button, int x, int new_win)
  218. {
  219. struct vt_page *vtp = w->vtp;
  220. int lk = 99, i, c;
  221. if (vtp && vtp->flof)
  222. {
  223. switch (button)
  224. {
  225. case 1 ... 3:
  226. for (i = 0; i <= x && i < 40; ++i)
  227. if ((c = vtp->data[24][i]) < 8) // fg-color code
  228. lk = c;
  229. lk = "x\0\1\2\3x\3x"[lk]; // color -> link#
  230. break;
  231. case KEY_F(1): lk = 0; break;
  232. case KEY_F(2): lk = 1; break;
  233. case KEY_F(3): lk = 2; break;
  234. case KEY_F(4): lk = 3; break;
  235. case KEY_F(5): lk = 5; break;
  236. }
  237. if (lk < 6 && (vtp->link[lk].pgno & 0xff) != 0xff)
  238. {
  239. new_or_query(w, vtp->link[lk].pgno, vtp->link[lk].subno, new_win);
  240. return;
  241. }
  242. }
  243. else
  244. {
  245. switch (button)
  246. {
  247. case 1 ... 3: lk = x / 8; break;
  248. case KEY_F(1): lk = 0; break;
  249. case KEY_F(2): lk = 1; break;
  250. case KEY_F(3): lk = 2; break;
  251. case KEY_F(4): lk = 3; break;
  252. case KEY_F(5): lk = 4; break;
  253. }
  254. switch (lk)
  255. {
  256. case 0: new_or_query(w, 0x100, ANY_SUB, new_win); return;
  257. case 1: do_next_pgno(w, -1, 1, 0, new_win); return;
  258. case 2: new_or_query(w, 0x900, ANY_SUB, new_win); return;
  259. case 3: do_next_pgno(w, 1, 1, 0, new_win); return;
  260. case 4: new_or_query(w, 0x999, ANY_SUB, new_win); return;
  261. }
  262. }
  263. err(w, "No page.");
  264. }
  265. static void do_hist_pgno(struct vtwin *w)
  266. {
  267. if (hist(w, -1)->pgno)
  268. {
  269. w->hist_top--;
  270. query_page(w, hist(w, 0)->pgno, hist(w, 0)->subno);
  271. }
  272. else
  273. err(w, "Empty history.");
  274. }
  275. static void put_head_line(struct vtwin *w, u8 *p)
  276. {
  277. char buf[40];
  278. if (p == 0)
  279. xio_get_line(w->xw, 0, buf);
  280. else
  281. memcpy(buf + 8, p + 8, 32);
  282. if (w->subno == ANY_SUB)
  283. sprintf(buf, "\2%3x \5\xb7", w->pgno);
  284. else
  285. sprintf(buf, "\2S%02x \5\xb7", w->subno & 0xff);
  286. if (w->searching)
  287. buf[0] = 1;
  288. if (w->hold)
  289. buf[4] = 'H';
  290. if (w->xw->concealed)
  291. buf[6] = '*';
  292. buf[7] = 7;
  293. xio_put_line(w->xw, 0, buf);
  294. }
  295. static void put_menu_line(struct vtwin *w)
  296. {
  297. if (w->status > 0)
  298. xio_put_line(w->xw, 24, w->statusline);
  299. else if (w->vtp && w->vtp->flof)
  300. xio_put_line(w->xw, 24, w->vtp->data[24]);
  301. else
  302. xio_put_line(w->xw, 24, "\0 100 \4<< \6Help \4>>\0 999 ");
  303. }
  304. static void _msg(struct vtwin *w, u8 *str, va_list args)
  305. {
  306. u8 buf[128];
  307. int i;
  308. i = vsprintf(buf, str, args);
  309. if (i > W)
  310. i = W;
  311. memset(w->statusline, ' ', W);
  312. memcpy(w->statusline + (W-i+1)/2, buf, i);
  313. w->status = 6;
  314. put_menu_line(w);
  315. }
  316. static void msg(struct vtwin *w, u8 *str, ...)
  317. {
  318. va_list args;
  319. va_start(args, str);
  320. _msg(w, str, args);
  321. va_end(args);
  322. }
  323. static void err(struct vtwin *w, u8 *str, ...)
  324. {
  325. va_list args;
  326. va_start(args, str);
  327. _msg(w, str, args);
  328. va_end(args);
  329. }
  330. static void next_search(struct vtwin *w, int rev)
  331. {
  332. if (w->search)
  333. {
  334. int pgno = w->pgno;
  335. int subno = w->subno;
  336. int dir = rev ? -w->searchdir : w->searchdir;
  337. if (search_next(w->search, &pgno, &subno, dir) == 0)
  338. {
  339. query_page(w, pgno, subno);
  340. if (not w->searching && w->search->len)
  341. xio_set_selection(w->xw, w->search->x, w->search->y,
  342. w->search->x + w->search->len - 1, w->search->y);
  343. return;
  344. }
  345. else
  346. err(w, "Pattern not found.");
  347. }
  348. else
  349. err(w, "No search pattern.");
  350. }
  351. static void start_search(struct vtwin *w, u8 *string)
  352. {
  353. if (not string)
  354. return;
  355. if (*string)
  356. {
  357. if (w->search)
  358. search_end(w->search);
  359. w->search = search_start(w->vbi->cache, string);
  360. if (w->search == 0)
  361. {
  362. err(w, "Bad search pattern.");
  363. return;
  364. }
  365. }
  366. next_search(w, 0);
  367. }
  368. static void start_save2(struct vtwin *w, u8 *name)
  369. {
  370. if (name && *name)
  371. if (export(w->export, w->vtp, name))
  372. err(w, export_errstr());
  373. export_close(w->export);
  374. w->export = 0;
  375. put_menu_line(w);
  376. }
  377. struct vtwin * vtwin_new(struct xio *xio, struct vbi *vbi, char *geom,
  378. struct vtwin *parent, int pgno, int subno)
  379. {
  380. struct vtwin *w;
  381. if (not(w = malloc(sizeof(*w))))
  382. goto fail1;
  383. if (not (w->xw = xio_open_win(xio, geom)))
  384. goto fail2;
  385. w->vbi = vbi;
  386. w->vtp = 0;
  387. w->search = 0;
  388. w->export = 0;
  389. w->parent = parent;
  390. w->child = 0;
  391. if (parent && parent->child)
  392. fatal("internal error: parent already has a child != 0");
  393. if (parent)
  394. parent->child = w;
  395. w->hist_top = 1;
  396. hist(w,0)->pgno = 0;
  397. hist(w,1)->pgno = 0;
  398. w->status = 0;
  399. xio_set_handler(w->xw, vtwin_event, w);
  400. vbi_add_handler(w->vbi, vtwin_event, w);
  401. query_page(w, pgno, subno);
  402. return w;
  403. fail2:
  404. free(w);
  405. fail1:
  406. return 0;
  407. }
  408. static void vtwin_close(struct vtwin *w)
  409. {
  410. if (w->parent)
  411. w->parent->child = w->child;
  412. if (w->child)
  413. w->child->parent = w->parent;
  414. if (w->search)
  415. search_end(w->search);
  416. if (w->export)
  417. export_close(w->export);
  418. vbi_del_handler(w->vbi, vtwin_event, w);
  419. xio_close_win(w->xw, 1);
  420. free(w);
  421. }
  422. static void vtwin_event(struct vtwin *w, struct vt_event *ev)
  423. {
  424. struct xio_win *xw = w->xw;
  425. int i;
  426. switch (ev->type)
  427. {
  428. case EV_CLOSE:
  429. vtwin_close(w);
  430. break;
  431. case EV_TIMER:
  432. if (w->status > 0 && --w->status == 0)
  433. put_menu_line(w);
  434. break;
  435. case EV_KEY:
  436. {
  437. switch (ev->i1)
  438. {
  439. case '0' ... '9':
  440. i = ev->i1 - '0';
  441. if (w->pgno >= 0x100)
  442. {
  443. if (i == 0)
  444. break;
  445. w->pgno = i;
  446. }
  447. else
  448. {
  449. w->pgno = w->pgno * 16 + i;
  450. if (w->pgno >= 0x100)
  451. query_page(w, w->pgno, ANY_SUB);
  452. }
  453. break;
  454. case 'q':
  455. case '\e':
  456. vtwin_close(w);
  457. break;
  458. case 'h':
  459. query_page(w, 0x900, ANY_SUB);
  460. break;
  461. case 'e':
  462. if (w->vbi->cache)
  463. {
  464. i = w->vbi->cache->op->mode(w->vbi->cache,
  465. CACHE_MODE_ERC, 0);
  466. w->vbi->cache->op->mode(w->vbi->cache,
  467. CACHE_MODE_ERC, !i);
  468. msg(w, "Error reduction %sabled.", i ? "dis" : "en");
  469. }
  470. break;
  471. case 'o':
  472. if (vtwin_new(xw->xio, w->vbi, 0, 0, w->pgno, w->subno) == 0)
  473. err(w, "Unable to open new window.");
  474. break;
  475. case KEY_RIGHT:
  476. do_next_pgno(w, 1, not ev->i2, 0, 0);
  477. break;
  478. case KEY_LEFT:
  479. do_next_pgno(w, -1, not ev->i2, 0, 0);
  480. break;
  481. case KEY_UP:
  482. do_next_pgno(w, -1, not ev->i2, 1, 0);
  483. break;
  484. case KEY_DOWN:
  485. do_next_pgno(w, 1, not ev->i2, 1, 0);
  486. break;
  487. case '\b':
  488. do_hist_pgno(w);
  489. break;
  490. case ' ':
  491. w->hold = !w->hold;
  492. break;
  493. case 'c':
  494. vbi_reset(w->vbi);
  495. break;
  496. case 'i':
  497. if (w->vtp && w->vtp->flof &&
  498. (w->vtp->link[5].pgno & 0xff) != 0xff)
  499. query_page(w, w->vtp->link[5].pgno,
  500. w->vtp->link[5].subno);
  501. else
  502. query_page(w, 0x100, ANY_SUB);
  503. break;
  504. case 'r':
  505. xio_set_concealed(xw, w->revealed = !w->revealed);
  506. break;
  507. case KEY_F(1) ... KEY_F(5):
  508. do_flof_pgno(w, ev->i1, 0, ev->i2);
  509. break;
  510. case 'n':
  511. next_search(w, 0);
  512. break;
  513. case 'N':
  514. next_search(w, 1);
  515. break;
  516. default:
  517. err(w, "Unused key.");
  518. break;
  519. }
  520. break;
  521. }
  522. case EV_RESET:
  523. {
  524. if (w->search)
  525. search_end(w->search);
  526. w->search = 0;
  527. query_page(w, w->pgno, w->subno);
  528. msg(w, "Cache cleared!");
  529. break;
  530. }
  531. case EV_MOUSE:
  532. {
  533. if (ev->i1 == 3)
  534. do_hist_pgno(w);
  535. else if (ev->i1 == 5) // wheel mouse
  536. do_next_pgno(w, 1, not ev->i2, 0, 0);
  537. else if (ev->i1 == 4) // wheel mouse
  538. do_next_pgno(w, -1, not ev->i2, 0, 0);
  539. else if (ev->i1 == 7) // dual wheel mouse
  540. do_next_pgno(w, 1, not ev->i2, 1, 0);
  541. else if (ev->i1 == 6) // dual wheel mouse
  542. do_next_pgno(w, -1, not ev->i2, 1, 0);
  543. else if (ev->i4 == 24)
  544. do_flof_pgno(w, ev->i1, ev->i3, ev->i1 == 2);
  545. else if (ev->i4 == 0 && ev->i3 < 5)
  546. {
  547. if (ev->i1 == 1)
  548. w->hold = !w->hold;
  549. else
  550. vtwin_new(xw->xio, w->vbi, 0, 0, w->pgno, w->subno);
  551. }
  552. else if (ev->i4 == 0 && ev->i3 < 8)
  553. {
  554. if (ev->i1 == 2 && w->child)
  555. w = w->child;
  556. xio_set_concealed(w->xw, w->revealed = !w->revealed);
  557. }
  558. else
  559. do_screen_pgno(w, ev->i3, ev->i4, ev->i1 == 2);
  560. break;
  561. }
  562. case EV_PAGE:
  563. {
  564. struct vt_page *vtp = ev->p1;
  565. if (0)
  566. if (vtp->errors)
  567. printf("errors=%4d\n",vtp->errors);
  568. if (w->searching || not(w->hold || ev->i1))
  569. if (vtp->pgno == w->pgno)
  570. if (w->subno == ANY_SUB || vtp->subno == w->subno)
  571. {
  572. w->searching = 0;
  573. w->vtp = vtp;
  574. put_head_line(w, vtp->data[0]);
  575. for (i = 1; i < 24; ++i)
  576. xio_put_line(w->xw, i, vtp->data[i]);
  577. put_menu_line(w);
  578. set_title(w);
  579. }
  580. break;
  581. }
  582. case EV_HEADER:
  583. {
  584. u8 *p = ev->p1;
  585. int hdr_mag = ev->i1 / 256;
  586. int flags = ev->i3;
  587. int mag = w->pgno;
  588. if (mag >= 0x10)
  589. mag = mag >> 4;
  590. if (mag >= 0x10)
  591. mag = mag >> 4;
  592. if (flags & PG_OUTOFSEQ)
  593. p = 0;
  594. else
  595. if (~flags & PG_MAGSERIAL)
  596. if (mag != hdr_mag)
  597. p = 0;
  598. put_head_line(w, p);
  599. break;
  600. }
  601. case EV_XPACKET:
  602. {
  603. #if 0 /* VPS data (seems to be unused in .de */
  604. u8 *p = ev->p1;
  605. if (ev->i1 == 8 && ev->i2 == 30 && p[0]/2 == 1)
  606. {
  607. int i;
  608. int pil, cni, pty, misc;
  609. for (i = 7; i < 20; ++i)
  610. p[i] = hamm8(p+i, &ev->i3);
  611. if (ev->i3 & 0xf000) /* uncorrectable errors */
  612. break;
  613. cni = p[9] + p[15]/4*16 + p[16]%4*64 + p[10]%4*256
  614. + p[16]/4*1024 + p[17]*4096;
  615. pty = p[18] + p[19]*16;
  616. pil = p[10]/4 + p[11]*4 + p[12]*64 + p[13]*1024
  617. + p[14]*16384 + p[15]%4*262144;
  618. misc = p[7] + p[8]*16;
  619. err(w, "%02x %04x %05x %02x: %.20s", misc, cni, pil, pty, p+20);
  620. }
  621. #endif
  622. break;
  623. }
  624. case EV_ERR:
  625. {
  626. char *errmsg = ev->p1;
  627. if (errmsg != NULL && *errmsg != '\0')
  628. {
  629. err(w, errmsg);
  630. w->status = 30;
  631. ev->p1 = NULL;
  632. free(errmsg);
  633. }
  634. break;
  635. }
  636. }
  637. }