Skip to content

Instantly share code, notes, and snippets.

@delasy
Created January 6, 2025 04:48
Show Gist options
  • Save delasy/df07cd7281d5b6abfd087fef8d2e1061 to your computer and use it in GitHub Desktop.
Save delasy/df07cd7281d5b6abfd087fef8d2e1061 to your computer and use it in GitHub Desktop.
Find all files/folders case-insensitively matching search criteria
// 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