aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/erl_tar.xml110
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml15
-rw-r--r--lib/stdlib/src/erl_lint.erl6
-rw-r--r--lib/stdlib/src/erl_parse.yrl22
-rw-r--r--lib/stdlib/src/erl_pp.erl23
-rw-r--r--lib/stdlib/src/erl_scan.erl5
-rw-r--r--lib/stdlib/src/erl_tar.erl93
-rw-r--r--lib/stdlib/src/ms_transform.erl4
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl44
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl2
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl29
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl39
-rw-r--r--lib/stdlib/test/tar_SUITE.erl3
13 files changed, 251 insertions, 144 deletions
diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml
index 7f25f5b7bc..95eefb8f9b 100644
--- a/lib/stdlib/doc/src/erl_tar.xml
+++ b/lib/stdlib/doc/src/erl_tar.xml
@@ -80,6 +80,12 @@
</section>
<section>
+ <title>OTHER STORAGE MEDIA</title>
+ <p>The <c>erl_ftp</c> module normally accesses the tar-file on disk using the <seealso marker="kernel:file">file module</seealso>. When other needs arise, there is a way to define your own low-level Erlang functions to perform the writing and reading on the storage media. See <seealso marker="#init/3">init/3</seealso> for usage.</p>
+ <p>An example of this is the sftp support in <seealso marker="ssh:ssh_sftp#open_tar/3">ssh_sftp:open_tar/3</seealso>. That function opens a tar file on a remote machine using an sftp channel.</p>
+ </section>
+
+ <section>
<title>LIMITATIONS</title>
<p>For maximum compatibility, it is safe to archive files with names
up to 100 characters in length. Such tar files can generally be
@@ -99,7 +105,8 @@
<v>TarDescriptor = term()</v>
<v>Filename = filename()</v>
<v>Options = [Option]</v>
- <v>Option = dereference|verbose</v>
+ <v>Option = dereference|verbose|{chunks,ChunkSize}</v>
+ <v>ChunkSize = positive_integer()</v>
<v>RetValue = ok|{error,{Filename,Reason}}</v>
<v>Reason = term()</v>
</type>
@@ -119,6 +126,12 @@
<item>
<p>Print an informational message about the file being added.</p>
</item>
+ <tag><c>{chunks,ChunkSize}</c></tag>
+ <item>
+ <p>Read data in parts from the file. This is intended for memory-limited
+ machines that for example builds a tar file on a remote machine over
+ <seealso marker="ssh:ssh_sftp#open_tar/3">sftp</seealso>.</p>
+ </item>
</taglist>
</desc>
</func>
@@ -389,6 +402,101 @@
</warning>
</desc>
</func>
+
+ <func>
+ <name>init(UserPrivate, AccessMode, Fun) -> {ok,TarDescriptor} | {error,Reason}
+</name>
+ <fsummary>Creates a TarDescriptor used in subsequent tar operations when
+ defining own low-level storage access functions
+ </fsummary>
+ <type>
+ <v>UserPrivate = term()</v>
+ <v>AccessMode = [write] | [read]</v>
+ <v>Fun when AccessMode is [write] = fun(write, {UserPrivate,DataToWrite})->...;
+ (position,{UserPrivate,Position})->...;
+ (close, UserPrivate)->...
+ end
+ </v>
+ <v>Fun when AccessMode is [read] = fun(read2, {UserPrivate,Size})->...;
+ (position,{UserPrivate,Position})->...;
+ (close, UserPrivate)->...
+ end
+ </v>
+ <v>TarDescriptor = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>The <c>Fun</c> is the definition of what to do when the different
+ storage operations functions are to be called from the higher tar
+ handling functions (<c>add/3</c>, <c>add/4</c>, <c>close/1</c>...).
+ </p>
+ <p>The <c>Fun</c> will be called when the tar function wants to do
+ a low-level operation, like writing a block to a file. The Fun is called
+ as <c>Fun(Op,{UserPrivate,Parameters...})</c> where <c>Op</c> is the operation name,
+ <c>UserPrivate</c> is the term passed as the first argument to <c>init/1</c> and
+ <c>Parameters...</c> are the data added by the tar function to be passed down to
+ the storage handling function.
+ </p>
+ <p>The parameter <c>UserPrivate</c> is typically the result of opening a low level
+ structure like a file descriptor, a sftp channel id or such. The different <c>Fun</c>
+ clauses operates on that very term.
+ </p>
+ <p>The fun clauses parameter lists are:
+ <taglist>
+ <tag><c>(write, {UserPrivate,DataToWrite})</c></tag>
+ <item>Write the term <c>DataToWrite</c> using <c>UserPrivate</c></item>
+ <tag><c>(close, UserPrivate)</c></tag>
+ <item>Close the access.</item>
+ <tag><c>(read2, {UserPrivate,Size})</c></tag>
+ <item>Read using <c>UserPrivate</c> but only <c>Size</c> bytes. Note that there is
+ only an arity-2 read function, not an arity-1
+ </item>
+ <tag><c> (position,{UserPrivate,Position})</c></tag>
+ <item>Sets the position of <c>UserPrivate</c> as defined for files in <seealso marker="kernel:file#position-2">file:position/2</seealso></item>
+ <tag><c></c></tag>
+ <item></item>
+ </taglist>
+ </p>
+ <p>A complete <c>Fun</c> parameter for reading and writing on files using the
+ <seealso marker="kernel:file">file module</seealso> could be:
+ </p>
+ <code type="none">
+ ExampleFun =
+ fun(write, {Fd,Data}) -> file:write(Fd, Data);
+ (position, {Fd,Pos}) -> file:position(Fd, Pos);
+ (read2, {Fd,Size}) -> file:read(Fd,Size);
+ (close, Fd) -> file:close(Fd)
+ end
+ </code>
+ <p>where <c>Fd</c> was given to the <c>init/3</c> function as:</p>
+ <code>
+ {ok,Fd} = file:open(Name,...).
+ {ok,TarDesc} = erl_tar:init(Fd, [write], ExampleFun),
+ </code>
+ <p>The <c>TarDesc</c> is then used:</p>
+ <code>
+ erl_tar:add(TarDesc, SomeValueIwantToAdd, FileNameInTarFile),
+ ....,
+ erl_tar:close(TarDesc)
+ </code>
+ <p>When the erl_tar core wants to e.g. write a piece of Data, it would call
+ <c>ExampleFun(write,{UserPrivate,Data})</c>.
+ </p>
+ <note>
+ <p>The example above with <c>file</c> module operations is not necessary to
+ use directly since that is what the <seealso marker="#open">open</seealso> function
+ in principle does.
+ </p>
+ </note>
+ <warning>
+ <p>The <c>TarDescriptor</c> term is not a file descriptor.
+ You should not rely on the specific contents of the <c>TarDescriptor</c>
+ term, as it may change in future versions as more features are added
+ to the <c>erl_tar</c> module.</p>
+ </warning>
+ </desc>
+ </func>
+
<func>
<name>table(Name) -> RetValue</name>
<fsummary>Retrieve the name of all files in a tar file</fsummary>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index bebfbd4514..29b8940c62 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -50,12 +50,8 @@
encoded files in several circumstances. Most notable is the support
for UTF-8 in files read by <c>file:consult/1</c>, release handler support
for UTF-8 and more support for Unicode character sets in the
- I/O-system.</p>
-
- <p>In Erlang/OTP 17.0, the encoding default for Erlang source files was
- switched to UTF-8 and in Erlang/OTP 18.0 Erlang will support atoms in the full
- Unicode range, meaning full Unicode function and module
- names</p>
+ I/O-system. In Erlang/OTP 17.0, the encoding default for Erlang source files was
+ switched to UTF-8.</p>
<p>This guide outlines the current Unicode support and gives a couple
of recipes for working with Unicode data.</p>
@@ -289,8 +285,8 @@
<tag>The language</tag>
<item>Having the source code in UTF-8 also allows you to write
string literals containing Unicode characters with code points &gt;
- 255, although atoms, module names and function names will be
- restricted to the ISO-Latin-1 range until the Erlang/OTP 18.0 release. Binary
+ 255, although atoms, module names and function names are
+ restricted to the ISO-Latin-1 range. Binary
literals where you use the <c>/utf8</c> type, can also be
expressed using Unicode characters &gt; 255. Having module names
using characters other than 7-bit ASCII can cause trouble on
@@ -385,8 +381,7 @@ external_charlist() = maybe_improper_list(char() |
using characters from the ISO-latin-1 character set and atoms are
restricted to the same ISO-latin-1 range. These restrictions in the
language are of course independent of the encoding of the source
- file. Erlang/OTP 18.0 is expected to handle functions named in
- Unicode as well as Unicode atoms.</p>
+ file.</p>
<section>
<title>Bit-syntax</title>
<p>The bit-syntax contains types for coping with binary data in the
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 39f8a26fe1..26d8454731 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -389,9 +389,7 @@ format_error({underspecified_opaque, {TypeName, Arity}}) ->
[TypeName, gen_type_paren(Arity)]);
%% --- obsolete? unused? ---
format_error({format_error, {Fmt, Args}}) ->
- io_lib:format(Fmt, Args);
-format_error({mnemosyne, What}) ->
- "mnemosyne " ++ What ++ ", missing transformation".
+ io_lib:format(Fmt, Args).
gen_type_paren(Arity) when is_integer(Arity), Arity >= 0 ->
gen_type_paren_1(Arity, ")").
@@ -759,8 +757,6 @@ function_state({attribute,La,Attr,_Val}, St) ->
add_error(La, {attribute,Attr}, St);
function_state({function,L,N,A,Cs}, St) ->
function(L, N, A, Cs, St);
-function_state({rule,L,_N,_A,_Cs}, St) ->
- add_error(L, {mnemosyne,"rule"}, St);
function_state({eof,L}, St) -> eof(L, St).
%% eof(LastLine, State) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 767b620871..3502a50eaa 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -42,7 +42,6 @@ function_call argument_list
exprs guard
atomic strings
prefix_op mult_op add_op list_op comp_op
-rule rule_clauses rule_clause rule_body
binary bin_elements bin_element bit_expr
opt_bit_size_expr bit_size_expr opt_bit_type_list bit_type_list bit_type
top_type top_type_100 top_types type typed_expr typed_attr_val
@@ -54,7 +53,7 @@ bin_base_type bin_unit_type type_200 type_300 type_400 type_500.
Terminals
char integer float atom string var
-'(' ')' ',' '->' ':-' '{' '}' '[' ']' '|' '||' '<-' ';' ':' '#' '.'
+'(' ')' ',' '->' '{' '}' '[' ']' '|' '||' '<-' ';' ':' '#' '.'
'after' 'begin' 'case' 'try' 'catch' 'end' 'fun' 'if' 'of' 'receive' 'when'
'andalso' 'orelse'
'bnot' 'not'
@@ -73,7 +72,6 @@ Rootsymbol form.
form -> attribute dot : '$1'.
form -> function dot : '$1'.
-form -> rule dot : '$1'.
attribute -> '-' atom attr_val : build_attribute('$2', '$3').
attribute -> '-' atom typed_attr_val : build_typed_attribute('$2','$3').
@@ -520,17 +518,6 @@ comp_op -> '>' : '$1'.
comp_op -> '=:=' : '$1'.
comp_op -> '=/=' : '$1'.
-rule -> rule_clauses : build_rule('$1').
-
-rule_clauses -> rule_clause : ['$1'].
-rule_clauses -> rule_clause ';' rule_clauses : ['$1'|'$3'].
-
-rule_clause -> atom clause_args clause_guard rule_body :
- {clause,?line('$1'),element(3, '$1'),'$2','$3','$4'}.
-
-rule_body -> ':-' lc_exprs: '$2'.
-
-
Erlang code.
-export([parse_form/1,parse_exprs/1,parse_term/1]).
@@ -846,13 +833,6 @@ build_function(Cs) ->
Arity = length(element(4, hd(Cs))),
{function,?line(hd(Cs)),Name,Arity,check_clauses(Cs, Name, Arity)}.
-%% build_rule([Clause]) -> {rule,Line,Name,Arity,[Clause]'}
-
-build_rule(Cs) ->
- Name = element(3, hd(Cs)),
- Arity = length(element(4, hd(Cs))),
- {rule,?line(hd(Cs)),Name,Arity,check_clauses(Cs, Name, Arity)}.
-
%% build_fun(Line, [Clause]) -> {'fun',Line,{clauses,[Clause]}}.
build_fun(Line, Cs) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 17a758ff58..469ce544c7 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -22,7 +22,7 @@
%%% the parser. It does not always produce pretty code.
-export([form/1,form/2,
- attribute/1,attribute/2,function/1,function/2,rule/1,rule/2,
+ attribute/1,attribute/2,function/1,function/2,
guard/1,guard/2,exprs/1,exprs/2,exprs/3,expr/1,expr/2,expr/3,expr/4]).
-import(lists, [append/1,foldr/3,mapfoldl/3,reverse/1,reverse/2]).
@@ -91,12 +91,6 @@ function(F) ->
function(F, Options) ->
frmt(lfunction(F, options(Options)), state(Options)).
-rule(R) ->
- rule(R, none).
-
-rule(R, Options) ->
- frmt(lrule(R, options(Options)), state(Options)).
-
-spec(guard(Guard) -> io_lib:chars() when
Guard :: [erl_parse:abstract_expr()]).
@@ -199,8 +193,6 @@ 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, _State) ->
- lrule({rule,Line,Name,Arity,Clauses}, Opts);
%% These are specials to make it easier for the compiler.
lform({error,E}, _Opts, _State) ->
leaf(format("~p\n", [{error,E}]));
@@ -418,19 +410,6 @@ func_clause(Name, {clause,Line,Head,Guard,Body}, Opts) ->
Bl = body(Body, Opts),
{step,Gl,Bl}.
-lrule({rule,_Line,Name,_Arity,Cs}, Opts) ->
- Cll = nl_clauses(fun (C, H) -> rule_clause(Name, C, H) end, $;, Opts, Cs),
- [Cll,leaf(".\n")].
-
-rule_clause(Name, {clause,Line,Head,Guard,Body}, Opts) ->
- Hl = call({atom,Line,Name}, Head, 0, Opts),
- Gl = guard_when(Hl, Guard, Opts, leaf(" :-")),
- Bl = rule_body(Body, Opts),
- {step,Gl,Bl}.
-
-rule_body(Es, Opts) ->
- lc_quals(Es, Opts).
-
guard_when(Before, Guard, Opts) ->
guard_when(Before, Guard, Opts, ' ->').
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 6fd6bb888b..4960a86760 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -599,9 +599,6 @@ scan1("|"=Cs, _St, Line, Col, Toks) ->
%% :=
scan1(":="++Cs, St, Line, Col, Toks) ->
tok2(Cs, St, Line, Col, Toks, ":=", ':=', 2);
-%% :-
-scan1(":-"++Cs, St, Line, Col, Toks) ->
- tok2(Cs, St, Line, Col, Toks, ":-", ':-', 2);
%% :: for typed records
scan1("::"++Cs, St, Line, Col, Toks) ->
tok2(Cs, St, Line, Col, Toks, "::", '::', 2);
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index acf7a5cd40..ab6223c0fe 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -22,7 +22,7 @@
%% Purpose: Unix tar (tape archive) utility.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([create/2, create/3, extract/1, extract/2, table/1, table/2,
+-export([init/3, create/2, create/3, extract/1, extract/2, table/1, table/2,
open/2, close/1, add/3, add/4,
t/1, tt/1, format_error/1]).
@@ -30,10 +30,16 @@
-record(add_opts,
{read_info, % Fun to use for read file/link info.
+ chunk_size = 0, % For file reading when sending to sftp. 0=do not chunk
verbose = false :: boolean()}). % Verbose on/off.
%% Opens a tar archive.
+init(UsrHandle, AccessMode, Fun) when is_function(Fun,2) ->
+ {ok, {AccessMode,{UsrHandle,Fun}}}.
+
+%%%================================================================
+%%% The open function with friends is to keep the file and binary api of this module
open(Name, Mode) ->
case open_mode(Mode) of
{ok, Access, Raw, Opts} ->
@@ -46,27 +52,37 @@ open1({binary,Bin}, read, _Raw, Opts) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
_ = [ram_file:uncompress(File) || Opts =:= [compressed]],
- {ok,{read,File}};
+ init(File,read,file_fun());
Error ->
Error
end;
open1({file, Fd}, read, _Raw, _Opts) ->
- {ok, {read, Fd}};
+ init(Fd, read, file_fun());
open1(Name, Access, Raw, Opts) ->
case file:open(Name, Raw ++ [binary, Access|Opts]) of
{ok, File} ->
- {ok, {Access, File}};
+ init(File, Access, file_fun());
{error, Reason} ->
{error, {Name, Reason}}
end.
+file_fun() ->
+ fun(write, {Fd,Data}) -> file:write(Fd, Data);
+ (position, {Fd,Pos}) -> file:position(Fd, Pos);
+ (read2, {Fd,Size}) -> file:read(Fd,Size);
+ (close, Fd) -> file:close(Fd)
+ end.
+
+%%% End of file and binary api (except for open_mode/1 downwards
+%%%================================================================
+
%% Closes a tar archive.
close({read, File}) ->
- ok = file:close(File);
+ ok = do_close(File);
close({write, File}) ->
PadResult = pad_file(File),
- ok = file:close(File),
+ ok = do_close(File),
PadResult;
close(_) ->
{error, einval}.
@@ -75,7 +91,6 @@ close(_) ->
add(File, Name, Options) ->
add(File, Name, Name, Options).
-
add({write, File}, Name, NameInArchive, Options) ->
Opts = #add_opts{read_info=fun(F) -> file:read_link_info(F) end},
add1(File, Name, NameInArchive, add_opts(Options, Opts));
@@ -88,6 +103,8 @@ add_opts([dereference|T], Opts) ->
add_opts(T, Opts#add_opts{read_info=fun(F) -> file:read_file_info(F) end});
add_opts([verbose|T], Opts) ->
add_opts(T, Opts#add_opts{verbose=true});
+add_opts([{chunks,N}|T], Opts) ->
+ add_opts(T, Opts#add_opts{chunk_size=N});
add_opts([_|T], Opts) ->
add_opts(T, Opts);
add_opts([], Opts) ->
@@ -321,16 +338,46 @@ add1(TarFile, Name, NameInArchive, Opts) ->
{error, {Name, Reason}}
end.
+add1(Tar, Name, Header, chunked, Options) ->
+ add_verbose(Options, "a ~ts [chunked ", [Name]),
+ try
+ ok = do_write(Tar, Header),
+ {ok,D} = file:open(Name, [read,binary]),
+ {ok,NumBytes} = add_read_write_chunks(D, Tar, Options#add_opts.chunk_size, 0, Options),
+ _ = file:close(D),
+ ok = do_write(Tar, padding(NumBytes,?record_size))
+ of
+ ok ->
+ add_verbose(Options, "~n", []),
+ ok
+ catch
+ error:{badmatch,{error,Error}} ->
+ add_verbose(Options, "~n", []),
+ {error,{Name,Error}}
+ end;
add1(Tar, Name, Header, Bin, Options) ->
add_verbose(Options, "a ~ts~n", [Name]),
- file:write(Tar, [Header, Bin, padding(byte_size(Bin), ?record_size)]).
+ do_write(Tar, [Header, Bin, padding(byte_size(Bin), ?record_size)]).
+
+add_read_write_chunks(D, Tar, ChunkSize, SumNumBytes, Options) ->
+ case file:read(D, ChunkSize) of
+ {ok,Bin} ->
+ ok = do_write(Tar, Bin),
+ add_verbose(Options, ".", []),
+ add_read_write_chunks(D, Tar, ChunkSize, SumNumBytes+byte_size(Bin), Options);
+ eof ->
+ add_verbose(Options, "]", []),
+ {ok,SumNumBytes};
+ Other ->
+ Other
+ end.
add_directory(TarFile, DirName, NameInArchive, Info, Options) ->
case file:list_dir(DirName) of
{ok, []} ->
add_verbose(Options, "a ~ts~n", [DirName]),
Header = create_header(NameInArchive, Info),
- file:write(TarFile, Header);
+ do_write(TarFile, Header);
{ok, Files} ->
Add = fun (File) ->
add1(TarFile,
@@ -396,7 +443,7 @@ to_string(Str0, Count) ->
%% Pads out end of file.
pad_file(File) ->
- {ok,Position} = file:position(File, {cur,0}),
+ {ok,Position} = do_position(File, {cur,0}),
%% There must be at least two zero records at the end.
Fill = case ?block_size - (Position rem ?block_size) of
Fill0 when Fill0 < 2*?record_size ->
@@ -407,7 +454,7 @@ pad_file(File) ->
%% Large enough.
Fill0
end,
- file:write(File, zeroes(Fill)).
+ do_write(File, zeroes(Fill)).
split_filename(Name) when length(Name) =< ?th_name_len ->
{"", Name};
@@ -500,7 +547,7 @@ foldl_read(TarName, Fun, Accu, Opts) ->
Ok ->
Ok
end,
- ok = file:close(File),
+ ok = do_close(File),
Result;
Error ->
Error
@@ -559,7 +606,7 @@ check_extract(Name, #read_opts{files=Files}) ->
ordsets:is_element(Name, Files).
get_header(File) ->
- case file:read(File, ?record_size) of
+ case do_read(File, ?record_size) of
eof ->
throw({error,eof});
{ok, Bin} when is_binary(Bin) ->
@@ -690,7 +737,7 @@ get_element(File, #tar_header{size = 0}) ->
skip_to_next(File),
{ok,<<>>};
get_element(File, #tar_header{size = Size}) ->
- case file:read(File, Size) of
+ case do_read(File, Size) of
{ok,Bin}=Res when byte_size(Bin) =:= Size ->
skip_to_next(File),
Res;
@@ -880,7 +927,7 @@ skip(File, Size) ->
%% Note: There is no point in handling failure to get the current position
%% in the file. If it doesn't work, something serious is wrong.
Amount = ((Size + ?record_size - 1) div ?record_size) * ?record_size,
- {ok,_} = file:position(File, {cur, Amount}),
+ {ok,_} = do_position(File, {cur, Amount}),
ok.
%% Skips to the next record in the file.
@@ -888,9 +935,9 @@ skip(File, Size) ->
skip_to_next(File) ->
%% Note: There is no point in handling failure to get the current position
%% in the file. If it doesn't work, something serious is wrong.
- {ok, Position} = file:position(File, {cur, 0}),
+ {ok, Position} = do_position(File, {cur, 0}),
NewPosition = ((Position + ?record_size - 1) div ?record_size) * ?record_size,
- {ok,NewPosition} = file:position(File, NewPosition),
+ {ok,NewPosition} = do_position(File, NewPosition),
ok.
%% Prints the message on if the verbose option is given.
@@ -916,6 +963,9 @@ posix_to_erlang_time(Sec) ->
read_file_and_info(Name, Opts) ->
ReadInfo = Opts#add_opts.read_info,
case ReadInfo(Name) of
+ {ok,Info} when Info#file_info.type =:= regular,
+ Opts#add_opts.chunk_size>0 ->
+ {ok,chunked,Info};
{ok,Info} when Info#file_info.type =:= regular ->
case file:read_file(Name) of
{ok,Bin} ->
@@ -962,3 +1012,12 @@ open_mode([], Access, Raw, Opts) ->
{ok, Access, Raw, Opts};
open_mode(_, _, _, _) ->
{error, einval}.
+
+%%%================================================================
+do_write({UsrHandle,Fun}, Data) -> Fun(write,{UsrHandle,Data}).
+
+do_position({UsrHandle,Fun}, Pos) -> Fun(position,{UsrHandle,Pos}).
+
+do_read({UsrHandle,Fun}, Len) -> Fun(read2,{UsrHandle,Len}).
+
+do_close({UsrHandle,Fun}) -> Fun(close,UsrHandle).
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index e671dcd8cf..7b6f4e5b50 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -725,10 +725,10 @@ transform_head([V],OuterBound) ->
th(NewV,NewBind,OuterBound).
-toplevel_head_match({match,Line,{var,_,VName},Expr},B,OB) ->
+toplevel_head_match({match,_,{var,Line,VName},Expr},B,OB) ->
warn_var_clash(Line,VName,OB),
{Expr,new_bind({VName,'$_'},B)};
-toplevel_head_match({match,Line,Expr,{var,_,VName}},B,OB) ->
+toplevel_head_match({match,_,Expr,{var,Line,VName}},B,OB) ->
warn_var_clash(Line,VName,OB),
{Expr,new_bind({VName,'$_'},B)};
toplevel_head_match(Other,B,_OB) ->
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 046b5cf330..f71446dd64 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -42,7 +42,6 @@
-export([ func/1, call/1, recs/1, try_catch/1, if_then/1,
receive_after/1, bits/1, head_tail/1,
cond1/1, block/1, case1/1, ops/1, messages/1,
- old_mnemosyne_syntax/1,
import_export/1, misc_attrs/1, dialyzer_attrs/1,
hook/1,
neg_indent/1,
@@ -77,7 +76,7 @@ groups() ->
[{expr, [],
[func, call, recs, try_catch, if_then, receive_after,
bits, head_tail, cond1, block, case1, ops,
- messages, old_mnemosyne_syntax, maps_syntax
+ messages, maps_syntax
]},
{attributes, [], [misc_attrs, import_export, dialyzer_attrs]},
{tickets, [],
@@ -561,27 +560,6 @@ messages(Config) when is_list(Config) ->
?line true = "\n" =:= lists:flatten(erl_pp:form({eof,0})),
ok.
-old_mnemosyne_syntax(Config) when is_list(Config) ->
- %% Since we have kept the ':-' token,
- %% better test that we can pretty print it.
- R = {rule,12,sales,2,
- [{clause,12,
- [{var,12,'E'},{atom,12,employee}],
- [],
- [{generate,13,
- {var,13,'E'},
- {call,13,{atom,13,table},[{atom,13,employee}]}},
- {match,14,
- {record_field,14,{var,14,'E'},{atom,14,salary}},
- {atom,14,sales}}]}]},
- ?line "sales(E, employee) :-\n"
- " E <- table(employee),\n"
- " E.salary = sales.\n" =
- lists:flatten(erl_pp:form(R)),
- ok.
-
-
-
import_export(suite) ->
[];
import_export(Config) when is_list(Config) ->
@@ -664,26 +642,6 @@ do_hook(HookFun) ->
AFormChars = erl_pp:form(A, H),
?line true = AChars =:= lists:flatten(AFormChars),
- R = {rule,0,sales,0,
- [{clause,0,[{var,0,'E'},{atom,0,employee}],[],
- [{generate,2,{var,2,'E'},
- {call,2,{atom,2,table},[{atom,2,employee}]}},
- {match,3,
- {record_field,3,{var,3,'E'},{atom,3,salary}},
- {foo,Expr}}]}]},
- RChars = lists:flatten(erl_pp:rule(R, H)),
- R2 = {rule,0,sales,0,
- [{clause,0,[{var,0,'E'},{atom,0,employee}],[],
- [{generate,2,{var,2,'E'},
- {call,2,{atom,2,table},[{atom,2,employee}]}},
- {match,3,
- {record_field,3,{var,3,'E'},{atom,3,salary}},
- {call,0,{atom,0,foo},[Expr2]}}]}]},
- RChars2 = erl_pp:rule(R2),
- ?line true = RChars =:= lists:flatten(RChars2),
- ARChars = erl_pp:form(R, H),
- ?line true = RChars =:= lists:flatten(ARChars),
-
?line "INVALID-FORM:{foo,bar}:" = lists:flatten(erl_pp:expr({foo,bar})),
%% A list (as before R6), not a list of lists.
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 9be9f641c8..6ef947f0e3 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -226,7 +226,7 @@ atoms() ->
punctuations() ->
L = ["<<", "<-", "<=", "<", ">>", ">=", ">", "->", "--",
"-", "++", "+", "=:=", "=/=", "=<", "=>", "==", "=", "/=",
- "/", "||", "|", ":=", ":-", "::", ":"],
+ "/", "||", "|", ":=", "::", ":"],
%% One token at a time:
[begin
W = list_to_atom(S),
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index 4ec13ed472..1577caa80f 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -91,21 +91,23 @@ warnings(Config) when is_list(Config) ->
" end)">>,
?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'A'}}]}] =
compile_ww(Prog),
- Prog2 = <<"C=5, "
- "ets:fun2ms(fun({A,B} = C) "
- " when is_integer(A) and (A+5 > B) -> "
- " {A andalso B,C} "
- " end)">>,
- ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
+ Prog2 = <<"C = 5,
+ ets:fun2ms(fun ({A,B} =
+ C) when is_integer(A) and (A+5 > B) ->
+ {A andalso B,C}
+ end)">>,
+ [{_,[{3,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
compile_ww(Prog2),
Rec3 = <<"-record(a,{a,b,c,d=foppa}).">>,
- Prog3 = <<"A=3,C=5, "
- "ets:fun2ms(fun(#a{a = A, b = B} = C) "
- " when is_integer(A) and (A+5 > B) -> "
- " {A andalso B,C} "
- " end)">>,
- ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'A'}},
- {_,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
+ Prog3 = <<"A = 3,
+ C = 5,
+ ets:fun2ms(fun (C
+ = #a{a = A, b = B})
+ when is_integer(A) and (A+5 > B) ->
+ {A andalso B,C}
+ end)">>,
+ [{_,[{3,ms_transform,{?WARN_NUMBER_SHADOW,'C'}},
+ {4,ms_transform,{?WARN_NUMBER_SHADOW,'A'}}]}] =
compile_ww(Rec3,Prog3),
Rec4 = <<"-record(a,{a,b,c,d=foppa}).">>,
Prog4 = <<"A=3,C=5, "
@@ -867,6 +869,7 @@ compile_ww(Records,Expr) ->
"-include_lib(\"stdlib/include/ms_transform.hrl\").\n",
"-export([tmp/0]).\n",
Records/binary,"\n",
+ "-file(?FILE, 0). ",
"tmp() ->\n",
Expr/binary,".\n">>,
FN=temp_name(),
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 37fbb5267b..4173a40d14 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -7891,7 +7891,7 @@ run_test(Config, Extra, {cres, Body, Opts, ExpectedCompileReturn}) ->
{module, _} = code:load_abs(AbsFile, Mod),
Ms0 = erlang:process_info(self(),messages),
- Before = {get(), pps(), ets:all(), Ms0},
+ Before = {{get(), ets:all(), Ms0}, pps()},
%% Prepare the check that the qlc module does not call qlc_pt.
_ = [unload_pt() || {file, Name} <- [code:is_loaded(qlc_pt)],
@@ -7921,12 +7921,29 @@ run_test(Config, Extra, {cres, Body, Opts, ExpectedCompileReturn}) ->
run_test(Config, Extra, Body) ->
run_test(Config, Extra, {cres,Body,[]}).
-wait_for_expected(R, Before, SourceFile, Wait) ->
+wait_for_expected(R, {Strict0,PPS0}=Before, SourceFile, Wait) ->
Ms = erlang:process_info(self(),messages),
- After = {get(), pps(), ets:all(), Ms},
+ After = {_,PPS1} = {{get(), ets:all(), Ms}, pps()},
case {R, After} of
{ok, Before} ->
ok;
+ {ok, {Strict0,_}} ->
+ {Ports0,Procs0} = PPS0,
+ {Ports1,Procs1} = PPS1,
+ case {Ports1 -- Ports0, Procs1 -- Procs0} of
+ {[], []} -> ok;
+ _ when Wait ->
+ timer:sleep(1000),
+ wait_for_expected(R, Before, SourceFile, false);
+ {PortsDiff,ProcsDiff} ->
+ io:format("failure, got ~p~n, expected ~p\n",
+ [PPS1, PPS0]),
+ show("Old port", Ports0 -- Ports1),
+ show("New port", PortsDiff),
+ show("Old proc", Procs0 -- Procs1),
+ show("New proc", ProcsDiff),
+ fail(SourceFile)
+ end;
_ when Wait ->
timer:sleep(1000),
wait_for_expected(R, Before, SourceFile, false);
@@ -7993,7 +8010,7 @@ compile_file(Config, Test0, Opts0) ->
case compile:file(File, Opts) of
{ok, _M, Ws} -> warnings(File, Ws);
{error, [{File,Es}], []} -> {errors, Es, []};
- {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws}
+ {error, [{File,Es}], [{File,Ws}]} -> {errors, Es, Ws}
end.
comp_compare(T, T) ->
@@ -8058,6 +8075,17 @@ filename(Name, Config) when is_atom(Name) ->
filename(Name, Config) ->
filename:join(?privdir, Name).
+show(_S, []) ->
+ ok;
+show(S, [{Pid, Name, InitCall}|Pids]) when is_pid(Pid) ->
+ io:format("~s: ~w (~w), ~w: ~p~n",
+ [S, Pid, proc_reg_name(Name), InitCall,
+ erlang:process_info(Pid)]),
+ show(S, Pids);
+show(S, [{Port, _}|Ports]) when is_port(Port)->
+ io:format("~s: ~w: ~p~n", [S, Port, erlang:port_info(Port)]),
+ show(S, Ports).
+
pps() ->
{port_list(), process_list()}.
@@ -8070,6 +8098,9 @@ process_list() ->
safe_second_element(process_info(P, initial_call))} ||
P <- processes(), is_process_alive(P)].
+proc_reg_name({registered_name, Name}) -> Name;
+proc_reg_name([]) -> no_reg_name.
+
safe_second_element({_,Info}) -> Info;
safe_second_element(Other) -> Other.
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 6349139925..9b6d65011e 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -654,6 +654,7 @@ open_add_close(Config) when is_list(Config) ->
?line ok = erl_tar:add(AD, FileOne, []),
?line ok = erl_tar:add(AD, FileTwo, "second file", []),
?line ok = erl_tar:add(AD, FileThree, [verbose]),
+ ?line ok = erl_tar:add(AD, FileThree, "chunked", [{chunks,11411},verbose]),
?line ok = erl_tar:add(AD, ADir, [verbose]),
?line ok = erl_tar:add(AD, AnotherDir, [verbose]),
?line ok = erl_tar:close(AD),
@@ -661,7 +662,7 @@ open_add_close(Config) when is_list(Config) ->
?line ok = erl_tar:t(TarOne),
?line ok = erl_tar:tt(TarOne),
- ?line {ok,[FileOne,"second file",FileThree,ADir,SomeContent]} = erl_tar:table(TarOne),
+ ?line {ok,[FileOne,"second file",FileThree,"chunked",ADir,SomeContent]} = erl_tar:table(TarOne),
?line delete_files(["oac_file","oac_small","oac_big",Dir,AnotherDir,ADir]),