Created
January 6, 2025 04:48
-
-
Save delasy/df07cd7281d5b6abfd087fef8d2e1061 to your computer and use it in GitHub Desktop.
Find all files/folders case-insensitively matching search criteria
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cc main.c -o main.out | |
// ./main.out <path> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <ctype.h> | |
#include <dirent.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
static unsigned long long files_count = 0; | |
static const char *search_phrase = NULL; | |
typedef struct { | |
char *name; | |
node_list_t *children; | |
} node_t; | |
typedef struct { | |
char *items; | |
} node_list_t; | |
static char *str_concat (const char *s1, const char *s2) { | |
size_t l1 = strlen(s1); | |
unsigned char has_trailing_slash = s1[l1 - 1] == '/'; | |
size_t l2 = strlen(s2); | |
size_t len = l1 + (has_trailing_slash ? 0 : 1) + l2 + 1; | |
char *result = malloc(len); | |
if (result == NULL) { | |
fprintf(stderr, "Failed to allocate %zu bytes.", len); | |
return NULL; | |
} | |
sprintf(result, "%s%s%s", s1, has_trailing_slash ? "" : "/", s2); | |
return result; | |
} | |
static int is_dir (const char *path) { | |
struct stat buf; | |
stat(path, &buf); | |
return S_ISDIR(buf.st_mode); | |
} | |
static int traverse_dir (const char *path) { | |
int status = 0; | |
DIR *dir = opendir(path); | |
if (dir == NULL) { | |
fprintf(stderr, "Failed to open path '%s' for reading.\n", path); | |
status = 1; | |
goto FAIL_OPEN; | |
} | |
struct dirent *dp; | |
while ((dp = readdir(dir)) != NULL) { | |
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) { | |
continue; | |
} | |
char *entry_path = str_concat(path, dp->d_name); | |
if (entry_path == NULL) { | |
status = 1; | |
goto FAIL_CONCAT; | |
} | |
if (strcasestr(dp->d_name, search_phrase) != NULL) { | |
printf("found: %s\n", entry_path); | |
} | |
if (is_dir(entry_path)) { | |
if (traverse_dir(entry_path) != 0) { | |
status = 1; | |
goto FAIL_TRAVERSE; | |
} | |
continue; | |
} | |
files_count += 1; | |
free(entry_path); | |
} | |
FAIL_CONCAT: | |
FAIL_TRAVERSE: | |
closedir(dir); | |
FAIL_OPEN: | |
return status; | |
} | |
int main (const int argc, const char **argv) { | |
int status = 0; | |
if (argc <= 1) { | |
fprintf(stderr, "Path parameter is not set." "\n" "Usage: `./main.out <path> <search>`.\n"); | |
status = 1; | |
goto FAIL_PARAMS; | |
} | |
if (argc <= 2) { | |
fprintf(stderr, "Path parameter is not set." "\n" "Usage: `./main.out <path> <search>`.\n"); | |
status = 1; | |
goto FAIL_PARAMS; | |
} | |
const char *relative_search_path = argv[1]; | |
search_phrase = argv[2]; | |
char *search_path = realpath(relative_search_path, NULL); | |
if (search_path == NULL) { | |
fprintf(stderr, "Failed to resolve real path.\n"); | |
status = 1; | |
goto FAIL_PATH; | |
} | |
if (traverse_dir(search_path) != 0) { | |
status = 1; | |
goto FAIL_TRAVERSE; | |
} | |
FAIL_TRAVERSE: | |
free(search_path); | |
FAIL_PATH: | |
FAIL_PARAMS: | |
if (files_count > 0) { | |
printf("Files scanned: %llu\n", files_count); | |
} | |
return status == 0 ? EXIT_SUCCESS : EXIT_FAILURE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment