ledit

Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/ledit.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ledit.git (over tor)
Log | Files | Refs | README | 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 }