|
diff --git a/main.c b/main.c
|
| ... |
| 10 |
// - Added depth flag (-r means recursive, -l2 means 2 levels deep). |
10 |
// - Added depth flag (-r means recursive, -l2 means 2 levels deep). |
| 11 |
|
11 |
|
| 12 |
#include <assert.h> |
12 |
#include <assert.h> |
|
|
13 |
#include <pthread.h> |
| 13 |
#include <stdio.h> |
14 |
#include <stdio.h> |
| 14 |
#include <stdlib.h> |
15 |
#include <stdlib.h> |
| 15 |
#include <string.h> |
16 |
#include <string.h> |
| 16 |
#include <pthread.h> |
|
|
| 17 |
|
17 |
|
| 18 |
#include <tree_sitter/api.h> |
18 |
#include <tree_sitter/api.h> |
| 19 |
|
19 |
|
| ... |
| 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, |
| 73 |
void *parse_source_file(void *arg) { |
73 |
// TSLanguage *language, const char *cfname) { |
| 74 |
struct ThreadArgs* args = (struct ThreadArgs*)arg; |
74 |
void* parse_source_file(void* arg) { |
|
|
75 |
struct ThreadArgs* args = (struct ThreadArgs*)arg; |
| 75 |
|
76 |
|
| 76 |
const char *file_path = args->file_path; |
77 |
const char* file_path = args->file_path; |
| 77 |
const char *source_code = args->source_code; |
78 |
const char* source_code = args->source_code; |
| 78 |
TSLanguage *language = args->language; |
79 |
TSLanguage* language = args->language; |
| 79 |
const char *cfname = args->cfname; |
80 |
const char* cfname = args->cfname; |
| 80 |
|
81 |
|
| 81 |
TSParser *parser = ts_parser_new(); |
82 |
TSParser* parser = ts_parser_new(); |
| 82 |
ts_parser_set_language(parser, language); |
83 |
ts_parser_set_language(parser, language); |
| 83 |
|
84 |
|
| 84 |
TSTree *tree = ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
85 |
TSTree* tree = |
| 85 |
TSNode root_node = ts_tree_root_node(tree); |
86 |
ts_parser_parse_string(parser, NULL, source_code, strlen(source_code)); |
|
|
87 |
TSNode root_node = ts_tree_root_node(tree); |
| 86 |
|
88 |
|
| 87 |
const char *query_string = "(function_definition type: (primitive_type) @ftype declarator: (function_declarator declarator: (identifier) @fname parameters: (parameter_list) @fparams))"; |
89 |
const char* query_string = |
|
|
90 |
"(function_definition type: (primitive_type) @ftype declarator: " |
|
|
91 |
"(function_declarator declarator: (identifier) @fname parameters: " |
|
|
92 |
"(parameter_list) @fparams))"; |
| 88 |
|
93 |
|
| 89 |
uint32_t error_offset; |
94 |
uint32_t error_offset; |
| 90 |
TSQueryError error_type; |
95 |
TSQueryError error_type; |
| 91 |
TSQuery *query = ts_query_new(language, query_string, strlen(query_string), &error_offset, &error_type); |
96 |
TSQuery* query = ts_query_new(language, query_string, strlen(query_string), |
|
|
97 |
&error_offset, &error_type); |
| 92 |
|
98 |
|
| 93 |
TSQueryCursor *query_cursor = ts_query_cursor_new(); |
99 |
TSQueryCursor* query_cursor = ts_query_cursor_new(); |
| 94 |
ts_query_cursor_exec(query_cursor, query, root_node); |
100 |
ts_query_cursor_exec(query_cursor, query, root_node); |
| 95 |
|
101 |
|
| 96 |
if (query != NULL) { |
102 |
if (query != NULL) { |
| 97 |
TSQueryMatch match; |
103 |
TSQueryMatch match; |
| 98 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
104 |
while (ts_query_cursor_next_match(query_cursor, &match)) { |
| 99 |
Function fn = {0}; |
105 |
Function fn = {0}; |
| 100 |
|
106 |
|
| 101 |
for (unsigned i = 0; i < match.capture_count; i++) { |
107 |
for (unsigned i = 0; i < match.capture_count; i++) { |
| 102 |
TSQueryCapture capture = match.captures[i]; |
108 |
TSQueryCapture capture = match.captures[i]; |
| 103 |
TSNode captured_node = capture.node; |
109 |
TSNode captured_node = capture.node; |
| 104 |
|
110 |
|
| 105 |
uint32_t capture_name_length; |
111 |
uint32_t capture_name_length; |
| 106 |
const char *capture_name = ts_query_capture_name_for_id(query, capture.index, &capture_name_length); |
112 |
const char* capture_name = ts_query_capture_name_for_id( |
|
|
113 |
query, capture.index, &capture_name_length); |
| 107 |
|
114 |
|
| 108 |
if (strcmp(capture_name, "fname") == 0) { |
115 |
if (strcmp(capture_name, "fname") == 0) { |
| 109 |
fn.fname = extract_value(captured_node, source_code); |
116 |
fn.fname = extract_value(captured_node, source_code); |
| 110 |
|
117 |
|
| 111 |
TSPoint start_point = ts_node_start_point(captured_node); |
118 |
TSPoint start_point = ts_node_start_point(captured_node); |
| 112 |
fn.lineno = start_point.row; |
119 |
fn.lineno = start_point.row; |
| 113 |
} |
120 |
} |
| 114 |
|
121 |
|
| 115 |
if (strcmp(capture_name, "ftype") == 0) { |
122 |
if (strcmp(capture_name, "ftype") == 0) { |
| 116 |
fn.ftype = extract_value(captured_node, source_code); |
123 |
fn.ftype = extract_value(captured_node, source_code); |
| 117 |
} |
124 |
} |
| 118 |
|
125 |
|
| 119 |
if (strcmp(capture_name, "fparams") == 0) { |
126 |
if (strcmp(capture_name, "fparams") == 0) { |
| 120 |
fn.fparams = extract_value(captured_node, source_code); |
127 |
fn.fparams = extract_value(captured_node, source_code); |
| 121 |
} |
128 |
} |
| 122 |
} |
129 |
} |
| 123 |
|
130 |
|
| 124 |
// Substring matching. |
131 |
// Substring matching. |
| 125 |
// FIXME: Add Levenshtein distance. |
132 |
// FIXME: Add Levenshtein distance. |
| 126 |
char *result = strstr(fn.fname, cfname); |
133 |
char* result = strstr(fn.fname, cfname); |
| 127 |
if (result != NULL) { |
134 |
if (result != NULL) { |
| 128 |
char *fparams_formatted = remove_newlines(fn.fparams); |
135 |
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); |
136 |
printf("%s:%zu:\t%s %s %s\n", file_path, fn.lineno, fn.ftype, fn.fname, |
| 130 |
} |
137 |
fparams_formatted); |
| 131 |
} |
138 |
} |
| 132 |
} else { |
139 |
} |
| 133 |
if (DEBUG) { |
140 |
} else { |
| 134 |
printf("Query creation failed at offset %u with error type %d\n", error_offset, error_type); |
141 |
if (DEBUG) { |
| 135 |
} |
142 |
printf("Query creation failed at offset %u with error type %d\n", |
| 136 |
} |
143 |
error_offset, error_type); |
|
|
144 |
} |
|
|
145 |
} |
| 137 |
|
146 |
|
| 138 |
ts_query_cursor_delete(query_cursor); |
147 |
ts_query_cursor_delete(query_cursor); |
| 139 |
ts_query_delete(query); |
148 |
ts_query_delete(query); |
| 140 |
ts_tree_delete(tree); |
149 |
ts_tree_delete(tree); |
| 141 |
ts_parser_delete(parser); |
150 |
ts_parser_delete(parser); |
| 142 |
|
151 |
|
| 143 |
return NULL; |
152 |
return NULL; |
| 144 |
} |
153 |
} |
| 145 |
|
154 |
|
| 146 |
const char *get_file_extension(const char *file_path) { |
155 |
const char* get_file_extension(const char* file_path) { |
| 147 |
const char *extension = strrchr(file_path, '.'); |
156 |
const char* extension = strrchr(file_path, '.'); |
| 148 |
if (extension != NULL) { |
157 |
if (extension != NULL) { |
| 149 |
return extension + 1; |
158 |
return extension + 1; |
| 150 |
} |
159 |
} |
| 151 |
return NULL; |
160 |
return NULL; |
| 152 |
} |
161 |
} |
| 153 |
|
162 |
|
| 154 |
int main(int argc, char *argv[]) { |
163 |
int main(int argc, char* argv[]) { |
| 155 |
if (argc < 3) { |
164 |
if (argc < 3) { |
| 156 |
printf("Usage: %s <search term> <directory>\n", argv[0]); |
165 |
printf("Usage: %s <search term> <directory>\n", argv[0]); |
| 157 |
return 1; |
166 |
return 1; |
| 158 |
} |
167 |
} |
| 159 |
|
168 |
|
| 160 |
char *cfname = argv[1]; |
169 |
char* cfname = argv[1]; |
| 161 |
char *directory = argv[2]; |
170 |
char* directory = argv[2]; |
| 162 |
|
171 |
|
| 163 |
TSLanguage *tree_sitter_c(void); |
172 |
TSLanguage* tree_sitter_c(void); |
| 164 |
TSLanguage *tree_sitter_python(void); |
173 |
TSLanguage* tree_sitter_python(void); |
| 165 |
|
174 |
|
| 166 |
Node *head = NULL; |
175 |
Node* head = NULL; |
| 167 |
list_files_recursively(directory, &head); |
176 |
list_files_recursively(directory, &head); |
| 168 |
int list_size = size_of_file_list(head); |
177 |
int list_size = size_of_file_list(head); |
| 169 |
/* pthread_t threads[list_size]; */ |
178 |
/* pthread_t threads[list_size]; */ |
| 170 |
|
179 |
|
| 171 |
if (DEBUG) { |
180 |
if (DEBUG) { |
| 172 |
printf("Scanning %d files\n", list_size); |
181 |
printf("Scanning %d files\n", list_size); |
| 173 |
} |
182 |
} |
| 174 |
|
183 |
|
| 175 |
Node *current = head; |
184 |
Node* current = head; |
| 176 |
// int thread_index = 0; |
185 |
// int thread_index = 0; |
| 177 |
while (current != NULL) { |
186 |
while (current != NULL) { |
| 178 |
const char *file_path = current->file_path; |
187 |
const char* file_path = current->file_path; |
| 179 |
const char *extension = get_file_extension(file_path); |
188 |
const char* extension = get_file_extension(file_path); |
| 180 |
struct FileContent source_file = read_entire_file(file_path); |
189 |
struct FileContent source_file = read_entire_file(file_path); |
| 181 |
|
190 |
|
| 182 |
if (source_file.content != NULL) { |
191 |
if (source_file.content != NULL) { |
| 183 |
if (extension != NULL) { |
192 |
if (extension != NULL) { |
| 184 |
if (strcmp(extension, "c") == 0 || strcmp(extension, "h") == 0) { |
193 |
if (strcmp(extension, "c") == 0 || strcmp(extension, "h") == 0) { |
| 185 |
/* parse_source_file(file_path, source_file.content, tree_sitter_c(), cfname); */ |
194 |
/* parse_source_file(file_path, source_file.content, tree_sitter_c(), |
|
|
195 |
* cfname); */ |
| 186 |
|
196 |
|
| 187 |
struct ThreadArgs thread_args; |
197 |
struct ThreadArgs thread_args; |
| 188 |
thread_args.file_path = file_path; |
198 |
thread_args.file_path = file_path; |
| 189 |
thread_args.source_code = source_file.content; |
199 |
thread_args.source_code = source_file.content; |
| 190 |
thread_args.language = tree_sitter_c(); |
200 |
thread_args.language = tree_sitter_c(); |
| 191 |
thread_args.cfname = cfname; |
201 |
thread_args.cfname = cfname; |
| 192 |
|
202 |
|
| 193 |
parse_source_file(&thread_args); |
203 |
parse_source_file(&thread_args); |
| 194 |
|
204 |
|
| 195 |
/* printf("> creating thread #%d\n", thread_index); */ |
205 |
/* printf("> creating thread #%d\n", thread_index); */ |
| 196 |
/* if (pthread_create(&threads[thread_index], NULL, parse_source_file, &thread_args) != 0) { */ |
206 |
/* if (pthread_create(&threads[thread_index], NULL, parse_source_file, |
| 197 |
/* fprintf(stderr, "Error creating thread %d\n", thread_index); */ |
207 |
* &thread_args) != 0) { */ |
| 198 |
/* return 1; */ |
208 |
/* fprintf(stderr, "Error creating thread %d\n", thread_index); */ |
| 199 |
/* } */ |
209 |
/* return 1; */ |
| 200 |
} |
210 |
/* } */ |
| 201 |
} |
211 |
} |
| 202 |
free((void *)source_file.content); |
212 |
} |
| 203 |
} else { |
213 |
free((void*)source_file.content); |
| 204 |
if (DEBUG) { |
214 |
} else { |
| 205 |
fprintf(stderr, "Failed to read file.\n"); |
215 |
if (DEBUG) { |
| 206 |
} |
216 |
fprintf(stderr, "Failed to read file.\n"); |
| 207 |
} |
217 |
} |
| 208 |
current = current->next; |
218 |
} |
| 209 |
// thread_index++; |
219 |
current = current->next; |
| 210 |
} |
220 |
// thread_index++; |
|
|
221 |
} |
| 211 |
|
222 |
|
| 212 |
// Collecting threads. |
223 |
// Collecting threads. |
| 213 |
/* for (int i = 0; i < list_size; i++) { */ |
224 |
/* for (int i = 0; i < list_size; i++) { */ |
| 214 |
/* printf("> collecting thread #%d\n", thread_index); */ |
225 |
/* printf("> collecting thread #%d\n", thread_index); */ |
| 215 |
/* if (pthread_join(threads[i], NULL) != 0) { */ |
226 |
/* if (pthread_join(threads[i], NULL) != 0) { */ |
| 216 |
/* fprintf(stderr, "Error joining thread %d\n", i); */ |
227 |
/* fprintf(stderr, "Error joining thread %d\n", i); */ |
| 217 |
/* return 1; */ |
228 |
/* return 1; */ |
| 218 |
/* } */ |
229 |
/* } */ |
| 219 |
/* } */ |
230 |
/* } */ |
| 220 |
|
231 |
|
| 221 |
free_file_list(head); |
232 |
free_file_list(head); |
| 222 |
return 0; |
233 |
return 0; |
| 223 |
} |
234 |
} |