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

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