File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / search.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jul 30 08:16:45 2014 UTC (9 years, 11 months ago) by misho
Branches: readline, MAIN
CVS tags: v6_3p10_cross, v6_3p10, v6_3, p6, HEAD
readline 6.3

    1: /* search.c - code for non-incremental searching in emacs and vi modes. */
    2: 
    3: /* Copyright (C) 1992-2013 Free Software Foundation, Inc.
    4: 
    5:    This file is part of the GNU Readline Library (Readline), a library
    6:    for reading lines of text with interactive input and history editing.      
    7: 
    8:    Readline is free software: you can redistribute it and/or modify
    9:    it under the terms of the GNU General Public License as published by
   10:    the Free Software Foundation, either version 3 of the License, or
   11:    (at your option) any later version.
   12: 
   13:    Readline is distributed in the hope that it will be useful,
   14:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:    GNU General Public License for more details.
   17: 
   18:    You should have received a copy of the GNU General Public License
   19:    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
   20: */
   21: 
   22: #define READLINE_LIBRARY
   23: 
   24: #if defined (HAVE_CONFIG_H)
   25: #  include <config.h>
   26: #endif
   27: 
   28: #include <sys/types.h>
   29: #include <stdio.h>
   30: 
   31: #if defined (HAVE_UNISTD_H)
   32: #  include <unistd.h>
   33: #endif
   34: 
   35: #if defined (HAVE_STDLIB_H)
   36: #  include <stdlib.h>
   37: #else
   38: #  include "ansi_stdlib.h"
   39: #endif
   40: 
   41: #include "rldefs.h"
   42: #include "rlmbutil.h"
   43: 
   44: #include "readline.h"
   45: #include "history.h"
   46: #include "histlib.h"
   47: 
   48: #include "rlprivate.h"
   49: #include "xmalloc.h"
   50: 
   51: #ifdef abs
   52: #  undef abs
   53: #endif
   54: #define abs(x)		(((x) >= 0) ? (x) : -(x))
   55: 
   56: _rl_search_cxt *_rl_nscxt = 0;
   57: 
   58: extern HIST_ENTRY *_rl_saved_line_for_history;
   59: 
   60: /* Functions imported from the rest of the library. */
   61: extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
   62: 
   63: static char *noninc_search_string = (char *) NULL;
   64: static int noninc_history_pos;
   65: 
   66: static char *prev_line_found = (char *) NULL;
   67: 
   68: static int rl_history_search_len;
   69: static int rl_history_search_pos;
   70: static int rl_history_search_flags;
   71: 
   72: static char *history_search_string;
   73: static int history_string_size;
   74: 
   75: static void make_history_line_current PARAMS((HIST_ENTRY *));
   76: static int noninc_search_from_pos PARAMS((char *, int, int));
   77: static int noninc_dosearch PARAMS((char *, int));
   78: static int noninc_search PARAMS((int, int));
   79: static int rl_history_search_internal PARAMS((int, int));
   80: static void rl_history_search_reinit PARAMS((int));
   81: 
   82: static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
   83: static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
   84: static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
   85: static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
   86: 
   87: /* Make the data from the history entry ENTRY be the contents of the
   88:    current line.  This doesn't do anything with rl_point; the caller
   89:    must set it. */
   90: static void
   91: make_history_line_current (entry)
   92:      HIST_ENTRY *entry;
   93: {
   94:   _rl_replace_text (entry->line, 0, rl_end);
   95:   _rl_fix_point (1);
   96: #if defined (VI_MODE)
   97:   if (rl_editing_mode == vi_mode)
   98:     /* POSIX.2 says that the `U' command doesn't affect the copy of any
   99:        command lines to the edit line.  We're going to implement that by
  100:        making the undo list start after the matching line is copied to the
  101:        current editing buffer. */
  102:     rl_free_undo_list ();
  103: #endif
  104: 
  105:   if (_rl_saved_line_for_history)
  106:     _rl_free_history_entry (_rl_saved_line_for_history);
  107:   _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
  108: }
  109: 
  110: /* Search the history list for STRING starting at absolute history position
  111:    POS.  If STRING begins with `^', the search must match STRING at the
  112:    beginning of a history line, otherwise a full substring match is performed
  113:    for STRING.  DIR < 0 means to search backwards through the history list,
  114:    DIR >= 0 means to search forward. */
  115: static int
  116: noninc_search_from_pos (string, pos, dir)
  117:      char *string;
  118:      int pos, dir;
  119: {
  120:   int ret, old;
  121: 
  122:   if (pos < 0)
  123:     return -1;
  124: 
  125:   old = where_history ();
  126:   if (history_set_pos (pos) == 0)
  127:     return -1;
  128: 
  129:   RL_SETSTATE(RL_STATE_SEARCH);
  130:   if (*string == '^')
  131:     ret = history_search_prefix (string + 1, dir);
  132:   else
  133:     ret = history_search (string, dir);
  134:   RL_UNSETSTATE(RL_STATE_SEARCH);
  135: 
  136:   if (ret != -1)
  137:     ret = where_history ();
  138: 
  139:   history_set_pos (old);
  140:   return (ret);
  141: }
  142: 
  143: /* Search for a line in the history containing STRING.  If DIR is < 0, the
  144:    search is backwards through previous entries, else through subsequent
  145:    entries.  Returns 1 if the search was successful, 0 otherwise. */
  146: static int
  147: noninc_dosearch (string, dir)
  148:      char *string;
  149:      int dir;
  150: {
  151:   int oldpos, pos;
  152:   HIST_ENTRY *entry;
  153: 
  154:   if (string == 0 || *string == '\0' || noninc_history_pos < 0)
  155:     {
  156:       rl_ding ();
  157:       return 0;
  158:     }
  159: 
  160:   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
  161:   if (pos == -1)
  162:     {
  163:       /* Search failed, current history position unchanged. */
  164:       rl_maybe_unsave_line ();
  165:       rl_clear_message ();
  166:       rl_point = 0;
  167:       rl_ding ();
  168:       return 0;
  169:     }
  170: 
  171:   noninc_history_pos = pos;
  172: 
  173:   oldpos = where_history ();
  174:   history_set_pos (noninc_history_pos);
  175:   entry = current_history ();		/* will never be NULL after successful search */
  176:   
  177: #if defined (VI_MODE)
  178:   if (rl_editing_mode != vi_mode)
  179: #endif
  180:     history_set_pos (oldpos);
  181: 
  182:   make_history_line_current (entry);
  183: 
  184:   rl_point = 0;
  185:   rl_mark = rl_end;
  186: 
  187:   rl_clear_message ();
  188:   return 1;
  189: }
  190: 
  191: static _rl_search_cxt *
  192: _rl_nsearch_init (dir, pchar)
  193:      int dir, pchar;
  194: {
  195:   _rl_search_cxt *cxt;
  196:   char *p;
  197: 
  198:   cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
  199:   if (dir < 0)
  200:     cxt->sflags |= SF_REVERSE;		/* not strictly needed */
  201: 
  202:   cxt->direction = dir;
  203:   cxt->history_pos = cxt->save_line;
  204: 
  205:   rl_maybe_save_line ();
  206: 
  207:   /* Clear the undo list, since reading the search string should create its
  208:      own undo list, and the whole list will end up being freed when we
  209:      finish reading the search string. */
  210:   rl_undo_list = 0;
  211: 
  212:   /* Use the line buffer to read the search string. */
  213:   rl_line_buffer[0] = 0;
  214:   rl_end = rl_point = 0;
  215: 
  216:   p = _rl_make_prompt_for_search (pchar ? pchar : ':');
  217:   rl_message ("%s", p);
  218:   xfree (p);
  219: 
  220:   RL_SETSTATE(RL_STATE_NSEARCH);
  221: 
  222:   _rl_nscxt = cxt;
  223: 
  224:   return cxt;
  225: }
  226: 
  227: static int
  228: _rl_nsearch_cleanup (cxt, r)
  229:      _rl_search_cxt *cxt;
  230:      int r;
  231: {
  232:   _rl_scxt_dispose (cxt, 0);
  233:   _rl_nscxt = 0;
  234: 
  235:   RL_UNSETSTATE(RL_STATE_NSEARCH);
  236: 
  237:   return (r != 1);
  238: }
  239: 
  240: static void
  241: _rl_nsearch_abort (cxt)
  242:      _rl_search_cxt *cxt;
  243: {
  244:   rl_maybe_unsave_line ();
  245:   rl_clear_message ();
  246:   rl_point = cxt->save_point;
  247:   rl_mark = cxt->save_mark;
  248:   rl_restore_prompt ();
  249: 
  250:   RL_UNSETSTATE (RL_STATE_NSEARCH);
  251: }
  252: 
  253: /* Process just-read character C according to search context CXT.  Return -1
  254:    if the caller should abort the search, 0 if we should break out of the
  255:    loop, and 1 if we should continue to read characters. */
  256: static int
  257: _rl_nsearch_dispatch (cxt, c)
  258:      _rl_search_cxt *cxt;
  259:      int c;
  260: {
  261:   switch (c)
  262:     {
  263:     case CTRL('W'):
  264:       rl_unix_word_rubout (1, c);
  265:       break;
  266: 
  267:     case CTRL('U'):
  268:       rl_unix_line_discard (1, c);
  269:       break;
  270: 
  271:     case RETURN:
  272:     case NEWLINE:
  273:       return 0;
  274: 
  275:     case CTRL('H'):
  276:     case RUBOUT:
  277:       if (rl_point == 0)
  278: 	{
  279: 	  _rl_nsearch_abort (cxt);
  280: 	  return -1;
  281: 	}
  282:       _rl_rubout_char (1, c);
  283:       break;
  284: 
  285:     case CTRL('C'):
  286:     case CTRL('G'):
  287:       rl_ding ();
  288:       _rl_nsearch_abort (cxt);
  289:       return -1;
  290: 
  291:     default:
  292: #if defined (HANDLE_MULTIBYTE)
  293:       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
  294: 	rl_insert_text (cxt->mb);
  295:       else
  296: #endif
  297: 	_rl_insert_char (1, c);
  298:       break;
  299:     }
  300: 
  301:   (*rl_redisplay_function) ();
  302:   return 1;
  303: }
  304: 
  305: /* Perform one search according to CXT, using NONINC_SEARCH_STRING.  Return
  306:    -1 if the search should be aborted, any other value means to clean up
  307:    using _rl_nsearch_cleanup ().  Returns 1 if the search was successful,
  308:    0 otherwise. */
  309: static int
  310: _rl_nsearch_dosearch (cxt)
  311:      _rl_search_cxt *cxt;
  312: {
  313:   rl_mark = cxt->save_mark;
  314: 
  315:   /* If rl_point == 0, we want to re-use the previous search string and
  316:      start from the saved history position.  If there's no previous search
  317:      string, punt. */
  318:   if (rl_point == 0)
  319:     {
  320:       if (noninc_search_string == 0)
  321: 	{
  322: 	  rl_ding ();
  323: 	  rl_restore_prompt ();
  324: 	  RL_UNSETSTATE (RL_STATE_NSEARCH);
  325: 	  return -1;
  326: 	}
  327:     }
  328:   else
  329:     {
  330:       /* We want to start the search from the current history position. */
  331:       noninc_history_pos = cxt->save_line;
  332:       FREE (noninc_search_string);
  333:       noninc_search_string = savestring (rl_line_buffer);
  334: 
  335:       /* If we don't want the subsequent undo list generated by the search
  336: 	 matching a history line to include the contents of the search string,
  337: 	 we need to clear rl_line_buffer here.  For now, we just clear the
  338: 	 undo list generated by reading the search string.  (If the search
  339: 	 fails, the old undo list will be restored by rl_maybe_unsave_line.) */
  340:       rl_free_undo_list ();
  341:     }
  342: 
  343:   rl_restore_prompt ();
  344:   return (noninc_dosearch (noninc_search_string, cxt->direction));
  345: }
  346: 
  347: /* Search non-interactively through the history list.  DIR < 0 means to
  348:    search backwards through the history of previous commands; otherwise
  349:    the search is for commands subsequent to the current position in the
  350:    history list.  PCHAR is the character to use for prompting when reading
  351:    the search string; if not specified (0), it defaults to `:'. */
  352: static int
  353: noninc_search (dir, pchar)
  354:      int dir;
  355:      int pchar;
  356: {
  357:   _rl_search_cxt *cxt;
  358:   int c, r;
  359: 
  360:   cxt = _rl_nsearch_init (dir, pchar);
  361: 
  362:   if (RL_ISSTATE (RL_STATE_CALLBACK))
  363:     return (0);
  364: 
  365:   /* Read the search string. */
  366:   r = 0;
  367:   while (1)
  368:     {
  369:       c = _rl_search_getchar (cxt);
  370: 
  371:       if (c == 0)
  372: 	break;
  373: 
  374:       r = _rl_nsearch_dispatch (cxt, c);
  375:       if (r < 0)
  376:         return 1;
  377:       else if (r == 0)
  378: 	break;        
  379:     }
  380: 
  381:   r = _rl_nsearch_dosearch (cxt);
  382:   return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
  383: }
  384: 
  385: /* Search forward through the history list for a string.  If the vi-mode
  386:    code calls this, KEY will be `?'. */
  387: int
  388: rl_noninc_forward_search (count, key)
  389:      int count, key;
  390: {
  391:   return noninc_search (1, (key == '?') ? '?' : 0);
  392: }
  393: 
  394: /* Reverse search the history list for a string.  If the vi-mode code
  395:    calls this, KEY will be `/'. */
  396: int
  397: rl_noninc_reverse_search (count, key)
  398:      int count, key;
  399: {
  400:   return noninc_search (-1, (key == '/') ? '/' : 0);
  401: }
  402: 
  403: /* Search forward through the history list for the last string searched
  404:    for.  If there is no saved search string, abort. */
  405: int
  406: rl_noninc_forward_search_again (count, key)
  407:      int count, key;
  408: {
  409:   int r;
  410: 
  411:   if (!noninc_search_string)
  412:     {
  413:       rl_ding ();
  414:       return (-1);
  415:     }
  416:   r = noninc_dosearch (noninc_search_string, 1);
  417:   return (r != 1);
  418: }
  419: 
  420: /* Reverse search in the history list for the last string searched
  421:    for.  If there is no saved search string, abort. */
  422: int
  423: rl_noninc_reverse_search_again (count, key)
  424:      int count, key;
  425: {
  426:   int r;
  427: 
  428:   if (!noninc_search_string)
  429:     {
  430:       rl_ding ();
  431:       return (-1);
  432:     }
  433:   r = noninc_dosearch (noninc_search_string, -1);
  434:   return (r != 1);
  435: }
  436: 
  437: #if defined (READLINE_CALLBACKS)
  438: int
  439: _rl_nsearch_callback (cxt)
  440:      _rl_search_cxt *cxt;
  441: {
  442:   int c, r;
  443: 
  444:   c = _rl_search_getchar (cxt);
  445:   r = _rl_nsearch_dispatch (cxt, c);
  446:   if (r != 0)
  447:     return 1;
  448: 
  449:   r = _rl_nsearch_dosearch (cxt);
  450:   return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
  451: }
  452: #endif
  453:   
  454: static int
  455: rl_history_search_internal (count, dir)
  456:      int count, dir;
  457: {
  458:   HIST_ENTRY *temp;
  459:   int ret, oldpos;
  460:   char *t;
  461: 
  462:   rl_maybe_save_line ();
  463:   temp = (HIST_ENTRY *)NULL;
  464: 
  465:   /* Search COUNT times through the history for a line matching
  466:      history_search_string.  If history_search_string[0] == '^', the
  467:      line must match from the start; otherwise any substring can match.
  468:      When this loop finishes, TEMP, if non-null, is the history line to
  469:      copy into the line buffer. */
  470:   while (count)
  471:     {
  472:       RL_CHECK_SIGNALS ();
  473:       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
  474:       if (ret == -1)
  475: 	break;
  476: 
  477:       /* Get the history entry we found. */
  478:       rl_history_search_pos = ret;
  479:       oldpos = where_history ();
  480:       history_set_pos (rl_history_search_pos);
  481:       temp = current_history ();	/* will never be NULL after successful search */
  482:       history_set_pos (oldpos);
  483: 
  484:       /* Don't find multiple instances of the same line. */
  485:       if (prev_line_found && STREQ (prev_line_found, temp->line))
  486:         continue;
  487:       prev_line_found = temp->line;
  488:       count--;
  489:     }
  490: 
  491:   /* If we didn't find anything at all, return. */
  492:   if (temp == 0)
  493:     {
  494:       rl_maybe_unsave_line ();
  495:       rl_ding ();
  496:       /* If you don't want the saved history line (last match) to show up
  497:          in the line buffer after the search fails, change the #if 0 to
  498:          #if 1 */
  499: #if 0
  500:       if (rl_point > rl_history_search_len)
  501:         {
  502:           rl_point = rl_end = rl_history_search_len;
  503:           rl_line_buffer[rl_end] = '\0';
  504:           rl_mark = 0;
  505:         }
  506: #else
  507:       rl_point = rl_history_search_len;	/* rl_maybe_unsave_line changes it */
  508:       rl_mark = rl_end;
  509: #endif
  510:       return 1;
  511:     }
  512: 
  513:   /* Copy the line we found into the current line buffer. */
  514:   make_history_line_current (temp);
  515: 
  516:   if (rl_history_search_flags & ANCHORED_SEARCH)
  517:     rl_point = rl_history_search_len;	/* easy case */
  518:   else
  519:     {
  520:       t = strstr (rl_line_buffer, history_search_string);
  521:       rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
  522:     }
  523:   rl_mark = rl_end;
  524: 
  525:   return 0;
  526: }
  527: 
  528: static void
  529: rl_history_search_reinit (flags)
  530:      int flags;
  531: {
  532:   int sind;
  533: 
  534:   rl_history_search_pos = where_history ();
  535:   rl_history_search_len = rl_point;
  536:   rl_history_search_flags = flags;
  537: 
  538:   prev_line_found = (char *)NULL;
  539:   if (rl_point)
  540:     {
  541:       /* Allocate enough space for anchored and non-anchored searches */
  542:       if (rl_history_search_len >= history_string_size - 2)
  543: 	{
  544: 	  history_string_size = rl_history_search_len + 2;
  545: 	  history_search_string = (char *)xrealloc (history_search_string, history_string_size);
  546: 	}
  547:       sind = 0;
  548:       if (flags & ANCHORED_SEARCH)
  549: 	history_search_string[sind++] = '^';
  550:       strncpy (history_search_string + sind, rl_line_buffer, rl_point);
  551:       history_search_string[rl_point + sind] = '\0';
  552:     }
  553:   _rl_free_saved_history_line ();
  554: }
  555: 
  556: /* Search forward in the history for the string of characters
  557:    from the start of the line to rl_point.  This is a non-incremental
  558:    search.  The search is anchored to the beginning of the history line. */
  559: int
  560: rl_history_search_forward (count, ignore)
  561:      int count, ignore;
  562: {
  563:   if (count == 0)
  564:     return (0);
  565: 
  566:   if (rl_last_func != rl_history_search_forward &&
  567:       rl_last_func != rl_history_search_backward)
  568:     rl_history_search_reinit (ANCHORED_SEARCH);
  569: 
  570:   if (rl_history_search_len == 0)
  571:     return (rl_get_next_history (count, ignore));
  572:   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
  573: }
  574: 
  575: /* Search backward through the history for the string of characters
  576:    from the start of the line to rl_point.  This is a non-incremental
  577:    search. */
  578: int
  579: rl_history_search_backward (count, ignore)
  580:      int count, ignore;
  581: {
  582:   if (count == 0)
  583:     return (0);
  584: 
  585:   if (rl_last_func != rl_history_search_forward &&
  586:       rl_last_func != rl_history_search_backward)
  587:     rl_history_search_reinit (ANCHORED_SEARCH);
  588: 
  589:   if (rl_history_search_len == 0)
  590:     return (rl_get_previous_history (count, ignore));
  591:   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
  592: }
  593: 
  594: /* Search forward in the history for the string of characters
  595:    from the start of the line to rl_point.  This is a non-incremental
  596:    search.  The search succeeds if the search string is present anywhere
  597:    in the history line. */
  598: int
  599: rl_history_substr_search_forward (count, ignore)
  600:      int count, ignore;
  601: {
  602:   if (count == 0)
  603:     return (0);
  604: 
  605:   if (rl_last_func != rl_history_substr_search_forward &&
  606:       rl_last_func != rl_history_substr_search_backward)
  607:     rl_history_search_reinit (NON_ANCHORED_SEARCH);
  608: 
  609:   if (rl_history_search_len == 0)
  610:     return (rl_get_next_history (count, ignore));
  611:   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
  612: }
  613: 
  614: /* Search backward through the history for the string of characters
  615:    from the start of the line to rl_point.  This is a non-incremental
  616:    search. */
  617: int
  618: rl_history_substr_search_backward (count, ignore)
  619:      int count, ignore;
  620: {
  621:   if (count == 0)
  622:     return (0);
  623: 
  624:   if (rl_last_func != rl_history_substr_search_forward &&
  625:       rl_last_func != rl_history_substr_search_backward)
  626:     rl_history_search_reinit (NON_ANCHORED_SEARCH);
  627: 
  628:   if (rl_history_search_len == 0)
  629:     return (rl_get_previous_history (count, ignore));
  630:   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
  631: }

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