"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libedit/vi.c" (4 Jul 2020, 25529 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vi.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /*  $NetBSD: vi.c,v 1.10 2020/07/04 14:34:28 lukem Exp $    */
    2 /*  from    NetBSD: vi.c,v 1.63 2019/07/23 10:18:52 christos Exp    */
    3 
    4 /*-
    5  * Copyright (c) 1992, 1993
    6  *  The Regents of the University of California.  All rights reserved.
    7  *
    8  * This code is derived from software contributed to Berkeley by
    9  * Christos Zoulas of Cornell University.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 #include "config.h"
   37 
   38 #if 0 /* tnftp */
   39 #if !defined(lint) && !defined(SCCSID)
   40 #if 0
   41 static char sccsid[] = "@(#)vi.c    8.1 (Berkeley) 6/4/93";
   42 #else
   43 __RCSID(" NetBSD: vi.c,v 1.63 2019/07/23 10:18:52 christos Exp  ");
   44 #endif
   45 #endif /* not lint && not SCCSID */
   46 #endif /* tnftp */
   47 
   48 /*
   49  * vi.c: Vi mode commands.
   50  */
   51 #if 0 /* tnftp */
   52 #include <sys/wait.h>
   53 #include <ctype.h>
   54 #include <limits.h>
   55 #include <stdlib.h>
   56 #include <string.h>
   57 #include <unistd.h>
   58 #endif /* tnftp */
   59 
   60 #include "el.h"
   61 #include "common.h"
   62 #include "emacs.h"
   63 #include "fcns.h"
   64 #include "vi.h"
   65 
   66 static el_action_t  cv_action(EditLine *, wint_t);
   67 static el_action_t  cv_paste(EditLine *, wint_t);
   68 
   69 /* cv_action():
   70  *  Handle vi actions.
   71  */
   72 static el_action_t
   73 cv_action(EditLine *el, wint_t c)
   74 {
   75 
   76     if (el->el_chared.c_vcmd.action != NOP) {
   77         /* 'cc', 'dd' and (possibly) friends */
   78         if (c != (wint_t)el->el_chared.c_vcmd.action)
   79             return CC_ERROR;
   80 
   81         if (!(c & YANK))
   82             cv_undo(el);
   83         cv_yank(el, el->el_line.buffer,
   84             (int)(el->el_line.lastchar - el->el_line.buffer));
   85         el->el_chared.c_vcmd.action = NOP;
   86         el->el_chared.c_vcmd.pos = 0;
   87         if (!(c & YANK)) {
   88             el->el_line.lastchar = el->el_line.buffer;
   89             el->el_line.cursor = el->el_line.buffer;
   90         }
   91         if (c & INSERT)
   92             el->el_map.current = el->el_map.key;
   93 
   94         return CC_REFRESH;
   95     }
   96     el->el_chared.c_vcmd.pos = el->el_line.cursor;
   97     el->el_chared.c_vcmd.action = c;
   98     return CC_ARGHACK;
   99 }
  100 
  101 /* cv_paste():
  102  *  Paste previous deletion before or after the cursor
  103  */
  104 static el_action_t
  105 cv_paste(EditLine *el, wint_t c)
  106 {
  107     c_kill_t *k = &el->el_chared.c_kill;
  108     size_t len = (size_t)(k->last - k->buf);
  109 
  110     if (k->buf == NULL || len == 0)
  111         return CC_ERROR;
  112 #ifdef DEBUG_PASTE
  113     (void) fprintf(el->el_errfile, "Paste: \"%.*ls\"\n", (int)len,
  114         k->buf);
  115 #endif
  116 
  117     cv_undo(el);
  118 
  119     if (!c && el->el_line.cursor < el->el_line.lastchar)
  120         el->el_line.cursor++;
  121 
  122     c_insert(el, (int)len);
  123     if (el->el_line.cursor + len > el->el_line.lastchar)
  124         return CC_ERROR;
  125     (void) memcpy(el->el_line.cursor, k->buf, len *
  126         sizeof(*el->el_line.cursor));
  127 
  128     return CC_REFRESH;
  129 }
  130 
  131 
  132 /* vi_paste_next():
  133  *  Vi paste previous deletion to the right of the cursor
  134  *  [p]
  135  */
  136 libedit_private el_action_t
  137 /*ARGSUSED*/
  138 vi_paste_next(EditLine *el, wint_t c __attribute__((__unused__)))
  139 {
  140 
  141     return cv_paste(el, 0);
  142 }
  143 
  144 
  145 /* vi_paste_prev():
  146  *  Vi paste previous deletion to the left of the cursor
  147  *  [P]
  148  */
  149 libedit_private el_action_t
  150 /*ARGSUSED*/
  151 vi_paste_prev(EditLine *el, wint_t c __attribute__((__unused__)))
  152 {
  153 
  154     return cv_paste(el, 1);
  155 }
  156 
  157 
  158 /* vi_prev_big_word():
  159  *  Vi move to the previous space delimited word
  160  *  [B]
  161  */
  162 libedit_private el_action_t
  163 /*ARGSUSED*/
  164 vi_prev_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
  165 {
  166 
  167     if (el->el_line.cursor == el->el_line.buffer)
  168         return CC_ERROR;
  169 
  170     el->el_line.cursor = cv_prev_word(el->el_line.cursor,
  171         el->el_line.buffer,
  172         el->el_state.argument,
  173         cv__isWord);
  174 
  175     if (el->el_chared.c_vcmd.action != NOP) {
  176         cv_delfini(el);
  177         return CC_REFRESH;
  178     }
  179     return CC_CURSOR;
  180 }
  181 
  182 
  183 /* vi_prev_word():
  184  *  Vi move to the previous word
  185  *  [b]
  186  */
  187 libedit_private el_action_t
  188 /*ARGSUSED*/
  189 vi_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
  190 {
  191 
  192     if (el->el_line.cursor == el->el_line.buffer)
  193         return CC_ERROR;
  194 
  195     el->el_line.cursor = cv_prev_word(el->el_line.cursor,
  196         el->el_line.buffer,
  197         el->el_state.argument,
  198         cv__isword);
  199 
  200     if (el->el_chared.c_vcmd.action != NOP) {
  201         cv_delfini(el);
  202         return CC_REFRESH;
  203     }
  204     return CC_CURSOR;
  205 }
  206 
  207 
  208 /* vi_next_big_word():
  209  *  Vi move to the next space delimited word
  210  *  [W]
  211  */
  212 libedit_private el_action_t
  213 /*ARGSUSED*/
  214 vi_next_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
  215 {
  216 
  217     if (el->el_line.cursor >= el->el_line.lastchar - 1)
  218         return CC_ERROR;
  219 
  220     el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
  221         el->el_line.lastchar, el->el_state.argument, cv__isWord);
  222 
  223     if (el->el_map.type == MAP_VI)
  224         if (el->el_chared.c_vcmd.action != NOP) {
  225             cv_delfini(el);
  226             return CC_REFRESH;
  227         }
  228     return CC_CURSOR;
  229 }
  230 
  231 
  232 /* vi_next_word():
  233  *  Vi move to the next word
  234  *  [w]
  235  */
  236 libedit_private el_action_t
  237 /*ARGSUSED*/
  238 vi_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
  239 {
  240 
  241     if (el->el_line.cursor >= el->el_line.lastchar - 1)
  242         return CC_ERROR;
  243 
  244     el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
  245         el->el_line.lastchar, el->el_state.argument, cv__isword);
  246 
  247     if (el->el_map.type == MAP_VI)
  248         if (el->el_chared.c_vcmd.action != NOP) {
  249             cv_delfini(el);
  250             return CC_REFRESH;
  251         }
  252     return CC_CURSOR;
  253 }
  254 
  255 
  256 /* vi_change_case():
  257  *  Vi change case of character under the cursor and advance one character
  258  *  [~]
  259  */
  260 libedit_private el_action_t
  261 vi_change_case(EditLine *el, wint_t c)
  262 {
  263     int i;
  264 
  265     if (el->el_line.cursor >= el->el_line.lastchar)
  266         return CC_ERROR;
  267     cv_undo(el);
  268     for (i = 0; i < el->el_state.argument; i++) {
  269 
  270         c = *el->el_line.cursor;
  271         if (iswupper(c))
  272             *el->el_line.cursor = towlower(c);
  273         else if (iswlower(c))
  274             *el->el_line.cursor = towupper(c);
  275 
  276         if (++el->el_line.cursor >= el->el_line.lastchar) {
  277             el->el_line.cursor--;
  278             re_fastaddc(el);
  279             break;
  280         }
  281         re_fastaddc(el);
  282     }
  283     return CC_NORM;
  284 }
  285 
  286 
  287 /* vi_change_meta():
  288  *  Vi change prefix command
  289  *  [c]
  290  */
  291 libedit_private el_action_t
  292 /*ARGSUSED*/
  293 vi_change_meta(EditLine *el, wint_t c __attribute__((__unused__)))
  294 {
  295 
  296     /*
  297          * Delete with insert == change: first we delete and then we leave in
  298          * insert mode.
  299          */
  300     return cv_action(el, DELETE | INSERT);
  301 }
  302 
  303 
  304 /* vi_insert_at_bol():
  305  *  Vi enter insert mode at the beginning of line
  306  *  [I]
  307  */
  308 libedit_private el_action_t
  309 /*ARGSUSED*/
  310 vi_insert_at_bol(EditLine *el, wint_t c __attribute__((__unused__)))
  311 {
  312 
  313     el->el_line.cursor = el->el_line.buffer;
  314     cv_undo(el);
  315     el->el_map.current = el->el_map.key;
  316     return CC_CURSOR;
  317 }
  318 
  319 
  320 /* vi_replace_char():
  321  *  Vi replace character under the cursor with the next character typed
  322  *  [r]
  323  */
  324 libedit_private el_action_t
  325 /*ARGSUSED*/
  326 vi_replace_char(EditLine *el, wint_t c __attribute__((__unused__)))
  327 {
  328 
  329     if (el->el_line.cursor >= el->el_line.lastchar)
  330         return CC_ERROR;
  331 
  332     el->el_map.current = el->el_map.key;
  333     el->el_state.inputmode = MODE_REPLACE_1;
  334     cv_undo(el);
  335     return CC_ARGHACK;
  336 }
  337 
  338 
  339 /* vi_replace_mode():
  340  *  Vi enter replace mode
  341  *  [R]
  342  */
  343 libedit_private el_action_t
  344 /*ARGSUSED*/
  345 vi_replace_mode(EditLine *el, wint_t c __attribute__((__unused__)))
  346 {
  347 
  348     el->el_map.current = el->el_map.key;
  349     el->el_state.inputmode = MODE_REPLACE;
  350     cv_undo(el);
  351     return CC_NORM;
  352 }
  353 
  354 
  355 /* vi_substitute_char():
  356  *  Vi replace character under the cursor and enter insert mode
  357  *  [s]
  358  */
  359 libedit_private el_action_t
  360 /*ARGSUSED*/
  361 vi_substitute_char(EditLine *el, wint_t c __attribute__((__unused__)))
  362 {
  363 
  364     c_delafter(el, el->el_state.argument);
  365     el->el_map.current = el->el_map.key;
  366     return CC_REFRESH;
  367 }
  368 
  369 
  370 /* vi_substitute_line():
  371  *  Vi substitute entire line
  372  *  [S]
  373  */
  374 libedit_private el_action_t
  375 /*ARGSUSED*/
  376 vi_substitute_line(EditLine *el, wint_t c __attribute__((__unused__)))
  377 {
  378 
  379     cv_undo(el);
  380     cv_yank(el, el->el_line.buffer,
  381         (int)(el->el_line.lastchar - el->el_line.buffer));
  382     (void) em_kill_line(el, 0);
  383     el->el_map.current = el->el_map.key;
  384     return CC_REFRESH;
  385 }
  386 
  387 
  388 /* vi_change_to_eol():
  389  *  Vi change to end of line
  390  *  [C]
  391  */
  392 libedit_private el_action_t
  393 /*ARGSUSED*/
  394 vi_change_to_eol(EditLine *el, wint_t c __attribute__((__unused__)))
  395 {
  396 
  397     cv_undo(el);
  398     cv_yank(el, el->el_line.cursor,
  399         (int)(el->el_line.lastchar - el->el_line.cursor));
  400     (void) ed_kill_line(el, 0);
  401     el->el_map.current = el->el_map.key;
  402     return CC_REFRESH;
  403 }
  404 
  405 
  406 /* vi_insert():
  407  *  Vi enter insert mode
  408  *  [i]
  409  */
  410 libedit_private el_action_t
  411 /*ARGSUSED*/
  412 vi_insert(EditLine *el, wint_t c __attribute__((__unused__)))
  413 {
  414 
  415     el->el_map.current = el->el_map.key;
  416     cv_undo(el);
  417     return CC_NORM;
  418 }
  419 
  420 
  421 /* vi_add():
  422  *  Vi enter insert mode after the cursor
  423  *  [a]
  424  */
  425 libedit_private el_action_t
  426 /*ARGSUSED*/
  427 vi_add(EditLine *el, wint_t c __attribute__((__unused__)))
  428 {
  429     int ret;
  430 
  431     el->el_map.current = el->el_map.key;
  432     if (el->el_line.cursor < el->el_line.lastchar) {
  433         el->el_line.cursor++;
  434         if (el->el_line.cursor > el->el_line.lastchar)
  435             el->el_line.cursor = el->el_line.lastchar;
  436         ret = CC_CURSOR;
  437     } else
  438         ret = CC_NORM;
  439 
  440     cv_undo(el);
  441 
  442     return (el_action_t)ret;
  443 }
  444 
  445 
  446 /* vi_add_at_eol():
  447  *  Vi enter insert mode at end of line
  448  *  [A]
  449  */
  450 libedit_private el_action_t
  451 /*ARGSUSED*/
  452 vi_add_at_eol(EditLine *el, wint_t c __attribute__((__unused__)))
  453 {
  454 
  455     el->el_map.current = el->el_map.key;
  456     el->el_line.cursor = el->el_line.lastchar;
  457     cv_undo(el);
  458     return CC_CURSOR;
  459 }
  460 
  461 
  462 /* vi_delete_meta():
  463  *  Vi delete prefix command
  464  *  [d]
  465  */
  466 libedit_private el_action_t
  467 /*ARGSUSED*/
  468 vi_delete_meta(EditLine *el, wint_t c __attribute__((__unused__)))
  469 {
  470 
  471     return cv_action(el, DELETE);
  472 }
  473 
  474 
  475 /* vi_end_big_word():
  476  *  Vi move to the end of the current space delimited word
  477  *  [E]
  478  */
  479 libedit_private el_action_t
  480 /*ARGSUSED*/
  481 vi_end_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
  482 {
  483 
  484     if (el->el_line.cursor == el->el_line.lastchar)
  485         return CC_ERROR;
  486 
  487     el->el_line.cursor = cv__endword(el->el_line.cursor,
  488         el->el_line.lastchar, el->el_state.argument, cv__isWord);
  489 
  490     if (el->el_chared.c_vcmd.action != NOP) {
  491         el->el_line.cursor++;
  492         cv_delfini(el);
  493         return CC_REFRESH;
  494     }
  495     return CC_CURSOR;
  496 }
  497 
  498 
  499 /* vi_end_word():
  500  *  Vi move to the end of the current word
  501  *  [e]
  502  */
  503 libedit_private el_action_t
  504 /*ARGSUSED*/
  505 vi_end_word(EditLine *el, wint_t c __attribute__((__unused__)))
  506 {
  507 
  508     if (el->el_line.cursor == el->el_line.lastchar)
  509         return CC_ERROR;
  510 
  511     el->el_line.cursor = cv__endword(el->el_line.cursor,
  512         el->el_line.lastchar, el->el_state.argument, cv__isword);
  513 
  514     if (el->el_chared.c_vcmd.action != NOP) {
  515         el->el_line.cursor++;
  516         cv_delfini(el);
  517         return CC_REFRESH;
  518     }
  519     return CC_CURSOR;
  520 }
  521 
  522 
  523 /* vi_undo():
  524  *  Vi undo last change
  525  *  [u]
  526  */
  527 libedit_private el_action_t
  528 /*ARGSUSED*/
  529 vi_undo(EditLine *el, wint_t c __attribute__((__unused__)))
  530 {
  531     c_undo_t un = el->el_chared.c_undo;
  532 
  533     if (un.len == -1)
  534         return CC_ERROR;
  535 
  536     /* switch line buffer and undo buffer */
  537     el->el_chared.c_undo.buf = el->el_line.buffer;
  538     el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
  539     el->el_chared.c_undo.cursor =
  540         (int)(el->el_line.cursor - el->el_line.buffer);
  541     el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
  542     el->el_line.buffer = un.buf;
  543     el->el_line.cursor = un.buf + un.cursor;
  544     el->el_line.lastchar = un.buf + un.len;
  545 
  546     return CC_REFRESH;
  547 }
  548 
  549 
  550 /* vi_command_mode():
  551  *  Vi enter command mode (use alternative key bindings)
  552  *  [<ESC>]
  553  */
  554 libedit_private el_action_t
  555 /*ARGSUSED*/
  556 vi_command_mode(EditLine *el, wint_t c __attribute__((__unused__)))
  557 {
  558 
  559     /* [Esc] cancels pending action */
  560     el->el_chared.c_vcmd.action = NOP;
  561     el->el_chared.c_vcmd.pos = 0;
  562 
  563     el->el_state.doingarg = 0;
  564 
  565     el->el_state.inputmode = MODE_INSERT;
  566     el->el_map.current = el->el_map.alt;
  567 #ifdef VI_MOVE
  568     if (el->el_line.cursor > el->el_line.buffer)
  569         el->el_line.cursor--;
  570 #endif
  571     return CC_CURSOR;
  572 }
  573 
  574 
  575 /* vi_zero():
  576  *  Vi move to the beginning of line
  577  *  [0]
  578  */
  579 libedit_private el_action_t
  580 vi_zero(EditLine *el, wint_t c)
  581 {
  582 
  583     if (el->el_state.doingarg)
  584         return ed_argument_digit(el, c);
  585 
  586     el->el_line.cursor = el->el_line.buffer;
  587     if (el->el_chared.c_vcmd.action != NOP) {
  588         cv_delfini(el);
  589         return CC_REFRESH;
  590     }
  591     return CC_CURSOR;
  592 }
  593 
  594 
  595 /* vi_delete_prev_char():
  596  *  Vi move to previous character (backspace)
  597  *  [^H] in insert mode only
  598  */
  599 libedit_private el_action_t
  600 /*ARGSUSED*/
  601 vi_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
  602 {
  603 
  604     if (el->el_line.cursor <= el->el_line.buffer)
  605         return CC_ERROR;
  606 
  607     c_delbefore1(el);
  608     el->el_line.cursor--;
  609     return CC_REFRESH;
  610 }
  611 
  612 
  613 /* vi_list_or_eof():
  614  *  Vi list choices for completion or indicate end of file if empty line
  615  *  [^D]
  616  */
  617 libedit_private el_action_t
  618 /*ARGSUSED*/
  619 vi_list_or_eof(EditLine *el, wint_t c)
  620 {
  621 
  622     if (el->el_line.cursor == el->el_line.lastchar) {
  623         if (el->el_line.cursor == el->el_line.buffer) {
  624             terminal_writec(el, c); /* then do a EOF */
  625             return CC_EOF;
  626         } else {
  627             /*
  628              * Here we could list completions, but it is an
  629              * error right now
  630              */
  631             terminal_beep(el);
  632             return CC_ERROR;
  633         }
  634     } else {
  635 #ifdef notyet
  636         re_goto_bottom(el);
  637         *el->el_line.lastchar = '\0';   /* just in case */
  638         return CC_LIST_CHOICES;
  639 #else
  640         /*
  641          * Just complain for now.
  642          */
  643         terminal_beep(el);
  644         return CC_ERROR;
  645 #endif
  646     }
  647 }
  648 
  649 
  650 /* vi_kill_line_prev():
  651  *  Vi cut from beginning of line to cursor
  652  *  [^U]
  653  */
  654 libedit_private el_action_t
  655 /*ARGSUSED*/
  656 vi_kill_line_prev(EditLine *el, wint_t c __attribute__((__unused__)))
  657 {
  658     wchar_t *kp, *cp;
  659 
  660     cp = el->el_line.buffer;
  661     kp = el->el_chared.c_kill.buf;
  662     while (cp < el->el_line.cursor)
  663         *kp++ = *cp++;  /* copy it */
  664     el->el_chared.c_kill.last = kp;
  665     c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
  666     el->el_line.cursor = el->el_line.buffer;    /* zap! */
  667     return CC_REFRESH;
  668 }
  669 
  670 
  671 /* vi_search_prev():
  672  *  Vi search history previous
  673  *  [?]
  674  */
  675 libedit_private el_action_t
  676 /*ARGSUSED*/
  677 vi_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
  678 {
  679 
  680     return cv_search(el, ED_SEARCH_PREV_HISTORY);
  681 }
  682 
  683 
  684 /* vi_search_next():
  685  *  Vi search history next
  686  *  [/]
  687  */
  688 libedit_private el_action_t
  689 /*ARGSUSED*/
  690 vi_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
  691 {
  692 
  693     return cv_search(el, ED_SEARCH_NEXT_HISTORY);
  694 }
  695 
  696 
  697 /* vi_repeat_search_next():
  698  *  Vi repeat current search in the same search direction
  699  *  [n]
  700  */
  701 libedit_private el_action_t
  702 /*ARGSUSED*/
  703 vi_repeat_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
  704 {
  705 
  706     if (el->el_search.patlen == 0)
  707         return CC_ERROR;
  708     else
  709         return cv_repeat_srch(el, el->el_search.patdir);
  710 }
  711 
  712 
  713 /* vi_repeat_search_prev():
  714  *  Vi repeat current search in the opposite search direction
  715  *  [N]
  716  */
  717 /*ARGSUSED*/
  718 libedit_private el_action_t
  719 vi_repeat_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
  720 {
  721 
  722     if (el->el_search.patlen == 0)
  723         return CC_ERROR;
  724     else
  725         return (cv_repeat_srch(el,
  726             el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
  727             ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
  728 }
  729 
  730 
  731 /* vi_next_char():
  732  *  Vi move to the character specified next
  733  *  [f]
  734  */
  735 libedit_private el_action_t
  736 /*ARGSUSED*/
  737 vi_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
  738 {
  739     return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
  740 }
  741 
  742 
  743 /* vi_prev_char():
  744  *  Vi move to the character specified previous
  745  *  [F]
  746  */
  747 libedit_private el_action_t
  748 /*ARGSUSED*/
  749 vi_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
  750 {
  751     return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
  752 }
  753 
  754 
  755 /* vi_to_next_char():
  756  *  Vi move up to the character specified next
  757  *  [t]
  758  */
  759 libedit_private el_action_t
  760 /*ARGSUSED*/
  761 vi_to_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
  762 {
  763     return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
  764 }
  765 
  766 
  767 /* vi_to_prev_char():
  768  *  Vi move up to the character specified previous
  769  *  [T]
  770  */
  771 libedit_private el_action_t
  772 /*ARGSUSED*/
  773 vi_to_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
  774 {
  775     return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
  776 }
  777 
  778 
  779 /* vi_repeat_next_char():
  780  *  Vi repeat current character search in the same search direction
  781  *  [;]
  782  */
  783 libedit_private el_action_t
  784 /*ARGSUSED*/
  785 vi_repeat_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
  786 {
  787 
  788     return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
  789         el->el_state.argument, el->el_search.chatflg);
  790 }
  791 
  792 
  793 /* vi_repeat_prev_char():
  794  *  Vi repeat current character search in the opposite search direction
  795  *  [,]
  796  */
  797 libedit_private el_action_t
  798 /*ARGSUSED*/
  799 vi_repeat_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
  800 {
  801     el_action_t r;
  802     int dir = el->el_search.chadir;
  803 
  804     r = cv_csearch(el, -dir, el->el_search.chacha,
  805         el->el_state.argument, el->el_search.chatflg);
  806     el->el_search.chadir = dir;
  807     return r;
  808 }
  809 
  810 
  811 /* vi_match():
  812  *  Vi go to matching () {} or []
  813  *  [%]
  814  */
  815 libedit_private el_action_t
  816 /*ARGSUSED*/
  817 vi_match(EditLine *el, wint_t c __attribute__((__unused__)))
  818 {
  819     const wchar_t match_chars[] = L"()[]{}";
  820     wchar_t *cp;
  821     size_t delta, i, count;
  822     wchar_t o_ch, c_ch;
  823 
  824     *el->el_line.lastchar = '\0';       /* just in case */
  825 
  826     i = wcscspn(el->el_line.cursor, match_chars);
  827     o_ch = el->el_line.cursor[i];
  828     if (o_ch == 0)
  829         return CC_ERROR;
  830     delta = (size_t)(wcschr(match_chars, o_ch) - match_chars);
  831     c_ch = match_chars[delta ^ 1];
  832     count = 1;
  833     delta = 1 - (delta & 1) * 2;
  834 
  835     for (cp = &el->el_line.cursor[i]; count; ) {
  836         cp += delta;
  837         if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
  838             return CC_ERROR;
  839         if (*cp == o_ch)
  840             count++;
  841         else if (*cp == c_ch)
  842             count--;
  843     }
  844 
  845     el->el_line.cursor = cp;
  846 
  847     if (el->el_chared.c_vcmd.action != NOP) {
  848         /* NB posix says char under cursor should NOT be deleted
  849            for -ve delta - this is different to netbsd vi. */
  850         if (delta > 0)
  851             el->el_line.cursor++;
  852         cv_delfini(el);
  853         return CC_REFRESH;
  854     }
  855     return CC_CURSOR;
  856 }
  857 
  858 /* vi_undo_line():
  859  *  Vi undo all changes to line
  860  *  [U]
  861  */
  862 libedit_private el_action_t
  863 /*ARGSUSED*/
  864 vi_undo_line(EditLine *el, wint_t c __attribute__((__unused__)))
  865 {
  866 
  867     cv_undo(el);
  868     return hist_get(el);
  869 }
  870 
  871 /* vi_to_column():
  872  *  Vi go to specified column
  873  *  [|]
  874  * NB netbsd vi goes to screen column 'n', posix says nth character
  875  */
  876 libedit_private el_action_t
  877 /*ARGSUSED*/
  878 vi_to_column(EditLine *el, wint_t c __attribute__((__unused__)))
  879 {
  880 
  881     el->el_line.cursor = el->el_line.buffer;
  882     el->el_state.argument--;
  883     return ed_next_char(el, 0);
  884 }
  885 
  886 /* vi_yank_end():
  887  *  Vi yank to end of line
  888  *  [Y]
  889  */
  890 libedit_private el_action_t
  891 /*ARGSUSED*/
  892 vi_yank_end(EditLine *el, wint_t c __attribute__((__unused__)))
  893 {
  894 
  895     cv_yank(el, el->el_line.cursor,
  896         (int)(el->el_line.lastchar - el->el_line.cursor));
  897     return CC_REFRESH;
  898 }
  899 
  900 /* vi_yank():
  901  *  Vi yank
  902  *  [y]
  903  */
  904 libedit_private el_action_t
  905 /*ARGSUSED*/
  906 vi_yank(EditLine *el, wint_t c __attribute__((__unused__)))
  907 {
  908 
  909     return cv_action(el, YANK);
  910 }
  911 
  912 /* vi_comment_out():
  913  *  Vi comment out current command
  914  *  [#]
  915  */
  916 libedit_private el_action_t
  917 /*ARGSUSED*/
  918 vi_comment_out(EditLine *el, wint_t c __attribute__((__unused__)))
  919 {
  920 
  921     el->el_line.cursor = el->el_line.buffer;
  922     c_insert(el, 1);
  923     *el->el_line.cursor = '#';
  924     re_refresh(el);
  925     return ed_newline(el, 0);
  926 }
  927 
  928 /* vi_alias():
  929  *  Vi include shell alias
  930  *  [@]
  931  * NB: posix implies that we should enter insert mode, however
  932  * this is against historical precedent...
  933  */
  934 libedit_private el_action_t
  935 /*ARGSUSED*/
  936 vi_alias(EditLine *el, wint_t c __attribute__((__unused__)))
  937 {
  938     char alias_name[3];
  939     const char *alias_text;
  940 
  941     if (el->el_chared.c_aliasfun == NULL)
  942         return CC_ERROR;
  943 
  944     alias_name[0] = '_';
  945     alias_name[2] = 0;
  946     if (el_getc(el, &alias_name[1]) != 1)
  947         return CC_ERROR;
  948 
  949     alias_text = (*el->el_chared.c_aliasfun)(el->el_chared.c_aliasarg,
  950         alias_name);
  951     if (alias_text != NULL)
  952         el_wpush(el, ct_decode_string(alias_text, &el->el_scratch));
  953     return CC_NORM;
  954 }
  955 
  956 /* vi_to_history_line():
  957  *  Vi go to specified history file line.
  958  *  [G]
  959  */
  960 libedit_private el_action_t
  961 /*ARGSUSED*/
  962 vi_to_history_line(EditLine *el, wint_t c __attribute__((__unused__)))
  963 {
  964     int sv_event_no = el->el_history.eventno;
  965     el_action_t rval;
  966 
  967 
  968     if (el->el_history.eventno == 0) {
  969          (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
  970              EL_BUFSIZ);
  971          el->el_history.last = el->el_history.buf +
  972              (el->el_line.lastchar - el->el_line.buffer);
  973     }
  974 
  975     /* Lack of a 'count' means oldest, not 1 */
  976     if (!el->el_state.doingarg) {
  977         el->el_history.eventno = 0x7fffffff;
  978         hist_get(el);
  979     } else {
  980         /* This is brain dead, all the rest of this code counts
  981          * upwards going into the past.  Here we need count in the
  982          * other direction (to match the output of fc -l).
  983          * I could change the world, but this seems to suffice.
  984          */
  985         el->el_history.eventno = 1;
  986         if (hist_get(el) == CC_ERROR)
  987             return CC_ERROR;
  988         el->el_history.eventno = 1 + el->el_history.ev.num
  989                     - el->el_state.argument;
  990         if (el->el_history.eventno < 0) {
  991             el->el_history.eventno = sv_event_no;
  992             return CC_ERROR;
  993         }
  994     }
  995     rval = hist_get(el);
  996     if (rval == CC_ERROR)
  997         el->el_history.eventno = sv_event_no;
  998     return rval;
  999 }
 1000 
 1001 /* vi_histedit():
 1002  *  Vi edit history line with vi
 1003  *  [v]
 1004  */
 1005 libedit_private el_action_t
 1006 /*ARGSUSED*/
 1007 vi_histedit(EditLine *el, wint_t c __attribute__((__unused__)))
 1008 {
 1009     int fd;
 1010     pid_t pid;
 1011     ssize_t st;
 1012     int status;
 1013     char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
 1014     char *cp = NULL;
 1015     size_t len;
 1016     wchar_t *line = NULL;
 1017 
 1018     if (el->el_state.doingarg) {
 1019         if (vi_to_history_line(el, 0) == CC_ERROR)
 1020             return CC_ERROR;
 1021     }
 1022 
 1023     fd = mkstemp(tempfile);
 1024     if (fd < 0)
 1025         return CC_ERROR;
 1026     len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
 1027 #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
 1028     cp = el_calloc(TMP_BUFSIZ, sizeof(*cp));
 1029     if (cp == NULL)
 1030         goto error;
 1031     line = el_calloc(len + 1, sizeof(*line));
 1032     if (line == NULL)
 1033         goto error;
 1034     wcsncpy(line, el->el_line.buffer, len);
 1035     line[len] = '\0';
 1036     wcstombs(cp, line, TMP_BUFSIZ - 1);
 1037     cp[TMP_BUFSIZ - 1] = '\0';
 1038     len = strlen(cp);
 1039     write(fd, cp, len);
 1040     write(fd, "\n", (size_t)1);
 1041     pid = fork();
 1042     switch (pid) {
 1043     case -1:
 1044         goto error;
 1045     case 0:
 1046         close(fd);
 1047         execlp("vi", "vi", tempfile, (char *)NULL);
 1048         exit(0);
 1049         /*NOTREACHED*/
 1050     default:
 1051         while (waitpid(pid, &status, 0) != pid)
 1052             continue;
 1053         lseek(fd, (off_t)0, SEEK_SET);
 1054         st = read(fd, cp, TMP_BUFSIZ - 1);
 1055         if (st > 0) {
 1056             cp[st] = '\0';
 1057             len = (size_t)(el->el_line.limit - el->el_line.buffer);
 1058             len = mbstowcs(el->el_line.buffer, cp, len);
 1059             if (len > 0 && el->el_line.buffer[len - 1] == '\n')
 1060                 --len;
 1061         }
 1062         else
 1063             len = 0;
 1064                 el->el_line.cursor = el->el_line.buffer;
 1065                 el->el_line.lastchar = el->el_line.buffer + len;
 1066         el_free(cp);
 1067                 el_free(line);
 1068         break;
 1069     }
 1070 
 1071     close(fd);
 1072     unlink(tempfile);
 1073     /* return CC_REFRESH; */
 1074     return ed_newline(el, 0);
 1075 error:
 1076     el_free(line);
 1077     el_free(cp);
 1078     close(fd);
 1079     unlink(tempfile);
 1080     return CC_ERROR;
 1081 }
 1082 
 1083 /* vi_history_word():
 1084  *  Vi append word from previous input line
 1085  *  [_]
 1086  * Who knows where this one came from!
 1087  * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
 1088  */
 1089 libedit_private el_action_t
 1090 /*ARGSUSED*/
 1091 vi_history_word(EditLine *el, wint_t c __attribute__((__unused__)))
 1092 {
 1093     const wchar_t *wp = HIST_FIRST(el);
 1094     const wchar_t *wep, *wsp;
 1095     int len;
 1096     wchar_t *cp;
 1097     const wchar_t *lim;
 1098 
 1099     if (wp == NULL)
 1100         return CC_ERROR;
 1101 
 1102     wep = wsp = NULL;
 1103     do {
 1104         while (iswspace(*wp))
 1105             wp++;
 1106         if (*wp == 0)
 1107             break;
 1108         wsp = wp;
 1109         while (*wp && !iswspace(*wp))
 1110             wp++;
 1111         wep = wp;
 1112     } while ((!el->el_state.doingarg || --el->el_state.argument > 0)
 1113         && *wp != 0);
 1114 
 1115     if (wsp == NULL || (el->el_state.doingarg && el->el_state.argument != 0))
 1116         return CC_ERROR;
 1117 
 1118     cv_undo(el);
 1119     len = (int)(wep - wsp);
 1120     if (el->el_line.cursor < el->el_line.lastchar)
 1121         el->el_line.cursor++;
 1122     c_insert(el, len + 1);
 1123     cp = el->el_line.cursor;
 1124     lim = el->el_line.limit;
 1125     if (cp < lim)
 1126         *cp++ = ' ';
 1127     while (wsp < wep && cp < lim)
 1128         *cp++ = *wsp++;
 1129     el->el_line.cursor = cp;
 1130 
 1131     el->el_map.current = el->el_map.key;
 1132     return CC_REFRESH;
 1133 }
 1134 
 1135 /* vi_redo():
 1136  *  Vi redo last non-motion command
 1137  *  [.]
 1138  */
 1139 libedit_private el_action_t
 1140 /*ARGSUSED*/
 1141 vi_redo(EditLine *el, wint_t c __attribute__((__unused__)))
 1142 {
 1143     c_redo_t *r = &el->el_chared.c_redo;
 1144 
 1145     if (!el->el_state.doingarg && r->count) {
 1146         el->el_state.doingarg = 1;
 1147         el->el_state.argument = r->count;
 1148     }
 1149 
 1150     el->el_chared.c_vcmd.pos = el->el_line.cursor;
 1151     el->el_chared.c_vcmd.action = r->action;
 1152     if (r->pos != r->buf) {
 1153         if (r->pos + 1 > r->lim)
 1154             /* sanity */
 1155             r->pos = r->lim - 1;
 1156         r->pos[0] = 0;
 1157         el_wpush(el, r->buf);
 1158     }
 1159 
 1160     el->el_state.thiscmd = r->cmd;
 1161     el->el_state.thisch = r->ch;
 1162     return (*el->el_map.func[r->cmd])(el, r->ch);
 1163 }