se

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

seek.c (12515B)


      1 
      2 
      3 #if 1
      4 #define _GNU_SOURCE
      5 #endif
      6 
      7 #include "seek.h"
      8 
      9 #include <string.h>
     10 #include <ctype.h>
     11 
     12 #include "config.h"
     13 #include <sys/stat.h>
     14 
     15 #if 0
     16 #define BOUNDS_CHECK(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
     17 #else
     18 #define BOUNDS_CHECK(x, a, b)
     19 #endif
     20 
     21 int
     22 str_contains_char(const char* string, char check)
     23 {
     24 		return strchr(string, check) != NULL;
     25 }
     26 
     27 inline int
     28 is_file_type(const char* file_path, const char* file_type)
     29 {
     30 		int ftlen  = strlen(file_type);
     31 		int offset = strlen(file_path) - ftlen;
     32 		if(offset >= 0 && memcmp(file_path + offset, file_type, ftlen) == 0)
     33 				return 1;
     34 		return 0;
     35 }
     36 
     37 char*
     38 file_path_get_path(const char* path)
     39 {
     40 		soft_assert(path, path = "/";);
     41 
     42 		const char* folder_start = strrchr(path, '/');
     43 		if (!folder_start)
     44 				folder_start = path;
     45 		else
     46 				folder_start++;
     47 		int folder_len = folder_start - path;
     48 		char* folder = xmalloc(folder_len + 1);
     49 
     50 		memcpy(folder, path, folder_len);
     51 		folder[folder_len] = '\0';
     52 
     53 		return folder;
     54 }
     55 
     56 inline int
     57 path_is_folder(const char* path)
     58 {
     59 		struct stat statbuf;
     60 		if (stat(path, &statbuf) != 0)
     61 				return 0;
     62 		return S_ISDIR(statbuf.st_mode);
     63 }
     64 
     65 inline int
     66 fb_seek_char(const struct file_buffer* fb, int offset, char byte)
     67 {
     68 		if (offset > fb->len) return -1;
     69 		char* new_buf = memchr(fb->contents + offset, byte, fb->len - offset);
     70 		if (!new_buf) return -1;
     71 		return new_buf - fb->contents;
     72 }
     73 
     74 inline int
     75 fb_seek_char_backwards(const struct file_buffer* fb, int offset, char byte)
     76 {
     77 		BOUNDS_CHECK(offset, 0, fb->len-1);
     78 		for (int n = offset-1; n >= 0; n--) {
     79 				if (fb->contents[n] == byte) {
     80 						return n+1;
     81 				}
     82 		}
     83 		return -1;
     84 }
     85 
     86 inline int
     87 fb_seek_string(const struct file_buffer* fb, int offset, const char* string)
     88 {
     89 		BOUNDS_CHECK(offset, 0, fb->len-1);
     90 		int str_len = strlen(string);
     91 
     92 #if 0
     93 		for (int n = offset; n < fb->len - str_len; n++)
     94 				if (!memcmp(fb->contents + n, string, str_len))
     95 						return n;
     96 #else
     97 		char* res = memmem(fb->contents + offset, fb->len - offset,
     98 						   string, str_len);
     99 		if (res)
    100 				return res - fb->contents;
    101 #endif
    102 		return -1;
    103 }
    104 
    105 inline int
    106 fb_seek_string_backwards(const struct file_buffer* fb, int offset, const char* string)
    107 {
    108 		int str_len = strlen(string);
    109 		offset += str_len;
    110 		BOUNDS_CHECK(offset, 0, fb->len-1);
    111 
    112 		for (int n = offset - str_len; n >= 0; n--)
    113 				if (!memcmp(fb->contents + n, string, str_len))
    114 						return n;
    115 		return -1;
    116 }
    117 
    118 inline int
    119 wb_seek_string_wrap(const struct window_buffer* wb, int offset, const char* search)
    120 {
    121 		struct file_buffer* fb = get_fb(focused_window);
    122 		if (*search == 0 || !fb_count_string_instances(fb, search, 0, NULL))
    123 				return -1;
    124 
    125 		int new_offset = fb_seek_string(fb, offset, search);
    126 		if (new_offset < 0)
    127 				new_offset = fb_seek_string(fb, 0, search);
    128 
    129 		if (!(fb->mode & FB_SEARCH_BLOCKING))
    130 				fb->mode |= FB_SEARCH_BLOCKING_IDLE;
    131 		return new_offset;
    132 }
    133 
    134 inline int
    135 wb_seek_string_wrap_backwards(const struct window_buffer* wb, int offset, const char* search)
    136 {
    137 		struct file_buffer* fb = get_fb(focused_window);
    138 		if (*search == 0 || !fb_count_string_instances(fb, search, 0, NULL))
    139 				return -1;
    140 
    141 		int new_offset = fb_seek_string_backwards(fb, offset, search);
    142 		if (new_offset < 0)
    143 				new_offset = fb_seek_string_backwards(fb, fb->len, search);
    144 
    145 		if (!(fb->mode & FB_SEARCH_BLOCKING))
    146 				fb->mode |= FB_SEARCH_BLOCKING_IDLE;
    147 		return new_offset;
    148 }
    149 
    150 int
    151 fb_is_on_a_word(const struct file_buffer* fb, int offset, const char* word_seperators)
    152 {
    153 		BOUNDS_CHECK(offset, 0, fb->len);
    154 		return !str_contains_char(word_seperators, fb->contents[offset]);
    155 }
    156 
    157 inline int
    158 fb_is_start_of_a_word(const struct file_buffer* fb, int offset, const char* word_seperators)
    159 {
    160 		BOUNDS_CHECK(offset, 0, fb->len);
    161 		return fb_is_on_a_word(fb, offset, word_seperators) &&
    162 				(offset-1 <= 0 || str_contains_char(word_seperators, fb->contents[offset-1]));
    163 }
    164 
    165 inline int
    166 fb_is_on_word(const struct file_buffer* fb, int offset, const char* word_seperators, const char* word)
    167 {
    168 		BOUNDS_CHECK(offset, 0, fb->len);
    169 		int word_start = fb_seek_start_of_word_backwards(fb, offset, word_seperators);
    170 		int word_len   = strlen(word);
    171 		if (word_start < offset - (word_len-1))
    172 				return 0;
    173 		return fb_offset_starts_with(fb, word_start, word) &&
    174 				!fb_is_on_a_word(fb, word_start + word_len, word_seperators);
    175 }
    176 
    177 inline int
    178 fb_offset_starts_with(const struct file_buffer* fb, int offset, const char* start)
    179 {
    180 		BOUNDS_CHECK(offset, 0, fb->len);
    181 		if (offset > 0 && fb->contents[offset-1] == '\\') return 0;
    182 
    183 		int len = strlen(start);
    184 		int mlen = MIN(len, fb->len - offset);
    185 		return memcmp(fb->contents + offset, start, mlen) == 0;
    186 }
    187 
    188 inline int
    189 fb_seek_word(const struct file_buffer* fb, int offset, const char* word_seperators)
    190 {
    191 		if (fb_is_on_a_word(fb, offset, word_seperators))
    192 				offset = fb_seek_word_end(fb, offset, word_seperators);
    193 		while (offset < fb->len && str_contains_char(word_seperators, fb->contents[offset])) offset++;
    194 		return offset;
    195 }
    196 
    197 inline int
    198 fb_seek_word_end(const struct file_buffer* fb, int offset, const char* word_seperators)
    199 {
    200 		BOUNDS_CHECK(offset, 0, fb->len);
    201 		if (!fb_is_on_a_word(fb, offset, word_seperators))
    202 				offset = fb_seek_word(fb, offset, word_seperators);
    203 		while (offset < fb->len && !str_contains_char(word_seperators, fb->contents[offset])) offset++;
    204 		return offset;
    205 }
    206 
    207 inline int
    208 fb_seek_word_backwards(const struct file_buffer* fb, int offset, const char* word_seperators)
    209 {
    210 		BOUNDS_CHECK(offset, 0, fb->len);
    211 		if (!fb_is_on_a_word(fb, offset, word_seperators))
    212 				while (offset > 0 && str_contains_char(word_seperators, fb->contents[offset])) offset--;
    213 		return offset;
    214 }
    215 
    216 inline int
    217 fb_seek_start_of_word_backwards(const struct file_buffer* fb, int offset, const char* word_seperators)
    218 {
    219 		BOUNDS_CHECK(offset, 0, fb->len);
    220 		if (!fb_is_on_a_word(fb, offset, word_seperators))
    221 				while (offset > 0 && str_contains_char(word_seperators, fb->contents[offset])) offset--;
    222 		while (offset > 0 && !str_contains_char(word_seperators, fb->contents[offset])) offset--;
    223 		return offset+1;
    224 }
    225 
    226 inline int
    227 fb_seek_whitespace(const struct file_buffer* fb, int offset)
    228 {
    229 		BOUNDS_CHECK(offset, 0, fb->len);
    230 		while (offset < fb->len && !isspace(fb->contents[offset])) offset++;
    231 		return offset;
    232 }
    233 
    234 inline int
    235 fb_seek_whitespace_backwards(const struct file_buffer* fb, int offset)
    236 {
    237 		BOUNDS_CHECK(offset, 0, fb->len);
    238 		while (offset > 0 && !isspace(fb->contents[offset])) offset--;
    239 		return offset;
    240 }
    241 
    242 inline int
    243 fb_seek_not_whitespace(const struct file_buffer* fb, int offset)
    244 {
    245 		BOUNDS_CHECK(offset, 0, fb->len);
    246 		while (offset < fb->len && isspace(fb->contents[offset])) offset++;
    247 		return offset;
    248 }
    249 
    250 inline int
    251 fb_seek_not_whitespace_backwards(const struct file_buffer* fb, int offset)
    252 {
    253 		BOUNDS_CHECK(offset, 0, fb->len);
    254 		while (offset > 0 && isspace(fb->contents[offset])) offset--;
    255 		return offset;
    256 }
    257 
    258 inline int
    259 fb_count_string_instances(const struct file_buffer* fb, const char* string, int offset, int* before_offset)
    260 {
    261 		int tmp;
    262 		if (!before_offset)
    263 				before_offset = &tmp;
    264 		if (!string || *string == 0) {
    265 				*before_offset = 0;
    266 				return 0;
    267 		}
    268 
    269 		int pos   = -1;
    270 		int count =  0;
    271 		int once  =  1;
    272 		while((pos = fb_seek_string(fb, pos+1, string)) >= 0) {
    273 				if (pos > 0 && fb->contents[pos-2] == '\\')
    274 						continue;
    275 				if (once && pos > offset) {
    276 						*before_offset = count;
    277 						once = 0;
    278 				}
    279 				count++;
    280 		}
    281 		if (once)
    282 				*before_offset = count;
    283 		return count;
    284 }
    285 
    286 /*
    287 ** Search from the start of the file
    288 ** Once any patterns are found, other patterns are disabled.
    289 ** If the pattern we are searching for extends beyond *offset* then we will use that as our delimiter
    290 */
    291 
    292 ///////////////
    293 // "   \" // we're here "
    294 // ↑                   ↑
    295 // start               seeked end
    296 int
    297 fb_seek_string_not_escaped(const struct file_buffer* fb, int offset, const char* string)
    298 {
    299 		for (;;) {
    300 				offset = fb_seek_string(fb, offset, string);
    301 				if (offset >= 0 && fb->contents[offset-1] == '\\')
    302 						offset++;
    303 				else
    304 						break;
    305 		}
    306 		return offset;
    307 }
    308 
    309 inline int
    310 fb_seek_string_backwards_not_escaped(const struct file_buffer* fb, int offset, const char* string)
    311 {
    312 		for (;;) {
    313 				offset = fb_seek_string_backwards(fb, offset, string);
    314 				if (offset >= 0 && fb->contents[offset-1] == '\\')
    315 						offset--;
    316 				else
    317 						break;
    318 		}
    319 		return offset;
    320 }
    321 
    322 inline static int
    323 fb_get_delimiter_equal_start_end(const struct file_buffer* fb, int offset, const char* string, struct delimiter* ignore, int* start, int* end)
    324 {
    325 		int ignore_index = 0;
    326 		int last_distance = 0;
    327 
    328 		while (last_distance >= 0) {
    329 				int d_res = INT32_MAX;
    330 				int i = 0;
    331 				if (ignore) {
    332 						for (struct delimiter* ign = ignore; ign->start; ign++) {
    333 								int d = fb_seek_string_not_escaped(fb, last_distance, ign->start);
    334 								if (d < 0 || d > offset) {
    335 										i++;
    336 										continue;
    337 								}
    338 
    339 								if (d < d_res) {
    340 										d_res = d;
    341 										ignore_index = i;
    342 								}
    343 								i++;
    344 						}
    345 				}
    346 				int str_d = fb_seek_string_not_escaped(fb, last_distance, string);
    347 
    348 				if ((str_d <= 0 || str_d > offset) && d_res == INT32_MAX)
    349 						return 0;
    350 
    351 				const char* end_str;
    352 				if (str_d >= 0 && str_d <= d_res) {
    353 						last_distance = str_d;
    354 						end_str = string;
    355 						*start = last_distance;
    356 				} else {
    357 						last_distance = d_res;
    358 						end_str = ignore[ignore_index].end;
    359 				}
    360 
    361 				last_distance = fb_seek_string_not_escaped(fb, last_distance+1, end_str);
    362 
    363 				if (end_str == string && last_distance > offset) {
    364 						*end = last_distance;
    365 						return 1;
    366 				}
    367 				if (last_distance >= 0)
    368 						last_distance++;
    369 		}
    370 		return 0;
    371 }
    372 
    373 inline static int
    374 fb_get_matched_delimiter_end(const struct file_buffer* fb, int offset, struct delimiter d)
    375 {
    376 		int closers_left = 1;
    377 		while (closers_left) {
    378 				int next_open = fb_seek_string_not_escaped(fb, offset, d.start);
    379 				int next_close = fb_seek_string_not_escaped(fb, offset, d.end);
    380 
    381 				if (next_close < 0 || next_open < 0)
    382 						return next_close;
    383 
    384 				if (next_open < next_close) {
    385 						closers_left++;
    386 						offset = next_open+1;
    387 				} else {
    388 						closers_left--;
    389 						offset = next_close;
    390 						if (closers_left)
    391 								offset++;
    392 				}
    393 		}
    394 		return offset;
    395 }
    396 
    397 inline static int
    398 fb_get_matched_delimiter_start(const struct file_buffer* fb, int offset, struct delimiter d)
    399 {
    400 		int openers_left = 1;
    401 		while (openers_left) {
    402 				int next_open = fb_seek_string_backwards_not_escaped(fb, offset, d.start);
    403 				int next_close = fb_seek_string_backwards_not_escaped(fb, offset, d.end);
    404 
    405 				if (next_close < 0 || next_open < 0)
    406 						return next_open;
    407 
    408 				if (next_open < next_close) {
    409 						openers_left++;
    410 						offset = next_open-1;
    411 				} else {
    412 						openers_left--;
    413 						offset = next_open;
    414 						if (openers_left)
    415 								offset--;
    416 				}
    417 		}
    418 		return offset;
    419 }
    420 
    421 inline int
    422 fb_get_delimiter(const struct file_buffer* fb, int offset, struct delimiter d, struct delimiter* ignore, int* start, int* end)
    423 {
    424 		const char* start_word = d.start;
    425 		const char* end_word = d.end;
    426 
    427 		soft_assert(start, return 0;);
    428 		soft_assert(end, return 0;);
    429 		soft_assert(start_word, return 0;);
    430 		soft_assert(end_word, return 0;);
    431 
    432 		if (strcmp(start_word, end_word) == 0)
    433 				return fb_get_delimiter_equal_start_end(fb, offset, start_word, ignore, start, end);
    434 		int wanted_opener = fb_get_matched_delimiter_start(fb, offset, d);
    435 
    436 		int ignore_index = 0;
    437 		int last_distance = 0;
    438 
    439 		while (last_distance >= 0) {
    440 				int d_res = INT32_MAX;
    441 				int i = 0;
    442 				if (ignore) {
    443 						for (struct delimiter* ign = ignore; ign->start; ign++) {
    444 								int d = fb_seek_string_not_escaped(fb, last_distance, ign->start);
    445 								if (d < 0 || d > offset) {
    446 										i++;
    447 										continue;
    448 								}
    449 
    450 								if (d < d_res) {
    451 										d_res = d;
    452 										ignore_index = i;
    453 								}
    454 								i++;
    455 						}
    456 				}
    457 				int str_d = fb_seek_string_not_escaped(fb, last_distance, start_word);
    458 
    459 				if ((str_d <= 0 || str_d > offset) && d_res == INT32_MAX)
    460 						return 0;
    461 
    462 				if (str_d >= 0 && str_d <= d_res) {
    463 						if (str_d == wanted_opener) {
    464 								last_distance = str_d;
    465 								*start = last_distance;
    466 
    467 								last_distance = fb_get_matched_delimiter_end(fb, last_distance+1, d);
    468 
    469 								if (last_distance > offset) {
    470 										*end = last_distance;
    471 										return 1;
    472 								}
    473 						}
    474 				} else {
    475 						last_distance = d_res;
    476 
    477 						last_distance = fb_seek_string_not_escaped(fb, last_distance+1, ignore[ignore_index].end);
    478 				}
    479 
    480 				if (last_distance >= 0)
    481 						last_distance++;
    482 		}
    483 		return 0;
    484 }