File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / isearch.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (3 years, 3 months ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

    1: /* isearch.c - incremental searching */
    2: 
    3: /* **************************************************************** */
    4: /*								    */
    5: /*			I-Search and Searching			    */
    6: /*								    */
    7: /* **************************************************************** */
    8: 
    9: /* Copyright (C) 1987-2020 Free Software Foundation, Inc.
   10: 
   11:    This file is part of the GNU Readline Library (Readline), a library
   12:    for reading lines of text with interactive input and history editing.      
   13: 
   14:    Readline is free software: you can redistribute it and/or modify
   15:    it under the terms of the GNU General Public License as published by
   16:    the Free Software Foundation, either version 3 of the License, or
   17:    (at your option) any later version.
   18: 
   19:    Readline is distributed in the hope that it will be useful,
   20:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   21:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22:    GNU General Public License for more details.
   23: 
   24:    You should have received a copy of the GNU General Public License
   25:    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
   26: */
   27: 
   28: #define READLINE_LIBRARY
   29: 
   30: #if defined (HAVE_CONFIG_H)
   31: #  include <config.h>
   32: #endif
   33: 
   34: #include <sys/types.h>
   35: 
   36: #include <stdio.h>
   37: 
   38: #if defined (HAVE_UNISTD_H)
   39: #  include <unistd.h>
   40: #endif
   41: 
   42: #if defined (HAVE_STDLIB_H)
   43: #  include <stdlib.h>
   44: #else
   45: #  include "ansi_stdlib.h"
   46: #endif
   47: 
   48: #include "rldefs.h"
   49: #include "rlmbutil.h"
   50: 
   51: #include "readline.h"
   52: #include "history.h"
   53: 
   54: #include "rlprivate.h"
   55: #include "xmalloc.h"
   56: 
   57: /* Variables exported to other files in the readline library. */
   58: char *_rl_isearch_terminators = (char *)NULL;
   59: 
   60: _rl_search_cxt *_rl_iscxt = 0;
   61: 
   62: /* Variables imported from other files in the readline library. */
   63: extern HIST_ENTRY *_rl_saved_line_for_history;
   64: 
   65: static int rl_search_history PARAMS((int, int));
   66: 
   67: static _rl_search_cxt *_rl_isearch_init PARAMS((int));
   68: static void _rl_isearch_fini PARAMS((_rl_search_cxt *));
   69: 
   70: /* Last line found by the current incremental search, so we don't `find'
   71:    identical lines many times in a row.  Now part of isearch context. */
   72: /* static char *prev_line_found; */
   73: 
   74: /* Last search string and its length. */
   75: static char *last_isearch_string;
   76: static int last_isearch_string_len;
   77: 
   78: static char * const default_isearch_terminators = "\033\012";
   79: 
   80: _rl_search_cxt *
   81: _rl_scxt_alloc (int type, int flags)
   82: {
   83:   _rl_search_cxt *cxt;
   84: 
   85:   cxt = (_rl_search_cxt *)xmalloc (sizeof (_rl_search_cxt));
   86: 
   87:   cxt->type = type;
   88:   cxt->sflags = flags;
   89: 
   90:   cxt->search_string = 0;
   91:   cxt->search_string_size = cxt->search_string_index = 0;
   92: 
   93:   cxt->lines = 0;
   94:   cxt->allocated_line = 0;
   95:   cxt->hlen = cxt->hindex = 0;
   96: 
   97:   cxt->save_point = rl_point;
   98:   cxt->save_mark = rl_mark;
   99:   cxt->save_line = where_history ();
  100:   cxt->last_found_line = cxt->save_line;
  101:   cxt->prev_line_found = 0;
  102: 
  103:   cxt->save_undo_list = 0;
  104: 
  105:   cxt->keymap = _rl_keymap;
  106:   cxt->okeymap = _rl_keymap;
  107: 
  108:   cxt->history_pos = 0;
  109:   cxt->direction = 0;
  110: 
  111:   cxt->prevc = cxt->lastc = 0;
  112: 
  113:   cxt->sline = 0;
  114:   cxt->sline_len = cxt->sline_index = 0;
  115: 
  116:   cxt->search_terminators = 0;
  117: 
  118:   return cxt;
  119: }
  120: 
  121: void
  122: _rl_scxt_dispose (_rl_search_cxt *cxt, int flags)
  123: {
  124:   FREE (cxt->search_string);
  125:   FREE (cxt->allocated_line);
  126:   FREE (cxt->lines);
  127: 
  128:   xfree (cxt);
  129: }
  130: 
  131: /* Search backwards through the history looking for a string which is typed
  132:    interactively.  Start with the current line. */
  133: int
  134: rl_reverse_search_history (int sign, int key)
  135: {
  136:   return (rl_search_history (-sign, key));
  137: }
  138: 
  139: /* Search forwards through the history looking for a string which is typed
  140:    interactively.  Start with the current line. */
  141: int
  142: rl_forward_search_history (int sign, int key)
  143: {
  144:   return (rl_search_history (sign, key));
  145: }
  146: 
  147: /* Display the current state of the search in the echo-area.
  148:    SEARCH_STRING contains the string that is being searched for,
  149:    DIRECTION is zero for forward, or non-zero for reverse,
  150:    WHERE is the history list number of the current line.  If it is
  151:    -1, then this line is the starting one. */
  152: static void
  153: rl_display_search (char *search_string, int flags, int where)
  154: {
  155:   char *message;
  156:   int msglen, searchlen;
  157: 
  158:   searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
  159: 
  160:   message = (char *)xmalloc (searchlen + 64);
  161:   msglen = 0;
  162: 
  163: #if defined (NOTDEF)
  164:   if (where != -1)
  165:     {
  166:       sprintf (message, "[%d]", where + history_base);
  167:       msglen = strlen (message);
  168:     }
  169: #endif /* NOTDEF */
  170: 
  171:   message[msglen++] = '(';
  172: 
  173:   if (flags & SF_FAILED)
  174:     {
  175:       strcpy (message + msglen, "failed ");
  176:       msglen += 7;
  177:     }
  178: 
  179:   if (flags & SF_REVERSE)
  180:     {
  181:       strcpy (message + msglen, "reverse-");
  182:       msglen += 8;
  183:     }
  184: 
  185:   strcpy (message + msglen, "i-search)`");
  186:   msglen += 10;
  187: 
  188:   if (search_string && *search_string)
  189:     {
  190:       strcpy (message + msglen, search_string);
  191:       msglen += searchlen;
  192:     }
  193:   else
  194:     _rl_optimize_redisplay ();
  195: 
  196:   strcpy (message + msglen, "': ");
  197: 
  198:   rl_message ("%s", message);
  199:   xfree (message);
  200:   (*rl_redisplay_function) ();
  201: }
  202: 
  203: static _rl_search_cxt *
  204: _rl_isearch_init (int direction)
  205: {
  206:   _rl_search_cxt *cxt;
  207:   register int i;
  208:   HIST_ENTRY **hlist;
  209: 
  210:   cxt = _rl_scxt_alloc (RL_SEARCH_ISEARCH, 0);
  211:   if (direction < 0)
  212:     cxt->sflags |= SF_REVERSE;
  213: 
  214:   cxt->search_terminators = _rl_isearch_terminators ? _rl_isearch_terminators
  215: 						: default_isearch_terminators;
  216: 
  217:   /* Create an array of pointers to the lines that we want to search. */
  218:   hlist = history_list ();
  219:   rl_maybe_replace_line ();
  220:   i = 0;
  221:   if (hlist)
  222:     for (i = 0; hlist[i]; i++);
  223: 
  224:   /* Allocate space for this many lines, +1 for the current input line,
  225:      and remember those lines. */
  226:   cxt->lines = (char **)xmalloc ((1 + (cxt->hlen = i)) * sizeof (char *));
  227:   for (i = 0; i < cxt->hlen; i++)
  228:     cxt->lines[i] = hlist[i]->line;
  229: 
  230:   if (_rl_saved_line_for_history)
  231:     cxt->lines[i] = _rl_saved_line_for_history->line;
  232:   else
  233:     {
  234:       /* Keep track of this so we can free it. */
  235:       cxt->allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer));
  236:       strcpy (cxt->allocated_line, &rl_line_buffer[0]);
  237:       cxt->lines[i] = cxt->allocated_line;
  238:     }
  239: 
  240:   cxt->hlen++;
  241: 
  242:   /* The line where we start the search. */
  243:   cxt->history_pos = cxt->save_line;
  244: 
  245:   rl_save_prompt ();
  246: 
  247:   /* Initialize search parameters. */
  248:   cxt->search_string = (char *)xmalloc (cxt->search_string_size = 128);
  249:   cxt->search_string[cxt->search_string_index = 0] = '\0';
  250: 
  251:   /* Normalize DIRECTION into 1 or -1. */
  252:   cxt->direction = (direction >= 0) ? 1 : -1;
  253: 
  254:   cxt->sline = rl_line_buffer;
  255:   cxt->sline_len = strlen (cxt->sline);
  256:   cxt->sline_index = rl_point;
  257: 
  258:   _rl_iscxt = cxt;		/* save globally */
  259: 
  260:   /* experimental right now */
  261:   _rl_init_executing_keyseq ();
  262: 
  263:   return cxt;
  264: }
  265: 
  266: static void
  267: _rl_isearch_fini (_rl_search_cxt *cxt)
  268: {
  269:   /* First put back the original state. */
  270:   rl_replace_line (cxt->lines[cxt->save_line], 0);
  271: 
  272:   rl_restore_prompt ();
  273: 
  274:   /* Save the search string for possible later use. */
  275:   FREE (last_isearch_string);
  276:   last_isearch_string = cxt->search_string;
  277:   last_isearch_string_len = cxt->search_string_index;
  278:   cxt->search_string = 0;
  279: 
  280:   if (cxt->last_found_line < cxt->save_line)
  281:     rl_get_previous_history (cxt->save_line - cxt->last_found_line, 0);
  282:   else
  283:     rl_get_next_history (cxt->last_found_line - cxt->save_line, 0);
  284: 
  285:   /* If the string was not found, put point at the end of the last matching
  286:      line.  If last_found_line == orig_line, we didn't find any matching
  287:      history lines at all, so put point back in its original position. */
  288:   if (cxt->sline_index < 0)
  289:     {
  290:       if (cxt->last_found_line == cxt->save_line)
  291: 	cxt->sline_index = cxt->save_point;
  292:       else
  293: 	cxt->sline_index = strlen (rl_line_buffer);
  294:       rl_mark = cxt->save_mark;
  295:       rl_deactivate_mark ();
  296:     }
  297: 
  298:   rl_point = cxt->sline_index;
  299:   /* Don't worry about where to put the mark here; rl_get_previous_history
  300:      and rl_get_next_history take care of it.
  301:      If we want to highlight the search string, this is where to set the
  302:      point and mark to do it. */
  303:   _rl_fix_point (0);
  304:   rl_deactivate_mark ();
  305: 
  306: /*  _rl_optimize_redisplay (); */
  307:   rl_clear_message ();
  308: }
  309: 
  310: /* XXX - we could use _rl_bracketed_read_mbstring () here. */
  311: int
  312: _rl_search_getchar (_rl_search_cxt *cxt)
  313: {
  314:   int c;
  315: 
  316:   /* Read a key and decide how to proceed. */
  317:   RL_SETSTATE(RL_STATE_MOREINPUT);
  318:   c = cxt->lastc = rl_read_key ();
  319:   RL_UNSETSTATE(RL_STATE_MOREINPUT);
  320: 
  321: #if defined (HANDLE_MULTIBYTE)
  322:   /* This ends up with C (and LASTC) being set to the last byte of the
  323:      multibyte character.  In most cases c == lastc == mb[0] */
  324:   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  325:     c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
  326: #endif
  327: 
  328:   RL_CHECK_SIGNALS ();
  329:   return c;
  330: }
  331: 
  332: #define ENDSRCH_CHAR(c) \
  333:   ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
  334: 
  335: /* Process just-read character C according to isearch context CXT.  Return
  336:    -1 if the caller should just free the context and return, 0 if we should
  337:    break out of the loop, and 1 if we should continue to read characters. */
  338: int
  339: _rl_isearch_dispatch (_rl_search_cxt *cxt, int c)
  340: {
  341:   int n, wstart, wlen, limit, cval, incr;
  342:   char *paste;
  343:   size_t pastelen;
  344:   int j;
  345:   rl_command_func_t *f;
  346: 
  347:   f = (rl_command_func_t *)NULL;
  348: 
  349:   if (c < 0)
  350:     {
  351:       cxt->sflags |= SF_FAILED;
  352:       cxt->history_pos = cxt->last_found_line;
  353:       return -1;
  354:     }
  355: 
  356:   _rl_add_executing_keyseq (c);
  357: 
  358:   /* XXX - experimental code to allow users to bracketed-paste into the search
  359:      string even when ESC is one of the isearch-terminators. Not perfect yet. */
  360:   if (_rl_enable_bracketed_paste && c == ESC && strchr (cxt->search_terminators, c) && (n = _rl_nchars_available ()) > (BRACK_PASTE_SLEN-1))
  361:     {
  362:       j = _rl_read_bracketed_paste_prefix (c);
  363:       if (j == 1)
  364: 	{
  365: 	  cxt->lastc = -7;		/* bracketed paste, see below */
  366: 	  goto opcode_dispatch;	
  367:         }
  368:       else if (_rl_pushed_input_available ())	/* eat extra char we pushed back */
  369: 	c = cxt->lastc = rl_read_key ();
  370:       else
  371: 	c = cxt->lastc;			/* last ditch */
  372:     }
  373: 
  374:   /* If we are moving into a new keymap, modify cxt->keymap and go on.
  375:      This can be a problem if c == ESC and we want to terminate the
  376:      incremental search, so we check */
  377:   if (c >= 0 && cxt->keymap[c].type == ISKMAP && strchr (cxt->search_terminators, cxt->lastc) == 0)
  378:     {
  379:       /* _rl_keyseq_timeout specified in milliseconds; _rl_input_queued
  380: 	 takes microseconds, so multiply by 1000.  If we don't get any
  381: 	 additional input and this keymap shadows another function, process
  382: 	 that key as if it was all we read. */
  383:       if (_rl_keyseq_timeout > 0 &&
  384: 	    RL_ISSTATE (RL_STATE_CALLBACK) == 0 &&
  385: 	    RL_ISSTATE (RL_STATE_INPUTPENDING) == 0 &&
  386: 	    _rl_pushed_input_available () == 0 &&
  387: 	    ((Keymap)(cxt->keymap[c].function))[ANYOTHERKEY].function &&
  388: 	    _rl_input_queued (_rl_keyseq_timeout*1000) == 0)
  389: 	goto add_character;
  390: 
  391:       cxt->okeymap = cxt->keymap;
  392:       cxt->keymap = FUNCTION_TO_KEYMAP (cxt->keymap, c);
  393:       cxt->sflags |= SF_CHGKMAP;
  394:       /* XXX - we should probably save this sequence, so we can do
  395: 	 something useful if this doesn't end up mapping to a command we
  396: 	 interpret here.  Right now we just save the most recent character
  397: 	 that caused the index into a new keymap. */
  398:       cxt->prevc = c;
  399: #if defined (HANDLE_MULTIBYTE)
  400:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  401: 	{
  402: 	  if (cxt->mb[1] == 0)
  403: 	    {
  404: 	      cxt->pmb[0] = c;		/* XXX should be == cxt->mb[0] */
  405: 	      cxt->pmb[1] = '\0';
  406: 	    }
  407: 	  else
  408: 	    memcpy (cxt->pmb, cxt->mb, sizeof (cxt->pmb));
  409: 	}
  410: #endif
  411:       return 1;
  412:     }
  413: 
  414: add_character:
  415: 
  416:   /* Translate the keys we do something with to opcodes. */
  417:   if (c >= 0 && cxt->keymap[c].type == ISFUNC)
  418:     {
  419:       /* If we have a multibyte character, see if it's bound to something that
  420: 	 affects the search. */
  421: #if defined (HANDLE_MULTIBYTE)
  422:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && cxt->mb[1])
  423: 	f = rl_function_of_keyseq (cxt->mb, cxt->keymap, (int *)NULL);
  424:       else
  425: #endif
  426: 	{
  427: 	  f = cxt->keymap[c].function;
  428: 	  if (f == rl_do_lowercase_version)
  429: 	    f = cxt->keymap[_rl_to_lower (c)].function;
  430: 	}
  431: 
  432:       if (f == rl_reverse_search_history)
  433: 	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -1 : -2;
  434:       else if (f == rl_forward_search_history)
  435: 	cxt->lastc = (cxt->sflags & SF_REVERSE) ? -2 : -1;
  436:       else if (f == rl_rubout)
  437: 	cxt->lastc = -3;
  438:       else if (c == CTRL ('G') || f == rl_abort)
  439: 	cxt->lastc = -4;
  440:       else if (c == CTRL ('W') || f == rl_unix_word_rubout)	/* XXX */
  441: 	cxt->lastc = -5;
  442:       else if (c == CTRL ('Y') || f == rl_yank)	/* XXX */
  443: 	cxt->lastc = -6;
  444:       else if (f == rl_bracketed_paste_begin)
  445: 	cxt->lastc = -7;
  446:     }
  447: 
  448:   /* If we changed the keymap earlier while translating a key sequence into
  449:      a command, restore it now that we've succeeded. */
  450:   if (cxt->sflags & SF_CHGKMAP)
  451:     {
  452:       cxt->keymap = cxt->okeymap;
  453:       cxt->sflags &= ~SF_CHGKMAP;
  454:       /* If we indexed into a new keymap, but didn't map to a command that
  455: 	 affects the search (lastc > 0), and the character that mapped to a
  456: 	 new keymap would have ended the search (ENDSRCH_CHAR(cxt->prevc)),
  457: 	 handle that now as if the previous char would have ended the search
  458: 	 and we would have read the current character. */
  459:       /* XXX - should we check cxt->mb? */
  460:       if (cxt->lastc > 0 && ENDSRCH_CHAR (cxt->prevc))
  461: 	{
  462: 	  rl_stuff_char (cxt->lastc);
  463: 	  rl_execute_next (cxt->prevc);
  464: 	  /* XXX - do we insert everything in cxt->pmb? */
  465: 	  return (0);
  466: 	}
  467:       /* Otherwise, if the current character is mapped to self-insert or
  468: 	 nothing (i.e., not an editing command), and the previous character
  469: 	 was a keymap index, then we need to insert both the previous
  470: 	 character and the current character into the search string. */
  471:       else if (cxt->lastc > 0 && cxt->prevc > 0 &&
  472: 	       cxt->keymap[cxt->prevc].type == ISKMAP &&
  473: 	       (f == 0 || f == rl_insert))
  474: 	{
  475: 	  /* Make lastc be the next character read */
  476: 	  /* XXX - do we insert everything in cxt->mb? */
  477: 	  rl_execute_next (cxt->lastc);
  478: 	  /* Dispatch on the previous character (insert into search string) */
  479: 	  cxt->lastc = cxt->prevc;
  480: #if defined (HANDLE_MULTIBYTE)
  481: 	  /* Have to overwrite cxt->mb here because dispatch uses it below */
  482: 	  if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  483: 	    {  
  484: 	      if (cxt->pmb[1] == 0)	  
  485: 		{
  486: 		  cxt->mb[0] = cxt->lastc;	/* == cxt->prevc */
  487: 		  cxt->mb[1] = '\0';
  488: 		}
  489: 	      else
  490: 		memcpy (cxt->mb, cxt->pmb, sizeof (cxt->mb));
  491: 	    }
  492: #endif
  493: 	  cxt->prevc = 0;	  
  494: 	}
  495:       else if (cxt->lastc > 0 && cxt->prevc > 0 && f && f != rl_insert)
  496: 	{
  497: 	  _rl_term_executing_keyseq ();		/* should this go in the caller? */
  498: 
  499: 	  _rl_pending_command.map = cxt->keymap;
  500: 	  _rl_pending_command.count = 1;	/* XXX */
  501: 	  _rl_pending_command.key = cxt->lastc;
  502: 	  _rl_pending_command.func = f;
  503: 	  _rl_command_to_execute = &_rl_pending_command;
  504: 
  505: 	  return (0);
  506: 	}
  507:     }
  508: 
  509:   /* The characters in isearch_terminators (set from the user-settable
  510:      variable isearch-terminators) are used to terminate the search but
  511:      not subsequently execute the character as a command.  The default
  512:      value is "\033\012" (ESC and C-J). */
  513:   if (cxt->lastc > 0 && strchr (cxt->search_terminators, cxt->lastc))
  514:     {
  515:       /* ESC still terminates the search, but if there is pending
  516: 	 input or if input arrives within 0.1 seconds (on systems
  517: 	 with select(2)) it is used as a prefix character
  518: 	 with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
  519: 	 to allow the arrow keys to be used like ^F and ^B are used
  520: 	 to terminate the search and execute the movement command.
  521: 	 XXX - since _rl_input_available depends on the application-
  522: 	 settable keyboard timeout value, this could alternatively
  523: 	 use _rl_input_queued(100000) */
  524:       if (cxt->lastc == ESC && (_rl_pushed_input_available () || _rl_input_available ()))
  525: 	rl_execute_next (ESC);
  526:       return (0);
  527:     }
  528: 
  529: #if defined (HANDLE_MULTIBYTE)
  530:   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  531:     {
  532:       if (cxt->lastc >= 0 && (cxt->mb[0] && cxt->mb[1] == '\0') && ENDSRCH_CHAR (cxt->lastc))
  533: 	{
  534: 	  /* This sets rl_pending_input to LASTC; it will be picked up the next
  535: 	     time rl_read_key is called. */
  536: 	  rl_execute_next (cxt->lastc);
  537: 	  return (0);
  538: 	}
  539:     }
  540:   else
  541: #endif
  542:     if (cxt->lastc >= 0 && ENDSRCH_CHAR (cxt->lastc))
  543:       {
  544: 	/* This sets rl_pending_input to LASTC; it will be picked up the next
  545: 	   time rl_read_key is called. */
  546: 	rl_execute_next (cxt->lastc);
  547: 	return (0);
  548:       }
  549: 
  550:   _rl_init_executing_keyseq ();
  551: 
  552: opcode_dispatch:
  553:   /* Now dispatch on the character.  `Opcodes' affect the search string or
  554:      state.  Other characters are added to the string.  */
  555:   switch (cxt->lastc)
  556:     {
  557:     /* search again */
  558:     case -1:
  559:       if (cxt->search_string_index == 0)
  560: 	{
  561: 	  if (last_isearch_string)
  562: 	    {
  563: 	      cxt->search_string_size = 64 + last_isearch_string_len;
  564: 	      cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
  565: 	      strcpy (cxt->search_string, last_isearch_string);
  566: 	      cxt->search_string_index = last_isearch_string_len;
  567: 	      rl_display_search (cxt->search_string, cxt->sflags, -1);
  568: 	      break;
  569: 	    }
  570: 	  /* XXX - restore keymap here? */
  571: 	  return (1);
  572: 	}
  573:       else if ((cxt->sflags & SF_REVERSE) && cxt->sline_index >= 0)
  574: 	cxt->sline_index--;
  575:       else if (cxt->sline_index != cxt->sline_len)
  576: 	cxt->sline_index++;
  577:       else
  578: 	rl_ding ();
  579:       break;
  580: 
  581:     /* switch directions */
  582:     case -2:
  583:       cxt->direction = -cxt->direction;
  584:       if (cxt->direction < 0)
  585: 	cxt->sflags |= SF_REVERSE;
  586:       else
  587: 	cxt->sflags &= ~SF_REVERSE;
  588:       break;
  589: 
  590:     /* delete character from search string. */
  591:     case -3:	/* C-H, DEL */
  592:       /* This is tricky.  To do this right, we need to keep a
  593: 	 stack of search positions for the current search, with
  594: 	 sentinels marking the beginning and end.  But this will
  595: 	 do until we have a real isearch-undo. */
  596:       if (cxt->search_string_index == 0)
  597: 	rl_ding ();
  598:       else if (MB_CUR_MAX == 1 || rl_byte_oriented)
  599: 	cxt->search_string[--cxt->search_string_index] = '\0';
  600:       else
  601: 	{
  602: 	  wstart = _rl_find_prev_mbchar (cxt->search_string, cxt->search_string_index, MB_FIND_NONZERO);
  603: 	  if (wstart >= 0)
  604: 	    cxt->search_string[cxt->search_string_index = wstart] = '\0';
  605: 	  else
  606: 	    cxt->search_string[cxt->search_string_index = 0] = '\0';
  607: 	}
  608: 
  609:       if (cxt->search_string_index == 0)
  610: 	rl_ding ();
  611: 
  612:       break;
  613: 
  614:     case -4:	/* C-G, abort */
  615:       rl_replace_line (cxt->lines[cxt->save_line], 0);
  616:       rl_point = cxt->save_point;
  617:       rl_mark = cxt->save_mark;
  618:       rl_deactivate_mark ();
  619:       rl_restore_prompt();
  620:       rl_clear_message ();
  621: 
  622:       _rl_fix_point (1);	/* in case save_line and save_point are out of sync */
  623:       return -1;
  624: 
  625:     case -5:	/* C-W */
  626:       /* skip over portion of line we already matched and yank word */
  627:       wstart = rl_point + cxt->search_string_index;
  628:       if (wstart >= rl_end)
  629: 	{
  630: 	  rl_ding ();
  631: 	  break;
  632: 	}
  633: 
  634:       /* if not in a word, move to one. */
  635:       cval = _rl_char_value (rl_line_buffer, wstart);
  636:       if (_rl_walphabetic (cval) == 0)
  637: 	{
  638: 	  rl_ding ();
  639: 	  break;
  640: 	}
  641:       n = MB_NEXTCHAR (rl_line_buffer, wstart, 1, MB_FIND_NONZERO);;
  642:       while (n < rl_end)
  643: 	{
  644: 	  cval = _rl_char_value (rl_line_buffer, n);
  645: 	  if (_rl_walphabetic (cval) == 0)
  646: 	    break;
  647: 	  n = MB_NEXTCHAR (rl_line_buffer, n, 1, MB_FIND_NONZERO);;
  648: 	}
  649:       wlen = n - wstart + 1;
  650:       if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
  651: 	{
  652: 	  cxt->search_string_size += wlen + 1;
  653: 	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
  654: 	}
  655:       for (; wstart < n; wstart++)
  656: 	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[wstart];
  657:       cxt->search_string[cxt->search_string_index] = '\0';
  658:       break;
  659: 
  660:     case -6:	/* C-Y */
  661:       /* skip over portion of line we already matched and yank rest */
  662:       wstart = rl_point + cxt->search_string_index;
  663:       if (wstart >= rl_end)
  664: 	{
  665: 	  rl_ding ();
  666: 	  break;
  667: 	}
  668:       n = rl_end - wstart + 1;
  669:       if (cxt->search_string_index + n + 1 >= cxt->search_string_size)
  670: 	{
  671: 	  cxt->search_string_size += n + 1;
  672: 	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
  673: 	}
  674:       for (n = wstart; n < rl_end; n++)
  675: 	cxt->search_string[cxt->search_string_index++] = rl_line_buffer[n];
  676:       cxt->search_string[cxt->search_string_index] = '\0';
  677:       break;
  678: 
  679:     case -7:	/* bracketed paste */
  680:       paste = _rl_bracketed_text (&pastelen);
  681:       if (paste == 0 || *paste == 0)
  682: 	{
  683: 	  free (paste);
  684: 	  break;
  685: 	}
  686:       if (_rl_enable_active_region)
  687: 	rl_activate_mark ();
  688:       if (cxt->search_string_index + pastelen + 1 >= cxt->search_string_size)
  689: 	{
  690: 	  cxt->search_string_size += pastelen + 2;
  691: 	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
  692: 	}
  693:       strcpy (cxt->search_string + cxt->search_string_index, paste);
  694:       cxt->search_string_index += pastelen;
  695:       free (paste);
  696:       break;
  697: 
  698:     /* Add character to search string and continue search. */
  699:     default:
  700: #if defined (HANDLE_MULTIBYTE)
  701:       wlen = (cxt->mb[0] == 0 || cxt->mb[1] == 0) ? 1 : RL_STRLEN (cxt->mb);
  702: #else
  703:       wlen = 1;
  704: #endif
  705:       if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
  706: 	{
  707: 	  cxt->search_string_size += 128;	/* 128 much greater than MB_CUR_MAX */
  708: 	  cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
  709: 	}
  710: #if defined (HANDLE_MULTIBYTE)
  711:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  712: 	{
  713: 	  int j;
  714: 
  715: 	  if (cxt->mb[0] == 0 || cxt->mb[1] == 0)
  716: 	    cxt->search_string[cxt->search_string_index++] = cxt->mb[0];
  717: 	  else
  718: 	    for (j = 0; j < wlen; )
  719: 	      cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
  720: 	}
  721:       else
  722: #endif
  723: 	cxt->search_string[cxt->search_string_index++] = cxt->lastc;	/* XXX - was c instead of lastc */
  724:       cxt->search_string[cxt->search_string_index] = '\0';
  725:       break;
  726:     }
  727: 
  728:   for (cxt->sflags &= ~(SF_FOUND|SF_FAILED);; )
  729:     {
  730:       if (cxt->search_string_index == 0)
  731: 	{
  732: 	  cxt->sflags |= SF_FAILED;
  733: 	  break;
  734: 	}
  735: 
  736:       limit = cxt->sline_len - cxt->search_string_index + 1;
  737: 
  738:       /* Search the current line. */
  739:       while ((cxt->sflags & SF_REVERSE) ? (cxt->sline_index >= 0) : (cxt->sline_index < limit))
  740: 	{
  741: 	  if (STREQN (cxt->search_string, cxt->sline + cxt->sline_index, cxt->search_string_index))
  742: 	    {
  743: 	      cxt->sflags |= SF_FOUND;
  744: 	      break;
  745: 	    }
  746: 	  else
  747: 	    cxt->sline_index += cxt->direction;
  748: 
  749: 	  if (cxt->sline_index < 0)
  750: 	    {
  751: 	      cxt->sline_index = 0;
  752: 	      break;
  753: 	    }
  754: 	}
  755:       if (cxt->sflags & SF_FOUND)
  756: 	break;
  757: 
  758:       /* Move to the next line, but skip new copies of the line
  759: 	 we just found and lines shorter than the string we're
  760: 	 searching for. */
  761:       do
  762: 	{
  763: 	  /* Move to the next line. */
  764: 	  cxt->history_pos += cxt->direction;
  765: 
  766: 	  /* At limit for direction? */
  767: 	  if ((cxt->sflags & SF_REVERSE) ? (cxt->history_pos < 0) : (cxt->history_pos == cxt->hlen))
  768: 	    {
  769: 	      cxt->sflags |= SF_FAILED;
  770: 	      break;
  771: 	    }
  772: 
  773: 	  /* We will need these later. */
  774: 	  cxt->sline = cxt->lines[cxt->history_pos];
  775: 	  cxt->sline_len = strlen (cxt->sline);
  776: 	}
  777:       while ((cxt->prev_line_found && STREQ (cxt->prev_line_found, cxt->lines[cxt->history_pos])) ||
  778: 	     (cxt->search_string_index > cxt->sline_len));
  779: 
  780:       if (cxt->sflags & SF_FAILED)
  781: 	{
  782: 	  /* XXX - reset sline_index if < 0 */
  783: 	  if (cxt->sline_index < 0)
  784: 	    cxt->sline_index = 0;
  785: 	  break;
  786: 	}
  787: 
  788:       /* Now set up the line for searching... */
  789:       cxt->sline_index = (cxt->sflags & SF_REVERSE) ? cxt->sline_len - cxt->search_string_index : 0;
  790:     }
  791: 
  792:   /* reset the keymaps for the next time through the loop */
  793:   cxt->keymap = cxt->okeymap = _rl_keymap;
  794: 
  795:   if (cxt->sflags & SF_FAILED)
  796:     {
  797:       /* We cannot find the search string.  Ding the bell. */
  798:       rl_ding ();
  799:       cxt->history_pos = cxt->last_found_line;
  800:       rl_deactivate_mark ();
  801:       rl_display_search (cxt->search_string, cxt->sflags, (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
  802:       return 1;
  803:     }
  804: 
  805:   /* We have found the search string.  Just display it.  But don't
  806:      actually move there in the history list until the user accepts
  807:      the location. */
  808:   if (cxt->sflags & SF_FOUND)
  809:     {
  810:       cxt->prev_line_found = cxt->lines[cxt->history_pos];
  811:       rl_replace_line (cxt->lines[cxt->history_pos], 0);
  812:       if (_rl_enable_active_region)
  813: 	rl_activate_mark ();	
  814:       rl_point = cxt->sline_index;
  815:       if (rl_mark_active_p () && cxt->search_string_index > 0)
  816: 	rl_mark = rl_point + cxt->search_string_index;
  817:       cxt->last_found_line = cxt->history_pos;
  818:       rl_display_search (cxt->search_string, cxt->sflags, (cxt->history_pos == cxt->save_line) ? -1 : cxt->history_pos);
  819:     }
  820: 
  821:   return 1;
  822: }
  823: 
  824: int
  825: _rl_isearch_cleanup (_rl_search_cxt *cxt, int r)
  826: {
  827:   if (r >= 0)
  828:     _rl_isearch_fini (cxt);
  829:   _rl_scxt_dispose (cxt, 0);
  830:   _rl_iscxt = 0;
  831: 
  832:   RL_UNSETSTATE(RL_STATE_ISEARCH);
  833: 
  834:   return (r != 0);
  835: }
  836: 
  837: /* Search through the history looking for an interactively typed string.
  838:    This is analogous to i-search.  We start the search in the current line.
  839:    DIRECTION is which direction to search; >= 0 means forward, < 0 means
  840:    backwards. */
  841: static int
  842: rl_search_history (int direction, int invoking_key)
  843: {
  844:   _rl_search_cxt *cxt;		/* local for now, but saved globally */
  845:   int c, r;
  846: 
  847:   RL_SETSTATE(RL_STATE_ISEARCH);
  848:   cxt = _rl_isearch_init (direction);
  849: 
  850:   rl_display_search (cxt->search_string, cxt->sflags, -1);
  851: 
  852:   /* If we are using the callback interface, all we do is set up here and
  853:       return.  The key is that we leave RL_STATE_ISEARCH set. */
  854:   if (RL_ISSTATE (RL_STATE_CALLBACK))
  855:     return (0);
  856: 
  857:   r = -1;
  858:   for (;;)
  859:     {
  860:       c = _rl_search_getchar (cxt);
  861:       /* We might want to handle EOF here (c == 0) */
  862:       r = _rl_isearch_dispatch (cxt, cxt->lastc);
  863:       if (r <= 0)
  864:         break;
  865:     }
  866: 
  867:   /* The searching is over.  The user may have found the string that she
  868:      was looking for, or else she may have exited a failing search.  If
  869:      LINE_INDEX is -1, then that shows that the string searched for was
  870:      not found.  We use this to determine where to place rl_point. */
  871:   return (_rl_isearch_cleanup (cxt, r));
  872: }
  873: 
  874: #if defined (READLINE_CALLBACKS)
  875: /* Called from the callback functions when we are ready to read a key.  The
  876:    callback functions know to call this because RL_ISSTATE(RL_STATE_ISEARCH).
  877:    If _rl_isearch_dispatch finishes searching, this function is responsible
  878:    for turning off RL_STATE_ISEARCH, which it does using _rl_isearch_cleanup. */
  879: int
  880: _rl_isearch_callback (_rl_search_cxt *cxt)
  881: {
  882:   int c, r;
  883: 
  884:   c = _rl_search_getchar (cxt);
  885:   /* We might want to handle EOF here */
  886:   r = _rl_isearch_dispatch (cxt, cxt->lastc);
  887: 
  888:   return (r <= 0) ? _rl_isearch_cleanup (cxt, r) : 0;
  889: }
  890: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>