home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume11 / mush5.7 / part12 / bind.c next >
Encoding:
C/C++ Source or Header  |  1987-09-19  |  11.2 KB  |  436 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 (isdigit(c)) {
  144.     (void) ungetc(c, stdin);
  145.     return C_GOTO_MSG;
  146.     }
  147.     for (;; p += strlen(p), c = getchar()) {
  148.     if (c == ESC)
  149.         (void) strcpy(buf, "\\E");
  150.     else if (c == '\n' || c == '\r')
  151.         (void) strcpy(p, "\\n");
  152.     else if (c == '\t')
  153.         (void) strcpy(p, "\\t");
  154.     else if (iscntrl(c))
  155.         (void) sprintf(p, "\\C%c", upper(unctrl(c)[1]));
  156.     else
  157.         *p = c;
  158.     m = 0;
  159.     for (list = cmd_map; list; list = list->m_next)
  160.         if ((match = prefix(buf, list->m_str)) == MATCH) {
  161.         if (debug)
  162.             print("\"%s\" ", map_func_names[list->m_cmd].m_str);
  163.         return list->m_cmd;
  164.         } else if (match != NO_MATCH)
  165.         m++;
  166.     if (m == 0) {
  167.         if (debug)
  168.         print("No binding for \"%s\" found.", buf);
  169.         return 0;
  170.     }
  171.     }
  172. }
  173.  
  174. /*
  175.  * bind chars or strings to commands -- doesn't touch messages; return -1
  176.  * for curses mode, return -2 to have curses command set cntd_cmd to
  177.  * prevent screen refresh to allow user to read output in case of multilines.
  178.  */
  179. bind_it(len, argv)
  180. char **argv;
  181. {
  182.     char buf[MAX_BIND_LEN], buf2[30];
  183.     register int x;
  184.     int (*oldint)(), (*oldquit)();
  185.     int unbind = (argv && **argv == 'u');
  186.     int ret = -1; /* return value */
  187.  
  188.     if (istool > 1 || argv && *++argv && !strcmp(*argv, "-?"))
  189.     return help(0, "bind", cmd_help) - 1;
  190.  
  191.     on_intr();
  192.  
  193.     if (unbind) {
  194.     if (!*argv) {
  195.         print("Unbind what? ");
  196.         if (Getstr(buf, MAX_BIND_LEN-1, 0) <= 0) {
  197.         off_intr();
  198.         return -1;
  199.         }
  200.     } else
  201.         (void) strcpy(buf, *argv);
  202.     if (!un_bind(buf))
  203.         print("\"%s\" isn't bound to a command.\n", buf);
  204.     off_intr();
  205.     return -1;
  206.     }
  207.     if (argv && *argv) {
  208.     (void) strncpy(buf, *argv, MAX_BIND_LEN-1);
  209.     if (!argv[1]) {
  210.         int binding = c_bind(*argv);
  211.         if (binding)
  212.         print("\"%s\" is bound to \"%s\".\n",
  213.             *argv, map_func_names[binding].m_str);
  214.         else
  215.         print("\"%s\" isn't bound to a command.\n", *argv);
  216.         off_intr();
  217.         return -1;
  218.     } else
  219.         argv++;
  220.     } else {
  221.     print("bind [<CR>=all, -?=help]: ");
  222.     if ((len = Getstr(buf, MAX_BIND_LEN-1, 0)) == 0) {
  223.         if (iscurses)
  224.         putchar('\n');
  225.         (void) c_bind(NULL);
  226.         off_intr();
  227.         return -2;
  228.     }
  229.     if (len < 0) {
  230.         off_intr();
  231.         return -1;
  232.     }
  233.     }
  234.     /* if a binding was given on the command line */
  235.     if (argv && *argv)
  236.     (void) argv_to_string(buf2, argv);
  237.     else {
  238.     int binding;
  239.     
  240.     if (!strcmp(buf, "-?")) {
  241.         if (iscurses)
  242.         clr_bot_line();
  243.         (void) help(0, "bind", cmd_help);
  244.         off_intr();
  245.         return -2;
  246.     }
  247.  
  248.     binding = c_bind(buf);
  249.  
  250.     for (len = 0; len == 0; ) {
  251.         print("\"%s\" = <%s>: New function [<CR> for list]: ",
  252.         buf, (binding? map_func_names[binding].m_str : "unset"));
  253.         len = Getstr(buf2, 29, 0);
  254.         if (iscurses)
  255.         clr_bot_line();
  256.         if (len == 0) {
  257.         char *maps[C_HELP+1], *p, *malloc();
  258.         int n = 0;
  259.  
  260.         if (iscurses)
  261.             putchar('\n');
  262.         for (x = 0; x < C_HELP; x++) {
  263.             if (!(x % 4))
  264.             if (!(p = maps[n++] = malloc(81))) {
  265.                 error("malloc in bind()");
  266.                 free_vec(maps);
  267.                 off_intr();
  268.                 return -1;
  269.             }
  270.             p += strlen(sprintf(p, "%-18.18s  ",
  271.                     map_func_names[x+1].m_str));
  272.         }
  273.         maps[n] = NULL;
  274.         (void) help(0, maps, NULL);
  275.         free_vec(maps);
  276.         ret--;
  277.         }
  278.     }
  279.     /* if list was printed, ret < -1 -- tells cntd_cmd to be set and
  280.      * prevents screen from being refreshed (lets user read output
  281.      */
  282.     if (len == -1) {
  283.         off_intr();
  284.         return ret;
  285.     }
  286.     }
  287.     for (x = 1; x <= C_HELP; x++)
  288.     if (!strcmp(buf2, map_func_names[x].m_str)) {
  289.         int add_to_ret;
  290.         if (debug)
  291.         print("\"%s\" will execute \"%s\".\n", buf, buf2);
  292.         add_to_ret = do_bind(buf, map_func_names[x].m_cmd);
  293.         /* if do_bind hda no errors, it returned -1.  If we already
  294.          * messed up the screen, then ret is less than -1.  return the
  295.          * lesser of the two to make sure that cntd_cmd gets set right
  296.          */
  297.         off_intr();
  298.         return min(add_to_ret, ret);
  299.     }
  300.     print("\"%s\": Unknown function.\n", buf2);
  301.     off_intr();
  302.     return ret;
  303. }
  304.  
  305. /*
  306.  * print current key to command bindings if "str" is NULL.
  307.  * else return the integer "m_cmd" which the str is bound to.
  308.  */
  309. c_bind(str)
  310. register char *str;
  311. {
  312.     register struct cmd_map *opts;
  313.     register int    incurses = iscurses;
  314.     register FILE   *pp = NULL_FILE;
  315.  
  316.     if (!str && !istool) {
  317.     echo_on();
  318.     if (!(pp = popen(pager, "w")))
  319.         error(pager);
  320.     else if (incurses)
  321.         clr_bot_line(), iscurses = FALSE;
  322.     turnon(glob_flags, IGN_SIGS);
  323.     if (pp)
  324.         fprintf(pp, "Current key to command bindings:\n\n");
  325.     else
  326.         wprint("Current key to command bindings:\n\n");
  327.     }
  328.  
  329.     for (opts = cmd_map; opts; opts = opts->m_next)
  330.     if (!str)
  331.         if (pp)
  332.         fprintf(pp, "%-20.20s %s\n",
  333.             opts->m_str, map_func_names[opts->m_cmd].m_str);
  334.         else
  335.         wprint("%-20.20s %s\n",
  336.             opts->m_str, map_func_names[opts->m_cmd].m_str);
  337.     else
  338.         if (strcmp(str, opts->m_str))
  339.         continue;
  340.         else if (opts->m_cmd)
  341.         return opts->m_cmd;
  342.         else
  343.         return 0;
  344.     if (pp)
  345.     (void) pclose(pp);
  346.     if (incurses)
  347.     iscurses = TRUE;
  348.     echo_off();
  349.     turnoff(glob_flags, IGN_SIGS);
  350.     return 0;
  351. }
  352.  
  353. /*
  354.  * doesn't touch messages: return -1.  Error output causes return < -1.
  355.  */
  356. do_bind(str, func)
  357. register char *str;
  358. {
  359.     register struct cmd_map *list;
  360.     register int match, ret = -1;
  361.  
  362.     (void) un_bind(str);
  363.     for (list = cmd_map; list; list = list->m_next)
  364.     if ((match = prefix(str, list->m_str)) == MATCH)
  365.         puts("Something impossible just happened."), ret--;
  366.     else if (match == A_PREFIX_B)
  367.         printf("Warning: \"%s\" prefixes \"%s\" (%s)\n",
  368.         str, list->m_str, map_func_names[list->m_cmd].m_str), ret--;
  369.     else if (match == B_PREFIX_A)
  370.         printf("Warning: \"%s\" (%s) prefixes: \"%s\"\n",
  371.         list->m_str, map_func_names[list->m_cmd].m_str, str), ret--;
  372.     add_bind(str, func);
  373.     /* errors decrement ret.  If ret returns less than -1, cntd_cmd is set
  374.      * and no redrawing is done so user can see the warning signs
  375.      */
  376.     return ret;
  377. }
  378.  
  379. add_bind(str, func)
  380. register char *str;
  381. {
  382.     register struct cmd_map *tmp;
  383.     struct cmd_map *calloc();
  384.  
  385.     /* now make a new option struct and set fields */
  386.     if (!(tmp = calloc((unsigned)1, sizeof(struct cmd_map)))) {
  387.     error("calloc");
  388.     return;
  389.     }
  390.     tmp->m_next = cmd_map;
  391.     cmd_map = tmp;
  392.  
  393.     tmp->m_str = savestr(str);
  394.     tmp->m_cmd = func; /* strdup handles the NULL case */
  395. }
  396.  
  397. un_bind(p)
  398. register char *p;
  399. {
  400.     register struct cmd_map *list = cmd_map, *tmp;
  401.  
  402.     if (!list || !*list->m_str || !p || !*p)
  403.     return 0;
  404.  
  405.     if (!strcmp(p, cmd_map->m_str)) {
  406.     cmd_map = cmd_map->m_next;
  407.     xfree (list->m_str);
  408.     xfree((char *)list);
  409.     return 1;
  410.     }
  411.     for ( ; list->m_next; list = list->m_next)
  412.     if (!strcmp(p, list->m_next->m_str)) {
  413.         tmp = list->m_next;
  414.         list->m_next = list->m_next->m_next;
  415.         xfree (tmp->m_str);
  416.         xfree ((char *)tmp);
  417.         return 1;
  418.     }
  419.     return 0;
  420. }
  421.  
  422. prefix(a, b)
  423. register char *a, *b;
  424. {
  425.     while (*a && *b && *a == *b)
  426.     a++, b++;
  427.     if (!*a && !*b)
  428.     return MATCH;
  429.     if (!*a && *b)
  430.     return A_PREFIX_B;
  431.     if (*a && !*b)
  432.     return B_PREFIX_A;
  433.     return NO_MATCH;
  434. }
  435. #endif CURSES
  436.