summaryrefslogtreecommitdiff
path: root/doc/api/libstd/fmt.txt
blob: 40f1b3fdd65d55a99661f53c87d24e44f794cf66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
{
        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))
}
```