]> pd.if.org Git - pd_readline/blobdiff - mg/kbd.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / kbd.c
diff --git a/mg/kbd.c b/mg/kbd.c
new file mode 100644 (file)
index 0000000..0eb3c36
--- /dev/null
+++ b/mg/kbd.c
@@ -0,0 +1,436 @@
+/*     $OpenBSD: kbd.c,v 1.25 2012/04/12 04:47:59 lum Exp $    */
+
+/* This file is in the public domain. */
+
+/*
+ *     Terminal independent keyboard handling.
+ */
+
+#include "def.h"
+#include "kbd.h"
+#include "key.h"
+#include "macro.h"
+
+#ifndef METABIT
+#define METABIT 0x80
+#endif /* !METABIT */
+
+#ifndef NO_DPROMPT
+#define PROMPTL 80
+char    prompt[PROMPTL] = "", *promptp = prompt;
+#endif /* !NO_DPROMPT */
+
+static int mgwrap(PF, int, int);
+
+static int      use_metakey = TRUE;
+static int      pushed = FALSE;
+static int      pushedc;
+
+struct map_element     *ele;
+
+struct key key;
+
+/*
+ * Toggle the value of use_metakey
+ */
+int
+do_meta(int f, int n)
+{
+       if (f & FFARG)
+               use_metakey = n > 0;
+       else
+               use_metakey = !use_metakey;
+       ewprintf("Meta keys %sabled", use_metakey ? "en" : "dis");
+       return (TRUE);
+}
+
+static int      bs_map = 0;
+
+/*
+ * Toggle backspace mapping
+ */
+int
+bsmap(int f, int n)
+{
+       if (f & FFARG)
+               bs_map = n > 0;
+       else
+               bs_map = !bs_map;
+       ewprintf("Backspace mapping %sabled", bs_map ? "en" : "dis");
+       return (TRUE);
+}
+
+void
+ungetkey(int c)
+{
+       if (use_metakey && pushed && c == CCHR('['))
+               pushedc |= METABIT;
+       else
+               pushedc = c;
+       pushed = TRUE;
+}
+
+int
+getkey(int flag)
+{
+       int      c;
+
+#ifndef NO_DPROMPT
+       if (flag && !pushed) {
+               if (prompt[0] != '\0' && ttwait(2000)) {
+                       /* avoid problems with % */
+                       ewprintf("%s", prompt);
+                       /* put the cursor back */
+                       update();
+                       epresf = KCLEAR;
+               }
+               if (promptp > prompt)
+                       *(promptp - 1) = ' ';
+       }
+#endif /* !NO_DPROMPT */
+       if (pushed) {
+               c = pushedc;
+               pushed = FALSE;
+       } else
+               c = ttgetc();
+
+       if (bs_map) {
+               if (c == CCHR('H'))
+                       c = CCHR('?');
+               else if (c == CCHR('?'))
+                       c = CCHR('H');
+       }
+       if (use_metakey && (c & METABIT)) {
+               pushedc = c & ~METABIT;
+               pushed = TRUE;
+               c = CCHR('[');
+       }
+#ifndef NO_DPROMPT
+       if (flag && promptp < &prompt[PROMPTL - 5]) {
+               promptp = getkeyname(promptp,
+                   sizeof(prompt) - (promptp - prompt) - 1, c);
+               *promptp++ = '-';
+               *promptp = '\0';
+       }
+#endif /* !NO_DPROMPT */
+       return (c);
+}
+
+/*
+ * doscan scans a keymap for a keyboard character and returns a pointer
+ * to the function associated with that character.  Sets ele to the
+ * keymap element the keyboard was found in as a side effect.
+ */
+PF
+doscan(KEYMAP *map, int c, KEYMAP **newmap)
+{
+       struct map_element      *elec = &map->map_element[0];
+       struct map_element      *last = &map->map_element[map->map_num];
+       PF               ret;
+
+       while (elec < last && c > elec->k_num)
+               elec++;
+
+       /* used by prefix and binding code */
+       ele = elec;
+       if (elec >= last || c < elec->k_base)
+               ret = map->map_default;
+       else
+               ret = elec->k_funcp[c - elec->k_base];
+       if (ret == NULL && newmap != NULL)
+               *newmap = elec->k_prefmap;
+
+       return (ret);
+}
+
+int
+doin(void)
+{
+       KEYMAP  *curmap;
+       PF       funct;
+
+#ifndef NO_DPROMPT
+       *(promptp = prompt) = '\0';
+#endif /* !NO_DPROMPT */
+       curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
+       key.k_count = 0;
+       while ((funct = doscan(curmap, (key.k_chars[key.k_count++] =
+           getkey(TRUE)), &curmap)) == NULL)
+               /* nothing */;
+
+       if (macrodef && macrocount < MAXMACRO)
+               macro[macrocount++].m_funct = funct;
+
+       return (mgwrap(funct, 0, 1));
+}
+
+int
+rescan(int f, int n)
+{
+       int      c;
+       KEYMAP  *curmap;
+       int      i;
+       PF       fp = NULL;
+       int      md = curbp->b_nmodes;
+
+       for (;;) {
+               if (ISUPPER(key.k_chars[key.k_count - 1])) {
+                       c = TOLOWER(key.k_chars[key.k_count - 1]);
+                       curmap = curbp->b_modes[md]->p_map;
+                       for (i = 0; i < key.k_count - 1; i++) {
+                               if ((fp = doscan(curmap, (key.k_chars[i]),
+                                   &curmap)) != NULL)
+                                       break;
+                       }
+                       if (fp == NULL) {
+                               if ((fp = doscan(curmap, c, NULL)) == NULL)
+                                       while ((fp = doscan(curmap,
+                                           key.k_chars[key.k_count++] =
+                                           getkey(TRUE), &curmap)) == NULL)
+                                               /* nothing */;
+                               if (fp != rescan) {
+                                       if (macrodef && macrocount <= MAXMACRO)
+                                               macro[macrocount - 1].m_funct
+                                                   = fp;
+                                       return (mgwrap(fp, f, n));
+                               }
+                       }
+               }
+               /* try previous mode */
+               if (--md < 0)
+                       return (ABORT);
+               curmap = curbp->b_modes[md]->p_map;
+               for (i = 0; i < key.k_count; i++) {
+                       if ((fp = doscan(curmap, (key.k_chars[i]), &curmap)) != NULL)
+                               break;
+               }
+               if (fp == NULL) {
+                       while ((fp = doscan(curmap, key.k_chars[i++] =
+                           getkey(TRUE), &curmap)) == NULL)
+                               /* nothing */;
+                       key.k_count = i;
+               }
+               if (fp != rescan && i >= key.k_count - 1) {
+                       if (macrodef && macrocount <= MAXMACRO)
+                               macro[macrocount - 1].m_funct = fp;
+                       return (mgwrap(fp, f, n));
+               }
+       }
+}
+
+int
+universal_argument(int f, int n)
+{
+       KEYMAP  *curmap;
+       PF       funct;
+       int      c, nn = 4;
+
+       if (f & FFUNIV)
+               nn *= n;
+       for (;;) {
+               key.k_chars[0] = c = getkey(TRUE);
+               key.k_count = 1;
+               if (c == '-')
+                       return (negative_argument(f, nn));
+               if (c >= '0' && c <= '9')
+                       return (digit_argument(f, nn));
+               curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
+               while ((funct = doscan(curmap, c, &curmap)) == NULL) {
+                       key.k_chars[key.k_count++] = c = getkey(TRUE);
+               }
+               if (funct != universal_argument) {
+                       if (macrodef && macrocount < MAXMACRO - 1) {
+                               if (f & FFARG)
+                                       macrocount--;
+                               macro[macrocount++].m_count = nn;
+                               macro[macrocount++].m_funct = funct;
+                       }
+                       return (mgwrap(funct, FFUNIV, nn));
+               }
+               nn <<= 2;
+       }
+}
+
+/* ARGSUSED */
+int
+digit_argument(int f, int n)
+{
+       KEYMAP  *curmap;
+       PF       funct;
+       int      nn, c;
+
+       nn = key.k_chars[key.k_count - 1] - '0';
+       for (;;) {
+               c = getkey(TRUE);
+               if (c < '0' || c > '9')
+                       break;
+               nn *= 10;
+               nn += c - '0';
+       }
+       key.k_chars[0] = c;
+       key.k_count = 1;
+       curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
+       while ((funct = doscan(curmap, c, &curmap)) == NULL) {
+               key.k_chars[key.k_count++] = c = getkey(TRUE);
+       }
+       if (macrodef && macrocount < MAXMACRO - 1) {
+               if (f & FFARG)
+                       macrocount--;
+               else
+                       macro[macrocount - 1].m_funct = universal_argument;
+               macro[macrocount++].m_count = nn;
+               macro[macrocount++].m_funct = funct;
+       }
+       return (mgwrap(funct, FFOTHARG, nn));
+}
+
+int
+negative_argument(int f, int n)
+{
+       KEYMAP  *curmap;
+       PF       funct;
+       int      c;
+       int      nn = 0;
+
+       for (;;) {
+               c = getkey(TRUE);
+               if (c < '0' || c > '9')
+                       break;
+               nn *= 10;
+               nn += c - '0';
+       }
+       if (nn)
+               nn = -nn;
+       else
+               nn = -n;
+       key.k_chars[0] = c;
+       key.k_count = 1;
+       curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
+       while ((funct = doscan(curmap, c, &curmap)) == NULL) {
+               key.k_chars[key.k_count++] = c = getkey(TRUE);
+       }
+       if (macrodef && macrocount < MAXMACRO - 1) {
+               if (f & FFARG)
+                       macrocount--;
+               else
+                       macro[macrocount - 1].m_funct = universal_argument;
+               macro[macrocount++].m_count = nn;
+               macro[macrocount++].m_funct = funct;
+       }
+       return (mgwrap(funct, FFNEGARG, nn));
+}
+
+/*
+ * Insert a character. While defining a macro, create a "LINE" containing
+ * all inserted characters.
+ */
+int
+selfinsert(int f, int n)
+{
+       struct line     *lp;
+       int      c;
+       int      count;
+
+       if (n < 0)
+               return (FALSE);
+       if (n == 0)
+               return (TRUE);
+       c = key.k_chars[key.k_count - 1];
+
+       if (macrodef && macrocount < MAXMACRO) {
+               if (f & FFARG)
+                       macrocount -= 2;
+
+               /* last command was insert -- tack on the end */
+               if (lastflag & CFINS) {
+                       macrocount--;
+                       /* Ensure the line can handle the new characters */
+                       if (maclcur->l_size < maclcur->l_used + n) {
+                               if (lrealloc(maclcur, maclcur->l_used + n) ==
+                                   FALSE)
+                                       return (FALSE);
+                       }
+                       maclcur->l_used += n;
+                       /* Copy in the new data */
+                       for (count = maclcur->l_used - n;
+                           count < maclcur->l_used; count++)
+                               maclcur->l_text[count] = c;
+               } else {
+                       macro[macrocount - 1].m_funct = insert;
+                       if ((lp = lalloc(n)) == NULL)
+                               return (FALSE);
+                       lp->l_bp = maclcur;
+                       lp->l_fp = maclcur->l_fp;
+                       maclcur->l_fp = lp;
+                       maclcur = lp;
+                       for (count = 0; count < n; count++)
+                               lp->l_text[count] = c;
+               }
+               thisflag |= CFINS;
+       }
+       if (c == '\n') {
+               do {
+                       count = lnewline();
+               } while (--n && count == TRUE);
+               return (count);
+       }
+
+       /* overwrite mode */
+       if (curbp->b_flag & BFOVERWRITE) {
+               lchange(WFEDIT);
+               while (curwp->w_doto < llength(curwp->w_dotp) && n--)
+                       lputc(curwp->w_dotp, curwp->w_doto++, c);
+               if (n <= 0)
+                       return (TRUE);
+       }
+       return (linsert(n, c));
+}
+
+/*
+ * This could be implemented as a keymap with everything defined as self-insert.
+ */
+int
+quote(int f, int n)
+{
+       int      c;
+
+       key.k_count = 1;
+       if ((key.k_chars[0] = getkey(TRUE)) >= '0' && key.k_chars[0] <= '7') {
+               key.k_chars[0] -= '0';
+               if ((c = getkey(TRUE)) >= '0' && c <= '7') {
+                       key.k_chars[0] <<= 3;
+                       key.k_chars[0] += c - '0';
+                       if ((c = getkey(TRUE)) >= '0' && c <= '7') {
+                               key.k_chars[0] <<= 3;
+                               key.k_chars[0] += c - '0';
+                       } else
+                               ungetkey(c);
+               } else
+                       ungetkey(c);
+       }
+       return (selfinsert(f, n));
+}
+
+/*
+ * Wraper function to count invocation repeats.
+ * We ignore any function whose sole purpose is to get us
+ * to the intended function.
+ */
+static int
+mgwrap(PF funct, int f, int n)
+{
+       static   PF ofp;
+       
+       if (funct != rescan &&
+           funct != negative_argument &&
+           funct != digit_argument &&
+           funct != universal_argument) {
+               if (funct == ofp)
+                       rptcount++;
+               else
+                       rptcount = 0;
+               ofp = funct;
+       }
+       
+       return ((*funct)(f, n));
+}