19ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley/* hexedit.c - Hexadecimal file editor
29ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley *
39ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley * Copyright 2015 Rob Landley <rob@landley.net>
49ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley *
59ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley * No standard
69ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
75ea14bd1c246f7571d466d18385db22f59ac3262Rob LandleyUSE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
89ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
99ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landleyconfig HEXEDIT
109ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  bool "hexedit"
114c182c325716776a3e40394b175de479738e31a6Rob Landley  default y
129ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  help
139ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley    usage: hexedit FILENAME
149ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
15137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    Hexadecimal file editor. All changes are written to disk immediately.
16ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
17ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    -r	Read only (display but don't edit)
18137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley
19137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    Keys:
20137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    Arrows        Move left/right/up/down by one line/column
21137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    Pg Up/Pg Dn   Move up/down by one page
22137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    0-9, a-f      Change current half-byte to hexadecimal value
23137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    u             Undo
24137f5c9b0937dfa204ea2580e58430c7180a79c5Rob Landley    q/^c/^d/<esc> Quit
259ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley*/
269ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
279ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley#define FOR_hexedit
289ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley#include "toys.h"
299ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
309ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob LandleyGLOBALS(
319ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  char *data;
329ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  long long len, base;
333b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley  int numlen, undo, undolen;
349ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  unsigned height;
359ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley)
369ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
373b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley#define UNDO_LEN (sizeof(toybuf)/(sizeof(long long)+1))
3853b0cb856deafa015626f21b5a2f972cddc015bdRob Landley
39ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley// Render all characters printable, using color to distinguish.
40e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landleystatic int draw_char(FILE *fp, wchar_t broiled)
41ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley{
42e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley  if (fp) {
43e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley    if (broiled<32 || broiled>=127) {
44e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley      if (broiled>127) {
45e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley        tty_esc("2m");
46e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley        broiled &= 127;
47e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley      }
48e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley      if (broiled<32 || broiled==127) {
49e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley        tty_esc("7m");
50e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley        if (broiled==127) broiled = 32;
51e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley        else broiled += 64;
52e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley      }
53e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley      printf("%c", broiled);
54e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley      tty_esc("0m");
55e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley    } else printf("%c", broiled);
56e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley  }
57e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley
58e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley  return 1;
59ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley}
60ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
615ea14bd1c246f7571d466d18385db22f59ac3262Rob Landleystatic void draw_tail(void)
625ea14bd1c246f7571d466d18385db22f59ac3262Rob Landley{
63b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_jump(0, TT.height);
64b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_esc("K");
655ea14bd1c246f7571d466d18385db22f59ac3262Rob Landley
66ba86864699997b0da780e15fd6be33c8a556e927Rob Landley  draw_trim(*toys.optargs, -1, 71);
675ea14bd1c246f7571d466d18385db22f59ac3262Rob Landley}
685ea14bd1c246f7571d466d18385db22f59ac3262Rob Landley
699ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landleystatic void draw_line(long long yy)
709ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley{
71913a7796bb47e0b65c4f28920c39a87c6b6211ddRob Landley  int x, xx = 16;
729ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
739ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  yy = (TT.base+yy)*16;
74913a7796bb47e0b65c4f28920c39a87c6b6211ddRob Landley  if (yy+xx>=TT.len) xx = TT.len-yy;
759ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
769ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  if (yy<TT.len) {
779ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley    printf("\r%0*llX ", TT.numlen, yy);
78913a7796bb47e0b65c4f28920c39a87c6b6211ddRob Landley    for (x=0; x<xx; x++) printf(" %02X", TT.data[yy+x]);
79913a7796bb47e0b65c4f28920c39a87c6b6211ddRob Landley    printf("%*s", 2+3*(16-xx), "");
80e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley    for (x=0; x<xx; x++) draw_char(stdout, TT.data[yy+x]);
81913a7796bb47e0b65c4f28920c39a87c6b6211ddRob Landley    printf("%*s", 16-xx, "");
829ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  }
83b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_esc("K");
849ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley}
859ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
86ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landleystatic void draw_page(void)
879ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley{
889ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  int y;
899ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
90b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_jump(0, 0);
919ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  for (y = 0; y<TT.height; y++) {
929ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley    if (y) printf("\r\n");
939ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley    draw_line(y);
949ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  }
955ea14bd1c246f7571d466d18385db22f59ac3262Rob Landley  draw_tail();
969ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley}
979ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
98ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley// side: 0 = editing left, 1 = editing right, 2 = clear, 3 = read only
99ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landleystatic void highlight(int xx, int yy, int side)
100ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley{
101ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  char cc = TT.data[16*(TT.base+yy)+xx];
102ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  int i;
103ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
104ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  // Display cursor
105b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_jump(2+TT.numlen+3*xx, yy);
106b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_esc("0m");
107b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  if (side!=2) tty_esc("7m");
108ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  if (side>1) printf("%02X", cc);
109ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  else for (i=0; i<2;) {
110b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley    if (side==i) tty_esc("32m");
111ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    printf("%X", (cc>>(4*(1&++i)))&15);
112ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  }
113b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_esc("0m");
114b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_jump(TT.numlen+17*3+xx, yy);
115e32e802240c5b3803b9769948dc7a18b3fc1630cRob Landley  draw_char(stdout, cc);
116ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley}
117ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
1189ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landleyvoid hexedit_main(void)
1199ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley{
1204eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley  long long pos = 0, y;
1214eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley  int x, i, side = 0, key, ro = toys.optflags&FLAG_r,
122ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley      fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR);
1233b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley  char keybuf[16];
1249ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
125671ce0c9298091f28c92430482b18c1449dcd09eRob Landley  *keybuf = 0;
126671ce0c9298091f28c92430482b18c1449dcd09eRob Landley
127b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  // Terminal setup
1289ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  TT.height = 25;
1299ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  terminal_size(0, &TT.height);
13053b0cb856deafa015626f21b5a2f972cddc015bdRob Landley  if (TT.height) TT.height--;
131b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  sigatexit(tty_sigreset);
132b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_esc("0m");
133b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_esc("?25l");
1349ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  fflush(0);
1351b983744cde6819fe1d810e98cfac52585ceacafRob Landley  xset_terminal(1, 1, 0);
1369ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
137544c1ec1614cd9a8dcedac3478701e4b97b0f8a0Rob Landley  if ((TT.len = fdlength(fd))<1) error_exit("bad length");
1389ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX;
139b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  // count file length hex in digits, rounded up to multiple of 4
1409ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++);
1419ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  TT.numlen += (4-TT.numlen)&3;
1429ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
143ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley  TT.data = mmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0);
1449ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  draw_page();
1459ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
1469ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  for (;;) {
1474eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    // Scroll display if necessary
1484eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    if (pos<0) pos = 0;
149544c1ec1614cd9a8dcedac3478701e4b97b0f8a0Rob Landley    if (pos>=TT.len) pos = TT.len-1;
1504eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    x = pos&15;
1514eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    y = pos/16;
1524eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley
1534eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    i = 0;
1544eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    while (y<TT.base) {
1554eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley      if (TT.base-y>(TT.height/2)) {
1564eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        TT.base = y;
1574eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        draw_page();
1584eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley      } else {
1594eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        TT.base--;
1604eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        i++;
1614eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        tty_esc("1T");
1624eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        tty_jump(0, 0);
1634eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        draw_line(0);
1644eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley      }
1654eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    }
1664eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    while (y>=TT.base+TT.height) {
1674eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley      if (y-(TT.base+TT.height)>(TT.height/2)) {
1684eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        TT.base = y-TT.height-1;
1694eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        draw_page();
1704eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley      } else {
1714eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        TT.base++;
1724eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        i++;
1734eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        tty_esc("1S");
1744eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        tty_jump(0, TT.height-1);
1754eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        draw_line(TT.height-1);
1764eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley      }
1779ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley    }
1784eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    if (i) draw_tail();
1794eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    y -= TT.base;
180ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
1814eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley    // Display cursor and flush output
182ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    highlight(x, y, ro ? 3 : side);
183d3a435e53c94ec25b4ae5fa2614f49ef8884e08aRob Landley    xflush();
1849ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley
185ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    // Wait for next key
186efb309d4cdb2f4c3926b0550d9dc1661c1e4a091Rob Landley    key = scan_key(keybuf, -1);
187ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    // Exit for q, ctrl-c, ctrl-d, escape, or EOF
188ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    if (key==-1 || key==3 || key==4 || key==27 || key=='q') break;
189ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    highlight(x, y, 2);
190ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
1913b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley    // Hex digit?
192ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    if (key>='a' && key<='f') key-=32;
193ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley    if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) {
1943b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley      if (!side) {
1953b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        long long *ll = (long long *)toybuf;
1963b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley
1973b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        ll[TT.undo] = pos;
1983b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        toybuf[(sizeof(long long)*UNDO_LEN)+TT.undo++] = TT.data[pos];
1993b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        if (TT.undolen < UNDO_LEN) TT.undolen++;
2003b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        TT.undo %= UNDO_LEN;
2013b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley      }
2023b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley
203ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley      i = key - '0';
204ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley      if (i>9) i -= 7;
205ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley      TT.data[pos] &= 15<<(4*side);
206ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley      TT.data[pos] |= i<<(4*!side);
207ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley
2083b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley      if (++side==2) {
2093b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        highlight(x, y, side);
210ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley        side = 0;
2114eab65b911caf1f192d2ad6432d8b2473961be0dRob Landley        ++pos;
212ed753aaa5481e487a23c9e0e6a855c09612eb7ceRob Landley      }
2133b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley    } else side = 0;
2143b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley    if (key=='u') {
2153b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley      if (TT.undolen) {
2163b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        long long *ll = (long long *)toybuf;
2173b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley
2183b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        TT.undolen--;
2193b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        if (!TT.undo) TT.undo = UNDO_LEN;
2203b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        pos = ll[--TT.undo];
2213b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley        TT.data[pos] = toybuf[sizeof(long long)*UNDO_LEN+TT.undo];
2223b5cb96b1080d26be10675227d6a6f91acf82519Rob Landley      }
2234b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley    }
224544c1ec1614cd9a8dcedac3478701e4b97b0f8a0Rob Landley    if (key>=256) {
2254b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      key -= 256;
2264b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley
2274b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      if (key==KEY_UP) pos -= 16;
2284b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      else if (key==KEY_DOWN) pos += 16;
2294b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      else if (key==KEY_RIGHT) {
2304b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley        if (x<15) pos++;
2314b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      } else if (key==KEY_LEFT) {
2324b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley        if (x) pos--;
2334b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      } else if (key==KEY_PGUP) pos -= 16*TT.height;
2344b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      else if (key==KEY_PGDN) pos += 16*TT.height;
2354b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      else if (key==KEY_HOME) pos = 0;
2364b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley      else if (key==KEY_END) pos = TT.len-1;
2374b4ab6a50998219cd94139c5669ef9a624c8f58fRob Landley    }
2389ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  }
2399ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  munmap(TT.data, TT.len);
2409ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley  close(fd);
241b20c80b603c1795c473b3957fd2538485ec4eb90Rob Landley  tty_reset();
2429ac2d6546a2154a6797e12dfe86f36cc9420d6d4Rob Landley}
243