Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nob.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const char *test_names[] = {
"cmd_redirect",
"cmd_args_passing",
"read_entire_dir",
"read_entire_file",
"da_resize",
"da_last",
"da_remove_unordered",
Expand Down
46 changes: 26 additions & 20 deletions nob.h
Original file line number Diff line number Diff line change
Expand Up @@ -2564,36 +2564,42 @@ NOBDEF bool nob_rename(const char *old_path, const char *new_path)
NOBDEF bool nob_read_entire_file(const char *path, Nob_String_Builder *sb)
{
bool result = true;
size_t saved_count = sb->count;
long long m = 0;

FILE *f = fopen(path, "rb");
size_t new_count = 0;
long long m = 0;
if (f == NULL) nob_return_defer(false);
if (fseek(f, 0, SEEK_END) < 0) nob_return_defer(false);
if (f == NULL) nob_return_defer(false);

if (fseek(f, 0, SEEK_END) == 0) {
#ifndef _WIN32
m = ftell(f);
m = ftell(f);
#else
m = _telli64(_fileno(f));
m = _telli64(_fileno(f));
#endif
if (m < 0) nob_return_defer(false);
if (fseek(f, 0, SEEK_SET) < 0) nob_return_defer(false);

new_count = sb->count + m;
if (new_count > sb->capacity) {
sb->items = NOB_DECLTYPE_CAST(sb->items)NOB_REALLOC(sb->items, new_count);
NOB_ASSERT(sb->items != NULL && "Buy more RAM lool!!");
sb->capacity = new_count;
if (fseek(f, 0, SEEK_SET) < 0) nob_return_defer(false);
if (m > 0) nob_da_reserve(sb, sb->count + (size_t)m);
} else {
clearerr(f);
}

fread(sb->items + sb->count, m, 1, f);
if (ferror(f)) {
// TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case.
nob_return_defer(false);
for (;;) {
nob_da_reserve(sb, sb->count + 1);
size_t n = fread(sb->items + sb->count, 1, sb->capacity - sb->count, f);
sb->count += n;
if (n == 0) {
if (ferror(f)) {
// TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case.
nob_return_defer(false);
}
break;
}
}
sb->count = new_count;

defer:
if (!result) nob_log(NOB_ERROR, "Could not read file %s: %s", path, strerror(errno));
if (!result) {
sb->count = saved_count;
nob_log(NOB_ERROR, "Could not read file %s: %s", path, strerror(errno));
}
if (f) fclose(f);
return result;
}
Expand Down
50 changes: 50 additions & 0 deletions tests/read_entire_file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "shared.h"

size_t error_counter = 0;

void error_counting_log_handler(Nob_Log_Level level, const char *fmt, va_list args)
{
UNUSED(fmt);
UNUSED(args);
if (level == ERROR) error_counter++;
}

int main(void)
{
String_Builder sb = {0};

const char *payload = "first line\nsecond line\n";
if (!write_entire_file("file.txt", payload, strlen(payload))) return 1;
if (!read_entire_file("file.txt", &sb)) return 1;
printf("regular file: read %zu bytes\n", sb.count);
printf("%.*s", (int)sb.count, sb.items);

if (!read_entire_file("file.txt", &sb)) return 1;
printf("read again: %zu bytes total\n", sb.count);

Nob_Log_Handler *saved_log_handler = get_log_handler();
set_log_handler(error_counting_log_handler);
bool ok = read_entire_file("does-not-exist.txt", &sb);
set_log_handler(saved_log_handler);
printf("missing file: ok=%s, error_counter=%zu, count=%zu\n", ok ? "true" : "false", error_counter, sb.count);

#ifndef _WIN32
if (mkfifo("fifo", 0644) < 0) return 1;
pid_t pid = fork();
if (pid < 0) return 1;
if (pid == 0) {
FILE *f = fopen("fifo", "wb");
if (f == NULL) _exit(1);
fputs("hello through a fifo\n", f);
fclose(f);
_exit(0);
}
sb.count = 0;
if (!read_entire_file("fifo", &sb)) return 1;
if (waitpid(pid, NULL, 0) < 0) return 1;
printf("fifo: read %zu bytes\n", sb.count);
printf("%.*s", (int)sb.count, sb.items);
#endif

return 0;
}
7 changes: 7 additions & 0 deletions tests/read_entire_file.stdout.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
regular file: read 23 bytes
first line
second line
read again: 46 bytes total
missing file: ok=false, error_counter=1, count=46
fifo: read 21 bytes
hello through a fifo
5 changes: 5 additions & 0 deletions tests/read_entire_file.win32.stdout.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
regular file: read 23 bytes
first line
second line
read again: 46 bytes total
missing file: ok=false, error_counter=1, count=46