From c5b60bcda55abd19a9d1546fb02b95fcfb08385f Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 9 Jun 2023 08:13:34 +0200
Subject: [PATCH 1/7] Revert "Merge pull request #6881 from
sile/fix-escript-binary-stdin-bug"
This reverts commit 4e668b984ef53a6942d857aea82ebccce375e61a, reversing
changes made to cfc86388f0536bb660728f1bc4784b90251e9a11.
---
lib/kernel/src/group.erl | 4 +---
lib/stdlib/src/io_lib.erl | 24 ++++++++++++++++--------
2 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index ca7251d7ecca..b104a710d03d 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -537,10 +537,8 @@ get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State0, LineCont, Encoding) ->
get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, Encoding) ->
try M:F(State, cast(Buf0, get(read_mode), Encoding), Encoding, Xa) of
- {stop,Result,eof} ->
- {ok,Result,eof};
{stop,Result,Rest} ->
- {ok,Result,append(Rest, [], Encoding)};
+ {ok, Result, Rest};
State1 ->
case get_chars_echo_off(Pbs, Drv, Shell) of
interrupted ->
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 5f45165968f2..7268fccc77bc 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -809,19 +809,23 @@ collect_chars(Tag, Data, N) ->
%% Now we are aware of encoding...
collect_chars(start, Data, unicode, N) when is_binary(Data), is_integer(N) ->
{Size,Npos} = count_and_find_utf8(Data,N),
- if Size >= N ->
+ if Size > N ->
{B1,B2} = split_binary(Data, Npos),
{stop,B1,B2};
Size < N ->
- {binary,[Data],N-Size}
+ {binary,[Data],N-Size};
+ true ->
+ {stop,Data,eof}
end;
collect_chars(start, Data, latin1, N) when is_binary(Data), is_integer(N) ->
Size = byte_size(Data),
- if Size >= N ->
+ if Size > N ->
{B1,B2} = split_binary(Data, N),
{stop,B1,B2};
Size < N ->
- {binary,[Data],N-Size}
+ {binary,[Data],N-Size};
+ true ->
+ {stop,Data,eof}
end;
collect_chars(start,Data,_,N) when is_list(Data), is_integer(N) ->
collect_chars_list([], N, Data);
@@ -831,19 +835,23 @@ collect_chars({binary,Stack,_N}, eof, _,_) ->
{stop,binrev(Stack),eof};
collect_chars({binary,Stack,N}, Data,unicode, _) when is_integer(N) ->
{Size,Npos} = count_and_find_utf8(Data,N),
- if Size >= N ->
+ if Size > N ->
{B1,B2} = split_binary(Data, Npos),
{stop,binrev(Stack, [B1]),B2};
Size < N ->
- {binary,[Data|Stack],N-Size}
+ {binary,[Data|Stack],N-Size};
+ true ->
+ {stop,binrev(Stack, [Data]),eof}
end;
collect_chars({binary,Stack,N}, Data,latin1, _) when is_integer(N) ->
Size = byte_size(Data),
- if Size >= N ->
+ if Size > N ->
{B1,B2} = split_binary(Data, N),
{stop,binrev(Stack, [B1]),B2};
Size < N ->
- {binary,[Data|Stack],N-Size}
+ {binary,[Data|Stack],N-Size};
+ true ->
+ {stop,binrev(Stack, [Data]),eof}
end;
collect_chars({list,Stack,N}, Data, _,_) when is_integer(N) ->
collect_chars_list(Stack, N, Data);
From c4a03418d2955ab00add62386132fe2bc88a28a6 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 9 Jun 2023 14:17:01 +0200
Subject: [PATCH 2/7] stdlib: Fix eof handling in io_lib:collect_chars
Various eof scenarios when group is using io_lib:collect_chars
was not handled correctly and thus when "oldshell" was changed
to be handled by group it broke some existing usages.
fixes #7368
fixes #6881
fixes #7286
---
lib/stdlib/src/io_lib.erl | 12 ++-
lib/stdlib/test/io_proto_SUITE.erl | 115 ++++++++++++++++++++++++++++-
2 files changed, 120 insertions(+), 7 deletions(-)
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 7268fccc77bc..87010361c050 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -815,7 +815,7 @@ collect_chars(start, Data, unicode, N) when is_binary(Data), is_integer(N) ->
Size < N ->
{binary,[Data],N-Size};
true ->
- {stop,Data,eof}
+ {stop,Data,<<>>}
end;
collect_chars(start, Data, latin1, N) when is_binary(Data), is_integer(N) ->
Size = byte_size(Data),
@@ -825,12 +825,14 @@ collect_chars(start, Data, latin1, N) when is_binary(Data), is_integer(N) ->
Size < N ->
{binary,[Data],N-Size};
true ->
- {stop,Data,eof}
+ {stop,Data,<<>>}
end;
collect_chars(start,Data,_,N) when is_list(Data), is_integer(N) ->
collect_chars_list([], N, Data);
collect_chars(start, eof, _,_) ->
{stop,eof,eof};
+collect_chars({binary,[<<>>],_N}, eof, _,_) ->
+ {stop,eof,eof};
collect_chars({binary,Stack,_N}, eof, _,_) ->
{stop,binrev(Stack),eof};
collect_chars({binary,Stack,N}, Data,unicode, _) when is_integer(N) ->
@@ -841,7 +843,7 @@ collect_chars({binary,Stack,N}, Data,unicode, _) when is_integer(N) ->
Size < N ->
{binary,[Data|Stack],N-Size};
true ->
- {stop,binrev(Stack, [Data]),eof}
+ {stop,binrev(Stack, [Data]),<<>>}
end;
collect_chars({binary,Stack,N}, Data,latin1, _) when is_integer(N) ->
Size = byte_size(Data),
@@ -851,7 +853,7 @@ collect_chars({binary,Stack,N}, Data,latin1, _) when is_integer(N) ->
Size < N ->
{binary,[Data|Stack],N-Size};
true ->
- {stop,binrev(Stack, [Data]),eof}
+ {stop,binrev(Stack, [Data]),<<>>}
end;
collect_chars({list,Stack,N}, Data, _,_) when is_integer(N) ->
collect_chars_list(Stack, N, Data);
@@ -879,6 +881,8 @@ collect_chars1(N, [], Stack) ->
collect_chars_list(Stack, 0, Data) ->
{stop,lists:reverse(Stack, []),Data};
+collect_chars_list([], _N, eof) ->
+ {stop,eof,eof};
collect_chars_list(Stack, _N, eof) ->
{stop,lists:reverse(Stack, []),eof};
collect_chars_list(Stack, N, []) ->
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index 368fdbdf0135..13457fe61caa 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -25,7 +25,10 @@
-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, raw_stdout/1, raw_stdout_isatty/1]).
+ unicode_prompt/1, shell_slogan/1, raw_stdout/1, raw_stdout_isatty/1,
+ file_read_stdin_binary_mode/1, file_read_stdin_list_mode/1,
+ io_get_chars_stdin_binary_mode/1, io_get_chars_stdin_list_mode/1
+ ]).
-export([io_server_proxy/1,start_io_server_proxy/0, proxy_getall/1,
@@ -35,7 +38,7 @@
-export([uprompt/1, slogan/0, session_slogan/0]).
--export([write_raw_to_stdout/0]).
+-export([write_raw_to_stdout/0, read_raw_from_stdin/1]).
%%-define(debug, true).
@@ -53,7 +56,13 @@ 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, raw_stdout, raw_stdout_isatty].
+ shell_slogan, raw_stdout, raw_stdout_isatty,
+ file_read_stdin_binary_mode,
+ file_read_stdin_list_mode,
+ io_get_chars_stdin_binary_mode,
+ io_get_chars_stdin_list_mode
+
+ ].
groups() ->
[].
@@ -269,6 +278,106 @@ setopts_getopts(Config) when is_list(Config) ->
],[],"",["-oldshell"]),
ok.
+%% Test that reading from stdin using file:read works when io is in binary mode
+file_read_stdin_binary_mode(_Config) ->
+ {ok, P, ErlPort} = start_stdin_node(fun() -> file:read(standard_io, 3) end, [binary]),
+
+ erlang:port_command(ErlPort, "abc"),
+ {ok, "got: <<\"abc\">>\n"} = gen_tcp:recv(P, 0),
+ erlang:port_command(ErlPort, "def"),
+ {ok, "got: <<\"def\">>\n"} = gen_tcp:recv(P, 0),
+ ErlPort ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P, 0),
+
+ ok.
+
+%% Test that reading from stdin using file:read works when io is in binary mode
+file_read_stdin_list_mode(_Config) ->
+ {ok, P, ErlPort} = start_stdin_node(fun() -> file:read(standard_io, 3) end, [list]),
+
+ erlang:port_command(ErlPort, "abc"),
+ {ok, "got: \"abc\"\n"} = gen_tcp:recv(P, 0),
+ erlang:port_command(ErlPort, "def"),
+ {ok, "got: \"def\"\n"} = gen_tcp:recv(P, 0),
+ ErlPort ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P, 0),
+
+ ok.
+
+%% Test that reading from stdin using file:read works when io is in binary mode
+io_get_chars_stdin_binary_mode(_Config) ->
+ {ok, P, ErlPort} = start_stdin_node(
+ fun() ->
+ case io:get_chars(standard_io, "", 1) of
+ eof -> eof;
+ Chars -> {ok, Chars}
+ end
+ end, [binary]),
+
+ erlang:port_command(ErlPort, "x\n"),
+ {ok, "got: <<\"x\">>\n"} = gen_tcp:recv(P, 0),
+ {ok, "got: <<\"\\n\">>\n"} = gen_tcp:recv(P, 0),
+ ErlPort ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P, 0),
+
+ ok.
+
+%% Test that reading from stdin using file:read works when io is in binary mode
+io_get_chars_stdin_list_mode(_Config) ->
+ {ok, P, ErlPort} = start_stdin_node(
+ fun() -> case io:get_chars(standard_io, "", 1) of
+ eof -> eof;
+ Chars -> {ok, Chars}
+ end
+ end, [list]),
+
+ erlang:port_command(ErlPort, "x\n"),
+ {ok, "got: \"x\"\n"} = gen_tcp:recv(P, 0),
+ {ok, "got: \"\\n\"\n"} = gen_tcp:recv(P, 0),
+ ErlPort ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P, 0),
+
+ ok.
+
+start_stdin_node(ReadFun, IoOptions) ->
+ {ok, L} = gen_tcp:listen(0,[{active, false},{packet,4}]),
+ {ok, Port} = inet:port(L),
+ Cmd = lists:append(
+ [ct:get_progname(),
+ " -noshell",
+ " -pa ", filename:dirname(code:which(?MODULE)),
+ " -s ", atom_to_list(?MODULE), " read_raw_from_stdin ", integer_to_list(Port)]),
+ ct:log("~p~n", [Cmd]),
+ ErlPort = open_port({spawn, Cmd}, [stream, eof]),
+ {ok, P} = gen_tcp:accept(L),
+ gen_tcp:send(P, term_to_binary(IoOptions)),
+ gen_tcp:send(P, term_to_binary(ReadFun)),
+ {ok, P, ErlPort}.
+
+read_raw_from_stdin([Port]) ->
+ try
+ dbg:tracer(file, "/home/eluklar/git/otp/trace.txt"),
+ dbg:p(whereis(user),[c,m]),
+ dbg:tpl(io_lib, x),
+ {ok, P} = gen_tcp:connect(localhost, list_to_integer(atom_to_list(Port)),
+ [binary, {packet, 4}, {active, false}]),
+ {ok, OptionsBin} = gen_tcp:recv(P, 0),
+ io:setopts(standard_io, binary_to_term(OptionsBin)),
+ {ok, ReadFunBin} = gen_tcp:recv(P, 0),
+ read_raw_from_stdin(binary_to_term(ReadFunBin), P)
+ catch E:R:ST ->
+ io:format(standard_error, "~p ~p",[Port,{E,R,ST}])
+ end.
+read_raw_from_stdin(ReadFun, P) ->
+ case ReadFun() of
+ eof ->
+ gen_tcp:send(P, "got: eof"),
+ init:stop();
+ {ok, Char} ->
+ gen_tcp:send(P, unicode:characters_to_binary(
+ io_lib:format("got: ~p\n",[Char]))),
+ read_raw_from_stdin(ReadFun, P)
+ end.
get_lc_ctype() ->
case {os:type(),os:version()} of
From 538bac474e3e9e97e84361ebcf476b91296cd870 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Wed, 14 Jun 2023 14:28:17 +0200
Subject: [PATCH 3/7] kernel: group:edit_line with echo needs to handle
binaries
fixes #6881
---
lib/kernel/src/group.erl | 9 ++++++---
lib/stdlib/test/io_proto_SUITE.erl | 31 ++++++++++++++++++++++++------
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index b104a710d03d..110bd58756e0 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -497,9 +497,12 @@ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, LineCont0, Encoding) ->
true ->
get_line(Buf0, Pbs, LineCont0, Drv, Shell, Encoding);
false ->
- %% get_line_echo_off only deals with lists
- %% and does not need encoding...
- get_line_echo_off(Buf0, Pbs, Drv, Shell)
+ %% get_line_echo_off only deals with lists,
+ %% so convert to list before calling it.
+ get_line_echo_off(
+ if Buf0 =:= eof -> eof;
+ true -> unicode:characters_to_list(Buf0, Encoding)
+ end, Pbs, Drv, Shell)
end,
case Result of
{done,LineCont1,Buf} ->
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index 13457fe61caa..5874b812400c 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -27,7 +27,8 @@
read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1,
unicode_prompt/1, shell_slogan/1, raw_stdout/1, raw_stdout_isatty/1,
file_read_stdin_binary_mode/1, file_read_stdin_list_mode/1,
- io_get_chars_stdin_binary_mode/1, io_get_chars_stdin_list_mode/1
+ io_get_chars_stdin_binary_mode/1, io_get_chars_stdin_list_mode/1,
+ io_get_chars_file_read_stdin_binary_mode/1
]).
@@ -60,8 +61,8 @@ all() ->
file_read_stdin_binary_mode,
file_read_stdin_list_mode,
io_get_chars_stdin_binary_mode,
- io_get_chars_stdin_list_mode
-
+ io_get_chars_stdin_list_mode,
+ io_get_chars_file_read_stdin_binary_mode
].
groups() ->
@@ -339,6 +340,27 @@ io_get_chars_stdin_list_mode(_Config) ->
ok.
+%% Test that mixing io:get_chars and file:read works when stdin is in binary mode.
+io_get_chars_file_read_stdin_binary_mode(_Config) ->
+ {ok, P, ErlPort} = start_stdin_node(
+ fun() -> case file:read(standard_io, 1) of
+ eof -> eof;
+ {ok, Chars} ->
+ case io:get_line(standard_io, "") of
+ eof -> Chars;
+ Line ->
+ {ok, [Chars, Line]}
+ end
+ end
+ end, [binary]),
+
+ erlang:port_command(ErlPort, "1\n"),
+ {ok, "got: [<<\"1\">>,<<\"\\n\">>]\n"} = gen_tcp:recv(P, 0),
+ ErlPort ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P, 0),
+
+ ok.
+
start_stdin_node(ReadFun, IoOptions) ->
{ok, L} = gen_tcp:listen(0,[{active, false},{packet,4}]),
{ok, Port} = inet:port(L),
@@ -356,9 +378,6 @@ start_stdin_node(ReadFun, IoOptions) ->
read_raw_from_stdin([Port]) ->
try
- dbg:tracer(file, "/home/eluklar/git/otp/trace.txt"),
- dbg:p(whereis(user),[c,m]),
- dbg:tpl(io_lib, x),
{ok, P} = gen_tcp:connect(localhost, list_to_integer(atom_to_list(Port)),
[binary, {packet, 4}, {active, false}]),
{ok, OptionsBin} = gen_tcp:recv(P, 0),
From bf1916dbbecb74c8315c83ffabf412ee36aef6d4 Mon Sep 17 00:00:00 2001
From: frazze-jobb
Date: Wed, 7 Jun 2023 14:09:31 +0200
Subject: [PATCH 4/7] kernel: Support sending byte stream on standard in
As group now acts as the proxy when running "oldshell" or
"noshell" it needs to be able to read and write raw binaries.
Latin1 encoding allows all possible bytes, so by fixing latin1
we allow any bytes to be passed into and out of Erlang unmodified.
fixes #7230
---
lib/kernel/doc/src/kernel_app.xml | 20 ++++++++-
lib/kernel/src/group.erl | 72 ++++++++++++++++--------------
lib/kernel/src/prim_tty.erl | 23 +++++++---
lib/kernel/src/user_drv.erl | 5 +--
lib/stdlib/test/io_proto_SUITE.erl | 47 +++++++++++++++++--
5 files changed, 120 insertions(+), 47 deletions(-)
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 17edb810020a..2f023f3daeaf 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -614,7 +614,25 @@ MaxT = NetTickTime + NetTickTime / NetTickIntensity
-
+ standard_io_encoding = Encoding
+ -
+
Set whether bytes sent or received via standard_io should be interpreted as unicode or latin1.
+ By default input and output is interpreted as Unicode if it is supported on the host. With this flag
+ you may configure the encoding on startup.
+ This works similarly to io:setopts(standard_io, {encoding, Encoding})
+ but is applied before any bytes on standard_io may have been read.
+ Encoding is one of:
+
+ unicode
+ Configure standard_io to use unicode mode.
+ latin1
+ Configure standard_io to use latin1 mode.
+ _
+ Anything other than unicode or latin1 will be ignored and the system will
+ configure the encoding by itself, typically unicode on modern systems.
+
+
+
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index 110bd58756e0..89d402896c09 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -20,6 +20,11 @@
-module(group).
%% A group leader process for user io.
+%% This process receives input data from user_drv in this format
+%% {Drv,{data,unicode:charlist()}}
+%% It then keeps that data as unicode in its state and converts it
+%% to latin1/unicode on a per request basis. If any data is left after
+%% a request, that data is again kept as unicode.
-export([start/2, start/3, whereis_shell/0, server/4]).
@@ -108,6 +113,9 @@ start_shell1(Fun) ->
exit(Error) % let the group process crash
end.
+-spec server_loop(UserDrv :: pid(), Shell:: pid(),
+ Buffer :: unicode:chardata()) ->
+ no_return().
server_loop(Drv, Shell, Buf0) ->
receive
{io_request,From,ReplyAs,Req} when is_pid(From) ->
@@ -499,14 +507,12 @@ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, LineCont0, Encoding) ->
false ->
%% get_line_echo_off only deals with lists,
%% so convert to list before calling it.
- get_line_echo_off(
- if Buf0 =:= eof -> eof;
- true -> unicode:characters_to_list(Buf0, Encoding)
- end, Pbs, Drv, Shell)
+ get_line_echo_off(cast(Buf0, list, Encoding), Pbs, Drv, Shell)
end,
case Result of
{done,LineCont1,Buf} ->
- get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State, LineCont1, Encoding);
+ get_chars_apply(Pbs, M, F, Xa, Drv, Shell, append(Buf, [], Encoding),
+ State, LineCont1, Encoding);
interrupted ->
{error,{error,interrupted},[]};
@@ -541,7 +547,7 @@ get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State0, LineCont, Encoding) ->
get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, Encoding) ->
try M:F(State, cast(Buf0, get(read_mode), Encoding), Encoding, Xa) of
{stop,Result,Rest} ->
- {ok, Result, Rest};
+ {ok, Result, append(Rest,[],Encoding)};
State1 ->
case get_chars_echo_off(Pbs, Drv, Shell) of
interrupted ->
@@ -605,13 +611,12 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding)
send_drv_reqs(Drv, edlin:erase_line()),
{more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)),
send_drv_reqs(Drv, Nrs),
- get_line1(edlin:edit_line1(string:to_graphemes(lists:sublist(Lcs,
- 1,
- length(Lcs)-1)),
- Ncont),
- Drv,
- Shell,
- Ls, Encoding)
+ get_line1(
+ edlin:edit_line1(
+ string:to_graphemes(
+ lists:sublist(Lcs, 1, length(Lcs)-1)),
+ Ncont),
+ Drv, Shell, Ls, Encoding)
end;
get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding)
when Mode =:= none, Char =:= $\^N;
@@ -801,7 +806,8 @@ more_data(What, Cont0, Drv, Shell, Ls, Encoding) ->
send_drv_reqs(Drv, edlin:redraw_line(Cont0)),
more_data(What, Cont0, Drv, Shell, Ls, Encoding);
{Drv,{data,Cs}} ->
- get_line1(edlin:edit_line(Cs, Cont0), Drv, Shell, Ls, Encoding);
+ get_line1(edlin:edit_line(cast(Cs, list), Cont0),
+ Drv, Shell, Ls, Encoding);
{Drv,eof} ->
get_line1(edlin:edit_line(eof, Cont0), Drv, Shell, Ls, Encoding);
{io_request,From,ReplyAs,Req} when is_pid(From) ->
@@ -832,7 +838,7 @@ get_line_echo_off(Chars, Pbs, Drv, Shell) ->
get_line_echo_off1({Chars,[]}, Drv, Shell) ->
receive
{Drv,{data,Cs}} ->
- get_line_echo_off1(edit_line(Cs, Chars), Drv, Shell);
+ get_line_echo_off1(edit_line(cast(Cs, list), Chars), Drv, Shell);
{Drv,eof} ->
get_line_echo_off1(edit_line(eof, Chars), Drv, Shell);
{io_request,From,ReplyAs,Req} when is_pid(From) ->
@@ -861,7 +867,7 @@ get_chars_echo_off(Pbs, Drv, Shell) ->
get_chars_echo_off1(Drv, Shell) ->
receive
{Drv, {data, Cs}} ->
- Cs;
+ cast(Cs, list);
{Drv, eof} ->
eof;
{io_request,From,ReplyAs,Req} when is_pid(From) ->
@@ -1009,7 +1015,7 @@ get_password_line(Chars, Drv, Shell) ->
get_password1({Chars,[]}, Drv, Shell) ->
receive
{Drv,{data,Cs}} ->
- get_password1(edit_password(Cs,Chars),Drv,Shell);
+ get_password1(edit_password(Cs,cast(Chars,list)),Drv,Shell);
{io_request,From,ReplyAs,Req} when is_pid(From) ->
io_request(Req, From, ReplyAs, Drv, Shell, []), %WRONG!!!
%% I guess the reason the above line is wrong is that Buf is
@@ -1049,20 +1055,18 @@ edit_password([Char|Cs],Chars) ->
prompt_bytes(Prompt, Encoding) ->
lists:flatten(io_lib:format_prompt(Prompt, Encoding)).
-cast(L, binary,latin1) when is_list(L) ->
- list_to_binary(L);
-cast(L, list, latin1) when is_list(L) ->
- binary_to_list(list_to_binary(L)); %% Exception if not bytes
-cast(L, binary,unicode) when is_list(L) ->
- unicode:characters_to_binary(L,utf8);
-cast(Other, _, _) ->
- Other.
-
-append(B, L, latin1) when is_binary(B) ->
- binary_to_list(B)++L;
-append(B, L, unicode) when is_binary(B) ->
- unicode:characters_to_list(B,utf8)++L;
-append(L1, L2, _) when is_list(L1) ->
- L1++L2;
-append(_Eof, L, _) ->
- L.
+cast(Buf, Type) ->
+ cast(Buf, Type, utf8).
+cast(eof, _, _) ->
+ eof;
+cast(L, binary, ToEnc) ->
+ unicode:characters_to_binary(L, utf8, ToEnc);
+cast(L, list, _ToEnc) ->
+ unicode:characters_to_list(L, utf8).
+
+append(eof, [], _) ->
+ eof;
+append(eof, L, _) ->
+ L;
+append(B, L, FromEnc) ->
+ unicode:characters_to_list(B, FromEnc) ++ L.
diff --git a/lib/kernel/src/prim_tty.erl b/lib/kernel/src/prim_tty.erl
index a03e746cc99f..006bd8146c1c 100644
--- a/lib/kernel/src/prim_tty.erl
+++ b/lib/kernel/src/prim_tty.erl
@@ -218,7 +218,7 @@ init(UserOptions) when is_map(UserOptions) ->
{ok, TTY} = tty_create(),
%% Initialize the locale to see if we support utf-8 or not
- UnicodeMode =
+ UnicodeSupported =
case setlocale(TTY) of
primitive ->
lists:any(
@@ -228,6 +228,11 @@ init(UserOptions) when is_map(UserOptions) ->
UnicodeLocale when is_boolean(UnicodeLocale) ->
UnicodeLocale
end,
+ IOEncoding = application:get_env(kernel, standard_io_encoding, default),
+ UnicodeMode = if IOEncoding =:= latin1 -> false;
+ IOEncoding =:= unicode -> true;
+ true -> UnicodeSupported
+ end,
{ok, ANSI_RE_MP} = re:compile(?ANSI_REGEXP, [unicode]),
init_term(#state{ tty = TTY, unicode = UnicodeMode, options = Options, ansi_regexp = ANSI_RE_MP }).
init_term(State = #state{ tty = TTY, options = Options }) ->
@@ -252,7 +257,12 @@ init_term(State = #state{ tty = TTY, options = Options }) ->
ReaderState =
case {maps:get(input, Options), TTYState#state.reader} of
{true, undefined} ->
- {ok, Reader} = proc_lib:start_link(?MODULE, reader, [[State#state.tty, self()]]),
+ DefaultReaderEncoding = if State#state.unicode -> utf8;
+ not State#state.unicode -> latin1
+ end,
+ {ok, Reader} = proc_lib:start_link(
+ ?MODULE, reader,
+ [[State#state.tty, DefaultReaderEncoding, self()]]),
WriterState#state{ reader = Reader };
{true, _} ->
WriterState;
@@ -421,14 +431,15 @@ call(Pid, Msg) ->
{error, Reason}
end.
-reader([TTY, Parent]) ->
+reader([TTY, Encoding, Parent]) ->
register(user_drv_reader, self()),
ReaderRef = make_ref(),
SignalRef = make_ref(),
+
ok = tty_select(TTY, SignalRef, ReaderRef),
proc_lib:init_ack({ok, {self(), ReaderRef}}),
FromEnc = case os:type() of
- {unix, _} -> utf8;
+ {unix, _} -> Encoding;
{win32, _} ->
case isatty(stdin) of
true ->
@@ -436,7 +447,7 @@ reader([TTY, Parent]) ->
_ ->
%% When not reading from a console
%% the data read is utf8 encoded
- utf8
+ Encoding
end
end,
reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, <<>>).
@@ -486,7 +497,7 @@ reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc) ->
Alias ! {Alias, true}
end,
receive
- {Parent, set_unicode_state, true} -> ok
+ {Parent, set_unicode_state, _} -> ok
end,
Latin1Chars = unicode:characters_to_binary(Error, latin1, utf8),
{<>, <<>>, latin1};
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index 25ebcbdd681b..0bc27e76ee88 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -421,8 +421,7 @@ server({call, From}, {start_shell, _Args}, _State) ->
keep_state_and_data;
server(info, {ReadHandle,{data,UTF8Binary}}, State = #state{ read = ReadHandle })
when State#state.current_group =:= State#state.user ->
- State#state.current_group !
- {self(), {data, unicode:characters_to_list(UTF8Binary, utf8)}},
+ State#state.current_group ! {self(), {data,UTF8Binary}},
keep_state_and_data;
server(info, {ReadHandle,{data,UTF8Binary}}, State = #state{ read = ReadHandle }) ->
case contains_ctrl_g_or_ctrl_c(UTF8Binary) of
@@ -435,7 +434,7 @@ server(info, {ReadHandle,{data,UTF8Binary}}, State = #state{ read = ReadHandle }
keep_state_and_data;
none ->
State#state.current_group !
- {self(), {data, unicode:characters_to_list(UTF8Binary, utf8)}},
+ {self(), {data, UTF8Binary}},
keep_state_and_data
end;
server(info, {ReadHandle,eof}, State = #state{ read = ReadHandle }) ->
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index 5874b812400c..2e6ba632e0c0 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -28,7 +28,8 @@
unicode_prompt/1, shell_slogan/1, raw_stdout/1, raw_stdout_isatty/1,
file_read_stdin_binary_mode/1, file_read_stdin_list_mode/1,
io_get_chars_stdin_binary_mode/1, io_get_chars_stdin_list_mode/1,
- io_get_chars_file_read_stdin_binary_mode/1
+ io_get_chars_file_read_stdin_binary_mode/1,
+ file_read_stdin_latin1_mode/1
]).
@@ -62,7 +63,8 @@ all() ->
file_read_stdin_list_mode,
io_get_chars_stdin_binary_mode,
io_get_chars_stdin_list_mode,
- io_get_chars_file_read_stdin_binary_mode
+ io_get_chars_file_read_stdin_binary_mode,
+ file_read_stdin_latin1_mode
].
groups() ->
@@ -361,12 +363,47 @@ io_get_chars_file_read_stdin_binary_mode(_Config) ->
ok.
+%% Test that reading from stdin using file:read_line works when io is not utf8
+file_read_stdin_latin1_mode(_Config) ->
+ {ok, P, ErlPort} = start_stdin_node(
+ fun() -> file:read_line(standard_io) end,
+ [binary],
+ "-kernel standard_io_encoding latin1"),
+
+ %% Invalid utf8
+ erlang:port_command(ErlPort, <<192,128,10,192,128,10,192,128,10>>),
+
+ {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P, 0, 5000),
+ {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P, 0, 5000),
+ {ok, "got: <<192,128,10>>\n"} = gen_tcp:recv(P, 0, 5000),
+ ErlPort ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P, 0, 5000),
+
+ {ok, P2, ErlPort2} = start_stdin_node(
+ fun() -> file:read(standard_io, 5) end,
+ [binary],
+ "-kernel standard_io_encoding latin1"),
+
+ %% Valid utf8
+ erlang:port_command(ErlPort2, <<"duπaduπaduπa"/utf8>>),
+
+ {ok, "got: <<100,117,207,128,97>>\n"} = gen_tcp:recv(P2, 0, 5000),
+ {ok, "got: <<100,117,207,128,97>>\n"} = gen_tcp:recv(P2, 0, 5000),
+ {ok, "got: <<100,117,207,128,97>>\n"} = gen_tcp:recv(P2, 0, 5000),
+ ErlPort2 ! {self(), close},
+ {ok, "got: eof"} = gen_tcp:recv(P2, 0, 5000),
+
+ ok.
+
start_stdin_node(ReadFun, IoOptions) ->
+ start_stdin_node(ReadFun, IoOptions, "").
+start_stdin_node(ReadFun, IoOptions, ExtraArgs) ->
{ok, L} = gen_tcp:listen(0,[{active, false},{packet,4}]),
{ok, Port} = inet:port(L),
Cmd = lists:append(
[ct:get_progname(),
- " -noshell",
+ " -noshell ",
+ ExtraArgs,
" -pa ", filename:dirname(code:which(?MODULE)),
" -s ", atom_to_list(?MODULE), " read_raw_from_stdin ", integer_to_list(Port)]),
ct:log("~p~n", [Cmd]),
@@ -383,6 +420,10 @@ read_raw_from_stdin([Port]) ->
{ok, OptionsBin} = gen_tcp:recv(P, 0),
io:setopts(standard_io, binary_to_term(OptionsBin)),
{ok, ReadFunBin} = gen_tcp:recv(P, 0),
+ spawn(fun() ->
+ gen_tcp:recv(P, 0),
+ init:stop("crash")
+ end),
read_raw_from_stdin(binary_to_term(ReadFunBin), P)
catch E:R:ST ->
io:format(standard_error, "~p ~p",[Port,{E,R,ST}])
From 13355a65101f4d6a029b89bb19a82914bf854d41 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 16 Jun 2023 10:46:46 +0200
Subject: [PATCH 5/7] kernel: Make group and prim_tty not get purged by cover
---
lib/kernel/src/group.erl | 14 ++++++++------
lib/kernel/src/prim_tty.erl | 22 ++++++++++++----------
2 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index 89d402896c09..53beae6e4fe1 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -28,6 +28,8 @@
-export([start/2, start/3, whereis_shell/0, server/4]).
+-export([server_loop/3]).
+
start(Drv, Shell) ->
start(Drv, Shell, []).
@@ -122,20 +124,20 @@ server_loop(Drv, Shell, Buf0) ->
%% This io_request may cause a transition to a couple of
%% selective receive loops elsewhere in this module.
Buf = io_request(Req, From, ReplyAs, Drv, Shell, Buf0),
- server_loop(Drv, Shell, Buf);
+ ?MODULE:server_loop(Drv, Shell, Buf);
{reply,{From,ReplyAs},Reply} ->
io_reply(From, ReplyAs, Reply),
- server_loop(Drv, Shell, Buf0);
+ ?MODULE:server_loop(Drv, Shell, Buf0);
{driver_id,ReplyTo} ->
ReplyTo ! {self(),driver_id,Drv},
- server_loop(Drv, Shell, Buf0);
+ ?MODULE:server_loop(Drv, Shell, Buf0);
{Drv, echo, Bool} ->
put(echo, Bool),
- server_loop(Drv, Shell, Buf0);
+ ?MODULE:server_loop(Drv, Shell, Buf0);
{'EXIT',Drv,interrupt} ->
%% Send interrupt to the shell.
exit_shell(interrupt),
- server_loop(Drv, Shell, Buf0);
+ ?MODULE:server_loop(Drv, Shell, Buf0);
{'EXIT',Drv,R} ->
exit(R);
{'EXIT',Shell,R} ->
@@ -147,7 +149,7 @@ server_loop(Drv, Shell, Buf0) ->
(tuple_size(NotDrvTuple) =/= 2) orelse
(element(1, NotDrvTuple) =/= Drv) ->
%% Ignore this unknown message.
- server_loop(Drv, Shell, Buf0)
+ ?MODULE:server_loop(Drv, Shell, Buf0)
end.
exit_shell(Reason) ->
diff --git a/lib/kernel/src/prim_tty.erl b/lib/kernel/src/prim_tty.erl
index 006bd8146c1c..1319b75e23f9 100644
--- a/lib/kernel/src/prim_tty.erl
+++ b/lib/kernel/src/prim_tty.erl
@@ -115,6 +115,8 @@
sizeof_wchar/0, tgetent_nif/1, tgetnum_nif/1, tgetflag_nif/1, tgetstr_nif/1,
tgoto_nif/2, tgoto_nif/3, tty_read_signal/2]).
+-export([reader_loop/6, writer_loop/2]).
+
%% Exported in order to remove "unused function" warning
-export([sizeof_wchar/0, wcswidth/1, tgoto/2, tgoto/3]).
@@ -459,20 +461,20 @@ reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc) ->
receive
{EnableAlias, enable} ->
EnableAlias ! {EnableAlias, ok},
- reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc)
+ ?MODULE:reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc)
end;
{select, TTY, SignalRef, ready_input} ->
{ok, Signal} = tty_read_signal(TTY, SignalRef),
Parent ! {ReaderRef,{signal,Signal}},
- reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc);
+ ?MODULE:reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc);
{Alias, {set_unicode_state, _}} when FromEnc =:= {utf16, little} ->
%% Ignore requests on windows
Alias ! {Alias, true},
- reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc);
+ ?MODULE:reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc);
{Alias, {set_unicode_state, Bool}} ->
Alias ! {Alias, FromEnc =/= latin1},
NewFromEnc = if Bool -> utf8; not Bool -> latin1 end,
- reader_loop(TTY, Parent, SignalRef, ReaderRef, NewFromEnc, Acc);
+ ?MODULE:reader_loop(TTY, Parent, SignalRef, ReaderRef, NewFromEnc, Acc);
{_Alias, stop} ->
ok;
{select, TTY, ReaderRef, ready_input} ->
@@ -482,7 +484,7 @@ reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc) ->
ok;
{ok, <<>>} ->
%% EAGAIN or EINTR
- reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc);
+ ?MODULE:reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc);
{ok, UtfXBytes} ->
{Bytes, NewAcc, NewFromEnc} =
@@ -507,7 +509,7 @@ reader_loop(TTY, Parent, SignalRef, ReaderRef, FromEnc, Acc) ->
{B, <<>>, FromEnc}
end,
Parent ! {ReaderRef, {data, Bytes}},
- reader_loop(TTY, Parent, SignalRef, ReaderRef, NewFromEnc, NewAcc)
+ ?MODULE:reader_loop(TTY, Parent, SignalRef, ReaderRef, NewFromEnc, NewAcc)
end
end.
@@ -529,18 +531,18 @@ write(#state{ writer = {WriterPid, _WriterRef}}, Chars, From) ->
writer_loop(TTY, WriterRef) ->
receive
{write, []} ->
- writer_loop(TTY, WriterRef);
+ ?MODULE:writer_loop(TTY, WriterRef);
{write, Chars} ->
_ = write_nif(TTY, Chars),
- writer_loop(TTY, WriterRef);
+ ?MODULE:writer_loop(TTY, WriterRef);
{write, From, []} ->
From ! {WriterRef, ok},
- writer_loop(TTY, WriterRef);
+ ?MODULE:writer_loop(TTY, WriterRef);
{write, From, Chars} ->
case write_nif(TTY, Chars) of
ok ->
From ! {WriterRef, ok},
- writer_loop(TTY, WriterRef);
+ ?MODULE:writer_loop(TTY, WriterRef);
{error, Reason} ->
exit(self(), Reason)
end
From 9a50bd82b1b6f0645388744de0b95e6620ac62c8 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Fri, 16 Jun 2023 10:47:34 +0200
Subject: [PATCH 6/7] tty: Add cover spec for tty
---
lib/kernel/test/Makefile | 2 +-
lib/kernel/test/tty.cover | 3 +++
lib/stdlib/test/Makefile | 2 +-
lib/stdlib/test/tty.cover | 1 +
4 files changed, 6 insertions(+), 2 deletions(-)
create mode 100644 lib/kernel/test/tty.cover
create mode 120000 lib/stdlib/test/tty.cover
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 0d88e3555e25..1d1c17776d92 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -150,7 +150,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
INSTALL_PROGS= $(TARGET_FILES)
EMAKEFILE=Emakefile
-COVERFILE=kernel.cover logger.cover
+COVERFILE=kernel.cover logger.cover tty.cover
# ----------------------------------------------------
# Release directory specification
diff --git a/lib/kernel/test/tty.cover b/lib/kernel/test/tty.cover
new file mode 100644
index 000000000000..cf4d26ea8e1a
--- /dev/null
+++ b/lib/kernel/test/tty.cover
@@ -0,0 +1,3 @@
+%% -*- erlang -*-
+{incl_mods,[prim_tty, user_drv, group, shell, edlin, edlin_expand, io_lib]}.
+
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 259715700448..98a7a03caa63 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -133,7 +133,7 @@ ERL_COMPILE_FLAGS := $(filter-out +deterministic,$(ERL_COMPILE_FLAGS))
EBIN = .
EMAKEFILE=Emakefile
-COVERFILE=stdlib.cover
+COVERFILE=stdlib.cover tty.cover
# ----------------------------------------------------
# Targets
diff --git a/lib/stdlib/test/tty.cover b/lib/stdlib/test/tty.cover
new file mode 120000
index 000000000000..841833897bae
--- /dev/null
+++ b/lib/stdlib/test/tty.cover
@@ -0,0 +1 @@
+../../../lib/kernel/test/tty.cover
\ No newline at end of file
From 2b1ce5dc22b3a07db72565036f0739aad034c9c9 Mon Sep 17 00:00:00 2001
From: Lukas Larsson
Date: Thu, 15 Jun 2023 15:22:47 +0200
Subject: [PATCH 7/7] Update primary bootstrap
---
bootstrap/lib/kernel/ebin/group.beam | Bin 15436 -> 16756 bytes
bootstrap/lib/kernel/ebin/prim_tty.beam | Bin 14492 -> 21672 bytes
bootstrap/lib/kernel/ebin/user_drv.beam | Bin 16884 -> 17616 bytes
bootstrap/lib/stdlib/ebin/io_lib.beam | Bin 14232 -> 14424 bytes
4 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam
index 73c53767c409d06f7a09e36deb39af3a6e93366f..1ee8fa4aac04027152a4c293b4d0af31146598e9 100644
GIT binary patch
literal 16756
zcmaic3w#_^_5V(0liW;mVVc>JK4IHkU|>6R!fs2_HtkKaX$rIunm{Q~l5}^IrcF1?
z?xqi(g#-xiYRh8;?1S>CfL2;j0TmRGpC}-pqJkhQqNv~#@x}jp?#v|V1OEANcV_NA
zbKduybMM@;=*(p`fj~oFV{^mOhT_?^fk63x0)fC&r9Junfm~^!*p)AqW%7Mp*`8n_
z)7P!`WQtm}E1Sv`iv9UQ#XvTl>F&*D(q)BAetjmd6>?o0vK@WB*|ou9ejrm(%y;EF
zG8=n~mAQOB-YRr-_jUECxq)J7CJnG)Z??C{CAEy@YgAu&=)>Jq}};j#UHQ-I;s^
zUd{DkuuuW=9qYUL1~Nf|K}XA1IC|r~_0qzHo3)mBf_Euj|cr^|^X1&-S~FtnKaV)4&Fe
z6*FmRkAZBlx33I5_w}x-fMGjQtGn`rvc9fjZ?>k~BX-2dKu2LyHWeHwcGrdouqy?0
zg^pr>$132=Zz_e1{dtL4;^C?OzP?P#!^(&^a*ayATRu?lh}`s$>napB^ykye(_^6=
zV)o~Xg>t+%ur6B&=KD7k$^lB9<3<%;VDcVHXN3$rhg{0PA)^$I^js*Dg`4$edqRbQ
zRfS@2aiEy#$Yy#Vbbq!0qjvZArS;V6OlmDTY;U@Q2$i`qGXLe$?ykN>?1tu$k9>hft9I&d_I$P
zRT{+X%c+_E?%=Ba;_9+OF%R)Di+k6V#A4FDJQ~tT$BnpSCe2_onqw(#9sI;)r6QAt
zYZ4FAmUL5tX_d_c;hkOM`g56V2Z8kG$GMk|bXT!U%jCNX8TncnX8pQcF+|`UeVK0f
z`9&S8;4f=4#o($;CRf&%$@UaiD^{tD4dpNd-BiMrdJuJ1XVzs3+6WglRfSAfKDD~z
zq5<&b;zrP-t}<86<3_Yivv?GkW^kq?i{L>4%d^Q5-DIR<2O5lAP%-mM3kXuhBeDbQ
zR$+2_17$8;a7}-2R--xK5($k?hqVyJon^r^)B|smY^Es4_EmaM-TjEP{!l(s80agO
z=Q9Wbh0M5grY{5MBQD3~GwFQS26-Q(uu?TjvLoByLB_0*HX>yQ>4#wg_O8cdmZ5==
zbWo)1=8b@d`QJ{>}JJw!g#h7Q4xr1rTVI-*x5~aQPQNe>N{GS<4y7A
zNJ*sGh#1YPp*F|Wh`7oSRjOm3VTYAYN0d}uC6rvH5F#EFk&rN=LQRNWhImAETFb-s
z%&S8!0g*5ss@4-?mFjeshlR4)$(09Moz3NeP7yQ&kZM(Gxt$ZLA@9OMXcKUIlB-UZI5zhlR?+Pj3H_8rH&%Dmd0=s1BRJ!Y>7s
zCxtdOB1+<-3SdVu@m4^23GjL*gV?dU@``HV8mO|lp^}_447bBr
z%0p_I&Zj6WRKq8zmAWp}U_}7B0hbfY!yk~+*`#uv>7;2X&t$1xwMsV>HbH2nitAAh
zn*te5uoYHa*=j#j9S$Z(d<6Qd2*CD1VF1}wU|o>p6GbRO)=sDoRokIx!eP_OZ8lzE
z6Bj0hnylfIlJrtg9Trga(LO839KcF=3@ejF64<9RomI6eY_h{<5JOPlluBDChTyKD
z16hd>D^WgGgusLza#-{cZDwG(3Mr;81bDQDPm6k7gu%tJJ{QLwz{T-nxR@rQ;KC#>
zfaPe1od7N@+#XYD+adxLgn(CJ;c9-OTE|at&23h9hWYU}pCR~kg-!SE7vrX(om9ik
zh=>>yV0<`$4coMdP?LzphxM?-P7HSPCU0tmKsv^3W`q?s!$(3s6XOv>n^ngnk-2DL
zU=wk5LZcCgG#Wbjhr?zDZGNQ)MnuSvB3Oh6d`DtD8qp@>7xO)Cz~Go_>?A4j2=FWq
zI4U`|WBk~-RukjLMWTSO0lXd5`OGocYrGeZl|aOd!%p^;b{vo(yvV+|*LOTgBaxr1
z3w;7?vfHS(4ejJ8rUmdPLSvB6_K=%%p|Icw&I
z6lPcRlVRo>buOCinH8bMe`ogk-D%|s4$pFEk{zkBH@q0Mn8SlnUrK;{&X
zNgPb(6iH@2$jq+hr+~~HkeM@<%$$gJN{r7LOJ>eQK3id@Oy;wROiS1$Q|qvLkg0_l
z>bNe#ZWJILt6Hs$ylesJ%&q40L1!N5%p0Kt?al)fevP1v2U47Q6Zu?)&7aKYjuofg
zVGBX04&p30Se!a3jsTg3)w}^@1jvXHGH^r@(dzI!Rva;rFH~5=WWI2$IE@Z#0GX3I
z71qRUyA!k9OIc(fBO;n2qOEC<0qr&hTlr~qeDQKs$jH06T7>x`n;z5%;XIvFFA2^mAJGRJm-xfogOa5AA!=qY;?SRnc!FikI8C5&K1`eYh2xJQaC;NVfyK)#|V|Hz+-*6=oAFw!wvb-)-a1dHap?vv5m8Xle}FT5Nnz)YMJt`4Q(MG)
zw8gv|XfIIM1tX5o0Y_M=u$7gqn?+Ml#J#c*s<@C$2mB5@%hkq(q>c0e)(aukh+tBt
z_+^LDM#pTvs!(Z$LFsS)DmxU!`_UAE4azLU{xz9XNXZ%&Jj_F
zBj=P!2D_;TZ8x*#d#>g|_QJz2bp{}EnLcac>
z!q)j9i$_4R^Hdo*&fq!iOx~}s{z|=-9EK{wa}obgoLq!(e~}tSey12IX_%@T3UXth
zR~!l*I1u_GUC{7)t4yiK>e3Q<_;RI;rq=
zgJUF-;G0yDh}ZLr6}Cy_;|jaD(FiwrwQw7haX#fE6n7#Kp+yM_JuFI~d7-dN#*mnM
z2;xg!#Fr`TQi=F7FfkVK1)q%g@&sRxWOD_S0-3ScSqYh!*$TTd#;;QIUX6bh4+xt|
z0&STQaoB|+>Zi328+2F)-e^PhFvJ6PxFQgtJR3nI>>P!<+F@OQY6sLc34SeB6LRTr
zt!{@2T3h0I`mn=R0q$(n2-nr}o1k+;ooDbHF(m}Q0rBQ~gT+^}>`#yM=e+(KEA=qy28U(*p&&+R1#?q^50lh4JFFX2mqO}WP^yns3=Zp|cgPqm
zn_-~UnDJQd^kNB64bwVo4Te7(<697tLUKtXSCMxB(Uvie7?MfRFw17Jz4TEEBvg#
zTy|H}w7xtK()X8#U&3U%Q?l_nu;G9WM_~@F*8OEv4w&owZ3S@yLqvtP0uV)T1k#^}ADqwc-o@`y*j*UG``A2S19;z8
zH^Np>s{8Jd%>}mpaO0mp}DRw~D17Tf%
zFrZeWoTE9gQ~vI9*e1N*ir4RvdX6mRyCe1dUWM%j+YyD`tK0VO2;6;AL~1;q=l3BV
z+^?|v01#K${kknsvxT+Ev`eEM)kMl@(pEI_PP^50ODx0^!oV`QeRl|eE1Dd3F`O_F
z;}1|?Y*6d@9)&%C`GQ%!2aA*4L4cj73Y0g&_F=u%VV3}YfzHP32$W&1!`)FxVmATv
zqB)8dQvINskZI`)4!abRb;6q-tPI$DjEGzgT^6*hO?CVsl+SM9HmJySgSX*o=AjsW
zSk>l>mM!k{!=hz}d-p|$T@IXGn-%sYO0tEZNQFdOR5T?-JShrr(kp^t>oZbOa~_B9s!*Hj!u&GYTRZ7bSy2Lq!wZN>y#?4*qDX!oEBT1PH)M2mk_N3;!M<
z9&y;_(_p`S4!aV(tO76lD?1P2CDJb0xr*2s#W_M4MB5`i-A;vl#bJZMmfE4PM=Lk)
zkY?K&5{0N}ONgeVh_{PKTBt=SnF_CdLQ3|vUHq#G`>JS)i$PkUh@v63wuuzHZwTxB
zSL^xL74|jh)LSF6`)cU_R%8^Bi~u+&EbJeAy^cQydmxJjWyO!ER036A1JKWjM4L!9
z2{k2xgCbfG?QxNojEm4#QBhdk4ux$-4hPGmKG-8aM&;eOhdqL
zR_=v>;b2H?jf%m9NF_yEyJ$*_cu_=#gt|=>c8|#UoRss)UHn@L`xex)TMRkv#Q
zQJ$O;s^?EB>`9RbirpcFJ+)vr|F)b4*p+~70eiia7!Sob6b?}gG1TUTo}5tFw-@fN
zG-%;3iPzqr||6N1thGKR@G23GN>1|riNC?=i^;GSJh)>7(Gs}l`
ztzKxWY3ch=b!RZqo-PhK>;}aC$)aVif$J1vs|xF!A*9WqZk>&`N^(P+NkedywF-NN
zxK0{kn>xG$3F}5O0p^K2KZ0%sdUk{}TNEQ=$Qa&>h2a8-dK1==Kh$&X9Bp=I6}J9l
zr1`E$rbK(2NW)3uLM@2Ipcry38QltcGyyP6o^#mEWUv2o*e$SE-xh^^uQIoV7Howv
zQ%!AmmApF5UnJKfkJ};@9h3nOlgAD2<$_JcK3Z>jJAYoar7qLb$pBYk40l4v&m2z3
z=SdL>0};q!p9Mf1KK}xIVIBX0HlKfAVc(bWAqV~cKsp=Uz2MDnP=~|P)D2+PGK*uNn^;s1Q^bFdfWObdV9%X+n|W7t*{@)_{-SH)#~f`%aOTgc4I`R%=xlg
z2)*L4TLHSbQ(>=Gwz``LZ6VPl!>^i5@E=70=&;-1z0>OXj}`VKJfjkJ*zItTqZRh!
z?ffUuQolD9X}8m1cOdayLpyd!a+Kt-j+LeZ_+xyBLTr}~MdbumYQZLVpA=Q#PvPG`
zaoFduYs_AA*qz|+qE?0dw2r^#I{a(Zoi_iw;D2l7KU3Jxyz)N<3;B!stug+)wtOA`
zU1~0x-I&tvX-tLp#rV(f(eg9->-+w!u%E~HTlZ)M{O+qjt^RstryIcrec>ZXVYHL1
zTOsRRQXblSyql&mr5gh|rAX<m&-^EXjB{{l7sFXWya@`SE#rw45y#(x2H
zY7m=%+sgwiOtYw6_0U2`*qPk{)YD1N+pTg>qajG;I@C@AZ4BzzPB7%ceHW>d6c>uS
ze&^}#7Zdp#3VU-B{k|3Bzmy`sy{|%7*e_%J*Y{`}@w>00L1Ayps7*l)F&jZ`BxV~$
zU+#M(gJjX&B)8AB)qy~;9GVAzI<}2|71B^aZvtbTQX%(}LTIlDTidkBaNj5J`YXiL
zXuHGi_cc;){b~een==(T0PkuHPP{t}h*=E_@9-tZ9Gisq4$1psq(o)m3qby7sy1
z+W)EQa@bc$V+W|~6Lj@1CK+^v-+dKTm_1b49DedVDz!r1fR9nFLZcPNS5c~xgS0$}
zhp)+sL%R|a?dza+^ma@0*q0te7JE!`aj3Wd4qG<}2-;Qr585FAL!SR$VZX2A?_uV@
zCucr3Qr=Uwq3!&=L7`pUIB2^ad40={#z9?e91OQ1Q(;JL(}rZu>Q}dxAq*+(y-$_u
zaVZs?UV8i!2bu62pJ2j2$U?#nhGdn5GNRBf2GgRcDB?pRvP~Gf{i*j&!cXCH58GxN2wCf_Wu&~*Q4tw@eOxPJ}
z)a36kkG6Kja7pOeRkhYQtQeC9u115A@UBts8j{ytC<5Dw0WkkvV2;uHScQ^WUIN3<
zf#I3@lhosu`Y7{dxu3u_sY0?=s6UYuI|2NE0Ja?VJraY87Fzn>jMatI-1E|?C0J_w
zRblUA@+I13|My9wb^HSa`VT13>+13R0|=o~o#kOj(p*hS@E?pt^MT$OkZyL1){tyg
zTiyacKHv*va?$dEOYqM=HiCSpT7YGj{EHHw5B3-2ScUynq>bSmCJH_nA2xRUjq+rS
zzt*O0p?v}sWwWiy<;@R?Drix1X$*!9$=w#!kXr|TACq3y?N%8|l&c$4c41zD{}yBU=2zHMLt42>_Oy^VZGB~zc@%NUmtH$g!L2YTU5BCoh=DM_X)^G
zG)b3k_zP-zbjTF%YX)Jt!~Zm}CEBt#czDhHr!v?sLLs2ylvjWwkqKbc9VetPc?0>ZNfukm2J^Y}q
zRtLm>R6|(D?yt8Lg?&6`G<@)=85kK2JQz;XyA-ANJM7oK{zZDfC<0qiF%^-9nSTSZ
zPog!jS`_*xw^6OaY~l7`KpO+^ghLL*5>JTF$T%wWQuERm>7O8Q;Sz$Bqr#*p9i>
zQYmh$rlq3V>Z-MlY;S0%czvW7ujxwhnywVDk2Dak9rg#WK8
zVl;;gqdAI}Kua3W)v=m136q6Xfdss&=K=)+BbfiKpY@RjhK=(oSpqTZ&m$*_jh<
za^uHcSjn}848DH_d)LUXs&bbHtH5^J0-zT=6|)?R0<42fhEkZW6%KoZt{Ms@x{h<$
z-{@NDu)kvkY;uP^wK%GnN1#Yp480ubuzxIWS4^x}Kg2r90m|{1tWZ^uChQnygqn8P
zKcUdG5P}r5s@ghQt+S@d6_+)wx-)D|vaOJ?48?>mx+isF)-*c0VNHwBzN?y^;9H>t
z9`}*VLu&hW>lmu#9QH3ikR@dxYfR&$N7`0tZwpeFv|+UfzS1(L{hJPapiF6}4`(PD
zlR)?%m_&x}s2d2q?;rii5<(F~$c`X%y208E`8;B^fQ@xXAT--LN}FX(P|OJsEHW33
z4vCCCAtGu2*Zrv7=AJ*HERdv>;aTLUm{qOf+=n$WlEguPb!rtB@n*IEJl}nu2-QRq
zSnBsE!%<1PoK%7a%jK*HnD<
zCZu{t4&WTDfN2x0D#bi{vQ-s4>HuOex>@oGw2py4ke`Mf6I(mlT|zOZbGy?&Wv51E
z&4HMNb9u;LNPlKfP7FNI*Hf(8@M$050SCwV7(Ab|q|ce~x#Jb{c#wt9f$PRdz?cad`3cyGiR_U_*CbNrIvzHF
zNN5kK8M981{&u1~X9Rx}@V66Umir8UqvsRBbR;yvF)PU5pxxN0zs-cdS-!tnMs(EQ
z$iE`14S2oQFHT4?MoNsM1?d
z+nGm5Zz1N?(y%ofu90xeBk|^T+|I5H(}yvtxXd}#mVgT^bX{N}xj?;b)e7qr#XQ9~
zV9Z)5U0~sXE`Zf1Tp$#8Ox?Br7;?4#yPokEO5@Lk@#_?`4g_KRg}(6@9$3(_)KJA_1X1`=cQ&LAx(!uU!;c20UF}$bKY-@=cvl?)URqIJur!O})
zlZas9bovrY9BDmxT9U9DRKKSL9ZMbaD9F4+SIjdK)|rUQSO_WRnP{z!Nk>?BV(2Uc
z-&PoSm(`~ATgw!4nb7VbxHi%IE?wIlb0T1O1NLmc!oF8+2@r{M9CH%J?!(yf?bbOU
zaW4WElBzuU7_YU?Mct$}#jF*PmVmyw6$?s$G^uf7TQz{;+=R8l@W!zbiEb@VR9EOZ
z(Hx1>9y;DIS^_xsYAsjH^Bi+BDBcf>=Wn<0iR?g%b=FEa=gLT+*190BZx#(W7VQ$n
zsoN2v7bL8eaoYDBA-7VJGdyyTE)H_%E9QlcN#|rAfZudLvIrzYNXEX4)fsOIB&<$V
z&)LmJiT5I;B<68;#daBw&=-2M%Q2?{%N{Vj3V73snR3i&==lPAupK|5G0f&3@ZS>w
z>WqrA6)$J-S<^9bpqAOSRySPKh{UXJqh&8r3w>EIyX9{WF@od82Ph1bRy*b~p!6Up
z^}5G}iGRc-!*I+nuug$dv0OH=TqX^Xwt<*je2rsH$Ey!P__Z^wzUAuXmc6ysI+VcR
zU>)`+H!CKcC4or&in(qiGCAf9M93Oiz=lx%VH6m$ju|0j;G>@wt~gfin9(!v5!uW+
z=CK(1BA_m+w8QSg)QCFfahO`8JF`|E%S8H2Z02cQNud%adD+P^tDtIosSCuy)j&r~gb7yMeyd-E%5t(J|?~?<1f*Z~)~KL3wnO(^~ISUhh+mxs*4I
zr91%28xBW#=Ao1~I;I86`|!%9%CP^jAD{iqlaPn5^Xenpx&*9U?3l9vyC1NZASik@
z!8M201eaD@SHp#d+=MVh31QH-E*I8iig}qI)MM6=Ob9~VP=a0gX{QD~&!XxujP8dW*C=G|{?LF|VFP
zzt>cTTj^g(G=<>K@S6#+L&8nNwCD{w=4?0TU%NbXP|l~^b?s=*56RRs?3i<4v9Ey4
zb+y(le!982TKv$u5#j!N#k{`Ox&irtg8X%gc|*dw*}J_lVcj$m$F(g$f0G~8DIDB9
znjG-nEeUIQ1ehZ77RRJR(T{@iXJp{0g`*~rQfCJg^RtdgXQ021!L2y$htp%$t%|wL
zG3Qb*Omb_?x($gGcy7Z&V;c;-!n#A7VBM~mx6|=J$DDUYm?59u;Xchj!)7Qp9LJ>7
z$d3a9)&X|{gB!Z;ti;&}q)~ifGZ%o5IVibs9D9ncn0Gk=yzvB>x*Pvy`)wx-gXkz!ZtNKRY9+*sXiVqPtHIhbhiOHTOFv
zor!)5(msHb6_5`58~7I{HsY`v2(%UR?eq_OPFnB=kz54~YwxAK81W&jLkAF|kbe}`>@7Lp={-}QgnosxQG543?p5QM<
zy9|wJ5)YT7`S`EEJ;7XyHtgLu;7T$QjL)-we?9sL55eDnM*YP9jc7ito5tL4!#%+e
zpSOAU#1HioJo&)GXg>ZgdHp_JqDA<>>h;sRUqd7K2DHb}2oK#8&je5H8)yXM-xCbo
zH&cJ}M)K#txoG8RPf#EJ+wR@dhDMT?ire)ip~7r%Y#|Asakap$*h?z{bsNB6%GnsvcHZkhMT6O$*s^3FG$
z4==obXiLTP=ojM;rO$i+4fgU?Hw2Hk{<>EO?%dk^+|BRJ%ujpiyfr`B_e5~TPfwpX
zwEwQmRJ=bvv?KmXy&fmiPQL+a6sV<#+oadG|SYwT;zd-T3@mZ@UJSufqQ
ztE+I$>0RG`zH!Nhho}GO`^TR4{IV7AztViu>UVy+;Mwo(GheK~^p+3)W}0`u_}jnz
z=3Vo0ZQ_ZiXKUVCyYD-%eWmS$C!Yy_tFd9@YqcMJaQsL2H*6f(x97FLpPkvd^x6G&
z57+MhIB@N*tv3gj;vWt}*HZ`k@T;sY*`Q~#U90*s_}>9!x{3q%SF~%^G!%<@j2=G%
zqpmMxC45#7Tx_*m_2J%||7kw{jn`i|@AdzzSrcgAl%sh+7ma+P;+T&E3Y-QKbHMAp8x;=
literal 15436
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
b&~@GJ9)|zRL-TS+aLqZ&;ll-3k>h^=OGl!d
diff --git a/bootstrap/lib/kernel/ebin/user_drv.beam b/bootstrap/lib/kernel/ebin/user_drv.beam
index 6ddb0fd0ba16313ec8c47fe84e995facb9133e5c..cd65cfc9af79c7a046e9b068160090c211bc5985 100644
GIT binary patch
delta 7683
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