home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / zle_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  22.4 KB  |  990 lines

  1. /*
  2.  *
  3.  * zle_main.c - main routines for line editor
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #define ZLEGLOBALS
  22. #define ZLE
  23. #include "zsh.h"
  24. #include <sys/types.h>
  25. #include <errno.h>
  26. #ifdef HAS_SYS_SELECT
  27. #include <sys/select.h>
  28. #endif
  29.  
  30. static int emacs_cur_bindtab[256], eofchar, eofsent;
  31. int viins_cur_bindtab[256], ungetok; /* needed in zle_hist */
  32.  
  33. /* hash table containing the zle multi-character bindings */
  34.  
  35. static Hashtab xbindtab, vi_xbindtab, em_xbindtab;
  36.  
  37. static Key cky;
  38.  
  39. /* set up terminal */
  40.  
  41. void setterm()
  42. {                /**/
  43.     struct ttyinfo ti;
  44.  
  45. #if defined(CLOBBERS_TYPEAHEAD) && defined(FIONREAD)
  46.     int val;
  47.     ioctl(SHTTY, FIONREAD, (char *) &val);
  48.     if (val)
  49.     return;
  50. #endif
  51.  
  52. /* sanitize the tty */
  53. #ifdef HAS_TIO
  54.     shttyinfo.tio.c_lflag |= ICANON | ECHO;
  55. #ifdef FLUSHO
  56.     shttyinfo.tio.c_lflag &= ~FLUSHO;
  57. #endif
  58. #else /* not HAS_TIO */
  59.     shttyinfo.sgttyb.sg_flags = (shttyinfo.sgttyb.sg_flags & ~CBREAK) | ECHO;
  60.     shttyinfo.lmodes &= ~LFLUSHO;
  61. #endif
  62.  
  63.     attachtty(mypgrp);
  64.     ti = shttyinfo;
  65. #ifdef HAS_TIO
  66.     if (isset(NOFLOWCONTROL))
  67.     ti.tio.c_iflag &= ~IXON;
  68.     ti.tio.c_lflag &= ~(ICANON | ECHO
  69. #ifdef FLUSHO
  70.             | FLUSHO
  71. #endif
  72.     );
  73. #ifdef TAB3
  74.     ti.tio.c_oflag &= ~TAB3;
  75. #else
  76. #ifdef OXTABS
  77.     ti.tio.c_oflag &= ~OXTABS;
  78. #else
  79.     ti.tio.c_oflag &= ~XTABS;
  80. #endif
  81. #endif
  82.     ti.tio.c_oflag |= ONLCR;
  83.     ti.tio.c_cc[VQUIT] =
  84. #ifdef VDISCARD
  85.     ti.tio.c_cc[VDISCARD] =
  86. #endif
  87. #ifdef VSUSP
  88.     ti.tio.c_cc[VSUSP] =
  89. #endif
  90. #ifdef VDSUSP
  91.     ti.tio.c_cc[VDSUSP] =
  92. #endif
  93. #ifdef VSWTCH
  94.     ti.tio.c_cc[VSWTCH] =
  95. #endif
  96. #ifdef VLNEXT
  97.     ti.tio.c_cc[VLNEXT] =
  98. #endif
  99.     VDISABLEVAL;
  100. #if defined(VSTART) && defined(VSTOP)
  101.     if (isset(NOFLOWCONTROL))
  102.     ti.tio.c_cc[VSTART] = ti.tio.c_cc[VSTOP] = VDISABLEVAL;
  103. #endif
  104.     eofchar = ti.tio.c_cc[VEOF];
  105.     ti.tio.c_cc[VMIN] = 1;
  106.     ti.tio.c_cc[VTIME] = 0;
  107.     ti.tio.c_iflag |= (INLCR | ICRNL);
  108.      /* this line exchanges \n and \r; it's changed back in getkey
  109.     so that the net effect is no change at all inside the shell.
  110.     This double swap is to allow typeahead in common cases, eg.
  111.  
  112.     % bindkey -s '^J' 'echo foo^M'
  113.     % sleep 10
  114.     echo foo<return>  <--- typed before sleep returns
  115.  
  116.     The shell sees \n instead of \r, since it was changed by the kernel
  117.     while zsh wasn't looking. Then in getkey() \n is changed back to \r,
  118.     and it sees "echo foo<accept line>", as expected. Without the double
  119.     swap the shell would see "echo foo\n", which is translated to
  120.     "echo fooecho foo<accept line>" because of the binding.
  121.     Note that if you type <line-feed> during the sleep the shell just sees
  122.     \n, which is translated to \r in getkey(), and you just get another
  123.     prompt. For type-ahead to work in ALL cases you have to use
  124.     stty inlcr.
  125.     This workaround is due to Sven Wischnowsky <oberon@cs.tu-berlin.de>.
  126.  
  127.     Unfortunately it's IMPOSSIBLE to have a general solution if both
  128.     <return> and <line-feed> are mapped to the same character. The shell
  129.     could check if there is input and read it before setting it's own
  130.     terminal modes but if we get a \n we don't know whether to keep it or
  131.     change to \r :-(
  132.     */
  133.  
  134. #else /* not HAS_TIO */
  135.     ti.sgttyb.sg_flags = (ti.sgttyb.sg_flags | CBREAK) & ~ECHO & ~XTABS;
  136.     ti.lmodes &= ~LFLUSHO;
  137.     eofchar = ti.tchars.t_eofc;
  138.     ti.tchars.t_quitc =
  139.     ti.ltchars.t_suspc =
  140.     ti.ltchars.t_flushc =
  141.     ti.ltchars.t_dsuspc = ti.ltchars.t_lnextc = -1;
  142. #endif
  143.  
  144. #if defined(TTY_NEEDS_DRAINING) && defined(TIOCOUTQ) && defined(HAS_SELECT)
  145. /* this is mostly stolen from bash's draino() */
  146.     if (baud) {                /**/
  147.     int n = 0;
  148.  
  149.     while ((ioctl(SHTTY, TIOCOUTQ, (char *) &n) >= 0) && n) {
  150.         struct timeval tv;
  151.  
  152.         tv.tv_sec = n / baud;
  153.         tv.tv_usec = ((n % baud) * 1000000) / baud;
  154.         select(0, NULL, NULL, NULL, &tv);
  155.     }
  156.     }
  157. #endif
  158.  
  159.     settyinfo(&ti);
  160. }
  161.  
  162. static char *kungetbuf;
  163. static int kungetct, kungetsz;
  164.  
  165. void ungetkey(ch)        /**/
  166. int ch;
  167. {
  168.     if (kungetct == kungetsz)
  169.     kungetbuf = realloc(kungetbuf, kungetsz *= 2);
  170.     kungetbuf[kungetct++] = ch;
  171. }
  172.  
  173. void ungetkeys(s, len)        /**/
  174. char *s;
  175. int len;
  176. {
  177.     s += len;
  178.     while (len--)
  179.     ungetkey(*--s);
  180. }
  181.  
  182. #if defined(pyr) && defined(HAS_SELECT)
  183. static int breakread(fd, buf, n)
  184. int fd, n;
  185. char *buf;
  186. {
  187.     fd_set f;
  188.  
  189.     FD_ZERO(&f);
  190.     FD_SET(fd, &f);
  191.     return (select(fd + 1, (SELECT_ARG_2_T) &f, NULL, NULL, NULL) == -1 ? 
  192.         EOF : read(fd, buf, n));
  193. }
  194.  
  195. #define read    breakread
  196. #endif
  197.  
  198. int getkey(keytmout)    /**/
  199. int keytmout;
  200. {
  201.     char cc;
  202.     unsigned int ret;
  203.     long exp100ths;
  204.     int die = 0, r;
  205.     int old_errno = errno;
  206. #ifdef HAS_SELECT
  207.     fd_set foofd;
  208. #else
  209. #ifdef HAS_TIO
  210.     struct ttyinfo ti;
  211. #endif
  212. #endif
  213.  
  214.     if (kungetct)
  215.     ret = (int)(unsigned char)kungetbuf[--kungetct];
  216.     else {
  217.     if (keytmout) {
  218.         if (keytimeout > 500)
  219.         exp100ths = 500;
  220.         else if (keytimeout > 0)
  221.         exp100ths = keytimeout;
  222.         else
  223.         exp100ths = 0;
  224. #ifdef HAS_SELECT
  225.         if (exp100ths) {
  226.         struct timeval expire_tv;
  227.  
  228.         expire_tv.tv_sec = exp100ths / 100;
  229.         expire_tv.tv_usec = (exp100ths % 100) * 10000L;
  230.         FD_ZERO(&foofd);
  231.         FD_SET(0, &foofd);
  232.         if (select(1, (SELECT_ARG_2_T)&foofd, NULL, NULL, &expire_tv) <= 0)
  233.             return EOF;
  234.         }
  235. #else
  236. #ifdef HAS_TIO
  237.         ti = shttyinfo;
  238.         ti.tio.c_lflag &= ~ICANON;
  239.         ti.tio.c_cc[VMIN] = 0;
  240.         ti.tio.c_cc[VTIME] = exp100ths / 10;
  241.         ioctl(SHTTY, TCSETA, &ti.tio);
  242.         r = read(0, &cc, 1);
  243.         ioctl(SHTTY, TCSETA, &shttyinfo.tio);
  244.         return (r <= 0) ? -1 : cc;
  245. #endif
  246. #endif
  247.     }
  248.         while ((r = read(0, &cc, 1)) != 1) {
  249.         if (r == 0) {
  250.         stopmsg = 1;
  251.         zexit(1);
  252.         }
  253.         if (errno == EINTR) {
  254.         die = 0;
  255.         if (!errflag)
  256.             continue;
  257.         errflag = 0;
  258.         errno = old_errno;
  259.         return EOF;
  260.         } else if (errno == EWOULDBLOCK) {
  261.         fcntl(0, F_SETFL, 0);
  262.         } else if (errno == EIO && !die) {
  263.         ret = jobbingv;
  264.         jobbingv = OPT_SET;
  265.         attachtty(mypgrp);
  266.         refresh();    /* kludge! */
  267.         jobbingv = ret;
  268.         die = 1;
  269.         } else if (errno != 0) {
  270.         zerr("error on TTY read: %e", NULL, errno);
  271.         stopmsg = 1;
  272.         zexit(1);
  273.         }
  274.     }
  275.     if (cc == '\r')    /* undo the exchange of \n and \r determined by */
  276.         cc = '\n';    /* setterm() */
  277.     else if (cc == '\n')
  278.         cc = '\r';
  279.  
  280.     ret = (int)(unsigned char)cc;
  281.     }
  282.     if (vichgflag) {
  283.     if (vichgbufptr == vichgbufsz)
  284.         vichgbuf = realloc(vichgbuf, vichgbufsz *= 2);
  285.     vichgbuf[vichgbufptr++] = ret;
  286.     }
  287.     errno = old_errno;
  288.     return ret;
  289. }
  290.  
  291. /* read a line */
  292.  
  293. unsigned char *zleread(ppt, ppt2, plen, p2len)    /**/
  294. unsigned char *ppt;
  295. unsigned char *ppt2;
  296. int plen;
  297. int p2len;
  298. {
  299.     int z;
  300.     unsigned char *s;
  301.     int old_errno = errno;
  302. #ifdef HAS_SELECT
  303.     long costmult = (baud) ? 3840000L /  baud : 0;
  304.     struct timeval tv;
  305.     fd_set foofd;
  306.     tv.tv_sec = 0;
  307. #endif
  308.  
  309.     fflush(stdout);
  310.     fflush(stderr);
  311.     intr();
  312.     insmode = unset(OVERSTRIKE);
  313.     eofsent = 0;
  314.     resetneeded = 0;
  315.     pmpt = (char *)ppt;
  316.     pmpt2 = (char *)ppt2;
  317.     pptlen = plen;
  318.     ppt2len = p2len;
  319.     permalloc();
  320.     histline = curhist;
  321. #ifdef HAS_SELECT
  322.     FD_ZERO(&foofd);
  323. #endif
  324.     undoing = 1;
  325.     line = (unsigned char *)zalloc((linesz = 256) + 1);
  326.     *line = '\0';
  327.     virangeflag = lastcmd = done = cs = ll = mark = 0;
  328.     curhistline = NULL;
  329.     mult = 1;
  330.     vibufspec = 0;
  331.     bindtab = mainbindtab;
  332.     addedsuffix = complexpect = vichgflag = 0;
  333.     viinsbegin = 0;
  334.     statusline = NULL;
  335.     if ((s = (unsigned char *)getnode(bufstack))) {
  336.     setline((char *)s);
  337.     zsfree((char *)s);
  338.     if (stackcs != -1) {
  339.         cs = stackcs;
  340.         stackcs = -1;
  341.         if (cs > ll)
  342.         cs = ll;
  343.     }
  344.     if (stackhist != -1) {
  345.         histline = stackhist;
  346.         stackhist = -1;
  347.     }
  348.     }
  349.     initundo();
  350.     if (unset(NOPROMPTCR))
  351.     putchar('\r');
  352.     if (tmout)
  353.     alarm(tmout);
  354.     zleactive = 1;
  355.     resetneeded = 1;
  356.     refresh();
  357.     errflag = retflag = 0;
  358.     while (!done && !errflag) {
  359.     struct zlecmd *zc;
  360.  
  361.     statusline = NULL;
  362.     bindk = getkeycmd();
  363.     if (!ll && c == eofchar) {
  364.         eofsent = 1;
  365.         break;
  366.     }
  367.     if (bindk != -1) {
  368.         int ce = complexpect;
  369.  
  370.         zc = zlecmds + bindk;
  371.         if (!(lastcmd & ZLE_ARG))
  372.         mult = 1;
  373.         if ((lastcmd & ZLE_UNDO) != (zc->flags & ZLE_UNDO) && undoing)
  374.         addundo();
  375.         if (bindk != z_sendstring) {
  376.         if (!(zc->flags & ZLE_MENUCMP) && menucmp)
  377.             menucmp = 0;
  378.         if (!(zc->flags & ZLE_MENUCMP) &&
  379.             addedsuffix && !(zc->flags & ZLE_DELETE) &&
  380.             !((zc->flags & ZLE_INSERT) && c != ' ')) {
  381.             backdel(addedsuffix);
  382.         }
  383.         if (!menucmp)
  384.             addedsuffix = 0;
  385.         }
  386.         if (zc->func)
  387.         (*zc->func) ();
  388.         if (ce == complexpect && ce)
  389.         complexpect = 0;
  390.         if (bindk != z_sendstring)
  391.         lastcmd = zc->flags;
  392.         if (!(lastcmd & ZLE_UNDO) && undoing)
  393.         addundo();
  394.     } else {
  395.         errflag = 1;
  396.         break;
  397.     }
  398. #ifdef HAS_SELECT
  399.     if (baud) {
  400.         FD_SET(0, &foofd);
  401.         if ((tv.tv_usec = cost * costmult) > 500000)
  402.         tv.tv_usec = 500000;
  403.         if (!kungetct && select(1, (SELECT_ARG_2_T)&foofd, NULL, NULL, &tv) <= 0)
  404.         refresh();
  405.     } else
  406. #endif
  407.         if (!kungetct)
  408.         refresh();
  409.     }
  410.     statusline = NULL;
  411.     trashzle();
  412.     zleactive = 0;
  413.     alarm(0);
  414.     z = strlen(UTOSCP(line));
  415.     line[z] = '\n';
  416.     line[z + 1] = 0;
  417.     heapalloc();
  418.     zsfree(curhistline);
  419.     if (eofsent) {
  420.     free(line);
  421.     line = NULL;
  422.     }
  423.     free(lastline);    /* freeundo */
  424.     errno = old_errno;
  425.     return line;
  426. }
  427.  
  428. int getkeycmd()        /**/
  429. {
  430.     int ret;
  431.     static int hops = 0;
  432.     cky = NULL;
  433.  
  434.     if ((c = getkey(0)) < 0)
  435.     return -1;
  436.     if ((ret = bindtab[c]) == z_sequenceleadin) {
  437.     int lastlen = 0, t0 = 1, buflen = 50;
  438.     Key ky;
  439.     char *buf;
  440.  
  441.     buf = (char *)zalloc(buflen);
  442.     ungetok = 0;
  443.     buf[0] = c, buf[1] = '\0';
  444.     if ((cky = (Key) gethnode(buf, xbindtab))->func == z_undefinedkey)
  445.         cky = NULL;
  446.     else
  447.         lastlen = 1;
  448.     if(!c)
  449.         buf[0] = (char) 0x80;
  450.     for (;;) {
  451.         if ((c = getkey(cky ? 1 : 0)) >= 0) {
  452.         if (t0 == buflen -1)
  453.             buf = (char *)realloc(buf, buflen *= 2);
  454.         buf[t0++] = (c) ? c : 0x80;
  455.         buf[t0] = '\0';
  456.         ky = (Key) gethnode(buf, xbindtab);
  457.         } else
  458.         ky = NULL;
  459.         if (ky) {
  460.         if (ky->func == z_undefinedkey)
  461.             continue;
  462.         cky = ky;
  463.         if (!ky->prefixct) {
  464.             ret = ky->func;
  465.             break;
  466.         }
  467.         lastlen = t0;
  468.         } else if (cky) {
  469.         ungetkeys(&buf[lastlen], t0 - lastlen);
  470.         ret = cky->func;
  471.         c = buf[lastlen - 1];
  472.         break;
  473.         } else
  474.         return z_undefinedkey;
  475.     }
  476.     zfree(buf, buflen);
  477.     } else
  478.     ungetok = 1; /* for doisearch() */
  479.     if (ret == z_vidigitorbeginningofline)
  480.     ret = (lastcmd & ZLE_ARG) ? z_digitargument : z_beginningofline;
  481.     else if (ret == z_executenamedcmd && !statusline)
  482.     ret = executenamedcommand();
  483.     else if (ret == z_executelastnamedcmd)
  484.     ret = lastnamed;
  485.     else if (ret == z_sendstring) {
  486. #define MAXHOPS 20
  487.     if (++hops == MAXHOPS) {
  488.         zerr("string inserting another one too many times", NULL, 0);
  489.         hops = 0;
  490.         return -1;
  491.     }
  492.     } else
  493.     hops = 0;
  494.     return ret;
  495. }
  496.  
  497. void sendstring()
  498. {                /**/
  499.     if (!cky) {
  500.     char buf[2];
  501.  
  502.     buf[0] = c;
  503.     buf[1] = '\0';
  504.     cky = (Key) gethnode(buf, xbindtab);
  505.     }
  506.     ungetkeys(cky->str, cky->len);
  507. }
  508.  
  509. Key makefunckey(fun)        /**/
  510. int fun;
  511. {
  512.     Key ky = (Key) zcalloc(sizeof *ky);
  513.  
  514.     ky->func = fun;
  515.     return ky;
  516. }
  517.  
  518. /* initialize the bindings */
  519.  
  520. void initxbindtab()
  521. {                /**/
  522.     int t0, vi = 0;
  523.     char buf[3], *s;
  524.     Key ky;
  525.  
  526.     lastnamed = z_undefinedkey;
  527.     for (t0 = 0; t0 != 32; t0++)
  528.     viins_cur_bindtab[t0] = viinsbind[t0];
  529.     for (t0 = 32; t0 != 256; t0++)
  530.     viins_cur_bindtab[t0] = z_selfinsert;
  531.     viins_cur_bindtab[127] = z_backwarddeletechar;
  532.     for (t0 = 0; t0 != 128; t0++)
  533.     emacs_cur_bindtab[t0] = emacsbind[t0];
  534.     for (t0 = 128; t0 != 256; t0++)
  535.     emacs_cur_bindtab[t0] = z_selfinsert;
  536.     em_xbindtab = newhtable(67);
  537.     vi_xbindtab = newhtable(20);
  538.     if ((s = zgetenv("VISUAL"))) {
  539.     if (ztrstr(s, "vi"))
  540.         vi = 1;
  541.     } else if ((s = zgetenv("EDITOR")) && ztrstr(s, "vi"))
  542.     vi = 1;
  543.     if (vi) {
  544.     mainbindtab = viins_cur_bindtab;
  545.     xbindtab = vi_xbindtab;
  546.     }
  547.     else {
  548.     mainbindtab = emacs_cur_bindtab;
  549.     xbindtab = em_xbindtab;
  550.     }
  551.     for (t0 = 0200; t0 != 0240; t0++)
  552.     emacs_cur_bindtab[t0] = viins_cur_bindtab[t0] = z_undefinedkey;
  553.     for (t0 = 0; t0 != 128; t0++)
  554.     altbindtab[t0] = vicmdbind[t0];
  555.     for (t0 = 128; t0 != 256; t0++)
  556.     altbindtab[t0] = emacsbind[t0];
  557.     bindtab = mainbindtab;
  558.     if (!kungetbuf)
  559.     kungetbuf = (char *)zalloc(kungetsz = 32);
  560.  
  561.     addhnode("\33\133", ky = makefunckey(z_undefinedkey), em_xbindtab, 0);
  562.     ky->prefixct = 4;
  563.     addhnode("\33\133C", makefunckey(z_forwardchar), em_xbindtab, 0);
  564.     addhnode("\33\133D", makefunckey(z_backwardchar), em_xbindtab, 0);
  565.     addhnode("\33\133A", makefunckey(z_uplineorhistory), em_xbindtab, 0);
  566.     addhnode("\33\133B", makefunckey(z_downlineorhistory), em_xbindtab, 0);
  567.     addhnode("\33", ky = makefunckey(z_vicmdmode), vi_xbindtab, 0);
  568.     ky->prefixct = 4;
  569.     addhnode("\33\133", ky = makefunckey(z_undefinedkey), vi_xbindtab, 0);
  570.     ky->prefixct = 4;
  571.     addhnode("\33\133C", makefunckey(z_forwardchar), vi_xbindtab, 0);
  572.     addhnode("\33\133D", makefunckey(z_backwardchar), vi_xbindtab, 0);
  573.     addhnode("\33\133A", makefunckey(z_uplineorhistory), vi_xbindtab, 0);
  574.     addhnode("\33\133B", makefunckey(z_downlineorhistory), vi_xbindtab, 0);
  575.     addhnode("\30", ky = makefunckey(z_undefinedkey), em_xbindtab, 0);
  576.     ky->prefixct = 15;
  577.     addhnode("\30*", makefunckey(z_expandword), em_xbindtab, (FFunc) 0);
  578.     addhnode("\30g", makefunckey(z_listexpand), em_xbindtab, (FFunc) 0);
  579.     addhnode("\30G", makefunckey(z_listexpand), em_xbindtab, (FFunc) 0);
  580.     addhnode("\30\16", makefunckey(z_infernexthistory), em_xbindtab, 0);
  581.     addhnode("\30\13", makefunckey(z_killbuffer), em_xbindtab, (FFunc) 0);
  582.     addhnode("\30\6", makefunckey(z_vifindnextchar), em_xbindtab, (FFunc) 0);
  583.     addhnode("\30\17", makefunckey(z_overwritemode), em_xbindtab, (FFunc) 0);
  584.     addhnode("\30\25", makefunckey(z_undo), em_xbindtab, (FFunc) 0);
  585.     addhnode("\30\26", makefunckey(z_vicmdmode), em_xbindtab, (FFunc) 0);
  586.     addhnode("\30\12", makefunckey(z_vijoin), em_xbindtab, (FFunc) 0);
  587.     addhnode("\30\2", makefunckey(z_vimatchbracket), em_xbindtab, (FFunc) 0);
  588.     addhnode("\30s", makefunckey(z_historyincrementalsearchforward),
  589.              em_xbindtab, (FFunc) 0);
  590.     addhnode("\30r", makefunckey(z_historyincrementalsearchbackward),
  591.              em_xbindtab, (FFunc) 0);
  592.     addhnode("\30u", makefunckey(z_undo), em_xbindtab, (FFunc) 0);
  593.     addhnode("\30\30", makefunckey(z_exchangepointandmark), em_xbindtab, 0);
  594.     addhnode("\33", ky = makefunckey(z_undefinedkey), em_xbindtab, 0);
  595.     ky->prefixct = 4;
  596.  
  597.     strcpy(buf, "\33q");
  598.     for (t0 = 128; t0 != 256; t0++)
  599.     if (emacsbind[t0] != z_undefinedkey) {
  600.         buf[1] = t0 & 0x7f;
  601.         addhnode(ztrdup(buf), makefunckey(emacsbind[t0]), em_xbindtab, 0);
  602.         ky->prefixct++;
  603.     }
  604.     stackhist = stackcs = -1;
  605. }
  606.  
  607. char *getkeystring(s, len, fromwhere, misc)    /**/
  608. char *s;
  609. int *len;
  610. int fromwhere;
  611. int *misc;
  612. {
  613.     char *buf = ((fromwhere == 2)
  614.          ? zalloc(strlen(s) + 1) : alloc(strlen(s) + 1));
  615.     char *t = buf, *u = NULL;
  616.     char svchar = '\0';
  617.     int meta = 0, control = 0;
  618.  
  619.     for (; *s; s++) {
  620.     if (*s == '\\' && s[1])
  621.         switch (*++s) {
  622.           case 'a':
  623. #ifdef __STDC__
  624.         *t++ = '\a';
  625. #else
  626.         *t++ = '\07';
  627. #endif
  628.         break;
  629.           case 'n':
  630.         *t++ = '\n';
  631.         break;
  632.           case 'b':
  633.         *t++ = '\010';
  634.         break;
  635.           case 't':
  636.         *t++ = '\t';
  637.         break;
  638.           case 'v':
  639.         *t++ = '\v';
  640.         break;
  641.           case 'f':
  642.         *t++ = '\f';
  643.         break;
  644.           case 'r':
  645.         *t++ = '\r';
  646.         break;
  647.           case 'E':
  648.         if (!fromwhere) {
  649.             *t++ ='\\', s--;
  650.             continue;
  651.         }
  652.           case 'e':
  653.         *t++ = '\033';
  654.         break;
  655.           case 'M':
  656.         if (fromwhere) {
  657.             if (s[1] == '-')
  658.             s++;
  659.             meta = 1 + control; /* preserve the order of ^ and meta */
  660.         } else
  661.             *t++ ='\\', s--;
  662.         continue;
  663.           case 'C':
  664.         if (fromwhere) {
  665.             if (s[1] == '-')
  666.             s++;
  667.             control = 1;
  668.         } else
  669.             *t++ ='\\', s--;
  670.         continue;
  671.           case 'c':
  672.         if (fromwhere < 2) {
  673.             *misc = 1;
  674.             break;
  675.         }
  676.         default:
  677.         if ((idigit(*s) && *s < '8') || *s == 'x') {
  678.             if (!fromwhere)
  679.             if (*s == '0')
  680.                 s++;
  681.             else if (*s != 'x') {
  682.                 *t++ = '\\', s--;
  683.                 continue;
  684.             }
  685.             if (s[1] && s[2] && s[3]) {
  686.             svchar = s[3];
  687.             s[3] = '\0';
  688.             u = s;
  689.             }
  690.             *t++ = zstrtol(s + (*s == 'x'), &s,
  691.                    (*s == 'x') ? 16 : 8);
  692.             if (svchar) {
  693.             u[3] = svchar;
  694.             svchar = '\0';
  695.             }
  696.             s--;
  697.         } else {
  698.             if (!fromwhere && *s != '\\')
  699.             *t++ ='\\';
  700.             *t++ = *s;
  701.         }
  702.         break;
  703.     } else if (*s == '^' && fromwhere == 2) {
  704.         control = 1;
  705.         continue;
  706.     } else
  707.         *t++ = *s;
  708.     if (meta == 2) {
  709.         t[-1] |= 0x80;
  710.         meta = 0;
  711.     }
  712.     if (control) {
  713.         if (t[-1] == '?')
  714.         t[-1] = 0x7f;
  715.         else
  716.         t[-1] &= 0x9f;
  717.         control = 0;
  718.     }
  719.     if (meta) {
  720.         t[-1] |= 0x80;
  721.         meta = 0;
  722.     }
  723.     }
  724.     *t = '\0';
  725.     *len = t - buf;
  726.     return buf;
  727. }
  728.  
  729. void printbind(s, len)        /**/
  730. char *s;
  731. int len;
  732. {
  733.     int ch;
  734.  
  735.     while (len--) {
  736.     ch = (unsigned char)*s++;
  737.     if (ch & 0x80) {
  738.         printf("\\M-");
  739.         ch &= 0x7f;
  740.     }
  741.     if (icntrl(ch))
  742.         switch (ch) {
  743.         case 0x7f:
  744.         printf("^?");
  745.         break;
  746.         default:
  747.         printf("^%c", (ch | 0x40));
  748.         break;
  749.     } else
  750.         putchar(ch);
  751.     }
  752. }
  753.  
  754. void printbinding(str, k)    /**/
  755. char *str;
  756. Key k;
  757. {
  758.     int len;
  759.  
  760.     if (k->func == z_undefinedkey)
  761.     return;
  762.     putchar('\"');
  763.     printbind(str, (len = strlen(str)) ? len : 1);
  764.     printf("\"\t");
  765.     if (k->func == z_sendstring) {
  766.     putchar('\"');
  767.     printbind(k->str, k->len);
  768.     printf("\"\n");
  769.     } else
  770.     printf("%s\n", zlecmds[k->func].name);
  771. }
  772.  
  773. int bin_bindkey(name, argv, ops, junc)    /**/
  774. char *name;
  775. char **argv;
  776. char *ops;
  777. int junc;
  778. {
  779.     int i, *tab;
  780.  
  781.     if (ops['v'] && ops['e']) {
  782.     zerrnam(name, "incompatible options", NULL, 0);
  783.     return 1;
  784.     }
  785.     if (ops['v'] || ops['e'] || ops['d'] || ops['m']) {
  786.     if (*argv) {
  787.         zerrnam(name, "too many arguments", NULL, 0);
  788.         return 1;
  789.     }
  790.     if (ops['d']) {
  791.         freehtab(em_xbindtab, freekey);
  792.         freehtab(vi_xbindtab, freekey);
  793.         initxbindtab();
  794.     }
  795.     if (ops['e']) {
  796.         mainbindtab = emacs_cur_bindtab;
  797.         xbindtab = em_xbindtab;
  798.     }
  799.     else if (ops['v']) {
  800.         mainbindtab = viins_cur_bindtab;
  801.         xbindtab = vi_xbindtab;
  802.     }
  803.     if (ops['m'])
  804.         for (i = 128; i != 256; i++)
  805.         if (mainbindtab[i] == z_selfinsert)
  806.             mainbindtab[i] = emacsbind[i];
  807.     return 0;
  808.     }
  809.  
  810.     tab = (ops['a']) ? altbindtab : mainbindtab;
  811.     if (!*argv) {
  812.     char buf[2];
  813.  
  814.     buf[1] = '\0';
  815.     for (i = 0; i != 256; i++) {
  816.         buf[0] = i;
  817.         putchar('\"');
  818.         printbind(buf, 1);
  819.         if (i < 254 && tab[i] == tab[i + 1] && tab[i] == tab[i + 2]) {
  820.         printf("\" to \"");
  821.         while (tab[i] == tab[i + 1])
  822.             i++;
  823.         buf[0] = i;
  824.         printbind(buf, 1);
  825.         }
  826.         printf("\"\t%s\n", zlecmds[tab[i]].name);
  827.     }
  828.     listhtable(xbindtab, (HFunc) printbinding);
  829.     return 0;
  830.     }
  831.  
  832.     while (*argv) {
  833.     Key ky = NULL, cur = NULL;
  834.     char *s;
  835.     int func, len, firstzero = 0;
  836.  
  837.     s = getkeystring(*argv++, &len, 2, NULL);
  838.     if (len > 1) {
  839.         if (s[0])
  840.         firstzero = 0;
  841.         else
  842.         firstzero = 1;
  843.         for (i = 0; i < len; i++)
  844.         if (!s[i])
  845.             s[i] = (char) 0x80;
  846.     }
  847.  
  848.     if (!*argv || ops['r']) {
  849.         if (len == 1)
  850.         func = tab[(unsigned char)*s];
  851.         else
  852.         func = (ky = (Key) gethnode(s, xbindtab)) ? ky->func
  853.                 : z_undefinedkey;
  854.         if (func == z_undefinedkey) {
  855.         zerrnam(name, "in-string is not bound", NULL, 0);
  856.         zfree(s, len);
  857.         return 1;
  858.         }
  859.         if (ops['r']) {
  860.         if (len == 1 && func != z_sequenceleadin) {
  861.             tab[(unsigned char)*s] = z_undefinedkey;
  862.             if (func == z_sendstring)
  863.             free(remhnode(s, xbindtab));
  864.         } else {
  865.             if (ky->prefixct) {
  866.             if (ky->func == z_sendstring)
  867.                 zfree(ky->str, ky->len);
  868.             ky->func = z_undefinedkey;
  869.             } else
  870.             free(remhnode(s, xbindtab));
  871.             if (len > 1) {
  872.             s[--len] = '\0';
  873.             while (len > 1) {
  874.                 (ky = (Key) gethnode(s, xbindtab))->prefixct--;
  875.                 if (!ky->prefixct && ky->func == z_undefinedkey)
  876.                 free(remhnode(s, xbindtab));
  877.                 s[--len] = '\0';
  878.             }
  879.             (ky = (Key) gethnode(s, xbindtab))->prefixct--;
  880.             if (!ky->prefixct) {
  881.                 tab[(unsigned char)*s] = ky->func;
  882.                 if (ky->func != z_sendstring)
  883.                 free(remhnode(s, xbindtab));
  884.             }
  885.             }
  886.         }
  887.         zfree(s, len);
  888.         continue;
  889.         }
  890.         if (func == z_sendstring) {
  891.         if (len == 1)
  892.             ky = (Key) gethnode(s, xbindtab);
  893.         printbind(ky->str, ky->len);
  894.         putchar('\n');
  895.         } else
  896.         printf("%s\n", zlecmds[func].name);
  897.         zfree(s, len);
  898.         return 0;
  899.     }
  900.  
  901.     if (!ops['s']) {
  902.         for (i = 0; i != ZLECMDCOUNT; i++)
  903.         if (!strcmp(*argv, zlecmds[i].name))
  904.             break;
  905.         if (i == ZLECMDCOUNT) {
  906.         zerr("undefined function: %s", *argv, 0);
  907.         zfree(s, len);
  908.         return 1;
  909.         }
  910.         func = i;
  911.     } else
  912.         func = z_sendstring;
  913.  
  914.     if (len == 1 && tab[(unsigned char)*s] != z_sequenceleadin) {
  915.         if (ops['s']) {
  916.         addhnode(ztrdup(s), cur = makefunckey(z_sendstring),
  917.              xbindtab, freekey);
  918.         } else if (tab[(unsigned char)*s] == z_sendstring)
  919.         free(remhnode(s, xbindtab));
  920.         tab[(unsigned char)*s] = func;
  921.     } else {
  922.         if (!  (cur = (Key) gethnode(s,xbindtab))
  923.         || (cur->func == z_undefinedkey))
  924.                 for (i = len - 1; i > 0; i--) {
  925.                     char sav;
  926.  
  927.                     sav = s[i];
  928.                     s[i] = '\0';
  929.             if (i == 1 && firstzero)
  930.             *s = '\0';
  931.             if (!(ky = (Key) gethnode(s, xbindtab)))
  932.             addhnode(ztrdup(s), ky = makefunckey(z_undefinedkey),
  933.                  xbindtab, freekey);
  934.             ky->prefixct++;
  935.                     s[i] = sav;
  936.             if (i == 1 && firstzero)
  937.             *s = (char) 0x80;
  938.         }
  939.         if (cur) {
  940.         cur->func = func;
  941.         zfree(cur->str, cur->len);
  942.         } else
  943.         addhnode(ztrdup(s), cur = makefunckey(func), xbindtab,freekey);
  944.         if (firstzero)
  945.         *s = 0;
  946.         if (tab[(unsigned char)*s] != z_sequenceleadin) {
  947.         cur->func = tab[(unsigned char)*s];
  948.         tab[(unsigned char)*s] = z_sequenceleadin;
  949.         }
  950.     }
  951.     if (ops['s']) {
  952.         cur->str = getkeystring(*argv, &cur->len, 2, NULL);
  953.         cur->str = (char *)realloc(cur->str, cur->len);
  954.     }
  955.     argv++;
  956.     zfree(s, len);
  957.     }
  958.     return 0;
  959. }
  960.  
  961. void freekey(x)            /**/
  962. vptr x;
  963. {
  964.     Key k = (Key) x;
  965.  
  966.     if (k->str)
  967.     zsfree(k->str);
  968.     zfree(k, sizeof(struct key));
  969. }
  970.  
  971. extern int clearflag;
  972.  
  973. void trashzle()
  974. {                /**/
  975.     if (zleactive) {
  976.     refresh();
  977.     moveto(nlnct, 0);
  978.     if (clearflag && tccan(TCCLEAREOD)) {
  979.         tcout(TCCLEAREOD);
  980.         clearflag = 0;
  981.     }
  982.     printf("%s", postedit);
  983.     fflush(stdout);
  984.     resetneeded = 1;
  985.     settyinfo(&shttyinfo);
  986.     }
  987.     if (errflag)
  988.     kungetct = 0;
  989. }
  990.