# 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: ```c #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 wrappers - **`FILE*` model** — ours is unbuffered (currently); Solid-C may use buffered streams - **Error code constants** — Solid-C's `EZERO/EINVFNC/etc.` vs our `errno` table. Will provide compat aliases in `errno.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`, `_setargv` stub - dir.h: `_ffirst` - mouse.h: `ms_*` aliases + `MSSTAT`/`MSGSTAT` typedefs - types.h: provide compat `BOOL`/`uint`/`WORD`/`f_point` types **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 `` that includes all the standard headers (`stdio.h`, `string.h`, `conio.h`, etc.) — Solid-C programs can `#include ` and have most functions available. ## History - 2026-06-01 — initial gap analysis vs Solid-C v2004