Skip to content

FileRead

Description

Read bytes from a file. Two arities via OVERLOAD:

FileRead(f, buf, n) - low-level: up to n bytes into buf. Short reads are normal at EOF and on signal interruption (we don’t retry on EINTR for you – callers loop if they need that). Sets at_eof when the syscall reports zero bytes. FileRead(f, out) - read to EOF into the container out. out may be a Buf * (binary payload – preferred for parser-input slurps) or a Str * (text payload – only when the caller knows the file is text). Existing length is overwritten; out grows through its own allocator.

out must be an already-init’d Buf * or Str * (its allocator drives the growth). Calling FileRead(f, out) more than once on the same container simply overwrites previous content. Both forms place a trailing zero past length (NUL terminator for the Str form, a benign sentinel byte for Buf).

Success

3-arg form returns bytes read (>= 0); 2-arg form returns total bytes loaded (== BufLength(out) / StrLen(out)).

Failure

Returns -1 on I/O error. The 2-arg form may leave out in a partial state.

Usage example (Cross-references)

Usage examples (Cross-references)
            LOG_INFO("Reading from non-seekable channel.");
            char buf_byte = 0;
            while (FileRead(file, &buf_byte, 1) == 1) {
                StrPushBackR(&buffer, buf_byte);
            }
            if (file_len > 0) {
                StrReserve(&buffer, (u64)file_len);
                i64 got = FileRead(file, StrBegin(&buffer), (u64)file_len);
                if (got < 0) {
                    LOG_ERROR("FileRead failed during f_read_fmt");
                i64 got = FileRead(file, StrBegin(&buffer), (u64)file_len);
                if (got < 0) {
                    LOG_ERROR("FileRead failed during f_read_fmt");
                    StrDeinit(&buffer);
                    DefaultAllocatorDeinit(&scratch);
            char *data = StrBegin(&chunk);
            for (;;) {
                i64 n = FileRead(&f, data, 4096);
                if (n < 0) {
                    ok = false;
            if (!StrReserve(raw, grown_to))
                return false;
            i64 n = FileRead(f, StrEnd(raw), CHUNK);
            if (n < 0)
                return false;
        FileClose(&f);
        if (!ok) {
            LOG_ERROR("ProcMapsLoad: FileRead failed");
            ProcMapsDeinit(out);
            return false;
        }
        if (!proc_maps_read_all(f, &out->raw)) {
            LOG_ERROR("ProcMapsLoadFrom: FileRead failed");
            ProcMapsDeinit(out);
            return false;
    
    bool test_file_read_into_str(void) {
        WriteFmt("Testing FileRead into Str (whole-file load)\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
    
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    
    bool test_file_read_grows_str(void) {
        WriteFmt("Testing FileRead grows the Str backing buffer\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
    
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    
        char scratch[8] = {0};
        ok              = ok && (FileRead(&f, scratch, sizeof(scratch)) == -1);
        ok              = ok && (FileWrite(&f, "x", 1) == -1);
        ok              = ok && (FileSeek(&f, 0, FILE_SEEK_SET) == -1);
    // observable values.
    bool test_write_seek_read_roundtrip(void) {
        WriteFmt("Testing FileWrite/FileSeek/FileTell/FileRead round-trip\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
    
        char got[4] = {0};
        i64  n      = FileRead(&f, got, 4);
        ok          = ok && (n == 4) && got[0] == 'c' && got[1] == 'd' && got[2] == 'e' && got[3] == 'f';
        // A zero-byte request returns 0 and must NOT flag eof.
        char scratch[4] = {0};
        ok              = ok && (FileRead(&f, scratch, 0) == 0) && !FileIsEof(&f);
    
        // Drain the 2 bytes of content.
    
        // Drain the 2 bytes of content.
        ok = ok && (FileRead(&f, scratch, 2) == 2) && !FileIsEof(&f);
    
        // The next read hits EOF: 0 bytes, eof flag set.
    
        // The next read hits EOF: 0 bytes, eof flag set.
        ok = ok && (FileRead(&f, scratch, 2) == 0) && FileIsEof(&f);
    
        FileClose(&f);
        ok       = ok && FileIsOpen(&r);
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&r, &body);
        FileClose(&r);
        File r    = FileOpen(&path, "rb");
        Str  body = StrInit(alloc_base);
        i64  got  = FileRead(&r, &body);
        FileClose(&r);
        Str  body = StrInit(alloc_base);
        File r    = FileOpen(&path, "rb");
        i64  got  = FileRead(&r, &body);
        FileClose(&r);
        ok = ok && (got == 10) && ZstrCompare(StrBegin(&body), "AAA3456789") == 0;
        ok          = ok && FileIsOpen(&f);
        char buf[8] = {0};
        i64  got    = FileRead(&f, buf, 7);
        // Real "r" (O_RDONLY) reads the 7 seeded bytes intact; and a write is
        // rejected. A constant flags value drops O_RDONLY and/or adds O_TRUNC,
    // byte counts the read/write syscalls report.
    bool test_fm_249_read_exact_count(void) {
        WriteFmt("Testing FileRead returns the exact byte count for a partial read\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
        char buf[5] = {0};
        // Exact 5-byte read of the leading content.
        i64 got = FileRead(&f, buf, 5);
        ok      = ok && (got == 5) && (MemCompare(buf, "ABCDE", 5) == 0);
        FileClose(&f);
    // L270 `f->at_eof = true`: a zero-byte read at EOF sets the eof flag.
    bool test_fm_270_read_sets_eof(void) {
        WriteFmt("Testing FileRead at EOF sets the eof flag\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
        ok          = ok && FileIsOpen(&f);
        char buf[4] = {0};
        ok          = ok && (FileRead(&f, buf, 2) == 2) && !FileIsEof(&f);
        // The next read hits EOF: 0 bytes and at_eof becomes true.
        ok = ok && (FileRead(&f, buf, 2) == 0) && FileIsEof(&f);
        ok          = ok && (FileRead(&f, buf, 2) == 2) && !FileIsEof(&f);
        // The next read hits EOF: 0 bytes and at_eof becomes true.
        ok = ok && (FileRead(&f, buf, 2) == 0) && FileIsEof(&f);
        FileClose(&f);
        char buf[8] = {0};
        // Drain to EOF to set at_eof.
        ok = ok && (FileRead(&f, buf, 6) == 6);
        ok = ok && (FileRead(&f, buf, 2) == 0) && FileIsEof(&f);
        // Drain to EOF to set at_eof.
        ok = ok && (FileRead(&f, buf, 6) == 6);
        ok = ok && (FileRead(&f, buf, 2) == 0) && FileIsEof(&f);
    
        // Seek back to start: returns offset 0 and clears the eof flag.
        // And reading now succeeds again from the top.
        char buf2[3] = {0};
        ok           = ok && (FileRead(&f, buf2, 3) == 3) && (MemCompare(buf2, "abc", 3) == 0);
        FileClose(&f);
        ok          = ok && (FileSeek(&f, 4, FILE_SEEK_CUR) == 7);
        char buf[2] = {0};
        ok          = ok && (FileRead(&f, buf, 1) == 1) && (buf[0] == '7');
        FileClose(&f);
    // right or the slurp drops/duplicates bytes.
    bool test_fm_403_remaining_size_from_midfile(void) {
        WriteFmt("Testing FileRead-to-EOF from a mid-file cursor reads only the tail\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
    
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    // total when here == 0; guards the `end < here` and reserve logic).
    bool test_fm_394_remaining_size_full(void) {
        WriteFmt("Testing FileRead-to-EOF from start reads the whole file exactly\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
        ok       = ok && FileIsOpen(&f);
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    // total and full content (guards the reserve-size and grow-loop).
    bool test_fm_427_read_to_buf_large(void) {
        WriteFmt("Testing FileRead-to-Buf slurps a multi-chunk payload exactly\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
        ok      = ok && FileIsOpen(&r);
        Buf dst = BufInit(alloc_base);
        i64 got = FileRead(&r, &dst);
        FileClose(&r);
        ok           = ok && (FileSeek(&f, 0, FILE_SEEK_SET) == 0);
        char buf[10] = {0};
        ok           = ok && (FileRead(&f, buf, 9) == 9) && (MemCompare(buf, "temp-data", 9) == 0);
        FileClose(&f);
    
        FileSeek(&tmp, 0, FILE_SEEK_SET);
        FileRead(&tmp, out);
        FileClose(&tmp);
    }
        bool ok = (rc == ARG_RUN_HELP);
        FileSeek(&tmp, 0, FILE_SEEK_SET);
        FileRead(&tmp, out);
        FileClose(&tmp);
        return ok;
    
        FileSeek(&tmp, 0, FILE_SEEK_SET);
        FileRead(&tmp, out);
        FileClose(&tmp);
        return rc;
        if (FileIsOpen(&f)) {
            Str back = StrInit(&alloc);
            FileRead(&f, &back);
            ok = (ZstrCompare(StrBegin(&back), expect) == 0);
            StrDeinit(&back);
            if (FileIsOpen(&r)) {
                Str back = StrInit(&alloc);
                FileRead(&r, &back);
                ok = ok && (ZstrCompare(StrBegin(&back), "n=42\n") == 0);
                StrDeinit(&back);
            if (FileIsOpen(&r)) {
                Str back = StrInit(&alloc);
                FileRead(&r, &back);
                ok = ok && (ZstrCompare(StrBegin(&back), "X") == 0);
                StrDeinit(&back);
            // position must still be 0: read the first raw byte.
            char c   = 0;
            i64  got = FileRead(&f, &c, 1);
            ok       = (v == 123) && (got == 1) && (c == 'x');
            FileClose(&f);
Last updated on