Annotation of embedaddon/readline/histsearch.c, revision 1.1.1.2
1.1 misho 1: /* histsearch.c -- searching the history list. */
2:
1.1.1.2 ! misho 3: /* Copyright (C) 1989, 1992-2009,2017 Free Software Foundation, Inc.
1.1 misho 4:
5: This file contains the GNU History Library (History), a set of
6: routines for managing the text of previously typed lines.
7:
8: History 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: History 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 History. 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 <stdio.h>
29: #if defined (HAVE_STDLIB_H)
30: # include <stdlib.h>
31: #else
32: # include "ansi_stdlib.h"
33: #endif /* HAVE_STDLIB_H */
34:
35: #if defined (HAVE_UNISTD_H)
36: # ifdef _MINIX
37: # include <sys/types.h>
38: # endif
39: # include <unistd.h>
40: #endif
41:
1.1.1.2 ! misho 42: #if defined (HAVE_FNMATCH)
! 43: # include <fnmatch.h>
! 44: #endif
! 45:
1.1 misho 46: #include "history.h"
47: #include "histlib.h"
1.1.1.2 ! misho 48: #include "xmalloc.h"
1.1 misho 49:
50: /* The list of alternate characters that can delimit a history search
51: string. */
52: char *history_search_delimiter_chars = (char *)NULL;
53:
54: static int history_search_internal PARAMS((const char *, int, int));
55:
56: /* Search the history for STRING, starting at history_offset.
57: If DIRECTION < 0, then the search is through previous entries, else
58: through subsequent. If ANCHORED is non-zero, the string must
59: appear at the beginning of a history line, otherwise, the string
60: may appear anywhere in the line. If the string is found, then
61: current_history () is the history entry, and the value of this
62: function is the offset in the line of that history entry that the
63: string was found in. Otherwise, nothing is changed, and a -1 is
64: returned. */
65:
66: static int
1.1.1.2 ! misho 67: history_search_internal (const char *string, int direction, int flags)
1.1 misho 68: {
69: register int i, reverse;
70: register char *line;
71: register int line_index;
1.1.1.2 ! misho 72: int string_len, anchored, patsearch;
1.1 misho 73: HIST_ENTRY **the_history; /* local */
74:
75: i = history_offset;
76: reverse = (direction < 0);
1.1.1.2 ! misho 77: anchored = (flags & ANCHORED_SEARCH);
! 78: #if defined (HAVE_FNMATCH)
! 79: patsearch = (flags & PATTERN_SEARCH);
! 80: #else
! 81: patsearch = 0;
! 82: #endif
1.1 misho 83:
84: /* Take care of trivial cases first. */
85: if (string == 0 || *string == '\0')
86: return (-1);
87:
88: if (!history_length || ((i >= history_length) && !reverse))
89: return (-1);
90:
91: if (reverse && (i >= history_length))
92: i = history_length - 1;
93:
94: #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
95:
96: the_history = history_list ();
97: string_len = strlen (string);
98: while (1)
99: {
100: /* Search each line in the history list for STRING. */
101:
102: /* At limit for direction? */
103: if ((reverse && i < 0) || (!reverse && i == history_length))
104: return (-1);
105:
106: line = the_history[i]->line;
107: line_index = strlen (line);
108:
109: /* If STRING is longer than line, no match. */
1.1.1.2 ! misho 110: if (patsearch == 0 && (string_len > line_index))
1.1 misho 111: {
112: NEXT_LINE ();
113: continue;
114: }
115:
116: /* Handle anchored searches first. */
117: if (anchored == ANCHORED_SEARCH)
118: {
1.1.1.2 ! misho 119: #if defined (HAVE_FNMATCH)
! 120: if (patsearch)
! 121: {
! 122: if (fnmatch (string, line, 0) == 0)
! 123: {
! 124: history_offset = i;
! 125: return (0);
! 126: }
! 127: }
! 128: else
! 129: #endif
1.1 misho 130: if (STREQN (string, line, string_len))
131: {
132: history_offset = i;
133: return (0);
134: }
135:
136: NEXT_LINE ();
137: continue;
138: }
139:
140: /* Do substring search. */
141: if (reverse)
142: {
1.1.1.2 ! misho 143: line_index -= (patsearch == 0) ? string_len : 1;
1.1 misho 144:
145: while (line_index >= 0)
146: {
1.1.1.2 ! misho 147: #if defined (HAVE_FNMATCH)
! 148: if (patsearch)
! 149: {
! 150: if (fnmatch (string, line + line_index, 0) == 0)
! 151: {
! 152: history_offset = i;
! 153: return (line_index);
! 154: }
! 155: }
! 156: else
! 157: #endif
1.1 misho 158: if (STREQN (string, line + line_index, string_len))
159: {
160: history_offset = i;
161: return (line_index);
162: }
163: line_index--;
164: }
165: }
166: else
167: {
168: register int limit;
169:
170: limit = line_index - string_len + 1;
171: line_index = 0;
172:
173: while (line_index < limit)
174: {
1.1.1.2 ! misho 175: #if defined (HAVE_FNMATCH)
! 176: if (patsearch)
! 177: {
! 178: if (fnmatch (string, line + line_index, 0) == 0)
! 179: {
! 180: history_offset = i;
! 181: return (line_index);
! 182: }
! 183: }
! 184: else
! 185: #endif
1.1 misho 186: if (STREQN (string, line + line_index, string_len))
187: {
188: history_offset = i;
189: return (line_index);
190: }
191: line_index++;
192: }
193: }
194: NEXT_LINE ();
195: }
196: }
197:
1.1.1.2 ! misho 198: int
! 199: _hs_history_patsearch (const char *string, int direction, int flags)
! 200: {
! 201: char *pat;
! 202: size_t len, start;
! 203: int ret, unescaped_backslash;
! 204:
! 205: #if defined (HAVE_FNMATCH)
! 206: /* Assume that the string passed does not have a leading `^' and any
! 207: anchored search request is captured in FLAGS */
! 208: len = strlen (string);
! 209: ret = len - 1;
! 210: /* fnmatch is required to reject a pattern that ends with an unescaped
! 211: backslash */
! 212: if (unescaped_backslash = (string[ret] == '\\'))
! 213: {
! 214: while (ret > 0 && string[--ret] == '\\')
! 215: unescaped_backslash = 1 - unescaped_backslash;
! 216: }
! 217: if (unescaped_backslash)
! 218: return -1;
! 219: pat = (char *)xmalloc (len + 3);
! 220: /* If the search string is not anchored, we'll be calling fnmatch (assuming
! 221: we have it). Prefix a `*' to the front of the search string so we search
! 222: anywhere in the line. */
! 223: if ((flags & ANCHORED_SEARCH) == 0 && string[0] != '*')
! 224: {
! 225: pat[0] = '*';
! 226: start = 1;
! 227: len++;
! 228: }
! 229: else
! 230: {
! 231: start = 0;
! 232: }
! 233:
! 234: /* Attempt to reduce the number of searches by tacking a `*' onto the end
! 235: of a pattern that doesn't have one. Assume a pattern that ends in a
! 236: backslash contains an even number of trailing backslashes; we check
! 237: above */
! 238: strcpy (pat + start, string);
! 239: if (pat[len - 1] != '*')
! 240: {
! 241: pat[len] = '*'; /* XXX */
! 242: pat[len+1] = '\0';
! 243: }
! 244: #else
! 245: pat = string;
! 246: #endif
! 247:
! 248: ret = history_search_internal (pat, direction, flags|PATTERN_SEARCH);
! 249:
! 250: if (pat != string)
! 251: free (pat);
! 252: return ret;
! 253: }
! 254:
1.1 misho 255: /* Do a non-anchored search for STRING through the history in DIRECTION. */
256: int
1.1.1.2 ! misho 257: history_search (const char *string, int direction)
1.1 misho 258: {
259: return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
260: }
261:
262: /* Do an anchored search for string through the history in DIRECTION. */
263: int
1.1.1.2 ! misho 264: history_search_prefix (const char *string, int direction)
1.1 misho 265: {
266: return (history_search_internal (string, direction, ANCHORED_SEARCH));
267: }
268:
269: /* Search for STRING in the history list. DIR is < 0 for searching
270: backwards. POS is an absolute index into the history list at
271: which point to begin searching. */
272: int
1.1.1.2 ! misho 273: history_search_pos (const char *string, int dir, int pos)
1.1 misho 274: {
275: int ret, old;
276:
277: old = where_history ();
278: history_set_pos (pos);
279: if (history_search (string, dir) == -1)
280: {
281: history_set_pos (old);
282: return (-1);
283: }
284: ret = where_history ();
285: history_set_pos (old);
286: return ret;
287: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>