/* * open / creat / close — ESTEX file-handle primitives. * * The interesting part is the open() flag state machine. We expose POSIX * flag bits (O_RDONLY/O_WRONLY/O_RDWR + O_CREAT/O_EXCL/O_TRUNC/O_APPEND) * and dispatch onto the three ESTEX entry points: * * $11 OPEN — open existing file * $0A CREATE — create (truncate if exists), return new handle * $0B CREATE_NEW — create only if file does not exist * * Three private __naked wrappers do the raw RST 10h calls; the public * open() / creat() / close() are plain C orchestrators. * * IX is saved across every RST 10h. Failures set errno and return -1. */ #include #include #include /* ---- raw ESTEX wrappers ---------------------------------------------- */ /* ESTEX $11 OPEN: A=mode (1=R, 2=W, 0=R/W), HL=path → A=handle, CF=err. */ static int _estex_open_raw(const char *path, int posix_mode) __naked { (void)path; (void)posix_mode; __asm push ix ;; HL = path, DE = posix_mode. Translate to ESTEX numbering. ld a, e and a, #0x03 ld c, #1 or a, a jr Z, _oopen_real ld c, #2 dec a jr Z, _oopen_real ld c, #0 _oopen_real: ld a, c ld c, #0x11 ; ESTEX OPEN rst #0x10 pop ix jr c, _oopen_err ld e, a ld d, #0 ret _oopen_err: call __errno_set ld de, #-1 ret __endasm; } /* ESTEX $0A CREATE: A=attr, HL=path → A=handle, CF=err. * Truncates an existing file. */ static int _estex_create_raw(const char *path) __naked { (void)path; __asm push ix xor a, a ; A = 0 (normal attribute) ld c, #0x0A rst #0x10 pop ix jr c, _ocreat_err ld e, a ld d, #0 ret _ocreat_err: call __errno_set ld de, #-1 ret __endasm; } /* ESTEX $0B CREATE_NEW: A=attr, HL=path → A=handle, CF=err. * Fails (errno=EEXIST) if file already exists. */ static int _estex_create_new_raw(const char *path) __naked { (void)path; __asm push ix xor a, a ld c, #0x0B rst #0x10 pop ix jr c, _ocreatn_err ld e, a ld d, #0 ret _ocreatn_err: call __errno_set ld de, #-1 ret __endasm; } /* ---- public surface --------------------------------------------------- */ int open(const char *path, int flags) { int fd; if (flags & O_CREAT) { if (flags & O_EXCL) { /* Must not already exist. */ fd = _estex_create_new_raw(path); } else if (flags & O_TRUNC) { /* Always create or truncate. */ fd = _estex_create_raw(path); } else { /* Open if it exists, otherwise create. */ fd = _estex_open_raw(path, flags); if (fd < 0 && errno == ENOENT) { fd = _estex_create_raw(path); } } } else { fd = _estex_open_raw(path, flags); } if (fd < 0) { return -1; } if (flags & O_APPEND) { /* Position at end of file so future writes append. */ (void)lseek(fd, 0L, SEEK_END); } return fd; } int creat(const char *path, int mode) { (void)mode; /* Sprinter has no per-file permission bits */ return open(path, O_WRONLY | O_CREAT | O_TRUNC); } int close(int fd) __naked { (void)fd; __asm push ix ld a, l ld c, #0x12 rst #0x10 pop ix jr c, _oclose_err ld de, #0 ret _oclose_err: call __errno_set ld de, #-1 ret __endasm; }