home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / zle_vi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-23  |  16.4 KB  |  879 lines

  1. /*
  2.  * $Id: zle_vi.c,v 2.11 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * zle_vi.c - vi-specific functions
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #define ZLE
  33. #include "zsh.h"
  34.  
  35. static int lastmult, lastbuf, lastgotmult, lastgotbuf, inrepeat, vichgrepeat;
  36.  
  37. static void startvichange _((int im));
  38.  
  39. static void
  40. startvichange(int im)
  41. {
  42.     if (im != -1) {
  43.     insmode = im;
  44.     vichgflag = 1;
  45.     }
  46.     if (inrepeat) {
  47.     zmult = lastmult;
  48.     vibufspec = lastbuf;
  49.     gotmult = lastgotmult;
  50.     gotvibufspec = lastgotbuf;
  51.     inrepeat = vichgflag = 0;
  52.     vichgrepeat = 1;
  53.     } else {
  54.     lastmult = zmult;
  55.     lastbuf = vibufspec;
  56.     lastgotmult = gotmult;
  57.     lastgotbuf = gotvibufspec;
  58.     if (vichgbuf)
  59.         free(vichgbuf);
  60.     vichgbuf = (char *)zalloc(vichgbufsz = 16);
  61.     vichgbuf[0] = c;
  62.     vichgbufptr = 1;
  63.     vichgrepeat = 0;
  64.     }
  65. }
  66.  
  67. static void startvitext _((int im));
  68.  
  69. static void
  70. startvitext(int im)
  71. {
  72.     startvichange(im);
  73.     bindtab = mainbindtab;
  74.     undoing = 0;
  75.     viinsbegin = cs;
  76. }
  77.  
  78. /**/
  79. int
  80. vigetkey(void)
  81. {
  82.     int cmd;
  83.  
  84.     if((c = getkey(0)) == EOF) {
  85.     feep();
  86.     return -1;
  87.     }
  88.     cmd = mainbindtab[c];
  89.     if(cmd == z_prefix) {
  90.     char buf[2];
  91.     Key ky;
  92.     buf[0] = c;
  93.     buf[1] = 0;
  94.     ky = (Key) keybindtab->getnode(keybindtab, buf);
  95.     if(!ky)
  96.         cmd = z_undefinedkey;
  97.     else
  98.         cmd = ky->func;
  99.     }
  100.  
  101.     if (cmd < 0 || cmd == z_sendbreak) {
  102.     feep();
  103.     return -1;
  104.     } else if (cmd == z_quotedinsert) {
  105.     if ((c = getkey(0)) == EOF) {
  106.         feep();
  107.         return -1;
  108.     }
  109.     } else if(cmd == z_viquotedinsert) {
  110.     char sav = line[cs];
  111.  
  112.     line[cs] = '^';
  113.     refresh();
  114.     c = getkey(0);
  115.     line[cs] = sav;
  116.     if(c == EOF) {
  117.         feep();
  118.         return -1;
  119.     }
  120.     } else if (cmd == z_vicmdmode)
  121.     return -1;
  122.     return c;
  123. }
  124.  
  125. /**/
  126. int
  127. getvirange(int wf)
  128. {
  129.     int k2, t0, startline, endline, obeep;
  130.     int mult1, gotmult1;
  131.  
  132.     vilinerange = 0;
  133.     startline = findbol();
  134.     endline = findeol();
  135.     /* get arguments for the command, and then the command key */
  136.     mult1 = zmult;
  137.     gotmult1 = gotmult;
  138.     zmult = 1;
  139.     gotmult = 0;
  140.     lastcmd &= ~(ZLE_NEGARG | ZLE_DIGIT);
  141.     while(1) {
  142.     if ((k2 = getkeycmd()) < 0 || k2 == z_sendbreak) {
  143.         feep();
  144.         return -1;
  145.     }
  146.     if (!(zlecmds[k2].flags & ZLE_ARG))
  147.         break;
  148.     (*zlecmds[k2].func) ();
  149.     lastcmd = zlecmds[k2].flags;
  150.     }
  151.  
  152.     /* double counts, such as in 3d4j, get multiplied, unless we're repeating */
  153.     if(vichgrepeat && gotmult1) {
  154.     zmult = mult1;
  155.     gotmult = 1;
  156.     } else if (gotmult1) {
  157.     zmult *= mult1;
  158.     gotmult = 1;
  159.     }
  160.     /* can't handle an empty file */
  161.     if (!ll) {
  162.     feep();
  163.     return -1;
  164.     }
  165.  
  166.     /* This bit handles repeated command keys, such as dd.  A number  *
  167.      * of lines is taken as the range.  The current line is included. *
  168.      * If the argument is positive, the lines go downward, otherwise  *
  169.      * vice versa.  The argument gives the number of lines.           */
  170.     if (k2 == bindk) {
  171.     vilinerange = 1;
  172.     if (!zmult) {
  173.         feep();
  174.         return -1;
  175.     }
  176.     t0 = cs;
  177.     if (zmult > 0) {
  178.         while(zmult-- && cs <= ll)
  179.         cs = findeol() + 1;
  180.         if (zmult != -1) {
  181.         cs = t0;
  182.         feep();
  183.         return -1;
  184.         }
  185.         t0 = cs - 1;
  186.         cs = startline;
  187.         return t0;
  188.     } else {
  189.         while(zmult++ && cs >= 0)
  190.         cs = findbol() - 1;
  191.         if (zmult != 1) {
  192.         cs = t0;
  193.         feep();
  194.         return -1;
  195.         }
  196.         cs++;
  197.         return endline;
  198.     }
  199.     }
  200.  
  201.     /* Not a movement?!  No, you can't do yd. */
  202.     if (!(zlecmds[k2].flags & ZLE_MOVEMENT)) {
  203.     feep();
  204.     return -1;
  205.     }
  206.  
  207.     /* Now we need to execute the movement command, to see where it *
  208.      * actually goes.  virangeflag here indicates to the movement   *
  209.      * function that it should place the cursor at the end of the   *
  210.      * range, rather than where the cursor would actually go if it  *
  211.      * were executed normally.  This makes a difference to some     *
  212.      * commands, but not all.  For example, if searching forward    *
  213.      * for a character, under normal circumstances the cursor lands *
  214.      * on the character.  For a range, the range must include the   *
  215.      * character, so the cursor gets placed after the character if  *
  216.      * virangeflag is set.  vi-match-bracket needs to change the    *
  217.      * value of virangeflag under some circumstances, meaning that  *
  218.      * we need to change the *starting* position.                   */
  219.     t0 = cs;
  220.     virangeflag = 1;
  221.     wordflag = wf;
  222.     obeep = opts[BEEP];
  223.     opts[BEEP] = 0;
  224.     (*zlecmds[k2].func) ();
  225.     wordflag = 0;
  226.     opts[BEEP] = obeep;
  227.     if (cs == t0) {
  228.     /* An error occured -- couldn't move.  The movement command didn't *
  229.      * feep, because we set NO_BEEP for the duration of the command.   */
  230.     feep();
  231.     virangeflag = 0;
  232.     return -1;
  233.     }
  234.     if(virangeflag == -1)
  235.     t0++;
  236.     virangeflag = 0;
  237.  
  238.     /* get the range the right way round */
  239.     if (cs > t0) {
  240.     int tmp = cs;
  241.     cs = t0;
  242.     t0 = tmp;
  243.     }
  244.  
  245.     /* Was it a line-oriented move?  In this case, entire lines are taken. *
  246.      * The terminating newline is left out of the range, which the real    *
  247.      * command must deal with appropriately.  At this point we just need   *
  248.      * to make the range encompass entire lines.                           */
  249.     if (zlecmds[k2].flags & ZLE_LINEMOVE) {
  250.     int newcs = findbol();
  251.     cs = t0;
  252.     t0 = findeol();
  253.     cs = newcs;
  254.     vilinerange = 1;
  255.     }
  256.     return t0;
  257. }
  258.  
  259. /**/
  260. void
  261. viaddnext(void)
  262. {
  263.     if (cs != findeol())
  264.     cs++;
  265.     startvitext(1);
  266. }
  267.  
  268. /**/
  269. void
  270. viaddeol(void)
  271. {
  272.     cs = findeol();
  273.     startvitext(1);
  274. }
  275.  
  276. /**/
  277. void
  278. viinsert(void)
  279. {
  280.     startvitext(1);
  281. }
  282.  
  283. /**/
  284. void
  285. viinsertbol(void)
  286. {
  287.     vifirstnonblank();
  288.     startvitext(1);
  289. }
  290.  
  291. /**/
  292. void
  293. videlete(void)
  294. {
  295.     int c2;
  296.  
  297.     startvichange(1);
  298.     if ((c2 = getvirange(0)) != -1) {
  299.     forekill(c2 - cs, 0);
  300.     if (vilinerange && ll) {
  301.         if (cs == ll)
  302.         cs--;
  303.         foredel(1);
  304.         vifirstnonblank();
  305.     }
  306.     }
  307.     vichgflag = vilinerange = 0;
  308. }
  309.  
  310. /**/
  311. void
  312. videletechar(void)
  313. {
  314.     startvichange(-1);
  315.     /* handle negative argument */
  316.     if (zmult < 0) {
  317.     zmult = -zmult;
  318.     vibackwarddeletechar();
  319.     return;
  320.     }
  321.     /* it is an error to be on the end of line */
  322.     if (cs == ll || line[cs] == '\n') {
  323.     feep();
  324.     return;
  325.     }
  326.     /* Put argument into the acceptable range -- it is not an error to  *
  327.      * specify a greater count than the number of available characters. */
  328.     if (zmult > findeol() - cs)
  329.     zmult = findeol() - cs;
  330.     /* do the deletion */
  331.     forekill(zmult, 0);
  332. }
  333.  
  334. /**/
  335. void
  336. vichange(void)
  337. {
  338.     int c2;
  339.  
  340.     startvichange(1);
  341.     if ((c2 = getvirange(1)) != -1) {
  342.     forekill(c2 - cs, 0);
  343.     bindtab = mainbindtab;
  344.     viinsbegin = cs;
  345.     undoing = 0;
  346.     }
  347.     vilinerange = 0;
  348. }
  349.  
  350. /**/
  351. void
  352. visubstitute(void)
  353. {
  354.     startvichange(1);
  355.     if (zmult < 0) {
  356.     feep();
  357.     return;
  358.     }
  359.     /* it is an error to be on the end of line */
  360.     if (cs == ll || line[cs] == '\n') {
  361.     feep();
  362.     return;
  363.     }
  364.     /* Put argument into the acceptable range -- it is not an error to  *
  365.      * specify a greater count than the number of available characters. */
  366.     if (zmult > findeol() - cs)
  367.     zmult = findeol() - cs;
  368.     /* do the substitution */
  369.     forekill(zmult, 0);
  370.     startvitext(1);
  371. }
  372.  
  373. /**/
  374. void
  375. vichangeeol(void)
  376. {
  377.     forekill(findeol() - cs, 0);
  378.     startvitext(1);
  379. }
  380.  
  381. /**/
  382. void
  383. vichangewholeline(void)
  384. {
  385.     vifirstnonblank();
  386.     vichangeeol();
  387. }
  388.  
  389. /**/
  390. void
  391. viyank(void)
  392. {
  393.     int oldcs = cs, c2;
  394.  
  395.     startvichange(1);
  396.     if ((c2 = getvirange(0)) != -1)
  397.     cut(cs, c2 - cs, 0);
  398.     vichgflag = vilinerange = 0;
  399.     cs = oldcs;
  400. }
  401.  
  402. /**/
  403. void
  404. viyankeol(void)
  405. {
  406.     int x = findeol();
  407.  
  408.     startvichange(-1);
  409.     if (x == cs) {
  410.     feep();
  411.     return;
  412.     }
  413.     cut(cs, x - cs, 0);
  414. }
  415.  
  416. /**/
  417. void
  418. viyankwholeline(void)
  419. {
  420.     int bol = findbol(), oldcs = cs;
  421.  
  422.     startvichange(-1);
  423.     if (zmult < 1)
  424.     return;
  425.     while(zmult--) {
  426.      if (cs > ll) {
  427.     feep();
  428.     cs = oldcs;
  429.     return;
  430.      }
  431.      cs = findeol() + 1;
  432.     }
  433.     vilinerange = 1;
  434.     cut(bol, cs - bol - 1, 0);
  435.     cs = oldcs;
  436. }
  437.  
  438. /**/
  439. void
  440. vireplace(void)
  441. {
  442.     startvitext(0);
  443. }
  444.  
  445. /* vi-replace-chars has some oddities relating to vi-repeat-change.  In *
  446.  * the real vi, if one does 3r at the end of a line, it feeps without   *
  447.  * reading the argument.  A successful rx followed by 3. at the end of  *
  448.  * a line (or 3rx followed by . at the end of a line) will obviously    *
  449.  * feep after the ., even though it has the argument available.  Here   *
  450.  * repeating is tied very closely to argument reading, such that we     *
  451.  * can't do that.  The solution is to just read the argument even if    *
  452.  * the command will fail -- not exactly vi compatible, but it is more   *
  453.  * consistent (consider dd in an empty file in vi).                     */
  454. /**/
  455. void
  456. vireplacechars(void)
  457. {
  458.     int ch;
  459.  
  460.     startvichange(1);
  461.     /* get key */
  462.     if((ch = vigetkey()) == -1) {
  463.     vichgflag = 0;
  464.     feep();
  465.     return;
  466.     }
  467.     /* check argument range */
  468.     if (zmult < 0 || zmult + cs > findeol()) {
  469.     vichgflag = 0;
  470.     feep();
  471.     return;
  472.     }
  473.     /* do change */
  474.     if (ch == '\r' || ch == '\n') {
  475.     /* <return> handled specially */
  476.     cs += zmult - 1;
  477.     backkill(zmult - 1, 0);
  478.     line[cs++] = '\n';
  479.     } else {
  480.     while (zmult--)
  481.         line[cs++] = ch;
  482.     cs--;
  483.     }
  484.     vichgflag = 0;
  485. }
  486.  
  487. /**/
  488. void
  489. vicmdmode(void)
  490. {
  491.     if (bindtab == altbindtab)
  492.     feep();
  493.     else {
  494.     bindtab = altbindtab;
  495.     undoing = 1;
  496.     vichgflag = 0;
  497.     if (cs != findbol())
  498.         cs--;
  499.     }
  500. }
  501.  
  502. /**/
  503. void
  504. viopenlinebelow(void)
  505. {
  506.     cs = findeol();
  507.     spaceinline(1);
  508.     line[cs++] = '\n';
  509.     startvitext(1);
  510. }
  511.  
  512. /**/
  513. void
  514. viopenlineabove(void)
  515. {
  516.     cs = findbol();
  517.     spaceinline(1);
  518.     line[cs] = '\n';
  519.     startvitext(1);
  520. }
  521.  
  522. /**/
  523. void
  524. vioperswapcase(void)
  525. {
  526.     int oldcs, c2;
  527.  
  528.     /* get the range */
  529.     startvichange(1);
  530.     if ((c2 = getvirange(0)) != -1) {
  531.     oldcs = cs;
  532.     /* swap the case of all letters within range */
  533.     while (cs < c2) {
  534.         if (islower(line[cs]))
  535.         line[cs] = tuupper(line[cs]);
  536.         else if (isupper(line[cs]))
  537.         line[cs] = tulower(line[cs]);
  538.         cs++;
  539.     }
  540.     /* go back to the first line of the range */
  541.     cs = oldcs;
  542.     vifirstnonblank();
  543.     }
  544.     vichgflag = vilinerange = 0;
  545. }
  546.  
  547. /**/
  548. void
  549. virepeatchange(void)
  550. {
  551.     /* make sure we have a change to repeat */
  552.     if (!vichgbuf || vichgflag) {
  553.     feep();
  554.     return;
  555.     }
  556.     /* restore or update the saved count and buffer */
  557.     if (gotmult) {
  558.     lastmult = zmult;
  559.     lastgotmult = 1;
  560.     }
  561.     if (gotvibufspec) {
  562.     lastbuf = vibufspec;
  563.     lastgotbuf = 1;
  564.     }
  565.     /* repeat the command */
  566.     inrepeat = 1;
  567.     ungetkeys(vichgbuf, vichgbufptr);
  568. }
  569.  
  570. /**/
  571. void
  572. viindent(void)
  573. {
  574.     int oldcs = cs, c2;
  575.  
  576.     /* get the range */
  577.     startvichange(1);
  578.     if ((c2 = getvirange(0)) == -1) {
  579.     vichgflag = vilinerange = 0;
  580.     return;
  581.     }
  582.     vichgflag = 0;
  583.     /* must be a line range */
  584.     if (!vilinerange) {
  585.     feep();
  586.     cs = oldcs;
  587.     return;
  588.     }
  589.     vilinerange = 0;
  590.     oldcs = cs;
  591.     /* add a tab to the beginning of each line within range */
  592.     while (cs < c2) {
  593.     spaceinline(1);
  594.     line[cs] = '\t';
  595.     cs = findeol() + 1;
  596.     }
  597.     /* go back to the first line of the range */
  598.     cs = oldcs;
  599.     vifirstnonblank();
  600. }
  601.  
  602. /**/
  603. void
  604. viunindent(void)
  605. {
  606.     int oldcs = cs, c2;
  607.  
  608.     /* get the range */
  609.     startvichange(1);
  610.     if ((c2 = getvirange(0)) == -1) {
  611.     vichgflag = vilinerange = 0;
  612.     return;
  613.     }
  614.     vichgflag = 0;
  615.     /* must be a line range */
  616.     if (!vilinerange) {
  617.     feep();
  618.     cs = oldcs;
  619.     return;
  620.     }
  621.     vilinerange = 0;
  622.     oldcs = cs;
  623.     /* remove a tab from the beginning of each line within range */
  624.     while (cs < c2) {
  625.     if (line[cs] == '\t')
  626.         foredel(1);
  627.     cs = findeol() + 1;
  628.     }
  629.     /* go back to the first line of the range */
  630.     cs = oldcs;
  631.     vifirstnonblank();
  632. }
  633.  
  634. /**/
  635. void
  636. vibackwarddeletechar(void)
  637. {
  638.     if (bindtab == altbindtab)
  639.     startvichange(-1);
  640.     /* handle negative argument */
  641.     if (zmult < 0) {
  642.     zmult = -zmult;
  643.     videletechar();
  644.     return;
  645.     }
  646.     /* It is an error to be at the beginning of the line, or (in *
  647.      * insert mode) to delete past the beginning of insertion.   */
  648.     if ((bindtab != altbindtab && cs - zmult < viinsbegin) || cs == findbol()) {
  649.     feep();
  650.     return;
  651.     }
  652.     /* Put argument into the acceptable range -- it is not an error to  *
  653.      * specify a greater count than the number of available characters. */
  654.     if (zmult > cs - findbol())
  655.     zmult = cs - findbol();
  656.     /* do the deletion */
  657.     backkill(zmult, 1);
  658. }
  659.  
  660. /**/
  661. void
  662. vikillline(void)
  663. {
  664.     if (viinsbegin > cs) {
  665.     feep();
  666.     return;
  667.     }
  668.     backdel(cs - viinsbegin);
  669. }
  670.  
  671. /**/
  672. void
  673. viputbefore(void)
  674. {
  675.     Cutbuffer buf = &cutbuf;
  676.  
  677.     startvichange(-1);
  678.     if (zmult < 0)
  679.     return;
  680.     if (gotvibufspec)
  681.     buf = &vibuf[vibufspec];
  682.     if (!buf->buf) {
  683.     feep();
  684.     return;
  685.     }
  686.     vilinerange = !!(buf->flags & CUTBUFFER_LINE);
  687.     if (vilinerange) {
  688.     cs = findbol();
  689.     spaceinline(buf->len + 1);
  690.     memcpy((char *)line + cs, buf->buf, buf->len);
  691.     line[cs + buf->len] = '\n';
  692.     vifirstnonblank();
  693.     } else {
  694.     while (zmult--) {
  695.         spaceinline(buf->len);
  696.         memcpy((char *)line + cs, buf->buf, buf->len);
  697.         cs += buf->len;
  698.     }
  699.     if (cs)
  700.         cs--;
  701.     }
  702. }
  703.  
  704. /**/
  705. void
  706. viputafter(void)
  707. {
  708.     Cutbuffer buf = &cutbuf;
  709.  
  710.     startvichange(-1);
  711.     if (zmult < 0)
  712.     return;
  713.     if (gotvibufspec)
  714.     buf = &vibuf[vibufspec];
  715.     if (!buf->buf) {
  716.     feep();
  717.     return;
  718.     }
  719.     vilinerange = !!(buf->flags & CUTBUFFER_LINE);
  720.     if (vilinerange) {
  721.     cs = findeol();
  722.     spaceinline(buf->len + 1);
  723.     line[cs++] = '\n';
  724.     memcpy((char *)line + cs, buf->buf, buf->len);
  725.     vifirstnonblank();
  726.     } else {
  727.     if (cs != findeol())
  728.         cs++;
  729.     while (zmult--) {
  730.         spaceinline(buf->len);
  731.         memcpy((char *)line + cs, buf->buf, buf->len);
  732.         cs += buf->len;
  733.     }
  734.     if (cs)
  735.         cs--;
  736.     }
  737.  
  738. }
  739.  
  740. /**/
  741. void
  742. vijoin(void)
  743. {
  744.     int x;
  745.  
  746.     startvichange(-1);
  747.     if ((x = findeol()) == ll) {
  748.     feep();
  749.     return;
  750.     }
  751.     cs = x + 1;
  752.     for (x = 1; cs != ll && iblank(line[cs]); cs++, x++);
  753.     backdel(x);
  754.     if (cs && iblank(line[cs-1]))
  755.     cs--;
  756.     else {
  757.     spaceinline(1);
  758.     line[cs] = ' ';
  759.     }
  760. }
  761.  
  762. /**/
  763. void
  764. viswapcase(void)
  765. {
  766.     int eol;
  767.  
  768.     startvichange(-1);
  769.     if (zmult < 1)
  770.     return;
  771.     eol = findeol();
  772.     while (cs < eol && zmult--) {
  773.     if (islower(line[cs]))
  774.         line[cs] = tuupper(line[cs]);
  775.     else if (isupper(line[cs]))
  776.         line[cs] = tulower(line[cs]);
  777.     cs++;
  778.     }
  779.     if (cs && cs == eol)
  780.     cs--;
  781. }
  782.  
  783. /**/
  784. void
  785. vicapslockpanic(void)
  786. {
  787.     feep();
  788.     statusline = "press a lowercase key to continue";
  789.     statusll = strlen(statusline);
  790.     refresh();
  791.     while (!islower(getkey(0)));
  792.     statusline = NULL;
  793. }
  794.  
  795. /**/
  796. void
  797. visetbuffer(void)
  798. {
  799.     int ch;
  800.  
  801.     if (gotvibufspec ||
  802.     (((ch = getkey(0)) < '1' || ch > '9') &&
  803.      (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))) {
  804.     feep();
  805.     return;
  806.     }
  807.     if (ch >= 'A' && ch <= 'Z')    /* needed in cut() */
  808.     vibufappend = 1;
  809.     else
  810.     vibufappend = 0;
  811.     vibufspec = tulower(ch) + (idigit(ch) ? -'1' + 26 : -'a');
  812.     gotvibufspec = 1;
  813. }
  814.  
  815. /**/
  816. void
  817. vikilleol(void)
  818. {
  819.     int n = findeol() - cs;
  820.  
  821.     startvichange(-1);
  822.     if (!n) {
  823.     /* error -- line already empty */
  824.     feep();
  825.     return;
  826.     }
  827.     /* delete to end of line */
  828.     forekill(findeol() - cs, 0);
  829. }
  830.  
  831. /**/
  832. void
  833. vipoundinsert(void)
  834. {
  835.     int oldcs = cs;
  836.  
  837.     startvichange(-1);
  838.     vifirstnonblank();
  839.     if(line[cs] != '#') {
  840.     spaceinline(1);
  841.     line[cs] = '#';
  842.     if(cs <= viinsbegin)
  843.         viinsbegin++;
  844.     cs = oldcs + (cs <= oldcs);
  845.     } else {
  846.     foredel(1);
  847.     if (cs < viinsbegin)
  848.         viinsbegin--;
  849.     cs = oldcs - (cs < oldcs);
  850.     }
  851. }
  852.  
  853. /**/
  854. void
  855. viquotedinsert(void)
  856. {
  857. #ifndef HAS_TIO
  858.     struct sgttyb sob;
  859. #endif
  860.  
  861.     spaceinline(1);
  862.     line[cs] = '^';
  863.     refresh();
  864. #ifndef HAS_TIO
  865.     sob = shttyinfo.sgttyb;
  866.     sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO;
  867.     ioctl(SHTTY, TIOCSETN, &sob);
  868. #endif
  869.     c = getkey(0);
  870. #ifndef HAS_TIO
  871.     setterm();
  872. #endif
  873.     foredel(1);
  874.     if(c < 0)
  875.     feep();
  876.     else
  877.     selfinsert();
  878. }
  879.