diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/doc/src/escript.xml | 217 | ||||
-rw-r--r-- | erts/preloaded/ebin/erl_prim_loader.beam | bin | 50808 -> 50816 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/erlang.beam | bin | 23800 -> 23808 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/init.beam | bin | 44488 -> 44500 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/otp_ring0.beam | bin | 1436 -> 1448 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_file.beam | bin | 29480 -> 29496 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_inet.beam | bin | 57308 -> 57320 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_zip.beam | bin | 21756 -> 22600 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/zlib.beam | bin | 10612 -> 10620 bytes | |||
-rw-r--r-- | erts/preloaded/src/prim_zip.erl | 89 |
10 files changed, 255 insertions, 51 deletions
diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml index a89449df23..44c9a5ac68 100644 --- a/erts/doc/src/escript.xml +++ b/erts/doc/src/escript.xml @@ -31,7 +31,7 @@ <com>escript</com> <comsummary>Erlang scripting support</comsummary> <description> - <p><c><![CDATA[escript]]></c> provides support for running short Erlang programs + <p><c>escript</c> provides support for running short Erlang programs without having to compile them first and an easy way to retrieve the command line arguments.</p> </description> @@ -41,10 +41,10 @@ <name>escript escript-flags script-name script-arg1 script-arg2...</name> <fsummary>Run a script written in Erlang</fsummary> <desc> - <p><c><![CDATA[escript]]></c> runs a script written in Erlang.</p> + <p><c>escript</c> runs a script written in Erlang.</p> <p>Here follows an example.</p> <pre> -$ <input>cat factorial</input> +$ <input>cat factorial</input> #!/usr/bin/env escript %% -*- erlang -*- %%! -smp enable -sname factorial -mnesia debug verbose @@ -59,11 +59,11 @@ main([String]) -> end; main(_) -> usage(). - + usage() -> io:format("usage: factorial integer\n"), halt(1). - + fac(0) -> 1; fac(N) -> N * fac(N-1). $ <input>factorial 5</input> @@ -74,9 +74,8 @@ $ <input>factorial five</input> usage: factorial integer </pre> <p>The header of the Erlang script in the example differs from a normal Erlang module. The first line is intended to be the - interpreter line, which invokes - <c><![CDATA[escript]]></c>. However if you invoke the - <c><![CDATA[escript]]></c> like this</p> + interpreter line, which invokes <c>escript</c>. However if you + invoke the <c>escript</c> like this</p> <pre> $ <input>escript factorial 5</input> </pre> <p>the contents of the first line does not matter, but it @@ -93,13 +92,13 @@ $ <input>escript factorial 5</input> </pre> %%! -smp enable -sname factorial -mnesia debug verbose</pre> <p>Such an argument line must start with <c>%%!</c> and the rest of the line will interpreted as arguments to the emulator.</p> - <p>If you know the location of the <c><![CDATA[escript]]></c> executable, the first - line can directly give the path to <c><![CDATA[escript]]></c>. For instance:</p> + <p>If you know the location of the <c>escript</c> executable, the first + line can directly give the path to <c>escript</c>. For instance:</p> <pre> #!/usr/local/bin/escript </pre> <p>As any other kind of scripts, Erlang scripts will not work on Unix platforms if the execution bit for the script file is not set. - (Use <c><![CDATA[chmod +x script-name]]></c> to turn on the execution bit.) + (Use <c>chmod +x script-name</c> to turn on the execution bit.) </p> <p>The rest of the Erlang script file may either contain @@ -108,33 +107,33 @@ $ <input>escript factorial 5</input> </pre> <p>An Erlang script file must always contain the function <em>main/1</em>. When the script is run, the - <c><![CDATA[main/1]]></c> function will be called with a list + <c>main/1</c> function will be called with a list of strings representing the arguments given to the script (not changed or interpreted in any way).</p> - <p>If the <c><![CDATA[main/1]]></c> function in the script returns successfully, + <p>If the <c>main/1</c> function in the script returns successfully, the exit status for the script will be 0. If an exception is generated during execution, a short message will be printed and the script terminated with exit status 127.</p> - <p>To return your own non-zero exit code, call <c><![CDATA[halt(ExitCode)]]></c>; + <p>To return your own non-zero exit code, call <c>halt(ExitCode)</c>; for instance:</p> <pre> halt(1).</pre> - <p>Call <c><![CDATA[escript:script_name/0]]></c> from your to - script to retrieve the pathname of the script (the pathname - is usually, but not always, absolute).</p> + <p>Call <seealso marker="#script_name_0">escript:script_name()</seealso> + from your to script to retrieve the pathname of the script + (the pathname is usually, but not always, absolute).</p> <p>If the file contains source code (as in the example above), it will be processed by the preprocessor <c>epp</c>. This means that you for example may use pre-defined macros (such as - <c><![CDATA[?MODULE]]></c>) as well as include directives like - the <c><![CDATA[-include_lib]]></c> directive. For instance, use</p> + <c>?MODULE</c>) as well as include directives like + the <c>-include_lib</c> directive. For instance, use</p> <pre> --include_lib("kernel/include/file.hrl"). </pre> +-include_lib("kernel/include/file.hrl").</pre> <p>to include the record definitions for the records used by the - <c><![CDATA[file:read_link_info/1]]></c> function.</p> + <c>file:read_link_info/1</c> function.</p> <p>The script will be checked for syntactic and semantic correctness before being run. If there are warnings (such as @@ -144,7 +143,7 @@ halt(1).</pre> 127.</p> <p>Both the module declaration and the export declaration of - the <c><![CDATA[main/1]]></c> function are optional.</p> + the <c>main/1</c> function are optional.</p> <p>By default, the script will be interpreted. You can force it to be compiled by including the following line somewhere @@ -198,6 +197,180 @@ factorial 5 = 120 </pre> </desc> </func> + <func> + <name>escript:create(FileOrBin, Sections) -> ok | {ok, binary()} | {error, term()}</name> + <fsummary>Create an escript</fsummary> + <type> + <v>FileOrBin = filename() | 'binary'</v> + <v>Sections = [Header] Body | Body</v> + <v>Header = shebang | {shebang, Shebang} + | comment | {comment, Comment} + | {emu_args, EmuArgs}</v> + <v>Shebang = string() | 'default' | 'undefined'</v> + <v>Comment = string() | 'default' | 'undefined'</v> + <v>EmuArgs = string() | 'undefined'</v> + <v>Body = {source, SourceCode} + | {beam, BeamCode} + | {archive, ZipArchive}</v> + <v>SourceCode = BeamCode = ZipArchive = binary()</v> + </type> + <desc> + <p>The <marker id="create_2"></marker> <c>create/2</c> + function creates an escript from a list of sections. The + sections can be given in any order. An escript begins with an + optional <c>Header</c> followed by a mandatory <c>Body</c>. If + the header is present, it does always begin with a + <c>shebang</c>, possibly followed by a <c>comment</c> and + <c>emu_args</c>. The <c>shebang</c> defaults to + <c>"/usr/bin/env escript"</c>. The comment defaults to + <c>"This is an -*- erlang -*- file"</c>. The created escript + can either be returned as a binary or written to file.</p> + + <p>As an example of how the function can be used, we create an + interpreted escript which uses emu_args to set some emulator + flag. In this case it happens to disable the smp_support. We + do also extract the different sections from the newly created + script:</p> + <pre> +> <input>Source = "%% Demo\nmain(_Args) ->\n io:format(erlang:system_info(smp_support)).\n".</input> +"%% Demo\nmain(_Args) ->\n io:format(erlang:system_info(smp_support)).\n" +> <input>io:format("~s\n", [Source]).</input> +%% Demo +main(_Args) -> + io:format(erlang:system_info(smp_support)). + +ok +> <input>{ok, Bin} = escript:create(binary, [shebang, comment, {emu_args, "-smp disable"}, + {source, list_to_binary(Source)}]).</input> +{ok,<<"#!/usr/bin/env escript\n%% This is an -*- erlang -*- file\n%%!-smp disabl"...>>} +> <input>file:write_file("demo.escript", Bin).</input> +ok +> <input>os:cmd("escript demo.escript").</input> +"false" +> <input>escript:extract("demo.escript", []).</input> +{ok,[{shebang,default}, {comment,default}, {emu_args,"-smp disable"}, + {source,<<"%% Demo\nmain(_Args) ->\n io:format(erlang:system_info(smp_su"...>>}]} + </pre> + + <p>An escript without header can be created like this:</p> +<pre> +> <input>file:write_file("demo.erl", + ["%% demo.erl\n-module(demo).\n-export([main/1]).\n\n", Source]).</input> +ok +> <input>{ok, _, BeamCode} = compile:file("demo.erl", [binary, debug_info]).</input> +{ok,demo, + <<70,79,82,49,0,0,2,208,66,69,65,77,65,116,111,109,0,0,0, + 79,0,0,0,9,4,100,...>>} +> <input>escript:create("demo.beam", [{beam, BeamCode}]).</input> +ok +> <input>escript:extract("demo.beam", []).</input> +{ok,[{shebang,undefined}, {comment,undefined}, {emu_args,undefined}, + {beam,<<70,79,82,49,0,0,3,68,66,69,65,77,65,116, + 111,109,0,0,0,83,0,0,0,9,...>>}]} +> <input>os:cmd("escript demo.beam").</input> +"true" +</pre> + <p>Here we create an archive script containing both Erlang + code as well as beam code. Then we iterate over all files in + the archive and collect their contents and some info about + them. + </p> +<pre> +> <input>{ok, SourceCode} = file:read_file("demo.erl").</input> +{ok,<<"%% demo.erl\n-module(demo).\n-export([main/1]).\n\n%% Demo\nmain(_Arg"...>>} +> <input>escript:create("demo.escript", + [shebang, + {archive, [{"demo.erl", SourceCode}, + {"demo.beam", BeamCode}], []}]).</input> +ok +> <input>{ok, [{shebang,default}, {comment,undefined}, {emu_args,undefined}, + {archive, ArchiveBin}]} = escript:extract("demo.escript", []).</input> +{ok,[{shebang,default}, {comment,undefined}, {emu_args,undefined}, + {{archive,<<80,75,3,4,20,0,0,0,8,0,118,7,98,60,105, + 152,61,93,107,0,0,0,118,0,...>>}]} +> <input>file:write_file("demo.zip", ArchiveBin).</input> +ok +> <input>zip:foldl(fun(N, I, B, A) -> [{N, I(), B()} | A] end, [], "demo.zip").</input> +{ok,[{"demo.beam", + {file_info,748,regular,read_write, + {{2010,3,2},{0,59,22}}, + {{2010,3,2},{0,59,22}}, + {{2010,3,2},{0,59,22}}, + 54,1,0,0,0,0,0}, + <<70,79,82,49,0,0,2,228,66,69,65,77,65,116,111,109,0,0,0, + 83,0,0,...>>}, + {"demo.erl", + {file_info,118,regular,read_write, + {{2010,3,2},{0,59,22}}, + {{2010,3,2},{0,59,22}}, + {{2010,3,2},{0,59,22}}, + 54,1,0,0,0,0,0}, + <<"%% demo.erl\n-module(demo).\n-export([main/1]).\n\n%% Demo\nmain(_Arg"...>>}]}</pre> + </desc> + </func> + <func> + <name>escript:extract(File, Options) -> {ok, Sections} | {error, term()}</name> + <fsummary>Parses an escript and extracts its sections</fsummary> + <type> + <v>File = filename()</v> + <v>Options = [] | [compile_source]</v> + <v>Sections = Headers Body</v> + <v>Headers = {shebang, Shebang} + {comment, Comment} + {emu_args, EmuArgs}</v> + <v>Shebang = string() | 'default' | 'undefined'</v> + <v>Comment = string() | 'default' | 'undefined'</v> + <v>EmuArgs = string() | 'undefined'</v> + <v>Body = {source, SourceCode} + | {source, BeamCode} + | {beam, BeamCode} + | {archive, ZipArchive}</v> + <v>SourceCode = BeamCode = ZipArchive = binary()</v> + </type> + <desc> + <p>The <marker id="extract_2"></marker> <c>extract/2</c> + function parses an escript and extracts its sections. This is + the reverse of <c>create/2</c>.</p> + + <p>All sections are returned even if they do not exist in the + escript. If a particular section happens to have the same + value as the default value, the extracted value is set to the + atom <c>default</c>. If a section is missing, the extracted + value is set to the atom <c>undefined</c>. </p> + + <p>The <c>compile_source</c> option only affects the result if + the escript contains <c>source</c> code. In that case the + Erlang code is automatically compiled and <c>{source, + BeamCode}</c> is returned instead of <c>{source, + SourceCode}</c>.</p> + + <pre> +> <input>escript:create("demo.escript", + [shebang, {archive, [{"demo.erl", SourceCode}, + {"demo.beam", BeamCode}], []}]).</input> +ok +> <input>{ok, [{shebang,default}, {comment,undefined}, {emu_args,undefined}, + {archive, ArchiveBin}]} = + escript:extract("demo.escript", []).</input> +{ok,[{{archive,<<80,75,3,4,20,0,0,0,8,0,118,7,98,60,105, + 152,61,93,107,0,0,0,118,0,...>>} + {emu_args,undefined}]} + </pre> + </desc> + </func> + <func> + <name>escript:script_name() -> File</name> + <fsummary>Returns the name of an escript</fsummary> + <type> + <v>File = filename()</v> + </type> + <desc> + <p>The <marker id="script_name_0"></marker> + <c>script_name/0</c> function returns the name of the escript + being executed. If the function is invoked outside the context + of an escript, the behavior is undefined.</p> + </desc> + </func> </funcs> <section> diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex 304ac41dce..afd8a90b3f 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 21e5525b2f..4ec84948d8 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 8ccc553c13..c3e746f3ee 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 8ae73ea9a7..4b2d8bb2de 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 3acda843fd..2916baaa77 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex 9457b6d360..46912e2bea 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 6837cb4661..ccf8aff6f6 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 4e4f85d312..ccd597ba68 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index 3f5a5b9721..6a9856fdad 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -65,34 +65,55 @@ filter_fun() -> open(F) -> open(filter_fun(), undefined, F). -open(FilterFun, FilterAcc, F) -> - case ?CATCH do_open(FilterFun, FilterAcc, F) of - {ok, PrimZip, Acc} -> - {ok, PrimZip, Acc}; - Error -> - {error, Error} - end. +open(FilterFun, FilterAcc, F) when is_function(FilterFun, 2) -> + try + do_open(FilterFun, FilterAcc, F) + catch + throw:{filter_fun_throw, Reason} -> + throw(Reason); + throw:InternalReason -> + {error, InternalReason}; + Class:Reason -> + erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) + end; +open(_, _, _) -> + {error, einval}. do_open(FilterFun, FilterAcc, F) -> Input = get_zip_input(F), In0 = Input({open, F, [read, binary, raw]}, []), Z = zlib:open(), PrimZip = #primzip{files = [], zlib = Z, in = In0, input = Input}, - {PrimZip2, FilterAcc2} = get_central_dir(PrimZip, FilterFun, FilterAcc), - {ok, PrimZip2, FilterAcc2}. + try + {PrimZip2, FilterAcc2} = get_central_dir(PrimZip, FilterFun, FilterAcc), + {ok, PrimZip2, FilterAcc2} + catch + Class:Reason -> + close(PrimZip), + erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) + end. %% iterate over all files in a zip archive -foldl(FilterFun, FilterAcc, #primzip{files = Files} = PrimZip) -> - case ?CATCH do_foldl(FilterFun, FilterAcc, Files, [], PrimZip, PrimZip) of - {ok, FilterAcc2, PrimZip2} -> {ok, PrimZip2, FilterAcc2}; - Error -> {error, Error} +foldl(FilterFun, FilterAcc, #primzip{files = Files} = PrimZip) + when is_function(FilterFun, 2) -> + try + {ok, FilterAcc2, PrimZip2} = + do_foldl(FilterFun, FilterAcc, Files, [], PrimZip, PrimZip), + {ok, PrimZip2, FilterAcc2} + catch + throw:{filter_fun_throw, Reason} -> + throw(Reason); + throw:InternalReason -> + {error, InternalReason}; + Class:Reason -> + erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) end; foldl(_, _, _) -> {error, einval}. do_foldl(FilterFun, FilterAcc, [PF | Tail], Acc0, PrimZip, PrimZipOrig) -> #primzip_file{name = F, get_info = GetInfo, get_bin = GetBin} = PF, - case FilterFun({F, GetInfo, GetBin}, FilterAcc) of + try FilterFun({F, GetInfo, GetBin}, FilterAcc) of {Continue, Include, FilterAcc2} -> Acc1 = include_acc(Include, PF, Acc0), case Continue of @@ -103,6 +124,9 @@ do_foldl(FilterFun, FilterAcc, [PF | Tail], Acc0, PrimZip, PrimZipOrig) -> end; FilterRes -> throw({illegal_filter, FilterRes}) + catch + throw:Reason -> + throw({filter_fun_throw, Reason}) end; do_foldl(_FilterFun, FilterAcc, [], Acc, PrimZip, _PrimZipOrig) -> {ok, FilterAcc, PrimZip#primzip{files = reverse(Acc)}}. @@ -121,12 +145,14 @@ include_acc(Include, PF, Acc) -> List when is_list(List) -> %% Add new entries Fun = fun(I, A) -> include_acc(I, PF, A) end, - lists_foldl(Fun, Acc, List) + lists_foldl(Fun, Acc, List); + Bad -> + throw({illegal_filter, Bad}) end. lists_foldl(F, Accu, [Hd|Tail]) -> lists_foldl(F, F(Hd, Accu), Tail); -lists_foldl(F, Accu, []) when is_function(F, 2) -> +lists_foldl(F, Accu, []) when is_function(F, 2) -> Accu. %% close a zip archive @@ -139,7 +165,9 @@ close(_) -> get_zip_input({F, B}) when is_binary(B), is_list(F) -> fun binary_io/2; get_zip_input(F) when is_list(F) -> - fun prim_file_io/2. + fun prim_file_io/2; +get_zip_input(_) -> + throw(einval). %% get a file from the archive get_z_file(F, Offset, ChunkSize, #primzip{zlib = Z, in = In0, input = Input}) -> @@ -218,15 +246,15 @@ get_cd_loop(N, BCD, Acc0, PrimZip, FileName, Offset, CFH, EndOffset, FilterFun, GetInfo = fun() -> cd_file_header_to_file_info(FileName, CFH, <<>>) end, GetBin = fun() -> get_z_file(FileName, Offset, Size, PrimZip) end, PF = #primzip_file{name = FileName, get_info = GetInfo, get_bin = GetBin}, - case FilterFun({FileName, GetInfo, GetBin}, FilterAcc) of + try FilterFun({FileName, GetInfo, GetBin}, FilterAcc) of {Continue, Include, FilterAcc2} -> Acc1 = case Include of - false -> + false -> Acc0; true -> [PF | Acc0]; - {true, Nick} -> + {true, Nick} -> [PF#primzip_file{name = Nick} | Acc0]; {true, Nick, GI, GB} -> PF2 = #primzip_file{name = Nick, get_info = GI, get_bin = GB}, @@ -247,13 +275,16 @@ get_cd_loop(N, BCD, Acc0, PrimZip, FileName, Offset, CFH, EndOffset, FilterFun, end; FilterRes -> throw({illegal_filter, FilterRes}) + catch + throw:Reason -> + throw({filter_fun_throw, Reason}) end. get_file_header(BCD) -> BCFH = case BCD of <<?CENTRAL_FILE_MAGIC:32/little, - B:(?CENTRAL_FILE_HEADER_SZ-4)/binary, + B:(?CENTRAL_FILE_HEADER_SZ-4)/binary, _/binary>> -> B; _ -> @@ -266,11 +297,11 @@ get_file_header(BCD) -> ToGet = FileNameLen + ExtraLen + CommentLen, {B2, BCDRest} = case BCD of - <<_:?CENTRAL_FILE_HEADER_SZ/binary, + <<_:?CENTRAL_FILE_HEADER_SZ/binary, G:ToGet/binary, - Rest/binary>> -> + Rest/binary>> -> {G, Rest}; - _ -> + _ -> throw(bad_central_directory) end, FileName = get_filename_from_b2(B2, FileNameLen, ExtraLen, CommentLen), @@ -319,9 +350,9 @@ prim_file_io({file_info, F}, _) -> end; prim_file_io({open, FN, Opts}, _) -> case ?CATCH prim_file:open(FN, Opts++[binary]) of - {ok, H} -> + {ok, H} -> H; - {error, E} -> + {error, E} -> throw(E) end; prim_file_io({read, N}, H) -> @@ -476,7 +507,7 @@ cd_file_header_to_file_info(FileName, %% FI; % not yet supported, and not widely used add_extra_info(FI, _) -> FI. -%% +%% %% unix_extra_field_and_var_from_bin(<<TSize:16/little, %% ATime:32/little, %% MTime:32/little, @@ -500,7 +531,7 @@ dos_date_time_to_datetime(DosDate, DosTime) -> <<Hour:5, Min:6, Sec:5>> = <<DosTime:16>>, <<YearFrom1980:7, Month:4, Day:5>> = <<DosDate:16>>, {{YearFrom1980+1980, Month, Day}, - {Hour, Min, Sec}}. + {Hour, Min, Sec}}. cd_file_header_from_bin(<<VersionMadeBy:16/little, VersionNeeded:16/little, @@ -622,7 +653,7 @@ reverse(X) -> reverse([H|T], Y) -> reverse(T, [H|Y]); -reverse([], X) -> +reverse([], X) -> X. last([E|Es]) -> last(E, Es). |