summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfrazze-jobb <frazze@erlang.org>2023-05-05 11:07:53 +0200
committerRickard Green <rickard@erlang.org>2023-05-05 18:44:44 +0200
commit338958e904bd3a7803a277b5e7af67985999b1f2 (patch)
tree6b8654715844f6015e0bb5eadfdf65116a56a1d4
parent36a02676a4c30d915518453a2664b8338fd46d85 (diff)
downloaderlang-338958e904bd3a7803a277b5e7af67985999b1f2.tar.gz
kernel: support sending raw byte data over stdout
After rewriting the shell, group.erl converts everything to Unicode. However, this is problematic if you want to send raw byte data over stdout which may contain Erlang terms converted to binary that you want to convert back to Erlang term after data transfer. If io:setopts(_, {encoding, latin1}) is set, group.erl will just send the data directly to user_drv.erl which will send the data to prim_tty.erl without converting it to Unicode.
-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
3 files changed, 33 insertions, 11 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) ->