| 5098 | } |
| 5099 | |
| 5100 | static char *handle_search_code(cbm_mcp_server_t *srv, const char *args) { |
| 5101 | char *pattern = cbm_mcp_get_string_arg(args, "pattern"); |
| 5102 | char *project = get_project_arg(args); |
| 5103 | char *file_pattern = cbm_mcp_get_string_arg(args, "file_pattern"); |
| 5104 | char *path_filter = cbm_mcp_get_string_arg(args, "path_filter"); |
| 5105 | char *mode_str = cbm_mcp_get_string_arg(args, "mode"); |
| 5106 | int limit = cbm_mcp_get_int_arg(args, "limit", MCP_DEFAULT_LIMIT); |
| 5107 | int context_lines = cbm_mcp_get_int_arg(args, "context", 0); |
| 5108 | bool use_regex = cbm_mcp_get_bool_arg(args, "regex"); |
| 5109 | uint64_t search_t0 = cbm_now_ms(); |
| 5110 | /* In literal (non-regex) mode a '|' is matched as a byte, not alternation — |
| 5111 | * a common silent 0-match trap; flagged in the result warnings (#282). */ |
| 5112 | bool pat_has_pipe = pattern && strchr(pattern, '|') != NULL; |
| 5113 | |
| 5114 | int mode = parse_search_mode(mode_str); |
| 5115 | free(mode_str); |
| 5116 | |
| 5117 | cbm_regex_t path_regex; |
| 5118 | bool has_path_filter = compile_path_filter(path_filter, &path_regex); |
| 5119 | free(path_filter); |
| 5120 | path_filter = NULL; |
| 5121 | |
| 5122 | if (!pattern) { |
| 5123 | free(project); |
| 5124 | free(file_pattern); |
| 5125 | return cbm_mcp_text_result("pattern is required", true); |
| 5126 | } |
| 5127 | |
| 5128 | /* Project is required */ |
| 5129 | if (!project) { |
| 5130 | free(pattern); |
| 5131 | free(file_pattern); |
| 5132 | char *_err = build_project_list_error("project is required"); |
| 5133 | char *_res = cbm_mcp_text_result(_err, true); |
| 5134 | free(_err); |
| 5135 | return _res; |
| 5136 | } |
| 5137 | |
| 5138 | char *root_path = get_project_root(srv, project); |
| 5139 | if (!root_path) { |
| 5140 | free(pattern); |
| 5141 | free(project); |
| 5142 | free(file_pattern); |
| 5143 | char *_err = build_project_list_error("project not found or not indexed"); |
| 5144 | char *_res = cbm_mcp_text_result(_err, true); |
| 5145 | free(_err); |
| 5146 | return _res; |
| 5147 | } |
| 5148 | |
| 5149 | if (!validate_search_args(root_path, file_pattern)) { |
| 5150 | if (has_path_filter) { |
| 5151 | cbm_regfree(&path_regex); |
| 5152 | } |
| 5153 | free(root_path); |
| 5154 | free(pattern); |
| 5155 | free(project); |
| 5156 | free(file_pattern); |
| 5157 | return cbm_mcp_text_result("path or file_pattern contains invalid characters", true); |
no test coverage detected