libc: сплит «1 функция = 1 модуль» — вся библиотека, wildcard-сборка
- bios/conio/env/errno/gfx/io/mem/mouse/stdio/stdlib/string/sys/time/ video разложены по модулям: общие статики и helpers — в internal _-модулях (_conio.h/_mouse.h/_gfx.h/_palette.h/_atexit.h/_time.h) - lib/Makefile: LIBC_C = wildcard libc/*/*.c — гранулярность файлов = гранулярность DCE линкера - эффект _CODE: gfx_text 6986→2568 Б, gfx_mous −1745, gfx_demo/d16 −542; ранее timedir −3270, ls −3098, stattest −2995 - комментарии оставшихся модулей переведены на русский; puts: убран мёртвый pchars; videomode_raw разложен на get/set - docs/libc-split-asm-cases.md — правила asm-связок между модулями; docs/libc-roadmap.md — план этапа - восстановлен examples/mdview/SAMPLE.MD (нужен make floppy) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* fstat — POSIX fstat() поверх метаданных ESTEX.
|
||||
*
|
||||
* fstat(fd, &st) -> ESTEX GET_D_T ($17) для mtime + lseek/SEEK_END
|
||||
* для размера.
|
||||
*
|
||||
* Sprinter / DSS не хранит POSIX owner/group/inode, поэтому mode
|
||||
* синтезируется минимальный (S_IFREG | rw для пользователя).
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Дата/время файла по хендлу. ESTEX GET_D_T: A=fd, C=$17 → D=day,
|
||||
* E=month, IX=year, H=hour, L=min, B=sec. CF=1 + A=errcode при ошибке.
|
||||
*
|
||||
* Пишет прямо в *out через `ex (sp), hl` (обмен сохранённого out с
|
||||
* HL=час:мин после RST) — статический скретч не нужен.
|
||||
* `out->dow` не трогается (GET_D_T его не возвращает). */
|
||||
static int get_dt_for_handle(int fd, datetime_t *out) __naked
|
||||
{
|
||||
(void)fd; (void)out;
|
||||
__asm
|
||||
;; __sdcccall(1): fd in HL (low byte), out in DE.
|
||||
push ix ; save caller IX
|
||||
push de ; stash out pointer
|
||||
ld a, l ; A = fd
|
||||
ld c, #0x17 ; ESTEX GET_D_T
|
||||
rst #0x10
|
||||
jr c, _gdt_err
|
||||
;; D=day E=month IX=year H=hour L=min B=sec
|
||||
ex (sp), hl ; TOS<->HL: HL=out, TOS=hour:min
|
||||
ld (hl), d ; +0 day
|
||||
inc hl
|
||||
ld (hl), e ; +1 month
|
||||
inc hl
|
||||
push ix ; year onto stack
|
||||
pop de ; DE = year
|
||||
ld (hl), e ; +2 year low
|
||||
inc hl
|
||||
ld (hl), d ; +3 year high
|
||||
inc hl
|
||||
pop de ; D=hour E=min (from earlier ex (sp))
|
||||
ld (hl), d ; +4 hour
|
||||
inc hl
|
||||
ld (hl), e ; +5 min
|
||||
inc hl
|
||||
ld (hl), b ; +6 sec (+7 dow left untouched)
|
||||
pop ix ; restore caller IX
|
||||
ld de, #0
|
||||
ret
|
||||
_gdt_err:
|
||||
pop hl ; discard stashed out pointer
|
||||
pop ix ; restore caller IX
|
||||
call __errno_set
|
||||
ld de, #-1
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
|
||||
int fstat(int fd, struct stat *buf)
|
||||
{
|
||||
/* Размер — через lseek-трюк. */
|
||||
long cur = lseek(fd, 0L, SEEK_CUR);
|
||||
if (cur < 0) return -1;
|
||||
long end = lseek(fd, 0L, SEEK_END);
|
||||
if (end < 0) return -1;
|
||||
(void)lseek(fd, cur, SEEK_SET);
|
||||
buf->st_size = (uint32_t)end;
|
||||
|
||||
/* Дата/время — через ESTEX. */
|
||||
datetime_t ft;
|
||||
if (get_dt_for_handle(fd, &ft) < 0) return -1;
|
||||
{
|
||||
struct tm tm;
|
||||
tm.tm_sec = ft.second;
|
||||
tm.tm_min = ft.minute;
|
||||
tm.tm_hour = ft.hour;
|
||||
tm.tm_mday = ft.day;
|
||||
tm.tm_mon = (unsigned char)(ft.month - 1);
|
||||
tm.tm_year = (int)ft.year - 1900;
|
||||
tm.tm_isdst = 0;
|
||||
tm.tm_hundredth = 0;
|
||||
buf->st_mtime = mktime(&tm);
|
||||
}
|
||||
buf->st_mode = S_IFREG | S_IRUSR | S_IWUSR;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user