shithub: mc

ref: 3a5ddf0610add4ea0663c4bf2d7f569ac723ad81
dir: /doc/api/libstd/fmt.txt/

View raw version
{
        title:  Formatted I/O
        description:  libstd: Formatted I/O
}



Formatted I/O
-------

    pkg std =
            /* output to file descriptors */
            const put	: (fmt : byte[:], args : ... -> size)
            const fput	: (fd : fd, fmt : byte[:], args : ... -> size)
            const putv	: (fmt : byte[:], ap : valist# -> size)
            const fputv	: (fd : fd, fmt : byte[:], ap : valist# -> size)

            /* formatting values */
            const fmt	: (fmt : byte[:], args : ... -> byte[:])
            const fmtv	: (fmt : byte[:], ap : valist# -> byte[:])
            const bfmt	: (buf : byte[:], fmt : byte[:], args : ... -> byte[:])
            const bfmtv	: (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:])
            const sbfmt	: (buf : strbuf#, fmt : byte[:], args : ... -> size)
            const sbfmtv	: (buf : strbuf#, fmt : byte[:], ap : valist# -> size)
            
            /* custom formatting */
            const fmtinstall	: (ty : byte[:], \
                    fn : (sb : strbuf#, \
                            ap : valist#, \
                            opts : (byte[:],byte[:])[:] \
                            -> void), \
		optdesc : (byte[:], bool)[:] \
		-> void)
    ;;


Overview
--------

Formatting in Myrddin is done with format strings. These are effectively
dynamically typed at runtime, using introspection to decide the best way to
format a type. Custom formatters are allowed and encouraged.

Formatting is specified with a `{}` pair, with any specifiers describing the
formatting passed in as a comma separated set of key value pairs. For example,
an integer can be padded with zeros and formatted in hex with the following
format specifier: `{p=0,x}`. If you want a literal '{' character, it can
be escaped by doubling it.

None of the format specifiers print a newline character by default.

Format Specifiers
--------------------------

The set of specifiers for the default types is sparse, and is fully
specified below.

<dl>
    <dt>w=WIDTH</dt>
    <dd><p>Fill out to at least width WIDTH, filling with pad
    characters.</p></dd>

    <dt>p=PAD</dt>
    <dd>
    <p>Fill spare width with this character. Defaults to a space
    character.</p> </dd>

    <dt>x</dt>
    <dd>
    <p>Format in hex. This is only valid for integer types.</p>
    </dd>

    <dt>j=joiner</dt>
    <dd>
    <p>Join slices with the joiner string. This leaves off the square
    brackets from the ends, and replaces the default joiner string ", ".
    </p>
    </dd>
</dl>

Specifiers can be installed by custom specifiers, and can be any
arbitrary set of strings.

Functions
---------

All the format functions come in two variants: A variadic one, and one
that takes a variadic argument list. The latter is present for ease of
chaining from within a variadic function.

    const put	: (fmt : byte[:], args : ... -> size)
    const fput	: (fd : fd, fmt : byte[:], args : ... -> size)
    const putv	: (fmt : byte[:], ap : valist# -> size)
    const fputv	: (fd : fd, fmt : byte[:], ap : valist# -> size)

The `put` set of functions will format and output to a file descriptor. For
`put` and `putv`, the file descriptor is stdout. For `fput` and `fputv`, the
file descriptor is the one that is provided.

These functions write immediately, and do not buffer, although they do attempt
to do their writing in a single system call, and will only split the call if
the kernel indicates short writes.

The `v` variants will take a variadic argument list for printing.

Returns: the number of bytes written to the file descriptor.

    const sbfmt	: (buf : strbuf#, fmt : byte[:], args : ... -> size)
    const sbfmtv	: (buf : strbuf#, fmt : byte[:], ap : valist# -> size)

The sbfmt functions will append to a string buffer, instead of writing to an
output stream, but are otherwise similar to the `fmt` functions. These
functions will return the number of bytes formatted. If the string buffer is
statically sized, and gets filled, the truncated size will be returned.

    const fmt	: (fmt : byte[:], args : ... -> byte[:])
    const fmtv	: (fmt : byte[:], ap : valist# -> byte[:])

These functions will format according to the format string, and return a
freshly allocated string containing the formatted string. This string should
be freed with `slfree`.

    const bfmt	: (buf : byte[:], fmt : byte[:], args : ... -> byte[:])
    const bfmtv	: (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:])

These functions will format according to the format string, putting the result
into `buf`. They return a slice into the buffer array.
    
    const fmtinstall	: (ty : byte[:], \
            fn : (sb : strbuf#, 
                    ap : valist#, \
                    opts : (byte[:],byte[:])[:] \
                    -> void), \
        optdesc : (byte[:], bool)[:] \
        -> void)

Fmtinstall installs a custom formatter for a type. The type `ty` is a type
description that you would want to format. It can be obtained
using `std.typeof(var)`, `fn` is a function that handles custom formatting,
and `optdesc` is a list of options that this custom formater takes. It is
in the form a list of strings -- the argument names -- and booleans that
define whether these arguments take values.


The custom formatter takes a string buffer `sb` which you are expected to
format the custom input into, as well as a valist that you are expected to
pull the value from. Finally, it takes an option list.

If a formatter is already installed for a type, it is replaced.

Examples
--------

This example demonstrates a bunch of formatting using the std.format API. It
covers all of the various format specifiers, escaping, as well as showing the
formatting of complex types.

```{runmyr fmtsimple}
use std

const main = {
        /* default formats */
	std.put("{} {}\n", "abcd", 123)
	std.put("{}\n", [1,2,3][:])
	std.put("{}\n", (1,"foo"))

        /* mix in some format options */
	std.put("{w=10}\n", "abcd")
	std.put("{p=0,w=10}\n", "abcdefghijkl")
	std.put("{w=10,x}\n", 10)
	std.put("{p=0,w=10}\n", 10)

        /* and now some escaping */
	std.put("{}bar{}\n", "foo\n", "baz")
	std.put("{{}}bar{}\n", "baz")
	std.put("{{bar{}}}\n", "baz")
}
```

This example shows how you would set up a 

```{runmyr customfmt}
use std

const main = {
        var x : int = 0 /* dummy: used for typeof */

        std.fmtinstall(std.typeof(x), goaway, [][:])
        std.put("custom format: {}\n", 0x41)
}

const goaway = {sb, ap, opts
        var i : int64

        i = std.vanext(ap)
        std.sbfmt(sb, "go away! char val={}\n", i castto(char))
}
```