// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. // See LICENSE.md for license information. // SPDX-License-Identifier: MIT // // JoeyLib file access: read-only game data, writable save files, and a disk- // space query. // // Two directories sit next to the executable, staged there by the per-platform // disk / directory packagers: // DATA/ -- game content (levels, sprites, audio). jlDataOpen. // SAVES/ -- writable save / preference files. jlSave*. // Both are addressed by a bare name relative to their directory; the prefix is // forced here so callers never hard-code "DATA/" or "SAVES/". Both are found // in the program's own folder wherever it was started from, before jlInit as // after: DOS from its start path, the Amiga as PROGDIR:, the X68000 from its // process block, the IIgs as GS/OS prefix 1, the hosted ports from their // executable's path. The ST uses the current directory (TOS tells a program // nothing of its folder); DVX keeps SAVES/ in the program's settings folder // (docs/ApiFile.adoc). #ifndef JOEYLIB_FILE_H #define JOEYLIB_FILE_H #include #include "types.h" // ----- Read-only game data (DATA/) ----- // Open a data file by its name relative to the DATA/ directory. The DATA/ // prefix is prepended automatically; pass "levels/title.dat", not // "DATA/levels/title.dat". mode is a standard fopen mode string, passed on // unchecked (DATA/ is meant to be read, but a writing mode is not refused). // Returns NULL if mode is NULL, the resulting path would overflow the // internal buffer, or the file cannot be opened. FILE *jlDataOpen(const char *name, const char *mode); // ----- Writable save files (SAVES/) ----- // // Save / preference data lives under a SAVES/ directory -- a writable // sibling of the DATA/ tree (where, per port: the top of this file). Names // are relative to SAVES/: pass "hero.sav", not "SAVES/hero.sav". A name is at // most 8 letters and digits starting with a letter, then optionally a period // and up to 3 more, so it fits ProDOS (15 characters, letter first) and DOS // 8.3; every save call refuses any other name, on every port, as if the file // could not be opened. Case must match on Linux, Haiku, BeOS, and the web. // // A failed open / write is non-fatal and simply reports failure (false / 0), // so save code can degrade gracefully on a platform or volume where SAVES/ is // unavailable. // Open a save file for streaming, name relative to SAVES/. mode is a standard // fopen mode string; for write / append modes the SAVES/ directory is created // on demand first. Returns NULL on failure. Use this for large or incremental // saves; for a whole-file blob prefer jlSaveWrite / jlSaveRead. FILE *jlSaveOpen(const char *name, const char *mode); // Write `len` bytes from `buf` to save file `name`, replacing any existing // contents. Returns true only if all `len` bytes were written. The bytes go to // a temporary file that takes the save's place only once it is whole, so a // write that fails part way leaves the old save as it was. buf NULL with // len > 0 returns false before the save is touched. bool jlSaveWrite(const char *name, const void *buf, uint32_t len); // Read up to `max` bytes from save file `name` into `buf`. Returns the number // of bytes read (0 if the file is missing or empty). uint32_t jlSaveRead(const char *name, void *buf, uint32_t max); // True if save file `name` exists and can be opened for reading. bool jlSaveExists(const char *name); // Delete save file `name`. Returns true if the file was removed. bool jlSaveDelete(const char *name); // ----- Disk space ----- // Free space, in bytes, on the volume that holds SAVES/. Returns 0 if it // cannot be determined. Saturates at UINT32_MAX (4 GB - 1) on larger // volumes; DOS's own query (DOS, Win16) stops near 2 GB, and the web's // figure is a fixed number from Emscripten's file system, not the // browser's real space. uint32_t jlDiskFree(void); #endif