diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-22 02:24:44 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-22 02:24:44 +0100 |
| commit | 069301a603ad07338179bafed0c35b6fe3b372f2 (patch) | |
| tree | 74010f542968876938d18effe8939694ddafdc03 | |
| parent | ac3c52c4431d422affe951ff0641b4eb04787e54 (diff) | |
| download | crep-069301a603ad07338179bafed0c35b6fe3b372f2.tar.gz | |
Better arg parsing
| -rw-r--r-- | list.c | 6 | ||||
| -rw-r--r-- | list.h | 2 | ||||
| -rw-r--r-- | main.c | 54 | ||||
| -rwxr-xr-x[-rw-r--r--] | tests.sh | 28 | ||||
| -rw-r--r-- | tests/depth_test/level0.c | 1 | ||||
| -rw-r--r-- | tests/depth_test/sub/level1.c | 1 | ||||
| -rw-r--r-- | tests/test.c | 5 |
7 files changed, 81 insertions, 16 deletions
@@ -22,7 +22,7 @@ void add_file_path(Node **head, char *file_path) { *head = new; } -void list_files_recursively(char *base_path, Node **head) { +void list_files_recursively(char *base_path, Node **head, int max_depth, int current_depth) { struct stat statbuf; if (stat(base_path, &statbuf) == -1) { perror("stat"); @@ -52,7 +52,9 @@ void list_files_recursively(char *base_path, Node **head) { if (stat(path, &statbuf) != -1) { if (S_ISDIR(statbuf.st_mode)) { - list_files_recursively(path, head); + if (max_depth == -1 || current_depth < max_depth) { + list_files_recursively(path, head, max_depth, current_depth + 1); + } } else if (S_ISREG(statbuf.st_mode)) { add_file_path(head, path); } @@ -7,7 +7,7 @@ typedef struct node { } Node; void add_file_path(Node **head, char *file_path); -void list_files_recursively(char *base_path, Node **head); +void list_files_recursively(char *base_path, Node **head, int max_depth, int current_depth); void free_file_list(Node *head); int size_of_file_list(Node *head); @@ -1,18 +1,15 @@ // TODO: -// - Add language specific filter (by default all but it can also passed -// with -tpy -tc -trb) which would only parse python, c and ruby files. -// - By default its case insensitive but with passing -cs it tells that -// all matching should be done in case sensitive way. // - Add Levenshtein distance for matching and expose distance as arg with // something like -d5 which would allow distance of 5 on a match. -// - Allow DEBUG to be provided as environmental variable. -// - Added depth flag (-r means recursive, -l2 means 2 levels deep). // FIXME: // - Truncate longer argument list. +#define _GNU_SOURCE #include <assert.h> +#include <getopt.h> #include <pthread.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -26,10 +23,10 @@ #include "queries/c.h" #include "queries/cpp.h" #include "queries/go.h" +#include "queries/javascript.h" #include "queries/php.h" #include "queries/python.h" #include "queries/rust.h" -#include "queries/javascript.h" int debug_enabled = 0; @@ -93,6 +90,7 @@ struct ThreadArgs { const char *query_string; uint32_t query_len; const char *cfname; + int case_sensitive; }; // void parse_source_file(const char *file_path, const char *source_code, @@ -104,6 +102,7 @@ void parse_source_file(void *arg) { const char *source_code = args->source_code; TSLanguage *language = args->language; const char *cfname = args->cfname; + int case_sensitive = args->case_sensitive; TSParser *parser = ts_parser_new(); ts_parser_set_language(parser, language); @@ -172,7 +171,13 @@ void parse_source_file(void *arg) { // Substring matching. // FIXME: Add Levenshtein distance. if (fn.fname != NULL) { - char *result = strstr(fn.fname, cfname); + char *result; + if (case_sensitive) { + result = strstr(fn.fname, cfname); + } else { + result = strcasestr(fn.fname, cfname); + } + if (result != NULL) { char *fparams_formatted = remove_newlines(fn.fparams); printf("%s:%zu: %s %s %s\n", file_path, fn.lineno, fn.ftype ? fn.ftype : "", fn.fname, fparams_formatted ? fparams_formatted : ""); @@ -205,16 +210,38 @@ const char *get_file_extension(const char *file_path) { } int main(int argc, char *argv[]) { - if (argc < 2) { - printf("Usage: %s <search term> [directory|file]\n", argv[0]); + int case_sensitive = 0; + int max_depth = -1; + int opt; + struct option long_options[] = { + {"case-sensitive", no_argument, 0, 'c'}, + {"depth", required_argument, 0, 'd'}, + {0, 0, 0, 0}}; + + while ((opt = getopt_long(argc, argv, "cd:", long_options, NULL)) != -1) { + switch (opt) { + case 'c': + case_sensitive = 1; + break; + case 'd': + max_depth = atoi(optarg); + break; + default: + fprintf(stderr, "Usage: %s [-c|--case-sensitive] [-d|--depth <level>] <search term> [directory|file]\n", argv[0]); + return 1; + } + } + + if (optind >= argc) { + fprintf(stderr, "Usage: %s [-c|--case-sensitive] [-d|--depth <level>] <search term> [directory|file]\n", argv[0]); return 1; } - const char *cfname = argv[1]; - char *directory = (argc > 2) ? argv[2] : "."; + const char *cfname = argv[optind]; + char *directory = (optind + 1 < argc) ? argv[optind + 1] : "."; Node *head = NULL; - list_files_recursively(directory, &head); + list_files_recursively(directory, &head, max_depth, 0); int list_size = size_of_file_list(head); const char *debug_env = getenv("DEBUG"); @@ -289,6 +316,7 @@ int main(int argc, char *argv[]) { thread_args->query_string = query_string; thread_args->query_len = query_len; thread_args->cfname = cfname; + thread_args->case_sensitive = case_sensitive; tp_add_job(pool, (thread_func_t)parse_source_file, thread_args); } else { @@ -29,6 +29,26 @@ run_test() { fi } +run_test_with_flags() { + local label=$1 + local flags=$2 + local search_term=$3 + local file=$4 + local expected_pattern=$5 + + printf "Testing %-50s " "$label ($flags $search_term)" + output=$($CREP $flags "$search_term" "$file") + + if echo "$output" | grep -q "$expected_pattern"; then + echo "PASSED" + else + echo "FAILED" + echo " Expected pattern: $expected_pattern" + echo " Actual output: $output" + failed=$((failed + 1)) + fi +} + echo "Starting tests..." echo "----------------" @@ -77,6 +97,14 @@ run_test "C++ Class" "MyClass" "$TEST_DIR/test.cpp" "class MyClass" run_test "C++ Struct" "MyStruct" "$TEST_DIR/test.cpp" "struct MyStruct" run_test "C++ Method" "myMethod" "$TEST_DIR/test.cpp" "void myMethod ()" +# Case Sensitivity Tests +run_test "Default Case Insensitive" "foo" "tests/test.c" "void FooBar" +run_test_with_flags "Case Sensitive -c" "-c" "foobar" "tests/test.c" "void foobar" + +# Depth Tests +run_test_with_flags "Depth 0 (root)" "-d 0" "level" "tests/depth_test" "void level0" +run_test_with_flags "Depth 1 (recursive)" "-d 1" "level" "tests/depth_test" "void level1" + echo "----------------" if [ $failed -eq 0 ]; then echo "All tests passed!" diff --git a/tests/depth_test/level0.c b/tests/depth_test/level0.c new file mode 100644 index 0000000..a872dab --- /dev/null +++ b/tests/depth_test/level0.c @@ -0,0 +1 @@ +void level0() {} diff --git a/tests/depth_test/sub/level1.c b/tests/depth_test/sub/level1.c new file mode 100644 index 0000000..e4fd738 --- /dev/null +++ b/tests/depth_test/sub/level1.c @@ -0,0 +1 @@ +void level1() {} diff --git a/tests/test.c b/tests/test.c index 4326f11..1d5fd3f 100644 --- a/tests/test.c +++ b/tests/test.c @@ -30,3 +30,8 @@ int main() { hello(); return 0; } + +// Case sensitivity tests +void FooBar() {} +void foobar() {} +void FOOBAR() {} |
