%% ``The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved via the world wide web at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings %% AB. All Rights Reserved.'' %% %% $Id$ %% -module(io). -export([put_chars/1,put_chars/2,nl/0,nl/1, get_chars/2,get_chars/3,get_line/1,get_line/2, get_password/0, get_password/1, setopts/1, setopts/2]). -export([write/1,write/2,read/1,read/2,read/3]). -export([columns/0,columns/1,rows/0,rows/1]). -export([fwrite/1,fwrite/2,fwrite/3,fread/2,fread/3, format/1,format/2,format/3]). -export([scan_erl_exprs/1,scan_erl_exprs/2,scan_erl_exprs/3, scan_erl_form/1,scan_erl_form/2,scan_erl_form/3, iscan_erl_exprs/1,iscan_erl_exprs/2,iscan_erl_exprs/3, iscan_erl_form/1,iscan_erl_form/2,iscan_erl_form/3, parse_erl_exprs/1,parse_erl_exprs/2,parse_erl_exprs/3, parse_erl_form/1,parse_erl_form/2,parse_erl_form/3, iparse_erl_exprs/1,iparse_erl_exprs/2,iparse_erl_exprs/3, iparse_erl_form/1,iparse_erl_form/2,iparse_erl_form/3]). -export([request/1,request/2,requests/1,requests/2]). %% %% User interface. %% %% Writing and reading characters. to_tuple(T) when is_tuple(T) -> T; to_tuple(T) -> {T}. %% Problem: the variables Other, Name and Args may collide with surrounding %% ones. %% Give extra args to macro, being the variables to use. -define(O_REQUEST(Io, Request), case request(Io, Request) of {error, Reason} -> [Name | Args] = tuple_to_list(to_tuple(Request)), erlang:error(conv_reason(Name, Reason), [Name, Io | Args]); Other -> Other end). o_request(Io, Request) -> case request(Io, Request) of {error, Reason} -> [Name | Args] = tuple_to_list(to_tuple(Request)), {'EXIT',{undef,[_Current|Mfas]}} = (catch erlang:error(undef)), MFA = {io, Name, [Io | Args]}, exit({conv_reason(Name, Reason),[MFA|Mfas]}); % erlang:error(conv_reason(Name, Reason), [Name, Io | Args]); Other -> Other end. put_chars(Chars) -> put_chars(default_output(), Chars). put_chars(Io, Chars) -> o_request(Io, {put_chars,Chars}). nl() -> nl(default_output()). nl(Io) -> % o_request(Io, {put_chars,io_lib:nl()}). o_request(Io, nl). columns() -> columns(default_output()). columns(Io) -> case request(Io,{get_geometry,columns}) of N when is_integer(N) -> {ok,N}; _ -> {error,enotsup} end. rows() -> rows(default_output()). rows(Io) -> case request(Io,{get_geometry,rows}) of N when is_integer(N) -> {ok,N}; _ -> {error,enotsup} end. get_chars(Prompt, N) -> get_chars(default_input(), Prompt, N). get_chars(Io, Prompt, N) when is_integer(N), N >= 0 -> request(Io, {get_chars,Prompt,N}). get_line(Prompt) -> get_line(default_input(), Prompt). get_line(Io, Prompt) -> request(Io, {get_line,Prompt}). get_password() -> get_password(default_input()). get_password(Io) -> request(Io, get_password). setopts(Opts) -> setopts(default_input(), Opts). setopts(Io, Opts) -> request(Io, {setopts, Opts}). %% Writing and reading Erlang terms. write(Term) -> write(default_output(), Term). write(Io, Term) -> o_request(Io, {write,Term}). read(Prompt) -> read(default_input(), Prompt). read(Io, Prompt) -> case request(Io, {get_until,Prompt,erl_scan,tokens,[1]}) of {ok,Toks,_EndLine} -> erl_parse:parse_term(Toks); % {error, Reason} when atom(Reason) -> % erlang:error(conv_reason(read, Reason), [Io, Prompt]); {error,E,_EndLine} -> {error,E}; {eof,_EndLine} -> eof; Other -> Other end. read(Io, Prompt, StartLine) when is_integer(StartLine) -> case request(Io, {get_until,Prompt,erl_scan,tokens,[StartLine]}) of {ok,Toks,EndLine} -> case erl_parse:parse_term(Toks) of {ok,Term} -> {ok,Term,EndLine}; {error,ErrorInfo} -> {error,ErrorInfo,EndLine} end; {error,E,EndLine} -> {error,E,EndLine}; {eof,EndLine} -> {eof,EndLine}; Other -> Other end. %% Formatted writing and reading. conv_reason(_, arguments) -> badarg; conv_reason(_, terminated) -> ebadf; conv_reason(_, _Reason) -> badarg. fwrite(Format) -> format(Format). fwrite(Format, Args) -> format(Format, Args). fwrite(Io, Format, Args) -> format(Io, Format, Args). fread(Prompt, Format) -> fread(default_input(), Prompt, Format). fread(Io, Prompt, Format) -> case request(Io, {fread,Prompt,Format}) of % {error, Reason} when atom(Reason) -> % erlang:error(conv_reason(fread, Reason), [Io, Prompt, Format]); Other -> Other end. format(Format) -> format(Format, []). format(Format, Args) -> format(default_output(), Format, Args). format(Io, Format, Args) -> o_request(Io, {format,Format,Args}). %% Scanning Erlang code. scan_erl_exprs(Prompt) -> scan_erl_exprs(default_input(), Prompt, 1). scan_erl_exprs(Io, Prompt) -> scan_erl_exprs(Io, Prompt, 1). scan_erl_exprs(Io, Prompt, Pos0) -> request(Io, {get_until,Prompt,erl_scan,tokens,[Pos0]}). iscan_erl_exprs(Prompt) -> scan_erl_exprs(default_input(), Prompt, 1). iscan_erl_exprs(Io, Prompt) -> scan_erl_exprs(Io, Prompt, 1). iscan_erl_exprs(Io, Prompt, Pos0) -> request(Io, {get_until,Prompt,erl_scan_ind,tokens,[Pos0]}). scan_erl_form(Prompt) -> scan_erl_form(default_input(), Prompt, 1). scan_erl_form(Io, Prompt) -> scan_erl_form(Io, Prompt, 1). scan_erl_form(Io, Prompt, Pos0) -> request(Io, {get_until,Prompt,erl_scan,tokens,[Pos0]}). iscan_erl_form(Prompt) -> iscan_erl_form(default_input(), Prompt, 1). iscan_erl_form(Io, Prompt) -> iscan_erl_form(Io, Prompt, 1). iscan_erl_form(Io, Prompt, Pos0) -> request(Io, {get_until,Prompt,erl_scan_ind,tokens,[Pos0]}). %% Parsing Erlang code. parse_erl_exprs(Prompt) -> parse_erl_exprs(default_input(), Prompt, 1). parse_erl_exprs(Io, Prompt) -> parse_erl_exprs(Io, Prompt, 1). parse_erl_exprs(Io, Prompt, Pos0) -> case request(Io, {get_until,Prompt,erl_scan,tokens,[Pos0]}) of {ok,Toks,EndPos} -> case erl_parse:parse_exprs(Toks) of {ok,Exprs} -> {ok,Exprs,EndPos}; {error,E} -> {error,E,EndPos} end; Other -> Other end. iparse_erl_exprs(Prompt) -> iparse_erl_exprs(default_input(), Prompt, 1). iparse_erl_exprs(Io, Prompt) -> iparse_erl_exprs(Io, Prompt, 1). iparse_erl_exprs(Io, Prompt, Pos0) -> case request(Io, {get_until,Prompt,erl_scan_ind,tokens,[Pos0]}) of {ok,Toks,EndPos} -> case erl_parse:parse_exprs(Toks) of {ok,Exprs} -> {ok,Exprs,EndPos}; {error,E} -> {error,E,EndPos} end; Other -> Other end. parse_erl_form(Prompt) -> parse_erl_form(default_input(), Prompt, 1). parse_erl_form(Io, Prompt) -> parse_erl_form(Io, Prompt, 1). parse_erl_form(Io, Prompt, Pos0) -> case request(Io, {get_until,Prompt,erl_scan,tokens,[Pos0]}) of {ok,Toks,EndPos} -> case erl_parse:parse_form(Toks) of {ok,Exprs} -> {ok,Exprs,EndPos}; {error,E} -> {error,E,EndPos} end; Other -> Other end. iparse_erl_form(Prompt) -> iparse_erl_form(default_input(), Prompt, 1). iparse_erl_form(Io, Prompt) -> iparse_erl_form(Io, Prompt, 1). iparse_erl_form(Io, Prompt, Pos0) -> case request(Io, {get_until,Prompt,erl_scan_ind,tokens,[Pos0]}) of {ok,Toks,EndPos} -> case erl_parse:parse_form(Toks) of {ok,Exprs} -> {ok,Exprs,EndPos}; {error,E} -> {error,E,EndPos} end; Other -> Other end. %% Miscellaneous functions. request(Request) -> request(default_output(), Request). request(standard_io, Request) -> request(group_leader(), Request); request(Pid, Request) when is_pid(Pid) -> Mref = erlang:monitor(process,Pid), Pid ! {io_request,self(),Pid,io_request(Pid, Request)}, wait_io_mon_reply(Pid,Mref); request(Name, Request) when is_atom(Name) -> case whereis(Name) of undefined -> {error, arguments}; Pid -> request(Pid, Request) end. requests(Requests) -> %Requests as atomic action requests(default_output(), Requests). requests(standard_io, Requests) -> %Requests as atomic action requests(group_leader(), Requests); requests(Pid, Requests) when is_pid(Pid) -> request(Pid, {requests,io_requests(Pid, Requests)}); requests(Name, Requests) when is_atom(Name) -> case whereis(Name) of undefined -> {error, arguments}; Pid -> requests(Pid, Requests) end. default_input() -> group_leader(). default_output() -> group_leader(). wait_io_mon_reply(From, Mref) -> receive {io_reply,From,Reply} -> erlang:demonitor(Mref), receive {'DOWN', Mref, _, _, _} -> true after 0 -> true end, Reply; {'EXIT', From, _What} -> receive {'DOWN', Mref, _, _, _} -> true after 0 -> true end, {error,terminated}; {'DOWN', Mref, _, _, _} -> receive {'EXIT', From, _What} -> true after 0 -> true end, {error,terminated} end. %% io_requests(Requests) %% Transform requests into correct i/o server messages. Only handle the %% one we KNOW must be changed, others, including incorrect ones, are %% passed straight through. Perform a flatten on the request list. io_requests(Pid, Rs) -> io_requests(Pid, Rs, [], []). io_requests(Pid, [{requests,Rs1}|Rs], Cont, Tail) -> io_requests(Pid, Rs1, [Rs|Cont], Tail); io_requests(Pid, [R|Rs], Cont, Tail) -> [io_request(Pid, R)|io_requests(Pid, Rs, Cont, Tail)]; io_requests(Pid, [], [Rs|Cont], Tail) -> io_requests(Pid, Rs, Cont, Tail); io_requests(_Pid, [], [], _Tail) -> []. io_request(_Pid, {write,Term}) -> {put_chars,io_lib,write,[Term]}; io_request(_Pid, {format,Format,Args}) -> {put_chars,io_lib,format,[Format,Args]}; io_request(_Pid, {fwrite,Format,Args}) -> {put_chars,io_lib,fwrite,[Format,Args]}; io_request(_Pid, nl) -> {put_chars,io_lib:nl()}; io_request(Pid, {put_chars,Chars}=Request0) when is_list(Chars), node(Pid) =:= node() -> %% Convert to binary data if the I/O server is guaranteed to be new Request = case catch list_to_binary(Chars) of Binary when is_binary(Binary) -> {put_chars,Binary}; _ -> Request0 end, Request; io_request(Pid, {get_chars,Prompt,N}) when node(Pid) =/= node() -> %% Do not send new I/O request to possibly old I/O server {get_until,Prompt,io_lib,collect_chars,[N]}; io_request(Pid, {get_line,Prompt}) when node(Pid) =/= node() -> %% Do not send new I/O request to possibly old I/O server {get_until,Prompt,io_lib,collect_line,[]}; io_request(_Pid, {fread,Prompt,Format}) -> {get_until,Prompt,io_lib,fread,[Format]}; io_request(_Pid, R) -> %Pass this straight through R.