aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r--lib/stdlib/src/binary.erl4
-rw-r--r--lib/stdlib/src/c.erl22
-rw-r--r--lib/stdlib/src/epp.erl2
-rw-r--r--lib/stdlib/src/erl_internal.erl7
-rw-r--r--lib/stdlib/src/erl_lint.erl6
-rw-r--r--lib/stdlib/src/erl_pp.erl63
-rw-r--r--lib/stdlib/src/filelib.erl224
-rw-r--r--lib/stdlib/src/filename.erl72
-rw-r--r--lib/stdlib/src/io.erl7
-rw-r--r--lib/stdlib/src/io_lib.erl48
-rw-r--r--lib/stdlib/src/io_lib_format.erl86
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl159
-rw-r--r--lib/stdlib/src/otp_internal.erl2
-rw-r--r--lib/stdlib/src/qlc.erl2
-rw-r--r--lib/stdlib/src/shell.erl52
15 files changed, 400 insertions, 356 deletions
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index 41b6ab1d5f..1fb241fd1d 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -58,7 +58,7 @@ bin_to_list(_, _) ->
-spec bin_to_list(Subject, Pos, Len) -> [byte()] when
Subject :: binary(),
Pos :: non_neg_integer(),
- Len :: non_neg_integer().
+ Len :: integer().
bin_to_list(_, _, _) ->
erlang:nif_error(undef).
@@ -186,7 +186,7 @@ part(_, _) ->
-spec part(Subject, Pos, Len) -> binary() when
Subject :: binary(),
Pos :: non_neg_integer(),
- Len :: non_neg_integer().
+ Len :: integer().
part(_, _, _) ->
erlang:nif_error(undef).
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 535f2d5174..91d317489c 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -512,7 +512,7 @@ m(M) ->
print_object_file(Mod) ->
case code:is_loaded(Mod) of
{file,File} ->
- format("Object file: ~s\n", [File]);
+ format("Object file: ~ts\n", [File]);
_ ->
ignore
end.
@@ -685,7 +685,7 @@ portformat(Name, Id, Cmd) ->
pwd() ->
case file:get_cwd() of
{ok, Str} ->
- ok = io:format("~ts\n", [fixup_one_bin(Str)]);
+ ok = io:format("~ts\n", [Str]);
{error, _} ->
ok = io:format("Cannot determine current directory\n")
end.
@@ -712,27 +712,11 @@ ls() ->
ls(Dir) ->
case file:list_dir(Dir) of
{ok, Entries} ->
- ls_print(sort(fixup_bin(Entries)));
+ ls_print(sort(Entries));
{error,_E} ->
format("Invalid directory\n")
end.
-fixup_one_bin(X) when is_binary(X) ->
- L = binary_to_list(X),
- [ if
- El > 127 ->
- $?;
- true ->
- El
- end || El <- L];
-fixup_one_bin(X) ->
- X.
-fixup_bin([H|T]) ->
- [fixup_one_bin(H) | fixup_bin(T)];
-fixup_bin([]) ->
- [].
-
-
ls_print([]) -> ok;
ls_print(L) ->
Width = min([max(lengths(L, [])), 40]) + 5,
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 1bb3b95ae2..0a1caa7178 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -614,7 +614,7 @@ enter_file_reply(From, Name, Location, AtLocation) ->
%% Flatten filename to a string. Must be a valid filename.
-file_name([C | T]) when is_integer(C), C > 0, C =< 255 ->
+file_name([C | T]) when is_integer(C), C > 0 ->
[C | file_name(T)];
file_name([H|T]) ->
file_name(H) ++ file_name(T);
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index 254384e877..378e629ac9 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -254,6 +254,9 @@ bif(binary_part, 2) -> true;
bif(binary_part, 3) -> true;
bif(binary_to_atom, 2) -> true;
bif(binary_to_existing_atom, 2) -> true;
+bif(binary_to_integer, 1) -> true;
+bif(binary_to_integer, 2) -> true;
+bif(binary_to_float, 1) -> true;
bif(binary_to_list, 1) -> true;
bif(binary_to_list, 3) -> true;
bif(binary_to_term, 1) -> true;
@@ -279,6 +282,8 @@ bif(exit, 2) -> true;
bif(float, 1) -> true;
bif(float_to_list, 1) -> true;
bif(float_to_list, 2) -> true;
+bif(float_to_binary, 1) -> true;
+bif(float_to_binary, 2) -> true;
bif(garbage_collect, 0) -> true;
bif(garbage_collect, 1) -> true;
bif(get, 0) -> true;
@@ -290,6 +295,8 @@ bif(halt, 0) -> true;
bif(halt, 1) -> true;
bif(halt, 2) -> true;
bif(hd, 1) -> true;
+bif(integer_to_binary, 1) -> true;
+bif(integer_to_binary, 2) -> true;
bif(integer_to_list, 1) -> true;
bif(integer_to_list, 2) -> true;
bif(iolist_size, 1) -> true;
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 12505b33d1..68a8534f15 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -3483,6 +3483,12 @@ extract_sequence(4, [$t, $P | Fmt], Need) ->
extract_sequence(5, [$P|Fmt], Need);
extract_sequence(4, [$t, C | _Fmt], _Need) ->
{error,"invalid control ~t" ++ [C]};
+extract_sequence(4, [$l, $p | Fmt], Need) ->
+ extract_sequence(5, [$p|Fmt], Need);
+extract_sequence(4, [$l, $P | Fmt], Need) ->
+ extract_sequence(5, [$P|Fmt], Need);
+extract_sequence(4, [$l, C | _Fmt], _Need) ->
+ {error,"invalid control ~l" ++ [C]};
extract_sequence(4, Fmt, Need) ->
extract_sequence(5, Fmt, Need);
extract_sequence(5, [C|Fmt], Need0) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index a868867a81..7c7566e4ec 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -61,7 +61,8 @@ form(Thing) ->
Options :: options()).
form(Thing, Options) ->
- frmt(lform(Thing, options(Options)), state(Options)).
+ State = state(Options),
+ frmt(lform(Thing, options(Options), State), State).
-spec(attribute(Attribute) -> io_lib:chars() when
Attribute :: erl_parse:abstract_form()).
@@ -74,7 +75,8 @@ attribute(Thing) ->
Options :: options()).
attribute(Thing, Options) ->
- frmt(lattribute(Thing, options(Options)), state(Options)).
+ State = state(Options),
+ frmt(lattribute(Thing, options(Options), State), State).
-spec(function(Function) -> io_lib:chars() when
Function :: erl_parse:abstract_form()).
@@ -193,47 +195,47 @@ encoding(Options) ->
unicode -> unicode
end.
-lform({attribute,Line,Name,Arg}, Opts) ->
- lattribute({attribute,Line,Name,Arg}, Opts);
-lform({function,Line,Name,Arity,Clauses}, Opts) ->
+lform({attribute,Line,Name,Arg}, Opts, State) ->
+ lattribute({attribute,Line,Name,Arg}, Opts, State);
+lform({function,Line,Name,Arity,Clauses}, Opts, _State) ->
lfunction({function,Line,Name,Arity,Clauses}, Opts);
-lform({rule,Line,Name,Arity,Clauses}, Opts) ->
+lform({rule,Line,Name,Arity,Clauses}, Opts, _State) ->
lrule({rule,Line,Name,Arity,Clauses}, Opts);
%% These are specials to make it easier for the compiler.
-lform({error,E}, _Opts) ->
+lform({error,E}, _Opts, _State) ->
leaf(format("~p\n", [{error,E}]));
-lform({warning,W}, _Opts) ->
+lform({warning,W}, _Opts, _State) ->
leaf(format("~p\n", [{warning,W}]));
-lform({eof,_Line}, _Opts) ->
+lform({eof,_Line}, _Opts, _State) ->
$\n.
-lattribute({attribute,_Line,type,Type}, Opts) ->
+lattribute({attribute,_Line,type,Type}, Opts, _State) ->
[typeattr(type, Type, Opts),leaf(".\n")];
-lattribute({attribute,_Line,opaque,Type}, Opts) ->
+lattribute({attribute,_Line,opaque,Type}, Opts, _State) ->
[typeattr(opaque, Type, Opts),leaf(".\n")];
-lattribute({attribute,_Line,spec,Arg}, _Opts) ->
+lattribute({attribute,_Line,spec,Arg}, _Opts, _State) ->
[specattr(Arg),leaf(".\n")];
-lattribute({attribute,_Line,Name,Arg}, Opts) ->
- [lattribute(Name, Arg, Opts),leaf(".\n")].
+lattribute({attribute,_Line,Name,Arg}, Opts, State) ->
+ [lattribute(Name, Arg, Opts, State),leaf(".\n")].
-lattribute(module, {M,Vs}, _Opts) ->
+lattribute(module, {M,Vs}, _Opts, _State) ->
attr("module",[{var,0,pname(M)},
foldr(fun(V, C) -> {cons,0,{var,0,V},C}
end, {nil,0}, Vs)]);
-lattribute(module, M, _Opts) ->
+lattribute(module, M, _Opts, _State) ->
attr("module", [{var,0,pname(M)}]);
-lattribute(export, Falist, _Opts) ->
+lattribute(export, Falist, _Opts, _State) ->
call({var,0,"-export"}, [falist(Falist)], 0, none);
-lattribute(import, Name, _Opts) when is_list(Name) ->
+lattribute(import, Name, _Opts, _State) when is_list(Name) ->
attr("import", [{var,0,pname(Name)}]);
-lattribute(import, {From,Falist}, _Opts) ->
+lattribute(import, {From,Falist}, _Opts, _State) ->
attr("import",[{var,0,pname(From)},falist(Falist)]);
-lattribute(file, {Name,Line}, _Opts) ->
- attr("file", [{var,0,format("~p", [Name])},{integer,0,Line}]);
-lattribute(record, {Name,Is}, Opts) ->
+lattribute(file, {Name,Line}, _Opts, State) ->
+ attr("file", [{var,0,(State#pp.string_fun)(Name)},{integer,0,Line}]);
+lattribute(record, {Name,Is}, Opts, _State) ->
Nl = leaf(format("-record(~w,", [Name])),
[{first,Nl,record_fields(Is, Opts)},$)];
-lattribute(Name, Arg, #options{encoding = Encoding}) ->
+lattribute(Name, Arg, #options{encoding = Encoding}, _State) ->
attr(write(Name), [erl_parse:abstract(Arg, [{encoding,Encoding}])]).
typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
@@ -423,7 +425,7 @@ lexpr(E, Opts) ->
lexpr({var,_,V}, _, _) when is_integer(V) -> %Special hack for Robert
leaf(format("_~w", [V]));
-lexpr({var,_,V}, _, _) -> leaf(format("~s", [V]));
+lexpr({var,_,V}, _, _) -> leaf(format("~ts", [V]));
lexpr({char,_,C}, _, _) -> {char,C};
lexpr({integer,_,N}, _, _) -> leaf(write(N));
lexpr({float,_,F}, _, _) -> leaf(write(F));
@@ -799,7 +801,7 @@ maybe_paren(_P, _Prec, Expr) ->
Expr.
leaf(S) ->
- {leaf,iolist_size(S),S}.
+ {leaf,chars_size(S),S}.
%%% Do the formatting. Currently nothing fancy. Could probably have
%%% done it in one single pass.
@@ -1009,7 +1011,7 @@ incr(I, Incr) ->
I+Incr.
indentation(E, I) when I < 0 ->
- iolist_size(E);
+ chars_size(E);
indentation(E, I0) ->
I = io_lib_format:indentation(E, I0),
case has_nl(E) of
@@ -1064,6 +1066,15 @@ write_char(C, PP) ->
%% Utilities
%%
+chars_size([C | Es]) when is_integer(C) ->
+ 1 + chars_size(Es);
+chars_size([E | Es]) ->
+ chars_size(E) + chars_size(Es);
+chars_size([]) ->
+ 0;
+chars_size(B) when is_binary(B) ->
+ byte_size(B).
+
-define(N_SPACES, 30).
spacetab() ->
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index 318f3b87b8..7df72a93e5 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -19,16 +19,14 @@
-module(filelib).
%% File utilities.
-
-%% Avoid warning for local function error/1 clashing with autoimported BIF.
--compile({no_auto_import,[error/1]}).
--export([wildcard/1, wildcard/2, is_dir/1, is_file/1, is_regular/1,
- compile_wildcard/1]).
+-export([wildcard/1, wildcard/2, is_dir/1, is_file/1, is_regular/1]).
-export([fold_files/5, last_modified/1, file_size/1, ensure_dir/1]).
-
-export([wildcard/3, is_dir/2, is_file/2, is_regular/2]).
-export([fold_files/6, last_modified/2, file_size/2]).
+%% For debugging/testing.
+-export([compile_wildcard/1]).
+
-include_lib("kernel/include/file.hrl").
-define(HANDLE_ERROR(Expr),
@@ -37,7 +35,7 @@
catch
error:{badpattern,_}=UnUsUalVaRiAbLeNaMe ->
%% Get the stack backtrace correct.
- erlang:error(UnUsUalVaRiAbLeNaMe)
+ error(UnUsUalVaRiAbLeNaMe)
end).
-type filename() :: file:name().
@@ -48,19 +46,19 @@
-spec wildcard(Wildcard) -> [file:filename()] when
Wildcard :: filename() | dirname().
wildcard(Pattern) when is_list(Pattern) ->
- ?HANDLE_ERROR(do_wildcard(Pattern, file)).
+ ?HANDLE_ERROR(do_wildcard(Pattern, ".", file)).
-spec wildcard(Wildcard, Cwd) -> [file:filename()] when
Wildcard :: filename() | dirname(),
Cwd :: dirname().
-wildcard(Pattern, Cwd) when is_list(Pattern), (is_list(Cwd) or is_binary(Cwd)) ->
+wildcard(Pattern, Cwd) when is_list(Pattern), is_list(Cwd) ->
?HANDLE_ERROR(do_wildcard(Pattern, Cwd, file));
wildcard(Pattern, Mod) when is_list(Pattern), is_atom(Mod) ->
- ?HANDLE_ERROR(do_wildcard(Pattern, Mod)).
+ ?HANDLE_ERROR(do_wildcard(Pattern, ".", Mod)).
-spec wildcard(file:name(), file:name(), atom()) -> [file:filename()].
wildcard(Pattern, Cwd, Mod)
- when is_list(Pattern), (is_list(Cwd) or is_binary(Cwd)), is_atom(Mod) ->
+ when is_list(Pattern), is_list(Cwd), is_atom(Mod) ->
?HANDLE_ERROR(do_wildcard(Pattern, Cwd, Mod)).
-spec is_dir(Name) -> boolean() when
@@ -124,47 +122,6 @@ file_size(File, Mod) when is_atom(Mod) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-do_wildcard(Pattern, Mod) when is_list(Pattern) ->
- do_wildcard_comp(do_compile_wildcard(Pattern), Mod).
-
-do_wildcard_comp({compiled_wildcard,{exists,File}}, Mod) ->
- case eval_read_file_info(File, Mod) of
- {ok,_} -> [File];
- _ -> []
- end;
-do_wildcard_comp({compiled_wildcard,[cwd,Base|Rest]}, Mod) ->
- do_wildcard_1([Base], Rest, Mod);
-do_wildcard_comp({compiled_wildcard,[Base|Rest]}, Mod) ->
- do_wildcard_1([Base], Rest, Mod).
-
-do_wildcard(Pattern, Cwd, Mod) when is_list(Pattern), (is_list(Cwd) or is_binary(Cwd)) ->
- do_wildcard_comp(do_compile_wildcard(Pattern), Cwd, Mod).
-
-do_wildcard_comp({compiled_wildcard,{exists,File}}, Cwd, Mod) ->
- case eval_read_file_info(filename:absname(File, Cwd), Mod) of
- {ok,_} -> [File];
- _ -> []
- end;
-do_wildcard_comp({compiled_wildcard,[cwd|Rest0]}, Cwd0, Mod) ->
- case Rest0 of
- [current|Rest] -> ok;
- Rest -> ok
- end,
- {Cwd,PrefixLen} = case filename:join([Cwd0]) of
- Bin when is_binary(Bin) -> {Bin,byte_size(Bin)+1};
- Other -> {Other,length(Other)+1}
- end, %Slash away redundant slashes.
- [
- if
- is_binary(N) ->
- <<_:PrefixLen/binary,Res/binary>> = N,
- Res;
- true ->
- lists:nthtail(PrefixLen, N)
- end || N <- do_wildcard_1([Cwd], Rest, Mod)];
-do_wildcard_comp({compiled_wildcard,[Base|Rest]}, _Cwd, Mod) ->
- do_wildcard_1([Base], Rest, Mod).
-
do_is_dir(Dir, Mod) ->
case eval_read_file_info(Dir, Mod) of
{ok, #file_info{type=directory}} ->
@@ -293,8 +250,24 @@ ensure_dir(F) ->
%%% Pattern matching using a compiled wildcard.
%%%
-do_wildcard_1(Files, Pattern, Mod) ->
- do_wildcard_2(Files, Pattern, [], Mod).
+do_wildcard(Pattern, Cwd, Mod) ->
+ {Compiled,PrefixLen} = compile_wildcard(Pattern, Cwd),
+ Files0 = do_wildcard_1(Compiled, Mod),
+ Files = if
+ PrefixLen =:= 0 ->
+ Files0;
+ true ->
+ [lists:nthtail(PrefixLen, File) || File <- Files0]
+ end,
+ lists:sort(Files).
+
+do_wildcard_1({exists,File}, Mod) ->
+ case eval_read_file_info(File, Mod) of
+ {ok,_} -> [File];
+ _ -> []
+ end;
+do_wildcard_1([Base|Rest], Mod) ->
+ do_wildcard_2([Base], Rest, [], Mod).
do_wildcard_2([File|Rest], Pattern, Result, Mod) ->
do_wildcard_2(Rest, Pattern, do_wildcard_3(File, Pattern, Result, Mod), Mod);
@@ -302,12 +275,12 @@ do_wildcard_2([], _, Result, _Mod) ->
Result.
do_wildcard_3(Base, [[double_star]|Rest], Result, Mod) ->
- lists:sort(do_double_star(current, [Base], Rest, Result, Mod, true));
-do_wildcard_3(Base, [Pattern|Rest], Result, Mod) ->
- case do_list_dir(Base, Mod) of
- {ok, Files0} ->
- Files = lists:sort(Files0),
- Matches = wildcard_4(Pattern, Files, Base, []),
+ do_double_star(".", [Base], Rest, Result, Mod, true);
+do_wildcard_3(Base0, [Pattern|Rest], Result, Mod) ->
+ case do_list_dir(Base0, Mod) of
+ {ok, Files} ->
+ Base = prepare_base(Base0),
+ Matches = do_wildcard_4(Pattern, Base, Files),
do_wildcard_2(Matches, Rest, Result, Mod);
_ ->
Result
@@ -315,51 +288,50 @@ do_wildcard_3(Base, [Pattern|Rest], Result, Mod) ->
do_wildcard_3(Base, [], Result, _Mod) ->
[Base|Result].
-wildcard_4(Pattern, [File|Rest], Base, Result) when is_binary(File) ->
- case wildcard_5(Pattern, binary_to_list(File)) of
- true ->
- wildcard_4(Pattern, Rest, Base, [join(Base, File)|Result]);
+do_wildcard_4(Pattern, Base, Files) ->
+ case will_always_match(Pattern) of
false ->
- wildcard_4(Pattern, Rest, Base, Result)
- end;
-wildcard_4(Pattern, [File|Rest], Base, Result) ->
- case wildcard_5(Pattern, File) of
+ [Base++F || F <- Files, match_part(Pattern, F)];
true ->
- wildcard_4(Pattern, Rest, Base, [join(Base, File)|Result]);
- false ->
- wildcard_4(Pattern, Rest, Base, Result)
- end;
-wildcard_4(_Patt, [], _Base, Result) ->
- Result.
+ [Base++F || F <- Files]
+ end.
-wildcard_5([question|Rest1], [_|Rest2]) ->
- wildcard_5(Rest1, Rest2);
-wildcard_5([accept], _) ->
+match_part([question|Rest1], [_|Rest2]) ->
+ match_part(Rest1, Rest2);
+match_part([accept], _) ->
true;
-wildcard_5([double_star], _) ->
+match_part([double_star], _) ->
true;
-wildcard_5([star|Rest], File) ->
+match_part([star|Rest], File) ->
do_star(Rest, File);
-wildcard_5([{one_of, Ordset}|Rest], [C|File]) ->
- case ordsets:is_element(C, Ordset) of
- true -> wildcard_5(Rest, File);
- false -> false
- end;
-wildcard_5([{alt, Alts}], File) ->
+match_part([{one_of, Ordset}|Rest], [C|File]) ->
+ gb_sets:is_element(C, Ordset) andalso match_part(Rest, File);
+match_part([{alt, Alts}], File) ->
do_alt(Alts, File);
-wildcard_5([C|Rest1], [C|Rest2]) when is_integer(C) ->
- wildcard_5(Rest1, Rest2);
-wildcard_5([X|_], [Y|_]) when is_integer(X), is_integer(Y) ->
+match_part([C|Rest1], [C|Rest2]) when is_integer(C) ->
+ match_part(Rest1, Rest2);
+match_part([X|_], [Y|_]) when is_integer(X), is_integer(Y) ->
false;
-wildcard_5([], []) ->
+match_part([], []) ->
true;
-wildcard_5([], [_|_]) ->
+match_part([], [_|_]) ->
false;
-wildcard_5([_|_], []) ->
+match_part([_|_], []) ->
false.
+will_always_match([accept]) -> true;
+will_always_match(_) -> false.
+
+prepare_base(Base0) ->
+ Base1 = filename:join(Base0, "x"),
+ "x"++Base2 = lists:reverse(Base1),
+ lists:reverse(Base2).
+
do_double_star(Base, [H|T], Rest, Result, Mod, Root) ->
- Full = join(Base, H),
+ Full = case Root of
+ false -> filename:join(Base, H);
+ true -> H
+ end,
Result1 = case do_list_dir(Full, Mod) of
{ok, Files} ->
do_double_star(Full, Files, Rest, Result, Mod, false);
@@ -373,62 +345,64 @@ do_double_star(Base, [H|T], Rest, Result, Mod, Root) ->
do_double_star(_Base, [], _Rest, Result, _Mod, _Root) ->
Result.
-do_star(Pattern, [X|Rest]) ->
- case wildcard_5(Pattern, [X|Rest]) of
- true -> true;
- false -> do_star(Pattern, Rest)
- end;
+do_star(Pattern, [_|Rest]=File) ->
+ match_part(Pattern, File) orelse do_star(Pattern, Rest);
do_star(Pattern, []) ->
- wildcard_5(Pattern, []).
+ match_part(Pattern, []).
do_alt([Alt|Rest], File) ->
- case wildcard_5(Alt, File) of
- true -> true;
- false -> do_alt(Rest, File)
- end;
+ match_part(Alt, File) orelse do_alt(Rest, File);
do_alt([], _File) ->
false.
-do_list_dir(current, Mod) -> eval_list_dir(".", Mod);
do_list_dir(Dir, Mod) -> eval_list_dir(Dir, Mod).
-join(current, File) -> File;
-join(Base, File) -> filename:join(Base, File).
-
%%% Compiling a wildcard.
-compile_wildcard(Pattern) ->
- ?HANDLE_ERROR(do_compile_wildcard(Pattern)).
-
-do_compile_wildcard(Pattern) ->
- {compiled_wildcard,compile_wildcard_1(Pattern)}.
+%% Only for debugging.
+compile_wildcard(Pattern) when is_list(Pattern) ->
+ {compiled_wildcard,?HANDLE_ERROR(compile_wildcard(Pattern, "."))}.
-compile_wildcard_1(Pattern) ->
+compile_wildcard(Pattern, Cwd0) ->
[Root|Rest] = filename:split(Pattern),
case filename:pathtype(Root) of
relative ->
- case compile_wildcard_2([Root|Rest], current) of
- {exists,_}=Wc -> Wc;
- [_|_]=Wc -> [cwd|Wc]
- end;
+ Cwd = filename:join([Cwd0]),
+ compile_wildcard_2([Root|Rest], {cwd,Cwd});
_ ->
- compile_wildcard_2(Rest, [Root])
+ compile_wildcard_2(Rest, {root,0,Root})
end.
compile_wildcard_2([Part|Rest], Root) ->
case compile_part(Part) of
Part ->
- compile_wildcard_2(Rest, join(Root, Part));
+ compile_wildcard_2(Rest, compile_join(Root, Part));
Pattern ->
compile_wildcard_3(Rest, [Pattern,Root])
end;
-compile_wildcard_2([], Root) -> {exists,Root}.
+compile_wildcard_2([], {root,PrefixLen,Root}) ->
+ {{exists,Root},PrefixLen}.
compile_wildcard_3([Part|Rest], Result) ->
compile_wildcard_3(Rest, [compile_part(Part)|Result]);
compile_wildcard_3([], Result) ->
- lists:reverse(Result).
+ case lists:reverse(Result) of
+ [{root,PrefixLen,Root}|Compiled] ->
+ {[Root|Compiled],PrefixLen};
+ [{cwd,Root}|Compiled] ->
+ {[Root|Compiled],length(filename:join(Root, "x"))-1}
+ end.
+
+compile_join({cwd,"."}, File) ->
+ {root,0,File};
+compile_join({cwd,Cwd}, File0) ->
+ File = filename:join([File0]),
+ Root = filename:join(Cwd, File),
+ PrefixLen = length(Root) - length(File),
+ {root,PrefixLen,Root};
+compile_join({root,PrefixLen,Root}, File) ->
+ {root,PrefixLen,filename:join(Root, File)}.
compile_part(Part) ->
compile_part(Part, false, []).
@@ -437,7 +411,7 @@ compile_part_to_sep(Part) ->
compile_part(Part, true, []).
compile_part([], true, _) ->
- error(missing_delimiter);
+ badpattern(missing_delimiter);
compile_part([$,|Rest], true, Result) ->
{ok, $,, lists:reverse(Result), Rest};
compile_part([$}|Rest], true, Result) ->
@@ -473,8 +447,6 @@ compile_part([], _Upto, Result) ->
compile_charset([$]|Rest], Ordset) ->
compile_charset1(Rest, ordsets:add_element($], Ordset));
-compile_charset([$-|Rest], Ordset) ->
- compile_charset1(Rest, ordsets:add_element($-, Ordset));
compile_charset([], _Ordset) ->
error;
compile_charset(List, Ordset) ->
@@ -483,7 +455,7 @@ compile_charset(List, Ordset) ->
compile_charset1([Lower, $-, Upper|Rest], Ordset) when Lower =< Upper ->
compile_charset1(Rest, compile_range(Lower, Upper, Ordset));
compile_charset1([$]|Rest], Ordset) ->
- {ok, {one_of, Ordset}, Rest};
+ {ok, {one_of, gb_sets:from_ordset(Ordset)}, Rest};
compile_charset1([X|Rest], Ordset) ->
compile_charset1(Rest, ordsets:add_element(X, Ordset));
compile_charset1([], _Ordset) ->
@@ -509,8 +481,8 @@ compile_alt(Pattern, Result) ->
error
end.
-error(Reason) ->
- erlang:error({badpattern,Reason}).
+badpattern(Reason) ->
+ error({badpattern,Reason}).
eval_read_file_info(File, file) ->
file:read_file_info(File);
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index 0c50eb34e6..66e54ef221 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% 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
@@ -61,15 +61,15 @@
%% (for WIN32): absname("/") -> "D:/"
--spec absname(Filename) -> file:filename() when
- Filename :: file:name().
+-spec absname(Filename) -> file:filename_all() when
+ Filename :: file:name_all().
absname(Name) ->
{ok, Cwd} = file:get_cwd(),
absname(Name, Cwd).
--spec absname(Filename, Dir) -> file:filename() when
- Filename :: file:name(),
- Dir :: file:name().
+-spec absname(Filename, Dir) -> file:filename_all() when
+ Filename :: file:name_all(),
+ Dir :: file:name_all().
absname(Name, AbsBase) when is_binary(Name), is_list(AbsBase) ->
absname(Name,filename_string_to_binary(AbsBase));
absname(Name, AbsBase) when is_list(Name), is_binary(AbsBase) ->
@@ -122,9 +122,9 @@ absname_vr([[X, $:]|Name], _, _AbsBase) ->
%% This is just a join/2, but assumes that
%% AbsBase must be absolute and Name must be relative.
--spec absname_join(Dir, Filename) -> file:filename() when
- Dir :: file:name(),
- Filename :: file:name().
+-spec absname_join(Dir, Filename) -> file:filename_all() when
+ Dir :: file:name_all(),
+ Filename :: file:name_all().
absname_join(AbsBase, Name) ->
join(AbsBase, flatten(Name)).
@@ -136,8 +136,8 @@ absname_join(AbsBase, Name) ->
%% basename("/usr/foo/") -> "foo" (trailing slashes ignored)
%% basename("/") -> []
--spec basename(Filename) -> file:filename() when
- Filename :: file:name().
+-spec basename(Filename) -> file:filename_all() when
+ Filename :: file:name_all().
basename(Name) when is_binary(Name) ->
case os:type() of
{win32,_} ->
@@ -201,9 +201,9 @@ skip_prefix(Name, _) ->
%% rootname(basename("xxx.jam")) -> "xxx"
%% rootname(basename("xxx.erl")) -> "xxx"
--spec basename(Filename, Ext) -> file:filename() when
- Filename :: file:name(),
- Ext :: file:name().
+-spec basename(Filename, Ext) -> file:filename_all() when
+ Filename :: file:name_all(),
+ Ext :: file:name_all().
basename(Name, Ext) when is_binary(Name), is_list(Ext) ->
basename(Name,filename_string_to_binary(Ext));
basename(Name, Ext) when is_list(Name), is_binary(Ext) ->
@@ -251,8 +251,8 @@ basename([], _Ext, Tail, _DrvSep2) ->
%% Example: dirname("/usr/src/kalle.erl") -> "/usr/src",
%% dirname("kalle.erl") -> "."
--spec dirname(Filename) -> file:filename() when
- Filename :: file:name().
+-spec dirname(Filename) -> file:filename_all() when
+ Filename :: file:name_all().
dirname(Name) when is_binary(Name) ->
{Dsep,Drivesep} = separators(),
SList = case Dsep of
@@ -344,8 +344,8 @@ dirjoin1([H|T],Acc,Sep) ->
%%
%% On Windows: fn:dirname("\\usr\\src/kalle.erl") -> "/usr/src"
--spec extension(Filename) -> file:filename() when
- Filename :: file:name().
+-spec extension(Filename) -> file:filename_all() when
+ Filename :: file:name_all().
extension(Name) when is_binary(Name) ->
{Dsep,_} = separators(),
SList = case Dsep of
@@ -387,8 +387,8 @@ extension([], Result, _OsType) ->
%% Joins a list of filenames with directory separators.
--spec join(Components) -> file:filename() when
- Components :: [file:name()].
+-spec join(Components) -> file:filename_all() when
+ Components :: [file:name_all()].
join([Name1, Name2|Rest]) ->
join([join(Name1, Name2)|Rest]);
join([Name]) when is_list(Name) ->
@@ -400,9 +400,9 @@ join([Name]) when is_atom(Name) ->
%% Joins two filenames with directory separators.
--spec join(Name1, Name2) -> file:filename() when
- Name1 :: file:name(),
- Name2 :: file:name().
+-spec join(Name1, Name2) -> file:filename_all() when
+ Name1 :: file:name_all(),
+ Name2 :: file:name_all().
join(Name1, Name2) when is_list(Name1), is_list(Name2) ->
OsType = major_os_type(),
case pathtype(Name2) of
@@ -488,7 +488,7 @@ maybe_remove_dirsep(Name, _) ->
%% a given base directory, which is is assumed to be normalised
%% by a previous call to join/{1,2}.
--spec append(file:filename(), file:name()) -> file:filename().
+-spec append(file:filename_all(), file:name_all()) -> file:filename_all().
append(Dir, Name) when is_binary(Dir), is_binary(Name) ->
<<Dir/binary,$/:8,Name/binary>>;
append(Dir, Name) when is_binary(Dir) ->
@@ -511,7 +511,7 @@ append(Dir, Name) ->
%% Example: a:bar.erl, /temp/foo.erl
-spec pathtype(Path) -> 'absolute' | 'relative' | 'volumerelative' when
- Path :: file:name().
+ Path :: file:name_all().
pathtype(Atom) when is_atom(Atom) ->
pathtype(atom_to_list(Atom));
pathtype(Name) when is_list(Name) or is_binary(Name) ->
@@ -564,8 +564,8 @@ win32_pathtype(_) -> relative.
%% Examples: rootname("/jam.src/kalle") -> "/jam.src/kalle"
%% rootname("/jam.src/foo.erl") -> "/jam.src/foo"
--spec rootname(Filename) -> file:filename() when
- Filename :: file:name().
+-spec rootname(Filename) -> file:filename_all() when
+ Filename :: file:name_all().
rootname(Name) when is_binary(Name) ->
list_to_binary(rootname(binary_to_list(Name))); % No need to handle unicode, . is < 128
rootname(Name0) ->
@@ -594,9 +594,9 @@ rootname([], Root, _Ext, _OsType) ->
%% Examples: rootname("/jam.src/kalle.jam", ".erl") -> "/jam.src/kalle.jam"
%% rootname("/jam.src/foo.erl", ".erl") -> "/jam.src/foo"
--spec rootname(Filename, Ext) -> file:filename() when
- Filename :: file:name(),
- Ext :: file:name().
+-spec rootname(Filename, Ext) -> file:filename_all() when
+ Filename :: file:name_all(),
+ Ext :: file:name_all().
rootname(Name, Ext) when is_binary(Name), is_binary(Ext) ->
list_to_binary(rootname(binary_to_list(Name),binary_to_list(Ext)));
rootname(Name, Ext) when is_binary(Name) ->
@@ -623,8 +623,8 @@ rootname2([Char|Rest], Ext, Result) when is_integer(Char) ->
%% split("a:\\msdev\\include") -> ["a:/", "msdev", "include"]
-spec split(Filename) -> Components when
- Filename :: file:name(),
- Components :: [file:name()].
+ Filename :: file:name_all(),
+ Components :: [file:name_all()].
split(Name) when is_binary(Name) ->
case os:type() of
{win32, _} -> win32_splitb(Name);
@@ -717,8 +717,8 @@ split([], Comp, Components, OsType) ->
%% will be converted to backslashes. On all platforms, the
%% name will be normalized as done by join/1.
--spec nativename(Path) -> file:filename() when
- Path :: file:name().
+-spec nativename(Path) -> file:filename_all() when
+ Path :: file:name_all().
nativename(Name0) ->
Name = join([Name0]), %Normalize.
case os:type() of
@@ -921,8 +921,8 @@ major_os_type() ->
%% flatten(List)
%% Flatten a list, also accepting atoms.
--spec flatten(Filename) -> file:filename() when
- Filename :: file:name().
+-spec flatten(Filename) -> file:filename_all() when
+ Filename :: file:name_all().
flatten(Bin) when is_binary(Bin) ->
Bin;
flatten(List) ->
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index 3dddb0d6e7..c92e9e3ade 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -32,6 +32,8 @@
parse_erl_exprs/4,parse_erl_form/1,parse_erl_form/2,
parse_erl_form/3,parse_erl_form/4]).
-export([request/1,request/2,requests/1,requests/2]).
+%% Implemented in native code
+-export([printable_range/0]).
-export_type([device/0, format/0, server_no_data/0]).
@@ -66,6 +68,11 @@ o_request(Io, Request, Func) ->
Other
end.
+%% Request what the user considers printable characters
+-spec printable_range() -> 'unicode' | 'latin1'.
+printable_range() ->
+ erlang:nif_error(undefined).
+
%% Put chars takes mixed *unicode* list from R13 onwards.
-spec put_chars(CharData) -> 'ok' when
CharData :: unicode:chardata().
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index b7ec848e1e..a9b6d4131e 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -72,7 +72,7 @@
-export([quote_atom/2, char_list/1, latin1_char_list/1,
deep_char_list/1, deep_latin1_char_list/1,
- printable_list/1, printable_latin1_list/1]).
+ printable_list/1, printable_latin1_list/1, printable_unicode_list/1]).
%% Utilities for collecting characters.
-export([collect_chars/3, collect_chars/4,
@@ -533,27 +533,45 @@ printable_latin1_list(_) -> false. %Everything else is false
%% Return true if CharList is a list of printable characters, else
%% false. The notion of printable in Unicode terms is somewhat floating.
%% Everything that is not a control character and not invalid unicode
-%% will be considered printable.
+%% will be considered printable.
+%% What the user has noted as printable characters is what actually
+%% specifies when this function will return true. If the VM is started
+%% with +pc latin1, only the latin1 range will be deemed as printable
+%% if on the other hand +pc unicode is given, all characters in the Unicode
+%% character set are deemed printable. latin1 is default.
-spec printable_list(Term) -> boolean() when
Term :: term().
-printable_list([C|Cs]) when is_integer(C), C >= $\040, C =< $\176 ->
- printable_list(Cs);
-printable_list([C|Cs])
+printable_list(L) ->
+ %% There will be more alternatives returns from io:printable range
+ %% in the future. To not have a catch-all clause is deliberate.
+ case io:printable_range() of
+ latin1 ->
+ printable_latin1_list(L);
+ unicode ->
+ printable_unicode_list(L)
+ end.
+
+-spec printable_unicode_list(Term) -> boolean() when
+ Term :: term().
+
+printable_unicode_list([C|Cs]) when is_integer(C), C >= $\040, C =< $\176 ->
+ printable_unicode_list(Cs);
+printable_unicode_list([C|Cs])
when is_integer(C), C >= 16#A0, C < 16#D800;
is_integer(C), C > 16#DFFF, C < 16#FFFE;
is_integer(C), C > 16#FFFF, C =< 16#10FFFF ->
- printable_list(Cs);
-printable_list([$\n|Cs]) -> printable_list(Cs);
-printable_list([$\r|Cs]) -> printable_list(Cs);
-printable_list([$\t|Cs]) -> printable_list(Cs);
-printable_list([$\v|Cs]) -> printable_list(Cs);
-printable_list([$\b|Cs]) -> printable_list(Cs);
-printable_list([$\f|Cs]) -> printable_list(Cs);
-printable_list([$\e|Cs]) -> printable_list(Cs);
-printable_list([]) -> true;
-printable_list(_) -> false. %Everything else is false
+ printable_unicode_list(Cs);
+printable_unicode_list([$\n|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([$\r|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([$\t|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([$\v|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([$\b|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([$\f|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([$\e|Cs]) -> printable_unicode_list(Cs);
+printable_unicode_list([]) -> true;
+printable_unicode_list(_) -> false. %Everything else is false
%% List = nl()
%% Return a list of characters to generate a newline.
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 64d19ccf48..56e15a17ec 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -58,14 +58,22 @@ collect_cseq(Fmt0, Args0) ->
{P,Fmt2,Args2} = precision(Fmt1, Args1),
{Pad,Fmt3,Args3} = pad_char(Fmt2, Args2),
{Encoding,Fmt4,Args4} = encoding(Fmt3, Args3),
- {C,As,Fmt5,Args5} = collect_cc(Fmt4, Args4),
- {{C,As,F,Ad,P,Pad,Encoding},Fmt5,Args5}.
+ {Strings,Fmt5,Args5} = strings(Fmt4, Args4),
+ {C,As,Fmt6,Args6} = collect_cc(Fmt5, Args5),
+ {{C,As,F,Ad,P,Pad,Encoding,Strings},Fmt6,Args6}.
encoding([$t|Fmt],Args) ->
+ true = hd(Fmt) =/= $l,
{unicode,Fmt,Args};
encoding(Fmt,Args) ->
{latin1,Fmt,Args}.
+strings([$l|Fmt],Args) ->
+ true = hd(Fmt) =/= $t,
+ {false,Fmt,Args};
+strings(Fmt,Args) ->
+ {true,Fmt,Args}.
+
field_width([$-|Fmt0], Args0) ->
{F,Fmt,Args} = field_value(Fmt0, Args0),
field_width(-F, Fmt, Args);
@@ -128,8 +136,8 @@ collect_cc([$i|Fmt], [A|Args]) -> {$i,[A],Fmt,Args}.
pcount(Cs) -> pcount(Cs, 0).
-pcount([{$p,_As,_F,_Ad,_P,_Pad,_Enc}|Cs], Acc) -> pcount(Cs, Acc+1);
-pcount([{$P,_As,_F,_Ad,_P,_Pad,_Enc}|Cs], Acc) -> pcount(Cs, Acc+1);
+pcount([{$p,_As,_F,_Ad,_P,_Pad,_Enc,_Str}|Cs], Acc) -> pcount(Cs, Acc+1);
+pcount([{$P,_As,_F,_Ad,_P,_Pad,_Enc,_Str}|Cs], Acc) -> pcount(Cs, Acc+1);
pcount([_|Cs], Acc) -> pcount(Cs, Acc);
pcount([], Acc) -> Acc.
@@ -138,8 +146,8 @@ pcount([], Acc) -> Acc.
%% remaining and only calculate indentation when necessary. Must also
%% be smart when calculating indentation for characters in format.
-build([{C,As,F,Ad,P,Pad,Enc}|Cs], Pc0, I) ->
- S = control(C, As, F, Ad, P, Pad, Enc, I),
+build([{C,As,F,Ad,P,Pad,Enc,Str}|Cs], Pc0, I) ->
+ S = control(C, As, F, Ad, P, Pad, Enc, Str, I),
Pc1 = decr_pc(C, Pc0),
if
Pc1 > 0 -> [S|build(Cs, Pc1, indentation(S, I))];
@@ -171,59 +179,59 @@ indentation([], I) -> I.
%% This is the main dispatch function for the various formatting commands.
%% Field widths and precisions have already been calculated.
-control($w, [A], F, Adj, P, Pad, _Enc,_I) ->
+control($w, [A], F, Adj, P, Pad, _Enc, _Str, _I) ->
term(io_lib:write(A, -1), F, Adj, P, Pad);
-control($p, [A], F, Adj, P, Pad, Enc, I) ->
- print(A, -1, F, Adj, P, Pad, Enc, I);
-control($W, [A,Depth], F, Adj, P, Pad, _Enc, _I) when is_integer(Depth) ->
+control($p, [A], F, Adj, P, Pad, Enc, Str, I) ->
+ print(A, -1, F, Adj, P, Pad, Enc, Str, I);
+control($W, [A,Depth], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(Depth) ->
term(io_lib:write(A, Depth), F, Adj, P, Pad);
-control($P, [A,Depth], F, Adj, P, Pad, Enc, I) when is_integer(Depth) ->
- print(A, Depth, F, Adj, P, Pad, Enc, I);
-control($s, [A], F, Adj, P, Pad, _Enc, _I) when is_atom(A) ->
+control($P, [A,Depth], F, Adj, P, Pad, Enc, Str, I) when is_integer(Depth) ->
+ print(A, Depth, F, Adj, P, Pad, Enc, Str, I);
+control($s, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_atom(A) ->
string(atom_to_list(A), F, Adj, P, Pad);
-control($s, [L0], F, Adj, P, Pad, latin1, _I) ->
+control($s, [L0], F, Adj, P, Pad, latin1, _Str, _I) ->
L = iolist_to_chars(L0),
string(L, F, Adj, P, Pad);
-control($s, [L0], F, Adj, P, Pad, unicode, _I) ->
+control($s, [L0], F, Adj, P, Pad, unicode, _Str, _I) ->
L = cdata_to_chars(L0),
uniconv(string(L, F, Adj, P, Pad));
-control($e, [A], F, Adj, P, Pad, _Enc, _I) when is_float(A) ->
+control($e, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
fwrite_e(A, F, Adj, P, Pad);
-control($f, [A], F, Adj, P, Pad, _Enc, _I) when is_float(A) ->
+control($f, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
fwrite_f(A, F, Adj, P, Pad);
-control($g, [A], F, Adj, P, Pad, _Enc, _I) when is_float(A) ->
+control($g, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
fwrite_g(A, F, Adj, P, Pad);
-control($b, [A], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($b, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, true);
-control($B, [A], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($B, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, false);
-control($x, [A,Prefix], F, Adj, P, Pad, _Enc, _I) when is_integer(A),
+control($x, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A),
is_atom(Prefix) ->
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), true);
-control($x, [A,Prefix], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($x, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
true = io_lib:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, true);
-control($X, [A,Prefix], F, Adj, P, Pad, _Enc, _I) when is_integer(A),
+control($X, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A),
is_atom(Prefix) ->
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), false);
-control($X, [A,Prefix], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($X, [A,Prefix], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
true = io_lib:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, false);
-control($+, [A], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($+, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, true);
-control($#, [A], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($#, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, false);
-control($c, [A], F, Adj, P, Pad, unicode, _I) when is_integer(A) ->
+control($c, [A], F, Adj, P, Pad, unicode, _Str, _I) when is_integer(A) ->
char(A, F, Adj, P, Pad);
-control($c, [A], F, Adj, P, Pad, _Enc, _I) when is_integer(A) ->
+control($c, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(A) ->
char(A band 255, F, Adj, P, Pad);
-control($~, [], F, Adj, P, Pad, _Enc, _I) -> char($~, F, Adj, P, Pad);
-control($n, [], F, Adj, P, Pad, _Enc, _I) -> newline(F, Adj, P, Pad);
-control($i, [_A], _F, _Adj, _P, _Pad, _Enc, _I) -> [].
+control($~, [], F, Adj, P, Pad, _Enc, _Str, _I) -> char($~, F, Adj, P, Pad);
+control($n, [], F, Adj, P, Pad, _Enc, _Str, _I) -> newline(F, Adj, P, Pad);
+control($i, [_A], _F, _Adj, _P, _Pad, _Enc, _Str, _I) -> [].
-ifdef(UNICODE_AS_BINARIES).
uniconv(C) ->
@@ -259,12 +267,16 @@ term(T, F, Adj, P0, Pad) ->
%% Indentation)
%% Print a term.
-print(T, D, none, Adj, P, Pad, E, I) -> print(T, D, 80, Adj, P, Pad, E, I);
-print(T, D, F, Adj, none, Pad, E, I) -> print(T, D, F, Adj, I+1, Pad, E, I);
-print(T, D, F, right, P, _Pad, latin1, _I) ->
- io_lib_pretty:print(T, P, F, D);
-print(T, D, F, right, P, _Pad, Enc, _I) ->
- Options = [{column, P}, {line_length, F}, {depth, D}, {encoding, Enc}],
+print(T, D, none, Adj, P, Pad, E, Str, I) ->
+ print(T, D, 80, Adj, P, Pad, E, Str, I);
+print(T, D, F, Adj, none, Pad, E, Str, I) ->
+ print(T, D, F, Adj, I+1, Pad, E, Str, I);
+print(T, D, F, right, P, _Pad, Enc, Str, _I) ->
+ Options = [{column, P},
+ {line_length, F},
+ {depth, D},
+ {encoding, Enc},
+ {strings, Str}],
io_lib_pretty:print(T, Options).
%% fwrite_e(Float, Field, Adjust, Precision, PadChar)
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index b05db3d290..7637ad7a3d 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -56,6 +56,7 @@ print(Term) ->
| {depth, depth()}
| {max_chars, max_chars()}
| {record_print_fun, rec_print_fun()}
+ | {strings, boolean()}
| {encoding, latin1 | utf8 | unicode}.
-type options() :: [option()].
@@ -69,7 +70,8 @@ print(Term, Options) when is_list(Options) ->
M = proplists:get_value(max_chars, Options, -1),
RecDefFun = proplists:get_value(record_print_fun, Options, no_fun),
Encoding = proplists:get_value(encoding, Options, epp:default_encoding()),
- print(Term, Col, Ll, D, M, RecDefFun, Encoding);
+ Strings = proplists:get_value(strings, Options, true),
+ print(Term, Col, Ll, D, M, RecDefFun, Encoding, Strings);
print(Term, RecDefFun) ->
print(Term, -1, RecDefFun).
@@ -81,7 +83,7 @@ print(Term, Depth, RecDefFun) ->
-spec print(term(), column(), line_length(), depth()) -> chars().
print(Term, Col, Ll, D) ->
- print(Term, Col, Ll, D, _M=-1, no_fun, latin1).
+ print(Term, Col, Ll, D, _M=-1, no_fun, latin1, true).
-spec print(term(), column(), line_length(), depth(), rec_print_fun()) ->
chars().
@@ -92,15 +94,15 @@ print(Term, Col, Ll, D, RecDefFun) ->
rec_print_fun()) -> chars().
print(Term, Col, Ll, D, M, RecDefFun) ->
- print(Term, Col, Ll, D, M, RecDefFun, latin1).
-
-print(_, _, _, 0, _M, _RF, _Enc) -> "...";
-print(Term, Col, Ll, D, M, RecDefFun, Enc) when Col =< 0 ->
- print(Term, 1, Ll, D, M, RecDefFun, Enc);
-print(Term, Col, Ll, D, M0, RecDefFun, Enc) when is_tuple(Term);
- is_list(Term);
- is_bitstring(Term) ->
- If = {_S, Len} = print_length(Term, D, RecDefFun, Enc),
+ print(Term, Col, Ll, D, M, RecDefFun, latin1, true).
+
+print(_, _, _, 0, _M, _RF, _Enc, _Str) -> "...";
+print(Term, Col, Ll, D, M, RecDefFun, Enc, Str) when Col =< 0 ->
+ print(Term, 1, Ll, D, M, RecDefFun, Enc, Str);
+print(Term, Col, Ll, D, M0, RecDefFun, Enc, Str) when is_tuple(Term);
+ is_list(Term);
+ is_bitstring(Term) ->
+ If = {_S, Len} = print_length(Term, D, RecDefFun, Enc, Str),
M = max_cs(M0, Len),
if
Len < Ll - Col, Len =< M ->
@@ -111,7 +113,7 @@ print(Term, Col, Ll, D, M0, RecDefFun, Enc) when is_tuple(Term);
1),
pp(If, Col, Ll, M, TInd, indent(Col), 0, 0)
end;
-print(Term, _Col, _Ll, _D, _M, _RF, _Enc) ->
+print(Term, _Col, _Ll, _D, _M, _RF, _Enc, _Str) ->
io_lib:write(Term).
%%%
@@ -325,12 +327,12 @@ write_tail(E, S) ->
%% counted but need to be added later.
%% D =/= 0
-print_length([], _D, _RF, _Enc) ->
+print_length([], _D, _RF, _Enc, _Str) ->
{"[]", 2};
-print_length({}, _D, _RF, _Enc) ->
+print_length({}, _D, _RF, _Enc, _Str) ->
{"{}", 2};
-print_length(List, D, RF, Enc) when is_list(List) ->
- case printable_list(List, D, Enc) of
+print_length(List, D, RF, Enc, Str) when is_list(List) ->
+ case Str andalso printable_list(List, D, Enc) of
true ->
S = write_string(List, Enc),
{S, length(S)};
@@ -339,30 +341,30 @@ print_length(List, D, RF, Enc) when is_list(List) ->
% S = write_string(Prefix, Enc),
% {[S | "..."], 3 + length(S)};
false ->
- print_length_list(List, D, RF, Enc)
+ print_length_list(List, D, RF, Enc, Str)
end;
-print_length(Fun, _D, _RF, _Enc) when is_function(Fun) ->
+print_length(Fun, _D, _RF, _Enc, _Str) when is_function(Fun) ->
S = io_lib:write(Fun),
{S, iolist_size(S)};
-print_length(R, D, RF, Enc) when is_atom(element(1, R)),
- is_function(RF) ->
+print_length(R, D, RF, Enc, Str) when is_atom(element(1, R)),
+ is_function(RF) ->
case RF(element(1, R), tuple_size(R) - 1) of
no ->
- print_length_tuple(R, D, RF, Enc);
+ print_length_tuple(R, D, RF, Enc, Str);
RDefs ->
- print_length_record(R, D, RF, RDefs, Enc)
+ print_length_record(R, D, RF, RDefs, Enc, Str)
end;
-print_length(Tuple, D, RF, Enc) when is_tuple(Tuple) ->
- print_length_tuple(Tuple, D, RF, Enc);
-print_length(<<>>, _D, _RF, _Enc) ->
+print_length(Tuple, D, RF, Enc, Str) when is_tuple(Tuple) ->
+ print_length_tuple(Tuple, D, RF, Enc, Str);
+print_length(<<>>, _D, _RF, _Enc, _Str) ->
{"<<>>", 4};
-print_length(<<_/bitstring>>, 1, _RF, _Enc) ->
+print_length(<<_/bitstring>>, 1, _RF, _Enc, _Str) ->
{"<<...>>", 7};
-print_length(<<_/bitstring>>=Bin, D, _RF, Enc) ->
+print_length(<<_/bitstring>>=Bin, D, _RF, Enc, Str) ->
case bit_size(Bin) rem 8 of
0 ->
D1 = D - 1,
- case printable_bin(Bin, D1, Enc) of
+ case Str andalso printable_bin(Bin, D1, Enc) of
{true, List} when is_list(List) ->
S = io_lib:write_string(List, $"), %"
{[$<,$<,S,$>,$>], 4 + length(S)};
@@ -383,51 +385,53 @@ print_length(<<_/bitstring>>=Bin, D, _RF, Enc) ->
S = io_lib:write(Bin, D),
{{bin,S}, iolist_size(S)}
end;
-print_length(Term, _D, _RF, _Enc) ->
+print_length(Term, _D, _RF, _Enc, _Str) ->
S = io_lib:write(Term),
{S, lists:flatlength(S)}.
-print_length_tuple(_Tuple, 1, _RF, _Enc) ->
+print_length_tuple(_Tuple, 1, _RF, _Enc, _Str) ->
{"{...}", 5};
-print_length_tuple(Tuple, D, RF, Enc) ->
- L = print_length_list1(tuple_to_list(Tuple), D, RF, Enc),
+print_length_tuple(Tuple, D, RF, Enc, Str) ->
+ L = print_length_list1(tuple_to_list(Tuple), D, RF, Enc, Str),
IsTagged = is_atom(element(1, Tuple)) and (tuple_size(Tuple) > 1),
{{tuple,IsTagged,L}, list_length(L, 2)}.
-print_length_record(_Tuple, 1, _RF, _RDefs, _Enc) ->
+print_length_record(_Tuple, 1, _RF, _RDefs, _Enc, _Str) ->
{"{...}", 5};
-print_length_record(Tuple, D, RF, RDefs, Enc) ->
+print_length_record(Tuple, D, RF, RDefs, Enc, Str) ->
Name = [$# | io_lib:write_atom(element(1, Tuple))],
NameL = length(Name),
- L = print_length_fields(RDefs, D - 1, tl(tuple_to_list(Tuple)), RF, Enc),
+ Elements = tl(tuple_to_list(Tuple)),
+ L = print_length_fields(RDefs, D - 1, Elements, RF, Enc, Str),
{{record, [{Name,NameL} | L]}, list_length(L, NameL + 2)}.
-print_length_fields([], _D, [], _RF, _Enc) ->
+print_length_fields([], _D, [], _RF, _Enc, _Str) ->
[];
-print_length_fields(_, 1, _, _RF, _Enc) ->
+print_length_fields(_, 1, _, _RF, _Enc, _Str) ->
{dots, 3};
-print_length_fields([Def | Defs], D, [E | Es], RF, Enc) ->
- [print_length_field(Def, D - 1, E, RF, Enc) |
- print_length_fields(Defs, D - 1, Es, RF, Enc)].
+print_length_fields([Def | Defs], D, [E | Es], RF, Enc, Str) ->
+ [print_length_field(Def, D - 1, E, RF, Enc, Str) |
+ print_length_fields(Defs, D - 1, Es, RF, Enc, Str)].
-print_length_field(Def, D, E, RF, Enc) ->
+print_length_field(Def, D, E, RF, Enc, Str) ->
Name = io_lib:write_atom(Def),
- {S, L} = print_length(E, D, RF, Enc),
+ {S, L} = print_length(E, D, RF, Enc, Str),
NameL = length(Name) + 3,
{{field, Name, NameL, {S, L}}, NameL + L}.
-print_length_list(List, D, RF, Enc) ->
- L = print_length_list1(List, D, RF, Enc),
+print_length_list(List, D, RF, Enc, Str) ->
+ L = print_length_list1(List, D, RF, Enc, Str),
{{list, L}, list_length(L, 2)}.
-print_length_list1([], _D, _RF, _Enc) ->
+print_length_list1([], _D, _RF, _Enc, _Str) ->
[];
-print_length_list1(_, 1, _RF, _Enc) ->
+print_length_list1(_, 1, _RF, _Enc, _Str) ->
{dots, 3};
-print_length_list1([E | Es], D, RF, Enc) ->
- [print_length(E, D - 1, RF, Enc) | print_length_list1(Es, D - 1, RF, Enc)];
-print_length_list1(E, D, RF, Enc) ->
- print_length(E, D - 1, RF, Enc).
+print_length_list1([E | Es], D, RF, Enc, Str) ->
+ [print_length(E, D - 1, RF, Enc, Str) |
+ print_length_list1(Es, D - 1, RF, Enc, Str)];
+print_length_list1(E, D, RF, Enc, Str) ->
+ print_length(E, D - 1, RF, Enc, Str).
list_length([], Acc) ->
Acc;
@@ -481,13 +485,18 @@ printable_bin(Bin, Len, D, latin1) ->
false
end;
printable_bin(Bin, Len, D, _Uni) ->
- case printable_unicode(Bin, Len, []) of
- {_, <<>>, L} ->
- {byte_size(Bin) =:= length(L), L};
- {NC, Bin1, L} when D > 0, Len - NC >= D ->
- {byte_size(Bin)-byte_size(Bin1) =:= length(L), true, L};
- {_NC, _Bin, _L} ->
- false
+ case valid_utf8(Bin,Len) of
+ true ->
+ case printable_unicode(Bin, Len, [], io:printable_range()) of
+ {_, <<>>, L} ->
+ {byte_size(Bin) =:= length(L), L};
+ {NC, Bin1, L} when D > 0, Len - NC >= D ->
+ {byte_size(Bin)-byte_size(Bin1) =:= length(L), true, L};
+ {_NC, _Bin, _L} ->
+ false
+ end;
+ false ->
+ printable_bin(Bin, Len, D, latin1)
end.
printable_bin1(_Bin, _Start, 0) ->
@@ -518,24 +527,36 @@ printable_latin1_list([$\e | Cs], N) -> printable_latin1_list(Cs, N - 1);
printable_latin1_list([], _) -> all;
printable_latin1_list(_, N) -> N.
-printable_unicode(<<C/utf8, R/binary>>=Bin, I, L) when I > 0 ->
- case printable_char(C) of
+valid_utf8(<<>>,_) ->
+ true;
+valid_utf8(_,0) ->
+ true;
+valid_utf8(<<_/utf8, R/binary>>,N) ->
+ valid_utf8(R,N-1);
+valid_utf8(_,_) ->
+ false.
+
+printable_unicode(<<C/utf8, R/binary>>=Bin, I, L, Range) when I > 0 ->
+ case printable_char(C,Range) of
true ->
- printable_unicode(R, I - 1, [C | L]);
+ printable_unicode(R, I - 1, [C | L],Range);
false ->
{I, Bin, lists:reverse(L)}
end;
-printable_unicode(Bin, I, L) ->
+printable_unicode(Bin, I, L,_) ->
{I, Bin, lists:reverse(L)}.
-printable_char($\n) -> true;
-printable_char($\r) -> true;
-printable_char($\t) -> true;
-printable_char($\v) -> true;
-printable_char($\b) -> true;
-printable_char($\f) -> true;
-printable_char($\e) -> true;
-printable_char(C) ->
+printable_char($\n,_) -> true;
+printable_char($\r,_) -> true;
+printable_char($\t,_) -> true;
+printable_char($\v,_) -> true;
+printable_char($\b,_) -> true;
+printable_char($\f,_) -> true;
+printable_char($\e,_) -> true;
+printable_char(C,latin1) ->
+ C >= $\s andalso C =< $~ orelse
+ C >= 16#A0 andalso C =< 16#FF;
+printable_char(C,unicode) ->
C >= $\s andalso C =< $~ orelse
C >= 16#A0 andalso C < 16#D800 orelse
C > 16#DFFF andalso C < 16#FFFE orelse
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 9257953071..a4f4035c79 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -353,7 +353,7 @@ obsolete_1(inviso, _, _) ->
%% Added in R15B01.
obsolete_1(gs, _, _) ->
- {deprecated,"the gs application has been deprecated and will be removed in R16; use the wx application instead"};
+ {deprecated,"the gs application has been deprecated and will be removed in R17; use the wx application instead"};
obsolete_1(ssh, sign_data, 2) ->
{deprecated,"deprecated (will be removed in R16A); use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
"and public_key:sign/3 instead"};
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index 6a27cff589..48f6622565 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -3709,7 +3709,7 @@ maybe_error_logger(Name, Why) ->
Trimmer = fun(M, _F, _A) -> M =:= erl_eval end,
Formater = fun(Term, I) -> io_lib:print(Term, I, 80, -1) end,
X = lib:format_stacktrace(1, Stacktrace, Trimmer, Formater),
- error_logger:Name("qlc: temporary file was needed for ~w\n~s\n",
+ error_logger:Name("qlc: temporary file was needed for ~w\n~ts\n",
[Why, lists:flatten(X)]).
expand_stacktrace() ->
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index c94f052b24..96f3e5dd32 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -22,7 +22,7 @@
-export([whereis_evaluator/0, whereis_evaluator/1]).
-export([start_restricted/1, stop_restricted/0]).
-export([local_allowed/3, non_local_allowed/3]).
--export([prompt_func/1]).
+-export([prompt_func/1, strings/1]).
-define(LINEMAX, 30).
-define(CHAR_MAX, 60).
@@ -30,6 +30,7 @@
-define(DEF_RESULTS, 20).
-define(DEF_CATCH_EXCEPTION, false).
-define(DEF_PROMPT_FUNC, default).
+-define(DEF_STRINGS, true).
-define(RECORDS, shell_records).
@@ -128,7 +129,7 @@ start_restricted(RShMod) when is_atom(RShMod) ->
error_logger:error_report(
lists:flatten(
io_lib:fwrite(
- "Restricted shell module ~w not found: ~"++cs_p() ++"\n",
+ "Restricted shell module ~w not found: ~tp\n",
[RShMod,What]))),
Error
end.
@@ -213,8 +214,7 @@ server(StartSync) ->
ok;
{RShMod2,What2} ->
io:fwrite(
- ("Warning! Restricted shell module ~w not found: ~"
- ++cs_p()++".\n"
+ ("Warning! Restricted shell module ~w not found: ~tp.\n"
"Only the commands q() and init:stop() will be allowed!\n"),
[RShMod2,What2]),
application:set_env(stdlib, restricted_shell, ?MODULE)
@@ -336,7 +336,7 @@ get_prompt_func() ->
end.
bad_prompt_func(M) ->
- fwrite_severity(benign, "Bad prompt function: ~"++cs_p(), [M]).
+ fwrite_severity(benign, "Bad prompt function: ~tp", [M]).
default_prompt(N) ->
%% Don't bother flattening the list irrespective of what the
@@ -1366,32 +1366,31 @@ pp(V, I, RT) ->
pp(V, I, RT, enc()).
pp(V, I, RT, Enc) ->
+ Strings =
+ case application:get_env(stdlib, shell_strings) of
+ {ok, false} ->
+ false;
+ _ ->
+ true
+ end,
io_lib_pretty:print(V, ([{column, I}, {line_length, columns()},
{depth, ?LINEMAX}, {max_chars, ?CHAR_MAX},
+ {strings, Strings},
{record_print_fun, record_print_fun(RT)}]
++ Enc)).
-%% Control sequence 'p' possibly with Unicode translation modifier
-cs_p() ->
- case encoding() of
- latin1 -> "p";
- unicode -> "tp"
- end.
-
columns() ->
case io:columns() of
{ok,N} -> N;
_ -> 80
end.
-
encoding() ->
[{encoding, Encoding}] = enc(),
Encoding.
-
enc() ->
case lists:keyfind(encoding, 1, io:getopts()) of
- false -> [{encoding,latin1}]; % should never happen
- Enc -> [Enc]
+ false -> [{encoding,latin1}]; % should never happen
+ Enc -> [Enc]
end.
garb(Shell) ->
@@ -1415,10 +1414,9 @@ check_env(V) ->
{ok, Val} when is_integer(Val), Val >= 0 ->
ok;
{ok, Val} ->
- Txt = io_lib:fwrite(
- ("Invalid value of STDLIB configuration parameter ~w: ~"
- ++cs_p()++"\n"),
- [V, Val]),
+ Txt = io_lib:fwrite
+ ("Invalid value of STDLIB configuration parameter"
+ "~w: ~tp\n", [V, Val]),
error_logger:info_report(lists:flatten(Txt))
end.
@@ -1444,14 +1442,22 @@ history(L) when is_integer(L), L >= 0 ->
results(L) when is_integer(L), L >= 0 ->
set_env(stdlib, shell_saved_results, L, ?DEF_RESULTS).
--spec catch_exception(Bool) -> Bool when
+-spec catch_exception(Bool) -> boolean() when
Bool :: boolean().
catch_exception(Bool) ->
set_env(stdlib, shell_catch_exception, Bool, ?DEF_CATCH_EXCEPTION).
--spec prompt_func(PromptFunc) -> PromptFunc when
- PromptFunc :: 'default' | {module(),atom()}.
+-spec prompt_func(PromptFunc) -> PromptFunc2 when
+ PromptFunc :: 'default' | {module(),atom()},
+ PromptFunc2 :: 'default' | {module(),atom()}.
prompt_func(String) ->
set_env(stdlib, shell_prompt_func, String, ?DEF_PROMPT_FUNC).
+
+-spec strings(Strings) -> Strings2 when
+ Strings :: boolean(),
+ Strings2 :: boolean().
+
+strings(Strings) ->
+ set_env(stdlib, shell_strings, Strings, ?DEF_STRINGS).