diff options
Diffstat (limited to 'lib')
38 files changed, 246 insertions, 592 deletions
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl index c2a6ef604e..0c7bef9183 100644 --- a/lib/compiler/src/beam_z.erl +++ b/lib/compiler/src/beam_z.erl @@ -79,17 +79,9 @@ undo_rename({put_map,Fail,assoc,S,D,R,L}) -> undo_rename({put_map,Fail,exact,S,D,R,L}) -> {put_map_exact,Fail,S,D,R,L}; undo_rename({test,has_map_fields,Fail,[Src|List]}) -> - {test,has_map_fields,Fail,Src,{list,[to_typed_literal(V)||V<-List]}}; -undo_rename({get_map_elements,Fail,Src,{list, List}}) -> - {get_map_elements,Fail,Src,{list,[to_typed_literal(V)||V<-List]}}; + {test,has_map_fields,Fail,Src,{list,List}}; +undo_rename({get_map_elements,Fail,Src,{list,List}}) -> + {get_map_elements,Fail,Src,{list,List}}; undo_rename({select,I,Reg,Fail,List}) -> {I,Reg,Fail,{list,List}}; undo_rename(I) -> I. - -%% to_typed_literal(Arg) -%% transform Arg to specific literal i.e. float | integer | atom if applicable -to_typed_literal({literal, V}) when is_float(V) -> {float, V}; -to_typed_literal({literal, V}) when is_atom(V) -> {atom, V}; -to_typed_literal({literal, V}) when is_integer(V) -> {integer, V}; -to_typed_literal({literal, []}) -> nil; -to_typed_literal(V) -> V. diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 08b1c0d7b7..ba46adfbc6 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -1370,7 +1370,6 @@ eval_is_record(Call, _, _, _, _) -> Call. is_not_integer(#c_literal{val=Val}) when not is_integer(Val) -> true; is_not_integer(#c_tuple{}) -> true; is_not_integer(#c_cons{}) -> true; -is_not_integer(#c_map{}) -> true; is_not_integer(_) -> false. %% is_not_tuple(Core) -> true | false. @@ -1378,7 +1377,6 @@ is_not_integer(_) -> false. is_not_tuple(#c_literal{val=Val}) when not is_tuple(Val) -> true; is_not_tuple(#c_cons{}) -> true; -is_not_tuple(#c_map{}) -> true; is_not_tuple(_) -> false. %% eval_setelement(Call, Pos, Tuple, NewVal) -> Core. diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl index b5408ecd8f..22aa19522d 100644 --- a/lib/compiler/test/andor_SUITE.erl +++ b/lib/compiler/test/andor_SUITE.erl @@ -33,7 +33,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [t_case,t_and_or,t_andalso,t_orelse,inside,overlap, combined,in_case,before_and_inside_if]}]. diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl index 9142ca6485..d2e24cb5ae 100644 --- a/lib/compiler/test/beam_utils_SUITE.erl +++ b/lib/compiler/test/beam_utils_SUITE.erl @@ -32,7 +32,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [apply_fun, apply_mf, bs_init, diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl index 8609a490f5..2433e7621e 100644 --- a/lib/compiler/test/bs_bit_binaries_SUITE.erl +++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl @@ -37,7 +37,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [misc,horrid_match,test_bitstr,test_bit_size, asymmetric_tests,big_asymmetric_tests, binary_to_and_from_list,big_binary_to_and_from_list, diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl index ce39de2a82..9df874c387 100644 --- a/lib/compiler/test/bs_construct_SUITE.erl +++ b/lib/compiler/test/bs_construct_SUITE.erl @@ -39,7 +39,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [two,test1,fail,float_bin,in_guard,in_catch, nasty_literals,side_effect,opt,otp_7556,float_arith, otp_8054]}]. diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index e1710988d8..f7af56afcc 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -48,7 +48,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [fun_shadow,int_float,otp_5269,null_fields,wiger, bin_tail,save_restore,shadowed_size_var, partitioned_bs_match,function_clause,unit, diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index 6a7036d728..6e839f4c6e 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -36,7 +36,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [t_element,setelement,t_length,append,t_apply,bifs, eq,nested_call_in_case,guard_try_catch,coverage, unused_multiple_values_error,unused_multiple_values, diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index 882e2c3f8b..8db47ffa40 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -42,7 +42,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [misc,const_cond,basic_not,complex_not,nested_nots, semicolon,complex_semicolon,comma,or_guard, more_or_guards,complex_or_guards,and_guard,xor_guard, diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl index 1234197cd7..74efed7588 100644 --- a/lib/compiler/test/match_SUITE.erl +++ b/lib/compiler/test/match_SUITE.erl @@ -34,7 +34,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [pmatch,mixed,aliases,match_in_call,untuplify, shortcut_boolean,letify_guard,selectify, underscore,match_map,map_vars_used,coverage]}]. diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index 5416e8b6c7..d721a86f5a 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -60,7 +60,7 @@ all() -> [{group,p}]. groups() -> - [{p,[],%%test_lib:parallel(), + [{p,[], [tobias,empty_string,md5,silly_coverage, confused_literals,integer_encoding,override_bif]}]. diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl index a8befbecd9..e06e42276a 100644 --- a/lib/compiler/test/test_lib.erl +++ b/lib/compiler/test/test_lib.erl @@ -44,6 +44,10 @@ smoke_disasm(File) when is_list(File) -> Res = beam_disasm:file(File), {beam_file,_Mod} = {element(1, Res),element(2, Res)}. +%% If we are running cover, we don't want to run test cases that +%% invokes the compiler in parallel, as doing so would probably +%% be slower than running them sequentially. + parallel() -> case ?t:is_cover() orelse erlang:system_info(schedulers) =:= 1 of true -> []; @@ -90,13 +94,18 @@ get_data_dir(Config) -> %% Will fail the test case if there were any errors. p_run(Test, List) -> + S = erlang:system_info(schedulers), N = case ?t:is_cover() of false -> - erlang:system_info(schedulers); + S + 1; true -> - %% Cover is running. Using more than one process - %% will probably only slow down compilation. - 1 + %% Cover is running. Using too many processes + %% could slow us down. Measurements on my computer + %% showed that using 4 parallel processes was + %% slightly faster than using 3. Using more than + %% 4 would not buy us much and could actually be + %% slower. + max(S, 4) end, p_run_loop(Test, List, N, [], 0, 0). diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl index 4530d08c77..b490257a6e 100644 --- a/lib/compiler/test/trycatch_SUITE.erl +++ b/lib/compiler/test/trycatch_SUITE.erl @@ -35,7 +35,7 @@ all() -> [{group,p}]. groups() -> - [{p,test_lib:parallel(), + [{p,[parallel], [basic,lean_throw,try_of,try_after,catch_oops, after_oops,eclectic,rethrow,nested_of,nested_catch, nested_after,nested_horrid,last_call_optimization, diff --git a/lib/edoc/doc/overview.edoc b/lib/edoc/doc/overview.edoc index 2af425272e..0ced8cab32 100644 --- a/lib/edoc/doc/overview.edoc +++ b/lib/edoc/doc/overview.edoc @@ -76,8 +76,6 @@ The following are the main functions for running EDoc: <ul> <li>{@link edoc:application/2}: Creates documentation for a typical Erlang application.</li> - <li>{@link edoc:packages/2}: Creates documentation for one or - more packages, automatically locating source files.</li> <li>{@link edoc:files/2}: Creates documentation for a specified set of source files.</li> <li>{@link edoc:run/3}: General interface function; the common @@ -184,7 +182,7 @@ The following tags can be used anywhere within a module: path (see {@link edoc:read_source/2}).</dd> <dt><a name="gtag-todo">`@todo' (or `@TODO')</a></dt> - <dd>Attaches a To-Do note to a function, module, package, or + <dd>Attaches a To-Do note to a function, module or overview-page. The content can be any XHTML text describing the issue, e.g.: ```%% @TODO Finish writing the documentation.''' @@ -338,7 +336,7 @@ The following tags can be used before a module declaration: <dt><a name="mtag-since">`@since'</a></dt> <dd>Specifies when the module was introduced, with respect to - the application, package, release or distribution it is part + the application, release or distribution it is part of. The content can be arbitrary text.</dd> <dt><a name="mtag-version">`@version'</a></dt> @@ -445,7 +443,6 @@ possible formats for references are: <table border="1" summary="reference syntax"> <tr><th>Reference syntax</th><th>Example</th><th>Scope</th></tr> <tr><td>`Module'</td><td>{@link edoc_run}, `erl.lang.list'</td><td>Global</td></tr> - <tr><td>`Package.*'</td><td>`erl.lang.*'</td><td>Global</td></tr> <tr><td>`Function/Arity'</td><td>`file/2'</td><td>Within module</td></tr> <tr><td>`Module:Function/Arity'</td><td>{@link edoc:application/2}</td><td>Global</td></tr> <tr><td>`Type()'</td><td>`filename()'</td><td>Within module</td></tr> @@ -531,7 +528,7 @@ after the empty line into separate paragraphs. For example: ```%% @doc This will all be part of the first paragraph. %% It can stretch over several lines and contain <em>any %% XHTML markup</em>. - %% + %% %% This is the second paragraph. The above line is %% regarded as "empty" by EDoc, even though it ends with %% a space.''' @@ -685,17 +682,6 @@ information. User-defined macros override predefined macros. <dd>Expands to the current date, as "<tt>Month Day Year</tt>", e.g. "{@date}".</dd> - <dt><a name="predefmacro-docRoot"><code>@{@docRoot}</code></a></dt> - <dd>Expands to the relative URL path (such as - `"../../.."') from the current page to the root - directory of the generated documentation. This can be used to - create XHTML references such as `<img - src="@{@docRoot}/images/logo.jpeg">' that are independent of how - deep down in a package structure they occur. If packages are not - used (i.e., if all modules are in the "empty" package), - <code>@{@docRoot}</code> will always resolve to the empty - string.</dd> - <dt><a name="predefmacro-link"><code>@{@link <em>reference</em>. <em>description</em>}</code></a></dt> <dd>This creates a hypertext link; cf. the @@ -710,9 +696,6 @@ information. User-defined macros override predefined macros. <dd>Expands to the name of the current module. Only defined when a module is being processed.</dd> - <dt><a name="predefmacro-package"><code>@{@package}</code></a></dt> - <dd>Expands to the name of the current package.</dd> - <dt><a name="predefmacro-section"><code>@{@section <em>heading</em>}</code></a></dt> <dd>Expands to a hypertext link to the specified section heading; diff --git a/lib/edoc/include/edoc_doclet.hrl b/lib/edoc/include/edoc_doclet.hrl index 60ec7f44e4..ac6763fb33 100644 --- a/lib/edoc/include/edoc_doclet.hrl +++ b/lib/edoc/include/edoc_doclet.hrl @@ -1,6 +1,6 @@ %% ===================================================================== %% Header file for EDoc doclet modules. -%% +%% %% Copyright (C) 2001-2004 Richard Carlsson %% %% This library is free software; you can redistribute it and/or modify @@ -43,16 +43,11 @@ %% @type doclet_gen() = #doclet_gen{sources = [string()], %% app = no_app() | atom(), -%% packages = [atom()], -%% modules = [atom()], -%% modules = [atom()], -%% filemap = function()} +%% modules = [atom()]} -record(doclet_gen, {sources = [], app = ?NO_APP, - packages = [], - modules = [], - filemap + modules = [] }). %% @type doclet_toc() = #doclet_gen{paths = [string()], diff --git a/lib/edoc/priv/edoc.dtd b/lib/edoc/priv/edoc.dtd index ba4ac0db28..4278a9e643 100644 --- a/lib/edoc/priv/edoc.dtd +++ b/lib/edoc/priv/edoc.dtd @@ -2,20 +2,13 @@ <!-- EDoc DTD Version 0.3 --> <!ELEMENT overview (title, description?, author*, copyright?, version?, - since?, see*, reference*, todo?, packages, modules)> + since?, see*, reference*, todo?, modules)> <!ATTLIST overview root CDATA #IMPLIED encoding CDATA #IMPLIED> <!ELEMENT title (#PCDATA)> -<!ELEMENT package (description?, author*, copyright?, version?, - since?, deprecated?, see*, reference*, todo?, - modules)> -<!ATTLIST package - name CDATA #REQUIRED - root CDATA #IMPLIED> - <!ELEMENT modules (module+)> diff --git a/lib/edoc/priv/stylesheet.css b/lib/edoc/priv/stylesheet.css index e426a90483..ab170c091f 100644 --- a/lib/edoc/priv/stylesheet.css +++ b/lib/edoc/priv/stylesheet.css @@ -27,10 +27,10 @@ div.spec { margin-left: 2em; background-color: #eeeeee; } -a.module,a.package { +a.module { text-decoration:none } -a.module:hover,a.package:hover { +a.module:hover { background-color: #eeeeee; } ul.definitions { diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl index 983f04e8b6..78915e8943 100644 --- a/lib/edoc/src/edoc.erl +++ b/lib/edoc/src/edoc.erl @@ -24,12 +24,11 @@ %% TODO: option for ignoring functions matching some pattern ('..._test_'/0) %% TODO: @private_type tag, opaque unless generating private docs? %% TODO: document the record type syntax -%% TODO: some 'skip' option for ignoring particular modules/packages? -%% TODO: intermediate-level packages: document even if no local sources. +%% TODO: some 'skip' option for ignoring particular modules? %% TODO: multiline comment support (needs modified comment representation) %% TODO: config-file for default settings %% TODO: config: locations of all local docdirs; generate local doc-index page -%% TODO: config: URL:s of offline packages/apps +%% TODO: config: URL:s of offline apps %% TODO: config: default stylesheet %% TODO: config: default header/footer, etc. %% TODO: offline linkage @@ -45,10 +44,10 @@ -module(edoc). --export([packages/1, packages/2, files/1, files/2, +-export([files/1, files/2, application/1, application/2, application/3, toc/1, toc/2, toc/3, - run/3, + run/2, file/1, file/2, read/1, read/2, layout/1, layout/2, @@ -68,15 +67,15 @@ file(Name) -> file(Name, []). -%% @spec file(filename(), proplist()) -> ok +%% @spec file(filename(), proplist()) -> ok %% %% @type filename() = //kernel/file:filename() %% @type proplist() = [term()] %% %% @deprecated This is part of the old interface to EDoc and is mainly %% kept for backwards compatibility. The preferred way of generating -%% documentation is through one of the functions {@link application/2}, -%% {@link packages/2} and {@link files/2}. +%% documentation is through one of the functions {@link application/2} +%% and {@link files/2}. %% %% @doc Reads a source code file and outputs formatted documentation to %% a corresponding file. @@ -121,44 +120,24 @@ file(Name, Options) -> ?DEFAULT_FILE_SUFFIX), Dir = proplists:get_value(dir, Options, filename:dirname(Name)), Encoding = [{encoding, edoc_lib:read_encoding(Name, [])}], - edoc_lib:write_file(Text, Dir, BaseName ++ Suffix, '', Encoding). + edoc_lib:write_file(Text, Dir, BaseName ++ Suffix, Encoding). -%% TODO: better documentation of files/1/2, packages/1/2, application/1/2/3 +%% TODO: better documentation of files/1/2, application/1/2/3 -%% @spec (Files::[filename() | {package(), [filename()]}]) -> ok -%% @equiv packages(Packages, []) +%% @spec (Files::[filename()]) -> ok files(Files) -> files(Files, []). -%% @spec (Files::[filename() | {package(), [filename()]}], +%% @spec (Files::[filename()], %% Options::proplist()) -> ok -%% @doc Runs EDoc on a given set of source files. See {@link run/3} for +%% @doc Runs EDoc on a given set of source files. See {@link run/2} for %% details, including options. %% @equiv run([], Files, Options) files(Files, Options) -> - run([], Files, Options). - -%% @spec (Packages::[package()]) -> ok -%% @equiv packages(Packages, []) - -packages(Packages) -> - packages(Packages, []). - -%% @spec (Packages::[package()], Options::proplist()) -> ok -%% @type package() = atom() | string() -%% -%% @doc Runs EDoc on a set of packages. The `source_path' option is used -%% to locate the files; see {@link run/3} for details, including -%% options. This function automatically appends the current directory to -%% the source path. -%% -%% @equiv run(Packages, [], Options) - -packages(Packages, Options) -> - run(Packages, [], Options ++ [{source_path, [?CURRENT_DIR]}]). + run(Files, Options). %% @spec (Application::atom()) -> ok %% @equiv application(Application, []) @@ -194,7 +173,7 @@ application(App, Options) when is_atom(App) -> %% subdirectory, if it exists, or otherwise in the application %% directory itself. %% </li> -%% <li>The {@link run/3. `subpackages'} option is turned on. All found +%% <li>The {@link run/2. `subpackages'} option is turned on. All found %% source files will be processed. %% </li> %% <li>The `include' subdirectory is automatically added to the @@ -203,7 +182,7 @@ application(App, Options) when is_atom(App) -> %% </li> %% </ul> %% -%% See {@link run/3} for details, including options. +%% See {@link run/2} for details, including options. %% %% @see application/2 @@ -219,7 +198,7 @@ application(App, Dir, Options) when is_atom(App) -> {includes, [filename:join(Dir, "include")]}], Opts1 = set_app_default(App, Dir, Opts), %% Recursively document all subpackages of '' - i.e., everything. - run([''], [], [{application, App} | Opts1]). + run([], [{application, App} | Opts1]). %% Try to set up a default application base URI in a smart way if the %% user has not specified it explicitly. @@ -240,31 +219,20 @@ set_app_default(App, Dir0, Opts) -> Opts end. -%% If no source files are found for a (specified) package, no package -%% documentation will be generated either (even if there is a -%% package-documentation file). This is the way it should be. For -%% specified files, use empty package (unless otherwise specified). The -%% assumed package is always used for creating the output. If the actual -%% module or package of the source differs from the assumption gathered -%% from the path and file name, a warning should be issued (since links -%% are likely to be incorrect). - opt_defaults() -> - [packages]. + []. opt_negations() -> [{no_preprocess, preprocess}, {no_subpackages, subpackages}, - {no_report_missing_types, report_missing_types}, - {no_packages, packages}]. + {no_report_missing_types, report_missing_types}]. -%% @spec run(Packages::[package()], -%% Files::[filename() | {package(), [filename()]}], +%% @spec run(Files::[filename()], %% Options::proplist()) -> ok -%% @doc Runs EDoc on a given set of source files and/or packages. Note +%% @doc Runs EDoc on a given set of source files. Note %% that the doclet plugin module has its own particular options; see the %% `doclet' option below. -%% +%% %% Also see {@link layout/2} for layout-related options, and %% {@link get_doc/2} for options related to reading source %% files. @@ -298,11 +266,6 @@ opt_negations() -> %% The default doclet module is {@link edoc_doclet}; see {@link %% edoc_doclet:run/2} for doclet-specific options. %% </dd> -%% <dt>{@type {exclude_packages, [package()]@}} -%% </dt> -%% <dd>Lists packages to be excluded from the documentation. Typically -%% used in conjunction with the `subpackages' option. -%% </dd> %% <dt>{@type {file_suffix, string()@}} %% </dt> %% <dd>Specifies the suffix used for output files. The default value is @@ -314,22 +277,6 @@ opt_negations() -> %% target directory will be ignored and overwritten. The default %% value is `false'. %% </dd> -%% <dt>{@type {packages, boolean()@}} -%% </dt> -%% <dd>If the value is `true', it it assumed that packages (module -%% namespaces) are being used, and that the source code directory -%% structure reflects this. The default value is `true'. (Usually, -%% this does the right thing even if all the modules belong to the -%% top-level "empty" package.) `no_packages' is an alias for -%% `{packages, false}'. See the `subpackages' option below for -%% further details. -%% -%% If the source code is organized in a hierarchy of -%% subdirectories although it does not use packages, use -%% `no_packages' together with the recursive-search `subpackages' -%% option (on by default) to automatically generate documentation -%% for all the modules. -%% </dd> %% <dt>{@type {source_path, [filename()]@}} %% </dt> %% <dd>Specifies a list of file system paths used to locate the source @@ -345,7 +292,7 @@ opt_negations() -> %% <dd>If the value is `true', all subpackages of specified packages %% will also be included in the documentation. The default value is %% `false'. `no_subpackages' is an alias for `{subpackages, -%% false}'. See also the `exclude_packages' option. +%% false}'. %% %% Subpackage source files are found by recursively searching %% for source code files in subdirectories of the known source code @@ -358,38 +305,31 @@ opt_negations() -> %% </dl> %% %% @see files/2 -%% @see packages/2 %% @see application/2 %% NEW-OPTIONS: source_path, application %% INHERIT-OPTIONS: init_context/1 %% INHERIT-OPTIONS: expand_sources/2 %% INHERIT-OPTIONS: target_dir_info/5 -%% INHERIT-OPTIONS: edoc_lib:find_sources/3 +%% INHERIT-OPTIONS: edoc_lib:find_sources/2 %% INHERIT-OPTIONS: edoc_lib:run_doclet/2 %% INHERIT-OPTIONS: edoc_lib:get_doc_env/4 -run(Packages, Files, Opts0) -> +run(Files, Opts0) -> Opts = expand_opts(Opts0), Ctxt = init_context(Opts), Dir = Ctxt#context.dir, Path = proplists:append_values(source_path, Opts), - Ss = sources(Path, Packages, Opts), + Ss = sources(Path, Opts), {Ss1, Ms} = expand_sources(expand_files(Files) ++ Ss, Opts), - Ps = [P || {_, P, _, _} <- Ss1], App = proplists:get_value(application, Opts, ?NO_APP), - {App1, Ps1, Ms1} = target_dir_info(Dir, App, Ps, Ms, Opts), - %% The "empty package" is never included in the list of packages. - Ps2 = edoc_lib:unique(lists:sort(Ps1)) -- [''], + {App1, Ms1} = target_dir_info(Dir, App, Ms, Opts), Ms2 = edoc_lib:unique(lists:sort(Ms1)), - Fs = package_files(Path, Ps2), - Env = edoc_lib:get_doc_env(App1, Ps2, Ms2, Opts), + Env = edoc_lib:get_doc_env(App1, Ms2, Opts), Ctxt1 = Ctxt#context{env = Env}, Cmd = #doclet_gen{sources = Ss1, app = App1, - packages = Ps2, - modules = Ms2, - filemap = Fs + modules = Ms2 }, F = fun (M) -> M:run(Cmd, Ctxt1) @@ -401,42 +341,22 @@ expand_opts(Opts0) -> Opts0 ++ opt_defaults()). %% NEW-OPTIONS: dir -%% DEFER-OPTIONS: run/3 +%% DEFER-OPTIONS: run/2 init_context(Opts) -> #context{dir = proplists:get_value(dir, Opts, ?CURRENT_DIR), opts = Opts }. -%% INHERIT-OPTIONS: edoc_lib:find_sources/3 - -sources(Path, Packages, Opts) -> - lists:foldl(fun (P, Xs) -> - edoc_lib:find_sources(Path, P, Opts) ++ Xs - end, - [], Packages). - -package_files(Path, Packages) -> - Name = ?PACKAGE_FILE, % this is hard-coded for now - D = lists:foldl(fun (P, D) -> - F = edoc_lib:find_file(Path, P, Name), - dict:store(P, F, D) - end, - dict:new(), Packages), - fun (P) -> - case dict:find(P, D) of - {ok, F} -> F; - error -> "" - end - end. +%% INHERIT-OPTIONS: edoc_lib:find_sources/2 + +sources(Path, Opts) -> + edoc_lib:find_sources(Path, Opts). %% Expand user-specified sets of files. -expand_files([{P, Fs1} | Fs]) -> - [{P, filename:basename(F), filename:dirname(F)} || F <- Fs1] - ++ expand_files(Fs); expand_files([F | Fs]) -> - [{'', filename:basename(F), filename:dirname(F)} | + [{filename:basename(F), filename:dirname(F)} | expand_files(Fs)]; expand_files([]) -> []. @@ -444,26 +364,23 @@ expand_files([]) -> %% Create the (assumed) full module names. Keep only the first source %% for each module, but preserve the order of the list. -%% NEW-OPTIONS: source_suffix, packages -%% DEFER-OPTIONS: run/3 +%% NEW-OPTIONS: source_suffix +%% DEFER-OPTIONS: run/2 expand_sources(Ss, Opts) -> Suffix = proplists:get_value(source_suffix, Opts, ?DEFAULT_SOURCE_SUFFIX), - Ss1 = case proplists:get_bool(packages, Opts) of - true -> Ss; - false -> [{'',F,D} || {_P,F,D} <- Ss] - end, + Ss1 = [{F,D} || {F,D} <- Ss], expand_sources(Ss1, Suffix, sets:new(), [], []). -expand_sources([{'', F, D} | Fs], Suffix, S, As, Ms) -> +expand_sources([{F, D} | Fs], Suffix, S, As, Ms) -> M = list_to_atom(filename:rootname(F, Suffix)), case sets:is_element(M, S) of true -> expand_sources(Fs, Suffix, S, As, Ms); false -> S1 = sets:add_element(M, S), - expand_sources(Fs, Suffix, S1, [{M, '', F, D} | As], + expand_sources(Fs, Suffix, S1, [{M, F, D} | As], [M | Ms]) end; expand_sources([], _Suffix, _S, As, Ms) -> @@ -471,16 +388,15 @@ expand_sources([], _Suffix, _S, As, Ms) -> %% NEW-OPTIONS: new -target_dir_info(Dir, App, Ps, Ms, Opts) -> +target_dir_info(Dir, App, Ms, Opts) -> case proplists:get_bool(new, Opts) of true -> - {App, Ps, Ms}; + {App, Ms}; false -> - {App1, Ps1, Ms1} = edoc_lib:read_info_file(Dir), + {App1, Ms1} = edoc_lib:read_info_file(Dir), {if App == ?NO_APP -> App1; true -> App end, - Ps ++ Ps1, Ms ++ Ms1} end. @@ -510,7 +426,7 @@ toc(Dir, Opts) -> toc(Dir, Paths, Opts0) -> Opts = expand_opts(Opts0 ++ [{dir, Dir}]), Ctxt = init_context(Opts), - Env = edoc_lib:get_doc_env('', [], [], Opts), + Env = edoc_lib:get_doc_env('', [], Opts), Ctxt1 = Ctxt#context{env = Env}, F = fun (M) -> M:run(#doclet_toc{paths=Paths}, Ctxt1) @@ -562,7 +478,7 @@ layout(Doc) -> %% </dl> %% %% @see layout/1 -%% @see run/3 +%% @see run/2 %% @see read/2 %% @see file/2 @@ -856,7 +772,7 @@ get_doc(File) -> %% edoc_lib:get_doc_env/4} for further options. %% %% @see get_doc/3 -%% @see run/3 +%% @see run/2 %% @see edoc_extract:source/5 %% @see read/2 %% @see layout/2 diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl index 44c5d6fef4..5b0fb68cf9 100644 --- a/lib/edoc/src/edoc.hrl +++ b/lib/edoc/src/edoc.hrl @@ -1,6 +1,6 @@ %% ===================================================================== %% Header file for EDoc -%% +%% %% Copyright (C) 2001-2004 Richard Carlsson %% %% This library is free software; you can redistribute it and/or modify @@ -25,9 +25,7 @@ -define(APPLICATION, edoc). -define(INFO_FILE, "edoc-info"). --define(PACKAGE_FILE, "package.edoc"). -define(OVERVIEW_FILE, "overview.edoc"). --define(PACKAGE_SUMMARY, "package-summary"). -define(DEFAULT_SOURCE_SUFFIX, ".erl"). -define(DEFAULT_FILE_SUFFIX, ".html"). -define(DEFAULT_DOCLET, edoc_doclet). @@ -65,13 +63,10 @@ %% Environment for generating documentation data -record(env, {module = [], - package = [], root = "", file_suffix, - package_summary, apps, modules, - packages, app_default, macros = [], includes = [] diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl index eceb5cb1bd..b797d74a71 100644 --- a/lib/edoc/src/edoc_data.erl +++ b/lib/edoc/src/edoc_data.erl @@ -26,7 +26,7 @@ -module(edoc_data). --export([module/4, package/4, overview/4, type/2]). +-export([module/4, overview/4, type/2]). -export([hidden_filter/2, get_all_tags/1]). @@ -510,41 +510,14 @@ get_tags(_, []) -> []. type(T, Env) -> xmerl_lib:expand_element({type, [edoc_types:to_xml(T, Env)]}). -%% <!ELEMENT package (description?, author*, copyright?, version?, -%% since?, deprecated?, see*, reference*, todo?, -%% modules)> -%% <!ATTLIST package -%% name CDATA #REQUIRED -%% root CDATA #IMPLIED> -%% <!ELEMENT modules (module+)> - -package(Package, Tags, Env, Opts) -> - Env1 = Env#env{package = Package, - root = edoc_refs:relative_package_path('', Package)}, - xmerl_lib:expand_element(package_1(Package, Tags, Env1, Opts)). - -package_1(Package, Tags, Env, Opts) -> - {package, [{root, Env#env.root}], - ([{packageName, [atom_to_list(Package)]}] - ++ get_doc(Tags) - ++ authors(Tags) - ++ get_copyright(Tags) - ++ get_version(Tags) - ++ get_since(Tags) - ++ get_deprecated(Tags) - ++ sees(Tags, Env) - ++ references(Tags) - ++ todos(Tags, Opts)) - }. - %% <!ELEMENT overview (title, description?, author*, copyright?, version?, -%% since?, see*, reference*, todo?, packages, modules)> +%% since?, see*, reference*, todo?, modules)> %% <!ATTLIST overview %% root CDATA #IMPLIED> %% <!ELEMENT title (#PCDATA)> overview(Title, Tags, Env, Opts) -> - Env1 = Env#env{package = '', + Env1 = Env#env{ root = ""}, xmerl_lib:expand_element(overview_1(Title, Tags, Env1, Opts)). diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl index 5653b5894b..5961ca8cc0 100644 --- a/lib/edoc/src/edoc_doclet.erl +++ b/lib/edoc/src/edoc_doclet.erl @@ -42,9 +42,7 @@ -define(DEFAULT_FILE_SUFFIX, ".html"). -define(INDEX_FILE, "index.html"). -define(OVERVIEW_FILE, "overview.edoc"). --define(PACKAGE_SUMMARY, "package-summary.html"). -define(OVERVIEW_SUMMARY, "overview-summary.html"). --define(PACKAGES_FRAME, "packages-frame.html"). -define(MODULES_FRAME, "modules-frame.html"). -define(STYLESHEET, "stylesheet.css"). -define(IMAGE, "erlang.png"). @@ -52,11 +50,10 @@ -include_lib("xmerl/include/xmerl.hrl"). -%% Sources is the list of inputs in the order they were found. Packages -%% and Modules are sorted lists of atoms without duplicates. (They +%% Sources is the list of inputs in the order they were found. +%% Modules are sorted lists of atoms without duplicates. (They %% usually include the data from the edoc-info file in the target -%% directory, if it exists.) Note that the "empty package" is never -%% included in Packages! +%% directory, if it exists.) %% @spec (Command::doclet_gen() | doclet_toc(), edoc_context()) -> ok %% @doc Main doclet entry point. See the file <a @@ -117,14 +114,12 @@ run(#doclet_gen{}=Cmd, Ctxt) -> gen(Cmd#doclet_gen.sources, Cmd#doclet_gen.app, - Cmd#doclet_gen.packages, Cmd#doclet_gen.modules, - Cmd#doclet_gen.filemap, Ctxt); run(#doclet_toc{}=Cmd, Ctxt) -> toc(Cmd#doclet_toc.paths, Ctxt). -gen(Sources, App, Packages, Modules, FileMap, Ctxt) -> +gen(Sources, App, Modules, Ctxt) -> Dir = Ctxt#context.dir, Env = Ctxt#context.env, Options = Ctxt#context.opts, @@ -132,11 +127,9 @@ gen(Sources, App, Packages, Modules, FileMap, Ctxt) -> CSS = stylesheet(Options), {Modules1, Error} = sources(Sources, Dir, Modules, Env, Options), modules_frame(Dir, Modules1, Title, CSS), - packages(Packages, Dir, FileMap, Env, Options), - packages_frame(Dir, Packages, Title, CSS), overview(Dir, Title, Env, Options), - index_file(Dir, length(Packages) > 1, Title), - edoc_lib:write_info_file(App, Packages, Modules1, Dir), + index_file(Dir, Title), + edoc_lib:write_info_file(App, Modules1, Dir), copy_stylesheet(Dir, Options), copy_image(Dir), %% handle postponed error during processing of source files @@ -182,19 +175,19 @@ sources(Sources, Dir, Modules, Env, Options) -> %% set if it was successful. Errors are just flagged at this stage, %% allowing all source files to be processed even if some of them fail. -source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden, +source({M, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden, Error, Options) -> File = filename:join(Path, Name), case catch {ok, edoc:get_doc(File, Env, Options)} of {ok, {Module, Doc}} -> - check_name(Module, M, P, File), + check_name(Module, M, File), case ((not is_private(Doc)) orelse Private) andalso ((not is_hidden(Doc)) orelse Hidden) of true -> Text = edoc:layout(Doc, Options), Name1 = atom_to_list(M) ++ Suffix, Encoding = [{encoding,encoding(Doc)}], - edoc_lib:write_file(Text, Dir, Name1, P, Encoding), + edoc_lib:write_file(Text, Dir, Name1, Encoding), {sets:add_element(Module, Set), Error}; false -> {Set, Error} @@ -204,8 +197,7 @@ source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden, {Set, true} end. -check_name(M, M0, P0, File) -> - P = '', +check_name(M, M0, File) -> N = M, N0 = M0, case N of @@ -222,47 +214,12 @@ check_name(M, M0, P0, File) -> ok end end, - if P =/= P0 -> - warning("file '~ts' belongs to package '~s', not '~s'.", - [File, P, P0]); - true -> - ok - end. - - -%% Generating the summary files for packages. - -%% INHERIT-OPTIONS: read_file/4 -%% INHERIT-OPTIONS: edoc_lib:run_layout/2 - -packages(Packages, Dir, FileMap, Env, Options) -> - lists:foreach(fun (P) -> - package(P, Dir, FileMap, Env, Options) - end, - Packages). - -package(P, Dir, FileMap, Env, Opts) -> - Tags = case FileMap(P) of - "" -> - []; - File -> - read_file(File, package, Env, Opts) - end, - Data = edoc_data:package(P, Tags, Env, Opts), - F = fun (M) -> - M:package(Data, Opts) - end, - Text = edoc_lib:run_layout(F, Opts), - edoc_lib:write_file(Text, Dir, ?PACKAGE_SUMMARY, P). - + ok. %% Creating an index file, with some frames optional. %% TODO: get rid of frames, or change doctype to Frameset -index_file(Dir, Packages, Title) -> - Frame1 = {frame, [{src,?PACKAGES_FRAME}, - {name,"packagesFrame"},{title,""}], - []}, +index_file(Dir, Title) -> Frame2 = {frame, [{src,?MODULES_FRAME}, {name,"modulesFrame"},{title,""}], []}, @@ -270,16 +227,7 @@ index_file(Dir, Packages, Title) -> {name,"overviewFrame"},{title,""}], []}, Frameset = {frameset, [{cols,"20%,80%"}], - case Packages of - true -> - [?NL, - {frameset, [{rows,"30%,70%"}], - [?NL, Frame1, ?NL, Frame2, ?NL]} - ]; - false -> - [?NL, Frame2, ?NL] - end - ++ [?NL, Frame3, ?NL, + [?NL, Frame2, ?NL, ?NL, Frame3, ?NL, {noframes, [?NL, {h2, ["This page uses frames"]}, @@ -296,24 +244,6 @@ index_file(Dir, Packages, Title) -> Text = xmerl:export_simple([XML], xmerl_html, []), edoc_lib:write_file(Text, Dir, ?INDEX_FILE). -packages_frame(Dir, Ps, Title, CSS) -> - Body = [?NL, - {h2, [{class, "indextitle"}], ["Packages"]}, - ?NL, - {table, [{width, "100%"}, {border, 0}, - {summary, "list of packages"}], - lists:concat( - [[?NL, - {tr, [{td, [], [{a, [{href, package_ref(P)}, - {target,"overviewFrame"}, - {class, "package"}], - [atom_to_list(P)]}]}]}] - || P <- Ps])}, - ?NL], - XML = xhtml(Title, CSS, Body), - Text = xmerl:export_simple([XML], xmerl_html, []), - edoc_lib:write_file(Text, Dir, ?PACKAGES_FRAME). - modules_frame(Dir, Ms, Title, CSS) -> Body = [?NL, {h2, [{class, "indextitle"}], ["Modules"]}, @@ -334,11 +264,7 @@ modules_frame(Dir, Ms, Title, CSS) -> edoc_lib:write_file(Text, Dir, ?MODULES_FRAME). module_ref(M) -> - edoc_refs:relative_package_path(M, '') ++ ?DEFAULT_FILE_SUFFIX. - -package_ref(P) -> - edoc_lib:join_uri(edoc_refs:relative_package_path(P, ''), - ?PACKAGE_SUMMARY). + atom_to_list(M) ++ ?DEFAULT_FILE_SUFFIX. xhtml(Title, CSS, Content) -> xhtml_1(Title, CSS, {body, [{bgcolor, "white"}], Content}). @@ -372,7 +298,7 @@ overview(Dir, Title, Env, Opts) -> end, Text = edoc_lib:run_layout(F, Opts), EncOpts = [{encoding,Encoding}], - edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY, '', EncOpts). + edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY, EncOpts). copy_image(Dir) -> case code:priv_dir(?EDOC_APP) of @@ -505,7 +431,7 @@ app_index_file(Paths, Dir, Env, Options) -> % Priv = proplists:get_bool(private, Options), CSS = stylesheet(Options), Apps1 = [{filename:dirname(A),filename:basename(A)} || A <- Paths], - index_file(Dir, false, Title), + index_file(Dir, Title), application_frame(Dir, Apps1, Title, CSS), modules_frame(Dir, [], Title, CSS), overview(Dir, Title, Env, Options), diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl index 67a95e80aa..a2a1a6b718 100644 --- a/lib/edoc/src/edoc_extract.erl +++ b/lib/edoc/src/edoc_extract.erl @@ -121,10 +121,8 @@ source1(Tree, File0, Env, Opts, TypeDocs) -> Module = get_module_info(Tree, File), {Header, Footer, Entries} = collect(Forms, Module), Name = Module#module.name, - Package = '', Env1 = Env#env{module = Name, - package = Package, - root = edoc_refs:relative_package_path('', Package)}, + root = ""}, Env2 = add_macro_defs(module_macros(Env1), Opts, Env1), Entries1 = get_tags([Header, Footer | Entries], Env2, File, TypeDocs), Entries2 = edoc_specs:add_data(Entries1, Opts, File, Module), @@ -218,7 +216,7 @@ add_macro_defs(Defs0, Opts, Env) -> %% @spec file(File::filename(), Context, Env::edoc_env(), %% Options::proplist()) -> {ok, Tags} | {error, Reason} -%% Context = overview | package +%% Context = overview %% Tags = [term()] %% Reason = term() %% @@ -249,7 +247,7 @@ file(File, Context, Env, Opts) -> %% @spec (Text::string(), Context, Env::edoc_env(), %% Options::proplist()) -> Tags -%% Context = overview | package +%% Context = overview %% Tags = [term()] %% %% @doc Returns the list of tags in the text. Any lines of text before diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl index 36d067d9bc..6309e88475 100644 --- a/lib/edoc/src/edoc_layout.erl +++ b/lib/edoc/src/edoc_layout.erl @@ -27,7 +27,7 @@ -module(edoc_layout). --export([module/2, package/2, overview/2, type/1]). +-export([module/2, overview/2, type/1]). -import(edoc_report, [report/2]). @@ -978,9 +978,6 @@ get_text(Name, Es) -> local_label(R) -> "#" ++ R. -xhtml(Title, CSS, Body) -> - xhtml(Title, CSS, Body, "latin1"). - xhtml(Title, CSS, Body, Encoding) -> EncString = case Encoding of "latin1" -> "ISO-8859-1"; @@ -1010,27 +1007,6 @@ type(E, Ds) -> xmerl:export_simple_content(t_utype_elem(E) ++ local_defs(Ds, Opts), ?HTML_EXPORT). -package(E=#xmlElement{name = package, content = Es}, Options) -> - Opts = init_opts(E, Options), - Name = get_text(packageName, Es), - Title = ["Package ", Name], - Desc = get_content(description, Es), -% ShortDesc = get_content(briefDescription, Desc), - FullDesc = get_content(fullDescription, Desc), - Body = ([?NL, {h1, [Title]}, ?NL] -% ++ ShortDesc - ++ copyright(Es) - ++ deprecated(Es, "package") - ++ version(Es) - ++ since(Es) - ++ authors(Es) - ++ references(Es) - ++ sees(Es) - ++ todos(Es) - ++ FullDesc), - XML = xhtml(Title, stylesheet(Opts), Body), - xmerl:export_simple(XML, ?HTML_EXPORT, []). - overview(E=#xmlElement{name = overview, content = Es}, Options) -> Opts = init_opts(E, Options), Title = [get_text(title, Es)], diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl index c46338a2e1..813fcf2476 100644 --- a/lib/edoc/src/edoc_lib.erl +++ b/lib/edoc/src/edoc_lib.erl @@ -29,9 +29,9 @@ get_first_sentence/1, is_space/1, strip_space/1, parse_expr/2, parse_contact/2, escape_uri/1, join_uri/2, is_relative_uri/1, is_name/1, to_label/1, find_doc_dirs/0, find_sources/2, - find_sources/3, find_file/3, try_subdir/2, unique/1, - write_file/3, write_file/4, write_file/5, write_info_file/4, - read_info_file/1, get_doc_env/1, get_doc_env/4, copy_file/2, + find_file/2, try_subdir/2, unique/1, + write_file/3, write_file/4, write_info_file/3, + read_info_file/1, get_doc_env/1, get_doc_env/3, copy_file/2, uri_get/1, run_doclet/2, run_layout/2, simplify_path/1, timestr/1, datestr/1, read_encoding/2]). @@ -266,13 +266,6 @@ is_name_1([$_ | Cs]) -> is_name_1([]) -> true; is_name_1(_) -> false. -to_atom(A) when is_atom(A) -> A; -to_atom(S) when is_list(S) -> list_to_atom(S). - -to_list(A) when is_atom(A) -> atom_to_list(A); -to_list(S) when is_list(S) -> S. - - %% @private unique([X | Xs]) -> [X | unique(Xs, X)]; unique([]) -> []. @@ -674,7 +667,7 @@ simplify_path(P) -> try_subdir(Dir, Subdir) -> D = filename:join(Dir, Subdir), case filelib:is_dir(D) of - true -> D; + true -> D; false -> Dir end. @@ -686,19 +679,10 @@ try_subdir(Dir, Subdir) -> %% @private write_file(Text, Dir, Name) -> - write_file(Text, Dir, Name, ''). - -%% @spec (Text::deep_string(), Dir::edoc:filename(), -%% Name::edoc:filename(), Package::atom()|string()) -> ok -%% @doc Like {@link write_file/3}, but adds path components to the target -%% directory corresponding to the specified package. -%% @private + write_file(Text, Dir, Name, [{encoding,latin1}]). -write_file(Text, Dir, Name, Package) -> - write_file(Text, Dir, Name, Package, [{encoding,latin1}]). - -write_file(Text, Dir, Name, Package, Options) -> - File = filename:join([Dir, to_list(Package), Name]), +write_file(Text, Dir, Name, Options) -> + File = filename:join([Dir, Name]), ok = filelib:ensure_dir(File), case file:open(File, [write] ++ Options) of {ok, FD} -> @@ -711,15 +695,14 @@ write_file(Text, Dir, Name, Package, Options) -> end. %% @private -write_info_file(App, Packages, Modules, Dir) -> - Ts = [{packages, Packages}, - {modules, Modules}], +write_info_file(App, Modules, Dir) -> + Ts = [{modules, Modules}], Ts1 = if App =:= ?NO_APP -> Ts; true -> [{application, App} | Ts] end, S0 = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1], S = ["%% encoding: UTF-8\n" | S0], - write_file(S, Dir, ?INFO_FILE, '', [{encoding,unicode}]). + write_file(S, Dir, ?INFO_FILE, [{encoding,unicode}]). %% @spec (Name::edoc:filename()) -> {ok, string()} | {error, Reason} %% @@ -744,9 +727,8 @@ read_file(File) -> info_file_data(Ts) -> App = proplists:get_value(application, Ts, ?NO_APP), - Ps = proplists:append_values(packages, Ts), Ms = proplists:append_values(modules, Ts), - {App, Ps, Ms}. + {App, Ms}. %% Local file access - don't complain if file does not exist. @@ -761,10 +743,10 @@ read_info_file(Dir) -> {error, R} -> R1 = file:format_error(R), warning("could not read '~ts': ~ts.", [File, R1]), - {?NO_APP, [], []} - end; + {?NO_APP, []} + end; false -> - {?NO_APP, [], []} + {?NO_APP, []} end. %% URI access @@ -776,7 +758,7 @@ uri_get_info_file(Base) -> parse_info_file(Text, URI); {error, Msg} -> warning("could not read '~ts': ~ts.", [URI, Msg]), - {?NO_APP, [], []} + {?NO_APP, []} end. parse_info_file(Text, Name) -> @@ -785,10 +767,10 @@ parse_info_file(Text, Name) -> info_file_data(Vs); {error, eof} -> warning("unexpected end of file in '~ts'.", [Name]), - {?NO_APP, [], []}; + {?NO_APP, []}; {error, {_Line,Module,R}} -> warning("~ts: ~ts.", [Module:format_error(R), Name]), - {?NO_APP, [], []} + {?NO_APP, []} end. parse_terms(Text) -> @@ -815,82 +797,67 @@ parse_terms_1([], _As, _Vs) -> %% --------------------------------------------------------------------- -%% Source files and packages - -%% @private -find_sources(Path, Opts) -> - find_sources(Path, "", Opts). +%% Source files -%% @doc See {@link edoc:run/3} for a description of the options -%% `subpackages', `source_suffix' and `exclude_packages'. +%% @doc See {@link edoc:run/2} for a description of the options +%% `subpackages', `source_suffix'. %% @private -%% NEW-OPTIONS: subpackages, source_suffix, exclude_packages -%% DEFER-OPTIONS: edoc:run/3 +%% NEW-OPTIONS: subpackages, source_suffix +%% DEFER-OPTIONS: edoc:run/2 -find_sources(Path, Pkg, Opts) -> +find_sources(Path, Opts) -> Rec = proplists:get_bool(subpackages, Opts), Ext = proplists:get_value(source_suffix, Opts, ?DEFAULT_SOURCE_SUFFIX), - find_sources(Path, Pkg, Rec, Ext, Opts). + find_sources(Path, Rec, Ext, Opts). -find_sources(Path, Pkg, Rec, Ext, Opts) -> - Skip = proplists:get_value(exclude_packages, Opts, []), - lists:flatten(find_sources_1(Path, to_atom(Pkg), Rec, Ext, Skip)). +find_sources(Path, Rec, Ext, _Opts) -> + lists:flatten(find_sources_1(Path, Rec, Ext)). -find_sources_1([P | Ps], Pkg, Rec, Ext, Skip) -> - Dir = filename:join(P, atom_to_list(Pkg)), - Fs1 = find_sources_1(Ps, Pkg, Rec, Ext, Skip), +find_sources_1([P | Ps], Rec, Ext) -> + Dir = P, + Fs1 = find_sources_1(Ps, Rec, Ext), case filelib:is_dir(Dir) of true -> - [find_sources_2(Dir, Pkg, Rec, Ext, Skip) | Fs1]; + [find_sources_2(Dir, Rec, Ext) | Fs1]; false -> Fs1 end; -find_sources_1([], _Pkg, _Rec, _Ext, _Skip) -> +find_sources_1([], _Rec, _Ext) -> []. -find_sources_2(Dir, Pkg, Rec, Ext, Skip) -> - case lists:member(Pkg, Skip) of - false -> - Es = list_dir(Dir, false), % just warn if listing fails - Es1 = [{Pkg, E, Dir} || E <- Es, is_source_file(E, Ext)], - case Rec of +find_sources_2(Dir, Rec, Ext) -> + Es = list_dir(Dir, false), % just warn if listing fails + Es1 = [{E, Dir} || E <- Es, is_source_file(E, Ext)], + case Rec of true -> - [find_sources_3(Es, Dir, Pkg, Rec, Ext, Skip) | Es1]; + [find_sources_3(Es, Dir, Rec, Ext) | Es1]; false -> - Es1 - end; - true -> - [] - end. + Es1 + end. -find_sources_3(Es, Dir, Pkg, Rec, Ext, Skip) -> +find_sources_3(Es, Dir, Rec, Ext) -> [find_sources_2(filename:join(Dir, E), - to_atom(join(Pkg, E)), Rec, Ext, Skip) - || E <- Es, is_package_dir(E, Dir)]. - -join('', E) -> E; -join(Pkg, E) -> filename:join(Pkg, E). + Rec, Ext) + || E <- Es, is_source_dir(E, Dir)]. is_source_file(Name, Ext) -> (filename:extension(Name) == Ext) andalso is_name(filename:rootname(Name, Ext)). -is_package_dir(Name, Dir) -> - is_name(filename:rootname(filename:basename(Name))) - andalso filelib:is_dir(filename:join(Dir, Name)). +is_source_dir(Name, Dir) -> + filelib:is_dir(filename:join(Dir, Name)). %% @private -find_file([P | Ps], []=Pkg, Name) -> - Pkg = [], +find_file([P | Ps], Name) -> File = filename:join(P, Name), case filelib:is_file(File) of true -> - File; + File; false -> - find_file(Ps, Pkg, Name) - end; -find_file([], [], _Name) -> + find_file(Ps, Name) + end; +find_file([], _Name) -> "". %% @private @@ -909,7 +876,7 @@ find_doc_dirs([P0 | Ps]) -> File = filename:join(Dir, ?INFO_FILE), case filelib:is_file(File) of true -> - [Dir | find_doc_dirs(Ps)]; + [Dir | find_doc_dirs(Ps)]; false -> find_doc_dirs(Ps) end; @@ -923,22 +890,21 @@ find_doc_dirs([]) -> %% NEW-OPTIONS: doc_path %% DEFER-OPTIONS: get_doc_env/4 -get_doc_links(App, Packages, Modules, Opts) -> +get_doc_links(App, Modules, Opts) -> Path = proplists:append_values(doc_path, Opts) ++ find_doc_dirs(), Ds = [{P, uri_get_info_file(P)} || P <- Path], - Ds1 = [{"", {App, Packages, Modules}} | Ds], + Ds1 = [{"", {App, Modules}} | Ds], D = dict:new(), - make_links(Ds1, D, D, D). + make_links(Ds1, D, D). -make_links([{Dir, {App, Ps, Ms}} | Ds], A, P, M) -> +make_links([{Dir, {App, Ms}} | Ds], A, M) -> A1 = if App == ?NO_APP -> A; true -> add_new(App, Dir, A) end, F = fun (K, D) -> add_new(K, Dir, D) end, - P1 = lists:foldl(F, P, Ps), M1 = lists:foldl(F, M, Ms), - make_links(Ds, A1, P1, M1); -make_links([], A, P, M) -> + make_links(Ds, A1, M1); +make_links([], A, M) -> F = fun (D) -> fun (K) -> case dict:find(K, D) of @@ -947,7 +913,7 @@ make_links([], A, P, M) -> end end end, - {F(A), F(P), F(M)}. + {F(A), F(M)}. add_new(K, V, D) -> case dict:is_key(K, D) of @@ -962,11 +928,10 @@ add_new(K, V, D) -> %% @private get_doc_env(Opts) -> - get_doc_env([], [], [], Opts). + get_doc_env([], [], Opts). -%% @spec (App, Packages, Modules, Options::proplist()) -> edoc_env() +%% @spec (App, Modules, Options::proplist()) -> edoc_env() %% App = [] | atom() -%% Packages = [atom()] %% Modules = [atom()] %% proplist() = [term()] %% @@ -985,17 +950,15 @@ get_doc_env(Opts) -> %% INHERIT-OPTIONS: get_doc_links/4 %% DEFER-OPTIONS: edoc:run/3 -get_doc_env(App, Packages, Modules, Opts) -> +get_doc_env(App, Modules, Opts) -> Suffix = proplists:get_value(file_suffix, Opts, ?DEFAULT_FILE_SUFFIX), AppDefault = proplists:get_value(app_default, Opts, ?APP_DEFAULT), Includes = proplists:append_values(includes, Opts), - {A, P, M} = get_doc_links(App, Packages, Modules, Opts), + {A, M} = get_doc_links(App, Modules, Opts), #env{file_suffix = Suffix, - package_summary = ?PACKAGE_SUMMARY ++ Suffix, apps = A, - packages = P, modules = M, app_default = AppDefault, includes = Includes diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl index 8efbfd00c7..bdcb3fe81f 100644 --- a/lib/edoc/src/edoc_macros.erl +++ b/lib/edoc/src/edoc_macros.erl @@ -40,10 +40,6 @@ std_macros(Env) -> true -> [{module, atom_to_list(Env#env.module)}] end ++ - if Env#env.package =:= [] -> []; - true -> [{package, atom_to_list(Env#env.package)}] - end - ++ [{date, fun date_macro/3}, {docRoot, Env#env.root}, {link, fun link_macro/3}, diff --git a/lib/edoc/src/edoc_parser.yrl b/lib/edoc/src/edoc_parser.yrl index c6f8a04775..48c01c8dce 100644 --- a/lib/edoc/src/edoc_parser.yrl +++ b/lib/edoc/src/edoc_parser.yrl @@ -28,7 +28,7 @@ Nonterminals start spec func_type utype_list utype_tuple utypes utype ptypes ptype nutype function_name where_defs defs defs2 def typedef etype -throws qname ref aref mref lref pref var_list vars fields field +throws qname ref aref mref lref var_list vars fields field utype_map utype_map_fields utype_map_field futype_list bin_base_type bin_unit_type. @@ -207,14 +207,11 @@ typedef -> atom var_list '=' utype where_defs: ref -> aref: '$1'. ref -> mref: '$1'. ref -> lref: '$1'. -ref -> pref: '$1'. aref -> '//' atom: edoc_refs:app(tok_val('$2')). aref -> '//' atom '/' mref: edoc_refs:app(tok_val('$2'), '$4'). -aref -> '//' atom '/' pref: - edoc_refs:app(tok_val('$2'), '$4'). mref -> qname ':' atom '/' integer: edoc_refs:function(qname('$1'), tok_val('$3'), tok_val('$5')). @@ -223,9 +220,6 @@ mref -> qname ':' atom '(' ')': mref -> qname: edoc_refs:module(qname('$1')). -pref -> qname '.' '*': - edoc_refs:package(qname('$1')). - lref -> atom '/' integer: edoc_refs:function(tok_val('$1'), tok_val('$3')). lref -> atom '(' ')': @@ -399,7 +393,7 @@ parse_typedef_1(S, L) -> %% @doc Parses a <a %% href="overview-summary.html#References">reference</a> to a module, -%% package, function, type, or application +%% function, type, or application parse_ref(S, L) -> case edoc_scanner:string(S, L) of diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl index ea439490ed..b9a9391053 100644 --- a/lib/edoc/src/edoc_refs.erl +++ b/lib/edoc/src/edoc_refs.erl @@ -27,10 +27,9 @@ -module(edoc_refs). --export([app/1, app/2, package/1, module/1, module/2, module/3, +-export([app/1, app/2, module/1, module/2, module/3, function/2, function/3, function/4, type/1, type/2, type/3, - to_string/1, to_label/1, get_uri/2, is_top/2, - relative_module_path/2, relative_package_path/2]). + to_string/1, to_label/1, get_uri/2, is_top/2]). -import(edoc_lib, [join_uri/2, escape_uri/1]). @@ -56,9 +55,6 @@ module(M, Ref) -> module(App, M, Ref) -> app(App, module(M, Ref)). -package(P) -> - {package, P}. - function(F, A) -> {function, F, A}. @@ -88,8 +84,6 @@ to_string({module, M}) -> atom_to_list(M) ; to_string({module, M, Ref}) -> atom_to_list(M) ++ ":" ++ to_string(Ref); -to_string({package, P}) -> - atom_to_list(P) ++ ".*"; to_string({function, F, A}) -> atom_to_list(F) ++ "/" ++ integer_to_list(A); to_string({type, T}) -> @@ -111,24 +105,19 @@ get_uri({module, M, Ref}, Env) -> module_ref(M, Env) ++ "#" ++ to_label(Ref); get_uri({module, M}, Env) -> module_ref(M, Env); -get_uri({package, P}, Env) -> - package_ref(P, Env); get_uri(Ref, _Env) -> "#" ++ to_label(Ref). abs_uri({module, M}, Env) -> module_absref(M, Env); abs_uri({module, M, Ref}, Env) -> - module_absref(M, Env) ++ "#" ++ to_label(Ref); -abs_uri({package, P}, Env) -> - package_absref(P, Env). + module_absref(M, Env) ++ "#" ++ to_label(Ref). module_ref(M, Env) -> case (Env#env.modules)(M) of "" -> File = atom_to_list(M) ++ Env#env.file_suffix, - Path = relative_module_path(M, Env#env.package), - join_uri(Path, escape_uri(File)); + escape_uri(File); Base -> join_uri(Base, module_absref(M, Env)) end. @@ -136,19 +125,6 @@ module_ref(M, Env) -> module_absref(M, Env) -> escape_uri(atom_to_list(M)) ++ escape_uri(Env#env.file_suffix). -package_ref(P, Env) -> - case (Env#env.packages)(P) of - "" -> - join_uri(relative_package_path(P, Env#env.package), - escape_uri(Env#env.package_summary)); - Base -> - join_uri(Base, package_absref(P, Env)) - end. - -package_absref(P, Env) -> - join_uri(escape_uri(atom_to_list(P)), - escape_uri(Env#env.package_summary)). - app_ref(A, Env) -> case (Env#env.apps)(A) of "" -> @@ -166,43 +142,3 @@ is_top({app, _App}, _Env) -> is_top(_Ref, _Env) -> false. -%% Each segment of a path must be separately escaped before joining. - -join_segments([S]) -> - escape_uri(S); -join_segments([S | Ss]) -> - join_uri(escape_uri(S), join_segments(Ss)). - -%% 'From' is always the "current package" here: - -%% The empty string is returned if the To module has only one segment, -%% implying a local reference. - -relative_module_path(_To, _From) -> - "". - -relative_package_path(To, From) -> - relative_path([atom_to_list(To)], [atom_to_list(From)]). - -%% This takes two lists of path segments (From, To). Note that an empty -%% string will be returned if the paths are the same. Empty leading -%% segments are stripped from both paths. - -relative_path(Ts, ["" | Fs]) -> - relative_path(Ts, Fs); -relative_path(["" | Ts], Fs) -> - relative_path(Ts, Fs); -relative_path(Ts, Fs) -> - relative_path_1(Ts, Fs). - -relative_path_1([T | Ts], [F | Fs]) when F == T -> - relative_path_1(Ts, Fs); -relative_path_1(Ts, Fs) -> - relative_path_2(Fs, Ts). - -relative_path_2([_F | Fs], Ts) -> - relative_path_2(Fs, [".." | Ts]); -relative_path_2([], []) -> - ""; -relative_path_2([], Ts) -> - join_segments(Ts). diff --git a/lib/edoc/src/edoc_run.erl b/lib/edoc/src/edoc_run.erl index b5a1ef713d..9a569d0879 100644 --- a/lib/edoc/src/edoc_run.erl +++ b/lib/edoc/src/edoc_run.erl @@ -17,7 +17,7 @@ %% @copyright 2003 Richard Carlsson %% @author Richard Carlsson <[email protected]> %% @see edoc -%% @end +%% @end %% ===================================================================== %% @doc Interface for calling EDoc from Erlang startup options. @@ -38,7 +38,7 @@ -module(edoc_run). --export([file/1, application/1, packages/1, files/1, toc/1]). +-export([file/1, application/1, files/1, toc/1]). -compile({no_auto_import,[error/1]}). @@ -92,28 +92,6 @@ files(Args) -> end, run(F). -%% @spec packages([string()]) -> none() -%% -%% @doc Calls {@link edoc:application/2} with the corresponding -%% arguments. The strings in the list are parsed as Erlang constant -%% terms. The list can be either `[Packages]' or `[Packages, Options]'. -%% In the first case {@link edoc:application/1} is called instead. -%% -%% The function call never returns; instead, the emulator is -%% automatically terminated when the call has completed, signalling -%% success or failure to the operating system. - -packages(Args) -> - F = fun () -> - case parse_args(Args) of - [Packages] -> edoc:packages(Packages); - [Packages, Opts] -> edoc:packages(Packages, Opts); - _ -> - invalid_args("edoc_run:packages/1", Args) - end - end, - run(F). - %% @hidden Not official yet toc(Args) -> F = fun () -> @@ -131,8 +109,8 @@ toc(Args) -> %% %% @deprecated This is part of the old interface to EDoc and is mainly %% kept for backwards compatibility. The preferred way of generating -%% documentation is through one of the functions {@link application/1}, -%% {@link packages/1} and {@link files/1}. +%% documentation is through one of the functions {@link application/1} +%% and {@link files/1}. %% %% @doc Calls {@link edoc:file/2} with the corresponding arguments. The %% strings in the list are parsed as Erlang constant terms. The list can diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl index 82a1b72d84..c1c453511a 100644 --- a/lib/edoc/src/edoc_tags.erl +++ b/lib/edoc/src/edoc_tags.erl @@ -42,7 +42,7 @@ %% Name = atom() %% Parser = text | xml | (Text,Line,Where) -> term() %% Flags = [Flag] -%% Flag = module | function | package | overview | single +%% Flag = module | function | overview | single %% %% Note that the pseudo-tag '@clear' is not listed here. %% (Cf. the function 'filter_tags'.) @@ -57,11 +57,11 @@ %% - @category (useless; superseded by keywords or free text search) tags() -> - All = [module,footer,function,package,overview], - [{author, fun parse_contact/4, [module,package,overview]}, - {copyright, text, [module,package,overview,single]}, - {deprecated, xml, [module,function,package,single]}, - {doc, xml, [module,function,package,overview,single]}, + All = [module,footer,function,overview], + [{author, fun parse_contact/4, [module,overview]}, + {copyright, text, [module,overview,single]}, + {deprecated, xml, [module,function,single]}, + {doc, xml, [module,function,overview,single]}, {docfile, fun parse_file/4, All}, {'end', text, All}, {equiv, fun parse_expr/4, [function,single]}, @@ -69,17 +69,17 @@ tags() -> {hidden, text, [module,function,single]}, {param, fun parse_param/4, [function]}, {private, text, [module,function,single]}, - {reference, xml, [module,footer,package,overview]}, + {reference, xml, [module,footer,overview]}, {returns, xml, [function,single]}, - {see, fun parse_see/4, [module,function,package,overview]}, - {since, text, [module,function,package,overview,single]}, + {see, fun parse_see/4, [module,function,overview]}, + {since, text, [module,function,overview,single]}, {spec, fun parse_spec/4, [function,single]}, {throws, fun parse_throws/4, [function,single]}, {title, text, [overview,single]}, {'TODO', xml, All}, {todo, xml, All}, {type, fun parse_typedef/4, [module,footer,function]}, - {version, text, [module,package,overview,single]}]. + {version, text, [module,overview,single]}]. aliases('TODO') -> todo; aliases(return) -> returns; @@ -369,7 +369,7 @@ parse_header(Data, Line, Env, Where) when is_list(Where) -> {string, _, File} -> Dir = filename:dirname(Where), Path = Env#env.includes ++ [Dir], - case edoc_lib:find_file(Path, "", File) of + case edoc_lib:find_file(Path, File) of "" -> throw_error(Line, {file_not_found, File}); File1 -> diff --git a/lib/edoc/src/otpsgml_layout.erl b/lib/edoc/src/otpsgml_layout.erl index 2c4cd919bb..052c75b9d4 100644 --- a/lib/edoc/src/otpsgml_layout.erl +++ b/lib/edoc/src/otpsgml_layout.erl @@ -28,7 +28,7 @@ -module(otpsgml_layout). --export([module/2, package/2, overview/2,type/1]). +-export([module/2, overview/2,type/1]). -import(edoc_report, [report/2]). @@ -811,27 +811,6 @@ xml(Title, CSS, Body) -> xmerl:export_simple_content(t_utype_elem(E) ++ local_defs(Ds), ?SGML_EXPORT). - -package(E=#xmlElement{name = package, content = Es}, Options) -> - Opts = init_opts(E, Options), - Name = get_text(packageName, Es), - Title = io_lib:fwrite("Package ~s", [Name]), - Desc = get_content(description, Es), -% ShortDesc = get_content(briefDescription, Desc), - FullDesc = get_content(fullDescription, Desc), - Body = ([?NL, {h1, [Title]}, ?NL] -% ++ ShortDesc - ++ copyright(Es) - ++ deprecated(Es, "package") - ++ version(Es) - ++ since(Es) - ++ authors(Es) - ++ references(Es) - ++ sees(Es) - ++ FullDesc), - XML = xml(Title, stylesheet(Opts), Body), - xmerl:export_simple([XML], ?SGML_EXPORT, []). - overview(E=#xmlElement{name = overview, content = Es}, Options) -> Opts = init_opts(E, Options), Title = get_text(title, Es), @@ -843,6 +822,7 @@ overview(E=#xmlElement{name = overview, content = Es}, Options) -> ++ copyright(Es) ++ version(Es) ++ since(Es) + ++ deprecated(Es, "application") ++ authors(Es) ++ references(Es) ++ sees(Es) diff --git a/lib/edoc/test/edoc_SUITE.erl b/lib/edoc/test/edoc_SUITE.erl index c63660c8c0..6b23054ce3 100644 --- a/lib/edoc/test/edoc_SUITE.erl +++ b/lib/edoc/test/edoc_SUITE.erl @@ -22,12 +22,12 @@ init_per_group/2,end_per_group/2]). %% Test cases --export([app/1,appup/1,build_std/1,build_map_module/1,otp_12008/1]). +-export([app/1,appup/1,build_std/1,build_map_module/1,otp_12008/1, build_app/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [app,appup,build_std,build_map_module,otp_12008]. + [app,appup,build_std,build_map_module,otp_12008, build_app]. groups() -> []. @@ -95,3 +95,20 @@ otp_12008(Config) when is_list(Config) -> ok = edoc:files([Un2], Opts2), {'EXIT', error} = (catch edoc:files([Un3], Opts2)), ok. + +build_app(suite) -> []; +build_app(doc) -> ["Build a local app with nested source directories"]; +build_app(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + OutDir = filename:join(PrivDir, "myapp"), + Src = filename:join(DataDir, "myapp"), + + ok = edoc:application(myapp, Src, [{dir, OutDir}, {subpackages, false}]), + true = filelib:is_regular(filename:join(OutDir, "a.html")), + false = filelib:is_regular(filename:join(OutDir, "b.html")), + + ok = edoc:application(myapp, Src, [{dir, OutDir}]), + true = filelib:is_regular(filename:join(OutDir, "a.html")), + true = filelib:is_regular(filename:join(OutDir, "b.html")), + ok. diff --git a/lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy b/lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/edoc/test/edoc_SUITE_data/myapp/doc/.dummy diff --git a/lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl b/lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl new file mode 100644 index 0000000000..1b5b704551 --- /dev/null +++ b/lib/edoc/test/edoc_SUITE_data/myapp/src/a.erl @@ -0,0 +1 @@ +-module(a). diff --git a/lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl b/lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl new file mode 100644 index 0000000000..6d6f15dfe5 --- /dev/null +++ b/lib/edoc/test/edoc_SUITE_data/myapp/src/src_1/b.erl @@ -0,0 +1 @@ +-module(b). diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript index 156311565c..e8a8f14e3a 100644 --- a/lib/erl_docgen/priv/bin/specs_gen.escript +++ b/lib/erl_docgen/priv/bin/specs_gen.escript @@ -97,7 +97,7 @@ read_file(File, Opts) -> edoc:read_source(File, Opts). extract(File, Forms, Opts) -> - Env = edoc_lib:get_doc_env([], [], [], _Opts=[]), + Env = edoc_lib:get_doc_env([], [], _Opts=[]), {_Module, Doc} = edoc_extract:source(Forms, File, Env, Opts), Doc. diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript index 65a580dca2..007546e7ba 100755 --- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript +++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript @@ -117,7 +117,7 @@ users_guide(File, Args) -> Text = edoc_lib:run_layout(F, Opts), OutFile = "chapter" ++ Args#args.suffix, - edoc_lib:write_file(Text, ".", OutFile, '', Encoding); + edoc_lib:write_file(Text, ".", OutFile, Encoding); false -> io:format("~s: not a regular file\n", [File]), usage() diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl index 134115bdfa..5d71a0bb8f 100644 --- a/lib/inets/src/http_client/httpc_cookie.erl +++ b/lib/inets/src/http_client/httpc_cookie.erl @@ -334,9 +334,23 @@ add_domain(Str, #http_cookie{domain_default = true}) -> add_domain(Str, #http_cookie{domain = Domain}) -> Str ++ "; $Domain=" ++ Domain. +is_set_cookie_valid("") -> + %% an empty Set-Cookie header is not valid + false; +is_set_cookie_valid([$=|_]) -> + %% a Set-Cookie header without name is not valid + false; +is_set_cookie_valid(SetCookieHeader) -> + %% a Set-Cookie header without name/value is not valid + case string:chr(SetCookieHeader, $=) of + 0 -> false; + _ -> true + end. + parse_set_cookies(CookieHeaders, DefaultPathDomain) -> - %% empty Set-Cookie header is invalid according to RFC but some sites violate it - SetCookieHeaders = [Value || {"set-cookie", Value} <- CookieHeaders, Value /= ""], + %% filter invalid Set-Cookie headers + SetCookieHeaders = [Value || {"set-cookie", Value} <- CookieHeaders, + is_set_cookie_valid(Value)], Cookies = [parse_set_cookie(SetCookieHeader, DefaultPathDomain) || SetCookieHeader <- SetCookieHeaders], %% print_cookies("Parsed Cookies", Cookies), diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 63f8bc5bc6..82e08a52cd 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -92,6 +92,7 @@ only_simulated() -> cookie, cookie_profile, empty_set_cookie, + invalid_set_cookie, trace, stream_once, stream_single_chunk, @@ -570,6 +571,18 @@ empty_set_cookie(Config) when is_list(Config) -> ok = httpc:set_options([{cookies, disabled}]). %%------------------------------------------------------------------------- +invalid_set_cookie(doc) -> + ["Test ignoring invalid Set-Cookie header"]; +invalid_set_cookie(Config) when is_list(Config) -> + ok = httpc:set_options([{cookies, enabled}]), + + URL = url(group_name(Config), "/invalid_set_cookie.html", Config), + {ok, {{_,200,_}, [_|_], [_|_]}} = + httpc:request(get, {URL, []}, [], []), + + ok = httpc:set_options([{cookies, disabled}]). + +%%------------------------------------------------------------------------- headers_as_is(doc) -> ["Test the option headers_as_is"]; headers_as_is(Config) when is_list(Config) -> @@ -1715,6 +1728,13 @@ handle_uri(_,"/empty_set_cookie.html",_,_,_,_) -> "Content-Length:32\r\n\r\n"++ "<HTML><BODY>foobar</BODY></HTML>"; +handle_uri(_,"/invalid_set_cookie.html",_,_,_,_) -> + "HTTP/1.1 200 ok\r\n" ++ + "set-cookie: =\r\n" ++ + "set-cookie: name-or-value\r\n" ++ + "Content-Length:32\r\n\r\n"++ + "<HTML><BODY>foobar</BODY></HTML>"; + handle_uri(_,"/missing_crlf.html",_,_,_,_) -> "HTTP/1.1 200 ok" ++ "Content-Length:32\r\n" ++ |