Annotation of embedaddon/readline/isearch.c, revision 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>