home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / mush6.0 / part05 / bind.c next >
Encoding:
C/C++ Source or Header  |  1988-04-12  |  11.8 KB  |  457 lines

  1. /* bind.c */
  2.  
  3. #ifdef CURSES
  4.  
  5. #include "bindings.h"
  6. #include "mush.h"
  7.  
  8. #define MAX_BIND_LEN 20   /* max length a string can be to bind to a command */
  9.  
  10. struct cmd_map {
  11.     int m_cmd;  /* the command this is mapped to  */
  12.     char *m_str;  /* the string user types (cbreak) */
  13.     struct cmd_map *m_next;
  14. } *cmd_map;
  15.  
  16. init_bindings()
  17. {
  18.     add_bind("g", 1);
  19.     add_bind("w", 2);
  20.     add_bind("W", 3);
  21.     add_bind("s", 4);
  22.     add_bind("S", 5);
  23.     add_bind("c", 6);
  24.     add_bind("C", 7);
  25.     add_bind("d", 8);
  26.     add_bind("D", 9);
  27.     add_bind("u", 10);
  28.     add_bind("U", 11);
  29.     add_bind("\\CR", 12);
  30.     add_bind("\\CL", 13);
  31.     add_bind("j", 14), add_bind("J", 14), add_bind("\\n", 14), add_bind("+",14);
  32.     add_bind("k", 15), add_bind("K", 15), add_bind("-",15), add_bind("\\CK",15);
  33.     add_bind("^", 16);
  34.     add_bind("$", 17);
  35.     add_bind("{", 18);
  36.     add_bind("}", 19);
  37.     add_bind("z", 20);
  38.     add_bind("Z", 21);
  39.     add_bind("H", 22);
  40.     add_bind("(", 23);
  41.     add_bind(")", 24);
  42.     add_bind("/", 25);
  43.     add_bind("\\C_", 26);  /* this is really ^/ */
  44.     add_bind("\\CN", 27);
  45.     add_bind("\\CP", 28);
  46.     add_bind("o" ,29);
  47.     add_bind("O", 30);
  48.     add_bind("Q", 31);
  49.     add_bind("q", 32);
  50.     add_bind("X", 33);
  51.     add_bind("x", 34);
  52.     add_bind("\\CU", 35);
  53.     add_bind("f", 36);
  54.     add_bind("!", 37);
  55.     add_bind(":", 38);
  56.     add_bind("|", 39);
  57.     add_bind("%", 40);
  58.     add_bind("v", 41);
  59.     add_bind("i", 42);
  60.     add_bind("a", 43);
  61.     add_bind("h", 44);
  62.     add_bind("V", 45);
  63.     add_bind("M", 46);
  64.     add_bind("m", 47);
  65.     add_bind("r", 48);
  66.     add_bind("R", 49);
  67.     add_bind("t", 50), add_bind(".", 50), add_bind("p", 50);
  68.     add_bind("T", 51);
  69.     add_bind("n", 52);
  70.     add_bind("b", 53);
  71.     add_bind("B", 54);
  72.     add_bind("?", 55); /* C_HELP Must be the last one! */
  73. }
  74.  
  75. struct cmd_map map_func_names[] = {
  76.     { C_NULL,        NULL,            NULL_MAP },
  77.     { C_GOTO_MSG,    "goto msg",        NULL_MAP },
  78.     { C_WRITE_MSG,    "write",        NULL_MAP },
  79.     { C_WRITE_LIST,    "write list",        NULL_MAP },
  80.     { C_SAVE_MSG,    "save",            NULL_MAP },
  81.     { C_SAVE_LIST,    "save list",        NULL_MAP },
  82.     { C_COPY_MSG,    "copy",            NULL_MAP },
  83.     { C_COPY_LIST,    "copy list",        NULL_MAP },
  84.     { C_DELETE_MSG,    "delete",        NULL_MAP },
  85.     { C_DELETE_LIST,    "delete list",        NULL_MAP },
  86.     { C_UNDEL_MSG,    "undelete",        NULL_MAP },
  87.     { C_UNDEL_LIST,    "undelete list",    NULL_MAP },
  88.     { C_REVERSE,    "reverse video",    NULL_MAP },
  89.     { C_REDRAW,        "redraw",        NULL_MAP },
  90.     { C_NEXT_MSG,    "next msg",        NULL_MAP },
  91.     { C_PREV_MSG,    "back msg",        NULL_MAP },
  92.     { C_FIRST_MSG,    "first msg",        NULL_MAP },
  93.     { C_LAST_MSG,    "last msg",        NULL_MAP },
  94.     { C_TOP_PAGE,    "top page",        NULL_MAP },
  95.     { C_BOTTOM_PAGE,    "bottom page",        NULL_MAP },
  96.     { C_NEXT_SCREEN,    "screen next",        NULL_MAP },
  97.     { C_PREV_SCREEN,    "screen back",        NULL_MAP },
  98.     { C_SHOW_HDR,    "show hdr",        NULL_MAP },
  99.     { C_SOURCE,        "source",        NULL_MAP },
  100.     { C_SAVEOPTS,    "saveopts",        NULL_MAP },
  101.     { C_NEXT_SEARCH,    "search up",        NULL_MAP },
  102.     { C_PREV_SEARCH,    "search down",        NULL_MAP },
  103.     { C_CONT_SEARCH,    "search cont",        NULL_MAP },
  104.     { C_PRESERVE,    "preserve",        NULL_MAP },
  105.     { C_SORT,        "sort",            NULL_MAP },
  106.     { C_REV_SORT,    "sort reverse",        NULL_MAP },
  107.     { C_QUIT_HARD,    "quit!",        NULL_MAP },
  108.     { C_QUIT,        "quit",            NULL_MAP },
  109.     { C_EXIT_HARD,    "exit!",        NULL_MAP },
  110.     { C_EXIT,        "exit",            NULL_MAP },
  111.     { C_UPDATE,        "update",        NULL_MAP },
  112.     { C_FOLDER,        "folder",        NULL_MAP },
  113.     { C_SHELL_ESC,    "shell escape",        NULL_MAP },
  114.     { C_CURSES_ESC,    "line mode",        NULL_MAP },
  115.     { C_PRINT_MSG,    "lpr",            NULL_MAP },
  116.     { C_CHDIR,        "chdir",        NULL_MAP },
  117.     { C_VAR_SET,    "variable",        NULL_MAP },
  118.     { C_IGNORE,        "ignore",        NULL_MAP },
  119.     { C_ALIAS,        "alias",        NULL_MAP },
  120.     { C_OWN_HDR,    "my hdrs",        NULL_MAP },
  121.     { C_VERSION,    "version",        NULL_MAP },
  122.     { C_MAIL_FLAGS,    "mail flags",        NULL_MAP },
  123.     { C_MAIL,        "mail",            NULL_MAP },
  124.     { C_REPLY_SENDER,    "reply",        NULL_MAP },
  125.     { C_REPLY_ALL,    "reply all",        NULL_MAP },
  126.     { C_DISPLAY_MSG,    "display",        NULL_MAP },
  127.     { C_TOP_MSG,    "top",            NULL_MAP },
  128.     { C_DISPLAY_NEXT,    "display next",        NULL_MAP },
  129.     { C_BIND,        "bind",            NULL_MAP },
  130.     { C_UNBIND,        "unbind",        NULL_MAP },
  131.     { C_HELP,        "help",            NULL_MAP }
  132. };
  133.  
  134. getcmd()
  135. {
  136.     char         buf[MAX_BIND_LEN];
  137.     register int     c, m, match;
  138.     register char    *p = buf;
  139.     register struct cmd_map *list;
  140.  
  141.     bzero(buf, MAX_BIND_LEN);
  142.     c = getchar();
  143.     /* If user did job control (^Z), then the interrupt flag will be
  144.      * set.  Be sure it's unset before continuing.
  145.      */
  146.     turnoff(glob_flags, WAS_INTR);
  147.     if (isdigit(c)) {
  148.     (void) ungetc(c, stdin);
  149.     return C_GOTO_MSG;
  150.     }
  151.     for (;; p += strlen(p), c = getchar()) {
  152.     if (c == ESC)
  153.         (void) strcpy(buf, "\\E");
  154.     else if (c == '\n' || c == '\r')
  155.         (void) strcpy(p, "\\n");
  156.     else if (c == '\t')
  157.         (void) strcpy(p, "\\t");
  158.     else if (iscntrl(c))
  159.         (void) sprintf(p, "\\C%c", upper(unctrl(c)[1]));
  160.     else
  161.         *p = c;
  162.     m = 0;
  163.     for (list = cmd_map; list; list = list->m_next)
  164.         if ((match = prefix(buf, list->m_str)) == MATCH) {
  165.         if (debug)
  166.             print("\"%s\" ", map_func_names[list->m_cmd].m_str);
  167.         return list->m_cmd;
  168.         } else if (match != NO_MATCH)
  169.         m++;
  170.     if (m == 0) {
  171.         if (debug)
  172.         print("No binding for \"%s\" found.", buf);
  173.         return C_NULL;
  174.     }
  175.     }
  176. }
  177.  
  178. /*
  179.  * bind chars or strings to commands -- doesn't touch messages; return -1
  180.  * for curses mode, return -2 to have curses command set CNTD_CMD to
  181.  * prevent screen refresh to allow user to read output in case of multilines.
  182.  */
  183. bind_it(len, argv)
  184. char **argv;
  185. {
  186.     char buf[MAX_BIND_LEN], buf2[256];
  187.     register int x;
  188.     int (*oldint)(), (*oldquit)();
  189.     int unbind = (argv && **argv == 'u');
  190.     int ret = -1; /* return value */
  191.  
  192.     if (argv && *++argv && !strcmp(*argv, "-?"))
  193.     return help(0, "bind", cmd_help) - 1;
  194.  
  195.     if (iscurses)
  196.     on_intr();
  197.  
  198.     if (unbind) {
  199.     if (!*argv) {
  200.         print("Unbind what? ");
  201.         if (Getstr(buf, MAX_BIND_LEN-1, 0) <= 0) {
  202.         if (iscurses)
  203.             off_intr();
  204.         return -1;
  205.         }
  206.     } else
  207.         (void) strcpy(buf, *argv);
  208.     if (!un_bind(buf))
  209.         print("\"%s\" isn't bound to a command.\n", buf);
  210.     if (iscurses)
  211.         off_intr();
  212.     return -1;
  213.     }
  214.     if (argv && *argv) {
  215.     (void) strncpy(buf, *argv, MAX_BIND_LEN-1);
  216.     if (!argv[1]) {
  217.         int binding = c_bind(*argv);
  218.         if (binding)
  219.         print("\"%s\" is bound to \"%s\".\n",
  220.             *argv, map_func_names[binding].m_str);
  221.         else
  222.         print("\"%s\" isn't bound to a command.\n", *argv);
  223.         if (iscurses)
  224.         off_intr();
  225.         return -1;
  226.     } else
  227.         argv++;
  228.     } else {
  229.     extern char *_unctrl[];
  230.     register char *p, *p2 = buf2;
  231.  
  232.     print("bind [<CR>=all, -?=help]: ");
  233.     if ((len = Getstr(buf, MAX_BIND_LEN-1, 0)) == 0) {
  234.         if (iscurses)
  235.         putchar('\n');
  236.         (void) c_bind(NULL);
  237.         if (iscurses)
  238.         off_intr();
  239.         return -2;
  240.     }
  241.     if (len < 0) {
  242.         if (iscurses)
  243.         off_intr();
  244.         return -1;
  245.     }
  246.     /* If user typed control chars, convert them to the \Cx format. */
  247.     for (p = buf; *p; p++)
  248.         if (*p == '\n' || *p == '\r')
  249.         *p2++ = '\\', *p2++ = 'n';
  250.         else if (*p == '\t')
  251.         *p2++ = '\\', *p2++ = 't';
  252.         else if (*p == ESC)
  253.         *p2++ = '\\', *p2++ = 'E';
  254.         else if (iscntrl(*p))
  255.         *p2++ = '\\', *p2++ = 'C', *p2++ = _unctrl[*p][1];
  256.         else
  257.         *p2++ = *p;
  258.     *p2 = 0;
  259.     (void) strcpy(buf, buf2);
  260.     }
  261.     /* if a binding was given on the command line */
  262.     if (argv && *argv)
  263.     (void) argv_to_string(buf2, argv);
  264.     else {
  265.     int binding;
  266.     
  267.     if (!strcmp(buf, "-?")) {
  268.         if (iscurses)
  269.         clr_bot_line();
  270.         (void) help(0, "bind", cmd_help);
  271.         if (iscurses)
  272.         off_intr();
  273.         return -2;
  274.     }
  275.  
  276.     binding = c_bind(buf);
  277.  
  278.     for (len = 0; len == 0; ) {
  279.         print("\"%s\" = <%s>: New function [<CR> for list]: ",
  280.         buf, (binding? map_func_names[binding].m_str : "unset"));
  281.         len = Getstr(buf2, 29, 0);
  282.         if (iscurses)
  283.         clr_bot_line();
  284.         if (len == 0) {
  285.         char *maps[C_HELP+1], *p, *malloc();
  286.         int n = 0;
  287.  
  288.         if (iscurses)
  289.             putchar('\n');
  290.         for (x = 0; x < C_HELP; x++) {
  291.             if (!(x % 4))
  292.             if (!(p = maps[n++] = malloc(81))) {
  293.                 error("malloc in bind()");
  294.                 free_vec(maps);
  295.                 if (iscurses)
  296.                 off_intr();
  297.                 return -1;
  298.             }
  299.             p += strlen(sprintf(p, "%-18.18s  ",
  300.                     map_func_names[x+1].m_str));
  301.         }
  302.         maps[n] = NULL;
  303.         (void) help(0, maps, NULL);
  304.         free_vec(maps);
  305.         ret--;
  306.         }
  307.     }
  308.     /* if list was printed, ret < -1 -- tells CNTD_CMD to be set and
  309.      * prevents screen from being refreshed (lets user read output
  310.      */
  311.     if (len == -1) {
  312.         if (iscurses)
  313.         off_intr();
  314.         return ret;
  315.     }
  316.     }
  317.     for (x = 1; x <= C_HELP; x++)
  318.     if (!strcmp(buf2, map_func_names[x].m_str)) {
  319.         int add_to_ret;
  320.         if (debug)
  321.         print("\"%s\" will execute \"%s\".\n", buf, buf2);
  322.         add_to_ret = do_bind(buf, map_func_names[x].m_cmd);
  323.         /* if do_bind hda no errors, it returned -1.  If we already
  324.          * messed up the screen, then ret is less than -1.  return the
  325.          * lesser of the two to make sure that CNTD_CMD gets set right
  326.          */
  327.         if (iscurses)
  328.         off_intr();
  329.         return min(add_to_ret, ret);
  330.     }
  331.     print("\"%s\": Unknown function.\n", buf2);
  332.     if (iscurses)
  333.     off_intr();
  334.     return ret;
  335. }
  336.  
  337. /*
  338.  * print current key to command bindings if "str" is NULL.
  339.  * else return the integer "m_cmd" which the str is bound to.
  340.  */
  341. c_bind(str)
  342. register char *str;
  343. {
  344.     register struct cmd_map *opts;
  345.     register int    incurses = iscurses;
  346.     char buf[128]; /* these lines can't get very long */
  347.  
  348.     if (!str) {
  349.     if (incurses)
  350.         clr_bot_line(), iscurses = FALSE;
  351.     (void) do_pager(NULL, TRUE);
  352.     (void) do_pager("Current key to command bindings:\n\n", FALSE);
  353.     }
  354.  
  355.     for (opts = cmd_map; opts; opts = opts->m_next)
  356.     if (!str) {
  357.         if (do_pager(sprintf(buf, "%-20.20s %s\n",
  358.              opts->m_str, map_func_names[opts->m_cmd].m_str),
  359.              FALSE) == EOF)
  360.         break;
  361.     } else
  362.         if (strcmp(str, opts->m_str))
  363.         continue;
  364.         else if (opts->m_cmd)
  365.         return opts->m_cmd;
  366.         else
  367.         return 0;
  368.     iscurses = incurses;
  369.     if (str)
  370.     (void) do_pager(NULL, FALSE);
  371.     return 0;
  372. }
  373.  
  374. /*
  375.  * doesn't touch messages: return -1.  Error output causes return < -1.
  376.  */
  377. do_bind(str, func)
  378. register char *str;
  379. {
  380.     register struct cmd_map *list;
  381.     register int match, ret = -1;
  382.  
  383.     (void) un_bind(str);
  384.     for (list = cmd_map; list; list = list->m_next)
  385.     if ((match = prefix(str, list->m_str)) == MATCH)
  386.         puts("Something impossible just happened."), ret--;
  387.     else if (match == A_PREFIX_B)
  388.         printf("Warning: \"%s\" prefixes \"%s\" (%s)\n",
  389.         str, list->m_str, map_func_names[list->m_cmd].m_str), ret--;
  390.     else if (match == B_PREFIX_A)
  391.         printf("Warning: \"%s\" (%s) prefixes: \"%s\"\n",
  392.         list->m_str, map_func_names[list->m_cmd].m_str, str), ret--;
  393.     add_bind(str, func);
  394.     /* errors decrement ret.  If ret returns less than -1, CNTD_CMD is set
  395.      * and no redrawing is done so user can see the warning signs
  396.      */
  397.     return ret;
  398. }
  399.  
  400. add_bind(str, func)
  401. register char *str;
  402. {
  403.     register struct cmd_map *tmp;
  404.     struct cmd_map *calloc();
  405.  
  406.     /* now make a new option struct and set fields */
  407.     if (!(tmp = calloc((unsigned)1, sizeof(struct cmd_map)))) {
  408.     error("calloc");
  409.     return;
  410.     }
  411.     tmp->m_next = cmd_map;
  412.     cmd_map = tmp;
  413.  
  414.     tmp->m_str = savestr(str);
  415.     tmp->m_cmd = func; /* strdup handles the NULL case */
  416. }
  417.  
  418. un_bind(p)
  419. register char *p;
  420. {
  421.     register struct cmd_map *list = cmd_map, *tmp;
  422.  
  423.     if (!list || !*list->m_str || !p || !*p)
  424.     return 0;
  425.  
  426.     if (!strcmp(p, cmd_map->m_str)) {
  427.     cmd_map = cmd_map->m_next;
  428.     xfree (list->m_str);
  429.     xfree((char *)list);
  430.     return 1;
  431.     }
  432.     for ( ; list->m_next; list = list->m_next)
  433.     if (!strcmp(p, list->m_next->m_str)) {
  434.         tmp = list->m_next;
  435.         list->m_next = list->m_next->m_next;
  436.         xfree (tmp->m_str);
  437.         xfree ((char *)tmp);
  438.         return 1;
  439.     }
  440.     return 0;
  441. }
  442.  
  443. prefix(a, b)
  444. register char *a, *b;
  445. {
  446.     while (*a && *b && *a == *b)
  447.     a++, b++;
  448.     if (!*a && !*b)
  449.     return MATCH;
  450.     if (!*a && *b)
  451.     return A_PREFIX_B;
  452.     if (*a && !*b)
  453.     return B_PREFIX_A;
  454.     return NO_MATCH;
  455. }
  456. #endif /* CURSES */
  457.