Note: This is taken from the Chicken Wiki, where a more recent version could be available.

Introduction

Code to generate format functions. It is relatively flexible, supporting inheritance and allowing you to extend your formatters. It is accompanied by an implementation of Common Lisp's format function which is thread safe and extendible (meaning you could define new format characters).

make-format-function

[procedure] (make-format-function CASE-SENSITIVE ESCAPE FORMATTERS)

Create and return a procedure that can be used as a format function. The resulting procedure receives a port, a format string and optional arguments. It parses the format string according to the FORMATTERS parameter and outputs a result to the port specified. If, instead of a port, #t is specified, the results will be sent to the current output port. If, on the other hand, #f is passed, the procedure will store its output on a new string and return it.

CASE-SENSITIVE is a boolean. Are the format directives and modifiers case-sensitive?

The returned procedure parses the format string looking for occurrences of the ESCAPE character (usually #\~); when one is found, a function from the formatters argument is called.

FORMATTERS is a list of formatters. Each formatter is itself a list of (char function) pairs, where char is the character for the escape sequence being defined and function the function to call when the character, preceeded by escape, is found in the format string.

To produce the functions included in the formatters, use the formatter-function procedure.

To output info at the current position, the formatter functions should use the *formatter-out-foo procedures.

To access an argument use the *formatter-next-argument procedure.

For convenience, you can also use formatter-padded procedure when you want to create a function to display an object with padding.

formatter-function

[procedure] (formatter-function PROC)

PROC is a procedure that receives the following parameters:

state
A structure with internal information. You won't normally inspect this directly but rather pass it to other functions that require it (such as *formatter-out-foo procedures).
start
The position in the format string where the beginning of the escape sequence was found. You'll normally just ignore this.
params
A list with paramters that occur between escape and char (for example, in a format string such as ~23,33,12A).
colon, atsign
Booleans indicating whether those characters occur between escape and char.

formatter-padded

[procedure] (formatter-padded SHOW-FUNC)

SHOW-FUNC is a one-argument function, the object, which should write (to the current-output-port) a representation of the object.

The object representation is padded according to the padding parameters - mincol,colinc,minpad,padchar.

*formatter-out-char

[procedure] (*formatter-out-char STATE CHAR)

Output the CHAR. STATE is the internal formatter state object as passed to a formatter-function.

*formatter-out-char-times

[procedure] (*formatter-out-char-times STATE TIMES CHAR)

Output the CHAR N TIMES. STATE is the internal formatter state object as passed to a formatter-function.

*formatter-out-char-list

[procedure] (*formatter-out-char-list STATE LIST-OF-CHAR)

Output the LIST-OF-CHAR. STATE is the internal formatter state object as passed to a formatter-function.

*formatter-out-string

[procedure] (*formatter-out-string STATE STRING)

Output the STRING. STATE is the internal formatter state object as passed to a formatter-function.

*formatter-next-argument

[procedure] (*formatter-next-argument STATE [INCREMENT])

Consumes and returns the next argument. When INCREMENT is supplied it is the number of arguments to consume, the default is 1. STATE is the internal formatter state object as passed to a formatter-function.

format

[procedure] (format PORT FORMAT-STRING . ARGS)

PORT is #f or a string for an output to a string, #t for output to the current output port, or a port.

FORMAT-STRING is a string composed of DIRECTIVEs and/or characters.

ARGS are the data for the FORMAT-STRING DIRECTIVEs.

DIRECTIVE ::= ~{DIRECTIVE-PARAMETER,}[:][@]DIRECTIVE-CHARACTER
DIRECTIVE-PARAMETER ::= [ [-|+]{0-9}+ | 'CHARACTER | v | # ]

This implementation supports directive parameters and modifiers (`:' and `@' characters). Multiple parameters must be separated by a comma (`,'). Parameters can be numerical parameters (positive or negative), character parameters (prefixed by a quote character (`''), variable parameters (`v'), number of rest arguments parameter (`#'), empty and default parameters. Directive characters are case independent.

Implemented CL Format Control Directives

Documentation syntax: Uppercase characters represent the corresponding control directive characters. Lowercase characters represent control directive parameter descriptions.

~A

~A
Aesthetic (print as `display' does).
~@A
left pad.
~mincol,colinc,minpad,padcharA
full padding.

~S

~S
S-expression (print as `write' does).
~@S
left pad.
~mincol,colinc,minpad,padcharS
full padding.

~D

~D
Decimal.
~@D
print number sign always.
~:D
print comma separated.
~mincol,padchar,commachar,commawidthD
padding.

~X

~X
Hexadecimal.
~@X
print number sign always.
~:X
print comma separated.
~mincol,padchar,commachar,commawidthX
padding.

~O

~O
Octal.
~@O
print number sign always.
~:O
print comma separated.
~mincol,padchar,commachar,commawidthO
padding.

~B

~B
Binary.
~@B
print number sign always.
~:B
print comma separated.
~mincol,padchar,commachar,commawidthB
padding.

~R

~nR
Radix N.
~n,mincol,padchar,commachar,commawidthR
padding.
~@R
print a number as a Roman numeral.
~:@R
print a number as an "old fashioned" Roman numeral.
~:R
print a number as an ordinal English number.
~R
print a number as a cardinal English number.

~P

~P
Plural.
~@P
prints `y' and `ies'.
~:P
as ~P but jumps 1 argument backward.
~:@P
as ~@P but jumps 1 argument backward.

~C

~C
Character.
~@C
prints a character as the reader can understand it (i.e. #\ prefixing).
~:C
prints a character as emacs does (eg. `^C' for ASCII 03).

~F

~F
Fixed-format floating-point (prints a flonum like MMM.NNN).
~width,digits,scale,overflowchar,padcharF
padding.
~@F
If the number is positive a plus sign is printed.

~E

~E
Exponential floating-point (prints a flonum like MMM.NNNEEE).
~width,digits,exponentdigits,scale,overflowchar,padchar,exponentcharE
padding
~@E
If the number is positive a plus sign is printed.

~G

~G
General floating-point (prints a flonum either fixed or exponential).
~width,digits,exponentdigits,scale,overflowchar,padchar,exponentcharG
padding.
~@G
If the number is positive a plus sign is printed.

~$

~$
Dollars floating-point (prints a flonum in fixed with signs separated).
~digits,scale,width,padchar$
padding
~@$
If the number is positive a plus sign is printed.
~:@$
A sign is always printed and appears before the padding.
~:$
The sign appears before the padding.

~%

~%
Newline.
~n%
print N newlines.

~&

~&
print newline if not at the beginning of the output line.
~n&
prints `~&' and then N-1 newlines.

~|

~|
Page Separator.
~n|
print N page separators.

~~

~~
Tilde.
~n~
print N tildes.

~T

~T
Tabulation.
~@T
relative tabulation.
~colnum,colincT
full tabulation.

~?

~?
Indirection (expects indirect arguments as a list).
~@?
extracts indirect arguments from format arguments.

~( ... ~)

~(str~)
Case conversion (converts by `string-downcase').
~:(str~)
converts by `string-capitalize'.
~@(str~)
converts by `string-capitalize-first'.
~:@(str~)
converts by `string-upcase'.

~*

~*
Argument Jumping (jumps 1 argument forward).
~n*
jumps N arguments forward.
~:*
jumps 1 argument backward.
~n:*
jumps N arguments backward.
~@*
jumps to the 0th argument.
~n@*
jumps to the Nth argument (beginning from 0)

~[ ... ~]

~[str0~;str1~;...~;strn~]
Conditional Expression (numerical clause conditional).
~n[
take argument from N.
~@[
true test conditional.
~:[
if-else-then conditional.
~;
clause separator.
~:;
default clause follows.

~{ ... ~}

~{STR~}
Iteration (args come from the next argument (a list)). Iteration bounding is controlled by configuration variables format:iteration-bounded and format:max-iterations. With both variables default, a maximum of 100 iterations will be performed.
~n{
at most N iterations.
~:{
args from next arg (a list of lists).
~@{
args from the rest of arguments.
~:@{
args from the rest args (lists).

~^

~^
Up and out.
~n^
aborts if N = 0
~n,m^
aborts if N = M
~n,m,k^
aborts if N ⇐ M ⇐ K

~'<newline>

~'<newline>
Continuation Line.
~:'<newline>
newline is ignored, whitespace left.
~@'<newline>
newline is left, whitespace ignored.

Extended, Replaced and Additional Control Directives

~...V...
Option maybe the character #\V, where the option value is from the argument list.
~colnum,colinc,tabcharT
TABCHAR may be specified.
~I
print a R4RS complex number as `~F~@Fi' with passed parameters for `~F'.
~Y
Pretty print formatting of an argument for scheme code lists.
~K
Same as `~?.'
~!
Flushes the output if format DESTINATION is a port.
~_
Print a `#\space' character
~n_
print N `#\space' characters.
~/
Print a `#\tab' character
~n/
print N `#\tab' characters.
~Q
Prints information and a copyright notice on the format implementation.
~:Q
prints format version.

Not Implemented (Both Common LISP & SLIB)

~<~>
Justification.
~:^
Terminate the iteration process iff the command it would terminate is ~:{ or ~:@{.
~W
Pretty-print, with support for depth abbreviation, circularity, and sharing.
~:S
Print out readproof. Prints out internal objects represented as #<...> as strings "#<...>" so that the format output can always be processed by `read'.
~:A
Print out readproof. Prints out internal objects represented as `#<...>' as strings `"#<...>"' so that the format output can always be processed by `read'.
~... parameter-char ...
PARAMETER-CHAR maybe an integer representation for a character.
~C
Argument maybe an integer representation for a character.
~nC
Takes N as an integer representation for a character. No arguments are consumed. N is converted to a character by `integer→char'. N must be a positive decimal number.
~F, ~E, ~G, ~$, ~I
May also print number strings, i.e. passing a number as a string and format it accordingly.

Incompatible with Common LISP

~/
Call Function ~/FUNC/.
~I
Indent.

Configuration Variables

Format has some configuration variables. There should be no modification necessary for the default configuration. If modification is desired the variable should be set after the format code is loaded.

Implemented

The following variables are supported by this format implementation:

format:floats (default #t)
System has floating-point numbers.
format:complex-numbers (default #f)
System has complex numbers.
format:expch (default #\E)
The character prefixing the exponent value in ~E printing.
format:iteration-bounded (default #t)
When #t, a ~{...~} control will iterate no more than the number of times specified by format:max-iterations regardless of the number of iterations implied by modifiers and arguments. When #f, a ~{...~} control will iterate the number of times implied by modifiers and arguments, unless termination is forced by language or system limitations.
format:max-iterations (default 100)
The maximum number of iterations performed by a ~{...~} control. Has effect only when format:iteration-bounded is #t.

Not Implemented

The following variables are still not supported by this format implementation:

format:fn-max (default 200)
Maximum number of number digits.
format:en-max (default 10)
Maximum number of exponent digits.
format:radix-pref
Does number→string add a radix prefix?
format:symbol-case-conv (default #f)
Symbols are converted by symbol→string so the case type of the printed symbols is implementation dependent. format:symbol-case-conv is a one arg closure which is either #f (no conversion), string-upcase, string-downcase or string-capitalize.
format:iobj-case-conv (default #f)
As format:symbol-case-conv but applies for the representation of implementation internal objects.
format:unprocessed-arguments-error? (default #f)
Are superfluous arguments treated as an error.

Pre-defined Formatters

Many predefined formatters that are used for the implementation of format are exported and can be reused to make new format functions:

*formatter-params*
Parameter escapes.
*formatter-iteration*
Iteration escapes.
*formatter-caseconv*
Case-conversion escapes.
*formatter-chars*
Character escapes.
*formatter-numbers*
Number escapes.
*formatter-cond*
Conditional escapes.
*formatter-indirection*
Indirection escapes.
*formatter-jump*
Jump escapes.
*formatter-objs*
Object escapes.
*formatter-flush*
Flush escapes.
*formatter-plural*
Plural escapes.
*formatter-tabulate*
Tabulate escapes.
*formatter-cl*
All of the above.

Example

format

(use format-modular)
(format #f "Found: [~D]: ~A~%" 12 "objects")

make-format-function

(use format-modular)

(define fprintf
  (make-format-function #f #\%
    `(((#\d ,(formatter-padded display))
       (#\s ,(formatter-padded write))))))

(fprintf #t "Found: [%d]: %s\n" 12 "objects")

Known limitations

Chicken doesn't have support for output port column position. Since a new state is created upon each invocation the format output column position has no "memory", thus ~& is accurate only within a single invocation.

History

1.8
Added '*formatter-next-argument' for argument access by an external formatter. [Kon Lovett]
1.7
Restore optimization (build the vector of formatter characters when the formatter is built, not whenever it is called). Export formatter-padded. Use doc-from-wiki.
1.6
Added KY$I&\\n escapes, V parameter, commawidth, tabchar, localization, bugfixes [Kon Lovett]
1.5
Added support for static linking
1.4
Bug fix for numbers egg use & float/expon format, made port optional [Kon Lovett]
1.3
Minor doc fixes, rename out-* to *formatter-out-*, works with utf8, uses vectors & fixnum arithmetic where possible [Kon Lovett]
1.2
bugfix in formatter-jump
1.1
Small bug fixes, more annotations to the source code
1.0
First public release