histsearch.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /* histsearch.c -- searching the history list. */
  2. /* Copyright (C) 1989, 1992-2009 Free Software Foundation, Inc.
  3. This file contains the GNU History Library (History), a set of
  4. routines for managing the text of previously typed lines.
  5. History is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. History is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with History. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #define READLINE_LIBRARY
  17. #if defined (HAVE_CONFIG_H)
  18. # include <config.h>
  19. #endif
  20. #include <stdio.h>
  21. #if defined (HAVE_STDLIB_H)
  22. # include <stdlib.h>
  23. #else
  24. # include "ansi_stdlib.h"
  25. #endif /* HAVE_STDLIB_H */
  26. #if defined (HAVE_UNISTD_H)
  27. # ifdef _MINIX
  28. # include <sys/types.h>
  29. # endif
  30. # include <unistd.h>
  31. #endif
  32. #include "history.h"
  33. #include "histlib.h"
  34. /* The list of alternate characters that can delimit a history search
  35. string. */
  36. char *history_search_delimiter_chars = (char *)NULL;
  37. static int history_search_internal PARAMS((const char *, int, int));
  38. /* Search the history for STRING, starting at history_offset.
  39. If DIRECTION < 0, then the search is through previous entries, else
  40. through subsequent. If ANCHORED is non-zero, the string must
  41. appear at the beginning of a history line, otherwise, the string
  42. may appear anywhere in the line. If the string is found, then
  43. current_history () is the history entry, and the value of this
  44. function is the offset in the line of that history entry that the
  45. string was found in. Otherwise, nothing is changed, and a -1 is
  46. returned. */
  47. static int
  48. history_search_internal (string, direction, anchored)
  49. const char *string;
  50. int direction, anchored;
  51. {
  52. register int i, reverse;
  53. register char *line;
  54. register int line_index;
  55. int string_len;
  56. HIST_ENTRY **the_history; /* local */
  57. i = history_offset;
  58. reverse = (direction < 0);
  59. /* Take care of trivial cases first. */
  60. if (string == 0 || *string == '\0')
  61. return (-1);
  62. if (!history_length || ((i >= history_length) && !reverse))
  63. return (-1);
  64. if (reverse && (i >= history_length))
  65. i = history_length - 1;
  66. #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
  67. the_history = history_list ();
  68. string_len = strlen (string);
  69. while (1)
  70. {
  71. /* Search each line in the history list for STRING. */
  72. /* At limit for direction? */
  73. if ((reverse && i < 0) || (!reverse && i == history_length))
  74. return (-1);
  75. line = the_history[i]->line;
  76. line_index = strlen (line);
  77. /* If STRING is longer than line, no match. */
  78. if (string_len > line_index)
  79. {
  80. NEXT_LINE ();
  81. continue;
  82. }
  83. /* Handle anchored searches first. */
  84. if (anchored == ANCHORED_SEARCH)
  85. {
  86. if (STREQN (string, line, string_len))
  87. {
  88. history_offset = i;
  89. return (0);
  90. }
  91. NEXT_LINE ();
  92. continue;
  93. }
  94. /* Do substring search. */
  95. if (reverse)
  96. {
  97. line_index -= string_len;
  98. while (line_index >= 0)
  99. {
  100. if (STREQN (string, line + line_index, string_len))
  101. {
  102. history_offset = i;
  103. return (line_index);
  104. }
  105. line_index--;
  106. }
  107. }
  108. else
  109. {
  110. register int limit;
  111. limit = line_index - string_len + 1;
  112. line_index = 0;
  113. while (line_index < limit)
  114. {
  115. if (STREQN (string, line + line_index, string_len))
  116. {
  117. history_offset = i;
  118. return (line_index);
  119. }
  120. line_index++;
  121. }
  122. }
  123. NEXT_LINE ();
  124. }
  125. }
  126. /* Do a non-anchored search for STRING through the history in DIRECTION. */
  127. int
  128. history_search (string, direction)
  129. const char *string;
  130. int direction;
  131. {
  132. return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
  133. }
  134. /* Do an anchored search for string through the history in DIRECTION. */
  135. int
  136. history_search_prefix (string, direction)
  137. const char *string;
  138. int direction;
  139. {
  140. return (history_search_internal (string, direction, ANCHORED_SEARCH));
  141. }
  142. /* Search for STRING in the history list. DIR is < 0 for searching
  143. backwards. POS is an absolute index into the history list at
  144. which point to begin searching. */
  145. int
  146. history_search_pos (string, dir, pos)
  147. const char *string;
  148. int dir, pos;
  149. {
  150. int ret, old;
  151. old = where_history ();
  152. history_set_pos (pos);
  153. if (history_search (string, dir) == -1)
  154. {
  155. history_set_pos (old);
  156. return (-1);
  157. }
  158. ret = where_history ();
  159. history_set_pos (old);
  160. return ret;
  161. }