diff --git a/os/format.c b/os/format.c index 185f63c2c..1bc27b38a 100644 --- a/os/format.c +++ b/os/format.c @@ -18,10 +18,220 @@ static char SccsId[] = "%W% %G%"; #endif -/* - * This file includes the definition of a pipe related IO. +/** + * @defgroup FormattedIO Formatted Output + * @ingroup YAPIO + * This file includes the definition of the formatted output predicates. * - */ + * @{ + * + * @pred format(+ _T_, :_L_) + + +Print formatted output to the current output stream. The arguments in +list _L_ are output according to the string, list of codes or +characters, or by the atom _T_. + +A control sequence is introduced by a `~`. The following control +sequences are available in YAP: + ++ `~~` +Print a single tilde. + ++ `~a` +The next argument must be an atom, that will be printed as if by `write`. + ++ `~Nc` +The next argument must be an integer, that will be printed as a +character code. The number _N_ is the number of times to print the +character (default 1). + ++ `~Ne` ++ `~NE` ++ `~Nf` ++ `~Ng` ++ `~NG` +The next argument must be a floating point number. The float _F_, the number + _N_ and the control code `c` will be passed to `printf` as: + +~~~~~{.prolog} + printf("%s.Nc", F) +~~~~~ + +As an example: + +~~~~~{.prolog} +?- format("~8e, ~8E, ~8f, ~8g, ~8G~w", + [3.14,3.14,3.14,3.14,3.14,3.14]). +3.140000e+00, 3.140000E+00, 3.140000, 3.14, 3.143.14 +~~~~~ + ++ `~Nd` +The next argument must be an integer, and _N_ is the number of digits +after the decimal point. If _N_ is `0` no decimal points will be +printed. The default is _N = 0_. + +~~~~~{.prolog} +?- format("~2d, ~d",[15000, 15000]). +150.00, 15000 +~~~~~ + ++ `~ND` +Identical to `~Nd`, except that commas are used to separate groups +of three digits. + +~~~~~{.prolog} +?- format("~2D, ~D",[150000, 150000]). +1,500.00, 150,000 +~~~~~ + ++ `~i` +Ignore the next argument in the list of arguments: + +~~~~~{.prolog} +?- format('The ~i met the boregrove',[mimsy]). +The met the boregrove +~~~~~ + ++ `~k` +Print the next argument with `write_canonical`: + +~~~~~{.prolog} +?- format("Good night ~k",a+[1,2]). +Good night +(a,[1,2]) +~~~~~ + ++ `~Nn` +Print _N_ newlines (where _N_ defaults to 1). + ++ `~NN` +Print _N_ newlines if at the beginning of the line (where _N_ +defaults to 1). + ++ `~Nr` +The next argument must be an integer, and _N_ is interpreted as a +radix, such that `2 <= N <= 36` (the default is 8). + +~~~~~{.prolog} +?- format("~2r, 0x~16r, ~r", + [150000, 150000, 150000]). +100100100111110000, 0x249f0, 444760 +~~~~~ + +Note that the letters `a-z` denote digits larger than 9. + ++ `~NR` +Similar to `~NR`. The next argument must be an integer, and _N_ is +interpreted as a radix, such that `2 <= N <= 36` (the default is 8). + +~~~~~{.prolog} +?- format("~2r, 0x~16r, ~r", + [150000, 150000, 150000]). +100100100111110000, 0x249F0, 444760 +~~~~~ + +The only difference is that letters `A-Z` denote digits larger than 9. + ++ `~p` +Print the next argument with print/1: + +~~~~~{.prolog} +?- format("Good night ~p",a+[1,2]). +Good night a+[1,2] +~~~~~ + ++ `~q` +Print the next argument with writeq/1: + +~~~~~{.prolog} +?- format("Good night ~q",'Hello'+[1,2]). +Good night 'Hello'+[1,2] +~~~~~ + ++ `~Ns` +The next argument must be a list of character codes.The system then +outputs their representation as a string, where _N_ is the maximum +number of characters for the string ( _N_ defaults to the length of the +string). + +~~~~~{.prolog} +?- format("The ~s are ~4s",["woods","lovely"]). +The woods are love +~~~~~ + ++ `~w` +Print the next argument with write/1: + +~~~~~ +?- format("Good night ~w",'Hello'+[1,2]). +Good night Hello+[1,2] +~~~~~ + + +The number of arguments, `N`, may be given as an integer, or it +may be given as an extra argument. The next example shows a small +procedure to write a variable number of `a` characters: + +~~~~~ +write_many_as(N) :- + format("~*c",[N,0'a]). +~~~~~ + +The format/2 built-in also allows for formatted output. One can +specify column boundaries and fill the intermediate space by a padding +character: + ++ `~N|` +Set a column boundary at position _N_, where _N_ defaults to the +current position. + ++ `~N+` +Set a column boundary at _N_ characters past the current position, where + _N_ defaults to `8`. + ++ `~Nt` +Set padding for a column, where _N_ is the fill code (default is +`SPC`). + + + +The next example shows how to align columns and padding. We first show +left-alignment: + +~~~~~ + ?- format("~n*Hello~16+*~n",[]). +*Hello * +~~~~~ + +Note that we reserve 16 characters for the column. + +The following example shows how to do right-alignment: + +~~~~~ + ?- format("*~tHello~16+*~n",[]). +* Hello* + +~~~~~ + +The `~t` escape sequence forces filling before `Hello`. + +We next show how to do centering: + +~~~~~ + ?- format("*~tHello~t~16+*~n",[]). +* Hello * +~~~~~ + +The two `~t` escape sequence force filling both before and after +`Hello`. Space is then evenly divided between the right and the +left sides. + ++ `~@` +Evaluate the next argument as a goal whose standard +output is directed to the stream used by format/2. + +*/ + #include "Yap.h" #include "Yatom.h" @@ -52,7 +262,7 @@ static char SccsId[] = "%W% %G%"; #include "eval.h" -#define FORMAT_MAX_SIZE 256 +#define FORMAT_MAX_SIZE 1024 typedef struct { Int len, start; /* tab point */ @@ -911,13 +1121,45 @@ doformat(volatile Term otail, volatile Term oargs, int sno USES_REGS) return (TRUE); } -/* - * @pred with_output_to( + _Stream_ , 0:_Goal ) - * - * Evaluate goal _Goal, such that the output will be sent to _Stream_. - * - * As in format/3, we shall have the special streams `chars`/1, `codes/` and symbtw - * +/** + * @pred with_output_to(+ _Ouput_,: _Goal_) + + +Run _Goal_ as once/1, while characters written to the current +output are sent to _Output_. The predicate was introduced by SWI-Prolog. + + The example below +defines the DCG rule `term/3` to insert a term in the output: + +~~~~~ + term(Term, In, Tail) :- + with_output_to(codes(In, Tail), write(Term)). + +?- phrase(term(hello), X). + +X = [104, 101, 108, 108, 111] +~~~~~ + ++ A Stream handle or alias +Temporary switch current output to the given stream. Redirection using with_output_to/2 guarantees the original output is restored, also if Goal fails or raises an exception. See also call_cleanup/2. ++ atom(- _Atom_) +Create an atom from the emitted characters. +Applications should generally avoid creating atoms by breaking and +concatenating other atoms as the creation of large numbers of +intermediate atoms puts pressure on the atom table and the data-base. This may lead to collisions in the hash tables used to implement atoms, and may result in frequent calls to the garbage collector. In multi-threaded applications, access to the atom table is controlled by locks. This predicate supports creating the therms by expanding +difference-list. + ++ string(- _String_) +Create a string-object, notice that strings are atomic objects. ++ codes(- _Codes_) +Create a list of character codes from the emitted characters, similar to atom_codes/2. ++ codes(- _Codes_, - _Tail_) +Create a list of character codes as a difference-list. ++ chars(- _Chars_) +Create a list of one-character-atoms codes from the emitted characters, similar to atom_chars/2. ++ chars(- _Chars_, - _Tail_) +Create a list of one-character-atoms as a difference-list. + */ static Int with_output_to( USES_REGS1 ) @@ -1042,6 +1284,10 @@ format(Term tout, Term tf, Term tas USES_REGS) return out; } +/** @pred format(+ _T_, :ListWithArguments) + * + * Print formatted output to the current output stream. + */ static Int format2( USES_REGS1 ) { /* 'format'(Stream,Control,Args) */ @@ -1050,9 +1296,14 @@ format2( USES_REGS1 ) return res; } + +/** @pred format(+_Stream_+ _T_, :ListWithArguments) + * + * Print formatted output to the stream _Stream_. + */ static Int format3( USES_REGS1 ) -{ /* 'format'(Stream,Control,Args) */ +{ Int res; res = format(Deref(ARG1), Deref(ARG2),Deref(ARG3) PASS_REGS); return res; @@ -1065,3 +1316,5 @@ Yap_InitFormat(void) Yap_InitCPred ("format", 3, format3, SyncPredFlag); Yap_InitCPred ("with_output_to", 2, with_output_to, SyncPredFlag); } + +/// @}