File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / isearch.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Wed Jul 30 08:16:45 2014 UTC (9 years, 10 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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