URI: 
       search.c - ledit - Text editor (WIP)
  HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/ledit.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ledit.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       search.c (5173B)
       ---
            1 #include <string.h>
            2 
            3 #include "view.h"
            4 #include "buffer.h"
            5 #include "search.h"
            6 #include "memory.h"
            7 
            8 /* FIXME: make sure only whole utf8 chars are matched
            9    -> actually, isn't this always the case as long as the
           10    pattern is valid utf8 because of the structure of utf8? */
           11 static char *last_search = NULL;
           12 static size_t last_search_len = 0;
           13 enum {
           14         FORWARD,
           15         BACKWARD
           16 } last_dir = FORWARD;
           17 
           18 void
           19 search_cleanup(void) {
           20         free(last_search);
           21         last_search = NULL;
           22         last_search_len = 0;
           23 }
           24 
           25 void
           26 set_search_forward(char *pattern) {
           27         last_dir = FORWARD;
           28         free(last_search);
           29         last_search = ledit_strdup(pattern);
           30         last_search_len = strlen(last_search);
           31 }
           32 
           33 void
           34 set_search_backward(char *pattern) {
           35         last_dir = BACKWARD;
           36         free(last_search);
           37         last_search = ledit_strdup(pattern);
           38         last_search_len = strlen(last_search);
           39 }
           40 
           41 static search_state
           42 search_forward(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t *len_ret) {
           43         *line_ret = view->cur_line;
           44         *byte_ret = view->cur_index;
           45         *len_ret = last_search_len;
           46         /* if last_search is empty, strstr will find the ending '\0' */
           47         if (last_search == NULL || last_search[0] == '\0')
           48                 return SEARCH_NO_PATTERN;
           49         size_t line = view->cur_line;
           50         /* start one byte later so it doesn't get stuck on a match
           51            note: in certain cases, this may not be a valid index */
           52         size_t byte = view->cur_index + 1;
           53         char *res;
           54         ledit_line *lline = buffer_get_line(view->buffer, line);
           55         buffer_normalize_line(lline);
           56         if (byte < lline->len && (res = strstr(lline->text + byte, last_search)) != NULL) {
           57                 *line_ret = line;
           58                 *byte_ret = (size_t)(res - lline->text);
           59                 return SEARCH_NORMAL;
           60         }
           61         for (size_t i = line + 1; i < view->lines_num; i++) {
           62                 lline = buffer_get_line(view->buffer, i);
           63                 buffer_normalize_line(lline);
           64                 if ((res = strstr(lline->text, last_search)) != NULL) {
           65                         *line_ret = i;
           66                         *byte_ret = (size_t)(res - lline->text);
           67                         return SEARCH_NORMAL;
           68                 }
           69         }
           70         for (size_t i = 0; i < line; i++) {
           71                 lline = buffer_get_line(view->buffer, i);
           72                 buffer_normalize_line(lline);
           73                 if ((res = strstr(lline->text, last_search)) != NULL) {
           74                         *line_ret = i;
           75                         *byte_ret = (size_t)(res - lline->text);
           76                         return SEARCH_WRAPPED;
           77                 }
           78         }
           79         lline = buffer_get_line(view->buffer, line);
           80         buffer_normalize_line(lline);
           81         if ((res = strstr(lline->text, last_search)) != NULL) {
           82                 *line_ret = line;
           83                 *byte_ret = (size_t)(res - lline->text);
           84                 return SEARCH_WRAPPED;
           85         }
           86         return SEARCH_NOT_FOUND;
           87 }
           88 
           89 /* FIXME: this is insanely inefficient */
           90 /* FIXME: just go backwards char-by-char and compare or knuth-morris-pratt */
           91 static search_state
           92 search_backward(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t *len_ret) {
           93         *line_ret = view->cur_line;
           94         *byte_ret = view->cur_index;
           95         *len_ret = last_search_len;
           96         if (last_search == NULL || last_search[0] == '\0')
           97                 return SEARCH_NO_PATTERN;
           98         size_t line = view->cur_line;
           99         size_t byte = view->cur_index;
          100         ledit_line *lline = buffer_get_line(view->buffer, line);
          101         buffer_normalize_line(lline);
          102         char *last = NULL, *res = lline->text;
          103         while ((res = strstr(res, last_search)) != NULL && res < lline->text + byte) {
          104                 last = res;
          105                 res++;
          106         }
          107         if (last != NULL) {
          108                 *line_ret = line;
          109                 /* FIXME: check if this is safe */
          110                 *byte_ret = (size_t)(last - lline->text);
          111                 return SEARCH_NORMAL;
          112         }
          113         for (size_t i = line; i > 0; i--) {
          114                 lline = buffer_get_line(view->buffer, i-1);
          115                 buffer_normalize_line(lline);
          116                 res = lline->text;
          117                 while ((res = strstr(res, last_search)) != NULL) {
          118                         last = res;
          119                         res++;
          120                 }
          121                 if (last != NULL) {
          122                         *line_ret = i-1;
          123                         *byte_ret = (size_t)(last - lline->text);
          124                         return SEARCH_NORMAL;
          125                 }
          126         }
          127         for (size_t i = view->lines_num - 1; i > line; i--) {
          128                 lline = buffer_get_line(view->buffer, i);
          129                 buffer_normalize_line(lline);
          130                 res = lline->text;
          131                 while ((res = strstr(res, last_search)) != NULL) {
          132                         last = res;
          133                         res++;
          134                 }
          135                 if (last != NULL) {
          136                         *line_ret = i;
          137                         *byte_ret = (size_t)(last - lline->text);
          138                         return SEARCH_WRAPPED;
          139                 }
          140         }
          141         lline = buffer_get_line(view->buffer, line);
          142         buffer_normalize_line(lline);
          143         res = lline->text + byte;
          144         while ((res = strstr(res, last_search)) != NULL) {
          145                 last = res;
          146                 res++;
          147         }
          148         if (last != NULL) {
          149                 *line_ret = line;
          150                 *byte_ret = (size_t)(last - lline->text);
          151                 return SEARCH_WRAPPED;
          152         }
          153         return SEARCH_NOT_FOUND;
          154 }
          155 
          156 search_state
          157 ledit_search_next(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t *len_ret) {
          158         if (last_dir == FORWARD)
          159                 return search_forward(view, line_ret, byte_ret, len_ret);
          160         else
          161                 return search_backward(view, line_ret, byte_ret, len_ret);
          162 }
          163 
          164 search_state
          165 ledit_search_prev(ledit_view *view, size_t *line_ret, size_t *byte_ret, size_t *len_ret) {
          166         if (last_dir == FORWARD)
          167                 return search_backward(view, line_ret, byte_ret, len_ret);
          168         else
          169                 return search_forward(view, line_ret, byte_ret, len_ret);
          170 }
          171 
          172 char *
          173 search_state_to_str(search_state s) {
          174         switch (s) {
          175         case SEARCH_NORMAL:
          176                 return "Found match";
          177         case SEARCH_WRAPPED:
          178                 return "Search wrapped";
          179         case SEARCH_NOT_FOUND:
          180                 return "Pattern not found";
          181         case SEARCH_NO_PATTERN:
          182                 return "No previous search pattern";
          183         default:
          184                 return "This message should not be shown. "
          185                        "Please bug lumidify about it.";
          186         }
          187 }