]> git.neil.brown.name Git - edlib.git/blob - render-hex.c
doc: change Call:Notify:doc: to doc:Notify:doc:
[edlib.git] / render-hex.c
1 /*
2  * Copyright Neil Brown ©2015-2019 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * hexedit renderer
6  *
7  * 16 bytes are rendered as hex, and then chars
8  * Well... currently we do chars, not bytes, because I cannot control
9  * char encoding yet.
10  *
11  */
12
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <wchar.h>
16 #include <string.h>
17 #include <stdio.h>
18
19 #include "core.h"
20 #include "misc.h"
21
22 struct he_data {
23         struct pane     *pane;
24         bool bytes;
25 };
26
27 static struct map *he_map;
28 static struct pane *do_render_hex_attach(struct pane *parent safe);
29
30 DEF_LOOKUP_CMD(render_hex_handle, he_map);
31
32 DEF_CMD(render_hex_close)
33 {
34         struct pane *p = ci->home;
35         struct he_data *he = p->data;
36
37         he->pane = NULL;
38         p->data = safe_cast NULL;
39         p->handle = NULL;
40         free(he);
41         return 1;
42 }
43
44 DEF_CMD(render_hex_clone)
45 {
46         struct pane *parent = ci->focus;
47
48         do_render_hex_attach(parent);
49         pane_clone_children(ci->home, parent->focus);
50         return 1;
51 }
52
53 DEF_CMD(render_hex_notify_replace)
54 {
55
56         /* If change happens only after the view port, we don't
57          * need damage.
58          * If before, we might need to update addresses.
59          * However we cannot currently access the view port, so
60          * always signal damage.
61          */
62         pane_damaged(ci->home, DAMAGED_CONTENT);
63         return 1;
64 }
65
66 DEF_CMD(render_hex_eol)
67 {
68         wint_t ch = 1;
69         int rpt = RPT_NUM(ci);
70         int pos;
71
72         if (!ci->mark)
73                 return Enoarg;
74         call("CountLines", ci->home, 0, ci->mark);
75
76         pos = attr_find_int(*mark_attr(ci->mark), "chars");
77         while (rpt > 0 && ch != WEOF) {
78                 while ((pos & 15) != 15 &&
79                        (ch = mark_next_pane(ci->focus, ci->mark)) != WEOF)
80                         pos += 1;
81                 rpt -= 1;
82                 if (rpt) {
83                         ch = mark_next_pane(ci->focus, ci->mark);
84                         pos += 1;
85                 }
86         }
87         while (rpt < 0 && ch != WEOF) {
88                 while ((pos & 15) != 0 &&
89                        (ch = mark_prev_pane(ci->focus, ci->mark)) != WEOF)
90                         pos -= 1;
91                 rpt += 1;
92                 if (rpt) {
93                         ch = mark_prev_pane(ci->focus, ci->mark);
94                         pos -= 1;
95                 }
96         }
97         return 1;
98 }
99
100 DEF_CMD(render_line)
101 {
102         struct buf ret;
103         struct mark *m = NULL;
104         struct mark *pm = ci->mark2;
105         int pos;
106         int i;
107         char buf[30];
108         int rv;
109
110         if (!ci->mark)
111                 return Enoarg;
112
113         call("CountLines", ci->home, 0, ci->mark);
114         pos = attr_find_int(*mark_attr(ci->mark), "chars");
115
116         buf_init(&ret);
117         if (doc_following_pane(ci->focus, ci->mark) == WEOF)
118                 goto done;
119         snprintf(buf, sizeof(buf), "<bold>%08x:</> ", pos);
120         buf_concat(&ret, buf);
121         m = mark_dup_view(ci->mark);
122         for (i = 0; i < 16; i++) {
123                 wint_t ch;
124                 struct mark *m2 = ci->mark;
125
126                 if (pm && mark_same(m2, pm))
127                         goto done;
128                 if (ci->num >= 0 && ci->num != NO_NUMERIC &&
129                     ci->num <= ret.len)
130                         goto done;
131
132                 ch = mark_next_pane(ci->focus, m2);
133                 if (ch == WEOF)
134                         strcpy(buf, "   ");
135                 else
136                         sprintf(buf, "%02x ", ch & 0xff);
137                 buf_concat(&ret, buf);
138                 if (i == 7)
139                         buf_append(&ret, ' ');
140         }
141
142         buf_concat(&ret, "  <fg:red>");
143         for (i = 0; i < 16; i++) {
144                 wint_t ch;
145
146                 ch = mark_next_pane(ci->focus, m);
147                 if (ch == WEOF)
148                         ch = ' ';
149                 if (ch < ' ')
150                         ch = '?';
151                 buf_append(&ret, ch);
152                 buf_append(&ret, ' ');
153                 if (i == 7)
154                         buf_append(&ret, ' ');
155         }
156         buf_concat(&ret, "</>\n");
157 done:
158         if (m)
159                 mark_free(m);
160         rv = comm_call(ci->comm2, "callback:render", ci->focus, 0, NULL,
161                        buf_final(&ret));
162         free(ret.b);
163         return rv;
164 }
165
166 DEF_CMD(render_line_prev)
167 {
168         /* If ->num is 0, round down to multiple of 16.
169          * if it is 1, subtract a further 16.
170          */
171         int to, from;
172
173         if (!ci->mark)
174                 return Enoarg;
175         call("CountLines", ci->home, 0, ci->mark);
176
177         from = attr_find_int(*mark_attr(ci->mark), "chars");
178         to = from & ~0xF;
179         if (ci->num && to >= 16)
180                 to -= 16;
181         while (to < from) {
182                 mark_prev_pane(ci->focus, ci->mark);
183                 from -= 1;
184         }
185         return 1;
186 }
187
188 DEF_CMD(hex_step)
189 {
190         struct he_data *he = ci->home->data;
191
192         if (!he->bytes || !ci->home->parent)
193                 return 0;
194         return home_call(ci->home->parent, "doc:step-bytes", ci->focus,
195                          ci->num, ci->mark, ci->str,
196                          ci->num2, ci->mark2, ci->str2);
197 }
198
199 static void render_hex_register_map(void)
200 {
201         he_map = key_alloc();
202
203         key_add(he_map, "Move-EOL", &render_hex_eol);
204         key_add(he_map, "doc:step", &hex_step);
205
206         key_add(he_map, "doc:render-line-prev", &render_line_prev);
207         key_add(he_map, "doc:render-line", &render_line);
208
209         key_add(he_map, "Close", &render_hex_close);
210         key_add(he_map, "Clone", &render_hex_clone);
211         key_add(he_map, "Notify:doc:Replace", &render_hex_notify_replace);
212 }
213
214 static struct pane *do_render_hex_attach(struct pane *parent safe)
215 {
216         struct he_data *he = malloc(sizeof(*he));
217         struct pane *p;
218         char *charset = pane_attr_get(parent, "doc:charset");
219
220         if (!he_map)
221                 render_hex_register_map();
222
223         p = pane_register(parent, 0, &render_hex_handle.c, he, NULL);
224         call("doc:Request:Notify:doc:Replace", p);
225         attr_set_str(&p->attrs, "render-wrap", "no");
226         attr_set_str(&p->attrs, "heading", "<bold>          00 11 22 33 44 55 66 77  88 99 aa bb cc dd ee ff   0 1 2 3 4 5 6 7  8 9 a b c d e f</>");
227         he->pane = p;
228         he->bytes = (charset && strcmp(charset, "8bit") != 0);
229         return call_ret(pane, "attach-render-lines", p);
230 }
231
232 DEF_CMD(render_hex_attach)
233 {
234         struct pane *p = do_render_hex_attach(ci->focus);
235
236         if (!p)
237                 return Esys;
238         return comm_call(ci->comm2, "callback:attach", p);
239 }
240
241 DEF_CMD(hex_appeared)
242 {
243         char *t = pane_attr_get(ci->focus, "doc-type");
244         if (t && strcmp(t, "text") == 0)
245                 attr_set_str(&ci->focus->attrs, "render-Chr-H", "hex");
246         return 0;
247 }
248
249 void edlib_init(struct pane *ed safe)
250 {
251         call_comm("global-set-command", ed, &render_hex_attach, 0, NULL, "attach-render-hex");
252         call_comm("global-set-command", ed, &hex_appeared, 0, NULL, "doc:appeared-hex");
253 }