1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#define FOR_hexedit
28#include "toys.h"
29
30GLOBALS(
31 char *data;
32 long long len, base;
33 int numlen, undo, undolen;
34 unsigned height;
35)
36
37#define UNDO_LEN (sizeof(toybuf)/(sizeof(long long)+1))
38
39
40static int draw_char(FILE *fp, wchar_t broiled)
41{
42 if (fp) {
43 if (broiled<32 || broiled>=127) {
44 if (broiled>127) {
45 tty_esc("2m");
46 broiled &= 127;
47 }
48 if (broiled<32 || broiled==127) {
49 tty_esc("7m");
50 if (broiled==127) broiled = 32;
51 else broiled += 64;
52 }
53 printf("%c", (int)broiled);
54 tty_esc("0m");
55 } else printf("%c", (int)broiled);
56 }
57
58 return 1;
59}
60
61static void draw_tail(void)
62{
63 tty_jump(0, TT.height);
64 tty_esc("K");
65
66 draw_trim(*toys.optargs, -1, 71);
67}
68
69static void draw_line(long long yy)
70{
71 int x, xx = 16;
72
73 yy = (TT.base+yy)*16;
74 if (yy+xx>=TT.len) xx = TT.len-yy;
75
76 if (yy<TT.len) {
77 printf("\r%0*llX ", TT.numlen, yy);
78 for (x=0; x<xx; x++) printf(" %02X", TT.data[yy+x]);
79 printf("%*s", 2+3*(16-xx), "");
80 for (x=0; x<xx; x++) draw_char(stdout, TT.data[yy+x]);
81 printf("%*s", 16-xx, "");
82 }
83 tty_esc("K");
84}
85
86static void draw_page(void)
87{
88 int y;
89
90 tty_jump(0, 0);
91 for (y = 0; y<TT.height; y++) {
92 if (y) printf("\r\n");
93 draw_line(y);
94 }
95 draw_tail();
96}
97
98
99static void highlight(int xx, int yy, int side)
100{
101 char cc = TT.data[16*(TT.base+yy)+xx];
102 int i;
103
104
105 tty_jump(2+TT.numlen+3*xx, yy);
106 tty_esc("0m");
107 if (side!=2) tty_esc("7m");
108 if (side>1) printf("%02X", cc);
109 else for (i=0; i<2;) {
110 if (side==i) tty_esc("32m");
111 printf("%X", (cc>>(4*(1&++i)))&15);
112 }
113 tty_esc("0m");
114 tty_jump(TT.numlen+17*3+xx, yy);
115 draw_char(stdout, cc);
116}
117
118void hexedit_main(void)
119{
120 long long pos = 0, y;
121 int x, i, side = 0, key, ro = toys.optflags&FLAG_r,
122 fd = xopen(*toys.optargs, ro ? O_RDONLY : O_RDWR);
123 char keybuf[16];
124
125 *keybuf = 0;
126
127
128 TT.height = 25;
129 terminal_size(0, &TT.height);
130 if (TT.height) TT.height--;
131 sigatexit(tty_sigreset);
132 tty_esc("0m");
133 tty_esc("?25l");
134 fflush(0);
135 xset_terminal(1, 1, 0, 0);
136
137 if ((TT.len = fdlength(fd))<1) error_exit("bad length");
138 if (sizeof(long)==32 && TT.len>SIZE_MAX) TT.len = SIZE_MAX;
139
140 for (pos = TT.len, TT.numlen = 0; pos; pos >>= 4, TT.numlen++);
141 TT.numlen += (4-TT.numlen)&3;
142
143 TT.data = xmmap(0, TT.len, PROT_READ|(PROT_WRITE*!ro), MAP_SHARED, fd, 0);
144 draw_page();
145
146 for (;;) {
147
148 if (pos<0) pos = 0;
149 if (pos>=TT.len) pos = TT.len-1;
150 x = pos&15;
151 y = pos/16;
152
153 i = 0;
154 while (y<TT.base) {
155 if (TT.base-y>(TT.height/2)) {
156 TT.base = y;
157 draw_page();
158 } else {
159 TT.base--;
160 i++;
161 tty_esc("1T");
162 tty_jump(0, 0);
163 draw_line(0);
164 }
165 }
166 while (y>=TT.base+TT.height) {
167 if (y-(TT.base+TT.height)>(TT.height/2)) {
168 TT.base = y-TT.height-1;
169 draw_page();
170 } else {
171 TT.base++;
172 i++;
173 tty_esc("1S");
174 tty_jump(0, TT.height-1);
175 draw_line(TT.height-1);
176 }
177 }
178 if (i) draw_tail();
179 y -= TT.base;
180
181
182 highlight(x, y, ro ? 3 : side);
183 xflush(1);
184
185
186 key = scan_key(keybuf, -1);
187
188 if (key==-1 || key==3 || key==4 || key==27 || key=='q') break;
189 highlight(x, y, 2);
190
191
192 if (key>='a' && key<='f') key-=32;
193 if (!ro && ((key>='0' && key<='9') || (key>='A' && key<='F'))) {
194 if (!side) {
195 long long *ll = (long long *)toybuf;
196
197 ll[TT.undo] = pos;
198 toybuf[(sizeof(long long)*UNDO_LEN)+TT.undo++] = TT.data[pos];
199 if (TT.undolen < UNDO_LEN) TT.undolen++;
200 TT.undo %= UNDO_LEN;
201 }
202
203 i = key - '0';
204 if (i>9) i -= 7;
205 TT.data[pos] &= 15<<(4*side);
206 TT.data[pos] |= i<<(4*!side);
207
208 if (++side==2) {
209 highlight(x, y, side);
210 side = 0;
211 ++pos;
212 }
213 } else side = 0;
214 if (key=='u') {
215 if (TT.undolen) {
216 long long *ll = (long long *)toybuf;
217
218 TT.undolen--;
219 if (!TT.undo) TT.undo = UNDO_LEN;
220 pos = ll[--TT.undo];
221 TT.data[pos] = toybuf[sizeof(long long)*UNDO_LEN+TT.undo];
222 }
223 }
224 if (key>=256) {
225 key -= 256;
226
227 if (key==KEY_UP) pos -= 16;
228 else if (key==KEY_DOWN) pos += 16;
229 else if (key==KEY_RIGHT) {
230 if (x<15) pos++;
231 } else if (key==KEY_LEFT) {
232 if (x) pos--;
233 } else if (key==KEY_PGUP) pos -= 16*TT.height;
234 else if (key==KEY_PGDN) pos += 16*TT.height;
235 else if (key==KEY_HOME) pos = 0;
236 else if (key==KEY_END) pos = TT.len-1;
237 }
238 }
239 munmap(TT.data, TT.len);
240 close(fd);
241 tty_reset();
242}
243