# DuskCC standard library

While DuskCC's core language tries to stay very close to ANSI C, we allow
ourselves significant deviations from ANSI when it comes to the standard
library. Dusk's I/O is different from a regular UNIX, it handles counted strings
rather than null-terminated strings, etc. The standard library needs
adjustements.

The standard library lives in /comp/c/lib.fs. That library is not loaded
automatically when you load /comp/c/cc.fs. If you need that library, you should
ensure that it's loaded with `?f<< /comp/c/lib.fs`. Then, in you C unit, you
do `#include /comp/c/lib.h`.

## Standard Library API

### Proxied Forth words

void abort();
void quit();
void noop();
void abortmsg(char *msg);
uint min(uint a, uint b);
uint max(uint a, uint b);
void emit(char c);
void stype(char *str);
int zstrlen(char *zstr);
int Console();                            --> console :self
uint allot(uint n);                       --> here# + allot
uint allot0(uint n);                      --> here# + allot0
void memset(void *addr, char c, int n)    --> cfill
void memcpy(void *dst, void *src, uint n) --> cmove

int llend(int ll);
void llappend(int ll, int elem);
int llcnt(int ll);

uint le_fetch32(uint addr);             --> le@
ushort le_fetch16(uint addr);           --> 16b le@
void le_store32(uint addr, uint val);   --> le!
void le_store16(uint addr, ushort val); --> 16b le!
uint be_fetch32(uint addr);             --> be@
ushort be_fetch16(uint addr);           --> 16b be@
void be_store32(uint addr, uint val);   --> be!
void be_store16(uint addr, ushort val); --> 16b be!

### Strings

uchar strlen(char *str)

  Return the length of string `str`.

int isdigit(char c)

  Returns 1 if char is in the 0-9 range, 0 otherwise.

### I/O

The I/O API is a simple layer over the system I/O. `hdl` is a regular I/O
handle.

int fgetc(int hdl)                        --> IO :getc
void fputc(int hdl, char c)               --> IO :putc
char* freadline(int hdl)                  --> IO :putback
int fopen(char *path)                     --> Path :find# + Path :open
int fread(int hdl, int *addr, int n)      --> IO :read
int freadbuf(int hdl, int **addr, uint n) --> IO :readbuf
int fwrite(int hdl, int *addr, int n)     --> IO :write
int fwritebuf(int hdl, int *addr, int n)  --> IO :writebuf
void fseek(int hdl, int pos)              --> File :seek
void fclose(int hdl)                      --> IO :close
void fputs(int hdl, char *str)            --> IO :puts
void puts(char *str)                      --> console :puts
(see below for details about printf/scanf)
void fprintf(int hdl, char *fmt, ...)     --> IO :printf
void printf(char *fmt, ...)               --> console :printf
char* sprintf(char *fmt, ...)             --> sprintf
int fscanf(int hdl, char *fmt)            --> see below
int scanf(char *fmt)                      --> fscanf(console readio)
int sscanf(char *fmt, char *str)

### freadbuf

This function is special because :readbuf returns two arguments. The return
value of freadbuf() is "read-n", but "a" is returned through a pointer to an
address which you supply as an argument. If :readbuf is successful, that the
resulting address is written there. Otherwise, nothing is written.

### printf/scanf and variants

fprintf behaves a bit like the standard one, but supports less formatting
arguments.

The I/O handle goes first, followed by the formatting string, then followed by a
variable number of arguments which must match the number of formatting
placeholder in `fmt`. For example, `printf("%b %w %d", 1, 2, 3)` prints
`01 0002 3`.

printf formatting arguments are described in [doc/lib/fmt].

fscanf doesn't exist in sys/io yet and is only and CC stdlib. It supports only
the `%d` placeholder.  It has a funky API because it *pushes* a variable number
of arguments, corresponding to the number of placeholders in the format string,
to PS. It then pushes a 1 in case of scan success.

If it couldn't properly scan the input stream, it pushes *no* argument, only a 0
to indicate failure.

For example, `sscanf("%d %d %d", "5 6 7")` results in PS receiveing elements
`5 6 7 1`, `1` being on top. `sscanf("%d %d %d", "5 6 foo")` yields only a `0`
to PS.

Therefore, when you use sscanf, you need to use "pspop()".

printf and scanf each have `f` and `s` variants. Without a variant, printing and
scanning is done through Console. The `f` variant allow us to choose another
target I/O handle.

For the `s` variant, we have a static buffer wrapped around a `MemIO` that is
used. The resulting string is a memory in that buffer and is overwritten at each
`sprintf` and `sscanf` call.

### Others

void qsort(uint *addr, uint count)

  Sorts an array of `count` integers at address `addr` using the QuickSort
  algorithm.
