Skip to content

File

Description

Cross-platform file handle. Replaces stdio FILE * in the project: Linux uses an fd through direct syscalls, macOS uses an fd through libSystem, Windows uses a HANDLE. The API surface (FileOpen / Close / Read / Write / Seek / Tell / Flush / Eof) is identical across platforms.

Value type – caller stack-allocates and passes by pointer. A failed open leaves fd (or handle) negative / INVALID; check with FileIsValid before doing anything else with the handle.

Open modes are libc-compatible ("r", "w", "a", "r+", "w+", "a+"), "b" suffix is accepted and ignored – the implementation is always binary. No buffering today.

Usage example (Cross-references)

Usage examples (Cross-references)
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Sys/SymbolResolver.h>
    
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    int main(void) {
        WriteFmt("[INFO] Starting File tests\n\n");
    
        TestFunction tests[] = {
        };
    
        return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "File");
    }
    #ifdef EEXIST
            case EEXIST :
                return "File exists";
    #endif
    #ifdef EXDEV
    #ifdef EFBIG
            case EFBIG :
                return "File too large";
    #endif
    #ifdef ENOSPC
    #ifdef ENAMETOOLONG
            case ENAMETOOLONG :
                return "File name too long";
    #endif
    #ifdef ENOTEMPTY
    #include <Misra/Std.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    static bool path_exists(const char *path) {
        File f = FileOpen(path, "rb");
        if (!FileIsValid(&f)) {
            return false;
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Memory.h>
    
    static bool path_exists(const char *path) {
        File f = FileOpen(path, "rb");
        if (!FileIsValid(&f)) {
            return false;
    
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    #include <stdint.h>
    #include <Misra/Std/File.h>
    
    // ---------------------------------------------------------------------------
    // Check whether `path` exists and is non-empty.
    static bool path_exists(const char *path) {
        File f = FileOpen(path, "rb");
        if (!FileIsValid(&f)) {
            return false;
    #include <Misra/Std/Memory.h>
    
    #include <Misra/Std/File.h>
    
    // ---------------------------------------------------------------------------
        // buffer size and short-circuits to empty — we have to loop-read
        // into a growing buffer ourselves.
        File f = FileOpen("/proc/self/maps", "rb");
        if (!FileIsValid(&f)) {
            LOG_ERROR("ProcMapsLoad: FileOpen(/proc/self/maps) failed");
                return "Unknown";
            case SYS_DIR_ENTRY_TYPE_REGULAR_FILE :
                return "Regular File";
            case SYS_DIR_ENTRY_TYPE_DIRECTORY :
                return "Directory";
    #include <Misra/Parsers/Pe.h>
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    #if MISRA_HAVE_FILE
    #    include <Misra/Std/File.h>
    #endif
    
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Parsers/MachO.h>
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    }
    
    bool f_write_fmt(File *stream, const char *fmtstr, TypeSpecificIO *argv, u64 argc, bool append_newline) {
        Str              out;
        bool             ok      = true;
    }
    
    void f_read_fmt(File *file, const char *fmtstr, TypeSpecificIO *argv, u64 argc) {
        DefaultAllocator scratch = DefaultAllocatorInit();
    #include <Misra/Std/Allocator/Heap.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
        StrWriteFmt(&full, "[{}] [{}:{}] {}\n", (const char *)NAMES[type], (const char *)tag, line, (const char *)msg);
    
        File out = (type == LOG_MESSAGE_TYPE_INFO) ? FileFromFd(1) : FileFromFd(2);
        (void)FileWrite(&out, full.data, full.length);
    /// CreateFile / ReadFile / WriteFile / SetFilePointer / CloseHandle.
    
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Sys.h>
    // ---------------------------------------------------------------------------
    
    File FileOpen(const char *path, const char *mode) {
        File f = {0};
    #ifdef _WIN32
    
    File FileOpen(const char *path, const char *mode) {
        File f = {0};
    #ifdef _WIN32
        f.handle = INVALID_HANDLE_VALUE;
    }
    
    File FileFromFd(i32 fd) {
        File f = {0};
    #ifdef _WIN32
    
    File FileFromFd(i32 fd) {
        File f = {0};
    #ifdef _WIN32
        (void)fd;
    }
    
    File FileStdin(void) {
    #ifdef _WIN32
        File f = {.handle = GetStdHandle(STD_INPUT_HANDLE), .owns = false};
    File FileStdin(void) {
    #ifdef _WIN32
        File f = {.handle = GetStdHandle(STD_INPUT_HANDLE), .owns = false};
        return f;
    #else
    }
    
    File FileStdout(void) {
    #ifdef _WIN32
        File f = {.handle = GetStdHandle(STD_OUTPUT_HANDLE), .owns = false};
    File FileStdout(void) {
    #ifdef _WIN32
        File f = {.handle = GetStdHandle(STD_OUTPUT_HANDLE), .owns = false};
        return f;
    #else
    }
    
    File FileStderr(void) {
    #ifdef _WIN32
        File f = {.handle = GetStdHandle(STD_ERROR_HANDLE), .owns = false};
    File FileStderr(void) {
    #ifdef _WIN32
        File f = {.handle = GetStdHandle(STD_ERROR_HANDLE), .owns = false};
        return f;
    #else
    }
    
    bool FileClose(File *f) {
        if (!f) {
            return false;
    }
    
    bool FileIsValid(const File *f) {
        if (!f) {
            return false;
    // ---------------------------------------------------------------------------
    
    i64 FileRead(File *f, void *buf, u64 n) {
        if (!FileIsValid(f) || !buf) {
            return -1;
    }
    
    i64 FileWrite(File *f, const void *buf, u64 n) {
        if (!FileIsValid(f) || !buf) {
            return -1;
    }
    
    i64 FileSeek(File *f, i64 offset, FileWhence whence) {
        if (!FileIsValid(f)) {
            return -1;
    }
    
    i64 FileTell(File *f) {
        return FileSeek(f, 0, FILE_SEEK_CUR);
    }
    }
    
    bool FileFlush(File *f) {
        if (!FileIsValid(f)) {
            return false;
    }
    
    bool FileIsEof(const File *f) {
        return f && f->at_eof;
    }
    }
    
    i32 FileFd(const File *f) {
    #ifdef _WIN32
        (void)f;
        }
    
        File f = FileOpen(filename, "rb");
        if (!FileIsValid(&f)) {
            return false;
    
    #if MISRA_HAVE_FILE
    #    include <Misra/Std/File.h>
    #endif
        bool at_eof; // last read returned 0 bytes
        bool owns;   // true when FileClose should release the handle
    } File;
    
    ///
    /// FAILURE : Returns a File where `FileIsValid(&out)` is false.
    ///
    File FileOpen(const char *path, const char *mode);
    
    ///
    /// elsewhere.
    ///
    File FileFromFd(i32 fd);
    
    ///
    /// 0/1/2 on POSIX, the GetStdHandle() values on Windows.
    ///
    File FileStdin(void);
    File FileStdout(void);
    File FileStderr(void);
    ///
    File FileStdin(void);
    File FileStdout(void);
    File FileStderr(void);
    File FileStdin(void);
    File FileStdout(void);
    File FileStderr(void);
    
    ///
    /// FAILURE : Returns false if the close syscall failed (logged).
    ///
    bool FileClose(File *f);
    
    ///
    /// True if the underlying handle is valid (open).
    ///
    bool FileIsValid(const File *f);
    
    ///
    /// FAILURE : Returns -1 on error.
    ///
    i64 FileRead(File *f, void *buf, u64 n);
    
    ///
    /// FAILURE : Returns -1 on error.
    ///
    i64 FileWrite(File *f, const void *buf, u64 n);
    
    ///
    /// FAILURE : Returns -1 on error (typically ESPIPE for a pipe/tty).
    ///
    i64 FileSeek(File *f, i64 offset, FileWhence whence);
    
    ///
    /// FAILURE : Returns -1 on error.
    ///
    i64 FileTell(File *f);
    
    ///
    /// FAILURE : Returns false.
    ///
    bool FileFlush(File *f);
    
    ///
    /// True if a previous FileRead returned 0 bytes.
    ///
    bool FileIsEof(const File *f);
    
    ///
    /// Useful for syscalls that need a raw fd (e.g. isatty checks).
    ///
    i32 FileFd(const File *f);
    
    /// Snake_case runtime helper. Users call `ReadCompleteFile(...)`; the
    
    #include <Misra/Std/Container.h>
    #include <Misra/Std/File.h>
    #include <Misra/Types.h>
    #define WriteFmt(...)                                                                                                  \
        do {                                                                                                               \
            File __misra_out__ = FileStdout();                                                                             \
            FWriteFmt(&__misra_out__, __VA_ARGS__);                                                                        \
        } while (0)
    #define WriteFmtLn(...)                                                                                                \
        do {                                                                                                               \
            File __misra_out__ = FileStdout();                                                                             \
            FWriteFmtLn(&__misra_out__, __VA_ARGS__);                                                                      \
        } while (0)
    #define ReadFmt(...)                                                                                                   \
        do {                                                                                                               \
            File __misra_in__ = FileStdin();                                                                               \
            FReadFmt(&__misra_in__, __VA_ARGS__);                                                                          \
        } while (0)
    int main(int argc, char **argv) {
        if (argc != 2) {
            File err_ = FileStderr();
            FWriteFmtLn(&err_, "USAGE : {} config.json", argc == 0 ? "MisraDoc" : argv[0]);
            return 1;
    
        if (argc < 2 || argc > 3) {
            File err_ = FileStderr();
            FWriteFmtLn(&err_, "USAGE : {} <enum-json-spec> [output-file-name]", argc == 0 ? "MisraEnum" : argv[0]);
            return 1;
        }
    
        File elf = FileOpen(argv[1], "rb");
        if (!FileIsValid(&elf)) {
            LOG_ERROR("Failed to open file for reading.");
Last updated on