/* * open — открыть/создать файл по POSIX-флагам. * * Машина состояний флагов: экспонируем POSIX-биты (O_RDONLY/O_WRONLY/ * O_RDWR + O_CREAT/O_EXCL/O_TRUNC/O_APPEND) и диспетчеризуем на три * входа ESTEX: * * $11 OPEN — открыть существующий файл * $0A CREATE — создать (усечь, если существует), вернуть хендл * $0B CREATE_NEW — создать, только если файла нет * * Три приватных __naked-обёртки делают сырые RST 10h; публичный open() * — обычный C-оркестратор. IX сохраняется через каждый RST. * При ошибке errno установлен, возврат -1. */ #include #include #include #include "_fd_guard.h" /* ---- сырые ESTEX-обёртки ---------------------------------------------- */ /* ESTEX $11 OPEN: A=режим (1=R, 2=W, 0=R/W), HL=путь → A=хендл, CF=err. */ static int _estex_open_raw(const char *path, int posix_mode) __naked { (void)path; (void)posix_mode; __asm push ix ;; HL = путь, DE = posix_mode. Перевести в нумерацию ESTEX. 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=атрибут, HL=путь → A=хендл, CF=err. * Усекает существующий файл. */ static int _estex_create_raw(const char *path) __naked { (void)path; __asm push ix xor a, a ; A = 0 (обычный атрибут) 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=атрибут, HL=путь → A=хендл, CF=err. * Падает (errno=EEXIST), если файл уже существует. */ 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; } /* ---- публичная поверхность --------------------------------------------- */ int open(const char *path, int flags) { int fd; /* Предохранитель: 9-й OPEN вешает DSS (см. _fd_guard.h) — * отказать самим, не доводя до syscall. */ if (_fd_open_count >= _FD_OPEN_MAX) { errno = EMFILE; return -1; } if (flags & O_CREAT) { if (flags & O_EXCL) { /* Не должен существовать. */ fd = _estex_create_new_raw(path); } else if (flags & O_TRUNC) { /* Всегда создать или усечь. */ fd = _estex_create_raw(path); } else { /* Открыть, если есть, иначе создать. */ 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; } _fd_open_count++; if (flags & O_APPEND) { /* Встать на конец файла — дальнейшие записи дописывают. */ (void)lseek(fd, 0L, SEEK_END); } return fd; }