Annotation of embedaddon/readline/search.c, revision 1.1.1.1

1.1       misho       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>