C · 5463 bytes Raw Blame History
1 // Regex wrapper - platform independent implementation
2 // Uses POSIX regex on Unix, simplified matching on Windows
3
4 #ifdef _WIN32
5 // Windows implementation - simplified pattern matching
6 // For full regex support on Windows, consider using PCRE2
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11
12 #define MAX_REGEX 10
13
14 typedef struct {
15 char* pattern;
16 int case_insensitive;
17 int used;
18 } regex_entry_t;
19
20 static regex_entry_t regex_storage[MAX_REGEX];
21
22 // Initialize storage
23 static void init_storage(void) {
24 static int initialized = 0;
25 if (!initialized) {
26 memset(regex_storage, 0, sizeof(regex_storage));
27 initialized = 1;
28 }
29 }
30
31 // Simple wildcard/literal pattern matching
32 // Supports: literal text, case-insensitive matching
33 // For Windows, we do basic substring matching
34 static int simple_match(const char* pattern, const char* text, int case_insensitive,
35 int* match_start, int* match_len) {
36 if (!pattern || !text) return 0;
37
38 size_t plen = strlen(pattern);
39 size_t tlen = strlen(text);
40
41 if (plen == 0) {
42 *match_start = 0;
43 *match_len = 0;
44 return 1;
45 }
46
47 // Simple substring search
48 for (size_t i = 0; i <= tlen - plen; i++) {
49 int matched = 1;
50 for (size_t j = 0; j < plen; j++) {
51 char pc = pattern[j];
52 char tc = text[i + j];
53
54 if (case_insensitive) {
55 pc = (char)tolower((unsigned char)pc);
56 tc = (char)tolower((unsigned char)tc);
57 }
58
59 if (pc != tc) {
60 matched = 0;
61 break;
62 }
63 }
64
65 if (matched) {
66 *match_start = (int)i;
67 *match_len = (int)plen;
68 return 1;
69 }
70 }
71
72 return 0; // No match
73 }
74
75 // Compile a regex pattern and return an ID
76 // cflags: 1 = case insensitive (REG_ICASE equivalent)
77 int compile_regex(const char* pattern, int cflags) {
78 init_storage();
79
80 int id = -1;
81
82 // Find free slot
83 for (int i = 0; i < MAX_REGEX; i++) {
84 if (!regex_storage[i].used) {
85 id = i;
86 break;
87 }
88 }
89
90 if (id == -1) {
91 return -1; // No free slots
92 }
93
94 // Store the pattern
95 regex_storage[id].pattern = _strdup(pattern);
96 if (!regex_storage[id].pattern) {
97 return -1;
98 }
99
100 regex_storage[id].case_insensitive = (cflags & 1); // REG_ICASE = 1
101 regex_storage[id].used = 1;
102
103 return id;
104 }
105
106 // Match a compiled regex against text
107 int match_regex(int id, const char* text, int* match_start, int* match_len) {
108 if (id < 0 || id >= MAX_REGEX || !regex_storage[id].used) {
109 return -1; // Invalid ID
110 }
111
112 if (simple_match(regex_storage[id].pattern, text,
113 regex_storage[id].case_insensitive,
114 match_start, match_len)) {
115 return 1; // Match found
116 }
117
118 return 0; // No match
119 }
120
121 // Free a compiled regex
122 void free_regex(int id) {
123 if (id >= 0 && id < MAX_REGEX && regex_storage[id].used) {
124 free(regex_storage[id].pattern);
125 regex_storage[id].pattern = NULL;
126 regex_storage[id].used = 0;
127 }
128 }
129
130 // Free all compiled regexes
131 void free_all_regex(void) {
132 for (int i = 0; i < MAX_REGEX; i++) {
133 if (regex_storage[i].used) {
134 free(regex_storage[i].pattern);
135 regex_storage[i].pattern = NULL;
136 regex_storage[i].used = 0;
137 }
138 }
139 }
140
141 #else
142 // Unix implementation using POSIX regex
143
144 #include <regex.h>
145 #include <stdlib.h>
146 #include <string.h>
147
148 // Maximum number of compiled regex patterns we can store
149 #define MAX_REGEX 10
150
151 // Storage for compiled regex patterns
152 static regex_t regex_storage[MAX_REGEX];
153 static int regex_used[MAX_REGEX] = {0};
154
155 // Compile a regex pattern and return an ID (index into storage)
156 // Returns -1 on error, >= 0 on success
157 int compile_regex(const char *pattern, int cflags) {
158 int id = -1;
159
160 // Find free slot
161 for (int i = 0; i < MAX_REGEX; i++) {
162 if (!regex_used[i]) {
163 id = i;
164 break;
165 }
166 }
167
168 if (id == -1) {
169 return -1; // No free slots
170 }
171
172 // Compile the pattern
173 int result = regcomp(&regex_storage[id], pattern, cflags);
174 if (result != 0) {
175 return -1; // Compilation failed
176 }
177
178 regex_used[id] = 1;
179 return id;
180 }
181
182 // Match a compiled regex against text
183 // Returns 1 if match found, 0 if no match, -1 on error
184 int match_regex(int id, const char *text, int *match_start, int *match_len) {
185 if (id < 0 || id >= MAX_REGEX || !regex_used[id]) {
186 return -1; // Invalid ID
187 }
188
189 regmatch_t pmatch[1];
190 int result = regexec(&regex_storage[id], text, 1, pmatch, 0);
191
192 if (result == 0) {
193 // Match found - return start position and length
194 *match_start = (int)pmatch[0].rm_so;
195 *match_len = (int)(pmatch[0].rm_eo - pmatch[0].rm_so);
196 return 1;
197 } else if (result == REG_NOMATCH) {
198 return 0; // No match
199 } else {
200 return -1; // Error
201 }
202 }
203
204 // Free a compiled regex
205 void free_regex(int id) {
206 if (id >= 0 && id < MAX_REGEX && regex_used[id]) {
207 regfree(&regex_storage[id]);
208 regex_used[id] = 0;
209 }
210 }
211
212 // Free all compiled regexes
213 void free_all_regex(void) {
214 for (int i = 0; i < MAX_REGEX; i++) {
215 if (regex_used[i]) {
216 regfree(&regex_storage[i]);
217 regex_used[i] = 0;
218 }
219 }
220 }
221
222 #endif
223