| 2262 | /* ── extractLikeHints ─────────────────────────────────────────── */ |
| 2263 | |
| 2264 | int cbm_extract_like_hints(const char *pattern, char **out, int max_out) { |
| 2265 | if (!pattern || !out || max_out <= 0) { |
| 2266 | return 0; |
| 2267 | } |
| 2268 | |
| 2269 | /* Bail on alternation — can't convert OR regex to AND LIKE */ |
| 2270 | for (const char *p = pattern; *p; p++) { |
| 2271 | if (*p == '|') { |
| 2272 | return 0; |
| 2273 | } |
| 2274 | } |
| 2275 | |
| 2276 | int count = 0; |
| 2277 | char buf[CBM_SZ_256]; |
| 2278 | int blen = 0; |
| 2279 | |
| 2280 | int i = 0; |
| 2281 | while (pattern[i]) { |
| 2282 | char ch = pattern[i]; |
| 2283 | switch (ch) { |
| 2284 | case '\\': |
| 2285 | /* Escaped char — the next char is literal */ |
| 2286 | if (pattern[i + SKIP_ONE]) { |
| 2287 | if (blen < (int)sizeof(buf) - SKIP_ONE) { |
| 2288 | buf[blen++] = pattern[i + SKIP_ONE]; |
| 2289 | } |
| 2290 | i += ST_GLOB_SKIP; |
| 2291 | } else { |
| 2292 | i++; |
| 2293 | } |
| 2294 | break; |
| 2295 | case '.': |
| 2296 | case '*': |
| 2297 | case '+': |
| 2298 | case '?': |
| 2299 | case '^': |
| 2300 | case '$': |
| 2301 | case '(': |
| 2302 | case ')': |
| 2303 | case '[': |
| 2304 | case ']': |
| 2305 | case '{': |
| 2306 | case '}': |
| 2307 | /* Meta character — flush current literal segment */ |
| 2308 | if (blen >= ST_GLOB_MIN_LEN && count < max_out) { |
| 2309 | buf[blen] = '\0'; |
| 2310 | out[count++] = strdup(buf); |
| 2311 | } |
| 2312 | blen = 0; |
| 2313 | i++; |
| 2314 | break; |
| 2315 | default: |
| 2316 | if (blen < (int)sizeof(buf) - SKIP_ONE) { |
| 2317 | buf[blen++] = ch; |
| 2318 | } |
| 2319 | i++; |
| 2320 | break; |
| 2321 | } |
no outgoing calls
no test coverage detected