|
diff --git a/main.c b/main.c
|
| ... |
| 23 |
#define DEBUG 1 |
23 |
#define DEBUG 1 |
| 24 |
|
24 |
|
| 25 |
typedef struct { |
25 |
typedef struct { |
| 26 |
const char *fname; |
26 |
const char *fname; |
| 27 |
const char *ftype; |
27 |
const char *ftype; |
| 28 |
const char *fparams; |
28 |
const char *fparams; |
| 29 |
size_t lineno; |
29 |
size_t lineno; |
| 30 |
} Function; |
30 |
} Function; |
| 31 |
|
31 |
|
| 32 |
const char *extract_value(TSNode captured_node, const char *source_code) { |
32 |
const char *extract_value(TSNode captured_node, const char *source_code) { |
| 33 |
size_t start = ts_node_start_byte(captured_node); |
33 |
size_t start = ts_node_start_byte(captured_node); |
| 34 |
size_t end = ts_node_end_byte(captured_node); |
34 |
size_t end = ts_node_end_byte(captured_node); |
| 35 |
size_t length = end - start; |
35 |
size_t length = end - start; |
| 36 |
char *buffer = malloc(length + 1); // +1 for the null terminator |
36 |
char *buffer = malloc(length + 1); // +1 for the null terminator |
| 37 |
|
37 |
|
| 38 |
if (buffer != NULL) { |
38 |
if (buffer != NULL) { |
| 39 |
snprintf(buffer, length + 1, "%.*s", (int)length, &source_code[start]); |
39 |
snprintf(buffer, length + 1, "%.*s", (int)length, &source_code[start]); |
| 40 |
return buffer; |
40 |
return buffer; |
| 41 |
} |
41 |
} |
| 42 |
|
42 |
|
| 43 |
return NULL; |
43 |
return NULL; |
| 44 |
} |
44 |
} |
| 45 |
|
45 |
|
| 46 |
char* remove_newlines(const char* str) { |
46 |
char* remove_newlines(const char* str) { |
| 47 |
size_t length = strlen(str); |
47 |
size_t length = strlen(str); |
| 48 |
char* result = (char*)malloc(length + 1); // +1 for the null terminator |
48 |
char* result = (char*)malloc(length + 1); // +1 for the null terminator |
| 49 |
if (result == NULL) { |
49 |
if (result == NULL) { |
| 50 |
fprintf(stderr, "Memory allocation failed\n"); |
50 |
fprintf(stderr, "Memory allocation failed\n"); |
| 51 |
exit(1); |
51 |
exit(1); |
| 52 |
} |
52 |
} |
| 53 |
|
53 |
|
| 54 |
size_t j = 0; |
54 |
size_t j = 0; |
| 55 |
for (size_t i = 0; i < length; i++) { |
55 |
for (size_t i = 0; i < length; i++) { |
| 56 |
if (str[i] != '\n') { |
56 |
if (str[i] != '\n') { |
| 57 |
result[j++] = str[i]; |
57 |
result[j++] = str[i]; |
| 58 |
} |
58 |
} |
| 59 |
} |
59 |
} |
| 60 |
|
60 |
|
| 61 |
result[j] = '\0'; |
61 |
result[j] = '\0'; |
| 62 |
return result; |
62 |
return result; |
| 63 |
} |
63 |
} |
| 64 |
|
64 |
|
| 65 |
struct ThreadArgs { |
65 |
struct ThreadArgs { |
| 66 |
const char* file_path; |
66 |
const char* file_path; |
| 67 |
const char* source_code; |
67 |
const char* source_code; |
| 68 |
TSLanguage* language; |
68 |
TSLanguage* language; |
| 69 |
const char* cfname; |
69 |
const char* cfname; |
| 70 |
}; |
70 |
}; |
| 71 |
|
71 |
|
| 72 |
// void parse_source_file(const char *file_path, const char *source_code, TSLanguage *language, const char *cfname) { |
72 |
// void parse_source_file(const char *file_path, const char *source_code, TSLanguage *language, const char *cfname) { |
| 73 |
void *parse_source_file(void *arg) { |
73 |
void *parse_source_file(void *arg) { |
| 74 |
struct ThreadArgs* args = (struct ThreadArgs*)arg; |
74 |
struct ThreadArgs* args = (struct ThreadArgs*)arg; |
| 75 |
|
75 |
|
| 76 |
const char *file_path = args->file_path; |
76 |
const char *file_path = args->file_path; |
| 77 |
const char *source_code = args->source_code; |
77 |
const char *source_code = args->source_code; |
| 78 |
TSLanguage *language = args->language; |
78 |
TSLanguage *language = args->language; |
| 79 |
const char *cfname = args->cfname; |
79 |
const char *cfname = args->cfname; |
| 80 |
|
80 |
|
| 81 |
TSParser *parser = ts_parser_new(); |
81 |
TSParser *parser = ts_parser_new(); |
| 82 |
ts_parser_set_language(parser, language); |
82 |
ts_parser_set_language(parser, language); |
| 83 |
|
83 |
|
| 84 |
TSTree *tree = ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
84 |
TSTree *tree = ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
| 85 |
TSNode root_node = ts_tree_root_node(tree); |
85 |
TSNode root_node = ts_tree_root_node(tree); |
| 86 |
|
86 |
|
| 87 |
const char *query_string = "(function_definition type: (primitive_type) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))"; |
87 |
const char *query_string = "(function_definition type: (primitive_type) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))"; |
| 88 |
|
88 |
|
| 89 |
uint32_t error_offset; |
89 |
uint32_t error_offset; |
| 90 |
TSQueryError error_type; |
90 |
TSQueryError error_type; |
| 91 |
TSQuery *query = ts_query_new(language, query_string, strlen(query_string), &error_offset, &error_type); |
91 |
TSQuery *query = ts_query_new(language, query_string, strlen(query_string), &error_offset, &error_type); |
| 92 |
|
92 |
|
| 93 |
TSQueryCursor *query_cursor = ts_query_cursor_new(); |
93 |
TSQueryCursor *query_cursor = ts_query_cursor_new(); |
| 94 |
ts_query_cursor_exec(query_cursor, query, root_node); |
94 |
ts_query_cursor_exec(query_cursor, query, root_node); |
| 95 |
|
95 |
|
| 96 |
if (query != NULL) { |
96 |
if (query != NULL) { |
| 97 |
TSQueryMatch match; |
97 |
TSQueryMatch match; |
| 98 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
98 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
| 99 |
Function fn = {0}; |
99 |
Function fn = {0}; |
| 100 |
|
100 |
|
| 101 |
for (unsigned i = 0; i < match.capture_count; i++) { |
101 |
for (unsigned i = 0; i < match.capture_count; i++) { |
| 102 |
TSQueryCapture capture = match.captures[i]; |
102 |
TSQueryCapture capture = match.captures[i]; |
| 103 |
TSNode captured_node = capture.node; |
103 |
TSNode captured_node = capture.node; |
| 104 |
|
104 |
|
| 105 |
uint32_t capture_name_length; |
105 |
uint32_t capture_name_length; |
| 106 |
const char *capture_name = ts_query_capture_name_for_id(query, capture.index, &capture_name_length); |
106 |
const char *capture_name = ts_query_capture_name_for_id(query, capture.index, &capture_name_length); |
| 107 |
|
107 |
|
| 108 |
if (strcmp(capture_name, "fname") == 0) { |
108 |
if (strcmp(capture_name, "fname") == 0) { |
| 109 |
fn.fname = extract_value(captured_node, source_code); |
109 |
fn.fname = extract_value(captured_node, source_code); |
| 110 |
|
110 |
|
| 111 |
TSPoint start_point = ts_node_start_point(captured_node); |
111 |
TSPoint start_point = ts_node_start_point(captured_node); |
| 112 |
fn.lineno = start_point.row; |
112 |
fn.lineno = start_point.row; |
| 113 |
} |
113 |
} |
| 114 |
|
114 |
|
| 115 |
if (strcmp(capture_name, "ftype") == 0) { |
115 |
if (strcmp(capture_name, "ftype") == 0) { |
| 116 |
fn.ftype = extract_value(captured_node, source_code); |
116 |
fn.ftype = extract_value(captured_node, source_code); |
| 117 |
} |
117 |
} |
| 118 |
|
118 |
|
| 119 |
if (strcmp(capture_name, "fparams") == 0) { |
119 |
if (strcmp(capture_name, "fparams") == 0) { |
| 120 |
fn.fparams = extract_value(captured_node, source_code); |
120 |
fn.fparams = extract_value(captured_node, source_code); |
| 121 |
} |
121 |
} |
| 122 |
} |
122 |
} |
| 123 |
|
123 |
|
| 124 |
// Substring matching. |
124 |
// Substring matching. |
| 125 |
// FIXME: Add Levenshtein distance. |
125 |
// FIXME: Add Levenshtein distance. |
| 126 |
char *result = strstr(fn.fname, cfname); |
126 |
char *result = strstr(fn.fname, cfname); |
| 127 |
if (result != NULL) { |
127 |
if (result != NULL) { |
| 128 |
char *fparams_formatted = remove_newlines(fn.fparams); |
128 |
char *fparams_formatted = remove_newlines(fn.fparams); |
| 129 |
printf("%s:%zu:\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, fparams_formatted); |
129 |
printf("%s:%zu:\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, fparams_formatted); |
| 130 |
} |
130 |
} |
| 131 |
} |
131 |
} |
| 132 |
} else { |
132 |
} else { |
| 133 |
if (DEBUG) { |
133 |
if (DEBUG) { |
| 134 |
printf("Query creation failed at offset %u with error type %d\n", error_offset, error_type); |
134 |
printf("Query creation failed at offset %u with error type %d\n", error_offset, error_type); |
| 135 |
} |
135 |
} |
| 136 |
} |
136 |
} |
| 137 |
|
137 |
|
| 138 |
ts_query_cursor_delete(query_cursor); |
138 |
ts_query_cursor_delete(query_cursor); |
| 139 |
ts_query_delete(query); |
139 |
ts_query_delete(query); |
| 140 |
ts_tree_delete(tree); |
140 |
ts_tree_delete(tree); |
| 141 |
ts_parser_delete(parser); |
141 |
ts_parser_delete(parser); |
| 142 |
|
142 |
|
| 143 |
return NULL; |
143 |
return NULL; |
| 144 |
} |
144 |
} |
| 145 |
|
145 |
|
| 146 |
const char *get_file_extension(const char *file_path) { |
146 |
const char *get_file_extension(const char *file_path) { |
| 147 |
const char *extension = strrchr(file_path, '.'); |
147 |
const char *extension = strrchr(file_path, '.'); |
| 148 |
if (extension != NULL) { |
148 |
if (extension != NULL) { |
| 149 |
return extension + 1; |
149 |
return extension + 1; |
| 150 |
} |
150 |
} |
| 151 |
return NULL; |
151 |
return NULL; |
| 152 |
} |
152 |
} |
| 153 |
|
153 |
|
| 154 |
int main(int argc, char *argv[]) { |
154 |
int main(int argc, char *argv[]) { |
| 155 |
if (argc < 3) { |
155 |
if (argc < 3) { |
| 156 |
printf("Usage: %s <search term> <directory>\n", argv[0]); |
156 |
printf("Usage: %s <search term> <directory>\n", argv[0]); |
| 157 |
return 1; |
157 |
return 1; |
| 158 |
} |
158 |
} |
| 159 |
|
159 |
|
| 160 |
char *cfname = argv[1]; |
160 |
char *cfname = argv[1]; |
| 161 |
char *directory = argv[2]; |
161 |
char *directory = argv[2]; |
| 162 |
|
162 |
|
| 163 |
TSLanguage *tree_sitter_c(void); |
163 |
TSLanguage *tree_sitter_c(void); |
| 164 |
TSLanguage *tree_sitter_python(void); |
164 |
TSLanguage *tree_sitter_python(void); |
| 165 |
|
165 |
|
| 166 |
Node *head = NULL; |
166 |
Node *head = NULL; |
| 167 |
list_files_recursively(directory, &head); |
167 |
list_files_recursively(directory, &head); |
| 168 |
int list_size = size_of_file_list(head); |
168 |
int list_size = size_of_file_list(head); |
| 169 |
/* pthread_t threads[list_size]; */ |
169 |
/* pthread_t threads[list_size]; */ |
| 170 |
|
170 |
|
| 171 |
if (DEBUG) { |
171 |
if (DEBUG) { |
| 172 |
printf("Scanning %d files\n", list_size); |
172 |
printf("Scanning %d files\n", list_size); |
| 173 |
} |
173 |
} |
| 174 |
|
174 |
|
| 175 |
Node *current = head; |
175 |
Node *current = head; |
| 176 |
int thread_index = 0; |
176 |
// int thread_index = 0; |
| 177 |
while (current != NULL) { |
177 |
while (current != NULL) { |
| 178 |
const char *file_path = current->file_path; |
178 |
const char *file_path = current->file_path; |
| 179 |
const char *extension = get_file_extension(file_path); |
179 |
const char *extension = get_file_extension(file_path); |
| 180 |
struct FileContent source_file = read_entire_file(file_path); |
180 |
struct FileContent source_file = read_entire_file(file_path); |
| 181 |
|
181 |
|
| 182 |
if (source_file.content != NULL) { |
182 |
if (source_file.content != NULL) { |
| 183 |
if (extension != NULL) { |
183 |
if (extension != NULL) { |
| 184 |
if (strcmp(extension, "c") == 0 || strcmp(extension, "h") == 0) { |
184 |
if (strcmp(extension, "c") == 0 || strcmp(extension, "h") == 0) { |
| 185 |
/* parse_source_file(file_path, source_file.content, tree_sitter_c(), cfname); */ |
185 |
/* parse_source_file(file_path, source_file.content, tree_sitter_c(), cfname); */ |
| 186 |
|
186 |
|
| 187 |
struct ThreadArgs thread_args; |
187 |
struct ThreadArgs thread_args; |
| 188 |
thread_args.file_path = file_path; |
188 |
thread_args.file_path = file_path; |
| 189 |
thread_args.source_code = source_file.content; |
189 |
thread_args.source_code = source_file.content; |
| 190 |
thread_args.language = tree_sitter_c(); |
190 |
thread_args.language = tree_sitter_c(); |
| 191 |
thread_args.cfname = cfname; |
191 |
thread_args.cfname = cfname; |
| 192 |
|
192 |
|
| 193 |
parse_source_file(&thread_args); |
193 |
parse_source_file(&thread_args); |
| 194 |
|
194 |
|
| 195 |
/* printf("> creating thread #%d\n", thread_index); */ |
195 |
/* printf("> creating thread #%d\n", thread_index); */ |
| 196 |
/* if (pthread_create(&threads[thread_index], NULL, parse_source_file, &thread_args) != 0) { */ |
196 |
/* if (pthread_create(&threads[thread_index], NULL, parse_source_file, &thread_args) != 0) { */ |
| 197 |
/* fprintf(stderr, "Error creating thread %d\n", thread_index); */ |
197 |
/* fprintf(stderr, "Error creating thread %d\n", thread_index); */ |
| 198 |
/* return 1; */ |
198 |
/* return 1; */ |
| 199 |
/* } */ |
199 |
/* } */ |
| 200 |
} |
200 |
} |
| 201 |
} |
201 |
} |
| 202 |
free((void *)source_file.content); |
202 |
free((void *)source_file.content); |
| 203 |
} else { |
203 |
} else { |
| 204 |
if (DEBUG) { |
204 |
if (DEBUG) { |
| 205 |
fprintf(stderr, "Failed to read file.\n"); |
205 |
fprintf(stderr, "Failed to read file.\n"); |
| 206 |
} |
206 |
} |
| 207 |
} |
207 |
} |
| 208 |
current = current->next; |
208 |
current = current->next; |
| 209 |
thread_index++; |
209 |
// thread_index++; |
| 210 |
} |
210 |
} |
| 211 |
|
211 |
|
| 212 |
// Collecting threads. |
212 |
// Collecting threads. |
| 213 |
/* for (int i = 0; i < list_size; i++) { */ |
213 |
/* for (int i = 0; i < list_size; i++) { */ |
| 214 |
/* printf("> collecting thread #%d\n", thread_index); */ |
214 |
/* printf("> collecting thread #%d\n", thread_index); */ |
| 215 |
/* if (pthread_join(threads[i], NULL) != 0) { */ |
215 |
/* if (pthread_join(threads[i], NULL) != 0) { */ |
| 216 |
/* fprintf(stderr, "Error joining thread %d\n", i); */ |
216 |
/* fprintf(stderr, "Error joining thread %d\n", i); */ |
| 217 |
/* return 1; */ |
217 |
/* return 1; */ |
| 218 |
/* } */ |
218 |
/* } */ |
| 219 |
/* } */ |
219 |
/* } */ |
| 220 |
|
220 |
|
| 221 |
free_file_list(head); |
221 |
free_file_list(head); |
| 222 |
return 0; |
222 |
return 0; |
| 223 |
} |
223 |
} |