summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Frantzen <71122361+frazze-jobb@users.noreply.github.com>2023-05-11 15:12:28 +0200
committerGitHub <noreply@github.com>2023-05-11 15:12:28 +0200
commit911461e585a1ab82857b501ca6c9ffb31c2efd8c (patch)
tree3ca7aaedba79b60de4c7eecf51205ae70a0d9d9d
parent04b86c346589cdf9c7b623cdec1bebc87d9e58ec (diff)
parent37556967e4ddc6b32c748f8bb0bd4245b1612671 (diff)
downloaderlang-911461e585a1ab82857b501ca6c9ffb31c2efd8c.tar.gz
Merge pull request #7211 from frazze-jobb/frazze/kernel/send_bytes_over_stdout
kernel: support sending raw byte data over stdout
-rw-r--r--lib/kernel/src/group.erl35
-rw-r--r--lib/kernel/src/prim_tty.erl5
-rw-r--r--lib/kernel/src/user_drv.erl4
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl45
4 files changed, 76 insertions, 13 deletions
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index 665b326ea0..311c2f3c5e 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -40,6 +40,7 @@ server(Ancestors, Drv, Shell, Options) ->
put(line_buffer, proplists:get_value(line_buffer, Options, group_history:load())),
put(read_mode, list),
put(user_drv, Drv),
+ put(unicode_state, true),
ExpandFun = normalize_expand_fun(Options, fun edlin_expand:expand/2),
put(expand_fun, ExpandFun),
put(echo, proplists:get_value(echo, Options, true)),
@@ -239,17 +240,27 @@ io_request({put_chars,unicode,M,F,As}, Drv, _Shell, From, Buf) ->
end
end;
io_request({put_chars,latin1,Binary}, Drv, _Shell, From, Buf) when is_binary(Binary) ->
- send_drv(Drv, {put_chars_sync, unicode,
- unicode:characters_to_binary(Binary,latin1),
- From}),
+ IsUnicode = get(unicode_state),
+ if IsUnicode ->
+ send_drv(Drv,
+ {put_chars_sync, unicode,
+ unicode:characters_to_binary(Binary,latin1),
+ From});
+ true ->
+ send_drv(Drv, {put_chars_sync, latin1, Binary, From})
+ end,
{noreply,Buf};
io_request({put_chars,latin1,Chars}, Drv, _Shell, From, Buf) ->
- case catch unicode:characters_to_binary(Chars,latin1) of
- Binary when is_binary(Binary) ->
- send_drv(Drv, {put_chars_sync, unicode, Binary, From}),
- {noreply,Buf};
- _ ->
- {error,{error,{put_chars,latin1,Chars}},Buf}
+ IsUnicode = get(unicode_state),
+ if IsUnicode ->
+ case catch unicode:characters_to_binary(Chars,latin1) of
+ Binary when is_binary(Binary) ->
+ send_drv(Drv, {put_chars_sync, unicode, Binary, From}),
+ {noreply,Buf};
+ _ ->
+ {error,{error,{put_chars,latin1,Chars}},Buf}
+ end;
+ true -> send_drv(Drv, {put_chars_sync, latin1, Chars, From})
end;
io_request({put_chars,latin1,M,F,As}, Drv, _Shell, From, Buf) ->
case catch apply(M, F, As) of
@@ -396,9 +407,11 @@ do_setopts(Opts, Drv, Buf) ->
put(echo, proplists:get_value(echo, Opts, get(echo))),
case proplists:get_value(encoding,Opts) of
Valid when Valid =:= unicode; Valid =:= utf8 ->
- set_unicode_state(Drv,true);
+ set_unicode_state(Drv,true),
+ put(unicode_state, true);
latin1 ->
- set_unicode_state(Drv,false);
+ set_unicode_state(Drv,false),
+ put(unicode_state, false);
_ ->
ok
end,
diff --git a/lib/kernel/src/prim_tty.erl b/lib/kernel/src/prim_tty.erl
index 7ed418de5e..4ef10c752d 100644
--- a/lib/kernel/src/prim_tty.erl
+++ b/lib/kernel/src/prim_tty.erl
@@ -164,6 +164,7 @@
sig => boolean()
}.
-type request() ::
+ {putc_raw, binary()} |
{putc, unicode:unicode_binary()} |
{expand, unicode:unicode_binary()} |
{insert, unicode:unicode_binary()} |
@@ -525,6 +526,8 @@ writer_loop(TTY, WriterRef) ->
-spec handle_request(state(), request()) -> {erlang:iovec(), state()}.
handle_request(State = #state{ options = #{ tty := false } }, Request) ->
case Request of
+ {putc_raw, Binary} ->
+ {Binary, State};
{putc, Binary} ->
{encode(Binary, State#state.unicode), State};
beep ->
@@ -565,6 +568,8 @@ handle_request(State = #state{ unicode = U }, {putc, Binary}) ->
{_, _, _, NewBA} = split(NewLength - OldLength, NewState#state.buffer_after, U),
{encode(PutBuffer, U), NewState#state{ buffer_after = NewBA }}
end;
+handle_request(State, {putc_raw, Binary}) ->
+ handle_request(State, {putc, unicode:characters_to_binary(Binary, latin1)});
handle_request(State = #state{ unicode = U }, {delete, N}) when N > 0 ->
{_DelNum, DelCols, _, NewBA} = split(N, State#state.buffer_after, U),
BBCols = cols(State#state.buffer_before, U),
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index bcc0d2b78b..fc1a4434fb 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -765,6 +765,10 @@ io_request({put_chars_sync, unicode, Chars, Reply}, TTY) ->
{Output, NewTTY} = prim_tty:handle_request(TTY, {putc, unicode:characters_to_binary(Chars)}),
{ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()),
{Reply, MonitorRef, NewTTY};
+io_request({put_chars_sync, latin1, Chars, Reply}, TTY) ->
+ {Output, NewTTY} = prim_tty:handle_request(TTY, {putc_raw, Chars}),
+ {ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()),
+ {Reply, MonitorRef, NewTTY};
io_request({put_expand, unicode, Chars}, TTY) ->
write(prim_tty:handle_request(TTY, {expand, unicode:characters_to_binary(Chars)}));
io_request({move_rel, N}, TTY) ->
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index bc96992ce2..0260b3251c 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -25,7 +25,7 @@
-export([setopts_getopts/1,unicode_options/1,unicode_options_gen/1,
binary_options/1, read_modes_gl/1,
read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1,
- unicode_prompt/1, shell_slogan/1]).
+ unicode_prompt/1, shell_slogan/1, raw_stdout/1, raw_stdout_isatty/1]).
-export([io_server_proxy/1,start_io_server_proxy/0, proxy_getall/1,
@@ -35,6 +35,8 @@
-export([uprompt/1, slogan/0, session_slogan/0]).
+-export([write_raw_to_stdout/0]).
+
%%-define(debug, true).
-ifdef(debug).
@@ -51,7 +53,7 @@ all() ->
[setopts_getopts, unicode_options, unicode_options_gen,
binary_options, read_modes_gl, read_modes_ogl,
broken_unicode, eof_on_pipe, unicode_prompt,
- shell_slogan].
+ shell_slogan, raw_stdout, raw_stdout_isatty].
groups() ->
[].
@@ -1091,6 +1093,45 @@ eof_on_pipe(Config) when is_list(Config) ->
{skipped,"Only on linux"}
end.
+raw_stdout(Config) when is_list(Config) ->
+ Cmd = lists:append(
+ [ct:get_progname(),
+ " -noshell -noinput",
+ " -pa ", filename:dirname(code:which(?MODULE)),
+ " -s ", atom_to_list(?MODULE), " write_raw_to_stdout"]),
+ ct:log("~p~n", [Cmd]),
+ Port = open_port({spawn, Cmd}, [stream, eof]),
+ Expected = lists:seq(0,255),
+ Expected = get_all_port_data(Port, []),
+ Port ! {self(), close},
+ ok.
+
+get_all_port_data(Port, Acc) ->
+ receive
+ {Port, {data, Data}} ->
+ get_all_port_data(Port, [Acc|Data]);
+ {Port, eof} ->
+ lists:flatten(Acc)
+ end.
+
+write_raw_to_stdout() ->
+ try
+ ok = io:setopts(standard_io, [{encoding, latin1}]),
+ ok = file:write(standard_io, lists:seq(0,255)),
+ halt(0)
+ catch
+ Class:Reason:StackTrace ->
+ io:format(standard_error, "~p~p~p", [Class, Reason, StackTrace]),
+ halt(17)
+ end.
+
+raw_stdout_isatty(Config) when is_list(Config) ->
+ rtnode:run(
+ [{putline,"io:setopts(group_leader(), [{encoding, latin1}])."},
+ {putline,"file:write(group_leader(),[90, 127, 128, 255, 131, 90, 10])."},%
+ {expect, "\\QZ^?\\200\\377\\203Z\\E"}
+ ],[]),
+ ok.
%%
%% Test I/O-server
%%