View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2011-2013, University of Amsterdam
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(writef,
   37          [ writef/1,                   % +Format
   38            writef/2,                   % +Format, +Args
   39            swritef/2,                  % -String, +Format
   40            swritef/3                   % -String, +Format, +Args
   41          ]).   42:- set_prolog_flag(generate_debug_info, false).   43
   44/** <module> Old-style formatted write
   45
   46This library provides writef/1 and   friends. These predicates originate
   47from Edinburgh C-Prolog and and provided for compatibility purposes. New
   48code should use format/1, format/2  and   friends,  which  are currently
   49supported by more Prolog implementations.
   50
   51The   writef-family   of   predicates   conflicts    with   the   modern
   52_|character-esacapes|_ flag about  the   interpretation  of \-sequences.
   53This can be avoided by
   54
   55  1. Disable character escapes (not recommended unless one wants to
   56  run really outdated code unmodified).
   57  2. Double the \ for conflicting interpretations
   58  3. Use ISO compliant alternatives for conflicting interpretations
   59
   60@copyright      Copied from Edinburgh C-Prolog. Original version by Byrd,
   61                changed many times since.
   62*/
   63
   64%!  writef(+Format) is det.
   65%!  writef(+Format, +Arguments) is det.
   66%
   67%   Formatted write to the  =current_output=.   Format  is  a format
   68%   specifier. Some escape sequences require  arguments that must be
   69%   provided in the list Arguments. There   are  two types of escape
   70%   sequences: special characters  start  with   =|\|=  and  include
   71%   arguments start with =|%|=. The special character sequences are:
   72%
   73%       | =|\n|= | Output a newline character |
   74%       | =|\l|= | Output a line separator (same as =|\n|=) |
   75%       | =|\r|= | Output a carriage-return character (ASCII 13) |
   76%       | =|\r|= | Output a TAB character (ASCII 9) |
   77%       | =|\\|= | Output =|\|= |
   78%       | =|\%|= | Output =|%|= |
   79%       | =|\nnn|= | Output character <nnn>. <nnn> is a 1-3 decimal number |
   80%
   81%   Escape sequences to include arguments  from Arguments. Each time
   82%   a %-escape sequence is found in   Format  the next argument from
   83%   Arguments is formatted according to the specification.
   84%
   85%       | =|%t|= | print/1 the next item (mnemonic: term) |
   86%       | =|%w|= | write/1 the next item |
   87%       | =|%q|= | writeq/1 the next item  |
   88%       | =|%d|= | display/1 the next item |
   89%       | =|%n|= | Put the next item as a character |
   90%       | =|%r|= | Write the next item N times where N is the second item (an integer) |
   91%       | =|%s|= | Write the next item as a String (so it must be a list of characters) |
   92%       | =|%f|= |Perform a ttyflush/0 (no items used) |
   93%       | =|%Nc|= | Write the next item Centered in N columns. |
   94%       | =|%Nl|= | Write the next item Left justified in N columns. |
   95%       | =|%Nr|= | Write the next item Right justified in N columns. |
   96%
   97%   @deprecated New code should use format/1, format/2, etc.
   98
   99writef(Format) :-
  100    writef(Format, []).
  101
  102writef([F|String], List) :-
  103    '$writefs'([F|String], List),
  104    fail.                           % clean up global stack
  105writef(String, List) :-
  106    string(String),
  107    string_codes(String, Fstring),
  108    '$writefs'(Fstring, List),
  109    fail.                           % clean up global stack
  110writef(Format, List) :-
  111    atom(Format),
  112    name(Format, Fstring),
  113    '$writefs'(Fstring, List),
  114    fail.                           % clean up global stack
  115writef(_, _).
  116
  117%!  swritef(-String, +Format) is det.
  118%!  swritef(-String, +Format, +Arguments) is det.
  119%
  120%   Use writef/1 or writef/2 and  write   the  result to a _string_.
  121%   Note that this is a  string   in  the sense of string_codes/2,
  122%   _not_ a list of character(-code)s.
  123%
  124%   @deprecated.  See format/2,3 and/or with_output_to/2.
  125
  126swritef(String, Format, Arguments) :-
  127    with_output_to(string(String), writef(Format, Arguments)).
  128swritef(String, Format) :-
  129    with_output_to(string(String), writef(Format)).
  130
  131                        % Formatted write for a string (i.e. a list of
  132                        % character codes).
  133
  134'$writefs'([], _).
  135'$writefs'([0'%, A|Rest], List) :-      %   %<$action'>
  136    '$action'(A, List, More),
  137    !,
  138    '$writefs'(Rest, More).
  139'$writefs'([0'%, D|Rest], [Head|Tail]) :-       %   %<columns><just>
  140    between(0'0, 0'9, D),
  141    '$getpad'(Size, Just, [D|Rest], More),
  142    !,
  143    '$padout'(Head, Size, Just),
  144    '$writefs'(More, Tail).
  145'$writefs'([0'\\, C|Rest], List) :-     %   \<special>
  146    '$special'(C, Char),
  147    !,
  148    put(Char),
  149    '$writefs'(Rest, List).
  150'$writefs'([0'\\|Rest], List) :-        %   \<character code in decimal>
  151    '$getcode'(Char, Rest, More),
  152    !,
  153    put(Char),
  154    '$writefs'(More, List).
  155'$writefs'([Char|Rest], List) :-        %   <ordinary character>
  156    put(Char),
  157    '$writefs'(Rest, List).
  158
  159
  160'$action'(0't, [Head|Tail], Tail) :-    %   Term
  161    print(Head).
  162'$action'(0'd, [Head|Tail], Tail) :-    %   Display
  163    write_canonical(Head).
  164'$action'(0'w, [Head|Tail], Tail) :-    %   Write
  165    write(Head).
  166'$action'(0'q, [Head|Tail], Tail) :-    %   Quoted
  167    writeq(Head).
  168'$action'(0'p,  [Head|Tail], Tail) :-   %   Print
  169    print(Head).
  170'$action'(0'f, List, List) :-           %   Flush
  171    ttyflush.
  172'$action'(0'n, [Char|Tail], Tail) :-    %   iNteger (character)
  173    put(Char).
  174'$action'(0'r, [Thing, Times|Tail], Tail) :-    %   Repeatedly
  175    '$writelots'(Times, Thing).
  176'$action'(0's, [Head|Tail], Tail) :-    %   String
  177    '$padout'(Head).
  178
  179'$special'(0'n, 10).            /*  n  */
  180'$special'(0'l, 10).            /*  l  */
  181'$special'(0'r, 10).            /*  r  */
  182'$special'(0't,  9).            /*  t  */
  183'$special'(0'\\, 0'\\).         /*  \  */
  184'$special'(0'%, 0'%).           /*  %  */
  185
  186'$getcode'(Char, In, Out) :-
  187    '$getdigits'(3, Digits, In, Out),
  188    Digits = [_|_],
  189    name(Char, Digits),
  190    Char < 128.
  191
  192'$getdigits'(Limit, [Digit|Digits], [Digit|Out0], Out) :-
  193    Limit > 0,
  194    between(0'0, 0'9, Digit),
  195    Fewer is Limit - 1,
  196    !,
  197    '$getdigits'(Fewer, Digits, Out0, Out).
  198'$getdigits'(_, [], Out, Out).
  199
  200'$writelots'(N, T) :-
  201    N > 0,
  202    !,
  203    write(T),
  204    M is N - 1,
  205    '$writelots'(M, T).
  206'$writelots'(_, _).
  207
  208/*  The new formats are %nC, %nL, and %nR for centered, left, and right
  209    justified output of atoms, integers, and strings.  This is meant to
  210    simplify the production of tabular output when it is appropriate.
  211    At least one space will always precede/follow the item written.
  212*/
  213
  214'$getpad'(Size, Just, In, Out) :-
  215    '$getdigits'(3, Digits, In, [Out1|Out]),
  216    name(Size, Digits),
  217    '$getpad'(Out1, Just).
  218
  219'$getpad'(0'r, r).              %  right justified
  220'$getpad'(0'l, l).              %  left justified
  221'$getpad'(0'c, c).              %  centered
  222'$getpad'(0'R, r).              %  right justified
  223'$getpad'(0'L, l).              %  left justified
  224'$getpad'(0'C, c).              %  centered
  225
  226
  227                                %   '$padout'(A, S, J) writes the item A in a
  228                                %   field of S or more characters, Justified.
  229
  230'$padout'(String, Size, Just) :-
  231    '$string'(String),
  232    !,
  233    name(Atom, String),
  234    '$padout'(Atom, Size, Just).
  235'$padout'(Term, Size, Just) :-
  236    format(string(String), '~w', [Term]),
  237    atom_length(String, Length),
  238    '$padout'(Just, Size, Length, Left, Right),
  239    tab(Left),
  240    write(String),
  241    tab(Right).
  242
  243'$string'(0) :- !, fail.
  244'$string'([]) :- !.
  245'$string'([H|T]) :-
  246    '$print'(H),
  247    !,
  248    '$string'(T).
  249
  250'$print'(10).                   % newline
  251'$print'(9).                    % tab
  252'$print'(X) :-
  253    integer(X),
  254    between(32, 0'~, X).
  255
  256
  257                                %   '$padout'(Just, Size, Length, Left, Right)
  258                                %   calculates the number of spaces to put
  259                                %   on the Left and Right of an item needing
  260                                %   Length characters in a field of Size.
  261
  262'$padout'(l, Size, Length, 0, Right) :-
  263    !,
  264    Right is max(1, Size-Length).
  265'$padout'(r, Size, Length, Left, 0) :-
  266    !,
  267    Left is max(1, Size-Length).
  268'$padout'(c, Size, Length, Left, Right) :-
  269    Left is max(1, round((Size - Length)/2)),
  270    Right is max(1, Size - Length - Left).
  271
  272                                %   '$padout'(Str) writes a string.
  273
  274'$padout'([Head|Tail]) :-
  275    !,
  276    put(Head),
  277    '$padout'(Tail).
  278'$padout'([])