1%% Copyright (c) 2008-2016 Robert Virding
2%%
3%% Licensed under the Apache License, Version 2.0 (the "License");
4%% you may not use this file except in compliance with the License.
5%% You may obtain a copy of the License at
6%%
7%%     http://www.apache.org/licenses/LICENSE-2.0
8%%
9%% Unless required by applicable law or agreed to in writing, software
10%% distributed under the License is distributed on an "AS IS" BASIS,
11%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12%% See the License for the specific language governing permissions and
13%% limitations under the License.
14
15%% File    : lfe_io.erl
16%% Author  : Robert Virding
17%% Purpose : Some basic i/o functions for Lisp Flavoured Erlang.
18%%
19%% The io functions have been split into the following modules:
20%% lfe_io        - basic read and write functions
21%% lfe_io_write  - basic write functions
22%% lfe_io_pretty - basic print functions
23%% lfe_io_format - formatted output
24
25-module(lfe_io).
26
27-export([parse_file/1,read_file/1]).
28-export([read/0,read/1,read/2,read_line/0,read_line/1,read_line/2]).
29-export([read_string/1]).
30-export([scan_sexpr/2,scan_sexpr/3]).
31-export([print/1,print/2,print1/1,print1/2]).
32-export([prettyprint/1,prettyprint/2,
33         prettyprint1/1,prettyprint1/2,prettyprint1/3,prettyprint1/4]).
34-export([format/2,format/3,fwrite/2,fwrite/3,
35         format1/2,fwrite1/2]).
36
37%% -compile(export_all).
38
39-import(lists, [flatten/1,reverse/1,reverse/2,map/2,mapfoldl/3,all/2]).
40
41%% Define IS_MAP/1 macro for is_map/1 bif.
42-ifdef(HAS_MAPS).
43-define(IS_MAP(T), is_map(T)).
44-else.
45-define(IS_MAP(T), false).
46-endif.
47
48%% parse_file(FileName) -> {ok,[{Sexpr,Line}]} | {error,Error}.
49%%  Parse a file returning the raw sexprs (as it should be) and line
50%%  numbers of start of each sexpr. Handle errors consistently.
51
52parse_file(Name) ->
53    with_token_file(Name, fun (Ts) -> parse_file1(Ts, [], []) end).
54
55parse_file1([_|_]=Ts0, Pc0, Ss) ->
56    case lfe_parse:sexpr(Pc0, Ts0) of
57        {ok,L,S,Ts1} -> parse_file1(Ts1, [], [{S,L}|Ss]);
58        {more,Pc1} ->
59            %% Need more tokens but there are none, so call again to
60            %% generate an error message.
61            {error,E,_} = lfe_parse:sexpr(Pc1, {eof,99999}),
62            {error,E};
63        {error,E,_} -> {error,E}
64    end;
65parse_file1([], _, Ss) -> {ok,reverse(Ss)}.
66
67%% read_file(FileName) -> {ok,[Sexpr]} | {error,Error}.
68%%  Read a file returning the raw sexprs (as it should be).
69
70read_file(Name) ->
71    with_token_file(Name, fun (Ts) -> read_file1(Ts, []) end).
72
73read_file1([_|_]=Ts0, Ss) ->
74    case lfe_parse:sexpr(Ts0) of
75        {ok,_,S,Ts1} -> read_file1(Ts1, [S|Ss]);
76        {more,Pc1} ->
77            %% Need more tokens but there are none, so call again to
78            %% generate an error message.
79            {error,E,_} = lfe_parse:sexpr(Pc1, {eof,99999}),
80            {error,E};
81        {error,E,_} -> {error,E}
82    end;
83read_file1([], Ss) -> {ok,reverse(Ss)}.
84
85%% with_token_file(FileName, DoFunc)
86%%  Open the file, scan all LFE tokens and apply DoFunc on them.
87
88with_token_file(Name, Do) ->
89    case file:open(Name, [read]) of
90        {ok,F} ->
91            Ret = case io:request(F, {get_until,unicode,'',lfe_scan,tokens,[1]}) of
92                      {ok,Ts,_} -> Do(Ts);
93                      {error,Error,_} -> {error,Error}
94                  end,
95            file:close(F),                      %Close the file
96            Ret;                                % and return value
97        {error,Error} -> {error,{none,file,Error}}
98    end.
99
100%% read() -> {ok,Sexpr} | {error,Error}.
101%% read(Prompt) -> {ok,Sexpr} | {error,Error}.
102%% read(IoDevice, Prompt) -> {ok,Sexpr} | {error,Error}.
103%%  A simple read function. It is not line oriented and stops as soon
104%%  as it has consumed enough.
105
106read() -> read(standard_io, '').
107read(Prompt) -> read(standard_io, Prompt).
108read(Io, Prompt) ->
109    case io:request(Io, {get_until,unicode,Prompt,?MODULE,scan_sexpr,[1]}) of
110        {ok,Sexpr,_} -> {ok,Sexpr};
111        {error,E} -> {error,{1,io,E}};
112        {error,Error,_} -> {error,Error};
113        {eof,_} -> eof
114    end.
115
116%% read_line() -> {ok,Sexpr} | {error,Error}.
117%% read_line(Prompt) -> {ok,Sexpr} | {error,Error}.
118%% read_line(IoDevice, Prompt) -> {ok,Sexpr} | {error,Error}.
119%%  A simple read function. It is line oriented and reads whole lines
120%%  until it has consumed enough characters. Left-over characters in
121%%  the last line are discarded.
122
123read_line() -> read_line(standard_io, '').
124read_line(Prompt) -> read_line(standard_io, Prompt).
125read_line(Io, Prompt) ->
126    %% We input lines and call scan_sexpr directly ourself.
127    read_line_1(Io, Prompt, [], 1).
128
129read_line_1(Io, P, C0, L0) ->
130    case io:get_line(Io, P) of
131        {error,Error} -> {error,{L0,io,Error}};
132        Cs0 ->
133            case scan_sexpr(C0, Cs0, L0) of
134                {done,{ok,Ret,_L1},_Cs1} -> {ok,Ret};
135                {done,{error,Error,_},_Cs1} -> {error,Error};
136                {more,C1} ->
137                    read_line_1(Io, P, C1, L0)
138            end
139    end.
140
141%% scan_sexpr(Continuation, Chars) ->
142%% scan_sexpr(Continuation, Chars, Line) ->
143%%     {done,Ret,Rest} | {more,Continuation}.
144%%  This function is a re-entrant call which scans tokens from the
145%%  input and parses a sexpr. If there are enough characters then it
146%%  returns {done,...} else {cont,Cont} if it needs more characters.
147%%  This is continued until a sexpr has been scanned.
148
149scan_sexpr([], Cs) ->
150    scan_sexpr({[],[]}, Cs, 1).
151
152scan_sexpr([], Cs, L) ->
153    scan_sexpr({[],[]}, Cs, L);
154scan_sexpr({Sc,Pc}, Cs, L) ->
155    scan_sexpr_1(Sc, Pc, Cs, L).
156
157scan_sexpr_1(Sc0, Pc0, Cs0, L0) ->
158    case lfe_scan:token(Sc0, Cs0, L0) of
159        {done,{error,_,_},_}=Error -> Error;
160        {done,{ok,T,L1},Cs1} ->
161            %% We have a token, now check if we have a sexpr.
162            case lfe_parse:sexpr(Pc0, [T]) of
163                {ok,L2,Sexpr,_} ->
164                    {done,{ok,Sexpr,L2},Cs1};
165                {error,Error,_} ->
166                    {done,{error,Error,Cs1},Cs1};
167                {more,Pc1} ->                   %Need more tokens
168                    scan_sexpr_1([], Pc1, Cs1, L1)
169            end;
170        {done,{eof,_},_}=Eof -> Eof;
171        {more,Sc1} ->
172            {more,{Sc1,Pc0}}
173    end.
174
175%% read_string(String) -> {ok,Sexpr} | {error,Error}.
176%%  Read a string.
177
178read_string(Cs) ->
179    case lfe_scan:string(Cs, 1) of
180        {ok,Ts,L} ->
181            case lfe_parse:sexpr(Ts ++ {eof,L}) of
182                {ok,_,S,_} -> {ok,S};
183                {error,E,_} -> {error,E}
184            end;
185        {error,E,_} -> {error,E}
186    end.
187
188%% print([IoDevice], Sexpr) -> ok.
189%% print1(Sexpr) -> [char()].
190%% print1(Sexpr, Depth) -> [char()].
191%%  A simple print function. Does not pretty-print but stops at Depth.
192
193print(S) -> print(standard_io, S).
194print(Io, S) -> io:put_chars(Io, print1(S)).
195
196print1(S) -> print1(S, -1).                     %All the way
197print1(S, D) -> lfe_io_write:term(S, D).
198
199%% prettyprint([IoDevice], Sexpr) -> ok.
200%% prettyprint1(Sexpr, Depth, Indentation, LineLength) -> [char()].
201%%  External interface to the prettyprint functions.
202
203prettyprint(S) -> prettyprint(standard_io, S).
204prettyprint(Io, S) -> io:put_chars(Io, prettyprint1(S, -1)).
205
206prettyprint1(S) -> lfe_io_pretty:term(S).
207prettyprint1(S, D) -> lfe_io_pretty:term(S, D, 0, 80).
208prettyprint1(S, D, I) -> lfe_io_pretty:term(S, D, I, 80).
209prettyprint1(S, D, I, L) -> lfe_io_pretty:term(S, D, I, L).
210
211%% format([IoDevice,] Format, Args) -> ok.
212%% fwrite([IoDevice,] Format, Args) -> ok.
213%% format1(Format, Args) -> [char()].
214%% fwrite1(Format, Args) -> [char()].
215%%  External interface to the formated output functions.
216
217format(F, As) -> format(standard_io, F, As).
218format(Io, F, As) -> io:put_chars(Io, format1(F, As)).
219
220format1(F, As) -> fwrite1(F, As).
221
222fwrite(F, As) -> fwrite(standard_io, F, As).
223fwrite(Io, F, As) -> io:put_chars(Io, fwrite1(F, As)).
224
225fwrite1(F, As) ->
226    case catch lfe_io_format:fwrite1(F, As) of
227        {'EXIT',_} ->                           %Something went wrong
228            erlang:error(badarg, [F,As]);       %Signal from here
229        Result -> Result
230    end.
231