]> pd.if.org Git - pd_readline/blob - mg/kbd.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / kbd.c
1 /*      $OpenBSD: kbd.c,v 1.25 2012/04/12 04:47:59 lum Exp $    */
2
3 /* This file is in the public domain. */
4
5 /*
6  *      Terminal independent keyboard handling.
7  */
8
9 #include "def.h"
10 #include "kbd.h"
11 #include "key.h"
12 #include "macro.h"
13
14 #ifndef METABIT
15 #define METABIT 0x80
16 #endif /* !METABIT */
17
18 #ifndef NO_DPROMPT
19 #define PROMPTL 80
20 char     prompt[PROMPTL] = "", *promptp = prompt;
21 #endif /* !NO_DPROMPT */
22
23 static int mgwrap(PF, int, int);
24
25 static int       use_metakey = TRUE;
26 static int       pushed = FALSE;
27 static int       pushedc;
28
29 struct map_element      *ele;
30
31 struct key key;
32
33 /*
34  * Toggle the value of use_metakey
35  */
36 int
37 do_meta(int f, int n)
38 {
39         if (f & FFARG)
40                 use_metakey = n > 0;
41         else
42                 use_metakey = !use_metakey;
43         ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis");
44         return (TRUE);
45 }
46
47 static int       bs_map = 0;
48
49 /*
50  * Toggle backspace mapping
51  */
52 int
53 bsmap(int f, int n)
54 {
55         if (f & FFARG)
56                 bs_map = n > 0;
57         else
58                 bs_map = !bs_map;
59         ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis");
60         return (TRUE);
61 }
62
63 void
64 ungetkey(int c)
65 {
66         if (use_metakey && pushed && c == CCHR('['))
67                 pushedc |= METABIT;
68         else
69                 pushedc = c;
70         pushed = TRUE;
71 }
72
73 int
74 getkey(int flag)
75 {
76         int      c;
77
78 #ifndef NO_DPROMPT
79         if (flag && !pushed) {
80                 if (prompt[0] != '\0' && ttwait(2000)) {
81                         /* avoid problems with % */
82                         ewprintf("%s", prompt);
83                         /* put the cursor back */
84                         update();
85                         epresf = KCLEAR;
86                 }
87                 if (promptp > prompt)
88                         *(promptp - 1) = ' ';
89         }
90 #endif /* !NO_DPROMPT */
91         if (pushed) {
92                 c = pushedc;
93                 pushed = FALSE;
94         } else
95                 c = ttgetc();
96
97         if (bs_map) {
98                 if (c == CCHR('H'))
99                         c = CCHR('?');
100                 else if (c == CCHR('?'))
101                         c = CCHR('H');
102         }
103         if (use_metakey && (c & METABIT)) {
104                 pushedc = c & ~METABIT;
105                 pushed = TRUE;
106                 c = CCHR('[');
107         }
108 #ifndef NO_DPROMPT
109         if (flag && promptp < &prompt[PROMPTL - 5]) {
110                 promptp = getkeyname(promptp,
111                     sizeof(prompt) - (promptp - prompt) - 1, c);
112                 *promptp++ = '-';
113                 *promptp = '\0';
114         }
115 #endif /* !NO_DPROMPT */
116         return (c);
117 }
118
119 /*
120  * doscan scans a keymap for a keyboard character and returns a pointer
121  * to the function associated with that character.  Sets ele to the
122  * keymap element the keyboard was found in as a side effect.
123  */
124 PF
125 doscan(KEYMAP *map, int c, KEYMAP **newmap)
126 {
127         struct map_element      *elec = &map->map_element[0];
128         struct map_element      *last = &map->map_element[map->map_num];
129         PF               ret;
130
131         while (elec < last && c > elec->k_num)
132                 elec++;
133
134         /* used by prefix and binding code */
135         ele = elec;
136         if (elec >= last || c < elec->k_base)
137                 ret = map->map_default;
138         else
139                 ret = elec->k_funcp[c - elec->k_base];
140         if (ret == NULL && newmap != NULL)
141                 *newmap = elec->k_prefmap;
142
143         return (ret);
144 }
145
146 int
147 doin(void)
148 {
149         KEYMAP  *curmap;
150         PF       funct;
151
152 #ifndef NO_DPROMPT
153         *(promptp = prompt) = '\0';
154 #endif /* !NO_DPROMPT */
155         curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
156         key.k_count = 0;
157         while ((funct = doscan(curmap, (key.k_chars[key.k_count++] =
158             getkey(TRUE)), &curmap)) == NULL)
159                 /* nothing */;
160
161         if (macrodef && macrocount < MAXMACRO)
162                 macro[macrocount++].m_funct = funct;
163
164         return (mgwrap(funct, 0, 1));
165 }
166
167 int
168 rescan(int f, int n)
169 {
170         int      c;
171         KEYMAP  *curmap;
172         int      i;
173         PF       fp = NULL;
174         int      md = curbp->b_nmodes;
175
176         for (;;) {
177                 if (ISUPPER(key.k_chars[key.k_count - 1])) {
178                         c = TOLOWER(key.k_chars[key.k_count - 1]);
179                         curmap = curbp->b_modes[md]->p_map;
180                         for (i = 0; i < key.k_count - 1; i++) {
181                                 if ((fp = doscan(curmap, (key.k_chars[i]),
182                                     &curmap)) != NULL)
183                                         break;
184                         }
185                         if (fp == NULL) {
186                                 if ((fp = doscan(curmap, c, NULL)) == NULL)
187                                         while ((fp = doscan(curmap,
188                                             key.k_chars[key.k_count++] =
189                                             getkey(TRUE), &curmap)) == NULL)
190                                                 /* nothing */;
191                                 if (fp != rescan) {
192                                         if (macrodef && macrocount <= MAXMACRO)
193                                                 macro[macrocount - 1].m_funct
194                                                     = fp;
195                                         return (mgwrap(fp, f, n));
196                                 }
197                         }
198                 }
199                 /* try previous mode */
200                 if (--md < 0)
201                         return (ABORT);
202                 curmap = curbp->b_modes[md]->p_map;
203                 for (i = 0; i < key.k_count; i++) {
204                         if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
205                                 break;
206                 }
207                 if (fp == NULL) {
208                         while ((fp = doscan(curmap, key.k_chars[i++] =
209                             getkey(TRUE), &curmap)) == NULL)
210                                 /* nothing */;
211                         key.k_count = i;
212                 }
213                 if (fp != rescan && i >= key.k_count - 1) {
214                         if (macrodef && macrocount <= MAXMACRO)
215                                 macro[macrocount - 1].m_funct = fp;
216                         return (mgwrap(fp, f, n));
217                 }
218         }
219 }
220
221 int
222 universal_argument(int f, int n)
223 {
224         KEYMAP  *curmap;
225         PF       funct;
226         int      c, nn = 4;
227
228         if (f & FFUNIV)
229                 nn *= n;
230         for (;;) {
231                 key.k_chars[0] = c = getkey(TRUE);
232                 key.k_count = 1;
233                 if (c == '-')
234                         return (negative_argument(f, nn));
235                 if (c >= '0' && c <= '9')
236                         return (digit_argument(f, nn));
237                 curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
238                 while ((funct = doscan(curmap, c, &curmap)) == NULL) {
239                         key.k_chars[key.k_count++] = c = getkey(TRUE);
240                 }
241                 if (funct != universal_argument) {
242                         if (macrodef && macrocount < MAXMACRO - 1) {
243                                 if (f & FFARG)
244                                         macrocount--;
245                                 macro[macrocount++].m_count = nn;
246                                 macro[macrocount++].m_funct = funct;
247                         }
248                         return (mgwrap(funct, FFUNIV, nn));
249                 }
250                 nn <<= 2;
251         }
252 }
253
254 /* ARGSUSED */
255 int
256 digit_argument(int f, int n)
257 {
258         KEYMAP  *curmap;
259         PF       funct;
260         int      nn, c;
261
262         nn = key.k_chars[key.k_count - 1] - '0';
263         for (;;) {
264                 c = getkey(TRUE);
265                 if (c < '0' || c > '9')
266                         break;
267                 nn *= 10;
268                 nn += c - '0';
269         }
270         key.k_chars[0] = c;
271         key.k_count = 1;
272         curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
273         while ((funct = doscan(curmap, c, &curmap)) == NULL) {
274                 key.k_chars[key.k_count++] = c = getkey(TRUE);
275         }
276         if (macrodef && macrocount < MAXMACRO - 1) {
277                 if (f & FFARG)
278                         macrocount--;
279                 else
280                         macro[macrocount - 1].m_funct = universal_argument;
281                 macro[macrocount++].m_count = nn;
282                 macro[macrocount++].m_funct = funct;
283         }
284         return (mgwrap(funct, FFOTHARG, nn));
285 }
286
287 int
288 negative_argument(int f, int n)
289 {
290         KEYMAP  *curmap;
291         PF       funct;
292         int      c;
293         int      nn = 0;
294
295         for (;;) {
296                 c = getkey(TRUE);
297                 if (c < '0' || c > '9')
298                         break;
299                 nn *= 10;
300                 nn += c - '0';
301         }
302         if (nn)
303                 nn = -nn;
304         else
305                 nn = -n;
306         key.k_chars[0] = c;
307         key.k_count = 1;
308         curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
309         while ((funct = doscan(curmap, c, &curmap)) == NULL) {
310                 key.k_chars[key.k_count++] = c = getkey(TRUE);
311         }
312         if (macrodef && macrocount < MAXMACRO - 1) {
313                 if (f & FFARG)
314                         macrocount--;
315                 else
316                         macro[macrocount - 1].m_funct = universal_argument;
317                 macro[macrocount++].m_count = nn;
318                 macro[macrocount++].m_funct = funct;
319         }
320         return (mgwrap(funct, FFNEGARG, nn));
321 }
322
323 /*
324  * Insert a character.  While defining a macro, create a "LINE" containing
325  * all inserted characters.
326  */
327 int
328 selfinsert(int f, int n)
329 {
330         struct line     *lp;
331         int      c;
332         int      count;
333
334         if (n < 0)
335                 return (FALSE);
336         if (n == 0)
337                 return (TRUE);
338         c = key.k_chars[key.k_count - 1];
339
340         if (macrodef && macrocount < MAXMACRO) {
341                 if (f & FFARG)
342                         macrocount -= 2;
343
344                 /* last command was insert -- tack on the end */
345                 if (lastflag & CFINS) {
346                         macrocount--;
347                         /* Ensure the line can handle the new characters */
348                         if (maclcur->l_size < maclcur->l_used + n) {
349                                 if (lrealloc(maclcur, maclcur->l_used + n) ==
350                                     FALSE)
351                                         return (FALSE);
352                         }
353                         maclcur->l_used += n;
354                         /* Copy in the new data */
355                         for (count = maclcur->l_used - n;
356                             count < maclcur->l_used; count++)
357                                 maclcur->l_text[count] = c;
358                 } else {
359                         macro[macrocount - 1].m_funct = insert;
360                         if ((lp = lalloc(n)) == NULL)
361                                 return (FALSE);
362                         lp->l_bp = maclcur;
363                         lp->l_fp = maclcur->l_fp;
364                         maclcur->l_fp = lp;
365                         maclcur = lp;
366                         for (count = 0; count < n; count++)
367                                 lp->l_text[count] = c;
368                 }
369                 thisflag |= CFINS;
370         }
371         if (c == '\n') {
372                 do {
373                         count = lnewline();
374                 } while (--n && count == TRUE);
375                 return (count);
376         }
377
378         /* overwrite mode */
379         if (curbp->b_flag & BFOVERWRITE) {
380                 lchange(WFEDIT);
381                 while (curwp->w_doto < llength(curwp->w_dotp) && n--)
382                         lputc(curwp->w_dotp, curwp->w_doto++, c);
383                 if (n <= 0)
384                         return (TRUE);
385         }
386         return (linsert(n, c));
387 }
388
389 /*
390  * This could be implemented as a keymap with everything defined as self-insert.
391  */
392 int
393 quote(int f, int n)
394 {
395         int      c;
396
397         key.k_count = 1;
398         if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') {
399                 key.k_chars[0] -= '0';
400                 if ((c = getkey(TRUE)) >= '0' && c <= '7') {
401                         key.k_chars[0] <<= 3;
402                         key.k_chars[0] += c - '0';
403                         if ((c = getkey(TRUE)) >= '0' && c <= '7') {
404                                 key.k_chars[0] <<= 3;
405                                 key.k_chars[0] += c - '0';
406                         } else
407                                 ungetkey(c);
408                 } else
409                         ungetkey(c);
410         }
411         return (selfinsert(f, n));
412 }
413
414 /*
415  * Wraper function to count invocation repeats.
416  * We ignore any function whose sole purpose is to get us
417  * to the intended function.
418  */
419 static int
420 mgwrap(PF funct, int f, int n)
421 {
422         static   PF ofp;
423         
424         if (funct != rescan &&
425             funct != negative_argument &&
426             funct != digit_argument &&
427             funct != universal_argument) {
428                 if (funct == ofp)
429                         rptcount++;
430                 else
431                         rptcount = 0;
432                 ofp = funct;
433         }
434         
435         return ((*funct)(f, n));
436 }