Browse code

Ignore escape sequences in has_match

No scoring code is changed, so this probably needs more work to be fully
functional.

Robert Cranston authored on 03/12/2025 12:25:52
Showing 1 changed files

... ...
@@ -11,19 +11,83 @@
11 11
 
12 12
 #include "../config.h"
13 13
 
14
+const char *ignore_escapes(const char *haystack) {
15
+	enum {
16
+		state_default,
17
+		state_escaped,
18
+		state_in_csi,
19
+		state_start_osc,
20
+		state_in_osc,
21
+		state_ignore_next,
22
+	} state = state_default;
23
+	do switch (state) {
24
+		case state_default: switch (*haystack) {
25
+			case '\x1b':
26
+				state = state_escaped; break;
27
+			case '\x7':
28
+				return ++haystack;
29
+			default:
30
+				return haystack;
31
+		}; break;
32
+		case state_escaped: switch (*haystack) {
33
+			case '[':
34
+				state = state_in_csi; break;
35
+			case ']':
36
+				state = state_start_osc; break;
37
+			case '%': case '(': case ')': case '#':
38
+			case '0': case '3': case '5': case '6':
39
+				state = state_ignore_next; break;
40
+			case '<': case '=': case '>': case '\x7':
41
+			case '1': case '2': case '7': case '8':
42
+			case 'c': case 's': case 'u':
43
+			case 'A': case 'B': case 'C': case 'D': case 'E':
44
+			case 'H': case 'I': case 'J': case 'K': case 'M':
45
+			case 'N': case 'O': case 'S': case 'T': case 'Z':
46
+				return ++haystack;
47
+			default:
48
+				return haystack;
49
+		}; break;
50
+		case state_in_csi: switch (*haystack) {
51
+			case ';': case '?':
52
+			case '0': case '1': case '2': case '3': case '4':
53
+			case '5': case '6': case '7': case '8': case '9':
54
+				break;
55
+			default:
56
+				return ++haystack;
57
+		}; break;
58
+		case state_start_osc: switch (*haystack) {
59
+			case '0': case '1': case '2': case '3': case '4':
60
+			case '5': case '6': case '7': case '8': case '9':
61
+				state = state_in_osc; break;
62
+			default:
63
+				return ++haystack;
64
+		}; break;
65
+		case state_in_osc: switch (*haystack) {
66
+			case '\x7':
67
+				return ++haystack;
68
+			case '\x1b':
69
+				state = state_ignore_next; break;
70
+		}; break;
71
+		case state_ignore_next:
72
+			return ++haystack;
73
+	} while (*++haystack);
74
+	return haystack;
75
+}
76
+
14 77
 char *strcasechr(const char *s, char c) {
15 78
 	const char accept[3] = {c, toupper(c), 0};
16 79
 	return strpbrk(s, accept);
17 80
 }
18 81
 
19 82
 int has_match(const char *needle, const char *haystack) {
83
+	haystack = ignore_escapes(haystack);
20 84
 	while (*needle) {
21 85
 		char nch = *needle++;
22 86
 
23 87
 		if (!(haystack = strcasechr(haystack, nch))) {
24 88
 			return 0;
25 89
 		}
26
-		haystack++;
90
+		haystack = ignore_escapes(++haystack);
27 91
 	}
28 92
 	return 1;
29 93
 }