-
Notifications
You must be signed in to change notification settings - Fork 157
Smaller C Standard Library Wiki
Supported headers and functions
The standard library is mostly complete for DOS, Windows and Linux and is already usable. In fact, the precompiled Smaller C binaries have been compiled with Smaller C and linked with the Smaller C standard library. Most of the compiler tests in this repository also successfully work with the library. This shows some maturity.
The library is implemented on top of system calls of DOS, Windows and Linux.
The DOS version of the library requires one of:
- MS-DOS 4.01 or better, i80386 CPU or better
- Windows 95/98/Me/2000/XP or 32-bit Windows Vista/7
- DOSBox 0.74 or better
The Windows version of the library requires one of:
- Client OS: Windows XP or better
- Server OS: Windows Server 2003 or better
The Linux version of the library requires:
- Ubuntu 12.04 LTS or better (none of the other distros has been tested)
NDEBUG
assert()
isalnum(), isalpha(), isblank(), iscntrl(), isdigit(), isgraph(), islower()
isprint(), ispunct(), isspace(), isupper(), isxdigit(), tolower(), toupper()
EDOM, ERANGE
errno
Note that the C standard does not define most of the E* macros, which are system-specific. As of now, there's only EDOM and ERANGE are supported and errno is never set to anything else than 0, EDOM and ERANGE.
O_RDONLY, O_WRONLY, O_RDWR, O_ACCMODE
O_CREAT, O_EXCL, O_TRUNC, O_APPEND
mode_t
off_t
creat()
open() (doesn't fully support O_APPEND since it's not directly supported by DOS/Windows system calls)
FLT_RADIX, FLT_EVAL_METHOD, FLT_ROUNDS
DECIMAL_DIG
FLT_MANT_DIG, FLT_EPSILON, FLT_DIG, FLT_MIN_EXP, FLT_MIN, FLT_MIN_10_EXP, FLT_MAX_EXP, FLT_MAX, FLT_MAX_10_EXP
DBL_MANT_DIG, DBL_EPSILON, DBL_DIG, DBL_MIN_EXP, DBL_MIN, DBL_MIN_10_EXP, DBL_MAX_EXP, DBL_MAX, DBL_MAX_10_EXP (defined same as the above FLT_* macros because double and float are 32-bit single-precision types)
Note that there are no LDBL_* macros as the long double type is not supported.
PRId<N>, PRIdLEAST<N>, PRIdFAST<N>, PRIdMAX, PRIdPTR,
PRIi<N>, PRIiLEAST<N>, PRIiFAST<N>, PRIiMAX, PRIiPTR,
PRIo<N>, PRIoLEAST<N>, PRIoFAST<N>, PRIoMAX, PRIoPTR,
PRIu<N>, PRIuLEAST<N>, PRIuFAST<N>, PRIuMAX, PRIuPTR,
PRIx<N>, PRIxLEAST<N>, PRIxFAST<N>, PRIxMAX, PRIxPTR,
PRIX<N>, PRIXLEAST<N>, PRIXFAST<N>, PRIXMAX, PRIXPTR,
SCNd<N>, SCNdLEAST<N>, SCNdFAST<N>, SCNdMAX, SCNdPTR,
SCNi<N>, SCNiLEAST<N>, SCNiFAST<N>, SCNiMAX, SCNiPTR,
SCNo<N>, SCNoLEAST<N>, SCNoFAST<N>, SCNoMAX, SCNoPTR,
SCNu<N>, SCNuLEAST<N>, SCNuFAST<N>, SCNuMAX, SCNuPTR,
SCNx<N>, SCNxLEAST<N>, SCNxFAST<N>, SCNxMAX, SCNxPTR,
where <N> is 8, 16 and 32.
imaxdiv_t
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq
CHAR_BIT, CHAR_MIN, CHAR_MAX (char is signed by default)
SCHAR_MIN, SCHAR_MAX, UCHAR_MAX
SHRT_MIN, SHRT_MAX, USHRT_MAX
INT_MIN, INT_MAX, UINT_MAX
LONG_MIN, LONG_MAX, ULONG_MAX
Note that long/32-bit types available in 32-bit and huge memory models only.
NULL
LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME
struct lconv
setlocale(), localeconv()
Note that only the "C" locale is supported.
HUGE_VAL, HUGE_VALF, INFINITY, NAN
MATH_ERRNO, MATH_ERREXCEPT, math_errhandling
frexp(), ldexp(), modf()
fmod(), fabs()
ceil(), floor(), round(), trunc()
sqrt(), hypot()
exp(), exp2(), expm1(), pow(), log(), log2(), log10()
sin(), cos(), tan(), atan2(), atan(), asin(), acos()
sinh(), cosh(), tanh()
Note that the single precision counterparts of the above functions (e.g. fabsf()) exist as well. Both do the same thing since float and double are 32-bit single-precision types.
jmp_buf
setjmp(), longjmp()
sig_atomic_t
SIG_DFL, SIG_ERR, SIG_IGN
SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
signal(), raise()
Note that currently signal() and raise() do nothing and return an error.
va_list
va_start(), va_arg(), va_end()
NULL
size_t, ptrdiff_t
offsetof()
intptr_t, uintptr_t
INTPTR_MIN, INTPTR_MAX, UINTPTR_MAX
PTRDIFF_MIN, PTRDIFF_MAX
SIZE_MAX
intmax_t, uintmax_t
INTMAX_MIN, INTMAX_MAX, UINTMAX_MAX
Note that [u]intmax_t is not a 64-bit or larger type, which it should be. It's a 16-bit integer in 16-bit memory models (tiny and small) and 32-bit in 32-bit and huge memory models.
int8_t, int_least8_t, int_fast8_t
uint8_t, uint_least8_t, uint_fast8_t
int16_t, int_least16_t, int_fast16_t
uint16_t, uint_least16_t, uint_fast16_t
int32_t, int_least32_t, int_fast32_t (32-bit types available in 32-bit and huge memory models only)
uint32_t, uint_least32_t, uint_fast32_t
[U]INT_*8_MIN, [U]INT_*8_MAX
[U]INT_*16_MIN, [U]INT_*16_MAX
[U]INT_*32_MIN, [U]INT_*32_MAX
[U]INT8_C(), [U]INT16_C(), [U]INT32_C(), [U]INTMAX_C()
Note there are no [u]int64*_t types.
NULL
size_t
EOF
SEEK_SET, SEEK_CUR, SEEK_END
fpos_t (contains unsigned short halves[2], the least significant (halves[0]) and the most significant (halves[1]) 16 bits of 32-bit file offsets/positions)
FILE
stdin, stdout, stderr
_IOFBF, _IONBF, _IOLBF, BUFSIZ
FOPEN_MAX, TMP_MAX
FILENAME_MAX, L_tmpnam
fopen() (doesn't support "a+" mode because it's not supported by DOS/Windows directly. "a" should work, though)
freopen() (doesn't support "a+"; doesn't support changing file mode when filename==NULL)
fflush()
fclose()
remove(), rename()
fread(), fwrite()
fgetc(), getc(), getchar()
ungetc() (you must first successfully read a character before calling ungetc())
fgets(), gets()
fputc(), putc(), putchar()
fputs(), puts()
ftell(), fseek() (available in 32-bit and huge memory models only since they provide the long/32-bit type, but you might use __ftell() and __fseek() instead, however, these two latter functions have not been thoroughly tested; also you may use fgetpos() and fsetpos() instead)
fgetpos(), fsetpos()
rewind()
clearerr(), ferror(), feof()
perror() (always prints "Unknown error <value of errno>")
setvbuf(), setbuf()
tmpnam(), tmpfile() (On DOS and Windows the following directories will be checked for existence in order: %TEMP%, %TMP%, C:, the current directory, and the temporary file will be in the first directory that's found to exist and it will be named TMP00000.$$$, where there may be a different number instead of the zeroes. Similarly, on Linux the following directories will be checked for existence in order: /tmp, the current directory, and the temporary file will be in the first directory that's found to exist and it will be named tmp00000.tmp, where there may be a different number instead of the zeroes.)
vfprintf(), fprintf()
vprintf(), printf()
vsprintf(), sprintf()
vsnprintf(), snprintf()
vfscanf(), fscanf() (scanf functions do not support ranges, e.g. "[a-z]"; floating-point isn't supported yet)
vscanf(), scanf()
vsscanf(), sscanf()
fileno() (POSIX)
__ftell(), __fseek() (Smaller C-specific; these are similar to ftell() and fseek(), but offsets are passed/returned via a pointer to fpos_t and fpos_t consists of 2 16-bit integers as opposed to 1 32-bit integer; these functions are intended for the tiny and small memory models in which 32-bit/long types aren't supported; these two functions haven't been thoroughly tested)
NULL
size_t
div_t, ldiv_t
EXIT_SUCCESS, EXIT_FAILURE
abort() (uses exit(EXIT_FAILURE) instead of raise(SIGABRT))
_Exit() (does not flush/close open files)
exit()
atexit()
malloc(), calloc(), free(), realloc()
abs()
labs() (available in 32-bit and huge memory models only)
div()
ldiv() (available in 32-bit and huge memory models only)
atoi()
atol(), strtol(), strtoul() (available in 32-bit and huge memory models only)
rand(), srand()
bsearch(), qsort()
getenv()
system() (the DOS version will try to execute your .COM/.EXE directly, not via COMMAND.COM; this was done in order to receive termination status from smlrc.exe, smlrl.exe and nasm.exe since "COMMAND.COM /C program" would always terminate with status 0, no matter how the program exits)
NULL
size_t
memset(), memcpy(), memmove()
memchr(), memcmp()
strcpy(), strncpy()
strxfrm()
strcat(), strncat()
strlen()
strchr(), strrchr(), strstr()
strcmp(), strncmp(), strcoll() (strcoll() is the same as strcmp())
strspn(), strcspn(), strpbrk()
strtok()
strerror() (always returns "Unknown error <value of errno>")
NULL
size_t
time_t, clock_t
CLOCKS_PER_SEC
struct tm
clock() (on Linux uses times()'s tms_utime + tms_stime and assumes sysconf(_SC_CLK_TCK)==100)
time()
gmtime(), localtime()
mktime()
ctime()
asctime()
strftime()
difftime()
Note that most of functions operate with the type time_t, which is 32-bit. 32-bit/long and floating types are available in 32-bit and huge memory models only and so are most of the functions in time.h.
Note that DOS implementations of all time functions operate with local time (and never UTC/GMT) since there's no standard way to set and maintain time zones and such in DOS. In the future these functions could be re-implemented to rely on the value of the environment variable TZ, commonly found in UNIX-like systems.
Windows implementations of localtime() and mktime() use SystemTimeToTzSpecificLocalTime() and TzSpecificLocalTimeToSystemTime() and no other data sources to perform local to/from UTC/GMT time conversions.
Linux implementations of localtime() and mktime() use the gettimeofday system call and no other data sources to perform local to/from UTC/GMT time conversions.
NULL
size_t, ssize_t
intptr_t
off_t
SEEK_SET, SEEK_CUR, SEEK_END
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO
lseek() (available in 32-bit and huge memory models only since they provide the long/32-bit type, but you might use __lseek() instead, however, the latter has not been tested)
read(), write()
unlink() (has basic semantics of remove())
isatty()
__lseek() (Smaller C-specific; similar to lseek() but offsets are passed/returned via a pointer to fpos_t and fpos_t consists of 2 16-bit integers as opposed to 1 32-bit integer; this function is intended for the tiny and small memory models in which 32-bit/long types aren't supported; this function hasn't been thoroughly tested)
S_IR*, S_IW*, S_IX*, S_IRWX*
mode_t
off_t
time_t
mode_t
off_t
fpos_t
size_t, ssize_t
time_t
The following functions implement poor-man's 32-bit arithmetic using pairs of 16-bit short unsigned ints.
__lngFromUnsigned() (creates a 32-bit value in 2 unsigned shorts from 1 unsigned int)
__lngFromSigned() (creates a 32-bit value in 2 unsigned shorts from 1 signed int)
__lngToUnsigned() (converts/truncates 32-bit value of a pair of 2 unsigned shorts to an unsigned int)
__lngToSigned() (converts/truncates 32-bit value of a pair of 2 unsigned shorts to a signed int)
__lngAdd() (adds 2 pairs of 2 unsigned shorts as 32-bit integers)
__lngSub() (subtracts 2 pairs of 2 unsigned shorts as 32-bit integers)
__lngEq() (compares 2 pairs of 2 unsigned shorts for equality)
__lngUnsignedLess() (tests if the first pair of 2 unsigned shorts is less than the second pair; the 32-bit values are treated as unsigned)
__lngSignedLess() (tests if the first pair of 2 unsigned shorts is less than the second pair; the 32-bit values are treated as signed)
__lngLessThan0() (tests the 32-bit value of a pair of 2 unsigned shorts is less than zero; the 32-bit value is treated as signed)
Note, these functions haven't been thoroughly tested.
Complex types aren't supported by Smaller C.
Floating-point environment isn't supported by Smaller C.
The type bool requires a special type, _Bool, to be supported by the compiler internally. This may be implemented in the future.
Type-generic math isn't supported by Smaller C.
The type wchar_t and wide characters and wide string literals aren't supported by Smaller C. Further, it looks like this functionality may need to be implemented differently for different platforms.
The type wchar_t and wide characters and wide string literals aren't supported by Smaller C. Further, it looks like this functionality may need to be implemented differently for different platforms.
POSIX compatibility is rudimentary. It is not planned to extend it much beyond what's already supported. Some basic functions like access(), stat(), chmod(), opendir(), readdir(), etc may be implemented in the future.
Some of conio.h, dos.h, etc functionality (e.g. clrscr(), kbhit(), getche(), intr(), etc), commonly found in compilers for DOS such as Borland/Turbo C/C++, Open Watcom C/C++ and Microsoft C/Visual C++, may be implemented in the future.
DOS, Windows and Linux provide a lot of system calls with documented public APIs. Many of them are usually accessible with other compilers via dedicated system header files. However, there's no goal to make all of them accessible via e.g. <Windows.h> in the library or in some other way. The primary focus of Smaller C is on what's defined in the language standard and thus on what is required in the standard library. Everything else is secondary.
The library is not multithreading-safe.
You can recompile the library. First, make sure you can successfully compile a hello-world-type of simple application. If that works, that means the compiler can successfully find system header files, which will be needed.
Change the current directory to srclib and then do:
smlrcc -small dpstub.asm -o dpstub.exe
smlrcc @lcdp.txt
smlrcc @lcdh.txt
smlrcc @lcds.txt
smlrcc @lcw.txt
smlrcc @lcl.txt
This will produce files dpstub.exe, lcdp.a, lcdh.a, lcds.a, lcw.a and lcl.a. You can then copy them into directory lib and try to use.