add a CVS snapshot, to thoroughly test on the Debian side
[alioth/jupp.git] / kbd.c
1 /* $MirOS: contrib/code/jupp/kbd.c,v 1.4 2017/01/10 19:16:27 tg Exp $ */
2 /*
3  *      Key-map handler
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "macro.h"
16 #include "termcap.h"
17 #include "utils.h"
18 #include "vs.h"
19
20 /* Create a KBD */
21
22 KBD *mkkbd(KMAP *kmap)
23 {
24         KBD *kbd = (KBD *) joe_malloc(sizeof(KBD));
25
26         kbd->topmap = kmap;
27         kbd->curmap = kmap;
28         kbd->x = 0;
29         return kbd;
30 }
31
32 /* Eliminate a KBD */
33
34 void rmkbd(KBD *k)
35 {
36         joe_free(k);
37 }
38
39 /* Process next key for KBD */
40
41 void *dokey(KBD *kbd, int n)
42 {
43         void *bind = NULL;
44
45         /* If we were passed a negative character */
46         if (n < 0)
47                 n += 256;
48
49         /* kmap->keys[KEYS]; */
50         if ((size_t)n >= (size_t)(KEYS))
51                 return (NULL);
52
53         /* If we're starting from scratch, clear the keymap sequence buffer */
54         if (kbd->curmap == kbd->topmap)
55                 kbd->x = 0;
56
57         if (kbd->curmap->keys[n].k == 1) {      /* A prefix key was found */
58                 kbd->seq[kbd->x++] = n;
59                 kbd->curmap = kbd->curmap->keys[n].value.submap;
60         } else {                /* A complete key sequence was entered or an unbound key was found */
61                 bind = kbd->curmap->keys[n].value.bind;
62 /*  kbd->seq[kbd->x++]=n; */
63                 kbd->x = 0;
64                 kbd->curmap = kbd->topmap;
65         }
66         return bind;
67 }
68
69 /* Return key code for key name or -1 for syntax error */
70
71 static int keyval(unsigned char *s)
72 {
73         if (s[0] == '^' && s[1] && !s[2])
74                 if (s[1] == '?')
75                         return 127;
76                 else
77                         return s[1] & 0x1F;
78         else if ((s[0] == 'S' || s[0] == 's')
79                  && (s[1] == 'P' || s[1] == 'p') && !s[2])
80                 return ' ';
81         else if (s[1] || !s[0])
82                 return -1;
83         else
84                 return (unsigned char) s[0];
85 }
86
87 /* Create an empty keymap */
88
89 KMAP *mkkmap(void)
90 {
91         KMAP *kmap = (KMAP *) joe_calloc(sizeof(KMAP), 1);
92
93         return kmap;
94 }
95
96 /* Eliminate a keymap */
97
98 void rmkmap(KMAP *kmap)
99 {
100         int x;
101
102         if (!kmap)
103                 return;
104         for (x = 0; x != KEYS; ++x)
105                 if (kmap->keys[x].k == 1)
106                         rmkmap(kmap->keys[x].value.submap);
107         joe_free(kmap);
108 }
109
110 /* Parse a range */
111
112 static unsigned char *range(unsigned char *seq, int *vv, int *ww)
113 {
114         unsigned char c;
115         int x, v, w;
116
117         for (x = 0; seq[x] && seq[x] != ' '; ++x) ;     /* Skip to a space */
118         c = seq[x];
119         seq[x] = 0;             /* Zero terminate the string */
120         v = keyval(seq);        /* Get key */
121         w = v;
122         if (w < 0)
123                 return NULL;
124         seq[x] = c;             /* Restore the space or 0 */
125         for (seq += x; *seq == ' '; ++seq) ;    /* Skip over spaces */
126
127         /* Check for 'TO ' */
128         if ((seq[0] == 'T' || seq[0] == 't') && (seq[1] == 'O' || seq[1] == 'o') && seq[2] == ' ') {
129                 for (seq += 2; *seq == ' '; ++seq) ;    /* Skip over spaces */
130                 for (x = 0; seq[x] && seq[x] != ' '; ++x) ;     /* Skip to space */
131                 c = seq[x];
132                 seq[x] = 0;     /* Zero terminate the string */
133                 w = keyval(seq);        /* Get key */
134                 if (w < 0)
135                         return NULL;
136                 seq[x] = c;     /* Restore the space or 0 */
137                 for (seq += x; *seq == ' '; ++seq) ;    /* Skip over spaces */
138         }
139
140         if (v > w)
141                 return NULL;
142
143         *vv = v;
144         *ww = w;
145         return seq;
146 }
147
148 /* Add a binding to a keymap */
149
150 static KMAP *kbuild(CAP *cap, KMAP *kmap, unsigned char *seq, void *bind, int *err, unsigned char *capseq, int seql)
151 {
152         int v, w;
153
154         if (!seql && seq[0] == '.' && seq[1]) {
155                 int x, c;
156                 unsigned char *s;
157
158                 for (x = 0; seq[x] && seq[x] != ' '; ++x) ;
159                 c = seq[x];
160                 seq[x] = 0;
161 #ifdef __MSDOS__
162                 if (!strcmp(seq + 1, "ku")) {
163                         capseq = "\0H";
164                         seql = 2;
165                 } else if (!strcmp(seq + 1, "kd")) {
166                         capseq = "\0P";
167                         seql = 2;
168                 } else if (!strcmp(seq + 1, "kl")) {
169                         capseq = "\0K";
170                         seql = 2;
171                 } else if (!strcmp(seq + 1, "kr")) {
172                         capseq = "\0M";
173                         seql = 2;
174                 } else if (!strcmp(seq + 1, "kI")) {
175                         capseq = "\0R";
176                         seql = 2;
177                 } else if (!strcmp(seq + 1, "kD")) {
178                         capseq = "\0S";
179                         seql = 2;
180                 } else if (!strcmp(seq + 1, "kh")) {
181                         capseq = "\0G";
182                         seql = 2;
183                 } else if (!strcmp(seq + 1, "kH")) {
184                         capseq = "\0O";
185                         seql = 2;
186                 } else if (!strcmp(seq + 1, "kP")) {
187                         capseq = "\0I";
188                         seql = 2;
189                 } else if (!strcmp(seq + 1, "kN")) {
190                         capseq = "\0Q";
191                         seql = 2;
192                 } else if (!strcmp(seq + 1, "k1")) {
193                         capseq = "\0;";
194                         seql = 2;
195                 } else if (!strcmp(seq + 1, "k2")) {
196                         capseq = "\0<";
197                         seql = 2;
198                 } else if (!strcmp(seq + 1, "k3")) {
199                         capseq = "\0=";
200                         seql = 2;
201                 } else if (!strcmp(seq + 1, "k4")) {
202                         capseq = "\0>";
203                         seql = 2;
204                 } else if (!strcmp(seq + 1, "k5")) {
205                         capseq = "\0?";
206                         seql = 2;
207                 } else if (!strcmp(seq + 1, "k6")) {
208                         capseq = "\0@";
209                         seql = 2;
210                 } else if (!strcmp(seq + 1, "k7")) {
211                         capseq = "\0A";
212                         seql = 2;
213                 } else if (!strcmp(seq + 1, "k8")) {
214                         capseq = "\0B";
215                         seql = 2;
216                 } else if (!strcmp(seq + 1, "k9")) {
217                         capseq = "\0C";
218                         seql = 2;
219                 } else if (!strcmp(seq + 1, "k0")) {
220                         capseq = "\0D";
221                         seql = 2;
222                 }
223                 seq[x] = c;
224                 if (seql) {
225                         for (seq += x; *seq == ' '; ++seq) ;
226                 }
227 #else
228                 s = jgetstr(cap, seq + 1);
229                 seq[x] = c;
230                 if (s && (s = tcompile(cap, s, 0, 0, 0, 0))
231                     && (sLEN(s) > 1 || (signed char)s[0] < 0)) {
232                         capseq = s;
233                         seql = sLEN(s);
234                         for (seq += x; *seq == ' '; ++seq) ;
235                 }
236 #endif
237                 else {
238                         *err = -2;
239                         return kmap;
240                 }
241         }
242
243         if (seql) {
244                 v = w = (unsigned char) *capseq++;
245                 --seql;
246         } else {
247                 seq = range(seq, &v, &w);
248                 if (!seq) {
249                         *err = -1;
250                         return kmap;
251                 }
252         }
253
254         if (!kmap)
255                 kmap = mkkmap();        /* Create new keymap if 'kmap' was NULL */
256
257         /* Make bindings between v and w */
258         while (v <= w) {
259                 if (*seq || seql) {
260                         if (kmap->keys[v].k == 0)
261                                 kmap->keys[v].value.submap = NULL;
262                         kmap->keys[v].k = 1;
263                         kmap->keys[v].value.submap = kbuild(cap, kmap->keys[v].value.bind, seq, bind, err, capseq, seql);
264                 } else {
265                         if (kmap->keys[v].k == 1)
266                                 rmkmap(kmap->keys[v].value.submap);
267                         kmap->keys[v].k = 0;
268                         kmap->keys[v].value.bind =
269                             /* This bit of code sticks the key value in the macro */
270                             (v == w ? macstk(bind, v) : dupmacro(macstk(bind, v)));
271                 }
272                 ++v;
273         }
274         return kmap;
275 }
276
277 int kadd(CAP *cap, KMAP *kmap, unsigned char *seq, void *bind)
278 {
279         int err = 0;
280
281         kbuild(cap, kmap, seq, bind, &err, NULL, 0);
282         return err;
283 }
284
285 void kcpy(KMAP *dest, KMAP *src)
286 {
287         int x;
288
289         for (x = 0; x != KEYS; ++x)
290                 if (src->keys[x].k == 1) {
291                         if (dest->keys[x].k != 1) {
292                                 dest->keys[x].k = 1;
293                                 dest->keys[x].value.submap = mkkmap();
294                         }
295                         kcpy(dest->keys[x].value.submap, src->keys[x].value.submap);
296                 } else if (src->keys[x].k == 0 && src->keys[x].value.bind) {
297                         if (dest->keys[x].k == 1)
298                                 rmkmap(dest->keys[x].value.submap);
299                         dest->keys[x].value.bind = src->keys[x].value.bind;
300                         dest->keys[x].k = 0;
301                 }
302 }
303
304 /* Remove a binding from a keymap */
305
306 int kdel(KMAP *kmap, unsigned char *seq)
307 {
308         int err = 1;
309         int v, w;
310
311         seq = range(seq, &v, &w);
312         if (!seq)
313                 return -1;
314
315         /* Clear bindings between v and w */
316         while (v <= w) {
317                 if (*seq) {
318                         if (kmap->keys[v].k == 1) {
319                                 int r = kdel(kmap->keys[v].value.submap, seq);
320
321                                 if (err != -1)
322                                         err = r;
323                         }
324                 } else {
325                         if (kmap->keys[v].k == 1)
326                                 rmkmap(kmap->keys[v].value.submap);
327                         kmap->keys[v].k = 0;
328                         kmap->keys[v].value.bind = NULL;
329                         if (err != -1)
330                                 err = 0;
331                 }
332                 ++v;
333         }
334
335         return err;
336 }