diff --git a/build.sh b/build.sh index a6639d3..45e9723 100755 --- a/build.sh +++ b/build.sh @@ -1 +1 @@ -gcc -o ibuild src/main.c src/memory.c src/utils.c -fsanitize=address -g -DDEBUG +gcc -o ibuild src/main.c src/memory.c src/utils.c src/string.c src/discovery.c src/io.c -fsanitize=address -g -DDEBUG diff --git a/src/discovery.c b/src/discovery.c new file mode 100644 index 0000000..bebf4d2 --- /dev/null +++ b/src/discovery.c @@ -0,0 +1,99 @@ +#include "discovery.h" + +#include "memory.h" +#include "string.h" +#include "io.h" +#include "utils.h" + +#include +#include + +Discovery discovery_create(Arena* a, StringPool* sp) +{ + assert(a != NULL); + assert(sp != NULL); + Discovery d; + + d.a = a; + d.sp = sp; + + d.files = d.a->mem; + d.c_files = NULL; + d.h_files = NULL; + d.cpp_files = NULL; + + d.file_count = 0; + d.c_count = 0; + d.h_count = 0; + d.cpp_count = 0; + + LOG_DEBUG("Discovery creation completed with arena with block @ %p, with capacity %d.", a->mem, a->cap); + return d; +} + +void discovery_cleanup(Discovery* d) +{ + +} + +void discovery_discover(Discovery* d) +{ + assert(d != NULL); + DirOpContext doc; + doc.a_f = d->a; + doc.sp = d->sp; + StringView path = SV(d->sp, "."); + size_t count = dir_get_recursive(&doc, &path); + d->file_count = count; + LOG_DEBUG("Discovered %d files.", count); + + StringView c_ext = SV(d->sp, ".c"); + ExtDiscoveryResult c_res = discovery_discover_ext(d, d->a, &c_ext); + + if(c_res.mem != NULL) + { + LOG_DEBUG("Discovered %d C files.", c_res.len); + d->c_count = c_res.len; + d->c_files = c_res.mem; + } + + StringView h_ext = SV(d->sp, ".h"); + ExtDiscoveryResult h_res = discovery_discover_ext(d, d->a, &h_ext); + + if(h_res.mem != NULL) + { + LOG_DEBUG("Discovered %d H files.", h_res.len); + d->h_count = h_res.len; + d->h_files = h_res.mem; + } +} + +// TODO: Make the search logic faster, or at least search all of the wanted extension at once, uniformly. +ExtDiscoveryResult discovery_discover_ext(Discovery* d, Arena* a, StringView* ext) +{ + assert(d != NULL); + assert(a != NULL); + assert(ext != NULL); + assert(ext->buf != NULL); + assert(ext->len > 0); + + void* res = a->last; + size_t count = 0; + + for(size_t i = 0; i < d->file_count; i++) + { + char* ptr = strrchr(d->files[i].path.buf, '.'); + if(ptr == NULL) + continue; + + if(strcmp(ptr, ext->buf) == 0) + { + DirEntry** entry = (DirEntry**)arena_alloc(a, sizeof(DirEntry*)); + *entry = &d->files[i]; + count++; + } + } + + if(count > 0) return (ExtDiscoveryResult){.mem = res, .len = count}; + return (ExtDiscoveryResult){.mem = NULL, .len = 0}; +} diff --git a/src/discovery.h b/src/discovery.h new file mode 100644 index 0000000..62c883c --- /dev/null +++ b/src/discovery.h @@ -0,0 +1,45 @@ +#ifndef DISCOVERY_H +#define DISCOVERY_H + +typedef struct Arena Arena; +typedef struct StringPool StringPool; +typedef struct StringView StringView; +typedef struct DirEntry DirEntry; + +#include + +struct Discovery +{ + // Memory + Arena* a; + StringPool* sp; + StringPool* sp_temp; + + // Results + DirEntry* files; + DirEntry** c_files; + DirEntry** h_files; + DirEntry** cpp_files; + + size_t file_count; + size_t c_count; + size_t h_count; + size_t cpp_count; +}; + +struct ExtDiscoveryResult +{ + void* mem; + size_t len; +}; + +typedef struct Discovery Discovery; +typedef struct ExtDiscoveryResult ExtDiscoveryResult; + +Discovery discovery_create(Arena* a, StringPool* sp); +void discovery_cleanup(Discovery* d); +void discovery_discover(Discovery* d); + +ExtDiscoveryResult discovery_discover_ext(Discovery* d, Arena* a, StringView* ext); + +#endif diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..4bacafa --- /dev/null +++ b/src/io.c @@ -0,0 +1,69 @@ +#include "io.h" + +#include "utils.h" +#include "memory.h" + +#include +#include +#include +#include + +StringView path_concat_ss(StringPool *sp, StringView* a, StringView* b) +{ + if(a == NULL) DIE("a must be a valid string!"); + if(b == NULL) DIE("b must be a valid string!"); + if(a->len <= 0 || b->len <= 0) DIE("a and b must not be empty! (a:%d, b:%d)", a->len, b->len); + if(a->buf[a->len - 1] == '/') + return string_createcat_ss(sp, a, b); + StringView slash = (StringView){.buf = "/", .len = 1}; + StringView ts = string_createcat_ss(sp, a, &slash); + return string_createcat_ss(sp, &ts, b); +} + +// Utilize DFS for recursive directory search. +size_t dir_get_recursive(DirOpContext* doc, StringView* p) +{ + assert(doc != NULL); + + if(p == NULL) DIE("p cannot be null!"); + if(p->len <= 0) DIE("p must not be empty!"); + + DIR* d = opendir(p->buf); + if(d == NULL) DIE("could not open directory!"); + + size_t count = 0; + while(d) + { + errno = 0; + struct dirent* de = readdir(d); + + if(de == NULL && errno != 0) DIE("failed to read directory: \"%s\"", p); + if(de == NULL) break; + + if(de->d_type != DT_DIR && de->d_type != DT_REG) continue; + if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, ".git") == 0) continue; + + StringView res = (StringView){.buf = de->d_name, strlen(de->d_name)}; + StringView fpath = path_concat_ss(doc->sp, p, &res); + DirEntry* file = (DirEntry*)arena_alloc(doc->a_f, sizeof(DirEntry)); + file->path = fpath; + file->type = de->d_type; + count++; + + switch(de->d_type) + { + case DT_REG: + LOG_DEBUG("Added entry: \"%.*s\" to memory location @ %p.", fpath.len, fpath.buf, file); + break; + case DT_DIR: + LOG_DEBUG("Added directory directory entry \"%.*s\" to memory location @ %p. Entering directory...", fpath.len, fpath.buf, file); + count += dir_get_recursive(doc, &fpath); + break; + default: + continue; + } + } + LOG_DEBUG("Directory complete: %s", p->buf); + closedir(d); + return count; +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..f718102 --- /dev/null +++ b/src/io.h @@ -0,0 +1,28 @@ +#ifndef IO_H +#define IO_H + +#include "string.h" + +typedef struct Arena Arena; + +struct DirEntry +{ + StringView path; + unsigned char type; +}; + +struct DirOpContext +{ + Arena* a_f; + StringPool* sp; +}; + +typedef struct DirEntry DirEntry; +typedef struct DirOpContext DirOpContext; + +// a should not contain a trailing slash +StringView path_concat_ss(StringPool* sp, StringView* a, StringView* b); + +size_t dir_get_recursive(DirOpContext* doc, StringView* p); + +#endif diff --git a/src/main.c b/src/main.c index 393f6ac..d487031 100644 --- a/src/main.c +++ b/src/main.c @@ -5,22 +5,22 @@ #include #include "utils.h" +#include "string.h" +#include "discovery.h" int main(void) { Backend b = {NULL, 0}; backend_initialize(&b); + + Arena a_sp = arena_create(&b, MEM_ARENA_MAX_CAP); + StringPool sp = string_pool_create(&a_sp); + + Arena a_sptemp = arena_create(&b, MEM_ARENA_MAX_CAP); + StringPool sp_temp = string_pool_create(&a_sptemp); - Arena a; - a.b = &b; - - char* test = (char*)arena_alloc(&a, 6); - char* test2 = "Noice"; - - memcpy(test, test2, 5); - - test[5] = '\0'; + Arena a_d = arena_create(&b, 1024*1024*5); // 5MB for Discovery + Discovery d = discovery_create(&a_d, &sp); + discovery_discover(&d); - printf("That's right. %s\n", test); - return 0; } diff --git a/src/memory.c b/src/memory.c index 9f86164..67e5ce4 100644 --- a/src/memory.c +++ b/src/memory.c @@ -23,24 +23,33 @@ void backend_free(Backend* b) if(munmap(b->mem, b->cap) == -1) DIE("munmap failed!"); } -void* backend_reserve(Backend* b) +void* backend_reserve(Backend* b, size_t cap) { assert(b != NULL); void* ptr = b->last; - if(b->len + MEM_ARENA_MAX_CAP >= MEM_BACKEND_MAX_CAP) - DIE("Out of memory, requested %d (current usage %d out of %d).", MEM_ARENA_MAX_CAP, b->len, b->cap); - b->last = (char*)b->last + (int)MEM_ARENA_MAX_CAP; - b->len += MEM_ARENA_MAX_CAP; + if(b->len + cap >= MEM_BACKEND_MAX_CAP) + DIE("Process out of memory, requested %d (current usage %d out of %d).", cap, b->len, b->cap); + b->last = (char*)b->last + (int)cap; + b->len += cap; return ptr; } -void arena_init(Arena* a) +Arena arena_create(Backend* b, size_t cap) +{ + assert(b != NULL); + Arena a; + a.b = b; + arena_init(&a, cap); + return a; +} + +void arena_init(Arena* a, size_t cap) { assert(a != NULL); assert(a->b != NULL); - void* mem = backend_reserve(a->b); + void* mem = backend_reserve(a->b, cap); a->mem = mem; - a->cap = MEM_ARENA_MAX_CAP; + a->cap = cap; a->len = 0; a->last = a->mem; a->next = NULL; @@ -51,7 +60,7 @@ void* arena_alloc(Arena* a, size_t len) { assert(a != NULL); assert(a->b != NULL); - if(a->mem == NULL || a->last == NULL) arena_init(a); + if(a->mem == NULL || a->last == NULL) arena_init(a, MEM_ARENA_MAX_CAP); int len_aligned = (len + 7) & ~7; diff --git a/src/memory.h b/src/memory.h index 1e665bf..6a00a49 100644 --- a/src/memory.h +++ b/src/memory.h @@ -12,30 +12,34 @@ #include -typedef struct +struct Backend { void* mem; void* last; size_t len; size_t cap; -} Backend; +}; -typedef struct +struct Arena { void* mem; void* last; size_t len; size_t cap; void* next; - Backend* b; -} Arena; + struct Backend* b; +}; + +typedef struct Backend Backend; +typedef struct Arena Arena; void backend_initialize(Backend* b); void backend_free(Backend* b); -void* backend_reserve(Backend* b); +void* backend_reserve(Backend* b, size_t cap); -void arena_init(Arena* a); +Arena arena_create(Backend* b, size_t cap); +void arena_init(Arena* a, size_t cap); //void arena_reset(Arena* a); void* arena_alloc(Arena* a, size_t len); diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..ab78be1 --- /dev/null +++ b/src/string.c @@ -0,0 +1,46 @@ +#include "string.h" + +#include +#include "utils.h" +#include + +StringPool string_pool_create(Arena* a) +{ + assert(a != NULL); + assert(a->mem != NULL); + StringPool sp; + sp.a = a; + LOG_DEBUG("String pool initialized on arena with block @ %p.", sp.a->mem); + return sp; +} + +void string_pool_reset(StringPool* ps) +{ + // arena_reset(&ps->a); +} + +StringView string_create(StringPool* sp, const char* s, size_t len) +{ + assert(sp != NULL); + if(s == NULL) DIE("Invalid string supplied!"); + char* buf = (char*)arena_alloc(sp->a, len + 1); + memcpy(buf, s, len); + buf[len] = '\0'; + LOG_DEBUG("A string was created @ %p with data: \"%s\"", buf, buf); + return (StringView){.buf = buf, .len=len}; +} + +StringView string_createcat_ss(StringPool* sp, StringView* a, StringView* b) +{ + if(a == NULL) DIE("a must be a valid C-style string!"); + if(b == NULL) DIE("b must be a valid C-style string!"); + if(a->len <= 0 || b->len <= 0) DIE("size must be valid! a: %d, b: %d", a->len, b->len); + size_t len = a->len + b->len; + char* buf = (char*)arena_alloc(sp->a, len + 1); + memcpy(buf, a->buf, a->len); + char* bbuf_off = buf + a->len; + memcpy(bbuf_off, b->buf, b->len); + buf[len] = '\0'; + LOG_DEBUG("A string was created @ %p with data: \"%s\"", buf, buf); + return (StringView){.buf = buf, .len = len}; +} diff --git a/src/string.h b/src/string.h new file mode 100644 index 0000000..802b0ca --- /dev/null +++ b/src/string.h @@ -0,0 +1,32 @@ +#ifndef STRING_H +#define STRING_H + +#include "memory.h" + +#include + +#define SV(sp, s) string_create(sp, s, sizeof(s) - 1) + +struct StringPool +{ + Arena* a; +}; + +struct StringView +{ + const char* buf; + size_t len; +}; + +typedef struct StringPool StringPool; +typedef struct StringView StringView; + +StringPool string_pool_create(Arena* a); +void string_pool_reset(StringPool* sp); + +StringView string_create(StringPool* sp, const char* s, size_t len); + +// Ensure that lengths do not contain null term +StringView string_createcat_ss(StringPool* sp, StringView* a, StringView* b); + +#endif