- <dos.h>: getdate/gettime/setdate/settime (структуры Turbo-C, обёртки над getdatetime), getdisk/setdisk (ESTEX $02/$01), absread/abswrite (BIOS $55/$56, rst 8 — номера найдены в solid-c DOS.ASM; сектор 0 = boot логического диска) - scanf/fscanf/sscanf: своё C-ядро _scanf_core (%d %u %x %o %c %s, модификатор l, ширина, подавление '*', %%); в SDCC z80 scanf нет, asm solid-c не портируем из-за чужого ABI; 22 хост-теста ядра - хвост П2: fdopen/freopen/fclosall/fgetpos/fsetpos поверх таблицы FILE; парсер режима и выдача слота вынесены в _file_mode/_file_slot - rename() — ESTEX RENAME $10; isatty(fd) = fd <= 0 (tty только псевдо-fd 0/-1/-2: из CLI DSS манипуляторы идут с 1 — verified, fd 1 не резерв, под Flex Navigator его держит навигатор) - errno.h: Solid-C имена ошибок (EZERO/EINVFNC/ENOFILE/...) как алиасы - <sprinter_solid.h> — зонтичный заголовок для портирования; ltell/_setargv в sprinter_compat.h; div/ldiv — из SDCC (проверено) - tests/solidt — smoke всех П3/П4 API, зелёный в MAME (вкл. absread boot-сектора с сигнатурой 55AA) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8.8 KiB
Solid-C compatibility — gap analysis
Goal: if a function exists in Solid-C, it must exist in our libc (with the same name). If we deliberately use a different name, document the difference here.
Solid-C source (third_party/solid-c/INCLUDE/*.H) provides these functions. SDCC's z80.lib auto-includes most of the standard C library. This document tracks the remaining gaps.
Already covered (no work needed)
From our libc directly: atexit, chdir, clearerr, close, clrscr, cprintf, cputs, creat, ctime, asctime, exit, exit, fclose, feof, ferror, fflush, fgetc, fgets, ffirst, fnext, fopen, fputc, fputs, fread, fseek, fstat, ftell, fwrite, getch, getchar, getche, getcwd, getenv, gotoxy, kbhit, longjmp, lseek, mkdir, open, perror, printf, putch, putchar, putenv, puts, read, rewind, rmdir, setjmp, sleep, sprintf, stat, textattr, textbackground, textcolor, unlink, vprintf, vsprintf, write, wherex, wherey, set_videomode, get_videomode, mouse{init,show,hide,read,goto,bounds_x,bounds_y,refresh,text_cursor, load_cursor,get_cursor,get_sensitivity_x,get_sensitivity_y,set_sensitivity, video_mode_changed}.
Free from SDCC's z80.lib (auto-linked): abs, atof, atoi, atol, bsearch, calloc, free, isalpha, isdigit, islower, isupper, isspace, iscntrl, isgraph, isprint, ispunct, isalnum, isxdigit, malloc, memchr, memcmp, memcpy, memmove, memset, qsort, rand, realloc, srand, strcat, strchr, strcmp, strcpy, strcspn, strlen, strncat, strncmp, strncpy, strpbrk, strrchr, strspn, strstr, strtok, strtol, strtoul, tolower, toupper.
REAL gaps — to implement
Category A: trivial (one-liner aliases or small wrappers)
| Solid-C | Status | Notes |
|---|---|---|
getc(fd) |
macro alias | #define getc(fp) fgetc(fp) |
putc(c, fp) |
macro alias | #define putc(c,fp) fputc(c,fp) |
remove(name) |
alias | #define remove(n) unlink(n) (POSIX semantic match) |
seek(fd, off) |
alias | int seek(fd, off) { return lseek(fd, off, SEEK_SET); } |
tell(fd) |
alias | int tell(fd) { return lseek(fd, 0, SEEK_CUR); } |
ltell(fd, &lpos) |
wrapper | wrap our lseek (32-bit) |
home() |
macro alias | #define home() gotoxy(0,0) |
_setargv() |
crt0 does this | provide stub or doc that crt0 covers it |
_ffirst() |
alias | already have ffirst with same semantic — alias macro |
setmem(p, n, b) |
alias | #define setmem(p,n,b) memset(p,b,n) |
movmem(s, d, n) |
alias | #define movmem(s,d,n) memcpy(d,s,n) (note arg order!) |
min(a,b), max(a,b) |
macros | #define min(a,b) ((a)<(b)?(a):(b)) etc. |
isascii(c) |
macro | #define isascii(c) ((unsigned)(c) < 128) |
abort() |
wrapper | void abort(void) { _exit(0xFF); } |
strerr(n) |
alias | rename existing strerror or alias |
sysenv() |
wrapper | already have env API, just alias |
Category B: small new implementations
| Solid-C | Notes |
|---|---|
dec8/dec16/dec32 |
print uint8/16/32 as decimal — use sprintf("%u") internally |
hex8/hex16/hex32 |
print uint8/16/32 as hex — we have print_hex, just add hex16 and hex32 |
strlwr(s) |
in-place lowercase the string (returns s) |
strupr(s) |
in-place uppercase the string |
div(num, den) |
returns div_t { quot, rem } — trivial wrapper over / and % |
getc/putc/ungetc |
one-byte putback for streams; ungetc needs 1-char buffer in FILE* |
gets(buf) |
dangerous-but-Solid-C-has-it, simple fgets-wrapper |
cgets(buf) |
line input via conio (no echo control — wrap getche loop) |
inp(port) / outp(port,val) |
direct port I/O — Z80 IN/OUT, can be __sfr or inline asm wrappers |
enable() / disable() |
__asm ei __endasm / __asm di __endasm |
getdisk() / setdisk(d) |
ESTEX $02 CURDISK / $01 CHDISK |
Category C: requires research / non-trivial work
| Solid-C | Notes |
|---|---|
fdopen(fd, mode) / freopen |
needs FILE* expansion — currently we have unbuffered FILE; mid-effort |
fclosall() |
iterate over all open FILE*'s and close them — depends on FILE table refactor |
fgetpos(fp, &pos) / fsetpos |
wrappers over ftell/fseek with fpos_t type |
bdos(a, hl) / bdosh(...) / intdos(®s) |
Solid-C exposes raw ESTEX call interface. Our convention is typed wrappers — we may document the difference and skip these. |
absread(disk, n, sect, buf) / abswrite |
absolute disk sector I/O — need ESTEX READ_SECT / WRITE_SECT (need to find function numbers) |
_ffirst raw vs ffirst cooked |
Solid-C has two — raw "FilenameExt" format and cooked. Investigate if we want both. |
ioctl(fd, ...) |
terminal control — Solid-C scope unclear, may skip |
isatty(fd) |
trivial (always returns 0 — we have no tty handle), but check our FD numbers |
brk(addr) / sbrk(n) |
classical Unix heap pointer manipulation; our heap is managed by SDCC _sbrk already? Investigate alias. |
scanf / sscanf / fscanf |
parser — SDCC may have it in stdlib if requested. Check or add stub. |
getdate / gettime / setdate / settime |
we have getdatetime/setdatetime; Solid-C splits into date/time structs. Build wrappers. |
Category D: Mouse aliases — Solid-C ms_* names
Solid-C uses short names: ms_init/show/hide/stat/spos/ybnd/xbnd/scur/tcur/gcur/gsen/ssen/hard/vmod/ref + msgstat/mssgpos. All have the same semantics as our mouse_* functions.
Plan: add aliases via header macros so both names work:
#define ms_init mouse_init
#define ms_show mouse_show
/* ... etc */
Also Solid-C wraps state into MSSTAT (8-bit coords) and MSGSTAT (16-bit coords) structs. Our mouse_state_t already matches MSGSTAT semantics — add a typedef alias.
Documented differences (will NOT match Solid-C exactly)
These will be in docs/solid_c_diff.md:
bdos/bdosh/intdos— we don't expose raw ESTEX call interface; use typed wrappersFILE*model — ours is unbuffered (currently); Solid-C may use buffered streams- Error code constants — Solid-C's
EZERO/EINVFNC/etc.vs ourerrnotable. Will provide compat aliases inerrno.h.
Implementation plan
Phase 1 — trivial aliases/macros (~1 hour):
- conio.h additions:
home,inp,outp,enable,disable - stdio.h:
getc,putc,remove,gets - string.h:
setmem,movmem,strlwr,strupr,strerr - stdlib.h:
min,max,div,abort,sysenv,dec8/16/32,hex8/16/32 - ctype.h:
isascii - io.h:
seek,tell,ltell,_setargvstub - dir.h:
_ffirst - mouse.h:
ms_*aliases +MSSTAT/MSGSTATtypedefs - types.h: provide compat
BOOL/uint/WORD/f_pointtypes
Phase 2 — new impls (~2-3 hours):
- ungetc, gets, cgets
- getdisk/setdisk
- getdate/gettime/setdate/settime (split datetime struct)
Phase 3 — investigate / decide (research first):
- absread/abswrite (sector I/O)
- scanf family (SDCC has it?)
- brk/sbrk vs SDCC heap
Compatibility header
To make porting easier, add a single <sprinter_solid.h> that includes all the standard headers (stdio.h, string.h, conio.h, etc.) — Solid-C programs can #include <sprinter_solid.h> and have most functions available.
Status 2026-07-06 — Phase 1/2/3 ЗАКРЫТЫ
Всё из категорий A/B/C реализовано или закрыто решением:
- A (алиасы): все на месте в sprinter_compat.h (+ ltell, _setargv добавлены 2026-07-06); div/ldiv — из SDCC z80.lib (проверено).
- B: getdisk/setdisk (ESTEX $02/$01, libc/io), getdate/gettime/ setdate/settime (обёртки над getdatetime, структуры Turbo-C в <dos.h>), остальное было готово ранее.
- C: fdopen/freopen/fclosall/fgetpos/fsetpos — реализованы поверх таблицы FILE v2 (libc/file); ungetc — есть (FILE v2); absread/abswrite — BIOS $55/$56 (rst 8, A=диск, HL:IX=сектор, DE=буфер, B=счётчик; найдено в solid-c DOS.ASM) — реализованы в libc/io; scanf/fscanf/sscanf — реализованы (своё C-ядро _scanf_core с семантикой Solid-C: %d %u %x %o %c %s, l, ширина, %*; в SDCC z80 scanf нет); isatty — fd < 2 (см. memory/dss_fd_limit). bdos/bdosh/intdos — НЕ экспонируем (решение: типизированные обёртки); brk/sbrk — НЕ нужны (heap SDCC); ioctl — скип.
- errno: Solid-C имена (EZERO/EINVFNC/ENOFILE/…) — алиасы в errno.h.
- Зонтичный заголовок: <sprinter_solid.h>.
- Тест: tests/solidt (MAME).
History
- 2026-07-06 — Phase 1/2/3 закрыты: dos.h (даты/диски/сектора), scanf-семейство, fdopen/freopen/fclosall/fgetpos/fsetpos, rename/isatty (П4), errno-алиасы, sprinter_solid.h, тест solidt
- 2026-06-01 — initial gap analysis vs Solid-C v2004